Compare commits

...

20 Commits

Author SHA1 Message Date
s_nakamoto
910bd45756 -- version 0.3.15 release
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@179 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-11-14 00:06:10 +00:00
gavinandresen
838e8c9166 Add paytxfee to getinfo output
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@178 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-11-10 16:43:31 +00:00
s_nakamoto
e2a186af10 SelectCoins first pass tries not to use coins with less than 6 confirmations
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@177 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-11-09 19:47:07 +00:00
s_nakamoto
461764cbbe -paytxfee is now per KB,
BitcoinMiner prioritise transactions by how old their dependencies are

git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@176 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-11-08 22:06:07 +00:00
gavinandresen
3b8848fa4e Fix IsInitialBlockDownload if running on testnet
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@175 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-11-04 00:23:00 +00:00
gavinandresen
3cac997e19 Prevent double-sends from quick double-button-clicks
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@174 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-11-03 23:40:43 +00:00
s_nakamoto
c891967b6f bugfixes from Dean Gores,
addr system changes,
make sure no gen before block 74000

git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@173 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-23 17:43:53 +00:00
gavinandresen
c285051c08 testnet and keypoololdest added to RPC getinfo output. And RPC now sends proper HTTP Date headers.
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@172 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-22 15:15:20 +00:00
s_nakamoto
2ce73dbe85 -- version 0.3.14 release
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@171 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-21 16:47:16 +00:00
s_nakamoto
d9c6b09ac4 Gavin Andresen: multiple instance check, -testnet use port 18333
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@170 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-20 16:12:23 +00:00
gavinandresen
2ea5fa0710 validateaddress RPC command
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@169 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-20 15:58:16 +00:00
s_nakamoto
5cbf75324d Gavin's TEST network as -testnet switch, misc fixes
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@168 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-19 17:16:51 +00:00
gavinandresen
2fad3d34b7 makefile.unix tweak from Xunie so bitcoind links on Ubuntu 10.04 x86_64
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@167 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-14 13:33:03 +00:00
gavinandresen
77cd030ac3 Fixed description of -rpcuser/-rpcpassword options.
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@166 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-11 18:32:33 +00:00
gavinandresen
ed54768f5f -rpcssl=1 option, allowing secure HTTPS JSON-RPC connections on OSX/Unix.
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@165 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-11 18:23:41 +00:00
s_nakamoto
83082f04a4 dkaparis: boost::bind build fix for c++0x
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@164 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-11 15:12:17 +00:00
s_nakamoto
103849419a key pool for safer wallet backup
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@163 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-09 19:33:35 +00:00
s_nakamoto
0a27bd065e updated Russian translation
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@162 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-06 15:43:04 +00:00
s_nakamoto
b22c884231 recursive function to determine if own unconfirmed transaction can be spent
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@161 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-06 02:19:47 +00:00
s_nakamoto
dc8adc3b48 Russian translation by eurekafag
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@160 1a98c847-1fd6-4fd8-948a-caf3550aa51b
2010-10-04 01:40:50 +00:00
22 changed files with 1873 additions and 369 deletions

View File

@@ -152,7 +152,7 @@ inline bool DecodeBase58Check(const string& str, vector<unsigned char>& vchRet)
static const unsigned char ADDRESSVERSION = 0;
#define ADDRESSVERSION ((unsigned char)(fTestNet ? 111 : 0))
inline string Hash160ToAddress(uint160 hash160)
{

View File

@@ -12,12 +12,8 @@ WINDOWS BUILD NOTES
Compilers Supported
-------------------
MinGW GCC (recommended)
MSVC 6.0 SP6: You'll need Boost version 1.34 because they dropped support
for MSVC 6.0 after that. However, they didn't add Asio until 1.35.
You should still be able to build with MSVC 6.0 by adding Asio to 1.34 by
unpacking boost_asio_*.zip into the boost directory:
http://sourceforge.net/projects/asio/files/asio
http://tdm-gcc.tdragon.net/ has an easy installer. Go back a few versions
for a little older gcc like gcc 4.4.?.
MSVC 8.0 (2005) SP1 has been tested. Note: MSVC 7.0 and up have a habit of
linking to runtime DLLs that are not installed on XP by default.
@@ -67,8 +63,7 @@ nmake -f makefile.vc
OpenSSL
-------
Bitcoin does not use any encryption. If you want to do a no-everything
build of OpenSSL to exclude encryption routines, a few patches are required.
If you want to exclude unused optional algorithms, a few patches are required.
(instructions for OpenSSL v0.9.8k)
Edit engines\e_gmp.c and engines\e_capi.c and add this #ifndef around
@@ -92,7 +87,7 @@ Build
cd \openssl
ms\mingw32.bat
If you want to use it with MSVC, generate the .lib file
If you're using MSVC, generate the .lib file
lib /machine:i386 /def:ms\libeay32.def /out:out\libeay32.lib

91
db.cpp
View File

@@ -503,6 +503,11 @@ bool CAddrDB::WriteAddress(const CAddress& addr)
return Write(make_pair(string("addr"), addr.GetKey()), addr);
}
bool CAddrDB::EraseAddress(const CAddress& addr)
{
return Erase(make_pair(string("addr"), addr.GetKey()));
}
bool CAddrDB::LoadAddresses()
{
CRITICAL_BLOCK(cs_mapAddresses)
@@ -554,11 +559,6 @@ bool CAddrDB::LoadAddresses()
pcursor->close();
printf("Loaded %d addresses\n", mapAddresses.size());
// Fix for possible bug that manifests in mapAddresses.count in irc.cpp,
// just need to call count here and it doesn't happen there. The bug was the
// pack pragma in irc.cpp and has been fixed, but I'm not in a hurry to delete this.
mapAddresses.count(vector<unsigned char>(18));
}
return true;
@@ -576,6 +576,9 @@ bool LoadAddresses()
// CWalletDB
//
static set<int64> setKeyPool;
static CCriticalSection cs_setKeyPool;
bool CWalletDB::LoadWallet()
{
vchDefaultKey.clear();
@@ -654,6 +657,12 @@ bool CWalletDB::LoadWallet()
{
ssValue >> vchDefaultKey;
}
else if (strType == "pool")
{
int64 nIndex;
ssKey >> nIndex;
setKeyPool.insert(nIndex);
}
else if (strType == "version")
{
ssValue >> nFileVersion;
@@ -836,3 +845,75 @@ void BackupWallet(const string& strDest)
Sleep(100);
}
}
void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
{
nIndex = -1;
keypool.vchPubKey.clear();
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_setKeyPool)
{
// Top up key pool
int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
while (setKeyPool.size() < nTargetSize+1)
{
int64 nEnd = 1;
if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1;
if (!Write(make_pair(string("pool"), nEnd), CKeyPool(GenerateNewKey())))
throw runtime_error("ReserveKeyFromKeyPool() : writing generated key failed");
setKeyPool.insert(nEnd);
printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
}
// Get the oldest key
assert(!setKeyPool.empty());
nIndex = *(setKeyPool.begin());
setKeyPool.erase(setKeyPool.begin());
if (!Read(make_pair(string("pool"), nIndex), keypool))
throw runtime_error("ReserveKeyFromKeyPool() : read failed");
if (!mapKeys.count(keypool.vchPubKey))
throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
assert(!keypool.vchPubKey.empty());
printf("keypool reserve %"PRI64d"\n", nIndex);
}
}
void CWalletDB::KeepKey(int64 nIndex)
{
// Remove from key pool
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapWallet)
{
Erase(make_pair(string("pool"), nIndex));
}
printf("keypool keep %"PRI64d"\n", nIndex);
}
void CWalletDB::ReturnKey(int64 nIndex)
{
// Return to key pool
CRITICAL_BLOCK(cs_setKeyPool)
setKeyPool.insert(nIndex);
printf("keypool return %"PRI64d"\n", nIndex);
}
vector<unsigned char> CWalletDB::GetKeyFromKeyPool()
{
int64 nIndex = 0;
CKeyPool keypool;
ReserveKeyFromKeyPool(nIndex, keypool);
KeepKey(nIndex);
return keypool.vchPubKey;
}
int64 CWalletDB::GetOldestKeyPoolTime()
{
int64 nIndex = 0;
CKeyPool keypool;
ReserveKeyFromKeyPool(nIndex, keypool);
ReturnKey(nIndex);
return keypool.nTime;
}

84
db.h
View File

@@ -298,6 +298,7 @@ private:
void operator=(const CAddrDB&);
public:
bool WriteAddress(const CAddress& addr);
bool EraseAddress(const CAddress& addr);
bool LoadAddresses();
};
@@ -308,6 +309,35 @@ bool LoadAddresses();
class CKeyPool
{
public:
int64 nTime;
vector<unsigned char> vchPubKey;
CKeyPool()
{
nTime = GetTime();
}
CKeyPool(const vector<unsigned char>& vchPubKeyIn)
{
nTime = GetTime();
vchPubKey = vchPubKeyIn;
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
READWRITE(nTime);
READWRITE(vchPubKey);
)
};
class CWalletDB : public CDB
{
public:
@@ -396,6 +426,14 @@ public:
}
bool LoadWallet();
protected:
void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool);
void KeepKey(int64 nIndex);
static void ReturnKey(int64 nIndex);
friend class CReserveKey;
public:
vector<unsigned char> GetKeyFromKeyPool();
int64 GetOldestKeyPoolTime();
};
bool LoadWallet(bool& fFirstRunRet);
@@ -405,3 +443,49 @@ inline bool SetAddressBookName(const string& strAddress, const string& strName)
{
return CWalletDB().WriteName(strAddress, strName);
}
class CReserveKey
{
protected:
int64 nIndex;
vector<unsigned char> vchPubKey;
public:
CReserveKey()
{
nIndex = -1;
}
~CReserveKey()
{
if (!fShutdown)
ReturnKey();
}
vector<unsigned char> GetReservedKey()
{
if (nIndex == -1)
{
CKeyPool keypool;
CWalletDB().ReserveKeyFromKeyPool(nIndex, keypool);
vchPubKey = keypool.vchPubKey;
}
assert(!vchPubKey.empty());
return vchPubKey;
}
void KeepKey()
{
if (nIndex != -1)
CWalletDB().KeepKey(nIndex);
nIndex = -1;
vchPubKey.clear();
}
void ReturnKey()
{
if (nIndex != -1)
CWalletDB::ReturnKey(nIndex);
nIndex = -1;
vchPubKey.clear();
}
};

View File

@@ -43,6 +43,7 @@
#include <db_cxx.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <limits.h>
#include <float.h>
@@ -70,6 +71,7 @@
#include <boost/filesystem/fstream.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/thread.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/date_time/gregorian/gregorian_types.hpp>

View File

@@ -165,17 +165,35 @@ bool AppInit2(int argc, char* argv[])
" bitcoin [options] help \t\t " + _("List commands\n") +
" bitcoin [options] help <command> \t\t " + _("Get help for a command\n") +
_("Options:\n") +
" -conf=<file> \t " + _("Specify configuration file (default: bitcoin.conf)\n") +
" -gen \t " + _("Generate coins\n") +
" -gen=0 \t " + _("Don't generate coins\n") +
" -min \t " + _("Start minimized\n") +
" -datadir=<dir> \t " + _("Specify data directory\n") +
" -proxy=<ip:port>\t " + _("Connect through socks4 proxy\n") +
" -addnode=<ip> \t " + _("Add a node to connect to\n") +
" -connect=<ip> \t " + _("Connect only to the specified node\n") +
" -server \t " + _("Accept command line and JSON-RPC commands\n") +
" -daemon \t " + _("Run in the background as a daemon and accept commands\n") +
" -? \t " + _("This help message\n");
" -conf=<file> \t\t " + _("Specify configuration file (default: bitcoin.conf)\n") +
" -gen \t\t " + _("Generate coins\n") +
" -gen=0 \t\t " + _("Don't generate coins\n") +
" -min \t\t " + _("Start minimized\n") +
" -datadir=<dir> \t\t " + _("Specify data directory\n") +
" -proxy=<ip:port> \t " + _("Connect through socks4 proxy\n") +
" -addnode=<ip> \t " + _("Add a node to connect to\n") +
" -connect=<ip> \t\t " + _("Connect only to the specified node\n") +
" -paytxfee=<amt> \t " + _("Fee per KB to add to transactions you send\n") +
" -server \t\t " + _("Accept command line and JSON-RPC commands\n") +
" -daemon \t\t " + _("Run in the background as a daemon and accept commands\n") +
" -testnet \t\t " + _("Use the test network\n") +
" -rpcuser=<user> \t " + _("Username for JSON-RPC connections\n") +
" -rpcpassword=<pw>\t " + _("Password for JSON-RPC connections\n") +
" -rpcport=<port> \t\t " + _("Listen for JSON-RPC connections on <port>\n") +
" -rpcallowip=<ip> \t\t " + _("Allow JSON-RPC connections from specified IP address\n") +
" -rpcconnect=<ip> \t " + _("Send commands to node running on <ip>\n");
#ifdef USE_SSL
strUsage += string() +
_("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)\n") +
" -rpcssl=1 \t " + _("Use OpenSSL (https) for JSON-RPC connections\n") +
" -rpcsslcertificatchainfile=<file.cert>\t " + _("Server certificate file (default: server.cert)\n") +
" -rpcsslprivatekeyfile=<file.pem> \t " + _("Server private key (default: server.pem)\n") +
" -rpcsslciphers=<ciphers> \t " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)\n");
#endif
strUsage += string() +
" -? \t\t " + _("This help message\n");
#if defined(__WXMSW__) && defined(GUI)
// Tabs make the columns line up in the message box
@@ -194,6 +212,9 @@ bool AppInit2(int argc, char* argv[])
if (mapArgs.count("-printtodebugger"))
fPrintToDebugger = true;
if (mapArgs.count("-testnet"))
fTestNet = true;
if (fCommandLine)
{
int ret = CommandLineRPC(argc, argv);
@@ -224,8 +245,7 @@ bool AppInit2(int argc, char* argv[])
// Required to protect the database files if we're going to keep deleting log.*
//
#if defined(__WXMSW__) && defined(GUI)
// todo: wxSingleInstanceChecker wasn't working on Linux, never deleted its lock file
// maybe should go by whether successfully bind port 8333 instead
// wxSingleInstanceChecker doesn't work on Linux
wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH");
for (int i = 0; i < strMutexName.size(); i++)
if (!isalnum(strMutexName[i]))
@@ -237,7 +257,6 @@ bool AppInit2(int argc, char* argv[])
unsigned int nStart = GetTime();
loop
{
// TODO: find out how to do this in Linux, or replace with wxWidgets commands
// Show the previous instance and exit
HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin");
if (hwndPrev)
@@ -261,8 +280,18 @@ bool AppInit2(int argc, char* argv[])
}
#endif
// Make sure only a single bitcoin process is using the data directory.
string strLockFile = GetDataDir() + "/.lock";
FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist.
fclose(file);
static boost::interprocess::file_lock lock(strLockFile.c_str());
if (!lock.try_lock())
{
wxMessageBox(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().c_str()), "Bitcoin");
return false;
}
// Bind to the port early so we can tell if another instance is already running.
// This is a backup to wxSingleInstanceChecker, which doesn't work on Linux.
string strErrors;
if (!BindListenPort(strErrors))
{
@@ -385,7 +414,7 @@ bool AppInit2(int argc, char* argv[])
wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "Bitcoin");
return false;
}
if (nTransactionFee > 1 * COIN)
if (nTransactionFee > 0.25 * COIN)
wxMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION);
}

45
irc.cpp
View File

@@ -84,18 +84,31 @@ bool RecvLine(SOCKET hSocket, string& strLine)
}
else if (nBytes <= 0)
{
if (fShutdown)
return false;
if (nBytes < 0)
{
int nErr = WSAGetLastError();
if (nErr == WSAEMSGSIZE)
continue;
if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
{
Sleep(10);
continue;
}
}
if (!strLine.empty())
return true;
// socket closed
printf("IRC socket closed\n");
return false;
}
else
{
// socket error
int nErr = WSAGetLastError();
if (nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
if (nBytes == 0)
{
// socket closed
printf("IRC socket closed\n");
return false;
}
else
{
// socket error
int nErr = WSAGetLastError();
printf("IRC recv failed: %d\n", nErr);
return false;
}
@@ -126,7 +139,7 @@ bool RecvLineIRC(SOCKET hSocket, string& strLine)
}
}
int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL)
int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
{
loop
{
@@ -141,6 +154,8 @@ int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const cha
return 2;
if (psz3 && strLine.find(psz3) != -1)
return 3;
if (psz4 && strLine.find(psz4) != -1)
return 4;
}
}
@@ -210,7 +225,7 @@ void ThreadIRCSeed2(void* parg)
return;
}
if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname"))
if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
{
closesocket(hSocket);
hSocket = INVALID_SOCKET;
@@ -250,8 +265,8 @@ void ThreadIRCSeed2(void* parg)
}
Sleep(500);
Send(hSocket, "JOIN #bitcoin\r");
Send(hSocket, "WHO #bitcoin\r");
Send(hSocket, fTestNet ? "JOIN #bitcoinTEST\r" : "JOIN #bitcoin\r");
Send(hSocket, fTestNet ? "WHO #bitcoinTEST\r" : "WHO #bitcoin\r");
int64 nStart = GetTime();
string strLine;
@@ -291,8 +306,8 @@ void ThreadIRCSeed2(void* parg)
CAddress addr;
if (DecodeAddress(pszName, addr))
{
addr.nTime = GetAdjustedTime() - 51 * 60;
if (AddAddress(addr))
addr.nTime = GetAdjustedTime();
if (AddAddress(addr, 51 * 60))
printf("IRC got new address\n");
nGotIRCAddresses++;
}

Binary file not shown.

View File

@@ -0,0 +1,895 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-10-05 10:53+0300\n"
"PO-Revision-Date: 2010-10-05 11:43+0300\n"
"Last-Translator: eurekafag\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
"X-Poedit-Basepath: .\n"
"X-Poedit-SearchPath-0: ../../..\n"
#: ../../../init.cpp:162
msgid "Usage:"
msgstr "Использование"
#: ../../../init.cpp:164
msgid "Send command to -server or bitcoind\n"
msgstr "Отправить команду bitcoin, запущенному с -server\n"
#: ../../../init.cpp:165
msgid "List commands\n"
msgstr "Список команд\n"
#: ../../../init.cpp:166
msgid "Get help for a command\n"
msgstr "Получить помощь для команды\n"
#: ../../../init.cpp:167
msgid "Options:\n"
msgstr "Параметры:\n"
#: ../../../init.cpp:168
msgid "Specify configuration file (default: bitcoin.conf)\n"
msgstr "Укажите конфигурационный файл (по умолчанию: bitcoin.conf)\n"
#: ../../../init.cpp:169
msgid "Generate coins\n"
msgstr "Генерировать монеты\n"
#: ../../../init.cpp:170
msgid "Don't generate coins\n"
msgstr "Не генерировать монеты\n"
#: ../../../init.cpp:171
msgid "Start minimized\n"
msgstr "Запускать свёрнутым\n"
#: ../../../init.cpp:172
msgid "Specify data directory\n"
msgstr "Указать каталог данных\n"
#: ../../../init.cpp:173
msgid "Connect through socks4 proxy\n"
msgstr "Подключаться через socks4 прокси\n"
#: ../../../init.cpp:174
msgid "Add a node to connect to\n"
msgstr "Добавить узел для подключения\n"
#: ../../../init.cpp:175
msgid "Connect only to the specified node\n"
msgstr "Подключаться только к указанному узлу\n"
#: ../../../init.cpp:176
msgid "Accept command line and JSON-RPC commands\n"
msgstr "Принимать команды из командной строки и через JSON-RPC\n"
#: ../../../init.cpp:177
msgid "Run in the background as a daemon and accept commands\n"
msgstr "Запустить в фоне как демон и принимать команды\n"
#: ../../../init.cpp:178
msgid "This help message\n"
msgstr "Эта справка\n"
#: ../../../init.cpp:284
msgid "Error loading addr.dat \n"
msgstr "Ошибка загрузки addr.dat \n"
#: ../../../init.cpp:290
msgid "Error loading blkindex.dat \n"
msgstr "Ошибка загрузки blkindex.dat \n"
#: ../../../init.cpp:297
msgid "Error loading wallet.dat \n"
msgstr "Ошибка загрузки wallet.dat \n"
#: ../../../init.cpp:365
msgid "Invalid -proxy address"
msgstr "Неверный адрес -proxy"
#: ../../../init.cpp:385
msgid "Invalid amount for -paytxfee=<amount>"
msgstr "Неверное значение для -paytxfee=<amount>"
#: ../../../init.cpp:389
msgid "Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."
msgstr "Внимание: -paytxfee установлено в очень большое значение. Это комиссия, которую вы будете платить при переводе."
#: ../../../main.cpp:1641
msgid "Warning: Disk space is low "
msgstr "Внимание: мало места на диске "
#: ../../../main.cpp:3505
#, c-format
msgid "Error: This is an oversized transaction that requires a transaction fee of %s "
msgstr "Ошибка: этот перевод слишком большого размера, который требует комиссию %s "
#: ../../../main.cpp:3507
msgid "Error: Transaction creation failed "
msgstr "Ошибка: не удалось создать перевод "
#: ../../../main.cpp:3512
#: ../../../ui.cpp:1964
#: ../../../ui.cpp:1966
#: ../../../ui.cpp:2107
#: ../../../ui.cpp:2260
msgid "Sending..."
msgstr "Отправка..."
#: ../../../main.cpp:3516
msgid "Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."
msgstr "Перевод был отклонен. Это могло произойти, если некоторые из монет в вашем кошельке уже были потрачены, например, если вы использовали копию wallet.dat, и монеты были потрачены в копии, но не отмечены израсходованными здесь."
#: ../../../main.cpp:3528
msgid "Invalid amount"
msgstr "Неверное количество"
#: ../../../main.cpp:3530
#: ../../../ui.cpp:2174
#: ../../../ui.cpp:2245
msgid "Insufficient funds"
msgstr "Недостаточно средств"
#: ../../../main.cpp:3535
msgid "Invalid bitcoin address"
msgstr "Неверный адрес bitcoin"
#: ../../../rpc.cpp:963
#: ../../../rpc.cpp:965
#, c-format
msgid "To use the %s option"
msgstr "Чтобы использовать опцию %s"
#: ../../../rpc.cpp:967
#, c-format
msgid ""
"Warning: %s, you must set rpcpassword=<password>\n"
"in the configuration file: %s\n"
"If the file does not exist, create it with owner-readable-only file permissions.\n"
msgstr ""
"Внимание: %s, вы должны установить rpcpassword=<пароль>\n"
"в конфигурационном файле: %s\n"
"Если файл не существует, создайте его с правами \"чтение только владельцем\".\n"
#: ../../../rpc.cpp:1100
#, c-format
msgid ""
"You must set rpcpassword=<password> in the configuration file:\n"
"%s\n"
"If the file does not exist, create it with owner-readable-only file permissions."
msgstr ""
"Вы должны установить rpcpassword=<пароль> в конфигурационном файле:\n"
"%s\n"
"Если файл не существует, создайте его с правами \"чтение только владельцем\"."
#: ../../../ui.cpp:202
#, c-format
msgid "This transaction is over the size limit. You can still send it for a fee of %s, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?"
msgstr "Этот перевод превышает допустимый лимит. Вы можете провести его с комиссией %s, которую получат узлы, обрабатывающие перевод, и поможет поддерживать сеть. Вы хотите заплатить комиссию?"
#: ../../../ui.cpp:301
msgid "Status"
msgstr "Статус"
#: ../../../ui.cpp:302
msgid "Date"
msgstr "Дата"
#: ../../../ui.cpp:303
msgid "Description"
msgstr "Описание"
#: ../../../ui.cpp:304
msgid "Debit"
msgstr "Дебет"
#: ../../../ui.cpp:305
msgid "Credit"
msgstr "Кредит"
#: ../../../ui.cpp:511
#, c-format
msgid "Open for %d blocks"
msgstr "Открыто для %d блоков"
#: ../../../ui.cpp:513
#, c-format
msgid "Open until %s"
msgstr "Открыто до %s"
#: ../../../ui.cpp:519
#, c-format
msgid "%d/offline?"
msgstr "%d/оффлайн?"
#: ../../../ui.cpp:521
#, c-format
msgid "%d/unconfirmed"
msgstr "%d/не подтверждено"
#: ../../../ui.cpp:523
#, c-format
msgid "%d confirmations"
msgstr "%d подтверждений"
#: ../../../ui.cpp:608
msgid "Generated"
msgstr "Сгенерировано"
#: ../../../ui.cpp:616
#, c-format
msgid "Generated (%s matures in %d more blocks)"
msgstr "Сгенерировано (%s станет доступно через %d блоков)"
#: ../../../ui.cpp:620
msgid "Generated - Warning: This block was not received by any other nodes and will probably not be accepted!"
msgstr "Сгенерировано - Внимание: этот блок не был получен ни одним узлом и, скорее всего, не будет принят!"
#: ../../../ui.cpp:624
msgid "Generated (not accepted)"
msgstr "Сгенерировано (не принято)"
#: ../../../ui.cpp:634
msgid "From: "
msgstr "От: "
#: ../../../ui.cpp:658
msgid "Received with: "
msgstr "Получено для: "
#: ../../../ui.cpp:704
msgid "Payment to yourself"
msgstr "Платёж самому себе"
#: ../../../ui.cpp:741
msgid "To: "
msgstr "Кому: "
#: ../../../ui.cpp:1049
msgid " Generating"
msgstr " Генерация"
#: ../../../ui.cpp:1051
msgid "(not connected)"
msgstr "(не подключен)"
#: ../../../ui.cpp:1054
#, c-format
msgid " %d connections %d blocks %d transactions"
msgstr " %d подключений %d блоков %d переводов"
#: ../../../ui.cpp:1165
#: ../../../ui.cpp:2560
msgid "New Receiving Address"
msgstr "Новый адрес получения"
#: ../../../ui.cpp:1166
#: ../../../ui.cpp:2561
msgid ""
"You should use a new address for each payment you receive.\n"
"\n"
"Label"
msgstr ""
"Вы должны использовать новый адрес для каждого получаемого платежа.\n"
"\n"
"Метка"
#: ../../../ui.cpp:1235
msgid "<b>Status:</b> "
msgstr "<b>Статус:</b> "
#: ../../../ui.cpp:1240
msgid ", has not been successfully broadcast yet"
msgstr ", ещё не был успешно разослан"
#: ../../../ui.cpp:1242
#, c-format
msgid ", broadcast through %d node"
msgstr ", рассылка через %d узел"
#: ../../../ui.cpp:1244
#, c-format
msgid ", broadcast through %d nodes"
msgstr ", рассылка через %d узлов"
#: ../../../ui.cpp:1248
msgid "<b>Date:</b> "
msgstr "<b>Дата:</b> "
#: ../../../ui.cpp:1256
msgid "<b>Source:</b> Generated<br>"
msgstr "<b>Источник:</b> Сгенерировано<br>"
#: ../../../ui.cpp:1262
#: ../../../ui.cpp:1280
msgid "<b>From:</b> "
msgstr "<b>От:</b> "
#: ../../../ui.cpp:1280
msgid "unknown"
msgstr "аноним"
#: ../../../ui.cpp:1281
#: ../../../ui.cpp:1305
#: ../../../ui.cpp:1364
msgid "<b>To:</b> "
msgstr "<b>Кому:</b> "
#: ../../../ui.cpp:1284
msgid " (yours, label: "
msgstr " (ваш, метка: "
#: ../../../ui.cpp:1286
msgid " (yours)"
msgstr " (ваш)"
#: ../../../ui.cpp:1323
#: ../../../ui.cpp:1335
#: ../../../ui.cpp:1398
msgid "<b>Credit:</b> "
msgstr "<b>Кредит:</b> "
#: ../../../ui.cpp:1325
#, c-format
msgid "(%s matures in %d more blocks)"
msgstr "(%s станет доступно через %d блоков)"
#: ../../../ui.cpp:1327
msgid "(not accepted)"
msgstr "(не принято)"
#: ../../../ui.cpp:1372
#: ../../../ui.cpp:1395
msgid "<b>Debit:</b> "
msgstr "<b>Дебет:</b> "
#: ../../../ui.cpp:1386
msgid "<b>Transaction fee:</b> "
msgstr "<b>Комиссия:</b> "
#: ../../../ui.cpp:1402
msgid "<b>Net amount:</b> "
msgstr "<b>Количество сети:</b> "
#: ../../../ui.cpp:1409
msgid "Message:"
msgstr "Сообщение:"
#: ../../../ui.cpp:1412
msgid "Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours."
msgstr "Сгенерированные монеты должны ждать 120 блоков, прежде чем они могут быть потрачены. Когда вы сгенерировали этот блок, он был разослан в сети для добавления в цепь блоков. Если не удалось добавить этот блок в цепь, он будет обозначен как \"не принятый\" и не может быть потрачен. Такое может случиться, если другой узел сгенерировал блок через несколько секунд после вас."
#: ../../../ui.cpp:1593
msgid "Cannot write autostart/bitcoin.desktop file"
msgstr "Не удаётся записать файл autostart/bitcoin.desktop"
#: ../../../ui.cpp:1629
msgid "Main"
msgstr "Основные"
#: ../../../ui.cpp:1634
msgid "&Start Bitcoin on window system startup"
msgstr "&Запускать Bitcoin при запуске оконной системы"
#: ../../../ui.cpp:1641
msgid "&Minimize on close"
msgstr "&Сворачивать при закрытии"
#: ../../../ui.cpp:1798
#, c-format
msgid "version %s%s beta"
msgstr "версия %s%s бета"
#: ../../../ui.cpp:1884
msgid "n/a"
msgstr "н/д"
#: ../../../ui.cpp:1885
msgid "Can't include a message when sending to a Bitcoin address"
msgstr "Не удаётся включить сообщение при отправке на адрес Bitcoin"
#: ../../../ui.cpp:1938
msgid "Error in amount "
msgstr "Ошибка в количестве "
#: ../../../ui.cpp:1938
#: ../../../ui.cpp:1943
#: ../../../ui.cpp:1948
#: ../../../ui.cpp:1974
#: ../../../uibase.cpp:59
msgid "Send Coins"
msgstr "Отправить монеты"
#: ../../../ui.cpp:1943
msgid "Amount exceeds your balance "
msgstr "Количество превышает ваш баланс "
#: ../../../ui.cpp:1948
msgid "Total exceeds your balance when the "
msgstr "Общая сумма превышает ваш баланс, когда "
#: ../../../ui.cpp:1948
msgid " transaction fee is included "
msgstr " комиссия включена "
#: ../../../ui.cpp:1964
msgid "Payment sent "
msgstr "Платёж отправлен "
#: ../../../ui.cpp:1974
msgid "Invalid address "
msgstr "Неверный адрес "
#: ../../../ui.cpp:2028
#, c-format
msgid "Sending %s to %s"
msgstr "Отправка %s для %s"
#: ../../../ui.cpp:2101
#: ../../../ui.cpp:2134
msgid "CANCELLED"
msgstr "ОТМЕНЕНО"
#: ../../../ui.cpp:2105
msgid "Cancelled"
msgstr "Отменено"
#: ../../../ui.cpp:2107
msgid "Transfer cancelled "
msgstr "Передача отменена "
#: ../../../ui.cpp:2160
msgid "Error: "
msgstr "Ошибка: "
#: ../../../ui.cpp:2179
msgid "Connecting..."
msgstr "Подключение..."
#: ../../../ui.cpp:2184
msgid "Unable to connect"
msgstr "Невозможно подключиться"
#: ../../../ui.cpp:2189
msgid "Requesting public key..."
msgstr "Запрос публичного ключа..."
#: ../../../ui.cpp:2201
msgid "Received public key..."
msgstr "Получен публичный ключ..."
#: ../../../ui.cpp:2215
msgid "Recipient is not accepting transactions sent by IP address"
msgstr "Получатель не принимает переводы на IP-адрес"
#: ../../../ui.cpp:2217
msgid "Transfer was not accepted"
msgstr "Передача не принята"
#: ../../../ui.cpp:2226
msgid "Invalid response received"
msgstr "Получен неверный отклик"
#: ../../../ui.cpp:2241
msgid "Creating transaction..."
msgstr "Создание перевода..."
#: ../../../ui.cpp:2253
#, c-format
msgid "This is an oversized transaction that requires a transaction fee of %s"
msgstr "Это слишком большой перевод, который требует комиссию в размере %s"
#: ../../../ui.cpp:2255
msgid "Transaction creation failed"
msgstr "Не удалось создать перевод"
#: ../../../ui.cpp:2262
msgid "Transaction aborted"
msgstr "Перевод прерван"
#: ../../../ui.cpp:2270
msgid "Lost connection, transaction cancelled"
msgstr "Соединение разорвано, перевод отменён"
#: ../../../ui.cpp:2286
msgid "Sending payment..."
msgstr "Отправка платежа..."
#: ../../../ui.cpp:2292
msgid "The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."
msgstr "Перевод был отклонён. Это могло произойти, если некоторые из монет в вашем кошельке уже были потрачены, например, если вы использовали копию wallet.dat, и монеты были потрачены в копии, но не отмечены израсходованными здесь."
#: ../../../ui.cpp:2301
msgid "Waiting for confirmation..."
msgstr "Ожидание подтверждения..."
#: ../../../ui.cpp:2319
msgid ""
"The payment was sent, but the recipient was unable to verify it.\n"
"The transaction is recorded and will credit to the recipient,\n"
"but the comment information will be blank."
msgstr ""
"Платёж был отправлен, но получатель не смог проверить его.\n"
"Перевод был записан и будет начислен получателю,\n"
"но поле комментария будет пустое."
#: ../../../ui.cpp:2328
msgid "Payment was sent, but an invalid response was received"
msgstr "Платёж отправлен, но был получен неверный отклик"
#: ../../../ui.cpp:2334
msgid "Payment completed"
msgstr "Платёж проведён"
#: ../../../ui.cpp:2365
#: ../../../ui.cpp:2511
#: ../../../ui.cpp:2548
msgid "Name"
msgstr "Имя"
#: ../../../ui.cpp:2366
#: ../../../ui.cpp:2511
#: ../../../ui.cpp:2548
msgid "Address"
msgstr "Адрес"
#: ../../../ui.cpp:2368
#: ../../../ui.cpp:2523
msgid "Label"
msgstr "Метка"
#: ../../../ui.cpp:2369
#: ../../../uibase.cpp:902
msgid "Bitcoin Address"
msgstr "Адрес Bitcoin"
#: ../../../ui.cpp:2493
msgid "This is one of your own addresses for receiving payments and cannot be entered in the address book. "
msgstr "Это один из ваших собственных адресов для получения платежей, он не может быть внесён в адресную книгу. "
#: ../../../ui.cpp:2511
#: ../../../ui.cpp:2517
msgid "Edit Address"
msgstr "Правка адреса"
#: ../../../ui.cpp:2523
msgid "Edit Address Label"
msgstr "Правка метки адреса"
#: ../../../ui.cpp:2548
#: ../../../ui.cpp:2554
msgid "Add Address"
msgstr "Добавить адрес"
#: ../../../ui.cpp:2630
msgid "Bitcoin"
msgstr "Bitcoin"
#: ../../../ui.cpp:2632
msgid "Bitcoin - Generating"
msgstr "Bitcoin - Генерация"
#: ../../../ui.cpp:2634
msgid "Bitcoin - (not connected)"
msgstr "Bitcoin - (не подключен)"
#: ../../../ui.cpp:2711
msgid "&Open Bitcoin"
msgstr "&Открыть Bitcoin"
#: ../../../ui.cpp:2712
msgid "O&ptions..."
msgstr "О&пции..."
#: ../../../ui.cpp:2713
#: ../../../uibase.cpp:32
msgid "&Generate Coins"
msgstr "&Генерировать монеты"
#: ../../../ui.cpp:2716
#: ../../../uibase.cpp:25
msgid "E&xit"
msgstr "&Выход"
#: ../../../ui.cpp:2931
msgid "Program has crashed and will terminate. "
msgstr "Сбой программы, завершение. "
#: ../../../uibase.cpp:28
msgid "&File"
msgstr "&Файл"
#: ../../../uibase.cpp:36
msgid "&Your Receiving Addresses..."
msgstr "&Ваши адреса получения..."
#: ../../../uibase.cpp:40
msgid "&Options..."
msgstr "&Опции"
#: ../../../uibase.cpp:43
msgid "&Settings"
msgstr "&Настройки"
#: ../../../uibase.cpp:47
msgid "&About..."
msgstr "&О программе..."
#: ../../../uibase.cpp:50
msgid "&Help"
msgstr "&Справка"
#: ../../../uibase.cpp:60
msgid "Address Book"
msgstr "Адресная книга"
#: ../../../uibase.cpp:75
msgid "Your Bitcoin Address:"
msgstr "Ваш адрес Bitcoin:"
#: ../../../uibase.cpp:82
msgid " &New... "
msgstr " &Новый... "
#: ../../../uibase.cpp:85
#: ../../../uibase.cpp:845
#: ../../../uibase.cpp:948
msgid " &Copy to Clipboard "
msgstr " &Копировать в буфер обмена "
#: ../../../uibase.cpp:99
msgid "Balance:"
msgstr "Баланс:"
#: ../../../uibase.cpp:115
msgid " All"
msgstr " Все"
#: ../../../uibase.cpp:115
msgid " Sent"
msgstr " Отправленные"
#: ../../../uibase.cpp:115
msgid " Received"
msgstr " Полученные"
#: ../../../uibase.cpp:115
msgid " In Progress"
msgstr " В процессе"
#: ../../../uibase.cpp:136
msgid "All Transactions"
msgstr "Все переводы"
#: ../../../uibase.cpp:147
msgid "Sent/Received"
msgstr "Отправленные/Полученные"
#: ../../../uibase.cpp:158
msgid "Sent"
msgstr "Отправленные"
#: ../../../uibase.cpp:169
msgid "Received"
msgstr "Полученные"
#: ../../../uibase.cpp:312
#: ../../../uibase.cpp:473
#: ../../../uibase.cpp:574
#: ../../../uibase.cpp:787
#: ../../../uibase.cpp:848
#: ../../../uibase.cpp:957
#: ../../../uibase.cpp:1046
msgid "OK"
msgstr "ОК"
#: ../../../uibase.cpp:355
msgid "Optional transaction fee you give to the nodes that process your transactions."
msgstr "Необязательная комиссия, которую вы даёте узлам, проводящим ваш перевод."
#: ../../../uibase.cpp:364
msgid "Transaction fee:"
msgstr "Комиссия:"
#: ../../../uibase.cpp:380
msgid "&Limit coin generation to"
msgstr "&Ограничить генерацию монет до"
#: ../../../uibase.cpp:387
msgid "processors"
msgstr "процессоров"
#: ../../../uibase.cpp:393
msgid "&Start Bitcoin on system startup"
msgstr "&Запускать Bitcoin при старте системы"
#: ../../../uibase.cpp:397
msgid "&Minimize to the tray instead of the taskbar"
msgstr "&Сворачивать в трей вместо панели задач"
#: ../../../uibase.cpp:401
msgid "M&inimize to the tray on close"
msgstr "С&ворачивать в трей при закрытии"
#: ../../../uibase.cpp:408
msgid "&Connect through socks4 proxy: "
msgstr "&Подключаться через socks4 прокси: "
#: ../../../uibase.cpp:420
msgid "Proxy &IP:"
msgstr "IP п&рокси:"
#: ../../../uibase.cpp:428
msgid " &Port:"
msgstr " &Порт"
#: ../../../uibase.cpp:450
msgid "// [don't translate] Test panel 2 for future expansion"
msgstr ""
#: ../../../uibase.cpp:454
msgid "// [don't translate] Let's not start multiple pages until the first page is filled up"
msgstr ""
#: ../../../uibase.cpp:476
#: ../../../uibase.cpp:729
#: ../../../uibase.cpp:792
#: ../../../uibase.cpp:851
#: ../../../uibase.cpp:960
#: ../../../uibase.cpp:1049
msgid "Cancel"
msgstr "Отмена"
#: ../../../uibase.cpp:479
msgid "&Apply"
msgstr "&Применить"
#: ../../../uibase.cpp:540
msgid "Bitcoin "
msgstr "Bitcoin "
#: ../../../uibase.cpp:546
msgid "version"
msgstr "версия"
#: ../../../uibase.cpp:557
msgid ""
"Copyright (c) 2009-2010 Satoshi Nakamoto.\n"
"\n"
"This is experimental software.\n"
"\n"
"Distributed under the MIT/X11 software license, see the accompanying file \n"
"license.txt or http://www.opensource.org/licenses/mit-license.php.\n"
"\n"
"This product includes software developed by the OpenSSL Project for use in the \n"
"OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by \n"
"Eric Young (eay@cryptsoft.com)."
msgstr ""
"Все права защищены (c) 2009-2010 Satoshi Nakamoto.\n"
"\n"
"Это экспериментальное ПО.\n"
"\n"
"Распространяется под лицензией MIT/X11, см. файл\n"
"license.txt или http://www.opensource.org/licenses/mit-license.php.\n"
"\n"
"Этот продукт включает ПО, разработанное проектом OpenSSL для использования в\n"
"OpenSSL Toolkit (http://www.openssl.org/), и криптографическое ПО, написанное\n"
"Eric Young (eay@cryptsoft.com)."
#: ../../../uibase.cpp:613
msgid "Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) or IP address (e.g. 123.45.6.7)"
msgstr "Введите адрес Bitcoin (напр. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) или IP адрес (напр. 123.45.6.7)"
#: ../../../uibase.cpp:627
msgid "Pay &To:"
msgstr "&Кому:"
#: ../../../uibase.cpp:642
msgid "&Paste"
msgstr "&Вставить"
#: ../../../uibase.cpp:645
msgid " Address &Book..."
msgstr " А&дресная книга..."
#: ../../../uibase.cpp:652
msgid "&Amount:"
msgstr "К&оличество:"
#: ../../../uibase.cpp:662
msgid "T&ransfer:"
msgstr "&Передача:"
#: ../../../uibase.cpp:668
msgid " Standard"
msgstr " Стандарт"
#: ../../../uibase.cpp:690
msgid "&From:"
msgstr "О&т:"
#: ../../../uibase.cpp:707
msgid "&Message:"
msgstr "&Сообщение:"
#: ../../../uibase.cpp:724
msgid "&Send"
msgstr "Отп&равить"
#: ../../../uibase.cpp:776
msgid ""
"\n"
"\n"
"Connecting..."
msgstr ""
"\n"
"\n"
"Подключение..."
#: ../../../uibase.cpp:826
msgid "These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. The highlighted address is displayed in the main window."
msgstr "Это ваши адреса для получения платежей. Вы можете использовать разные для каждого отправителя, чтобы отслеживать, кто вам платит. Выделенный адрес отображается в главном окне."
#: ../../../uibase.cpp:839
#: ../../../uibase.cpp:951
msgid "&Edit..."
msgstr "&Правка..."
#: ../../../uibase.cpp:842
#: ../../../uibase.cpp:954
msgid " &New Address... "
msgstr " &Новый адрес... "
#: ../../../uibase.cpp:914
msgid "Sending"
msgstr "Отправка"
#: ../../../uibase.cpp:922
msgid "These are your Bitcoin addresses for receiving payments. You can give a different one to each sender to keep track of who is paying you. The highlighted address will be displayed in the main window."
msgstr "Это ваши адреса для получения платежей. Вы можете использовать разные для каждого отправителя, чтобы отслеживать, кто вам платит. Выделенный адрес отображается в главном окне."
#: ../../../uibase.cpp:935
msgid "Receiving"
msgstr "Получение"
#: ../../../uibase.cpp:945
msgid "&Delete"
msgstr "&Удалить"
#: ../../../util.cpp:807
msgid "Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly."
msgstr "Внимание: пожалуйста, проверьте дату и время на вашем компьютере. Если часы идут неверно, Bitcoin не будет работать правильно."
#: ../../../uibase.h:149
msgid "Transaction Details"
msgstr "Подробности транзакции"
#: ../../../uibase.h:202
msgid "Options"
msgstr "Опции"
#: ../../../uibase.h:230
msgid "About Bitcoin"
msgstr "О Bitcoin"
#: ../../../uibase.h:340
msgid "Your Bitcoin Addresses"
msgstr "Ваш адрес Bitcoin"
#~ msgid ""
#~ "It's good policy to use a new address for each payment you receive.\n"
#~ "\n"
#~ "Label"
#~ msgstr ""
#~ "Неплохо будет использовать новый адрес для каждого получаемого платежа.\n"
#~ "\n"
#~ "Метка"
#~ msgid "Will appear as \"From: Unknown\""
#~ msgstr "Будет отображаться как \"От: Аноним\""

448
main.cpp
View File

@@ -21,7 +21,8 @@ unsigned int nTransactionsUpdated = 0;
map<COutPoint, CInPoint> mapNextTx;
map<uint256, CBlockIndex*> mapBlockIndex;
const uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1;
CBigNum bnBestChainWork = 0;
@@ -143,7 +144,7 @@ bool AddToWallet(const CWalletTx& wtxIn)
}
//// debug print
printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().substr(0,6).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().substr(0,10).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
// Write to disk
if (fInsertedNew || fUpdated)
@@ -158,7 +159,8 @@ bool AddToWallet(const CWalletTx& wtxIn)
if (txout.scriptPubKey == scriptDefaultKey)
{
CWalletDB walletdb;
walletdb.WriteDefaultKey(GenerateNewKey());
vchDefaultKey = walletdb.GetKeyFromKeyPool();
walletdb.WriteDefaultKey(vchDefaultKey);
walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
}
}
@@ -275,6 +277,34 @@ void EraseOrphanTx(uint256 hash)
// CTransaction
//
bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet)
{
SetNull();
if (!txdb.ReadTxIndex(prevout.hash, txindexRet))
return false;
if (!ReadFromDisk(txindexRet.pos))
return false;
if (prevout.n >= vout.size())
{
SetNull();
return false;
}
return true;
}
bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout)
{
CTxIndex txindex;
return ReadFromDisk(txdb, prevout, txindex);
}
bool CTransaction::ReadFromDisk(COutPoint prevout)
{
CTxDB txdb("r");
CTxIndex txindex;
return ReadFromDisk(txdb, prevout, txindex);
}
bool CTxIn::IsMine() const
{
CRITICAL_BLOCK(cs_mapWallet)
@@ -587,7 +617,7 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
{
if (pfMissingInputs)
*pfMissingInputs = true;
return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,6).c_str());
return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
}
// Store transaction in memory
@@ -606,7 +636,7 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
if (ptxOld)
EraseFromWallet(ptxOld->GetHash());
printf("AcceptToMemoryPool(): accepted %s\n", hash.ToString().substr(0,6).c_str());
printf("AcceptToMemoryPool(): accepted %s\n", hash.ToString().substr(0,10).c_str());
return true;
}
@@ -775,7 +805,7 @@ void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
uint256 hash = GetHash();
if (!txdb.ContainsTx(hash))
{
printf("Relaying wtx %s\n", hash.ToString().substr(0,6).c_str());
printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
}
}
@@ -927,7 +957,7 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits)
bool IsInitialBlockDownload()
{
if (pindexBest == NULL)
if (pindexBest == NULL || (!fTestNet && nBestHeight < 74000))
return true;
static int64 nLastUpdate;
static CBlockIndex* pindexLastBest;
@@ -985,7 +1015,8 @@ bool CTransaction::DisconnectInputs(CTxDB& txdb)
txindex.vSpent[prevout.n].SetNull();
// Write back
txdb.UpdateTxIndex(prevout.hash, txindex);
if (!txdb.UpdateTxIndex(prevout.hash, txindex))
return error("DisconnectInputs() : UpdateTxIndex failed");
}
}
@@ -1022,7 +1053,7 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPoo
fFound = txdb.ReadTxIndex(prevout.hash, txindex);
}
if (!fFound && (fBlock || fMiner))
return fMiner ? false : error("ConnectInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,6).c_str(), prevout.hash.ToString().substr(0,6).c_str());
return fMiner ? false : error("ConnectInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
// Read txPrev
CTransaction txPrev;
@@ -1032,7 +1063,7 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPoo
CRITICAL_BLOCK(cs_mapTransactions)
{
if (!mapTransactions.count(prevout.hash))
return error("ConnectInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,6).c_str(), prevout.hash.ToString().substr(0,6).c_str());
return error("ConnectInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
txPrev = mapTransactions[prevout.hash];
}
if (!fFound)
@@ -1042,11 +1073,11 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPoo
{
// Get prev tx from disk
if (!txPrev.ReadFromDisk(txindex.pos))
return error("ConnectInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,6).c_str(), prevout.hash.ToString().substr(0,6).c_str());
return error("ConnectInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
}
if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
return error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,6).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,6).c_str(), txPrev.ToString().c_str());
return error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str());
// If prev is coinbase, check that it's matured
if (txPrev.IsCoinBase())
@@ -1056,11 +1087,11 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPoo
// Verify signature
if (!VerifySignature(txPrev, *this, i))
return error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,6).c_str());
return error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
// Check for conflicts
if (!txindex.vSpent[prevout.n].IsNull())
return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,6).c_str(), txindex.vSpent[prevout.n].ToString().c_str());
return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str());
// Check for negative or overflow input values
nValueIn += txPrev.vout[prevout.n].nValue;
@@ -1072,18 +1103,23 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPoo
// Write back
if (fBlock)
txdb.UpdateTxIndex(prevout.hash, txindex);
{
if (!txdb.UpdateTxIndex(prevout.hash, txindex))
return error("ConnectInputs() : UpdateTxIndex failed");
}
else if (fMiner)
{
mapTestPool[prevout.hash] = txindex;
}
}
if (nValueIn < GetValueOut())
return error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,6).c_str());
return error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str());
// Tally transaction fees
int64 nTxFee = nValueIn - GetValueOut();
if (nTxFee < 0)
return error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,6).c_str());
return error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str());
if (nTxFee < nMinFee)
return false;
nFees += nTxFee;
@@ -1168,7 +1204,8 @@ bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex)
{
CDiskBlockIndex blockindexPrev(pindex->pprev);
blockindexPrev.hashNext = 0;
txdb.WriteBlockIndex(blockindexPrev);
if (!txdb.WriteBlockIndex(blockindexPrev))
return error("DisconnectBlock() : WriteBlockIndex failed");
}
return true;
@@ -1203,7 +1240,8 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
{
CDiskBlockIndex blockindexPrev(pindex->pprev);
blockindexPrev.hashNext = pindex->GetBlockHash();
txdb.WriteBlockIndex(blockindexPrev);
if (!txdb.WriteBlockIndex(blockindexPrev))
return error("ConnectBlock() : WriteBlockIndex failed");
}
// Watch for transactions paying to me
@@ -1282,8 +1320,9 @@ bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
if (!txdb.WriteHashBestChain(pindexNew->GetBlockHash()))
return error("Reorganize() : WriteHashBestChain failed");
// Commit now because resurrecting could take some time
txdb.TxnCommit();
// Make sure it's successfully written to disk before changing memory structure
if (!txdb.TxnCommit())
return error("Reorganize() : TxnCommit failed");
// Disconnect shorter branch
foreach(CBlockIndex* pindex, vDisconnect)
@@ -1314,8 +1353,10 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
txdb.TxnBegin();
if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)
{
pindexGenesisBlock = pindexNew;
txdb.WriteHashBestChain(hash);
if (!txdb.TxnCommit())
return error("SetBestChain() : TxnCommit failed");
pindexGenesisBlock = pindexNew;
}
else if (hashPrevBlock == hashBestChain)
{
@@ -1326,7 +1367,10 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
InvalidChainFound(pindexNew);
return error("SetBestChain() : ConnectBlock failed");
}
txdb.TxnCommit();
if (!txdb.TxnCommit())
return error("SetBestChain() : TxnCommit failed");
// Add to current best branch
pindexNew->pprev->pnext = pindexNew;
// Delete redundant memory transactions
@@ -1343,7 +1387,6 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
return error("SetBestChain() : Reorganize failed");
}
}
txdb.TxnCommit();
// New best block
hashBestChain = hash;
@@ -1473,21 +1516,13 @@ bool CBlock::AcceptBlock()
return error("AcceptBlock() : contains a non-final transaction");
// Check that the block chain matches the known block chain up to a checkpoint
if ((nHeight == 11111 && hash != uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) ||
(nHeight == 33333 && hash != uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")) ||
(nHeight == 68555 && hash != uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a")) ||
(nHeight == 70567 && hash != uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a")) ||
(nHeight == 74000 && hash != uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")))
return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight);
// Scanback checkpoint lockin
for (CBlockIndex* pindex = pindexPrev; pindex->nHeight >= 74000; pindex = pindex->pprev)
{
if (pindex->nHeight == 74000 && pindex->GetBlockHash() != uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
return error("AcceptBlock() : rejected by scanback lockin at %d", pindex->nHeight);
if (pindex->nHeight == 74638 && pindex->GetBlockHash() == uint256("0x0000000000790ab3f22ec756ad43b6ab569abf0bddeb97c67a6f7b1470a7ec1c"))
return error("AcceptBlock() : rejected by scanback lockin at %d", pindex->nHeight);
}
if (!fTestNet)
if ((nHeight == 11111 && hash != uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) ||
(nHeight == 33333 && hash != uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")) ||
(nHeight == 68555 && hash != uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a")) ||
(nHeight == 70567 && hash != uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a")) ||
(nHeight == 74000 && hash != uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")))
return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight);
// Write block to history file
if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))
@@ -1678,6 +1713,16 @@ FILE* AppendBlockFile(unsigned int& nFileRet)
bool LoadBlockIndex(bool fAllowNew)
{
if (fTestNet)
{
hashGenesisBlock = uint256("0x0000000224b1593e3ff16a0e3b61285bbc393a39f78c8aa48c456142671f7110");
bnProofOfWorkLimit = CBigNum(~uint256(0) >> 28);
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
pchMessageStart[2] = 0xb5;
pchMessageStart[3] = 0xda;
}
//
// Load block index
//
@@ -1718,13 +1763,19 @@ bool LoadBlockIndex(bool fAllowNew)
block.nBits = 0x1d00ffff;
block.nNonce = 2083236893;
//// debug print
printf("%s\n", block.GetHash().ToString().c_str());
printf("%s\n", hashGenesisBlock.ToString().c_str());
printf("%s\n", block.hashMerkleRoot.ToString().c_str());
assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
block.print();
if (fTestNet)
{
block.nTime = 1279232055;
block.nBits = 0x1d07fff8;
block.nNonce = 81622180;
}
//// debug print
printf("%s\n", block.GetHash().ToString().c_str());
printf("%s\n", hashGenesisBlock.ToString().c_str());
printf("%s\n", block.hashMerkleRoot.ToString().c_str());
assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
block.print();
assert(block.GetHash() == hashGenesisBlock);
// Start new block file
@@ -1948,7 +1999,7 @@ bool AlreadyHave(CTxDB& txdb, const CInv& inv)
{
switch (inv.type)
{
case MSG_TX: return mapTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash);
case MSG_TX: return mapTransactions.count(inv.hash) || mapOrphanTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash);
case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash);
}
// Don't know what it is, just say we already got one
@@ -1958,7 +2009,10 @@ bool AlreadyHave(CTxDB& txdb, const CInv& inv)
// The message start string is designed to be unlikely to occur in normal data.
// The characters are rarely used upper ascii, not valid as UTF-8, and produce
// a large 4-byte int at any alignment.
char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
bool ProcessMessages(CNode* pfrom)
@@ -2017,19 +2071,14 @@ bool ProcessMessages(CNode* pfrom)
if (nMessageSize > vRecv.size())
{
// Rewind and wait for rest of message
///// need a mechanism to give up waiting for overlong message size error
vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
break;
}
// Copy message to its own buffer
CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);
vRecv.ignore(nMessageSize);
// Checksum
if (vRecv.GetVersion() >= 209)
{
uint256 hash = Hash(vMsg.begin(), vMsg.end());
uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
unsigned int nChecksum = 0;
memcpy(&nChecksum, &hash, sizeof(nChecksum));
if (nChecksum != hdr.nChecksum)
@@ -2040,6 +2089,10 @@ bool ProcessMessages(CNode* pfrom)
}
}
// Copy message to its own buffer
CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);
vRecv.ignore(nMessageSize);
// Process message
bool fRet = false;
try
@@ -2126,6 +2179,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce && nNonce > 1)
{
printf("connected to self at %s, disconnecting\n", pfrom->addr.ToString().c_str());
pfrom->fDisconnect = true;
return true;
}
@@ -2146,6 +2200,24 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (pfrom->nVersion < 209)
pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
if (!pfrom->fInbound)
{
// Advertise our address
if (addrLocalHost.IsRoutable() && !fUseProxy)
{
CAddress addr(addrLocalHost);
addr.nTime = GetAdjustedTime();
pfrom->PushAddress(addr);
}
// Get recent addresses
if (pfrom->nVersion >= 31402 || mapAddresses.size() < 1000)
{
pfrom->PushMessage("getaddr");
pfrom->fGetAddr = true;
}
}
// Ask the first connected node for block updates
static int nAskedForBlocks;
if (!pfrom->fClient && (nAskedForBlocks < 1 || vNodes.size() <= 1))
@@ -2182,14 +2254,18 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
vector<CAddress> vAddr;
vRecv >> vAddr;
if (pfrom->nVersion < 200) // don't want addresses from 0.1.5
// Don't want addr from older versions unless seeding
if (pfrom->nVersion < 209)
return true;
if (pfrom->nVersion < 209 && mapAddresses.size() > 1000) // don't want addr from 0.2.0 unless seeding
if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000)
return true;
if (vAddr.size() > 1000)
return error("message addr size() = %d", vAddr.size());
// Store the new addresses
int64 nNow = GetAdjustedTime();
int64 nSince = nNow - 10 * 60;
foreach(CAddress& addr, vAddr)
{
if (fShutdown)
@@ -2197,25 +2273,33 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// ignore IPv6 for now, since it isn't implemented anyway
if (!addr.IsIPv4())
continue;
addr.nTime = GetAdjustedTime() - 2 * 60 * 60;
if (pfrom->fGetAddr || vAddr.size() > 10)
addr.nTime -= 5 * 24 * 60 * 60;
AddAddress(addr);
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60;
AddAddress(addr, 2 * 60 * 60);
pfrom->AddAddressKnown(addr);
if (!pfrom->fGetAddr && addr.IsRoutable())
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{
// Relay to a limited number of other nodes
CRITICAL_BLOCK(cs_vNodes)
{
// Use deterministic randomness to send to
// the same places for 12 hours at a time
// Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the setAddrKnowns of the chosen nodes prevent repeats
static uint256 hashSalt;
if (hashSalt == 0)
RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
uint256 hashRand = addr.ip ^ ((GetTime()+addr.ip)/(12*60*60)) ^ hashSalt;
uint256 hashRand = hashSalt ^ (((int64)addr.ip)<<32) ^ ((GetTime()+addr.ip)/(24*60*60));
hashRand = Hash(BEGIN(hashRand), END(hashRand));
multimap<uint256, CNode*> mapMix;
foreach(CNode* pnode, vNodes)
mapMix.insert(make_pair(hashRand = Hash(BEGIN(hashRand), END(hashRand)), pnode));
{
if (pnode->nVersion < 31402)
continue;
unsigned int nPointer;
memcpy(&nPointer, &pnode, sizeof(nPointer));
uint256 hashKey = hashRand ^ nPointer;
hashKey = Hash(BEGIN(hashKey), END(hashKey));
mapMix.insert(make_pair(hashKey, pnode));
}
int nRelayNodes = 2;
for (multimap<uint256, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
((*mi).second)->PushAddress(addr);
@@ -2386,7 +2470,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (tx.AcceptToMemoryPool(true))
{
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,6).c_str());
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
AddToWalletIfMine(tx, NULL);
RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv);
@@ -2400,7 +2484,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
else if (fMissingInputs)
{
printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,6).c_str());
printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
AddOrphanTx(vMsg);
}
}
@@ -2427,15 +2511,20 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
// Nodes rebroadcast an addr every 24 hours
pfrom->vAddrToSend.clear();
int64 nSince = GetAdjustedTime() - 6 * 60 * 60; // in the last 6 hours
int64 nSince = GetAdjustedTime() - 3 * 60 * 60; // in the last 3 hours
CRITICAL_BLOCK(cs_mapAddresses)
{
unsigned int nCount = 0;
foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
{
if (fShutdown)
return true;
const CAddress& addr = item.second;
if (addr.nTime > nSince)
nCount++;
}
foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
{
const CAddress& addr = item.second;
if (addr.nTime > nSince && GetRand(nCount) < 2500)
pfrom->PushAddress(addr);
}
}
@@ -2458,7 +2547,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Keep giving the same key to the same ip until they use it
if (!mapReuseKey.count(pfrom->addr.ip))
mapReuseKey[pfrom->addr.ip] = GenerateNewKey();
mapReuseKey[pfrom->addr.ip] = CWalletDB().GetKeyFromKeyPool();
// Send back approval of order and pubkey to use
CScript scriptPubKey;
@@ -2572,9 +2661,12 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty())
pto->PushMessage("ping");
// Resend wallet transactions that haven't gotten in a block yet
ResendWalletTransactions();
// Address refresh broadcast
static int64 nLastRebroadcast;
if (GetTime() - nLastRebroadcast > 24 * 60 * 60) // every 24 hours
if (GetTime() - nLastRebroadcast > 24 * 60 * 60)
{
nLastRebroadcast = GetTime();
CRITICAL_BLOCK(cs_vNodes)
@@ -2586,13 +2678,42 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// Rebroadcast our address
if (addrLocalHost.IsRoutable() && !fUseProxy)
pnode->PushAddress(addrLocalHost);
{
CAddress addr(addrLocalHost);
addr.nTime = GetAdjustedTime();
pnode->PushAddress(addr);
}
}
}
}
// Resend wallet transactions that haven't gotten in a block yet
ResendWalletTransactions();
// Clear out old addresses periodically so it's not too much work at once
static int64 nLastClear;
if (nLastClear == 0)
nLastClear = GetTime();
if (GetTime() - nLastClear > 10 * 60 && vNodes.size() >= 3)
{
nLastClear = GetTime();
CRITICAL_BLOCK(cs_mapAddresses)
{
CAddrDB addrdb;
int64 nSince = GetAdjustedTime() - 14 * 24 * 60 * 60;
for (map<vector<unsigned char>, CAddress>::iterator mi = mapAddresses.begin();
mi != mapAddresses.end();)
{
const CAddress& addr = (*mi).second;
if (addr.nTime < nSince)
{
if (mapAddresses.size() < 1000 || GetTime() > nLastClear + 20)
break;
addrdb.EraseAddress(addr);
mapAddresses.erase(mi++);
}
else
mi++;
}
}
}
//
@@ -2774,7 +2895,7 @@ void ThreadBitcoinMiner(void* parg)
vnThreadsRunning[3]--;
PrintException(NULL, "ThreadBitcoinMiner()");
}
UIThreadCall(bind(CalledSetStatusBar, "", 0));
UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
nHPSTimerStart = 0;
if (vnThreadsRunning[3] == 0)
dHashesPerSec = 0;
@@ -2789,7 +2910,7 @@ void CallCPUID(int in, int& aret, int& cret)
"mov %2, %%eax; " // in into eax
"cpuid;"
"mov %%eax, %0;" // eax into a
"mov %%ecx, %1;" // eax into c
"mov %%ecx, %1;" // ecx into c
:"=r"(a),"=r"(c) /* output */
:"r"(in) /* input */
:"%eax","%ecx" /* clobbered register */
@@ -2831,6 +2952,10 @@ bool Detect128BitSSE2()
bool fUseSSE2 = ((fIntel && nFamily * 10000 + nModel >= 60026) ||
(fAMD && nFamily * 10000 + nModel >= 160010));
// AMD reports a lower model number in 64-bit mode
if (fAMD && sizeof(void*) > 4 && nFamily * 10000 + nModel >= 160000)
fUseSSE2 = true;
static bool fPrinted;
if (!fPrinted)
{
@@ -2915,12 +3040,13 @@ void BitcoinMiner()
if (mapArgs.count("-4way"))
f4WaySSE2 = (mapArgs["-4way"] != "0");
CKey key;
key.MakeNewKey();
CBigNum bnExtraNonce = 0;
CReserveKey reservekey;
unsigned int nExtraNonce = 0;
int64 nPrevTime = 0;
while (fGenerateBitcoins)
{
Sleep(50);
if (AffinityBugWorkaround(ThreadBitcoinMiner))
return;
if (fShutdown)
return;
while (vNodes.empty() || IsInitialBlockDownload())
@@ -2943,9 +3069,15 @@ void BitcoinMiner()
CTransaction txNew;
txNew.vin.resize(1);
txNew.vin[0].prevout.SetNull();
txNew.vin[0].scriptSig << nBits << ++bnExtraNonce;
int64 nNow = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
if (++nExtraNonce >= 0x7f && nNow > nPrevTime+1)
{
nExtraNonce = 1;
nPrevTime = nNow;
}
txNew.vin[0].scriptSig << nBits << CBigNum(nExtraNonce);
txNew.vout.resize(1);
txNew.vout[0].scriptPubKey << key.GetPubKey() << OP_CHECKSIG;
txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG;
//
@@ -2964,42 +3096,97 @@ void BitcoinMiner()
CRITICAL_BLOCK(cs_mapTransactions)
{
CTxDB txdb("r");
// Priority order to process transactions
multimap<double, CTransaction*> mapPriority;
for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi)
{
CTransaction& tx = (*mi).second;
if (tx.IsCoinBase() || !tx.IsFinal())
continue;
double dPriority = 0;
foreach(const CTxIn& txin, tx.vin)
{
// Read prev transaction
CTransaction txPrev;
CTxIndex txindex;
if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex))
continue;
int64 nValueIn = txPrev.vout[txin.prevout.n].nValue;
// Read block header
int nConf = 0;
CBlock block;
if (block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
{
map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(block.GetHash());
if (it != mapBlockIndex.end())
{
CBlockIndex* pindex = (*it).second;
if (pindex->IsInMainChain())
nConf = 1 + nBestHeight - pindex->nHeight;
}
}
dPriority += (double)nValueIn * nConf;
if (fDebug && mapArgs.count("-printpriority"))
printf("priority nValueIn=%-12I64d nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority);
}
// Priority is sum(valuein * age) / txsize
dPriority /= ::GetSerializeSize(tx, SER_NETWORK);
mapPriority.insert(make_pair(-dPriority, &(*mi).second));
if (fDebug && mapArgs.count("-printpriority"))
printf("priority %-20.1f %s\n%s\n", dPriority, tx.GetHash().ToString().substr(0,10).c_str(), tx.ToString().c_str());
}
// Collect transactions into block
map<uint256, CTxIndex> mapTestPool;
vector<char> vfAlreadyAdded(mapTransactions.size());
uint64 nBlockSize = 1000;
int nBlockSigOps = 100;
bool fFoundSomething = true;
while (fFoundSomething)
{
fFoundSomething = false;
unsigned int n = 0;
for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi, ++n)
for (multimap<double, CTransaction*>::iterator mi = mapPriority.begin(); mi != mapPriority.end();)
{
if (vfAlreadyAdded[n])
continue;
CTransaction& tx = (*mi).second;
if (tx.IsCoinBase() || !tx.IsFinal())
continue;
CTransaction& tx = *(*mi).second;
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK);
if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN)
{
mapPriority.erase(mi++);
continue;
}
int nTxSigOps = tx.GetSigOpCount();
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
{
mapPriority.erase(mi++);
continue;
}
// Transaction fee based on block size
int64 nMinFee = tx.GetMinFee(nBlockSize);
// Connecting can fail due to dependency on other memory pool transactions
// that aren't in the block yet, so keep trying in later passes
map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);
if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nMinFee))
{
mi++;
continue;
}
swap(mapTestPool, mapTestPoolTmp);
// Added
pblock->vtx.push_back(tx);
nBlockSize += nTxSize;
nBlockSigOps += nTxSigOps;
vfAlreadyAdded[n] = true;
fFoundSomething = true;
mapPriority.erase(mi++);
}
}
}
@@ -3031,9 +3218,9 @@ void BitcoinMiner()
tmpworkspace& tmp = *(tmpworkspace*)alignup<16>(tmpbuf);
tmp.block.nVersion = pblock->nVersion;
tmp.block.hashPrevBlock = pblock->hashPrevBlock = (pindexPrev ? pindexPrev->GetBlockHash() : 0);
tmp.block.hashPrevBlock = pblock->hashPrevBlock = pindexPrev->GetBlockHash();
tmp.block.hashMerkleRoot = pblock->hashMerkleRoot = pblock->BuildMerkleTree();
tmp.block.nTime = pblock->nTime = max((pindexPrev ? pindexPrev->GetMedianTimePast()+1 : 0), GetAdjustedTime());
tmp.block.nTime = pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
tmp.block.nBits = pblock->nBits = nBits;
tmp.block.nNonce = pblock->nNonce = 0;
@@ -3095,10 +3282,8 @@ void BitcoinMiner()
{
if (pindexPrev == pindexBest)
{
// Save key
if (!AddKey(key))
return;
key.MakeNewKey();
// Remove key from key pool
reservekey.KeepKey();
// Track how many getdata requests this block gets
CRITICAL_BLOCK(cs_mapRequestCount)
@@ -3136,7 +3321,7 @@ void BitcoinMiner()
nHPSTimerStart = GetTimeMillis();
nHashCounter = 0;
string strStatus = strprintf(" %.0f khash/s", dHashesPerSec/1000.0);
UIThreadCall(bind(CalledSetStatusBar, strStatus, 0));
UIThreadCall(boost::bind(CalledSetStatusBar, strStatus, 0));
static int64 nLogTime;
if (GetTime() - nLogTime > 30 * 60)
{
@@ -3204,9 +3389,7 @@ int64 GetBalance()
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsFinal() || pcoin->fSpent)
continue;
if (pcoin->GetDepthInMainChain() < 1 && pcoin->GetDebit() <= 0)
if (!pcoin->IsFinal() || pcoin->fSpent || !pcoin->IsConfirmed())
continue;
nTotal += pcoin->GetCredit(true);
}
@@ -3217,7 +3400,7 @@ int64 GetBalance()
}
bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)
bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<CWalletTx*>& setCoinsRet)
{
setCoinsRet.clear();
@@ -3237,10 +3420,13 @@ bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)
foreach(CWalletTx* pcoin, vCoins)
{
if (!pcoin->IsFinal() || pcoin->fSpent)
if (!pcoin->IsFinal() || pcoin->fSpent || !pcoin->IsConfirmed())
continue;
if (pcoin->GetDepthInMainChain() < 1 && pcoin->GetDebit() <= 0)
int nDepth = pcoin->GetDepthInMainChain();
if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
continue;
int64 n = pcoin->GetCredit();
if (n <= 0)
continue;
@@ -3325,19 +3511,25 @@ bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)
return true;
}
bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CKey& keyRet, int64& nFeeRequiredRet)
bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)
{
return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet) ||
SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet) ||
SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet));
}
bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
{
nFeeRequiredRet = 0;
CRITICAL_BLOCK(cs_main)
{
// txdb must be opened before the mapWallet lock
CTxDB txdb("r");
CRITICAL_BLOCK(cs_mapWallet)
{
int64 nFee = nTransactionFee;
nFeeRet = nTransactionFee;
loop
{
wtxNew.vin.clear();
@@ -3346,7 +3538,7 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CK
if (nValue < 0)
return false;
int64 nValueOut = nValue;
int64 nTotalValue = nValue + nFee;
int64 nTotalValue = nValue + nFeeRet;
// Choose coins to use
set<CWalletTx*> setCoins;
@@ -3372,18 +3564,20 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CK
// rediscover unknown transactions that were written with keys of ours to recover
// post-backup change.
// New private key
if (keyRet.IsNull())
keyRet.MakeNewKey();
// Reserve a new key pair from key pool
vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
assert(mapKeys.count(vchPubKey));
// Fill a vout to ourself, using same address type as the payment
CScript scriptChange;
if (scriptPubKey.GetBitcoinAddressHash160() != 0)
scriptChange.SetBitcoinAddress(keyRet.GetPubKey());
scriptChange.SetBitcoinAddress(vchPubKey);
else
scriptChange << keyRet.GetPubKey() << OP_CHECKSIG;
scriptChange << vchPubKey << OP_CHECKSIG;
wtxNew.vout.push_back(CTxOut(nChange, scriptChange));
}
else
reservekey.ReturnKey();
// Fill a vout to the payee
if (fChangeFirst)
@@ -3404,13 +3598,16 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CK
return false;
// Limit size
if (::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK) >= MAX_BLOCK_SIZE_GEN/5)
unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
return false;
// Check that enough fee is included
if (nFee < wtxNew.GetMinFee())
int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
int64 nMinFee = wtxNew.GetMinFee();
if (nFeeRet < max(nPayFee, nMinFee))
{
nFee = nFeeRequiredRet = wtxNew.GetMinFee();
nFeeRet = max(nPayFee, nMinFee);
continue;
}
@@ -3426,7 +3623,7 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CK
}
// Call after CreateTransaction unless you want to abort
bool CommitTransaction(CWalletTx& wtxNew, const CKey& key)
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
{
CRITICAL_BLOCK(cs_main)
{
@@ -3438,9 +3635,8 @@ bool CommitTransaction(CWalletTx& wtxNew, const CKey& key)
// maybe makes sense; please don't do it anywhere else.
CWalletDB walletdb("r");
// Add the change's private key to wallet
if (!key.IsNull() && !AddKey(key))
throw runtime_error("CommitTransaction() : AddKey failed");
// Take key pair from key pool so it won't be used again
reservekey.KeepKey();
// Add tx to wallet, because if it has change it's also ours,
// otherwise just for transaction history.
@@ -3482,9 +3678,9 @@ string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAs
{
CRITICAL_BLOCK(cs_main)
{
CKey key;
CReserveKey reservekey;
int64 nFeeRequired;
if (!CreateTransaction(scriptPubKey, nValue, wtxNew, key, nFeeRequired))
if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
{
string strError;
if (nValue + nFeeRequired > GetBalance())
@@ -3498,7 +3694,7 @@ string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAs
if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
return "ABORTED";
if (!CommitTransaction(wtxNew, key))
if (!CommitTransaction(wtxNew, reservekey))
return _("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
}
MainFrameRepaint();

77
main.h
View File

@@ -22,7 +22,6 @@ static const int64 CENT = 1000000;
static const int64 MAX_MONEY = 21000000 * COIN;
inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
static const int COINBASE_MATURITY = 100;
static const CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
@@ -31,7 +30,8 @@ static const CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
extern CCriticalSection cs_main;
extern map<uint256, CBlockIndex*> mapBlockIndex;
extern const uint256 hashGenesisBlock;
extern uint256 hashGenesisBlock;
extern CBigNum bnProofOfWorkLimit;
extern CBlockIndex* pindexGenesisBlock;
extern int nBestHeight;
extern CBigNum bnBestChainWork;
@@ -76,8 +76,8 @@ bool ProcessMessages(CNode* pfrom);
bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv);
bool SendMessages(CNode* pto, bool fSendTrickle);
int64 GetBalance();
bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CKey& keyRet, int64& nFeeRequiredRet);
bool CommitTransaction(CWalletTx& wtxNew, const CKey& key);
bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
bool BroadcastTransaction(CWalletTx& wtxNew);
string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
@@ -195,7 +195,7 @@ public:
string ToString() const
{
return strprintf("COutPoint(%s, %d)", hash.ToString().substr(0,6).c_str(), n);
return strprintf("COutPoint(%s, %d)", hash.ToString().substr(0,10).c_str(), n);
}
void print() const
@@ -361,7 +361,7 @@ public:
{
if (scriptPubKey.size() < 6)
return "CTxOut(error)";
return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,24).c_str());
return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str());
}
void print() const
@@ -487,6 +487,11 @@ public:
return false;
}
bool IsFromMe() const
{
return (GetDebit() > 0);
}
int64 GetDebit() const
{
int64 nDebit = 0;
@@ -580,7 +585,6 @@ public:
return true;
}
friend bool operator==(const CTransaction& a, const CTransaction& b)
{
return (a.nVersion == b.nVersion &&
@@ -599,7 +603,7 @@ public:
{
string str;
str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n",
GetHash().ToString().substr(0,6).c_str(),
GetHash().ToString().substr(0,10).c_str(),
nVersion,
vin.size(),
vout.size(),
@@ -617,6 +621,9 @@ public:
}
bool ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet);
bool ReadFromDisk(CTxDB& txdb, COutPoint prevout);
bool ReadFromDisk(COutPoint prevout);
bool DisconnectInputs(CTxDB& txdb);
bool ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0);
@@ -787,6 +794,52 @@ public:
return nCreditCached;
}
bool IsFromMe() const
{
return (GetDebit() > 0);
}
bool IsConfirmed() const
{
// Quick answer in most cases
if (!IsFinal())
return false;
if (GetDepthInMainChain() >= 1)
return true;
if (!IsFromMe()) // using wtx's cached debit
return false;
// If no confirmations but it's from us, we can still
// consider it confirmed if all dependencies are confirmed
map<uint256, const CMerkleTx*> mapPrev;
vector<const CMerkleTx*> vWorkQueue;
vWorkQueue.reserve(vtxPrev.size()+1);
vWorkQueue.push_back(this);
for (int i = 0; i < vWorkQueue.size(); i++)
{
const CMerkleTx* ptx = vWorkQueue[i];
if (!ptx->IsFinal())
return false;
if (ptx->GetDepthInMainChain() >= 1)
return true;
if (!ptx->IsFromMe())
return false;
if (mapPrev.empty())
foreach(const CMerkleTx& tx, vtxPrev)
mapPrev[tx.GetHash()] = &tx;
foreach(const CTxIn& txin, ptx->vin)
{
if (!mapPrev.count(txin.prevout.hash))
return false;
vWorkQueue.push_back(mapPrev[txin.prevout.hash]);
}
}
return true;
}
bool WriteToDisk()
{
return CWalletDB().WriteTx(GetHash(), *this);
@@ -1065,7 +1118,7 @@ public:
GetHash().ToString().substr(0,20).c_str(),
nVersion,
hashPrevBlock.ToString().substr(0,20).c_str(),
hashMerkleRoot.ToString().substr(0,6).c_str(),
hashMerkleRoot.ToString().substr(0,10).c_str(),
nTime, nBits, nNonce,
vtx.size());
for (int i = 0; i < vtx.size(); i++)
@@ -1075,7 +1128,7 @@ public:
}
printf(" vMerkleTree: ");
for (int i = 0; i < vMerkleTree.size(); i++)
printf("%s ", vMerkleTree[i].ToString().substr(0,6).c_str());
printf("%s ", vMerkleTree[i].ToString().substr(0,10).c_str());
printf("\n");
}
@@ -1233,7 +1286,7 @@ public:
{
return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)",
pprev, pnext, nFile, nBlockPos, nHeight,
hashMerkleRoot.ToString().substr(0,6).c_str(),
hashMerkleRoot.ToString().substr(0,10).c_str(),
GetBlockHash().ToString().substr(0,20).c_str());
}
@@ -1623,7 +1676,7 @@ public:
bool Cancels(const CAlert& alert) const
{
if (!IsInEffect())
false;
return false; // this was a no-op before 31403
return (alert.nID <= nCancel || setCancel.count(alert.nID));
}

View File

@@ -22,9 +22,10 @@ LIBS= -dead_strip \
$(DEPSDIR)/lib/libboost_filesystem.a \
$(DEPSDIR)/lib/libboost_program_options.a \
$(DEPSDIR)/lib/libboost_thread.a \
$(DEPSDIR)/lib/libssl.a \
$(DEPSDIR)/lib/libcrypto.a
DEFS=$(shell $(DEPSDIR)/bin/wx-config --cxxflags) -D__WXMAC_OSX__ -DNOPCH -DMSG_NOSIGNAL=0
DEFS=$(shell $(DEPSDIR)/bin/wx-config --cxxflags) -D__WXMAC_OSX__ -DNOPCH -DMSG_NOSIGNAL=0 -DUSE_SSL
DEBUGFLAGS=-g -DwxDEBUG_LEVEL=0
# ppc doesn't work because we don't support big-endian

View File

@@ -23,11 +23,14 @@ LIBS= \
-l boost_program_options \
-l boost_thread \
-l db_cxx \
-l ssl \
-l crypto \
-Wl,-Bdynamic \
-l gthread-2.0
-l gthread-2.0 \
-l z \
-l dl
DEFS=-D__WXGTK__ -DNOPCH -DFOURWAYSSE2
DEFS=-D__WXGTK__ -DNOPCH -DFOURWAYSSE2 -DUSE_SSL
DEBUGFLAGS=-g -D__WXDEBUG__
CFLAGS=-O2 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \

39
net.cpp
View File

@@ -20,7 +20,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect);
//
bool fClient = false;
uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
CAddress addrLocalHost(0, DEFAULT_PORT, nLocalServices);
CAddress addrLocalHost(0, 0, nLocalServices);
CNode* pnodeLocalHost = NULL;
uint64 nLocalHostNonce = 0;
array<int, 10> vnThreadsRunning;
@@ -144,7 +144,7 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha
}
}
closesocket(hSocket);
if (strLine.find("<"))
if (strLine.find("<") != -1)
strLine = strLine.substr(0, strLine.find("<"));
strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
@@ -224,12 +224,13 @@ bool GetMyExternalIP(unsigned int& ipRet)
bool AddAddress(CAddress addr)
bool AddAddress(CAddress addr, int64 nTimePenalty)
{
if (!addr.IsRoutable())
return false;
if (addr.ip == addrLocalHost.ip)
return false;
addr.nTime = max((int64)0, (int64)addr.nTime - nTimePenalty);
CRITICAL_BLOCK(cs_mapAddresses)
{
map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
@@ -937,7 +938,7 @@ void ThreadOpenConnections2(void* parg)
// Add seed nodes if IRC isn't working
static bool fSeedUsed;
bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR))
if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
{
for (int i = 0; i < ARRAYLEN(pnSeed); i++)
{
@@ -1006,7 +1007,7 @@ void ThreadOpenConnections2(void* parg)
// 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 (addr.port != DEFAULT_PORT)
if (addr.port != GetDefaultPort())
nRandomizer += 2 * 60 * 60;
// Last seen Base retry frequency
@@ -1073,25 +1074,6 @@ bool OpenNetworkConnection(const CAddress& addrConnect)
return false;
pnode->fNetworkNode = true;
if (addrLocalHost.IsRoutable() && !fUseProxy)
{
// Advertise our address
vector<CAddress> vAddr;
vAddr.push_back(addrLocalHost);
pnode->PushMessage("addr", vAddr);
}
// Get as many addresses as we can
pnode->PushMessage("getaddr");
pnode->fGetAddr = true; // don't relay the results of the getaddr
////// should the one on the receiving end do this too?
// Subscribe our local subscription list
const unsigned int nHops = 0;
for (unsigned int nChannel = 0; nChannel < pnodeLocalHost->vfSubscribe.size(); nChannel++)
if (pnodeLocalHost->vfSubscribe[nChannel])
pnode->PushMessage("subscribe", nChannel, nHops);
return true;
}
@@ -1185,6 +1167,7 @@ bool BindListenPort(string& strError)
{
strError = "";
int nOne = 1;
addrLocalHost.port = GetDefaultPort();
#ifdef __WXMSW__
// Initialize Windows Sockets
@@ -1236,12 +1219,12 @@ bool BindListenPort(string& strError)
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer
sockaddr.sin_port = DEFAULT_PORT;
sockaddr.sin_port = GetDefaultPort();
if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
if (nErr == WSAEADDRINUSE)
strError = strprintf("Unable to bind to port %d on this computer. Bitcoin is probably already running.", ntohs(sockaddr.sin_port));
strError = strprintf(_("Unable to bind to port %d on this computer. Bitcoin is probably already running."), ntohs(sockaddr.sin_port));
else
strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr);
printf("%s\n", strError.c_str());
@@ -1278,7 +1261,7 @@ void StartNode(void* parg)
printf("host ip %d: %s\n", i, CAddress(*(unsigned int*)phostent->h_addr_list[i]).ToStringIP().c_str());
for (int i = 0; phostent->h_addr_list[i] != NULL; i++)
{
CAddress addr(*(unsigned int*)phostent->h_addr_list[i], DEFAULT_PORT, nLocalServices);
CAddress addr(*(unsigned int*)phostent->h_addr_list[i], GetDefaultPort(), nLocalServices);
if (addr.IsValid() && addr.GetByte(3) != 127)
{
addrLocalHost = addr;
@@ -1306,7 +1289,7 @@ void StartNode(void* parg)
printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
// Take the first IP that isn't loopback 127.x.x.x
CAddress addr(*(unsigned int*)&s4->sin_addr, DEFAULT_PORT, nLocalServices);
CAddress addr(*(unsigned int*)&s4->sin_addr, GetDefaultPort(), nLocalServices);
if (addr.IsValid() && addr.GetByte(3) != 127)
{
addrLocalHost = addr;

35
net.h
View File

@@ -12,7 +12,7 @@ extern int nBestHeight;
static const unsigned short DEFAULT_PORT = 0x8d20; // htons(8333)
inline unsigned short GetDefaultPort() { return fTestNet ? htons(18333) : htons(8333); }
static const unsigned int PUBLISH_HOPS = 5;
enum
{
@@ -24,7 +24,7 @@ enum
bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet);
bool GetMyExternalIP(unsigned int& ipRet);
bool AddAddress(CAddress addr);
bool AddAddress(CAddress addr, int64 nTimePenalty=0);
void AddressCurrentlyConnected(const CAddress& addr);
CNode* FindNode(unsigned int ip);
CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
@@ -48,10 +48,7 @@ bool StopNode();
// (4) size
// (4) checksum
// The message start string is designed to be unlikely to occur in normal data.
// The characters are rarely used upper ascii, not valid as UTF-8, and produce
// a large 4-byte int at any alignment.
static const char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
extern char pchMessageStart[4];
class CMessageHeader
{
@@ -142,7 +139,7 @@ public:
unsigned int ip;
unsigned short port;
// disk only
// disk and network only
unsigned int nTime;
// memory only
@@ -153,11 +150,11 @@ public:
Init();
}
CAddress(unsigned int ipIn, unsigned short portIn=DEFAULT_PORT, uint64 nServicesIn=NODE_NETWORK)
CAddress(unsigned int ipIn, unsigned short portIn=0, uint64 nServicesIn=NODE_NETWORK)
{
Init();
ip = ipIn;
port = portIn;
port = (portIn == 0 ? GetDefaultPort() : portIn);
nServices = nServicesIn;
}
@@ -188,15 +185,15 @@ public:
nServices = NODE_NETWORK;
memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
ip = INADDR_NONE;
port = DEFAULT_PORT;
nTime = GetAdjustedTime();
port = GetDefaultPort();
nTime = 100000000;
nLastTry = 0;
}
bool SetAddress(const char* pszIn)
{
ip = INADDR_NONE;
port = DEFAULT_PORT;
port = GetDefaultPort();
char psz[100];
strlcpy(psz, pszIn, sizeof(psz));
unsigned int a=0, b=0, c=0, d=0, e=0;
@@ -221,11 +218,12 @@ public:
IMPLEMENT_SERIALIZE
(
if (fRead)
const_cast<CAddress*>(this)->Init();
if (nType & SER_DISK)
{
READWRITE(nVersion);
if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH)))
READWRITE(nTime);
}
READWRITE(nServices);
READWRITE(FLATDATA(pchReserved)); // for IPv6
READWRITE(ip);
@@ -418,7 +416,7 @@ public:
const char* GetCommand() const
{
if (!IsKnownType())
throw std::out_of_range(strprintf("CInv::GetCommand() : type=% unknown type", type));
throw std::out_of_range(strprintf("CInv::GetCommand() : type=%d unknown type", type));
return ppszTypeName[type];
}
@@ -735,13 +733,6 @@ public:
AbortMessage();
}
const char* GetMessageCommand() const
{
if (nHeaderStart == -1)
return "";
return &vSend[nHeaderStart] + offsetof(CMessageHeader, pchCommand);
}

183
rpc.cpp
View File

@@ -5,6 +5,12 @@
#include "headers.h"
#undef printf
#include <boost/asio.hpp>
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
#ifdef USE_SSL
#include <boost/asio/ssl.hpp>
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
#endif
#include "json/json_spirit_reader_template.h"
#include "json/json_spirit_writer_template.h"
#include "json/json_spirit_utils.h"
@@ -14,7 +20,7 @@
// a certain size around 145MB. If we need access to json_spirit outside this
// file, we could use the compiled json_spirit option.
using boost::asio::ip::tcp;
using namespace boost::asio;
using namespace json_spirit;
void ThreadRPCServer2(void* parg);
@@ -255,6 +261,9 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
obj.push_back(Pair("testnet", fTestNet));
obj.push_back(Pair("keypoololdest", (boost::int64_t)CWalletDB().GetOldestKeyPoolTime()));
obj.push_back(Pair("paytxfee", (double)nTransactionFee / (double)COIN));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
return obj;
}
@@ -275,7 +284,7 @@ Value getnewaddress(const Array& params, bool fHelp)
strLabel = params[0].get_str();
// Generate a new key that is added to wallet
string strAddress = PubKeyToAddress(GenerateNewKey());
string strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool());
SetAddressBookName(strAddress, strLabel);
return strAddress;
@@ -649,6 +658,28 @@ Value backupwallet(const Array& params, bool fHelp)
}
Value validateaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"validateaddress <bitcoinaddress>\n"
"Return information about <bitcoinaddress>.");
string strAddress = params[0].get_str();
uint160 hash160;
bool isValid = AddressToHash160(strAddress, hash160);
Object ret;
ret.push_back(Pair("isvalid", isValid));
if (isValid)
{
// Call Hash160ToAddress() so we always return current ADDRESSVERSION
// version of the address:
ret.push_back(Pair("address", Hash160ToAddress(hash160)));
ret.push_back(Pair("ismine", (mapPubKeys.count(hash160) > 0)));
}
return ret;
}
@@ -689,6 +720,7 @@ pair<string, rpcfn_type> pCallTable[] =
make_pair("listreceivedbyaddress", &listreceivedbyaddress),
make_pair("listreceivedbylabel", &listreceivedbylabel),
make_pair("backupwallet", &backupwallet),
make_pair("validateaddress", &validateaddress),
};
map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
@@ -709,6 +741,7 @@ string pAllowInSafeMode[] =
"getlabel",
"getaddressesbylabel",
"backupwallet",
"validateaddress",
};
set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
@@ -738,12 +771,22 @@ string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeader
return s.str();
}
string rfc1123Time()
{
char buffer[32];
time_t now;
time(&now);
struct tm* now_gmt = gmtime(&now);
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S %Z", now_gmt);
return string(buffer);
}
string HTTPReply(int nStatus, const string& strMsg)
{
if (nStatus == 401)
return "HTTP/1.0 401 Authorization Required\r\n"
"Server: HTTPd/1.0\r\n"
"Date: Sat, 08 Jul 2006 12:04:08 GMT\r\n"
return strprintf("HTTP/1.0 401 Authorization Required\r\n"
"Date: %s\r\n"
"Server: bitcoin-json-rpc\r\n"
"WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 311\r\n"
@@ -756,7 +799,7 @@ string HTTPReply(int nStatus, const string& strMsg)
"<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
"</HEAD>\r\n"
"<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
"</HTML>\r\n";
"</HTML>\r\n", rfc1123Time().c_str());
string strStatus;
if (nStatus == 200) strStatus = "OK";
else if (nStatus == 400) strStatus = "Bad Request";
@@ -764,20 +807,21 @@ string HTTPReply(int nStatus, const string& strMsg)
else if (nStatus == 500) strStatus = "Internal Server Error";
return strprintf(
"HTTP/1.1 %d %s\r\n"
"Date: %s\r\n"
"Connection: close\r\n"
"Content-Length: %d\r\n"
"Content-Type: application/json\r\n"
"Date: Sat, 08 Jul 2006 12:04:08 GMT\r\n"
"Server: json-rpc/1.0\r\n"
"Server: bitcoin-json-rpc/1.0\r\n"
"\r\n"
"%s",
nStatus,
strStatus.c_str(),
rfc1123Time().c_str(),
strMsg.size(),
strMsg.c_str());
}
int ReadHTTPStatus(tcp::iostream& stream)
int ReadHTTPStatus(std::basic_istream<char>& stream)
{
string str;
getline(stream, str);
@@ -788,7 +832,7 @@ int ReadHTTPStatus(tcp::iostream& stream)
return atoi(vWords[1].c_str());
}
int ReadHTTPHeader(tcp::iostream& stream, map<string, string>& mapHeadersRet)
int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
{
int nLen = 0;
loop
@@ -812,7 +856,7 @@ int ReadHTTPHeader(tcp::iostream& stream, map<string, string>& mapHeadersRet)
return nLen;
}
int ReadHTTP(tcp::iostream& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
{
mapHeadersRet.clear();
strMessageRet = "";
@@ -930,8 +974,59 @@ bool ClientAllowed(const string& strAddress)
return false;
}
#ifdef USE_SSL
//
// IOStream device that speaks SSL but can also speak non-SSL
//
class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
public:
SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
{
fUseSSL = fUseSSLIn;
fNeedHandshake = fUseSSLIn;
}
void handshake(ssl::stream_base::handshake_type role)
{
if (!fNeedHandshake) return;
fNeedHandshake = false;
stream.handshake(role);
}
std::streamsize read(char* s, std::streamsize n)
{
handshake(ssl::stream_base::server); // HTTPS servers read first
if (fUseSSL) return stream.read_some(asio::buffer(s, n));
return stream.next_layer().read_some(asio::buffer(s, n));
}
std::streamsize write(const char* s, std::streamsize n)
{
handshake(ssl::stream_base::client); // HTTPS clients write first
if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
return asio::write(stream.next_layer(), asio::buffer(s, n));
}
bool connect(const std::string& server, const std::string& port)
{
ip::tcp::resolver resolver(stream.get_io_service());
ip::tcp::resolver::query query(server.c_str(), port.c_str());
ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
ip::tcp::resolver::iterator end;
boost::system::error_code error = asio::error::host_not_found;
while (error && endpoint_iterator != end)
{
stream.lowest_layer().close();
stream.lowest_layer().connect(*endpoint_iterator++, error);
}
if (error)
return false;
return true;
}
private:
bool fNeedHandshake;
bool fUseSSL;
SSLStream& stream;
};
#endif
void ThreadRPCServer(void* parg)
{
@@ -972,18 +1067,54 @@ void ThreadRPCServer2(void* parg)
return;
}
// Bind to loopback 127.0.0.1 so the socket can only be accessed locally
boost::asio::io_service io_service;
tcp::endpoint endpoint(mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback(), 8332);
tcp::acceptor acceptor(io_service, endpoint);
bool fUseSSL = (mapArgs.count("-rpcssl") > 0);
asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
asio::io_service io_service;
ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
ip::tcp::acceptor acceptor(io_service, endpoint);
#ifdef USE_SSL
ssl::context context(io_service, ssl::context::sslv23);
if (fUseSSL)
{
context.set_options(ssl::context::no_sslv2);
filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
string ciphers = GetArg("-rpcsslciphers",
"TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
}
#else
if (fUseSSL)
throw runtime_error("-rpcssl=true, but bitcoin compiled without full openssl libraries.");
#endif
loop
{
// Accept connection
tcp::iostream stream;
tcp::endpoint peer;
#ifdef USE_SSL
SSLStream sslStream(io_service, context);
SSLIOStreamDevice d(sslStream, fUseSSL);
iostreams::stream<SSLIOStreamDevice> stream(d);
#else
ip::tcp::iostream stream;
#endif
ip::tcp::endpoint peer;
vnThreadsRunning[4]--;
#ifdef USE_SSL
acceptor.accept(sslStream.lowest_layer(), peer);
#else
acceptor.accept(*stream.rdbuf(), peer);
#endif
vnThreadsRunning[4]++;
if (fShutdown)
return;
@@ -1102,9 +1233,25 @@ Object CallRPC(const string& strMethod, const Array& params)
GetConfigFile().c_str()));
// Connect to localhost
tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), "8332");
bool fUseSSL = (mapArgs.count("-rpcssl") > 0);
#ifdef USE_SSL
asio::io_service io_service;
ssl::context context(io_service, ssl::context::sslv23);
context.set_options(ssl::context::no_sslv2);
SSLStream sslStream(io_service, context);
SSLIOStreamDevice d(sslStream, fUseSSL);
iostreams::stream<SSLIOStreamDevice> stream(d);
if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
throw runtime_error("couldn't connect to server");
#else
if (fUseSSL)
throw runtime_error("-rpcssl=true, but bitcoin compiled without full openssl libraries.");
ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
if (stream.fail())
throw runtime_error("couldn't connect to server");
#endif
// HTTP basic authentication
string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);

View File

@@ -776,16 +776,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
return false;
int nKeysCount = CastToBigNum(stacktop(-i)).getint();
if (nKeysCount < 0)
if (nKeysCount < 0 || nKeysCount > 20)
return false;
nOpCount += nKeysCount;
if (nOpCount > 201)
return false;
if (nBestHeight > 84000)
{
if (nKeysCount > 20)
return false;
nOpCount += nKeysCount;
if (nOpCount > 201)
return false;
}
int ikey = ++i;
i += nKeysCount;
if (stack.size() < i)

View File

@@ -22,7 +22,7 @@ class CDataStream;
class CAutoFile;
static const unsigned int MAX_SIZE = 0x02000000;
static const int VERSION = 31300;
static const int VERSION = 31500;
static const char* pszSubVer = "";
@@ -725,39 +725,39 @@ public:
typedef vector_type::const_iterator const_iterator;
typedef vector_type::reverse_iterator reverse_iterator;
explicit CDataStream(int nTypeIn=0, int nVersionIn=VERSION)
explicit CDataStream(int nTypeIn=SER_NETWORK, int nVersionIn=VERSION)
{
Init(nTypeIn, nVersionIn);
}
CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn=0, int nVersionIn=VERSION) : vch(pbegin, pend)
CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn=SER_NETWORK, int nVersionIn=VERSION) : vch(pbegin, pend)
{
Init(nTypeIn, nVersionIn);
}
#if !defined(_MSC_VER) || _MSC_VER >= 1300
CDataStream(const char* pbegin, const char* pend, int nTypeIn=0, int nVersionIn=VERSION) : vch(pbegin, pend)
CDataStream(const char* pbegin, const char* pend, int nTypeIn=SER_NETWORK, int nVersionIn=VERSION) : vch(pbegin, pend)
{
Init(nTypeIn, nVersionIn);
}
#endif
CDataStream(const vector_type& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end())
CDataStream(const vector_type& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end())
{
Init(nTypeIn, nVersionIn);
}
CDataStream(const vector<char>& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end())
CDataStream(const vector<char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end())
{
Init(nTypeIn, nVersionIn);
}
CDataStream(const vector<unsigned char>& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0])
CDataStream(const vector<unsigned char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=VERSION) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0])
{
Init(nTypeIn, nVersionIn);
}
void Init(int nTypeIn=0, int nVersionIn=VERSION)
void Init(int nTypeIn=SER_NETWORK, int nVersionIn=VERSION)
{
nReadPos = 0;
nType = nTypeIn;

View File

@@ -7,7 +7,7 @@ RequestExecutionLevel highest
# General Symbol Definitions
!define REGKEY "SOFTWARE\$(^Name)"
!define VERSION 0.3.13
!define VERSION 0.3.15
!define COMPANY "Bitcoin project"
!define URL http://www.bitcoin.org/
@@ -42,12 +42,12 @@ Var StartMenuGroup
!insertmacro MUI_LANGUAGE English
# Installer attributes
OutFile bitcoin-0.3.13-win32-setup.exe
OutFile bitcoin-0.3.15-win32-setup.exe
InstallDir $PROGRAMFILES\Bitcoin
CRCCheck on
XPStyle on
ShowInstDetails show
VIProductVersion 0.3.13.0
VIProductVersion 0.3.15.0
VIAddVersionKey ProductName Bitcoin
VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}"

166
ui.cpp
View File

@@ -196,7 +196,7 @@ int ThreadSafeMessageBox(const string& message, const string& caption, int style
bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent)
{
if (nFeeRequired < CENT || fDaemon)
if (nFeeRequired < CENT || nFeeRequired <= nTransactionFee || fDaemon)
return true;
string strMessage = strprintf(
_("This transaction is over the size limit. You can still send it for a fee of %s, "
@@ -502,10 +502,9 @@ bool CMainFrame::DeleteLine(uint256 hashKey)
return nIndex != -1;
}
string FormatTxStatus(const CWalletTx& wtx, bool& fConfirmed)
string FormatTxStatus(const CWalletTx& wtx)
{
// Status
fConfirmed = false;
if (!wtx.IsFinal())
{
if (wtx.nLockTime < 500000000)
@@ -516,8 +515,6 @@ string FormatTxStatus(const CWalletTx& wtx, bool& fConfirmed)
else
{
int nDepth = wtx.GetDepthInMainChain();
if (nDepth >= 1 || wtx.GetDebit() > 0)
fConfirmed = true;
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
return strprintf(_("%d/offline?"), nDepth);
else if (nDepth < 6)
@@ -527,12 +524,6 @@ string FormatTxStatus(const CWalletTx& wtx, bool& fConfirmed)
}
}
string FormatTxStatus(const CWalletTx& wtx)
{
bool fConfirmed;
return FormatTxStatus(wtx, fConfirmed);
}
string SingleLine(const string& strIn)
{
string strOut;
@@ -561,9 +552,8 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
int64 nDebit = wtx.GetDebit();
int64 nNet = nCredit - nDebit;
uint256 hash = wtx.GetHash();
bool fConfirmed;
string strStatus = FormatTxStatus(wtx, fConfirmed);
wtx.fConfirmedDisplayed = fConfirmed;
string strStatus = FormatTxStatus(wtx);
bool fConfirmed = wtx.fConfirmedDisplayed = wtx.IsConfirmed();
wxColour colour = (fConfirmed ? wxColour(0,0,0) : wxColour(128,128,128));
map<string, string> mapValue = wtx.mapValue;
wtx.nLinesDisplayed = 1;
@@ -773,6 +763,7 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
SingleLine(strDescription),
FormatMoney(-nValue, true),
"");
nIndex = -1;
wtx.nLinesDisplayed++;
}
}
@@ -914,16 +905,16 @@ void CMainFrame::RefreshStatusColumn()
continue;
}
CWalletTx& wtx = (*mi).second;
bool fConfirmed;
string strStatus = FormatTxStatus(wtx, fConfirmed);
if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed || fConfirmed != wtx.fConfirmedDisplayed)
if (wtx.IsCoinBase() ||
wtx.GetTxTime() != wtx.nTimeDisplayed ||
wtx.IsConfirmed() != wtx.fConfirmedDisplayed)
{
if (!InsertTransaction(wtx, false, nIndex))
m_listCtrl->DeleteItem(nIndex--);
}
else
{
m_listCtrl->SetItem(nIndex, 2, strStatus);
m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
}
}
}
@@ -1180,7 +1171,7 @@ void CMainFrame::OnButtonNew(wxCommandEvent& event)
string strName = dialog.GetValue();
// Generate new key
string strAddress = PubKeyToAddress(GenerateNewKey());
string strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool());
// Save
SetAddressBookName(strAddress, strName);
@@ -1435,7 +1426,10 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
if (txout.IsMine())
strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
strHTML += "<b>Inputs:</b><br>";
strHTML += "<br><b>Transaction:</b><br>";
strHTML += HtmlEscape(wtx.ToString(), true);
strHTML += "<br><b>Inputs:</b><br>";
CRITICAL_BLOCK(cs_mapWallet)
{
foreach(const CTxIn& txin, wtx.vin)
@@ -1454,9 +1448,6 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
}
}
}
strHTML += "<br><hr><br><b>Transaction:</b><br>";
strHTML += HtmlEscape(wtx.ToString(), true);
}
@@ -1938,69 +1929,78 @@ void CSendDialog::OnButtonPaste(wxCommandEvent& event)
void CSendDialog::OnButtonSend(wxCommandEvent& event)
{
CWalletTx wtx;
string strAddress = (string)m_textCtrlAddress->GetValue();
static CCriticalSection cs_sendlock;
TRY_CRITICAL_BLOCK(cs_sendlock)
{
CWalletTx wtx;
string strAddress = (string)m_textCtrlAddress->GetValue();
// Parse amount
int64 nValue = 0;
if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
{
wxMessageBox(_("Error in amount "), _("Send Coins"));
return;
}
if (nValue > GetBalance())
{
wxMessageBox(_("Amount exceeds your balance "), _("Send Coins"));
return;
}
if (nValue + nTransactionFee > GetBalance())
{
wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included "), _("Send Coins"));
return;
}
// Parse bitcoin address
uint160 hash160;
bool fBitcoinAddress = AddressToHash160(strAddress, hash160);
if (fBitcoinAddress)
{
// Send to bitcoin address
CScript scriptPubKey;
scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
string strError = SendMoney(scriptPubKey, nValue, wtx, true);
if (strError == "")
wxMessageBox(_("Payment sent "), _("Sending..."));
else if (strError != "ABORTED")
wxMessageBox(strError + " ", _("Sending..."));
}
else
{
// Parse IP address
CAddress addr(strAddress);
if (!addr.IsValid())
// Parse amount
int64 nValue = 0;
if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
{
wxMessageBox(_("Invalid address "), _("Send Coins"));
wxMessageBox(_("Error in amount "), _("Send Coins"));
return;
}
if (nValue > GetBalance())
{
wxMessageBox(_("Amount exceeds your balance "), _("Send Coins"));
return;
}
if (nValue + nTransactionFee > GetBalance())
{
wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included "), _("Send Coins"));
return;
}
// Message
wtx.mapValue["to"] = strAddress;
wtx.mapValue["from"] = m_textCtrlFrom->GetValue();
wtx.mapValue["message"] = m_textCtrlMessage->GetValue();
// Parse bitcoin address
uint160 hash160;
bool fBitcoinAddress = AddressToHash160(strAddress, hash160);
// Send to IP address
CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
if (!pdialog->ShowModal())
return;
if (fBitcoinAddress)
{
// Send to bitcoin address
CScript scriptPubKey;
scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
string strError = SendMoney(scriptPubKey, nValue, wtx, true);
if (strError == "")
wxMessageBox(_("Payment sent "), _("Sending..."));
else if (strError == "ABORTED")
return; // leave send dialog open
else
{
wxMessageBox(strError + " ", _("Sending..."));
EndModal(false);
}
}
else
{
// Parse IP address
CAddress addr(strAddress);
if (!addr.IsValid())
{
wxMessageBox(_("Invalid address "), _("Send Coins"));
return;
}
// Message
wtx.mapValue["to"] = strAddress;
wtx.mapValue["from"] = m_textCtrlFrom->GetValue();
wtx.mapValue["message"] = m_textCtrlMessage->GetValue();
// Send to IP address
CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
if (!pdialog->ShowModal())
return;
}
CRITICAL_BLOCK(cs_mapAddressBook)
if (!mapAddressBook.count(strAddress))
SetAddressBookName(strAddress, "");
EndModal(true);
}
CRITICAL_BLOCK(cs_mapAddressBook)
if (!mapAddressBook.count(strAddress))
SetAddressBookName(strAddress, "");
EndModal(true);
}
void CSendDialog::OnButtonCancel(wxCommandEvent& event)
@@ -2255,9 +2255,9 @@ void CSendingDialog::OnReply2(CDataStream& vRecv)
Error(_("Insufficient funds"));
return;
}
CKey key;
CReserveKey reservekey;
int64 nFeeRequired;
if (!CreateTransaction(scriptPubKey, nPrice, wtx, key, nFeeRequired))
if (!CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired))
{
if (nPrice + nFeeRequired > GetBalance())
Error(strprintf(_("This is an oversized transaction that requires a transaction fee of %s"), FormatMoney(nFeeRequired).c_str()));
@@ -2297,7 +2297,7 @@ void CSendingDialog::OnReply2(CDataStream& vRecv)
return;
// Commit
if (!CommitTransaction(wtx, key))
if (!CommitTransaction(wtx, reservekey))
{
Error(_("The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."));
return;
@@ -2575,7 +2575,7 @@ void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
strName = dialog.GetValue();
// Generate new key
strAddress = PubKeyToAddress(GenerateNewKey());
strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool());
}
// Add to list and select it

View File

@@ -16,6 +16,7 @@ bool fShutdown = false;
bool fDaemon = false;
bool fCommandLine = false;
string strMiscWarning;
bool fTestNet = false;
@@ -572,7 +573,7 @@ void PrintExceptionContinue(std::exception* pex, const char* pszThread)
strMiscWarning = pszMessage;
#ifdef GUI
if (wxTheApp && !fDaemon)
boost::thread(bind(ThreadOneMessageBox, string(pszMessage)));
boost::thread(boost::bind(ThreadOneMessageBox, string(pszMessage)));
#endif
}
@@ -649,15 +650,11 @@ string GetDefaultDataDir()
void GetDataDir(char* pszDir)
{
// pszDir must be at least MAX_PATH length.
int nVariation;
if (pszSetDataDir[0] != 0)
{
strlcpy(pszDir, pszSetDataDir, MAX_PATH);
static bool fMkdirDone;
if (!fMkdirDone)
{
fMkdirDone = true;
filesystem::create_directory(pszDir);
}
nVariation = 0;
}
else
{
@@ -665,11 +662,23 @@ void GetDataDir(char* pszDir)
// value so we don't have to do memory allocations after that.
static char pszCachedDir[MAX_PATH];
if (pszCachedDir[0] == 0)
{
strlcpy(pszCachedDir, GetDefaultDataDir().c_str(), sizeof(pszCachedDir));
filesystem::create_directory(pszCachedDir);
}
strlcpy(pszDir, pszCachedDir, MAX_PATH);
nVariation = 1;
}
if (fTestNet)
{
char* p = pszDir + strlen(pszDir);
if (p > pszDir && p[-1] != '/' && p[-1] != '\\')
*p++ = '/';
strcpy(p, "testnet");
nVariation += 2;
}
static bool pfMkdir[4];
if (!pfMkdir[nVariation])
{
pfMkdir[nVariation] = true;
filesystem::create_directory(pszDir);
}
}
@@ -807,7 +816,7 @@ void AddTimeData(unsigned int ip, int64 nTime)
string strMessage = _("Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly.");
strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str());
boost::thread(bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1));
boost::thread(boost::bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1));
}
}
foreach(int64 n, vTimeOffsets)

25
util.h
View File

@@ -145,6 +145,7 @@ extern bool fShutdown;
extern bool fDaemon;
extern bool fCommandLine;
extern string strMiscWarning;
extern bool fTestNet;
void RandAddSeed();
void RandAddSeedPerfmon();
@@ -621,3 +622,27 @@ inline void ExitThread(unsigned int nExitCode)
pthread_exit((void*)nExitCode);
}
#endif
inline bool AffinityBugWorkaround(void(*pfn)(void*))
{
#ifdef __WXMSW__
// Sometimes after a few hours affinity gets stuck on one processor
DWORD dwProcessAffinityMask = -1;
DWORD dwSystemAffinityMask = -1;
GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask);
DWORD dwPrev1 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
DWORD dwPrev2 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
if (dwPrev2 != dwProcessAffinityMask)
{
printf("AffinityBugWorkaround() : SetThreadAffinityMask=%d, ProcessAffinityMask=%d, restarting thread\n", dwPrev2, dwProcessAffinityMask);
if (!CreateThread(pfn, NULL))
printf("Error: CreateThread() failed\n");
return true;
}
#endif
return false;
}