From 401926283a200994ecd7df8eae8ced8e0b067c46 Mon Sep 17 00:00:00 2001 From: s_nakamoto Date: Wed, 25 Aug 2010 00:05:37 +0000 Subject: alert system -- version 0.3.11 git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@142 1a98c847-1fd6-4fd8-948a-caf3550aa51b --- main.cpp | 200 +++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 156 insertions(+), 44 deletions(-) (limited to 'main.cpp') diff --git a/main.cpp b/main.cpp index aa1d67aac8..0171f1470e 100644 --- a/main.cpp +++ b/main.cpp @@ -898,14 +898,7 @@ bool IsInitialBlockDownload() 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 @@ void Lockdown(CBlockIndex* pindexNew) 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 @@ void Lockdown(CBlockIndex* pindexNew) + + + bool CTransaction::DisconnectInputs(CTxDB& txdb) { // Relinquish previous transactions' spent pointers @@ -1282,7 +1277,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash)) { txdb.TxnAbort(); - Lockdown(pindexNew); + InvalidChainFound(pindexNew); return error("SetBestChain() : ConnectBlock failed"); } txdb.TxnCommit(); @@ -1298,7 +1293,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) if (!Reorganize(txdb, pindexNew)) { txdb.TxnAbort(); - Lockdown(pindexNew); + InvalidChainFound(pindexNew); return error("SetBestChain() : Reorganize failed"); } } @@ -1571,16 +1566,16 @@ bool ScanMessageStart(Stream& s) } } -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 @@ bool LoadBlockIndex(bool fAllowNew) 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 @@ bool LoadBlockIndex(bool fAllowNew) 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; - 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 @@ bool LoadBlockIndex(bool fAllowNew) //// debug print printf("%s\n", block.GetHash().ToString().c_str()); - printf("%s\n", block.hashMerkleRoot.ToString().c_str()); printf("%s\n", hashGenesisBlock.ToString().c_str()); - txNew.vout[0].scriptPubKey.print(); - block.print(); + printf("%s\n", block.hashMerkleRoot.ToString().c_str()); assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); + block.print(); assert(block.GetHash() == hashGenesisBlock); @@ -1798,6 +1780,111 @@ void PrintBlockTree() +////////////////////////////////////////////////////////////////////////////// +// +// CAlert +// + +map 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::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 @@ bool ProcessMessages(CNode* pfrom) 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 @@ bool ProcessMessages(CNode* pfrom) // 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 @@ bool ProcessMessages(CNode* pfrom) 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 @@ bool ProcessMessages(CNode* pfrom) } 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 @@ bool ProcessMessages(CNode* pfrom) } 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 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) 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 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) 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 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } + 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 @@ void BitcoinMiner() map mapTestPool; vector vfAlreadyAdded(mapTransactions.size()); bool fFoundSomething = true; - unsigned int nBlockSize = 0; + uint64 nBlockSize = 0; while (fFoundSomething && nBlockSize < MAX_SIZE/2) { fFoundSomething = false; -- cgit v1.2.3