Browse Source

better prevention of inventory relaying during initial download,

message checksum between nodes with 0.2.9 or higher,
optimization level up from -O0 to -O2,
rpc functions: setlabel, getlabel, getaddressesbylabel, getreceivedbyaddress, getreceivedbylabel, listreceivedbyaddress, listreceivedbylabel
 -- version 0.2.9

git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@78 1a98c847-1fd6-4fd8-948a-caf3550aa51b
miguelfreitas
s_nakamoto 15 years ago
parent
commit
42605ce8bc
  1. 2
      db.h
  2. 7
      init.cpp
  3. 76
      main.cpp
  4. 2
      makefile.mingw
  5. 2
      makefile.unix
  6. 30
      net.h
  7. 267
      rpc.cpp
  8. 14
      serialize.h
  9. 9
      ui.cpp
  10. 9
      ui.h
  11. 2
      uibase.h
  12. 2
      uiproject.fbp
  13. 5
      util.cpp

2
db.h

@ -328,6 +328,8 @@ public:
bool EraseName(const string& strAddress) bool EraseName(const string& strAddress)
{ {
// This should only be used for sending addresses, never for receiving addresses,
// receiving addresses must always have an address book entry if they're not change return.
CRITICAL_BLOCK(cs_mapAddressBook) CRITICAL_BLOCK(cs_mapAddressBook)
mapAddressBook.erase(strAddress); mapAddressBook.erase(strAddress);
nWalletDBUpdated++; nWalletDBUpdated++;

7
init.cpp

@ -224,9 +224,6 @@ bool CMyApp::Initialize(int& argc, wxChar** argv)
} }
} }
if (fDaemon)
fprintf(stdout, "bitcoin server starting\n");
#ifdef __WXGTK__ #ifdef __WXGTK__
if (fDaemon || fCommandLine) if (fDaemon || fCommandLine)
{ {
@ -447,7 +444,8 @@ bool CMyApp::OnInit2()
// //
// Load data files // Load data files
// //
bool fFirstRun; if (fDaemon)
fprintf(stdout, "bitcoin server starting\n");
strErrors = ""; strErrors = "";
int64 nStart; int64 nStart;
@ -465,6 +463,7 @@ bool CMyApp::OnInit2()
printf("Loading wallet...\n"); printf("Loading wallet...\n");
nStart = GetTimeMillis(); nStart = GetTimeMillis();
bool fFirstRun;
if (!LoadWallet(fFirstRun)) if (!LoadWallet(fFirstRun))
strErrors += _("Error loading wallet.dat \n"); strErrors += _("Error loading wallet.dat \n");
printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart); printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);

76
main.cpp

@ -1336,19 +1336,12 @@ bool CBlock::AcceptBlock()
if (!AddToBlockIndex(nFile, nBlockPos)) if (!AddToBlockIndex(nFile, nBlockPos))
return error("AcceptBlock() : AddToBlockIndex failed"); return error("AcceptBlock() : AddToBlockIndex failed");
// Don't relay old inventory during initial block download. // Relay inventory, but don't relay old inventory during initial block download
// Please keep this number updated to a few thousand below current block count. if (hashBestChain == hash)
if (hashBestChain == hash && nBestHeight > 55000) CRITICAL_BLOCK(cs_vNodes)
RelayInventory(CInv(MSG_BLOCK, hash)); foreach(CNode* pnode, vNodes)
if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 55000))
// // Add atoms to user reviews for coins created pnode->PushInventory(CInv(MSG_BLOCK, hash));
// vector<unsigned char> vchPubKey;
// if (ExtractPubKey(vtx[0].vout[0].scriptPubKey, false, vchPubKey))
// {
// unsigned short nAtom = GetRand(USHRT_MAX - 100) + 100;
// vector<unsigned short> vAtoms(1, nAtom);
// AddAtomsAndPropagate(Hash(vchPubKey.begin(), vchPubKey.end()), vAtoms, true);
// }
return true; return true;
} }
@ -1721,6 +1714,7 @@ bool ProcessMessages(CNode* pfrom)
// (4) message start // (4) message start
// (12) command // (12) command
// (4) size // (4) size
// (4) checksum
// (x) data // (x) data
// //
@ -1728,12 +1722,13 @@ bool ProcessMessages(CNode* pfrom)
{ {
// Scan for message start // Scan for message start
CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart)); CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart));
if (vRecv.end() - pstart < sizeof(CMessageHeader)) int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
if (vRecv.end() - pstart < nHeaderSize)
{ {
if (vRecv.size() > sizeof(CMessageHeader)) if (vRecv.size() > nHeaderSize)
{ {
printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n"); printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
vRecv.erase(vRecv.begin(), vRecv.end() - sizeof(CMessageHeader)); vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
} }
break; break;
} }
@ -1742,6 +1737,7 @@ bool ProcessMessages(CNode* pfrom)
vRecv.erase(vRecv.begin(), pstart); vRecv.erase(vRecv.begin(), pstart);
// Read header // Read header
vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize);
CMessageHeader hdr; CMessageHeader hdr;
vRecv >> hdr; vRecv >> hdr;
if (!hdr.IsValid()) if (!hdr.IsValid())
@ -1757,10 +1753,9 @@ bool ProcessMessages(CNode* pfrom)
{ {
// Rewind and wait for rest of message // Rewind and wait for rest of message
///// need a mechanism to give up waiting for overlong message size error ///// need a mechanism to give up waiting for overlong message size error
//if (fDebug) if (fDebug)
// printf("message-break\n"); printf("message-break\n");
vRecv.insert(vRecv.begin(), BEGIN(hdr), END(hdr)); vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
Sleep(100);
break; break;
} }
@ -1768,6 +1763,20 @@ bool ProcessMessages(CNode* pfrom)
CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion); CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);
vRecv.ignore(nMessageSize); vRecv.ignore(nMessageSize);
// Checksum
if (vRecv.GetVersion() >= 209)
{
uint256 hash = Hash(vMsg.begin(), vMsg.end());
unsigned int nChecksum = 0;
memcpy(&nChecksum, &hash, sizeof(nChecksum));
if (nChecksum != hdr.nChecksum)
{
printf("ProcessMessage(%s, %d bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
continue;
}
}
// Process message // Process message
bool fRet = false; bool fRet = false;
try try
@ -1844,6 +1853,9 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vRecv >> addrFrom >> nNonce; vRecv >> addrFrom >> nNonce;
if (pfrom->nVersion >= 106 && !vRecv.empty()) if (pfrom->nVersion >= 106 && !vRecv.empty())
vRecv >> strSubVer; vRecv >> strSubVer;
if (pfrom->nVersion >= 209 && !vRecv.empty())
vRecv >> pfrom->nStartingHeight;
if (pfrom->nVersion == 0) if (pfrom->nVersion == 0)
return false; return false;
@ -1854,9 +1866,6 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return true; return true;
} }
pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION));
pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
pfrom->fClient = !(pfrom->nServices & NODE_NETWORK); pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
if (pfrom->fClient) if (pfrom->fClient)
{ {
@ -1866,6 +1875,13 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
AddTimeData(pfrom->addr.ip, nTime); AddTimeData(pfrom->addr.ip, nTime);
// Change version
if (pfrom->nVersion >= 209)
pfrom->PushMessage("verack");
pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION));
if (pfrom->nVersion < 209)
pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
// Ask the first connected node for block updates // Ask the first connected node for block updates
static bool fAskedForBlocks; static bool fAskedForBlocks;
if (!fAskedForBlocks && !pfrom->fClient) if (!fAskedForBlocks && !pfrom->fClient)
@ -1876,7 +1892,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fSuccessfullyConnected = true; pfrom->fSuccessfullyConnected = true;
printf("version message: version %d\n", pfrom->nVersion); printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
} }
@ -1887,6 +1903,12 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
} }
else if (strCommand == "verack")
{
pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
}
else if (strCommand == "addr") else if (strCommand == "addr")
{ {
vector<CAddress> vAddr; vector<CAddress> vAddr;
@ -2101,9 +2123,8 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vRecv >> *pblock; vRecv >> *pblock;
//// debug print //// debug print
// printf("received block:\n");
// pblock->print();
printf("received block %s\n", pblock->GetHash().ToString().substr(0,16).c_str()); printf("received block %s\n", pblock->GetHash().ToString().substr(0,16).c_str());
// pblock->print();
CInv inv(MSG_BLOCK, pblock->GetHash()); CInv inv(MSG_BLOCK, pblock->GetHash());
pfrom->AddInventoryKnown(inv); pfrom->AddInventoryKnown(inv);
@ -2388,8 +2409,11 @@ void GenerateBitcoins(bool fGenerate)
int nAddThreads = nProcessors - vnThreadsRunning[3]; int nAddThreads = nProcessors - vnThreadsRunning[3];
printf("Starting %d BitcoinMiner threads\n", nAddThreads); printf("Starting %d BitcoinMiner threads\n", nAddThreads);
for (int i = 0; i < nAddThreads; i++) for (int i = 0; i < nAddThreads; i++)
{
if (!CreateThread(ThreadBitcoinMiner, NULL)) if (!CreateThread(ThreadBitcoinMiner, NULL))
printf("Error: CreateThread(ThreadBitcoinMiner) failed\n"); printf("Error: CreateThread(ThreadBitcoinMiner) failed\n");
Sleep(10);
}
} }
} }

2
makefile.mingw

@ -29,7 +29,7 @@ LIBS= \
WXDEFS=-DWIN32 -D__WXMSW__ -D_WINDOWS -DNOPCH WXDEFS=-DWIN32 -D__WXMSW__ -D_WINDOWS -DNOPCH
DEBUGFLAGS=-g -D__WXDEBUG__ DEBUGFLAGS=-g -D__WXDEBUG__
CFLAGS=-mthreads -O0 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS) CFLAGS=-mthreads -O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \ HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
script.h db.h net.h irc.h main.h rpc.h uibase.h ui.h init.h sha.h script.h db.h net.h irc.h main.h rpc.h uibase.h ui.h init.h sha.h

2
makefile.unix

@ -29,7 +29,7 @@ LIBS= \
WXDEFS=-D__WXGTK__ -DNOPCH WXDEFS=-D__WXGTK__ -DNOPCH
DEBUGFLAGS=-g -D__WXDEBUG__ DEBUGFLAGS=-g -D__WXDEBUG__
CFLAGS=-O0 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS) CFLAGS=-O2 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \ HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
script.h db.h net.h irc.h main.h rpc.h uibase.h ui.h init.h sha.h script.h db.h net.h irc.h main.h rpc.h uibase.h ui.h init.h sha.h

30
net.h

@ -8,6 +8,7 @@ class CInv;
class CRequestTracker; class CRequestTracker;
class CNode; class CNode;
class CBlockIndex; class CBlockIndex;
extern int nBestHeight;
@ -59,7 +60,7 @@ public:
char pchMessageStart[sizeof(::pchMessageStart)]; char pchMessageStart[sizeof(::pchMessageStart)];
char pchCommand[COMMAND_SIZE]; char pchCommand[COMMAND_SIZE];
unsigned int nMessageSize; unsigned int nMessageSize;
//unsigned int nChecksum; unsigned int nChecksum;
CMessageHeader() CMessageHeader()
{ {
@ -67,7 +68,7 @@ public:
memset(pchCommand, 0, sizeof(pchCommand)); memset(pchCommand, 0, sizeof(pchCommand));
pchCommand[1] = 1; pchCommand[1] = 1;
nMessageSize = -1; nMessageSize = -1;
//nChecksum = 0; nChecksum = 0;
} }
CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn) CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
@ -75,6 +76,7 @@ public:
memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
strncpy(pchCommand, pszCommand, COMMAND_SIZE); strncpy(pchCommand, pszCommand, COMMAND_SIZE);
nMessageSize = nMessageSizeIn; nMessageSize = nMessageSizeIn;
nChecksum = 0;
} }
IMPLEMENT_SERIALIZE IMPLEMENT_SERIALIZE
@ -82,8 +84,8 @@ public:
READWRITE(FLATDATA(pchMessageStart)); READWRITE(FLATDATA(pchMessageStart));
READWRITE(FLATDATA(pchCommand)); READWRITE(FLATDATA(pchCommand));
READWRITE(nMessageSize); READWRITE(nMessageSize);
//if (nVersion >= 209 && GetCommand() != "version") if (nVersion >= 209)
// READWRITE(nChecksum); READWRITE(nChecksum);
) )
string GetCommand() string GetCommand()
@ -475,6 +477,7 @@ extern CAddress addrProxy;
class CNode class CNode
{ {
public: public:
@ -507,6 +510,7 @@ public:
uint256 hashContinue; uint256 hashContinue;
CBlockIndex* pindexLastGetBlocksBegin; CBlockIndex* pindexLastGetBlocksBegin;
uint256 hashLastGetBlocksEnd; uint256 hashLastGetBlocksEnd;
int nStartingHeight;
// flood // flood
vector<CAddress> vAddrToSend; vector<CAddress> vAddrToSend;
@ -529,7 +533,9 @@ public:
nServices = 0; nServices = 0;
hSocket = hSocketIn; hSocket = hSocketIn;
vSend.SetType(SER_NETWORK); vSend.SetType(SER_NETWORK);
vSend.SetVersion(0);
vRecv.SetType(SER_NETWORK); vRecv.SetType(SER_NETWORK);
vRecv.SetVersion(0);
nLastSend = 0; nLastSend = 0;
nLastRecv = 0; nLastRecv = 0;
nLastSendEmpty = GetTime(); nLastSendEmpty = GetTime();
@ -548,6 +554,7 @@ public:
hashContinue = 0; hashContinue = 0;
pindexLastGetBlocksBegin = 0; pindexLastGetBlocksBegin = 0;
hashLastGetBlocksEnd = 0; hashLastGetBlocksEnd = 0;
nStartingHeight = -1;
fGetAddr = false; fGetAddr = false;
nNextSendTxInv = 0; nNextSendTxInv = 0;
vfSubscribe.assign(256, false); vfSubscribe.assign(256, false);
@ -558,7 +565,8 @@ public:
CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr); CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost); CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);
RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce, string(pszSubVer)); PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, string(pszSubVer), nBestHeight);
} }
~CNode() ~CNode()
@ -680,10 +688,20 @@ public:
if (nHeaderStart == -1) if (nHeaderStart == -1)
return; return;
// Patch in the size // Set the size
unsigned int nSize = vSend.size() - nMessageStart; unsigned int nSize = vSend.size() - nMessageStart;
memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize)); memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize));
// Set the checksum
if (vSend.GetVersion() >= 209)
{
uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
unsigned int nChecksum = 0;
memcpy(&nChecksum, &hash, sizeof(nChecksum));
assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));
memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));
}
printf("(%d bytes) ", nSize); printf("(%d bytes) ", nSize);
printf("\n"); printf("\n");

267
rpc.cpp

@ -26,7 +26,7 @@ void ThreadRPCServer2(void* parg);
/// ///
/// Note: I'm not finished designing this interface, it's still subject to change. /// Note: This interface may still be subject to change.
/// ///
@ -188,6 +188,73 @@ Value getnewaddress(const Array& params)
} }
Value setlabel(const Array& params)
{
if (params.size() < 1 || params.size() > 2)
throw runtime_error(
"setlabel <bitcoinaddress> <label>\n"
"Sets the label associated with the given address.");
string strAddress = params[0].get_str();
string strLabel;
if (params.size() > 1)
strLabel = params[1].get_str();
SetAddressBookName(strAddress, strLabel);
return Value::null;
}
Value getlabel(const Array& params)
{
if (params.size() != 1)
throw runtime_error(
"getlabel <bitcoinaddress>\n"
"Returns the label associated with the given address.");
string strAddress = params[0].get_str();
string strLabel;
CRITICAL_BLOCK(cs_mapAddressBook)
{
map<string, string>::iterator mi = mapAddressBook.find(strAddress);
if (mi != mapAddressBook.end() && !(*mi).second.empty())
strLabel = (*mi).second;
}
return strLabel;
}
Value getaddressesbylabel(const Array& params)
{
if (params.size() != 1)
throw runtime_error(
"getaddressesbylabel <label>\n"
"Returns the list of addresses with the given label.");
string strLabel = params[0].get_str();
// Find all addresses that have the given label
Array ret;
CRITICAL_BLOCK(cs_mapAddressBook)
{
foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
{
const string& strAddress = item.first;
const string& strName = item.second;
if (strName == strLabel)
{
// We're only adding valid bitcoin addresses and not ip addresses
CScript scriptPubKey;
if (scriptPubKey.SetBitcoinAddress(strAddress))
ret.push_back(strAddress);
}
}
}
return ret;
}
Value sendtoaddress(const Array& params) Value sendtoaddress(const Array& params)
{ {
if (params.size() < 2 || params.size() > 4) if (params.size() < 2 || params.size() > 4)
@ -237,11 +304,11 @@ Value listtransactions(const Array& params)
} }
Value getamountreceived(const Array& params) Value getreceivedbyaddress(const Array& params)
{ {
if (params.size() < 1 || params.size() > 2) if (params.size() < 1 || params.size() > 2)
throw runtime_error( throw runtime_error(
"getamountreceived <bitcoinaddress> [minconf=1]\n" "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
"Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations."); "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
// Bitcoin address // Bitcoin address
@ -249,6 +316,8 @@ Value getamountreceived(const Array& params)
CScript scriptPubKey; CScript scriptPubKey;
if (!scriptPubKey.SetBitcoinAddress(strAddress)) if (!scriptPubKey.SetBitcoinAddress(strAddress))
throw runtime_error("Invalid bitcoin address"); throw runtime_error("Invalid bitcoin address");
if (!IsMine(scriptPubKey))
return (double)0.0;
// Minimum confirmations // Minimum confirmations
int nMinDepth = 1; int nMinDepth = 1;
@ -276,6 +345,59 @@ Value getamountreceived(const Array& params)
} }
Value getreceivedbylabel(const Array& params)
{
if (params.size() < 1 || params.size() > 2)
throw runtime_error(
"getreceivedbylabel <label> [minconf=1]\n"
"Returns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.");
// Get the set of pub keys that have the label
string strLabel = params[0].get_str();
set<CScript> setPubKey;
CRITICAL_BLOCK(cs_mapAddressBook)
{
foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
{
const string& strAddress = item.first;
const string& strName = item.second;
if (strName == strLabel)
{
// We're only counting our own valid bitcoin addresses and not ip addresses
CScript scriptPubKey;
if (scriptPubKey.SetBitcoinAddress(strAddress))
if (IsMine(scriptPubKey))
setPubKey.insert(scriptPubKey);
}
}
}
// Minimum confirmations
int nMinDepth = 1;
if (params.size() > 1)
nMinDepth = params[1].get_int();
// Tally
int64 nAmount = 0;
CRITICAL_BLOCK(cs_mapWallet)
{
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal())
continue;
foreach(const CTxOut& txout, wtx.vout)
if (setPubKey.count(txout.scriptPubKey))
if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue;
}
}
return (double)nAmount / (double)COIN;
}
struct tallyitem struct tallyitem
{ {
int64 nAmount; int64 nAmount;
@ -287,23 +409,18 @@ struct tallyitem
} }
}; };
Value getallreceived(const Array& params) Value ListReceived(const Array& params, bool fByLabels)
{ {
if (params.size() > 1)
throw runtime_error(
"getallreceived [minconf=1]\n"
"[minconf] is the minimum number of confirmations before payments are included.\n"
"Returns an array of objects containing:\n"
" \"address\" : receiving address\n"
" \"amount\" : total amount received by the address\n"
" \"confirmations\" : number of confirmations of the most recent transaction included\n"
" \"label\" : the label of the receiving address");
// Minimum confirmations // Minimum confirmations
int nMinDepth = 1; int nMinDepth = 1;
if (params.size() > 0) if (params.size() > 0)
nMinDepth = params[0].get_int(); nMinDepth = params[0].get_int();
// Whether to include empty accounts
bool fIncludeEmpty = false;
if (params.size() > 1)
fIncludeEmpty = params[1].get_bool();
// Tally // Tally
map<uint160, tallyitem> mapTally; map<uint160, tallyitem> mapTally;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
@ -318,18 +435,11 @@ Value getallreceived(const Array& params)
if (nDepth < nMinDepth) if (nDepth < nMinDepth)
continue; continue;
// Filter out debits and payments to self, which may have change return
// we don't want to count.
int64 nCredit = wtx.GetCredit(true);
int64 nDebit = wtx.GetDebit();
int64 nNet = nCredit - nDebit;
if (nNet <= 0)
continue;
foreach(const CTxOut& txout, wtx.vout) foreach(const CTxOut& txout, wtx.vout)
{ {
// Only counting our own bitcoin addresses and not ip addresses
uint160 hash160 = txout.scriptPubKey.GetBitcoinAddressHash160(); uint160 hash160 = txout.scriptPubKey.GetBitcoinAddressHash160();
if (hash160 == 0 || !mapPubKeys.count(hash160)) if (hash160 == 0 || !mapPubKeys.count(hash160)) // IsMine
continue; continue;
tallyitem& item = mapTally[hash160]; tallyitem& item = mapTally[hash160];
@ -341,27 +451,100 @@ Value getallreceived(const Array& params)
// Reply // Reply
Array ret; Array ret;
map<string, tallyitem> mapLabelTally;
CRITICAL_BLOCK(cs_mapAddressBook) CRITICAL_BLOCK(cs_mapAddressBook)
{ {
for (map<uint160, tallyitem>::iterator it = mapTally.begin(); it != mapTally.end(); ++it) foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
{ {
string strAddress = Hash160ToAddress((*it).first); const string& strAddress = item.first;
string strLabel; const string& strLabel = item.second;
map<string, string>::iterator mi = mapAddressBook.find(strAddress); uint160 hash160;
if (mi != mapAddressBook.end()) if (!AddressToHash160(strAddress, hash160))
strLabel = (*mi).second; continue;
map<uint160, tallyitem>::iterator it = mapTally.find(hash160);
if (it == mapTally.end() && !fIncludeEmpty)
continue;
int64 nAmount = 0;
int nConf = INT_MAX;
if (it != mapTally.end())
{
nAmount = (*it).second.nAmount;
nConf = (*it).second.nConf;
}
if (fByLabels)
{
tallyitem& item = mapLabelTally[strLabel];
item.nAmount += nAmount;
item.nConf = min(item.nConf, nConf);
}
else
{
Object obj; Object obj;
obj.push_back(Pair("address", strAddress)); obj.push_back(Pair("address", strAddress));
obj.push_back(Pair("amount", (double)(*it).second.nAmount / (double)COIN));
obj.push_back(Pair("confirmations", (*it).second.nConf));
obj.push_back(Pair("label", strLabel)); obj.push_back(Pair("label", strLabel));
obj.push_back(Pair("amount", (double)nAmount / (double)COIN));
obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
ret.push_back(obj);
}
}
}
if (fByLabels)
{
for (map<string, tallyitem>::iterator it = mapLabelTally.begin(); it != mapLabelTally.end(); ++it)
{
int64 nAmount = (*it).second.nAmount;
int nConf = (*it).second.nConf;
Object obj;
obj.push_back(Pair("label", (*it).first));
obj.push_back(Pair("amount", (double)nAmount / (double)COIN));
obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
ret.push_back(obj); ret.push_back(obj);
} }
} }
return ret; return ret;
} }
Value listreceivedbyaddress(const Array& params)
{
if (params.size() > 2)
throw runtime_error(
"listreceivedbyaddress [minconf=1] [includeempty=false]\n"
"[minconf] is the minimum number of confirmations before payments are included.\n"
"[includeempty] whether to include addresses that haven't received any payments.\n"
"Returns an array of objects containing:\n"
" \"address\" : receiving address\n"
" \"label\" : the label of the receiving address\n"
" \"amount\" : total amount received by the address\n"
" \"confirmations\" : number of confirmations of the most recent transaction included");
return ListReceived(params, false);
}
Value listreceivedbylabel(const Array& params)
{
if (params.size() > 2)
throw runtime_error(
"listreceivedbylabel [minconf=1] [includeempty=false]\n"
"[minconf] is the minimum number of confirmations before payments are included.\n"
"[includeempty] whether to include labels that haven't received any payments.\n"
"Returns an array of objects containing:\n"
" \"label\" : the label of the receiving addresses\n"
" \"amount\" : total amount received by addresses with this label\n"
" \"confirmations\" : number of confirmations of the most recent transaction included");
return ListReceived(params, true);
}
@ -385,10 +568,17 @@ pair<string, rpcfn_type> pCallTable[] =
make_pair("setgenerate", &setgenerate), make_pair("setgenerate", &setgenerate),
make_pair("getinfo", &getinfo), make_pair("getinfo", &getinfo),
make_pair("getnewaddress", &getnewaddress), make_pair("getnewaddress", &getnewaddress),
make_pair("setlabel", &setlabel),
make_pair("getlabel", &getlabel),
make_pair("getaddressesbylabel", &getaddressesbylabel),
make_pair("sendtoaddress", &sendtoaddress), make_pair("sendtoaddress", &sendtoaddress),
make_pair("listtransactions", &listtransactions), make_pair("listtransactions", &listtransactions),
make_pair("getamountreceived", &getamountreceived), make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
make_pair("getallreceived", &getallreceived), make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
make_pair("getreceivedbyaddress", &getreceivedbyaddress),
make_pair("getreceivedbylabel", &getreceivedbylabel),
make_pair("listreceivedbyaddress", &listreceivedbyaddress),
make_pair("listreceivedbylabel", &listreceivedbylabel),
}; };
map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0])); map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
@ -671,8 +861,15 @@ int CommandLineRPC(int argc, char *argv[])
if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]); if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
if (strMethod == "listtransactions" && n > 0) ConvertTo<boost::int64_t>(params[0]); if (strMethod == "listtransactions" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listtransactions" && n > 1) ConvertTo<bool>(params[1]); if (strMethod == "listtransactions" && n > 1) ConvertTo<bool>(params[1]);
if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]);
if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]);
// Execute // Execute
Value result = CallRPC(strMethod, params); Value result = CallRPC(strMethod, params);

14
serialize.h

@ -19,7 +19,7 @@ class CScript;
class CDataStream; class CDataStream;
class CAutoFile; class CAutoFile;
static const int VERSION = 208; static const int VERSION = 209;
static const char* pszSubVer = ".0"; static const char* pszSubVer = ".0";
@ -809,6 +809,18 @@ public:
vch.insert(it, first, last); vch.insert(it, first, last);
} }
void insert(iterator it, vector<char>::const_iterator first, vector<char>::const_iterator last)
{
if (it == vch.begin() + nReadPos && last - first <= nReadPos)
{
// special case for inserting at the front when there's room
nReadPos -= (last - first);
memcpy(&vch[nReadPos], &first[0], last - first);
}
else
vch.insert(it, first, last);
}
#if !defined(_MSC_VER) || _MSC_VER >= 1300 #if !defined(_MSC_VER) || _MSC_VER >= 1300
void insert(iterator it, const char* first, const char* last) void insert(iterator it, const char* first, const char* last)
{ {

9
ui.cpp

@ -193,6 +193,12 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* pa
return (ThreadSafeMessageBox(strMessage, strCaption, wxYES_NO, parent) == wxYES); return (ThreadSafeMessageBox(strMessage, strCaption, wxYES_NO, parent) == wxYES);
} }
void CalledSetStatusBar(const string& strText, int nField)
{
if (pframeMain && pframeMain->m_statusBar)
pframeMain->m_statusBar->SetStatusText(strText, nField);
}
void SetDefaultReceivingAddress(const string& strAddress) void SetDefaultReceivingAddress(const string& strAddress)
{ {
// Update main window address and database // Update main window address and database
@ -268,7 +274,8 @@ CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
if (!strstr(DateTimeStr(1229413914).c_str(), "2008")) if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))
nDateWidth += 12; nDateWidth += 12;
#ifdef __WXMAC__ #ifdef __WXMAC__
nDateWidth += 2; nDateWidth += 5;
dResize -= 0.01;
#endif #endif
wxListCtrl* pplistCtrl[] = {m_listCtrlAll, m_listCtrlSentReceived, m_listCtrlSent, m_listCtrlReceived}; wxListCtrl* pplistCtrl[] = {m_listCtrlAll, m_listCtrlSentReceived, m_listCtrlSent, m_listCtrlReceived};
foreach(wxListCtrl* p, pplistCtrl) foreach(wxListCtrl* p, pplistCtrl)

9
ui.h

@ -30,6 +30,7 @@ string FormatTxStatus(const CWalletTx& wtx);
void UIThreadCall(boost::function0<void>); void UIThreadCall(boost::function0<void>);
int ThreadSafeMessageBox(const string& message, const string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1); int ThreadSafeMessageBox(const string& message, const string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1);
bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent); bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent);
void CalledSetStatusBar(const string& strText, int nField);
void MainFrameRepaint(); void MainFrameRepaint();
void CreateMainWindow(); void CreateMainWindow();
@ -48,6 +49,14 @@ inline bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWin
return true; return true;
} }
inline void CalledSetStatusBar(const string& strText, int nField)
{
}
inline void UIThreadCall(boost::function0<void> fn)
{
}
inline void MainFrameRepaint() inline void MainFrameRepaint()
{ {
} }

2
uibase.h

@ -77,7 +77,6 @@ class CMainFrameBase : public wxFrame
wxMenu* m_menuFile; wxMenu* m_menuFile;
wxMenu* m_menuHelp; wxMenu* m_menuHelp;
wxToolBar* m_toolBar; wxToolBar* m_toolBar;
wxStatusBar* m_statusBar;
wxStaticText* m_staticText32; wxStaticText* m_staticText32;
wxButton* m_buttonNew; wxButton* m_buttonNew;
@ -121,6 +120,7 @@ class CMainFrameBase : public wxFrame
public: public:
wxMenu* m_menuOptions; wxMenu* m_menuOptions;
wxStatusBar* m_statusBar;
wxTextCtrl* m_textCtrlAddress; wxTextCtrl* m_textCtrlAddress;
wxListCtrl* m_listCtrlAll; wxListCtrl* m_listCtrlAll;
wxListCtrl* m_listCtrlSentReceived; wxListCtrl* m_listCtrlSentReceived;

2
uiproject.fbp

@ -293,7 +293,7 @@
<property name="maximum_size"></property> <property name="maximum_size"></property>
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">m_statusBar</property> <property name="name">m_statusBar</property>
<property name="permission">protected</property> <property name="permission">public</property>
<property name="pos"></property> <property name="pos"></property>
<property name="size"></property> <property name="size"></property>
<property name="style">wxST_SIZEGRIP</property> <property name="style">wxST_SIZEGRIP</property>

5
util.cpp

@ -250,11 +250,6 @@ string strprintf(const char* format, ...)
if (p == NULL) if (p == NULL)
throw std::bad_alloc(); throw std::bad_alloc();
} }
#ifdef _MSC_VER
// msvc optimisation
if (p == buffer)
return string(p, p+ret);
#endif
string str(p, p+ret); string str(p, p+ret);
if (p != buffer) if (p != buffer)
delete p; delete p;

Loading…
Cancel
Save