changeset 249:cb4f9fbb1863 draft

alert system -- version 0.3.11
author Satoshi Nakamoto <satoshin@gmx.com>
date Sat, 28 Aug 2010 00:51:52 +0000
parents 41628b8a75b9
children 8c9f73243ec7
files main.cpp main.h net.h rpc.cpp serialize.h ui.cpp util.cpp util.h
diffstat 8 files changed, 409 insertions(+), 86 deletions(-) [+]
line wrap: on
line diff
--- a/main.cpp
+++ b/main.cpp
@@ -898,14 +898,7 @@
             pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60);
 }
 
-bool IsLockdown()
-{
-    if (!pindexBest)
-        return false;
-    return (bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6);
-}
-
-void Lockdown(CBlockIndex* pindexNew)
+void InvalidChainFound(CBlockIndex* pindexNew)
 {
     if (pindexNew->bnChainWork > bnBestInvalidWork)
     {
@@ -913,11 +906,10 @@
         CTxDB().WriteBestInvalidWork(bnBestInvalidWork);
         MainFrameRepaint();
     }
-    printf("Lockdown: invalid block=%s  height=%d  work=%s\n", pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, pindexNew->bnChainWork.ToString().c_str());
-    printf("Lockdown:  current best=%s  height=%d  work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
-    printf("Lockdown: IsLockdown()=%d\n", (IsLockdown() ? 1 : 0));
-    if (IsLockdown())
-        printf("Lockdown: WARNING: Displayed transactions may not be correct!  You may need to upgrade, or other nodes may need to upgrade.\n");
+    printf("InvalidChainFound: invalid block=%s  height=%d  work=%s\n", pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, pindexNew->bnChainWork.ToString().c_str());
+    printf("InvalidChainFound:  current best=%s  height=%d  work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
+    if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6)
+        printf("InvalidChainFound: WARNING: Displayed transactions may not be correct!  You may need to upgrade, or other nodes may need to upgrade.\n");
 }
 
 
@@ -927,6 +919,9 @@
 
 
 
+
+
+
 bool CTransaction::DisconnectInputs(CTxDB& txdb)
 {
     // Relinquish previous transactions' spent pointers
@@ -1282,7 +1277,7 @@
         if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
         {
             txdb.TxnAbort();
-            Lockdown(pindexNew);
+            InvalidChainFound(pindexNew);
             return error("SetBestChain() : ConnectBlock failed");
         }
         txdb.TxnCommit();
@@ -1298,7 +1293,7 @@
         if (!Reorganize(txdb, pindexNew))
         {
             txdb.TxnAbort();
-            Lockdown(pindexNew);
+            InvalidChainFound(pindexNew);
             return error("SetBestChain() : Reorganize failed");
         }
     }
@@ -1571,16 +1566,16 @@
     }
 }
 
-bool CheckDiskSpace(int64 nAdditionalBytes)
+bool CheckDiskSpace(uint64 nAdditionalBytes)
 {
     uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available;
 
     // Check for 15MB because database could create another 10MB log file at any time
-    if (nFreeBytesAvailable < (int64)15000000 + nAdditionalBytes)
+    if (nFreeBytesAvailable < (uint64)15000000 + nAdditionalBytes)
     {
         fShutdown = true;
         string strMessage = _("Warning: Disk space is low  ");
-        strWarning = strMessage;
+        strMiscWarning = strMessage;
         printf("*** %s\n", strMessage.c_str());
         ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
         CreateThread(Shutdown, NULL);
@@ -1648,17 +1643,7 @@
         if (!fAllowNew)
             return false;
 
-
         // Genesis Block:
-        // GetHash()      = 0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
-        // hashMerkleRoot = 0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
-        // txNew.vin[0].scriptSig     = 486604799 4 0x736B6E616220726F662074756F6C69616220646E6F63657320666F206B6E697262206E6F20726F6C6C65636E61684320393030322F6E614A2F33302073656D695420656854
-        // txNew.vout[0].nValue       = 5000000000
-        // txNew.vout[0].scriptPubKey = 0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704 OP_CHECKSIG
-        // block.nVersion = 1
-        // block.nTime    = 1231006505
-        // block.nBits    = 0x1d00ffff
-        // block.nNonce   = 2083236893
         // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
         //   CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
         //     CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
@@ -1672,9 +1657,7 @@
         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;
-        CBigNum bnPubKey;
-        bnPubKey.SetHex("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704");
-        txNew.vout[0].scriptPubKey = CScript() << bnPubKey << OP_CHECKSIG;
+        txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
         CBlock block;
         block.vtx.push_back(txNew);
         block.hashPrevBlock = 0;
@@ -1686,11 +1669,10 @@
 
             //// debug print
             printf("%s\n", block.GetHash().ToString().c_str());
+            printf("%s\n", hashGenesisBlock.ToString().c_str());
             printf("%s\n", block.hashMerkleRoot.ToString().c_str());
-            printf("%s\n", hashGenesisBlock.ToString().c_str());
-            txNew.vout[0].scriptPubKey.print();
+            assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
             block.print();
-            assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
 
         assert(block.GetHash() == hashGenesisBlock);
 
@@ -1800,6 +1782,111 @@
 
 //////////////////////////////////////////////////////////////////////////////
 //
+// CAlert
+//
+
+map<uint256, CAlert> mapAlerts;
+CCriticalSection cs_mapAlerts;
+
+string GetWarnings(string strFor)
+{
+    int nPriority = 0;
+    string strStatusBar;
+    string strRPC;
+
+    // Misc warnings like out of disk space and clock is wrong
+    if (strMiscWarning != "")
+    {
+        nPriority = 1000;
+        strStatusBar = strMiscWarning;
+    }
+
+    // Longer invalid proof-of-work chain
+    if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6)
+    {
+        nPriority = 2000;
+        strStatusBar = strRPC = "WARNING: Displayed transactions may not be correct!  You may need to upgrade, or other nodes may need to upgrade.";
+    }
+
+    // Alerts
+    CRITICAL_BLOCK(cs_mapAlerts)
+    {
+        foreach(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
+        {
+            const CAlert& alert = item.second;
+            if (alert.AppliesToMe() && alert.nPriority > nPriority)
+            {
+                nPriority = alert.nPriority;
+                strStatusBar = alert.strStatusBar;
+                strRPC = alert.strRPCError;
+            }
+        }
+    }
+
+    if (strFor == "statusbar")
+        return strStatusBar;
+    else if (strFor == "rpc")
+        return strRPC;
+    assert(("GetWarnings() : invalid parameter", false));
+    return "error";
+}
+
+bool CAlert::ProcessAlert()
+{
+    if (!CheckSignature())
+        return false;
+    if (!IsInEffect())
+        return false;
+
+    CRITICAL_BLOCK(cs_mapAlerts)
+    {
+        // Cancel previous alerts
+        for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
+        {
+            const CAlert& alert = (*mi).second;
+            if (Cancels(alert))
+            {
+                printf("cancelling alert %d\n", alert.nID);
+                mapAlerts.erase(mi++);
+            }
+            else if (!alert.IsInEffect())
+            {
+                printf("expiring alert %d\n", alert.nID);
+                mapAlerts.erase(mi++);
+            }
+            else
+                mi++;
+        }
+
+        // Check if this alert has been cancelled
+        foreach(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
+        {
+            const CAlert& alert = item.second;
+            if (alert.Cancels(*this))
+            {
+                printf("alert already cancelled by %d\n", alert.nID);
+                return false;
+            }
+        }
+
+        // Add to mapAlerts
+        mapAlerts.insert(make_pair(GetHash(), *this));
+    }
+
+    printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
+    MainFrameRepaint();
+    return true;
+}
+
+
+
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
 // Messages
 //
 
@@ -1827,7 +1914,7 @@
     if (vRecv.empty())
         return true;
     //if (fDebug)
-    //    printf("ProcessMessages(%d bytes)\n", vRecv.size());
+    //    printf("ProcessMessages(%u bytes)\n", vRecv.size());
 
     //
     // Message format
@@ -1869,6 +1956,11 @@
 
         // Message size
         unsigned int nMessageSize = hdr.nMessageSize;
+        if (nMessageSize > MAX_SIZE)
+        {
+            printf("ProcessMessage(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
+            continue;
+        }
         if (nMessageSize > vRecv.size())
         {
             // Rewind and wait for rest of message
@@ -1889,7 +1981,7 @@
             memcpy(&nChecksum, &hash, sizeof(nChecksum));
             if (nChecksum != hdr.nChecksum)
             {
-                printf("ProcessMessage(%s, %d bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
+                printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
                        strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
                 continue;
             }
@@ -1906,15 +1998,15 @@
         }
         catch (std::ios_base::failure& e)
         {
-            if (strstr(e.what(), "CDataStream::read() : end of data"))
+            if (strstr(e.what(), "end of data"))
             {
                 // Allow exceptions from underlength message on vRecv
-                printf("ProcessMessage(%s, %d bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
+                printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
             }
-            else if (strstr(e.what(), ": size too large"))
+            else if (strstr(e.what(), "size too large"))
             {
                 // Allow exceptions from overlong size
-                printf("ProcessMessage(%s, %d bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
+                printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
             }
             else
             {
@@ -1928,7 +2020,7 @@
         }
 
         if (!fRet)
-            printf("ProcessMessage(%s, %d bytes) FAILED\n", strCommand.c_str(), nMessageSize);
+            printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize);
     }
 
     vRecv.Compact();
@@ -1965,14 +2057,13 @@
         CAddress addrMe;
         CAddress addrFrom;
         uint64 nNonce = 1;
-        string strSubVer;
         vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
         if (pfrom->nVersion == 10300)
             pfrom->nVersion = 300;
         if (pfrom->nVersion >= 106 && !vRecv.empty())
             vRecv >> addrFrom >> nNonce;
         if (pfrom->nVersion >= 106 && !vRecv.empty())
-            vRecv >> strSubVer;
+            vRecv >> pfrom->strSubVer;
         if (pfrom->nVersion >= 209 && !vRecv.empty())
             vRecv >> pfrom->nStartingHeight;
 
@@ -2010,6 +2101,11 @@
             pfrom->PushGetBlocks(pindexBest, uint256(0));
         }
 
+        // Relay alerts
+        CRITICAL_BLOCK(cs_mapAlerts)
+            foreach(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
+                item.second.RelayTo(pfrom);
+
         pfrom->fSuccessfullyConnected = true;
 
         printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
@@ -2362,6 +2458,22 @@
     }
 
 
+    else if (strCommand == "alert")
+    {
+        CAlert alert;
+        vRecv >> alert;
+
+        if (alert.ProcessAlert())
+        {
+            // Relay
+            pfrom->setKnown.insert(alert.GetHash());
+            CRITICAL_BLOCK(cs_vNodes)
+                foreach(CNode* pnode, vNodes)
+                    alert.RelayTo(pnode);
+        }
+    }
+
+
     else
     {
         // Ignore unknown commands for extensibility
@@ -2695,7 +2807,7 @@
             map<uint256, CTxIndex> mapTestPool;
             vector<char> vfAlreadyAdded(mapTransactions.size());
             bool fFoundSomething = true;
-            unsigned int nBlockSize = 0;
+            uint64 nBlockSize = 0;
             while (fFoundSomething && nBlockSize < MAX_SIZE/2)
             {
                 fFoundSomething = false;
--- a/main.h
+++ b/main.h
@@ -14,7 +14,6 @@
 class CWalletTx;
 class CKeyItem;
 
-static const unsigned int MAX_SIZE = 0x02000000;
 static const unsigned int MAX_BLOCK_SIZE = 1000000;
 static const int64 COIN = 100000000;
 static const int64 CENT = 1000000;
@@ -61,7 +60,7 @@
 
 
 
-bool CheckDiskSpace(int64 nAdditionalBytes=0);
+bool CheckDiskSpace(uint64 nAdditionalBytes=0);
 FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");
 FILE* AppendBlockFile(unsigned int& nFileRet);
 bool AddKey(const CKey& key);
@@ -85,7 +84,7 @@
 void BitcoinMiner();
 bool CheckProofOfWork(uint256 hash, unsigned int nBits);
 bool IsInitialBlockDownload();
-bool IsLockdown();
+string GetWarnings(string strFor);
 
 
 
@@ -298,7 +297,6 @@
     int64 nValue;
     CScript scriptPubKey;
 
-public:
     CTxOut()
     {
         SetNull();
@@ -475,6 +473,10 @@
         if (vin.empty() || vout.empty())
             return error("CTransaction::CheckTransaction() : vin or vout empty");
 
+        // Size limits
+        if (::GetSerializeSize(*this, SER_DISK) > MAX_SIZE)
+            return error("CTransaction::CheckTransaction() : size limits failed");
+
         // Check for negative or overflow output values
         int64 nValueOut = 0;
         foreach(const CTxOut& txout, vout)
@@ -1469,6 +1471,214 @@
 
 
 
+//
+// 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
+// versions can still relay the original data.
+//
+class CUnsignedAlert
+{
+public:
+    int nVersion;
+    int64 nRelayUntil;      // when newer nodes stop relaying to newer nodes
+    int64 nExpiration;
+    int nID;
+    int nCancel;
+    set<int> setCancel;
+    int nMinVer;            // lowest version inclusive
+    int nMaxVer;            // highest version inclusive
+    set<string> setSubVer;  // empty matches all
+    int nPriority;
+
+    // Actions
+    string strComment;
+    string strStatusBar;
+    string strRPCError;
+
+    IMPLEMENT_SERIALIZE
+    (
+        READWRITE(this->nVersion);
+        nVersion = this->nVersion;
+        READWRITE(nRelayUntil);
+        READWRITE(nExpiration);
+        READWRITE(nID);
+        READWRITE(nCancel);
+        READWRITE(setCancel);
+        READWRITE(nMinVer);
+        READWRITE(nMaxVer);
+        READWRITE(setSubVer);
+        READWRITE(nPriority);
+
+        READWRITE(strComment);
+        READWRITE(strStatusBar);
+        READWRITE(strRPCError);
+    )
+
+    void SetNull()
+    {
+        nVersion = 1;
+        nRelayUntil = 0;
+        nExpiration = 0;
+        nID = 0;
+        nCancel = 0;
+        setCancel.clear();
+        nMinVer = 0;
+        nMaxVer = 0;
+        setSubVer.clear();
+        nPriority = 0;
+
+        strComment.clear();
+        strStatusBar.clear();
+        strRPCError.clear();
+    }
+
+    string ToString() const
+    {
+        string strSetCancel;
+        foreach(int n, setCancel)
+            strSetCancel += strprintf("%d ", n);
+        string strSetSubVer;
+        foreach(string str, setSubVer)
+            strSetSubVer += "\"" + str + "\" ";
+        return strprintf(
+                "CAlert(\n"
+                "    nVersion     = %d\n"
+                "    nRelayUntil  = %"PRI64d"\n"
+                "    nExpiration  = %"PRI64d"\n"
+                "    nID          = %d\n"
+                "    nCancel      = %d\n"
+                "    setCancel    = %s\n"
+                "    nMinVer      = %d\n"
+                "    nMaxVer      = %d\n"
+                "    setSubVer    = %s\n"
+                "    nPriority    = %d\n"
+                "    strComment   = \"%s\"\n"
+                "    strStatusBar = \"%s\"\n"
+                "    strRPCError  = \"%s\"\n"
+                ")\n",
+            nVersion,
+            nRelayUntil,
+            nExpiration,
+            nID,
+            nCancel,
+            strSetCancel.c_str(),
+            nMinVer,
+            nMaxVer,
+            strSetSubVer.c_str(),
+            nPriority,
+            strComment.c_str(),
+            strStatusBar.c_str(),
+            strRPCError.c_str());
+    }
+
+    void print() const
+    {
+        printf("%s", ToString().c_str());
+    }
+};
+
+class CAlert : public CUnsignedAlert
+{
+public:
+    vector<unsigned char> vchMsg;
+    vector<unsigned char> vchSig;
+
+    CAlert()
+    {
+        SetNull();
+    }
+
+    IMPLEMENT_SERIALIZE
+    (
+        READWRITE(vchMsg);
+        READWRITE(vchSig);
+    )
+
+    void SetNull()
+    {
+        CUnsignedAlert::SetNull();
+        vchMsg.clear();
+        vchSig.clear();
+    }
+
+    bool IsNull() const
+    {
+        return (nExpiration == 0);
+    }
+
+    uint256 GetHash() const
+    {
+        return SerializeHash(*this);
+    }
+
+    bool IsInEffect() const
+    {
+        return (GetAdjustedTime() < nExpiration);
+    }
+
+    bool Cancels(const CAlert& alert) const
+    {
+        if (!IsInEffect())
+            false;
+        return (alert.nID <= nCancel || setCancel.count(alert.nID));
+    }
+
+    bool AppliesTo(int nVersion, string strSubVerIn) const
+    {
+        return (IsInEffect() &&
+                nMinVer <= nVersion && nVersion <= nMaxVer &&
+                (setSubVer.empty() || setSubVer.count(strSubVerIn)));
+    }
+
+    bool AppliesToMe() const
+    {
+        return AppliesTo(VERSION, ::pszSubVer);
+    }
+
+    bool RelayTo(CNode* pnode) const
+    {
+        if (!IsInEffect())
+            return false;
+        // returns true if wasn't already contained in the set
+        if (pnode->setKnown.insert(GetHash()).second)
+        {
+            if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
+                AppliesToMe() ||
+                GetAdjustedTime() < nRelayUntil)
+            {
+                pnode->PushMessage("alert", *this);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    bool CheckSignature()
+    {
+        CKey key;
+        if (!key.SetPubKey(ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284")))
+            return error("CAlert::CheckSignature() : SetPubKey failed");
+        if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
+            return error("CAlert::CheckSignature() : verify signature failed");
+
+        // Now unserialize the data
+        CDataStream sMsg(vchMsg);
+        sMsg >> *(CUnsignedAlert*)this;
+        return true;
+    }
+
+    bool ProcessAlert();
+};
+
+
+
+
+
+
+
+
+
+
 extern map<uint256, CTransaction> mapTransactions;
 extern map<uint256, CWalletTx> mapWallet;
 extern vector<uint256> vWalletUpdated;
--- a/net.h
+++ b/net.h
@@ -504,6 +504,7 @@
     unsigned int nMessageStart;
     CAddress addr;
     int nVersion;
+    string strSubVer;
     bool fClient;
     bool fInbound;
     bool fNetworkNode;
@@ -520,10 +521,11 @@
     uint256 hashLastGetBlocksEnd;
     int nStartingHeight;
 
-    // flood
+    // flood relay
     vector<CAddress> vAddrToSend;
     set<CAddress> setAddrKnown;
     bool fGetAddr;
+    set<uint256> setKnown;
 
     // inventory based relay
     set<CInv> setInventoryKnown;
@@ -557,6 +559,7 @@
         nMessageStart = -1;
         addr = addrIn;
         nVersion = 0;
+        strSubVer = "";
         fClient = false; // set by version message
         fInbound = fInboundIn;
         fNetworkNode = false;
--- a/rpc.cpp
+++ b/rpc.cpp
@@ -247,7 +247,7 @@
     obj.push_back(Pair("genproclimit",  (int)(fLimitProcessors ? nLimitProcessors : -1)));
     obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
     obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
-    obj.push_back(Pair("status",        strWarning));
+    obj.push_back(Pair("errors",        GetWarnings("statusbar")));
     return obj;
 }
 
@@ -975,8 +975,9 @@
                 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
 
                 // Observe lockdown
-                if (IsLockdown() && !mapArgs.count("-overridesafety") && strMethod != "help" && strMethod != "stop" && strMethod != "getgenerate" && strMethod != "setgenerate")
-                    throw runtime_error("WARNING: Displayed transactions may not be correct!  You may need to upgrade, or other nodes may need to upgrade.");
+                string strWarning = GetWarnings("rpc");
+                if (strWarning != "" && !mapArgs.count("-overridesafety") && strMethod != "getinfo" && strMethod != "help" && strMethod != "stop" && strMethod != "getgenerate" && strMethod != "setgenerate")
+                    throw runtime_error(strWarning);
 
                 // Execute
                 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
--- a/serialize.h
+++ b/serialize.h
@@ -19,8 +19,11 @@
 class CDataStream;
 class CAutoFile;
 
-static const int VERSION = 310;
-static const char* pszSubVer = ".5";
+static const unsigned int MAX_SIZE = 0x02000000;
+
+static const int VERSION = 311;
+static const char* pszSubVer = ".0";
+
 
 
 
@@ -224,7 +227,7 @@
         READDATA(is, nSize);
         nSizeRet = nSize;
     }
-    if (nSizeRet > (uint64)INT_MAX)
+    if (nSizeRet > (uint64)MAX_SIZE)
         throw std::ios_base::failure("ReadCompactSize() : size too large");
     return nSizeRet;
 }
--- a/ui.cpp
+++ b/ui.cpp
@@ -196,7 +196,7 @@
 
 void CalledSetStatusBar(const string& strText, int nField)
 {
-    if (nField == 0 && IsLockdown())
+    if (nField == 0 && GetWarnings("statusbar") != "")
         return;
     if (pframeMain && pframeMain->m_statusBar)
         pframeMain->m_statusBar->SetStatusText(strText, nField);
@@ -1013,12 +1013,13 @@
     RefreshStatusColumn();
 
     // Update status bar
-    static bool fPrevLockdown;
-    if (IsLockdown())
-        m_statusBar->SetStatusText(string("    ") + _("WARNING: Displayed transactions may not be correct!  You may need to upgrade, or other nodes may need to upgrade."), 0);
-    else if (fPrevLockdown)
+    static string strPrevWarning;
+    string strWarning = GetWarnings("statusbar");
+    if (strWarning != "")
+        m_statusBar->SetStatusText(string("    ") + _(strWarning), 0);
+    else if (strPrevWarning != "")
         m_statusBar->SetStatusText("", 0);
-    fPrevLockdown = IsLockdown();
+    strPrevWarning = strWarning;
 
     string strGen = "";
     if (fGenerateBitcoins)
--- a/util.cpp
+++ b/util.cpp
@@ -14,7 +14,7 @@
 bool fShutdown = false;
 bool fDaemon = false;
 bool fCommandLine = false;
-string strWarning;
+string strMiscWarning;
 
 
 
@@ -104,12 +104,8 @@
     RegCloseKey(HKEY_PERFORMANCE_DATA);
     if (ret == ERROR_SUCCESS)
     {
-        uint256 hash;
-        SHA256(pdata, nSize, (unsigned char*)&hash);
-        RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash)));
-        hash = 0;
+        RAND_add(pdata, nSize, nSize/100.0);
         memset(pdata, 0, nSize);
-
         printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M", GetTime()).c_str(), nSize);
     }
 #endif
@@ -371,11 +367,6 @@
 
 vector<unsigned char> ParseHex(const char* psz)
 {
-    vector<unsigned char> vch;
-    while (isspace(*psz))
-        psz++;
-    vch.reserve((strlen(psz)+1)/3);
-
     static char phexdigit[256] =
     { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
@@ -394,24 +385,22 @@
       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
 
-    while (*psz)
+    // convert hex dump to vector
+    vector<unsigned char> vch;
+    loop
     {
+        while (isspace(*psz))
+            psz++;
         char c = phexdigit[(unsigned char)*psz++];
         if (c == -1)
             break;
         unsigned char n = (c << 4);
-        if (*psz)
-        {
-            char c = phexdigit[(unsigned char)*psz++];
-            if (c == -1)
-                break;
-            n |= c;
-            vch.push_back(n);
-        }
-        while (isspace(*psz))
-            psz++;
+        c = phexdigit[(unsigned char)*psz++];
+        if (c == -1)
+            break;
+        n |= c;
+        vch.push_back(n);
     }
-
     return vch;
 }
 
@@ -761,7 +750,7 @@
             {
                 fDone = true;
                 string strMessage = _("Warning: Check your system date and time, you may not be able to generate or receive the most recent blocks!");
-                strWarning = strMessage;
+                strMiscWarning = strMessage;
                 printf("*** %s\n", strMessage.c_str());
                 boost::thread(bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1));
             }
--- a/util.h
+++ b/util.h
@@ -143,7 +143,7 @@
 extern bool fShutdown;
 extern bool fDaemon;
 extern bool fCommandLine;
-extern string strWarning;
+extern string strMiscWarning;
 
 void RandAddSeed();
 void RandAddSeedPerfmon();
@@ -307,6 +307,8 @@
 template<typename T>
 string HexStr(const T itbegin, const T itend, bool fSpaces=true)
 {
+    if (itbegin == itend)
+        return "";
     const unsigned char* pbegin = (const unsigned char*)&itbegin[0];
     const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]);
     string str;
@@ -323,6 +325,8 @@
 template<typename T>
 string HexNumStr(const T itbegin, const T itend, bool f0x=true)
 {
+    if (itbegin == itend)
+        return "";
     const unsigned char* pbegin = (const unsigned char*)&itbegin[0];
     const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]);
     string str = (f0x ? "0x" : "");