From 30158c77e99a099cbdd556bacbac18b431c3870c Mon Sep 17 00:00:00 2001 From: s_nakamoto Date: Tue, 23 Feb 2010 22:01:39 +0000 Subject: [PATCH] run as daemon without GUI, hooked wxApp::Initialize to ignore gtk-init-check failure if no GUI, fork to daemonize, rpc getinfo, getconnectioncount, getbalance, getgenerate, setgenerate, -- version 0.2.6 --- main.cpp | 15 +++--- main.h | 4 ++ rpc.cpp | 134 ++++++++++++++++++++++++++++++++++++++++++++-------- serialize.h | 2 +- ui.cpp | 94 +++++++++++++++++++++++++++++------- util.cpp | 4 +- util.h | 1 + 7 files changed, 207 insertions(+), 47 deletions(-) diff --git a/main.cpp b/main.cpp index 56020a13..bd69de92 100644 --- a/main.cpp +++ b/main.cpp @@ -1315,11 +1315,10 @@ bool CBlock::AcceptBlock() if (nTime <= pindexPrev->GetMedianTimePast()) return error("AcceptBlock() : block's timestamp is too early"); - // Check that all transactions are finalized (starting around Mar 2010) - if (nBestHeight > 36000) - foreach(const CTransaction& tx, vtx) - if (!tx.IsFinal(nTime)) - return error("AcceptBlock() : contains a non-final transaction"); + // Check that all transactions are finalized + foreach(const CTransaction& tx, vtx) + if (!tx.IsFinal(nTime)) + return error("AcceptBlock() : contains a non-final transaction"); // Check proof of work if (nBits != GetNextWorkRequired(pindexPrev)) @@ -1336,7 +1335,7 @@ bool CBlock::AcceptBlock() return error("AcceptBlock() : AddToBlockIndex failed"); // Don't relay old inventory during initial block download. - // Please keep this constant updated to a few thousand below current block count. + // Please keep this number updated to a few thousand below current block count. if (hashBestChain == hash && nBestHeight > 40000) RelayInventory(CInv(MSG_BLOCK, hash)); @@ -1556,8 +1555,8 @@ bool LoadBlockIndex(bool fAllowNew) CTransaction txNew; txNew.vin.resize(1); txNew.vout.resize(1); - txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); - txNew.vout[0].nValue = 50 * COIN; + txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vout[0].nValue = 50 * COIN; CBigNum bnPubKey; bnPubKey.SetHex("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704"); txNew.vout[0].scriptPubKey = CScript() << bnPubKey << OP_CHECKSIG; diff --git a/main.h b/main.h index 4027f87e..452ce85b 100644 --- a/main.h +++ b/main.h @@ -1384,6 +1384,9 @@ public: CPrivKey vchPrivKey; int64 nTimeCreated; int64 nTimeExpires; + string strComment; + //// todo: add something to note what created it (user, getnewaddress, change) + //// maybe should have a map property map CWalletKey(int64 nTimeExpiresIn=0) { @@ -1398,6 +1401,7 @@ public: READWRITE(vchPrivKey); READWRITE(nTimeCreated); READWRITE(nTimeExpires); + READWRITE(strComment); ) }; diff --git a/rpc.cpp b/rpc.cpp index f4eef37f..7f3e71db 100644 --- a/rpc.cpp +++ b/rpc.cpp @@ -66,6 +66,17 @@ Value getblocknumber(const Array& params) } +Value getconnectioncount(const Array& params) +{ + if (params.size() != 0) + throw runtime_error( + "getconnectioncount (no parameters)\n" + "Returns the number of connections to other nodes."); + + return (int)vNodes.size(); +} + + Value getdifficulty(const Array& params) { if (params.size() != 0) @@ -85,6 +96,71 @@ Value getdifficulty(const Array& params) } +Value getbalance(const Array& params) +{ + if (params.size() != 0) + throw runtime_error( + "getbalance (no parameters)\n" + "Returns the server's available balance."); + + return ((double)GetBalance() / (double)COIN); +} + + +Value getgenerate(const Array& params) +{ + if (params.size() != 0) + throw runtime_error( + "getgenerate (no parameters)\n" + "Returns true or false."); + + return (bool)fGenerateBitcoins; +} + + +Value setgenerate(const Array& params) +{ + if (params.size() < 1 || params.size() > 2) + throw runtime_error( + "setgenerate [genproclimit]\n" + " is true or false to turn generation on or off.\n" + "Generation is limited to [genproclimit] processors, -1 is unlimited."); + + bool fGenerate = true; + if (params.size() > 0) + fGenerate = params[0].get_bool(); + + if (params.size() > 1) + { + int nGenProcLimit = params[1].get_int(); + fLimitProcessors = (nGenProcLimit != -1); + CWalletDB().WriteSetting("fLimitProcessors", fLimitProcessors); + if (nGenProcLimit != -1) + CWalletDB().WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit); + } + + GenerateBitcoins(fGenerate); + return Value::null; +} + + +Value getinfo(const Array& params) +{ + if (params.size() != 0) + throw runtime_error( + "getinfo (no parameters)"); + + Object obj; + obj.push_back(Pair("balance", (double)GetBalance() / (double)COIN)); + obj.push_back(Pair("blocks", (int)nBestHeight + 1)); + obj.push_back(Pair("connections", (int)vNodes.size())); + obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string()))); + obj.push_back(Pair("generate", (bool)fGenerateBitcoins)); + obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1))); + return obj; +} + + Value getnewaddress(const Array& params) { if (params.size() > 1) @@ -102,8 +178,7 @@ Value getnewaddress(const Array& params) // Generate a new key that is added to wallet string strAddress = PubKeyToAddress(GenerateNewKey()); - if (params.size() > 0) - SetAddressBookName(strAddress, strLabel); + SetAddressBookName(strAddress, strLabel); return strAddress; } @@ -214,10 +289,10 @@ Value getallreceived(const Array& params) "getallreceived [minconf=1]\n" "[minconf] is the minimum number of confirmations before payments are included.\n" "Returns an array of objects containing:\n" - " \"address\" : bitcoin address\n" + " \"address\" : receiving address\n" " \"amount\" : total amount received by the address\n" - " \"conf\" : number of confirmations\n" - " \"label\" : the label set for this address when it was created by getnewaddress"); + " \"confirmations\" : number of confirmations of the most recent transaction included\n" + " \"label\" : the label of the receiving address"); // Minimum confirmations int nMinDepth = 1; @@ -235,18 +310,26 @@ Value getallreceived(const Array& params) continue; int nDepth = wtx.GetDepthInMainChain(); - if (nDepth >= nMinDepth) + if (nDepth < nMinDepth) + 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) - { - uint160 hash160 = txout.scriptPubKey.GetBitcoinAddressHash160(); - if (hash160 == 0 || !mapPubKeys.count(hash160)) - continue; - - tallyitem& item = mapTally[hash160]; - item.nAmount += txout.nValue; - item.nConf = min(item.nConf, nDepth); - } + uint160 hash160 = txout.scriptPubKey.GetBitcoinAddressHash160(); + if (hash160 == 0 || !mapPubKeys.count(hash160)) + continue; + + tallyitem& item = mapTally[hash160]; + item.nAmount += txout.nValue; + item.nConf = min(item.nConf, nDepth); } } } @@ -264,10 +347,10 @@ Value getallreceived(const Array& params) strLabel = (*mi).second; Object obj; - obj.push_back(Pair("address", strAddress)); - obj.push_back(Pair("amount", (double)(*it).second.nAmount / (double)COIN)); - obj.push_back(Pair("conf", (*it).second.nConf)); - obj.push_back(Pair("label", strLabel)); + 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)); ret.push_back(obj); } } @@ -290,7 +373,12 @@ pair pCallTable[] = make_pair("stop", &stop), make_pair("getblockcount", &getblockcount), make_pair("getblocknumber", &getblocknumber), + make_pair("getconnectioncount", &getconnectioncount), make_pair("getdifficulty", &getdifficulty), + make_pair("getbalance", &getbalance), + make_pair("getgenerate", &getgenerate), + make_pair("setgenerate", &setgenerate), + make_pair("getinfo", &getinfo), make_pair("getnewaddress", &getnewaddress), make_pair("sendtoaddress", &sendtoaddress), make_pair("listtransactions", &listtransactions), @@ -568,9 +656,13 @@ int CommandLineRPC(int argc, char *argv[]) Array params; for (int i = 2; i < argc; i++) params.push_back(argv[i]); + int n = params.size(); + // // Special case other types - int n = params.size(); + // + if (strMethod == "setgenerate" && n > 0) ConvertTo(params[0]); + if (strMethod == "setgenerate" && n > 1) ConvertTo(params[1]); if (strMethod == "sendtoaddress" && n > 1) ConvertTo(params[1]); if (strMethod == "listtransactions" && n > 0) ConvertTo(params[0]); if (strMethod == "listtransactions" && n > 1) ConvertTo(params[1]); diff --git a/serialize.h b/serialize.h index fb06f881..8fb72a0a 100644 --- a/serialize.h +++ b/serialize.h @@ -19,7 +19,7 @@ class CScript; class CDataStream; class CAutoFile; -static const int VERSION = 205; +static const int VERSION = 206; static const char* pszSubVer = ".0"; diff --git a/ui.cpp b/ui.cpp index 68d57b6c..748b4dad 100644 --- a/ui.cpp +++ b/ui.cpp @@ -26,6 +26,20 @@ int fMinimizeOnClose = true; +int MyMessageBox(const wxString& message, const wxString& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1) +{ + if (fDaemon) + { + printf("wxMessageBox %s: %s\n", string(caption).c_str(), string(message).c_str()); + fprintf(stderr, "%s: %s\n", string(caption).c_str(), string(message).c_str()); + return wxOK; + } + return wxMessageBox(message, caption, style, parent, x, y); +} +#define wxMessageBox MyMessageBox + + + @@ -209,16 +223,10 @@ void CalledMessageBox(const string& message, const string& caption, int style, w int ThreadSafeMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y) { - if (fDaemon) - { - printf("wxMessageBox %s: %s\n", caption.c_str(), message.c_str()); - return wxOK; - } - #ifdef __WXMSW__ return wxMessageBox(message, caption, style, parent, x, y); #else - if (wxThread::IsMain()) + if (wxThread::IsMain() || fDaemon) { return wxMessageBox(message, caption, style, parent, x, y); } @@ -563,7 +571,7 @@ string SingleLine(const string& strIn) bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) { int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime(); - int64 nCredit = wtx.GetCredit(); + int64 nCredit = wtx.GetCredit(true); int64 nDebit = wtx.GetDebit(); int64 nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(); @@ -2571,6 +2579,9 @@ public: bool OnInit2(); int OnExit(); + // Hook Initialize so we can start without GUI + virtual bool Initialize(int& argc, wxChar** argv); + // 2nd-level exception handling: we get all the exceptions occurring in any // event handler here virtual bool OnExceptionInMainLoop(); @@ -2586,6 +2597,64 @@ public: IMPLEMENT_APP(CMyApp) +bool CMyApp::Initialize(int& argc, wxChar** argv) +{ + if (argc > 1 && argv[1][0] != '-' && (!fWindows || argv[1][0] != '/') && + wxString(argv[1]) != "start") + { + fCommandLine = true; + } + else + { + // wxApp::Initialize will remove environment-specific parameters, + // so it's too early to call ParseParameters yet + for (int i = 1; i < argc; i++) + { + wxString str = argv[i]; + #ifdef __WXMSW__ + if (str.size() >= 1 && str[0] == '/') + str[0] = '-'; + str = str.MakeLower(); + #endif + // haven't decided which argument to use for this yet + if (str == "-daemon" || str == "-d" || str == "start") + fDaemon = true; + } + } + +#ifdef __WXGTK__ + if (fDaemon || fCommandLine) + { + // Call the original Initialize while suppressing error messages + // and ignoring failure. If unable to initialize GTK, it fails + // near the end so hopefully the last few things don't matter. + { + wxLogNull logNo; + wxApp::Initialize(argc, argv); + } + + if (fDaemon) + { + fprintf(stdout, "bitcoin server starting\n"); + + // Daemonize + pid_t pid = fork(); + if (pid < 0) + { + fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno); + return false; + } + if (pid > 0) + pthread_exit((void*)0); + } + + return true; + } +#endif + + return wxApp::Initialize(argc, argv); +} + bool CMyApp::OnInit() { bool fRet = false; @@ -2650,7 +2719,7 @@ bool CMyApp::OnInit2() // // Parameters // - if (argc > 1 && argv[1][0] != '-' && argv[1][0] != '/') + if (fCommandLine) { int ret = CommandLineRPC(argc, argv); exit(ret); @@ -2696,13 +2765,6 @@ bool CMyApp::OnInit2() if (mapArgs.count("-printtodebugger")) fPrintToDebugger = true; - if (mapArgs.count("-daemon") || mapArgs.count("-d")) - { - fDaemon = true; - /// todo: need to fork - /// should it fork after the bind/single instance stuff? - } - if (!fDebug && !pszSetDataDir[0]) ShrinkDebugFile(); printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); diff --git a/util.cpp b/util.cpp index 40f7af34..6ea735d1 100644 --- a/util.cpp +++ b/util.cpp @@ -13,6 +13,7 @@ bool fPrintToDebugger = false; char pszSetDataDir[MAX_PATH] = ""; bool fShutdown = false; bool fDaemon = false; +bool fCommandLine = false; @@ -500,7 +501,8 @@ void PrintException(std::exception* pex, const char* pszThread) char pszMessage[1000]; FormatException(pszMessage, pex, pszThread); printf("\n\n************************\n%s\n", pszMessage); - if (wxTheApp) + fprintf(stderr, "\n\n************************\n%s\n", pszMessage); + if (wxTheApp && !fDaemon) wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR); throw; //DebugBreak(); diff --git a/util.h b/util.h index 8aed902f..75f0956f 100644 --- a/util.h +++ b/util.h @@ -121,6 +121,7 @@ extern bool fPrintToDebugger; extern char pszSetDataDir[MAX_PATH]; extern bool fShutdown; extern bool fDaemon; +extern bool fCommandLine; void RandAddSeed(); void RandAddSeedPerfmon();