Merge remote branch 'refs/remotes/svn/trunk' into svn
This commit is contained in:
commit
55c43da5d8
10 changed files with 329 additions and 155 deletions
16
db.cpp
16
db.cpp
|
@ -592,9 +592,9 @@ bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
|
||||||
return Write(make_pair(string("acc"), strAccount), account);
|
return Write(make_pair(string("acc"), strAccount), account);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletDB::WriteAccountingEntry(const string& strAccount, const CAccountingEntry& acentry)
|
bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
|
||||||
{
|
{
|
||||||
return Write(make_tuple(string("acentry"), strAccount, ++nAccountingEntryNumber), acentry);
|
return Write(make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
|
int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
|
||||||
|
@ -613,6 +613,8 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
|
||||||
{
|
{
|
||||||
int64 nCreditDebit = 0;
|
int64 nCreditDebit = 0;
|
||||||
|
|
||||||
|
bool fAllAccounts = (strAccount == "*");
|
||||||
|
|
||||||
Dbc* pcursor = GetCursor();
|
Dbc* pcursor = GetCursor();
|
||||||
if (!pcursor)
|
if (!pcursor)
|
||||||
throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
|
throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
|
||||||
|
@ -622,7 +624,7 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
|
||||||
// Read next record
|
// Read next record
|
||||||
CDataStream ssKey;
|
CDataStream ssKey;
|
||||||
if (fFlags == DB_SET_RANGE)
|
if (fFlags == DB_SET_RANGE)
|
||||||
ssKey << make_tuple(string("acentry"), strAccount, uint64(0));
|
ssKey << make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0));
|
||||||
CDataStream ssValue;
|
CDataStream ssValue;
|
||||||
int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
|
int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
|
||||||
fFlags = DB_NEXT;
|
fFlags = DB_NEXT;
|
||||||
|
@ -639,12 +641,11 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
|
||||||
ssKey >> strType;
|
ssKey >> strType;
|
||||||
if (strType != "acentry")
|
if (strType != "acentry")
|
||||||
break;
|
break;
|
||||||
string strAccountName;
|
CAccountingEntry acentry;
|
||||||
ssKey >> strAccountName;
|
ssKey >> acentry.strAccount;
|
||||||
if (strAccountName != strAccount)
|
if (!fAllAccounts && acentry.strAccount != strAccount)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
CAccountingEntry acentry;
|
|
||||||
ssValue >> acentry;
|
ssValue >> acentry;
|
||||||
entries.push_back(acentry);
|
entries.push_back(acentry);
|
||||||
}
|
}
|
||||||
|
@ -652,6 +653,7 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
|
||||||
pcursor->close();
|
pcursor->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CWalletDB::LoadWallet()
|
bool CWalletDB::LoadWallet()
|
||||||
{
|
{
|
||||||
vchDefaultKey.clear();
|
vchDefaultKey.clear();
|
||||||
|
|
2
db.h
2
db.h
|
@ -433,7 +433,7 @@ public:
|
||||||
|
|
||||||
bool ReadAccount(const string& strAccount, CAccount& account);
|
bool ReadAccount(const string& strAccount, CAccount& account);
|
||||||
bool WriteAccount(const string& strAccount, const CAccount& account);
|
bool WriteAccount(const string& strAccount, const CAccount& account);
|
||||||
bool WriteAccountingEntry(const string& strAccount, const CAccountingEntry& acentry);
|
bool WriteAccountingEntry(const CAccountingEntry& acentry);
|
||||||
int64 GetAccountCreditDebit(const string& strAccount);
|
int64 GetAccountCreditDebit(const string& strAccount);
|
||||||
void ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& acentries);
|
void ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& acentries);
|
||||||
|
|
||||||
|
|
10
irc.cpp
10
irc.cpp
|
@ -5,6 +5,7 @@
|
||||||
#include "headers.h"
|
#include "headers.h"
|
||||||
|
|
||||||
int nGotIRCAddresses = 0;
|
int nGotIRCAddresses = 0;
|
||||||
|
bool fGotExternalIP = false;
|
||||||
|
|
||||||
void ThreadIRCSeed2(void* parg);
|
void ThreadIRCSeed2(void* parg);
|
||||||
|
|
||||||
|
@ -223,6 +224,8 @@ bool GetIPFromIRC(SOCKET hSocket, string strMyName, unsigned int& ipRet)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Hybrid IRC used by lfnet always returns IP when you userhost yourself,
|
||||||
|
// but in case another IRC is ever used this should work.
|
||||||
printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
|
printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
|
||||||
if (fUseProxy)
|
if (fUseProxy)
|
||||||
return false;
|
return false;
|
||||||
|
@ -327,14 +330,15 @@ void ThreadIRCSeed2(void* parg)
|
||||||
}
|
}
|
||||||
Sleep(500);
|
Sleep(500);
|
||||||
|
|
||||||
// Get my external IP from IRC server
|
// Get our external IP from the IRC server and re-nick before joining the channel
|
||||||
CAddress addrFromIRC;
|
CAddress addrFromIRC;
|
||||||
if (GetIPFromIRC(hSocket, strMyName, addrFromIRC.ip))
|
if (GetIPFromIRC(hSocket, strMyName, addrFromIRC.ip))
|
||||||
{
|
{
|
||||||
// Just using it as a backup for now
|
|
||||||
printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToStringIP().c_str());
|
printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToStringIP().c_str());
|
||||||
if (addrFromIRC.IsRoutable() && !fUseProxy && !addrLocalHost.IsRoutable())
|
if (!fUseProxy && addrFromIRC.IsRoutable())
|
||||||
{
|
{
|
||||||
|
// IRC lets you to re-nick
|
||||||
|
fGotExternalIP = true;
|
||||||
addrLocalHost.ip = addrFromIRC.ip;
|
addrLocalHost.ip = addrFromIRC.ip;
|
||||||
strMyName = EncodeAddress(addrLocalHost);
|
strMyName = EncodeAddress(addrLocalHost);
|
||||||
Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
|
Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
|
||||||
|
|
1
irc.h
1
irc.h
|
@ -6,3 +6,4 @@ bool RecvLine(SOCKET hSocket, string& strLine);
|
||||||
void ThreadIRCSeed(void* parg);
|
void ThreadIRCSeed(void* parg);
|
||||||
|
|
||||||
extern int nGotIRCAddresses;
|
extern int nGotIRCAddresses;
|
||||||
|
extern bool fGotExternalIP;
|
||||||
|
|
57
main.cpp
57
main.cpp
|
@ -394,6 +394,63 @@ int CWalletTx::GetRequestCount() const
|
||||||
return nRequests;
|
return nRequests;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CWalletTx::GetAmounts(int64& nGenerated, list<pair<string, int64> >& listReceived,
|
||||||
|
int64& nSent, int64& nFee, string& strSentAccount) const
|
||||||
|
{
|
||||||
|
nGenerated = nSent = nFee = 0;
|
||||||
|
|
||||||
|
if (IsCoinBase())
|
||||||
|
{
|
||||||
|
if (GetBlocksToMaturity() == 0)
|
||||||
|
nGenerated = GetCredit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Received. Standard client will never generate a send-to-multiple-recipients,
|
||||||
|
// but non-standard clients might (so return a list of address/amount pairs)
|
||||||
|
foreach(const CTxOut& txout, vout)
|
||||||
|
{
|
||||||
|
vector<unsigned char> vchPubKey;
|
||||||
|
if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
|
||||||
|
listReceived.push_back(make_pair(PubKeyToAddress(vchPubKey), txout.nValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sent
|
||||||
|
int64 nDebit = GetDebit();
|
||||||
|
if (nDebit > 0)
|
||||||
|
{
|
||||||
|
int64 nValueOut = GetValueOut();
|
||||||
|
nFee = nDebit - nValueOut;
|
||||||
|
nSent = nValueOut - GetChange();
|
||||||
|
strSentAccount = strFromAccount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived,
|
||||||
|
int64& nSent, int64& nFee) const
|
||||||
|
{
|
||||||
|
nGenerated = nReceived = nSent = nFee = 0;
|
||||||
|
|
||||||
|
int64 allGenerated, allSent, allFee;
|
||||||
|
allGenerated = allSent = allFee = 0;
|
||||||
|
string strSentAccount;
|
||||||
|
list<pair<string, int64> > listReceived;
|
||||||
|
GetAmounts(allGenerated, listReceived, allSent, allFee, strSentAccount);
|
||||||
|
|
||||||
|
if (strAccount == "")
|
||||||
|
nGenerated = allGenerated;
|
||||||
|
if (strAccount == strSentAccount)
|
||||||
|
{
|
||||||
|
nSent = allSent;
|
||||||
|
nFee = allFee;
|
||||||
|
}
|
||||||
|
CRITICAL_BLOCK(cs_mapAddressBook)
|
||||||
|
{
|
||||||
|
foreach(const PAIRTYPE(string,int64)& r, listReceived)
|
||||||
|
if (mapAddressBook.count(r.first) && mapAddressBook[r.first] == strAccount)
|
||||||
|
nReceived += r.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
38
main.h
38
main.h
|
@ -873,36 +873,11 @@ public:
|
||||||
return nChangeCached;
|
return nChangeCached;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetAccountAmounts(string strAccount, const set<CScript>& setPubKey,
|
void GetAmounts(int64& nGenerated, list<pair<string /* address */, int64> >& listReceived,
|
||||||
int64& nGenerated, int64& nReceived, int64& nSent, int64& nFee) const
|
int64& nSent, int64& nFee, string& strSentAccount) const;
|
||||||
{
|
|
||||||
nGenerated = nReceived = nSent = nFee = 0;
|
|
||||||
|
|
||||||
// Generated blocks count to account ""
|
void GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived,
|
||||||
if (IsCoinBase())
|
int64& nSent, int64& nFee) const;
|
||||||
{
|
|
||||||
if (strAccount == "" && GetBlocksToMaturity() == 0)
|
|
||||||
nGenerated = GetCredit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Received
|
|
||||||
foreach(const CTxOut& txout, vout)
|
|
||||||
if (setPubKey.count(txout.scriptPubKey))
|
|
||||||
nReceived += txout.nValue;
|
|
||||||
|
|
||||||
// Sent
|
|
||||||
if (strFromAccount == strAccount)
|
|
||||||
{
|
|
||||||
int64 nDebit = GetDebit();
|
|
||||||
if (nDebit > 0)
|
|
||||||
{
|
|
||||||
int64 nValueOut = GetValueOut();
|
|
||||||
nFee = nDebit - nValueOut;
|
|
||||||
nSent = nValueOut - GetChange();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsFromMe() const
|
bool IsFromMe() const
|
||||||
{
|
{
|
||||||
|
@ -1695,6 +1670,7 @@ public:
|
||||||
class CAccountingEntry
|
class CAccountingEntry
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
string strAccount;
|
||||||
int64 nCreditDebit;
|
int64 nCreditDebit;
|
||||||
int64 nTime;
|
int64 nTime;
|
||||||
string strOtherAccount;
|
string strOtherAccount;
|
||||||
|
@ -1709,6 +1685,7 @@ public:
|
||||||
{
|
{
|
||||||
nCreditDebit = 0;
|
nCreditDebit = 0;
|
||||||
nTime = 0;
|
nTime = 0;
|
||||||
|
strAccount.clear();
|
||||||
strOtherAccount.clear();
|
strOtherAccount.clear();
|
||||||
strComment.clear();
|
strComment.clear();
|
||||||
}
|
}
|
||||||
|
@ -1717,6 +1694,7 @@ public:
|
||||||
(
|
(
|
||||||
if (!(nType & SER_GETHASH))
|
if (!(nType & SER_GETHASH))
|
||||||
READWRITE(nVersion);
|
READWRITE(nVersion);
|
||||||
|
// Note: strAccount is serialized as part of the key, not here.
|
||||||
READWRITE(nCreditDebit);
|
READWRITE(nCreditDebit);
|
||||||
READWRITE(nTime);
|
READWRITE(nTime);
|
||||||
READWRITE(strOtherAccount);
|
READWRITE(strOtherAccount);
|
||||||
|
@ -1733,6 +1711,8 @@ public:
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
// Alerts are for notifying old versions if they become too obsolete and
|
||||||
|
// need to upgrade. The message is displayed in the status bar.
|
||||||
// Alert messages are broadcast as a vector of signed data. Unserializing may
|
// Alert messages are broadcast as a vector of signed data. Unserializing may
|
||||||
// not read the entire buffer if the alert is for a newer version, but older
|
// not read the entire buffer if the alert is for a newer version, but older
|
||||||
// versions can still relay the original data.
|
// versions can still relay the original data.
|
||||||
|
|
49
net.cpp
49
net.cpp
|
@ -163,7 +163,7 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha
|
||||||
return error("GetMyExternalIP() : connection closed");
|
return error("GetMyExternalIP() : connection closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We now get our external IP from the IRC server first and only use this as a backup
|
||||||
bool GetMyExternalIP(unsigned int& ipRet)
|
bool GetMyExternalIP(unsigned int& ipRet)
|
||||||
{
|
{
|
||||||
CAddress addrConnect;
|
CAddress addrConnect;
|
||||||
|
@ -176,6 +176,10 @@ bool GetMyExternalIP(unsigned int& ipRet)
|
||||||
for (int nLookup = 0; nLookup <= 1; nLookup++)
|
for (int nLookup = 0; nLookup <= 1; nLookup++)
|
||||||
for (int nHost = 1; nHost <= 2; nHost++)
|
for (int nHost = 1; nHost <= 2; nHost++)
|
||||||
{
|
{
|
||||||
|
// We should be phasing out our use of sites like these. If we need
|
||||||
|
// replacements, we should ask for volunteers to put this simple
|
||||||
|
// php file on their webserver that prints the client IP:
|
||||||
|
// <?php echo $_SERVER["REMOTE_ADDR"]; ?>
|
||||||
if (nHost == 1)
|
if (nHost == 1)
|
||||||
{
|
{
|
||||||
addrConnect = CAddress("91.198.22.70:80"); // checkip.dyndns.org
|
addrConnect = CAddress("91.198.22.70:80"); // checkip.dyndns.org
|
||||||
|
@ -222,6 +226,36 @@ bool GetMyExternalIP(unsigned int& ipRet)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ThreadGetMyExternalIP(void* parg)
|
||||||
|
{
|
||||||
|
// Wait for IRC to get it first
|
||||||
|
if (!GetBoolArg("-noirc"))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 2 * 60; i++)
|
||||||
|
{
|
||||||
|
Sleep(1000);
|
||||||
|
if (fGotExternalIP || fShutdown)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback in case IRC fails to get it
|
||||||
|
if (GetMyExternalIP(addrLocalHost.ip))
|
||||||
|
{
|
||||||
|
printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
|
||||||
|
if (addrLocalHost.IsRoutable())
|
||||||
|
{
|
||||||
|
// If we already connected to a few before we had our IP, go back and addr them.
|
||||||
|
// setAddrKnown automatically filters any duplicate sends.
|
||||||
|
CAddress addr(addrLocalHost);
|
||||||
|
addr.nTime = GetAdjustedTime();
|
||||||
|
CRITICAL_BLOCK(cs_vNodes)
|
||||||
|
foreach(CNode* pnode, vNodes)
|
||||||
|
pnode->PushAddress(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1310,8 +1344,7 @@ void StartNode(void* parg)
|
||||||
#endif
|
#endif
|
||||||
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
|
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
|
||||||
|
|
||||||
// Get our external IP address for incoming connections
|
if (fUseProxy || mapArgs.count("-connect"))
|
||||||
if (fUseProxy)
|
|
||||||
{
|
{
|
||||||
// Proxies can't take incoming connections
|
// Proxies can't take incoming connections
|
||||||
addrLocalHost.ip = CAddress("0.0.0.0").ip;
|
addrLocalHost.ip = CAddress("0.0.0.0").ip;
|
||||||
|
@ -1319,15 +1352,7 @@ void StartNode(void* parg)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (addrIncoming.IsValid())
|
CreateThread(ThreadGetMyExternalIP, NULL);
|
||||||
addrLocalHost.ip = addrIncoming.ip;
|
|
||||||
|
|
||||||
if (GetMyExternalIP(addrLocalHost.ip))
|
|
||||||
{
|
|
||||||
addrIncoming = addrLocalHost;
|
|
||||||
CWalletDB().WriteSetting("addrIncoming", addrIncoming);
|
|
||||||
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
301
rpc.cpp
301
rpc.cpp
|
@ -84,7 +84,13 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
|
||||||
entry.push_back(Pair(item.first, item.second));
|
entry.push_back(Pair(item.first, item.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string AccountFromValue(const Value& value)
|
||||||
|
{
|
||||||
|
string strAccount = value.get_str();
|
||||||
|
if (strAccount == "*")
|
||||||
|
throw JSONRPCError(-11, "Invalid account name");
|
||||||
|
return strAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -296,7 +302,7 @@ Value getnewaddress(const Array& params, bool fHelp)
|
||||||
// Parse the account first so we don't generate a key if there's an error
|
// Parse the account first so we don't generate a key if there's an error
|
||||||
string strAccount;
|
string strAccount;
|
||||||
if (params.size() > 0)
|
if (params.size() > 0)
|
||||||
strAccount = params[0].get_str();
|
strAccount = AccountFromValue(params[0]);
|
||||||
|
|
||||||
// Generate a new key that is added to wallet
|
// Generate a new key that is added to wallet
|
||||||
string strAddress = PubKeyToAddress(GetKeyFromKeyPool());
|
string strAddress = PubKeyToAddress(GetKeyFromKeyPool());
|
||||||
|
@ -314,7 +320,7 @@ Value getaccountaddress(const Array& params, bool fHelp)
|
||||||
"Returns the current bitcoin address for receiving payments to this account.");
|
"Returns the current bitcoin address for receiving payments to this account.");
|
||||||
|
|
||||||
// Parse the account first so we don't generate a key if there's an error
|
// Parse the account first so we don't generate a key if there's an error
|
||||||
string strAccount = params[0].get_str();
|
string strAccount = AccountFromValue(params[0]);
|
||||||
|
|
||||||
CRITICAL_BLOCK(cs_mapWallet)
|
CRITICAL_BLOCK(cs_mapWallet)
|
||||||
{
|
{
|
||||||
|
@ -365,7 +371,7 @@ Value setaccount(const Array& params, bool fHelp)
|
||||||
string strAddress = params[0].get_str();
|
string strAddress = params[0].get_str();
|
||||||
string strAccount;
|
string strAccount;
|
||||||
if (params.size() > 1)
|
if (params.size() > 1)
|
||||||
strAccount = params[1].get_str();
|
strAccount = AccountFromValue(params[1]);
|
||||||
|
|
||||||
SetAddressBookName(strAddress, strAccount);
|
SetAddressBookName(strAddress, strAccount);
|
||||||
return Value::null;
|
return Value::null;
|
||||||
|
@ -399,7 +405,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
|
||||||
"getaddressesbyaccount <account>\n"
|
"getaddressesbyaccount <account>\n"
|
||||||
"Returns the list of addresses for the given account.");
|
"Returns the list of addresses for the given account.");
|
||||||
|
|
||||||
string strAccount = params[0].get_str();
|
string strAccount = AccountFromValue(params[0]);
|
||||||
|
|
||||||
// Find all addresses that have the given account
|
// Find all addresses that have the given account
|
||||||
Array ret;
|
Array ret;
|
||||||
|
@ -436,7 +442,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
|
||||||
// Wallet comments
|
// Wallet comments
|
||||||
CWalletTx wtx;
|
CWalletTx wtx;
|
||||||
if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
|
if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
|
||||||
wtx.mapValue["message"] = params[2].get_str();
|
wtx.mapValue["comment"] = params[2].get_str();
|
||||||
if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
|
if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
|
||||||
wtx.mapValue["to"] = params[3].get_str();
|
wtx.mapValue["to"] = params[3].get_str();
|
||||||
|
|
||||||
|
@ -522,7 +528,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
|
||||||
nMinDepth = params[1].get_int();
|
nMinDepth = params[1].get_int();
|
||||||
|
|
||||||
// Get the set of pub keys that have the label
|
// Get the set of pub keys that have the label
|
||||||
string strAccount = params[0].get_str();
|
string strAccount = AccountFromValue(params[0]);
|
||||||
set<CScript> setPubKey;
|
set<CScript> setPubKey;
|
||||||
GetAccountPubKeys(strAccount, setPubKey);
|
GetAccountPubKeys(strAccount, setPubKey);
|
||||||
|
|
||||||
|
@ -549,9 +555,6 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
|
||||||
|
|
||||||
int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
|
int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
|
||||||
{
|
{
|
||||||
set<CScript> setPubKey;
|
|
||||||
GetAccountPubKeys(strAccount, setPubKey);
|
|
||||||
|
|
||||||
int64 nBalance = 0;
|
int64 nBalance = 0;
|
||||||
CRITICAL_BLOCK(cs_mapWallet)
|
CRITICAL_BLOCK(cs_mapWallet)
|
||||||
{
|
{
|
||||||
|
@ -563,7 +566,7 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int64 nGenerated, nReceived, nSent, nFee;
|
int64 nGenerated, nReceived, nSent, nFee;
|
||||||
wtx.GetAccountAmounts(strAccount, setPubKey, nGenerated, nReceived, nSent, nFee);
|
wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
|
||||||
|
|
||||||
if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
|
if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
|
||||||
nBalance += nReceived;
|
nBalance += nReceived;
|
||||||
|
@ -595,7 +598,7 @@ Value getbalance(const Array& params, bool fHelp)
|
||||||
if (params.size() == 0)
|
if (params.size() == 0)
|
||||||
return ((double)GetBalance() / (double)COIN);
|
return ((double)GetBalance() / (double)COIN);
|
||||||
|
|
||||||
string strAccount = params[0].get_str();
|
string strAccount = AccountFromValue(params[0]);
|
||||||
int nMinDepth = 1;
|
int nMinDepth = 1;
|
||||||
if (params.size() > 1)
|
if (params.size() > 1)
|
||||||
nMinDepth = params[1].get_int();
|
nMinDepth = params[1].get_int();
|
||||||
|
@ -613,8 +616,8 @@ Value movecmd(const Array& params, bool fHelp)
|
||||||
"move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
|
"move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
|
||||||
"Move from one account in your wallet to another.");
|
"Move from one account in your wallet to another.");
|
||||||
|
|
||||||
string strFrom = params[0].get_str();
|
string strFrom = AccountFromValue(params[0]);
|
||||||
string strTo = params[1].get_str();
|
string strTo = AccountFromValue(params[1]);
|
||||||
int64 nAmount = AmountFromValue(params[2]);
|
int64 nAmount = AmountFromValue(params[2]);
|
||||||
int nMinDepth = 1;
|
int nMinDepth = 1;
|
||||||
if (params.size() > 3)
|
if (params.size() > 3)
|
||||||
|
@ -647,19 +650,21 @@ Value movecmd(const Array& params, bool fHelp)
|
||||||
|
|
||||||
// Debit
|
// Debit
|
||||||
CAccountingEntry debit;
|
CAccountingEntry debit;
|
||||||
|
debit.strAccount = strFrom;
|
||||||
debit.nCreditDebit = -nAmount;
|
debit.nCreditDebit = -nAmount;
|
||||||
debit.nTime = nNow;
|
debit.nTime = nNow;
|
||||||
debit.strOtherAccount = strTo;
|
debit.strOtherAccount = strTo;
|
||||||
debit.strComment = strComment;
|
debit.strComment = strComment;
|
||||||
walletdb.WriteAccountingEntry(strFrom, debit);
|
walletdb.WriteAccountingEntry(debit);
|
||||||
|
|
||||||
// Credit
|
// Credit
|
||||||
CAccountingEntry credit;
|
CAccountingEntry credit;
|
||||||
|
credit.strAccount = strTo;
|
||||||
credit.nCreditDebit = nAmount;
|
credit.nCreditDebit = nAmount;
|
||||||
credit.nTime = nNow;
|
credit.nTime = nNow;
|
||||||
credit.strOtherAccount = strFrom;
|
credit.strOtherAccount = strFrom;
|
||||||
credit.strComment = strComment;
|
credit.strComment = strComment;
|
||||||
walletdb.WriteAccountingEntry(strTo, credit);
|
walletdb.WriteAccountingEntry(credit);
|
||||||
|
|
||||||
walletdb.TxnCommit();
|
walletdb.TxnCommit();
|
||||||
}
|
}
|
||||||
|
@ -674,7 +679,7 @@ Value sendfrom(const Array& params, bool fHelp)
|
||||||
"sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
|
"sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
|
||||||
"<amount> is a real and is rounded to the nearest 0.01");
|
"<amount> is a real and is rounded to the nearest 0.01");
|
||||||
|
|
||||||
string strAccount = params[0].get_str();
|
string strAccount = AccountFromValue(params[0]);
|
||||||
string strAddress = params[1].get_str();
|
string strAddress = params[1].get_str();
|
||||||
int64 nAmount = AmountFromValue(params[2]);
|
int64 nAmount = AmountFromValue(params[2]);
|
||||||
int nMinDepth = 1;
|
int nMinDepth = 1;
|
||||||
|
@ -684,7 +689,7 @@ Value sendfrom(const Array& params, bool fHelp)
|
||||||
CWalletTx wtx;
|
CWalletTx wtx;
|
||||||
wtx.strFromAccount = strAccount;
|
wtx.strFromAccount = strAccount;
|
||||||
if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
|
if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
|
||||||
wtx.mapValue["message"] = params[4].get_str();
|
wtx.mapValue["comment"] = params[4].get_str();
|
||||||
if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
|
if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
|
||||||
wtx.mapValue["to"] = params[5].get_str();
|
wtx.mapValue["to"] = params[5].get_str();
|
||||||
|
|
||||||
|
@ -849,97 +854,180 @@ Value listreceivedbyaccount(const Array& params, bool fHelp)
|
||||||
return ListReceived(params, true);
|
return ListReceived(params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListAccountTransactions(CWalletDB& walletdb, const string& strAccount, int nMinDepth, multimap<int64, Object>& ret)
|
void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, Array& ret)
|
||||||
{
|
{
|
||||||
set<CScript> setPubKey;
|
int64 nGenerated, nSent, nFee;
|
||||||
GetAccountPubKeys(strAccount, setPubKey);
|
string strSentAccount;
|
||||||
|
list<pair<string, int64> > listReceived;
|
||||||
|
wtx.GetAmounts(nGenerated, listReceived, nSent, nFee, strSentAccount);
|
||||||
|
|
||||||
CRITICAL_BLOCK(cs_mapWallet)
|
bool fAllAccounts = (strAccount == string("*"));
|
||||||
|
|
||||||
|
// Generated blocks assigned to account ""
|
||||||
|
if (nGenerated != 0 && (fAllAccounts || strAccount == ""))
|
||||||
{
|
{
|
||||||
// Wallet: generate/send/receive transactions
|
Object entry;
|
||||||
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
entry.push_back(Pair("account", string("")));
|
||||||
|
entry.push_back(Pair("category", "generate"));
|
||||||
|
entry.push_back(Pair("amount", ValueFromAmount(nGenerated)));
|
||||||
|
WalletTxToJSON(wtx, entry);
|
||||||
|
ret.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sent
|
||||||
|
if ((nSent != 0 || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
|
||||||
|
{
|
||||||
|
Object entry;
|
||||||
|
entry.push_back(Pair("account", strSentAccount));
|
||||||
|
entry.push_back(Pair("category", "send"));
|
||||||
|
entry.push_back(Pair("amount", ValueFromAmount(-nSent)));
|
||||||
|
entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
|
||||||
|
WalletTxToJSON(wtx, entry);
|
||||||
|
ret.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Received
|
||||||
|
if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
|
||||||
|
CRITICAL_BLOCK(cs_mapAddressBook)
|
||||||
{
|
{
|
||||||
const CWalletTx& wtx = (*it).second;
|
foreach(const PAIRTYPE(string, int64)& r, listReceived)
|
||||||
if (!wtx.IsFinal())
|
if (mapAddressBook.count(r.first) && (fAllAccounts || r.first == strAccount))
|
||||||
continue;
|
{
|
||||||
|
Object entry;
|
||||||
int64 nGenerated, nReceived, nSent, nFee;
|
entry.push_back(Pair("account", r.first));
|
||||||
wtx.GetAccountAmounts(strAccount, setPubKey, nGenerated, nReceived, nSent, nFee);
|
entry.push_back(Pair("category", "receive"));
|
||||||
|
entry.push_back(Pair("amount", ValueFromAmount(r.second)));
|
||||||
// Generated blocks count to account ""
|
WalletTxToJSON(wtx, entry);
|
||||||
if (nGenerated != 0)
|
ret.push_back(entry);
|
||||||
{
|
}
|
||||||
Object entry;
|
|
||||||
entry.push_back(Pair("category", "generate"));
|
|
||||||
entry.push_back(Pair("amount", ValueFromAmount(nGenerated)));
|
|
||||||
WalletTxToJSON(wtx, entry);
|
|
||||||
ret.insert(make_pair(wtx.GetTxTime(), entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sent
|
|
||||||
if (nSent != 0 || nFee != 0)
|
|
||||||
{
|
|
||||||
Object entry;
|
|
||||||
entry.push_back(Pair("category", "send"));
|
|
||||||
entry.push_back(Pair("amount", ValueFromAmount(-nSent)));
|
|
||||||
entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
|
|
||||||
WalletTxToJSON(wtx, entry);
|
|
||||||
ret.insert(make_pair(wtx.GetTxTime(), entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Received
|
|
||||||
if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
|
|
||||||
{
|
|
||||||
Object entry;
|
|
||||||
entry.push_back(Pair("category", "receive"));
|
|
||||||
entry.push_back(Pair("amount", ValueFromAmount(nReceived)));
|
|
||||||
WalletTxToJSON(wtx, entry);
|
|
||||||
ret.insert(make_pair(wtx.GetTxTime(), entry));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal accounting entries
|
}
|
||||||
list<CAccountingEntry> acentries;
|
|
||||||
walletdb.ListAccountCreditDebit(strAccount, acentries);
|
void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
|
||||||
foreach (const CAccountingEntry& acentry, acentries)
|
{
|
||||||
{
|
bool fAllAccounts = (strAccount == string("*"));
|
||||||
Object entry;
|
|
||||||
entry.push_back(Pair("category", "move"));
|
if (fAllAccounts || acentry.strAccount == strAccount)
|
||||||
entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
|
{
|
||||||
entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
|
Object entry;
|
||||||
ret.insert(make_pair(acentry.nTime, entry));
|
entry.push_back(Pair("account", acentry.strAccount));
|
||||||
}
|
entry.push_back(Pair("category", "move"));
|
||||||
|
entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
|
||||||
|
entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
|
||||||
|
entry.push_back(Pair("comment", acentry.strComment));
|
||||||
|
ret.push_back(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Value listtransactions(const Array& params, bool fHelp)
|
Value listtransactions(const Array& params, bool fHelp)
|
||||||
{
|
{
|
||||||
if (fHelp || params.size() < 1 || params.size() > 2)
|
if (fHelp || params.size() > 2)
|
||||||
throw runtime_error(
|
throw runtime_error(
|
||||||
"listtransactions <account> [count=10]\n"
|
"listtransactions [account] [count=10]\n"
|
||||||
"Returns up to [count] most recent transactions for account <account>.");
|
"Returns up to [count] most recent transactions for account <account>.");
|
||||||
|
|
||||||
string strAccount = params[0].get_str();
|
string strAccount = "*";
|
||||||
|
if (params.size() > 0)
|
||||||
|
strAccount = params[0].get_str();
|
||||||
int nCount = 10;
|
int nCount = 10;
|
||||||
if (params.size() > 1)
|
if (params.size() > 1)
|
||||||
nCount = params[1].get_int();
|
nCount = params[1].get_int();
|
||||||
|
|
||||||
|
Array ret;
|
||||||
CWalletDB walletdb;
|
CWalletDB walletdb;
|
||||||
multimap<int64, Object> mapByTime; // keys are transaction time
|
|
||||||
ListAccountTransactions(walletdb, strAccount, 0, mapByTime);
|
|
||||||
|
|
||||||
// Return only last nCount items:
|
CRITICAL_BLOCK(cs_mapWallet)
|
||||||
int nToErase = mapByTime.size()-nCount;
|
|
||||||
if (nToErase > 0)
|
|
||||||
{
|
{
|
||||||
multimap<int64, Object>::iterator end = mapByTime.begin();
|
// Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
|
||||||
std::advance(end, nToErase);
|
typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
|
||||||
mapByTime.erase(mapByTime.begin(), end);
|
typedef multimap<int64, TxPair > TxItems;
|
||||||
|
TxItems txByTime;
|
||||||
|
|
||||||
|
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||||
|
{
|
||||||
|
CWalletTx* wtx = &((*it).second);
|
||||||
|
txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, 0)));
|
||||||
|
}
|
||||||
|
list<CAccountingEntry> acentries;
|
||||||
|
walletdb.ListAccountCreditDebit(strAccount, acentries);
|
||||||
|
foreach(CAccountingEntry& entry, acentries)
|
||||||
|
{
|
||||||
|
txByTime.insert(make_pair(entry.nTime, TxPair(0, &entry)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now: iterate backwards until we have nCount items to return:
|
||||||
|
for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
|
||||||
|
{
|
||||||
|
CWalletTx *const pwtx = (*it).second.first;
|
||||||
|
if (pwtx != 0)
|
||||||
|
ListTransactions(*pwtx, strAccount, 0, ret);
|
||||||
|
CAccountingEntry *const pacentry = (*it).second.second;
|
||||||
|
if (pacentry != 0)
|
||||||
|
AcentryToJSON(*pacentry, strAccount, ret);
|
||||||
|
|
||||||
|
if (ret.size() >= nCount) break;
|
||||||
|
}
|
||||||
|
// ret is now newest to oldest
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we return only last nCount items (sends-to-self might give us an extra):
|
||||||
|
if (ret.size() > nCount)
|
||||||
|
{
|
||||||
|
Array::iterator last = ret.begin();
|
||||||
|
std::advance(last, nCount);
|
||||||
|
ret.erase(last, ret.end());
|
||||||
|
}
|
||||||
|
std::reverse(ret.begin(), ret.end()); // oldest to newest
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value listaccounts(const Array& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (fHelp || params.size() > 1)
|
||||||
|
throw runtime_error(
|
||||||
|
"listaccounts [minconf=1]\n"
|
||||||
|
"Returns Object that has account names as keys, account balances as values.");
|
||||||
|
|
||||||
|
int nMinDepth = 1;
|
||||||
|
if (params.size() > 1)
|
||||||
|
nMinDepth = params[1].get_int();
|
||||||
|
|
||||||
|
map<string, int64> mapAccountBalances;
|
||||||
|
CRITICAL_BLOCK(cs_mapWallet)
|
||||||
|
CRITICAL_BLOCK(cs_mapAddressBook)
|
||||||
|
{
|
||||||
|
foreach(const PAIRTYPE(string, string)& entry, mapAddressBook)
|
||||||
|
mapAccountBalances[entry.second] = 0;
|
||||||
|
|
||||||
|
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||||
|
{
|
||||||
|
const CWalletTx& wtx = (*it).second;
|
||||||
|
int64 nGenerated, nSent, nFee;
|
||||||
|
string strSentAccount;
|
||||||
|
list<pair<string, int64> > listReceived;
|
||||||
|
wtx.GetAmounts(nGenerated, listReceived, nSent, nFee, strSentAccount);
|
||||||
|
mapAccountBalances[strSentAccount] -= nSent+nFee;
|
||||||
|
if (wtx.GetDepthInMainChain() >= nMinDepth)
|
||||||
|
{
|
||||||
|
mapAccountBalances[""] += nGenerated;
|
||||||
|
foreach(const PAIRTYPE(string, int64)& r, listReceived)
|
||||||
|
if (mapAddressBook.count(r.first))
|
||||||
|
mapAccountBalances[mapAddressBook[r.first]] += r.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Array ret;
|
list<CAccountingEntry> acentries;
|
||||||
foreach(const PAIRTYPE(int64, Object)& item, mapByTime)
|
CWalletDB().ListAccountCreditDebit("*", acentries);
|
||||||
ret.push_back(item.second);
|
foreach(const CAccountingEntry& entry, acentries)
|
||||||
|
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
|
||||||
|
|
||||||
|
Object ret;
|
||||||
|
foreach(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
|
||||||
|
ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1175,6 +1263,7 @@ pair<string, rpcfn_type> pCallTable[] =
|
||||||
make_pair("gettransaction", &gettransaction),
|
make_pair("gettransaction", &gettransaction),
|
||||||
make_pair("listtransactions", &listtransactions),
|
make_pair("listtransactions", &listtransactions),
|
||||||
make_pair("getwork", &getwork),
|
make_pair("getwork", &getwork),
|
||||||
|
make_pair("listaccounts", &listaccounts),
|
||||||
};
|
};
|
||||||
map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
|
map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
|
||||||
|
|
||||||
|
@ -1247,7 +1336,7 @@ string HTTPReply(int nStatus, const string& strMsg)
|
||||||
"Server: bitcoin-json-rpc\r\n"
|
"Server: bitcoin-json-rpc\r\n"
|
||||||
"WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
|
"WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
|
||||||
"Content-Type: text/html\r\n"
|
"Content-Type: text/html\r\n"
|
||||||
"Content-Length: 311\r\n"
|
"Content-Length: 296\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
|
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
|
||||||
"\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
|
"\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
|
||||||
|
@ -1421,6 +1510,17 @@ string JSONRPCReply(const Value& result, const Value& error, const Value& id)
|
||||||
return write_string(Value(reply), false) + "\n";
|
return write_string(Value(reply), false) + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
|
||||||
|
{
|
||||||
|
// Send error reply from json-rpc error object
|
||||||
|
int nStatus = 500;
|
||||||
|
int code = find_value(objError, "code").get_int();
|
||||||
|
if (code == -32600) nStatus = 400;
|
||||||
|
else if (code == -32601) nStatus = 404;
|
||||||
|
string strReply = JSONRPCReply(Value::null, objError, id);
|
||||||
|
stream << HTTPReply(nStatus, strReply) << std::flush;
|
||||||
|
}
|
||||||
|
|
||||||
bool ClientAllowed(const string& strAddress)
|
bool ClientAllowed(const string& strAddress)
|
||||||
{
|
{
|
||||||
if (strAddress == asio::ip::address_v4::loopback().to_string())
|
if (strAddress == asio::ip::address_v4::loopback().to_string())
|
||||||
|
@ -1581,10 +1681,16 @@ void ThreadRPCServer2(void* parg)
|
||||||
if (!ClientAllowed(peer.address().to_string()))
|
if (!ClientAllowed(peer.address().to_string()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Receive request
|
|
||||||
map<string, string> mapHeaders;
|
map<string, string> mapHeaders;
|
||||||
string strRequest;
|
string strRequest;
|
||||||
ReadHTTP(stream, mapHeaders, strRequest);
|
|
||||||
|
boost::thread api_caller(ReadHTTP, ref(stream), ref(mapHeaders), ref(strRequest));
|
||||||
|
if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
|
||||||
|
{ // Timed out:
|
||||||
|
acceptor.cancel();
|
||||||
|
printf("ThreadRPCServer ReadHTTP timeout\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Check authorization
|
// Check authorization
|
||||||
if (mapHeaders.count("Authorization") == 0)
|
if (mapHeaders.count("Authorization") == 0)
|
||||||
|
@ -1656,26 +1762,16 @@ void ThreadRPCServer2(void* parg)
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
// Send error reply from method
|
ErrorReply(stream, JSONRPCError(-1, e.what()), id);
|
||||||
string strReply = JSONRPCReply(Value::null, JSONRPCError(-1, e.what()), id);
|
|
||||||
stream << HTTPReply(500, strReply) << std::flush;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Object& objError)
|
catch (Object& objError)
|
||||||
{
|
{
|
||||||
// Send error reply from json-rpc error object
|
ErrorReply(stream, objError, id);
|
||||||
int nStatus = 500;
|
|
||||||
int code = find_value(objError, "code").get_int();
|
|
||||||
if (code == -32600) nStatus = 400;
|
|
||||||
else if (code == -32601) nStatus = 404;
|
|
||||||
string strReply = JSONRPCReply(Value::null, objError, id);
|
|
||||||
stream << HTTPReply(nStatus, strReply) << std::flush;
|
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
// Send error reply from other json-rpc parsing errors
|
ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
|
||||||
string strReply = JSONRPCReply(Value::null, JSONRPCError(-32700, e.what()), id);
|
|
||||||
stream << HTTPReply(500, strReply) << std::flush;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1812,6 +1908,7 @@ int CommandLineRPC(int argc, char *argv[])
|
||||||
if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
|
if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
|
||||||
if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
|
if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
|
||||||
if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
|
if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
|
||||||
|
if (strMethod == "listaccounts" && n > 1) ConvertTo<boost::int64_t>(params[1]);
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
Object reply = CallRPC(strMethod, params);
|
Object reply = CallRPC(strMethod, params);
|
||||||
|
|
|
@ -25,7 +25,7 @@ class CDataStream;
|
||||||
class CAutoFile;
|
class CAutoFile;
|
||||||
static const unsigned int MAX_SIZE = 0x02000000;
|
static const unsigned int MAX_SIZE = 0x02000000;
|
||||||
|
|
||||||
static const int VERSION = 31900;
|
static const int VERSION = 31902;
|
||||||
static const char* pszSubVer = "";
|
static const char* pszSubVer = "";
|
||||||
|
|
||||||
|
|
||||||
|
|
8
ui.cpp
8
ui.cpp
|
@ -746,6 +746,12 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
|
||||||
strDescription += " - ";
|
strDescription += " - ";
|
||||||
strDescription += mapValue["message"];
|
strDescription += mapValue["message"];
|
||||||
}
|
}
|
||||||
|
else if (!mapValue["comment"].empty())
|
||||||
|
{
|
||||||
|
if (!strDescription.empty())
|
||||||
|
strDescription += " - ";
|
||||||
|
strDescription += mapValue["comment"];
|
||||||
|
}
|
||||||
|
|
||||||
int64 nValue = txout.nValue;
|
int64 nValue = txout.nValue;
|
||||||
if (nTxFee > 0)
|
if (nTxFee > 0)
|
||||||
|
@ -1405,6 +1411,8 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
|
||||||
//
|
//
|
||||||
if (!wtx.mapValue["message"].empty())
|
if (!wtx.mapValue["message"].empty())
|
||||||
strHTML += string() + "<br><b>" + _("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
|
strHTML += string() + "<br><b>" + _("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
|
||||||
|
if (!wtx.mapValue["comment"].empty())
|
||||||
|
strHTML += string() + "<br><b>" + _("Comment:") + "</b><br>" + HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
|
||||||
|
|
||||||
if (wtx.IsCoinBase())
|
if (wtx.IsCoinBase())
|
||||||
strHTML += string() + "<br>" + _("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.") + "<br>";
|
strHTML += string() + "<br>" + _("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.") + "<br>";
|
||||||
|
|
Loading…
Reference in a new issue