changeset 142:993a3e02f1d7 draft

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
author s_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>
date Tue, 23 Feb 2010 22:01:39 +0000
parents d57f149af4c6
children acae4b87419a
files main.cpp main.h rpc.cpp serialize.h ui.cpp util.cpp util.h
diffstat 7 files changed, 206 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/main.cpp
+++ b/main.cpp
@@ -1315,11 +1315,10 @@
     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 @@
         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 @@
         CTransaction txNew;
         txNew.vin.resize(1);
         txNew.vout.resize(1);
-        txNew.vin[0].scriptSig     = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((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<unsigned char>((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;
--- a/main.h
+++ b/main.h
@@ -1384,6 +1384,9 @@
     CPrivKey vchPrivKey;
     int64 nTimeCreated;
     int64 nTimeExpires;
+    string strComment;
+    //// todo: add something to note what created it (user, getnewaddress, change)
+    ////   maybe should have a map<string, string> property map
 
     CWalletKey(int64 nTimeExpiresIn=0)
     {
@@ -1398,6 +1401,7 @@
         READWRITE(vchPrivKey);
         READWRITE(nTimeCreated);
         READWRITE(nTimeExpires);
+        READWRITE(strComment);
     )
 };
 
--- a/rpc.cpp
+++ b/rpc.cpp
@@ -66,6 +66,17 @@
 }
 
 
+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 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 <generate> [genproclimit]\n"
+            "<generate> 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 @@
     // 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 @@
             "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 @@
                 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;
+                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);
-                }
+                tallyitem& item = mapTally[hash160];
+                item.nAmount += txout.nValue;
+                item.nConf = min(item.nConf, nDepth);
             }
         }
     }
@@ -264,10 +347,10 @@
                 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 @@
     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 @@
         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<bool>(params[0]);
+        if (strMethod == "setgenerate"       && n > 1) ConvertTo<boost::int64_t>(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 > 1) ConvertTo<bool>(params[1]);
--- a/serialize.h
+++ b/serialize.h
@@ -19,7 +19,7 @@
 class CDataStream;
 class CAutoFile;
 
-static const int VERSION = 205;
+static const int VERSION = 206;
 static const char* pszSubVer = ".0";
 
 
--- a/ui.cpp
+++ b/ui.cpp
@@ -26,6 +26,20 @@
 
 
 
+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 @@
 
 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 @@
 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 @@
     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 @@
 
 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 @@
     //
     // Parameters
     //
-    if (argc > 1 && argv[1][0] != '-' && argv[1][0] != '/')
+    if (fCommandLine)
     {
         int ret = CommandLineRPC(argc, argv);
         exit(ret);
@@ -2696,13 +2765,6 @@
     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");
--- a/util.cpp
+++ b/util.cpp
@@ -13,6 +13,7 @@
 char pszSetDataDir[MAX_PATH] = "";
 bool fShutdown = false;
 bool fDaemon = false;
+bool fCommandLine = false;
 
 
 
@@ -500,7 +501,8 @@
     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();
--- a/util.h
+++ b/util.h
@@ -121,6 +121,7 @@
 extern char pszSetDataDir[MAX_PATH];
 extern bool fShutdown;
 extern bool fDaemon;
+extern bool fCommandLine;
 
 void RandAddSeed();
 void RandAddSeedPerfmon();