From a7d735dcc25c85ad883e6d619848ce0478ebe299 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Sun, 27 Nov 2011 14:53:30 -0500 Subject: [PATCH 1/3] Add missing command-line arguments to --help/-? output --- src/init.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 2d21a261437..68303c19fad 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -162,10 +162,10 @@ bool AppInit2(int argc, char* argv[]) string strUsage = string() + _("Bitcoin version") + " " + FormatFullVersion() + "\n\n" + _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" + - " bitcoin [options] \t " + "\n" + - " bitcoin [options] [params]\t " + _("Send command to -server or bitcoind\n") + - " bitcoin [options] help \t\t " + _("List commands\n") + - " bitcoin [options] help \t\t " + _("Get help for a command\n") + + " bitcoind [options] \t " + "\n" + + " bitcoind [options] [params]\t " + _("Send command to -server or bitcoind\n") + + " bitcoind [options] help \t\t " + _("List commands\n") + + " bitcoind [options] help \t\t " + _("Get help for a command\n") + _("Options:\n") + " -conf= \t\t " + _("Specify configuration file (default: bitcoin.conf)\n") + " -pid= \t\t " + _("Specify pid file (default: bitcoind.pid)\n") + @@ -176,9 +176,14 @@ bool AppInit2(int argc, char* argv[]) " -timeout= \t " + _("Specify connection timeout (in milliseconds)\n") + " -proxy= \t " + _("Connect through socks4 proxy\n") + " -dns \t " + _("Allow DNS lookups for addnode and connect\n") + + " -port= \t\t " + _("Listen for connections on (default: 8333 or testnet: 18333)\n") + + " -maxconnections=\t " + _("Maintain at most connections to peers (default: 125)\n") + " -addnode= \t " + _("Add a node to connect to\n") + " -connect= \t\t " + _("Connect only to the specified node\n") + " -nolisten \t " + _("Don't accept connections from outside\n") + + " -nodnsseed \t " + _("Don't bootstrap list of peers using DNS\n") + + " -maxreceivebuffer=\t " + _("Maximum per-connection receive buffer, *1000 bytes (default: 10000)\n") + + " -maxsendbuffer=\t " + _("Maximum per-connection send buffer, *1000 bytes (default: 10000)\n") + #ifdef USE_UPNP #if USE_UPNP " -noupnp \t " + _("Don't attempt to use UPnP to map the listening port\n") + @@ -194,6 +199,12 @@ bool AppInit2(int argc, char* argv[]) " -daemon \t\t " + _("Run in the background as a daemon and accept commands\n") + #endif " -testnet \t\t " + _("Use the test network\n") + + " -debug \t\t " + _("Output extra debugging information\n") + + " -logtimestamps \t " + _("Prepend debug output with timestamp\n") + + " -printtoconsole \t " + _("Send trace/debug info to console instead of debug.log file\n") + +#ifdef WIN32 + " -printtodebugger \t " + _("Send trace/debug info to debugger\n") + +#endif " -rpcuser= \t " + _("Username for JSON-RPC connections\n") + " -rpcpassword=\t " + _("Password for JSON-RPC connections\n") + " -rpcport= \t\t " + _("Listen for JSON-RPC connections on (default: 8332)\n") + From 0e6425da4a29d6944e7edce85535725e1f963e2c Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 8 Sep 2011 16:50:58 -0400 Subject: [PATCH 2/3] Moved checkpoints out of main, to prep for using them to help prevent DoS attacks --- src/checkpoints.cpp | 43 ++++++++++++++++++++++++++++++++++ src/checkpoints.h | 22 +++++++++++++++++ src/main.cpp | 30 ++++-------------------- src/main.h | 1 - src/makefile.linux-mingw | 2 ++ src/makefile.mingw | 2 ++ src/makefile.osx | 2 ++ src/makefile.unix | 2 ++ src/makefile.vc | 6 +++++ src/test/Checkpoints_tests.cpp | 34 +++++++++++++++++++++++++++ src/test/test_bitcoin.cpp | 1 + 11 files changed, 118 insertions(+), 27 deletions(-) create mode 100644 src/checkpoints.cpp create mode 100644 src/checkpoints.h create mode 100644 src/test/Checkpoints_tests.cpp diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp new file mode 100644 index 00000000000..4419a06c830 --- /dev/null +++ b/src/checkpoints.cpp @@ -0,0 +1,43 @@ +// Copyright (c) 2011 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include "checkpoints.h" +#include "uint256.h" +#include "util.h" + +#include // for 'map_list_of()' + +namespace Checkpoints +{ + typedef std::map MapCheckpoints; + + static MapCheckpoints mapCheckpoints = + boost::assign::map_list_of + ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) + ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")) + ( 68555, uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a")) + ( 70567, uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a")) + ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")) + (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")) + (118000, uint256("0x000000000000774a7f8a7a12dc906ddb9e17e75d684f15e00f8767f9e8f36553")) + (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")) + (140700, uint256("0x000000000000033b512028abb90e1626d8b346fd0ed598ac0a3c371138dce2bd")) + ; + + bool CheckBlock(int nHeight, const uint256& hash) + { + if (fTestNet) return true; // Testnet has no checkpoints + + MapCheckpoints::const_iterator i = mapCheckpoints.find(nHeight); + if (i == mapCheckpoints.end()) return true; + return hash == i->second; + } + + int GetTotalBlocksEstimate() + { + if (fTestNet) return 0; // Testnet has no checkpoints + + return mapCheckpoints.rbegin()->first; + } +} diff --git a/src/checkpoints.h b/src/checkpoints.h new file mode 100644 index 00000000000..32094fdde62 --- /dev/null +++ b/src/checkpoints.h @@ -0,0 +1,22 @@ +// Copyright (c) 2011 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_CHECKPOINT_H +#define BITCOIN_CHECKPOINT_H + +class uint256; + +// +// Block-chain checkpoints are compiled-in sanity checks. +// They are updated every release or three. +// +namespace Checkpoints +{ + // Returns true if block passes checkpoint checks + bool CheckBlock(int nHeight, const uint256& hash); + + // Return conservative estimate of total number of blocks, 0 if unknown + int GetTotalBlocksEstimate(); +} + +#endif diff --git a/src/main.cpp b/src/main.cpp index 6a3bacc78e9..dad7d144e7d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #include "headers.h" +#include "checkpoints.h" #include "db.h" #include "net.h" #include "init.h" @@ -30,7 +31,6 @@ map mapNextTx; map mapBlockIndex; uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); -const int nTotalBlocksEstimate = 140700; // Conservative estimate of total nr of blocks on main chain const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download" CBlockIndex* pindexGenesisBlock = NULL; int nBestHeight = -1; @@ -713,22 +713,9 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits) return true; } -// Return conservative estimate of total number of blocks, 0 if unknown -int GetTotalBlocksEstimate() -{ - if(fTestNet) - { - return 0; - } - else - { - return nTotalBlocksEstimate; - } -} - bool IsInitialBlockDownload() { - if (pindexBest == NULL || nBestHeight < (GetTotalBlocksEstimate()-nInitialBlockThreshold)) + if (pindexBest == NULL || nBestHeight < (Checkpoints::GetTotalBlocksEstimate()-nInitialBlockThreshold)) return true; static int64 nLastUpdate; static CBlockIndex* pindexLastBest; @@ -1294,17 +1281,8 @@ bool CBlock::AcceptBlock() return error("AcceptBlock() : contains a non-final transaction"); // Check that the block chain matches the known block chain up to a checkpoint - if (!fTestNet) - if ((nHeight == 11111 && hash != uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) || - (nHeight == 33333 && hash != uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")) || - (nHeight == 68555 && hash != uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a")) || - (nHeight == 70567 && hash != uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a")) || - (nHeight == 74000 && hash != uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")) || - (nHeight == 105000 && hash != uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")) || - (nHeight == 118000 && hash != uint256("0x000000000000774a7f8a7a12dc906ddb9e17e75d684f15e00f8767f9e8f36553")) || - (nHeight == 134444 && hash != uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")) || - (nHeight == 140700 && hash != uint256("0x000000000000033b512028abb90e1626d8b346fd0ed598ac0a3c371138dce2bd"))) - return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight); + if (!Checkpoints::CheckBlock(nHeight, hash)) + return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight); // Write block to history file if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK))) diff --git a/src/main.h b/src/main.h index c400145d015..f5e7f6c3e37 100644 --- a/src/main.h +++ b/src/main.h @@ -98,7 +98,6 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey); bool CheckProofOfWork(uint256 hash, unsigned int nBits); -int GetTotalBlocksEstimate(); bool IsInitialBlockDownload(); std::string GetWarnings(std::string strFor); diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index 24cc127c2d8..23b417cad18 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -38,6 +38,7 @@ CFLAGS=-O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATH HEADERS = \ base58.h \ bignum.h \ + checkpoints.h \ crypter.h \ db.h \ headers.h \ @@ -68,6 +69,7 @@ endif LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l shlwapi OBJS= \ + obj/checkpoints.o \ obj/crypter.o \ obj/db.o \ obj/init.o \ diff --git a/src/makefile.mingw b/src/makefile.mingw index 1ca1a7bbe25..ef7eebf4306 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -35,6 +35,7 @@ CFLAGS=-mthreads -O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(I HEADERS = \ base58.h \ bignum.h \ + checkpoints.h \ crypter.h \ db.h \ headers.h \ @@ -66,6 +67,7 @@ endif LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l shlwapi OBJS= \ + obj/checkpoints.o \ obj/crypter.o \ obj/db.o \ obj/init.o \ diff --git a/src/makefile.osx b/src/makefile.osx index 97264c7eb4c..af526369191 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -35,6 +35,7 @@ CFLAGS=-mmacosx-version-min=10.5 -arch i386 -arch x86_64 -O3 -Wno-invalid-offset HEADERS = \ base58.h \ bignum.h \ + checkpoints.h \ crypter.h \ db.h \ headers.h \ @@ -57,6 +58,7 @@ HEADERS = \ wallet.h OBJS= \ + obj/checkpoints.o \ obj/crypter.o \ obj/db.o \ obj/init.o \ diff --git a/src/makefile.unix b/src/makefile.unix index 9e0b3263d7a..a2cbc7c77e1 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -73,6 +73,7 @@ CXXFLAGS=-O2 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(HARDENING) HEADERS = \ base58.h \ bignum.h \ + checkpoints.h \ crypter.h \ db.h \ headers.h \ @@ -95,6 +96,7 @@ HEADERS = \ wallet.h OBJS= \ + obj/checkpoints.o \ obj/crypter.o \ obj/db.o \ obj/init.o \ diff --git a/src/makefile.vc b/src/makefile.vc index a5437bcf5cd..4c81cc400fc 100644 --- a/src/makefile.vc +++ b/src/makefile.vc @@ -48,6 +48,7 @@ CFLAGS=/MD /c /nologo /EHsc /GR /Zm300 $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) HEADERS = \ base58.h \ bignum.h \ + checkpoints.h \ crypter.h \ db.h \ headers.h \ @@ -70,6 +71,7 @@ HEADERS = \ wallet.h OBJS= \ + obj\checkpoints.o \ obj\crypter.o \ obj\db.o \ obj\init.o \ @@ -98,6 +100,8 @@ all: bitcoin.exe .cpp{obj}.obj: cl $(CFLAGS) /DGUI /Fo$@ %s +obj\checkpoints.obj: $(HEADERS) + obj\util.obj: $(HEADERS) obj\script.obj: $(HEADERS) @@ -140,6 +144,8 @@ bitcoin.exe: $(OBJS) $(CRYPTOPP_OBJS) obj\ui.obj obj\uibase.obj obj\ui.res .cpp{obj\nogui}.obj: cl $(CFLAGS) /Fo$@ %s +obj\nogui\checkpoints.obj: $(HEADERS) + obj\nogui\util.obj: $(HEADERS) obj\nogui\script.obj: $(HEADERS) diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp new file mode 100644 index 00000000000..0d8a366d7ac --- /dev/null +++ b/src/test/Checkpoints_tests.cpp @@ -0,0 +1,34 @@ +// +// Unit tests for block-chain checkpoints +// +#include // for 'map_list_of()' +#include +#include + +#include "../checkpoints.h" +#include "../util.h" + +using namespace std; + +BOOST_AUTO_TEST_SUITE(Checkpoints_tests) + +BOOST_AUTO_TEST_CASE(sanity) +{ + uint256 p11111 = uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"); + uint256 p140700 = uint256("0x000000000000033b512028abb90e1626d8b346fd0ed598ac0a3c371138dce2bd"); + BOOST_CHECK(Checkpoints::CheckBlock(11111, p11111)); + BOOST_CHECK(Checkpoints::CheckBlock(140700, p140700)); + + + // Wrong hashes at checkpoints should fail: + BOOST_CHECK(!Checkpoints::CheckBlock(11111, p140700)); + BOOST_CHECK(!Checkpoints::CheckBlock(140700, p11111)); + + // ... but any hash not at a checkpoint should succeed: + BOOST_CHECK(Checkpoints::CheckBlock(11111+1, p140700)); + BOOST_CHECK(Checkpoints::CheckBlock(140700+1, p11111)); + + BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 140700); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 0230bb6ecad..645d8a2bdfe 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -8,6 +8,7 @@ #include "uint256_tests.cpp" #include "script_tests.cpp" #include "transaction_tests.cpp" +#include "Checkpoints_tests.cpp" CWallet* pwalletMain; From 5d901f1ba0b2f4444e484b9cb3db8d86c428af3f Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 8 Sep 2011 12:51:43 -0400 Subject: [PATCH 3/3] Orphan block fill-up-memory attack prevention --- src/checkpoints.cpp | 32 +++++++++++++++++++++++++----- src/checkpoints.h | 7 +++++++ src/main.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++--- src/main.h | 1 + 4 files changed, 79 insertions(+), 8 deletions(-) diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 4419a06c830..c7e054df378 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -2,16 +2,23 @@ // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "checkpoints.h" -#include "uint256.h" -#include "util.h" - #include // for 'map_list_of()' +#include + +#include "headers.h" +#include "checkpoints.h" namespace Checkpoints { typedef std::map MapCheckpoints; + // + // What makes a good checkpoint block? + // + Is surrounded by blocks with reasonable timestamps + // (no blocks before with a timestamp after, none after with + // timestamp before) + // + Contains no strange transactions + // static MapCheckpoints mapCheckpoints = boost::assign::map_list_of ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) @@ -36,8 +43,23 @@ namespace Checkpoints int GetTotalBlocksEstimate() { - if (fTestNet) return 0; // Testnet has no checkpoints + if (fTestNet) return 0; return mapCheckpoints.rbegin()->first; } + + CBlockIndex* GetLastCheckpoint(const std::map& mapBlockIndex) + { + if (fTestNet) return NULL; + + int64 nResult; + BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints) + { + const uint256& hash = i.second; + std::map::const_iterator t = mapBlockIndex.find(hash); + if (t != mapBlockIndex.end()) + return t->second; + } + return NULL; + } } diff --git a/src/checkpoints.h b/src/checkpoints.h index 32094fdde62..9d52da404fb 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -4,7 +4,11 @@ #ifndef BITCOIN_CHECKPOINT_H #define BITCOIN_CHECKPOINT_H +#include +#include "util.h" + class uint256; +class CBlockIndex; // // Block-chain checkpoints are compiled-in sanity checks. @@ -17,6 +21,9 @@ namespace Checkpoints // Return conservative estimate of total number of blocks, 0 if unknown int GetTotalBlocksEstimate(); + + // Returns last CBlockIndex* in mapBlockIndex that is a checkpoint + CBlockIndex* GetLastCheckpoint(const std::map& mapBlockIndex); } #endif diff --git a/src/main.cpp b/src/main.cpp index dad7d144e7d..af00069d663 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -651,11 +651,32 @@ int64 static GetBlockValue(int nHeight, int64 nFees) return nSubsidy + nFees; } +static const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks +static const int64 nTargetSpacing = 10 * 60; +static const int64 nInterval = nTargetTimespan / nTargetSpacing; + +// +// minimum amount of work that could possibly be required nTime after +// minimum work required was nBase +// +unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) +{ + CBigNum bnResult; + bnResult.SetCompact(nBase); + while (nTime > 0 && bnResult < bnProofOfWorkLimit) + { + // Maximum 400% adjustment... + bnResult *= 4; + // ... in best-case exactly 4-times-normal target time + nTime -= nTargetTimespan*4; + } + if (bnResult > bnProofOfWorkLimit) + bnResult = bnProofOfWorkLimit; + return bnResult.GetCompact(); +} + unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast) { - const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks - const int64 nTargetSpacing = 10 * 60; - const int64 nInterval = nTargetTimespan / nTargetSpacing; // Genesis block if (pindexLast == NULL) @@ -1317,6 +1338,26 @@ bool static ProcessBlock(CNode* pfrom, CBlock* pblock) if (!pblock->CheckBlock()) return error("ProcessBlock() : CheckBlock FAILED"); + CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); + if (pcheckpoint && pblock->hashPrevBlock != hashBestChain) + { + // Extra checks to prevent "fill up memory by spamming with bogus blocks" + int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime; + if (deltaTime < 0) + { + return error("ProcessBlock() : block with timestamp before last checkpoint"); + } + CBigNum bnNewBlock; + bnNewBlock.SetCompact(pblock->nBits); + CBigNum bnRequired; + bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); + if (bnNewBlock > bnRequired) + { + return error("ProcessBlock() : block with too little proof-of-work"); + } + } + + // If don't already have its previous block, shunt it off to holding area until we get it if (!mapBlockIndex.count(pblock->hashPrevBlock)) { diff --git a/src/main.h b/src/main.h index f5e7f6c3e37..876a35d9cc3 100644 --- a/src/main.h +++ b/src/main.h @@ -98,6 +98,7 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey); bool CheckProofOfWork(uint256 hash, unsigned int nBits); +unsigned int ComputeMinWork(unsigned int nBase, int64 nTime); bool IsInitialBlockDownload(); std::string GetWarnings(std::string strFor);