diff options
-rw-r--r-- | bitcoin-qt.pro | 2 | ||||
-rw-r--r-- | doc/readme-qt.rst | 14 | ||||
-rw-r--r-- | src/bignum.h | 68 | ||||
-rw-r--r-- | src/bitcoinrpc.cpp | 4 | ||||
-rw-r--r-- | src/bitcoinrpc.h | 2 | ||||
-rw-r--r-- | src/checkpoints.cpp | 9 | ||||
-rw-r--r-- | src/init.cpp | 16 | ||||
-rwxr-xr-x | src/leveldb/build_detect_platform | 10 | ||||
-rw-r--r-- | src/main.cpp | 131 | ||||
-rw-r--r-- | src/main.h | 16 | ||||
-rw-r--r-- | src/makefile.mingw | 2 | ||||
-rw-r--r-- | src/noui.cpp | 2 | ||||
-rw-r--r-- | src/qt/bitcoin.cpp | 4 | ||||
-rw-r--r-- | src/qt/bitcoingui.cpp | 8 | ||||
-rw-r--r-- | src/qt/bitcoingui.h | 5 | ||||
-rw-r--r-- | src/qt/clientmodel.cpp | 2 | ||||
-rw-r--r-- | src/qt/clientmodel.h | 2 | ||||
-rw-r--r-- | src/qt/notificator.h | 8 | ||||
-rw-r--r-- | src/qt/walletmodel.cpp | 2 | ||||
-rw-r--r-- | src/qt/walletmodel.h | 2 | ||||
-rw-r--r-- | src/rpcwallet.cpp | 77 | ||||
-rw-r--r-- | src/test/bignum_tests.cpp | 53 | ||||
-rw-r--r-- | src/ui_interface.h | 4 | ||||
-rw-r--r-- | src/util.cpp | 2 | ||||
-rw-r--r-- | src/util.h | 8 | ||||
-rw-r--r-- | src/wallet.cpp | 40 | ||||
-rw-r--r-- | src/wallet.h | 7 |
27 files changed, 395 insertions, 105 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index e78318e28e..3b2de5af3b 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -24,6 +24,8 @@ UI_DIR = build contains(RELEASE, 1) { # Mac: compile for maximum compatibility (10.5, 32-bit) macx:QMAKE_CXXFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk + macx:QMAKE_CFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk + macx:QMAKE_OBJECTIVE_CFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk !windows:!macx { # Linux: static link diff --git a/doc/readme-qt.rst b/doc/readme-qt.rst index f6adbd8fdd..b0fdd4d810 100644 --- a/doc/readme-qt.rst +++ b/doc/readme-qt.rst @@ -8,7 +8,11 @@ Debian ------- First, make sure that the required packages for Qt4 development of your -distribution are installed, for Debian and Ubuntu these are: +distribution are installed, these are + +:: + +for Debian and Ubuntu <= 11.10 : :: @@ -16,6 +20,14 @@ distribution are installed, for Debian and Ubuntu these are: libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ libssl-dev libdb4.8++-dev +for Ubuntu >= 12.04 (please read the 'Berkely DB version warning' below): + +:: + + apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \ + libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ + libssl-dev libdb++-dev libminiupnpc-dev + then execute the following: :: diff --git a/src/bignum.h b/src/bignum.h index 96b1b2e6ae..ad98613f5f 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -262,28 +262,68 @@ public: return vch; } + // The "compact" format is a representation of a whole + // number N using an unsigned 32bit number similar to a + // floating point format. + // The most significant 8 bits are the unsigned exponent of base 256. + // This exponent can be thought of as "number of bytes of N". + // The lower 23 bits are the mantissa. + // Bit number 24 (0x800000) represents the sign of N. + // N = (-1^sign) * mantissa * 256^(exponent-3) + // + // Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). + // MPI uses the most significant bit of the first byte as sign. + // Thus 0x1234560000 is compact (0x05123456) + // and 0xc0de000000 is compact (0x0600c0de) + // (0x05c0de00) would be -0x40de000000 + // + // Bitcoin only uses this "compact" format for encoding difficulty + // targets, which are unsigned 256bit quantities. Thus, all the + // complexities of the sign bit and using base 256 are probably an + // implementation accident. + // + // This implementation directly uses shifts instead of going + // through an intermediate MPI representation. CBigNum& SetCompact(unsigned int nCompact) { unsigned int nSize = nCompact >> 24; - std::vector<unsigned char> vch(4 + nSize); - vch[3] = nSize; - if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff; - if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff; - if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff; - BN_mpi2bn(&vch[0], vch.size(), this); + bool fNegative =(nCompact & 0x00800000) != 0; + unsigned int nWord = nCompact & 0x007fffff; + if (nSize <= 3) + { + nWord >>= 8*(3-nSize); + BN_set_word(this, nWord); + } + else + { + BN_set_word(this, nWord); + BN_lshift(this, this, 8*(nSize-3)); + } + BN_set_negative(this, fNegative); return *this; } unsigned int GetCompact() const { - unsigned int nSize = BN_bn2mpi(this, NULL); - std::vector<unsigned char> vch(nSize); - nSize -= 4; - BN_bn2mpi(this, &vch[0]); - unsigned int nCompact = nSize << 24; - if (nSize >= 1) nCompact |= (vch[4] << 16); - if (nSize >= 2) nCompact |= (vch[5] << 8); - if (nSize >= 3) nCompact |= (vch[6] << 0); + unsigned int nSize = BN_num_bytes(this); + unsigned int nCompact = 0; + if (nSize <= 3) + nCompact = BN_get_word(this) << 8*(3-nSize); + else + { + CBigNum bn; + BN_rshift(&bn, this, 8*(nSize-3)); + nCompact = BN_get_word(&bn); + } + // The 0x00800000 bit denotes the sign. + // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. + if (nCompact & 0x00800000) + { + nCompact >>= 8; + nSize++; + } + nCompact |= nSize << 24; + nCompact |= (BN_is_negative(this) ? 0x00800000 : 0); return nCompact; } diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 481ceb9f40..bfb696da3d 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -254,6 +254,8 @@ static const CRPCCommand vRPCCommands[] = { "sendrawtransaction", &sendrawtransaction, false, false }, { "gettxoutsetinfo", &gettxoutsetinfo, true, false }, { "gettxout", &gettxout, true, false }, + { "lockunspent", &lockunspent, false, false }, + { "listlockunspent", &listlockunspent, false, false }, }; CRPCTable::CRPCTable() @@ -1215,6 +1217,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true); if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]); if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]); + if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]); + if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]); return params; } diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index dc4dc303a8..44050ae1bb 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -177,6 +177,8 @@ extern json_spirit::Value getinfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value lockunspent(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listlockunspent(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value createrawtransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp); diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 8208854962..279003072e 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -39,6 +39,9 @@ namespace Checkpoints bool CheckBlock(int nHeight, const uint256& hash) { + if (!GetBoolArg("-checkpoints", true)) + return true; + MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); MapCheckpoints::const_iterator i = checkpoints.find(nHeight); @@ -48,6 +51,9 @@ namespace Checkpoints int GetTotalBlocksEstimate() { + if (!GetBoolArg("-checkpoints", true)) + return 0; + MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); return checkpoints.rbegin()->first; @@ -55,6 +61,9 @@ namespace Checkpoints CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex) { + if (!GetBoolArg("-checkpoints", true)) + return NULL; + MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints) diff --git a/src/init.cpp b/src/init.cpp index e0fbb31338..7f311fa881 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -258,6 +258,7 @@ std::string HelpMessage() " -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4, IPv6 or Tor)") + "\n" + " -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n" + " -irc " + _("Find peers using internet relay chat (default: 0)") + "\n" + + " -checkpoints " + _("Lock in block chain with compiled-in checkpoints (default: 1)") + "\n" + " -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n" + " -bind=<addr> " + _("Bind to given address and always listen on it. Use [host]:port notation for IPv6") + "\n" + " -dnsseed " + _("Find peers using DNS lookup (default: 1 unless -connect)") + "\n" + @@ -345,10 +346,8 @@ void ThreadImport(void *data) { if (fReindex) { CImportingNow imp; int nFile = 0; - while (!fShutdown) { - CDiskBlockPos pos; - pos.nFile = nFile; - pos.nPos = 0; + while (!fRequestShutdown) { + CDiskBlockPos pos(nFile, 0); FILE *file = OpenBlockFile(pos, true); if (!file) break; @@ -356,7 +355,7 @@ void ThreadImport(void *data) { LoadExternalBlockFile(file, &pos); nFile++; } - if (!fShutdown) { + if (!fRequestShutdown) { pblocktree->WriteReindexing(false); fReindex = false; printf("Reindexing finished\n"); @@ -365,7 +364,7 @@ void ThreadImport(void *data) { // hardcoded $DATADIR/bootstrap.dat filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat"; - if (filesystem::exists(pathBootstrap) && !fShutdown) { + if (filesystem::exists(pathBootstrap) && !fRequestShutdown) { FILE *file = fopen(pathBootstrap.string().c_str(), "rb"); if (file) { CImportingNow imp; @@ -378,7 +377,7 @@ void ThreadImport(void *data) { // -loadblock= BOOST_FOREACH(boost::filesystem::path &path, import->vFiles) { - if (fShutdown) + if (fRequestShutdown) break; FILE *file = fopen(path.string().c_str(), "rb"); if (file) { @@ -483,6 +482,7 @@ bool AppInit2() // ********************************************************* Step 3: parameter-to-internal-flags fDebug = GetBoolArg("-debug"); + fBenchmark = GetBoolArg("-benchmark"); // -debug implies fDebug* if (fDebug) @@ -867,7 +867,7 @@ bool AppInit2() if (walletdb.ReadBestBlock(locator)) pindexRescan = locator.GetBlockIndex(); } - if (pindexBest != pindexRescan) + if (pindexBest && pindexBest != pindexRescan) { uiInterface.InitMessage(_("Rescanning...")); printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight); diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform index dd982236fd..b16a3aae7c 100755 --- a/src/leveldb/build_detect_platform +++ b/src/leveldb/build_detect_platform @@ -119,6 +119,16 @@ case "$TARGET_OS" in PLATFORM_EXTRALIBS="-lboost_system-mt-s -lboost_filesystem-mt-s -lboost_thread_win32-mt-s" CROSS_COMPILE=true ;; + NATIVE_WINDOWS) + PLATFORM=OS_WINDOWS + COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS -DBOOST_THREAD_USE_LIB" + PLATFORM_CXXFLAGS="" + PLATFORM_LDFLAGS="" + PLATFORM_SHARED_CFLAGS="" + PLATFORM_SOURCES="port/port_win.cc util/env_boost.cc util/win_logger.cc" + PLATFORM_EXTRALIBS="-lboost_system-mgw45-mt-s-1_50 -lboost_filesystem-mgw45-mt-s-1_50 -lboost_thread-mgw45-mt-s-1_50 -lboost_chrono-mgw45-mt-s-1_50" + CROSS_COMPILE=true + ;; *) echo "Unknown platform!" >&2 exit 1 diff --git a/src/main.cpp b/src/main.cpp index 944345abb2..61bd6b7b87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,6 +42,7 @@ set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid; // may contain int64 nTimeBestReceived = 0; bool fImporting = false; bool fReindex = false; +bool fBenchmark = false; unsigned int nCoinCacheSize = 5000; CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have @@ -1240,9 +1241,12 @@ bool ConnectBestBlock() { if (pindexTest->pprev == NULL || pindexTest->pnext != NULL) { reverse(vAttach.begin(), vAttach.end()); - BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) + BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) { + if (fRequestShutdown) + break; if (!SetBestChain(pindexSwitch)) return false; + } return true; } pindexTest = pindexTest->pprev; @@ -1535,17 +1539,19 @@ void static FlushBlockFile() { LOCK(cs_LastBlockFile); - CDiskBlockPos posOld; - posOld.nFile = nLastBlockFile; - posOld.nPos = 0; + CDiskBlockPos posOld(nLastBlockFile, 0); FILE *fileOld = OpenBlockFile(posOld); - FileCommit(fileOld); - fclose(fileOld); + if (fileOld) { + FileCommit(fileOld); + fclose(fileOld); + } fileOld = OpenUndoFile(posOld); - FileCommit(fileOld); - fclose(fileOld); + if (fileOld) { + FileCommit(fileOld); + fclose(fileOld); + } } bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize); @@ -1588,12 +1594,16 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust CBlockUndo blockundo; + int64 nStart = GetTimeMicros(); int64 nFees = 0; + int nInputs = 0; unsigned int nSigOps = 0; for (unsigned int i=0; i<vtx.size(); i++) { + const CTransaction &tx = vtx[i]; + nInputs += tx.vin.size(); nSigOps += tx.GetLegacySigOpCount(); if (nSigOps > MAX_BLOCK_SIGOPS) return DoS(100, error("ConnectBlock() : too many sigops")); @@ -1624,7 +1634,11 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust return error("ConnectBlock() : UpdateInputs failed"); if (!tx.IsCoinBase()) blockundo.vtxundo.push_back(txundo); + } + int64 nTime = GetTimeMicros() - nStart; + if (fBenchmark) + printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)vtx.size(), 0.001 * nTime, 0.001 * nTime / vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1)); if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees)) return error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)); @@ -1667,7 +1681,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust bool SetBestChain(CBlockIndex* pindexNew) { - CCoinsViewCache &view = *pcoinsTip; + // All modifications to the coin state will be done in this cache. + // Only when all have succeeded, we push it to pcoinsTip. + CCoinsViewCache view(*pcoinsTip, true); // special case for attaching the genesis block // note that no ConnectBlock is called, so its coinbase output is non-spendable @@ -1687,7 +1703,7 @@ bool SetBestChain(CBlockIndex* pindexNew) // Find the fork (typically, there is none) CBlockIndex* pfork = view.GetBestBlock(); CBlockIndex* plonger = pindexNew; - while (pfork != plonger) + while (pfork && pfork != plonger) { while (plonger->nHeight > pfork->nHeight) if (!(plonger = plonger->pprev)) @@ -1720,15 +1736,17 @@ bool SetBestChain(CBlockIndex* pindexNew) CBlock block; if (!block.ReadFromDisk(pindex)) return error("SetBestBlock() : ReadFromDisk for disconnect failed"); - CCoinsViewCache viewTemp(view, true); - if (!block.DisconnectBlock(pindex, viewTemp)) + int64 nStart = GetTimeMicros(); + if (!block.DisconnectBlock(pindex, view)) return error("SetBestBlock() : DisconnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str()); - if (!viewTemp.Flush()) - return error("SetBestBlock() : Cache flush failed after disconnect"); + if (fBenchmark) + printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); - // Queue memory transactions to resurrect + // Queue memory transactions to resurrect. + // We only do this for blocks after the last checkpoint (reorganisation before that + // point should only happen with -reindex/-loadblock, or a misbehaving peer. BOOST_FOREACH(const CTransaction& tx, block.vtx) - if (!tx.IsCoinBase()) + if (!tx.IsCoinBase() && pindex->nHeight > Checkpoints::GetTotalBlocksEstimate()) vResurrect.push_back(tx); } @@ -1738,26 +1756,35 @@ bool SetBestChain(CBlockIndex* pindexNew) CBlock block; if (!block.ReadFromDisk(pindex)) return error("SetBestBlock() : ReadFromDisk for connect failed"); - CCoinsViewCache viewTemp(view, true); - if (!block.ConnectBlock(pindex, viewTemp)) { + int64 nStart = GetTimeMicros(); + if (!block.ConnectBlock(pindex, view)) { InvalidChainFound(pindexNew); InvalidBlockFound(pindex); return error("SetBestBlock() : ConnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str()); } - if (!viewTemp.Flush()) - return error("SetBestBlock() : Cache flush failed after connect"); + if (fBenchmark) + printf("- Connect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); // Queue memory transactions to delete BOOST_FOREACH(const CTransaction& tx, block.vtx) vDelete.push_back(tx); } + // Flush changes to global coin state + int64 nStart = GetTimeMicros(); + int nModified = view.GetCacheSize(); + if (!view.Flush()) + return error("SetBestBlock() : unable to modify coin state"); + int64 nTime = GetTimeMicros() - nStart; + if (fBenchmark) + printf("- Flush %i transactions: %.2fms (%.4fms/tx)\n", nModified, 0.001 * nTime, 0.001 * nTime / nModified); + // Make sure it's successfully written to disk before changing memory structure bool fIsInitialDownload = IsInitialBlockDownload(); - if (!fIsInitialDownload || view.GetCacheSize() > nCoinCacheSize) { + if (!fIsInitialDownload || pcoinsTip->GetCacheSize() > nCoinCacheSize) { FlushBlockFile(); pblocktree->Sync(); - if (!view.Flush()) + if (!pcoinsTip->Flush()) return false; } @@ -1776,7 +1803,7 @@ bool SetBestChain(CBlockIndex* pindexNew) // Resurrect memory transactions that were in the disconnected branch BOOST_FOREACH(CTransaction& tx, vResurrect) - tx.AcceptToMemoryPool(false); + tx.AcceptToMemoryPool(); // Delete redundant memory transactions that are in the connected branch BOOST_FOREACH(CTransaction& tx, vDelete) { @@ -1893,6 +1920,7 @@ bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeigh nLastBlockFile = pos.nFile; infoLastBlockFile.SetNull(); pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile); + fUpdatedLast = true; } } else { while (infoLastBlockFile.nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { @@ -1914,12 +1942,16 @@ bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeigh unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; unsigned int nNewChunks = (infoLastBlockFile.nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; if (nNewChunks > nOldChunks) { - FILE *file = OpenBlockFile(pos); - if (file) { - printf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile); - AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos); - fclose(file); + if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos)) { + FILE *file = OpenBlockFile(pos); + if (file) { + printf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile); + AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos); + fclose(file); + } } + else + return error("FindBlockPos() : out of disk space"); } } @@ -1956,12 +1988,16 @@ bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize) unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; unsigned int nNewChunks = (nNewSize + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; if (nNewChunks > nOldChunks) { - FILE *file = OpenUndoFile(pos); - if (file) { - printf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); - AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos); - fclose(file); + if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) { + FILE *file = OpenUndoFile(pos); + if (file) { + printf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); + AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos); + fclose(file); + } } + else + return error("FindUndoPos() : out of disk space"); } return true; @@ -2086,12 +2122,8 @@ bool CBlock::AcceptBlock(CDiskBlockPos *dbp) // Write block to history file unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION); CDiskBlockPos blockPos; - if (dbp == NULL) { - if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION))) - return error("AcceptBlock() : out of disk space"); - } else { + if (dbp != NULL) blockPos = *dbp; - } if (!FindBlockPos(blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL)) return error("AcceptBlock() : FindBlockPos failed"); if (dbp == NULL) @@ -2318,13 +2350,18 @@ bool static LoadBlockIndexDB() if (pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile)) printf("LoadBlockIndex(): last block file: %s\n", infoLastBlockFile.ToString().c_str()); + // Load bnBestInvalidWork, OK if it doesn't exist + pblocktree->ReadBestInvalidWork(bnBestInvalidWork); + + // Check whether we need to continue reindexing + bool fReindexing = false; + pblocktree->ReadReindexing(fReindexing); + fReindex |= fReindexing; + // Load hashBestChain pointer to end of best chain pindexBest = pcoinsTip->GetBestBlock(); if (pindexBest == NULL) - { - if (pindexGenesisBlock == NULL) - return true; - } + return true; hashBestChain = pindexBest->GetBlockHash(); nBestHeight = pindexBest->nHeight; bnBestChainWork = pindexBest->bnChainWork; @@ -2340,14 +2377,6 @@ bool static LoadBlockIndexDB() BlockHashStr(hashBestChain).c_str(), nBestHeight, DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); - // Load bnBestInvalidWork, OK if it doesn't exist - pblocktree->ReadBestInvalidWork(bnBestInvalidWork); - - // Check whether we need to continue reindexing - bool fReindexing = false; - pblocktree->ReadReindexing(fReindexing); - fReindex |= fReindexing; - // Verify blocks in the best chain int nCheckLevel = GetArg("-checklevel", 1); int nCheckDepth = GetArg( "-checkblocks", 2500); @@ -2548,7 +2577,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) } } uint64 nRewind = blkdat.GetPos(); - while (blkdat.good() && !blkdat.eof() && !fShutdown) { + while (blkdat.good() && !blkdat.eof() && !fRequestShutdown) { blkdat.SetPos(nRewind); nRewind++; // start one byte further next time, in case of failure blkdat.SetLimit(); // remove former limit diff --git a/src/main.h b/src/main.h index 4bd4782ccb..fdaec3469e 100644 --- a/src/main.h +++ b/src/main.h @@ -89,6 +89,7 @@ extern std::set<CWallet*> setpwalletRegistered; extern unsigned char pchMessageStart[4]; extern bool fImporting; extern bool fReindex; +extern bool fBenchmark; extern unsigned int nCoinCacheSize; // Settings @@ -192,6 +193,15 @@ public: READWRITE(VARINT(nPos)); ) + CDiskBlockPos() { + SetNull(); + } + + CDiskBlockPos(int nFileIn, unsigned int nPosIn) { + nFile = nFileIn; + nPos = nPosIn; + } + friend bool operator==(const CDiskBlockPos &a, const CDiskBlockPos &b) { return (a.nFile == b.nFile && a.nPos == b.nPos); } @@ -1493,8 +1503,7 @@ public: if (nStatus & BLOCK_HAVE_DATA) { ret.nFile = nFile; ret.nPos = nDataPos; - } else - ret.SetNull(); + } return ret; } @@ -1503,8 +1512,7 @@ public: if (nStatus & BLOCK_HAVE_UNDO) { ret.nFile = nFile; ret.nPos = nUndoPos; - } else - ret.SetNull(); + } return ret; } diff --git a/src/makefile.mingw b/src/makefile.mingw index fd61d44709..22d65d6703 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -97,7 +97,7 @@ DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) # TODO: If this fails, try adding a ranlib libleveldb.a && ranlib libmemenv.a leveldb/libleveldb.a: cd leveldb && $(MAKE) libleveldb.a libmemenv.a && cd .. -obj/leveldb.o: leveldb/libleveldb.lib +obj/leveldb.o: leveldb/libleveldb.a obj/%.o: %.cpp $(HEADERS) g++ -c $(CFLAGS) -o $@ $< diff --git a/src/noui.cpp b/src/noui.cpp index ba2b1aab4d..204e76aba7 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -32,7 +32,7 @@ static int noui_ThreadSafeMessageBox(const std::string& message, const std::stri return 4; } -static bool noui_ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) +static bool noui_ThreadSafeAskFee(int64 /*nFeeRequired*/) { return true; } diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index d64114e131..dbdfade0b1 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -45,7 +45,6 @@ static void ThreadSafeMessageBox(const std::string& message, const std::string& modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(caption)), Q_ARG(QString, QString::fromStdString(message)), - Q_ARG(bool, modal), Q_ARG(unsigned int, style)); } else @@ -55,12 +54,13 @@ static void ThreadSafeMessageBox(const std::string& message, const std::string& } } -static bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) +static bool ThreadSafeAskFee(int64 nFeeRequired) { if(!guiref) return false; if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon) return true; + bool payFee = false; QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(), diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index aa45716c48..3fe86501f6 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -373,7 +373,7 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int))); // Receive and report messages from network/worker thread - connect(clientModel, SIGNAL(message(QString,QString,bool,unsigned int)), this, SLOT(message(QString,QString,bool,unsigned int))); + connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); overviewPage->setClientModel(clientModel); rpcConsole->setClientModel(clientModel); @@ -388,7 +388,7 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel) if(walletModel) { // Receive and report messages from wallet thread - connect(walletModel, SIGNAL(message(QString,QString,bool,unsigned int)), this, SLOT(message(QString,QString,bool,unsigned int))); + connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); // Put transaction list in tabs transactionView->setModel(walletModel); @@ -606,7 +606,7 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) progressBar->setToolTip(tooltip); } -void BitcoinGUI::message(const QString &title, const QString &message, bool modal, unsigned int style) +void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style) { QString strTitle = tr("Bitcoin") + " - "; // Default to information icon @@ -639,7 +639,7 @@ void BitcoinGUI::message(const QString &title, const QString &message, bool moda } // Display message - if (modal) { + if (style & CClientUIInterface::MODAL) { // Check for buttons, use OK as default, if none was supplied QMessageBox::StandardButton buttons; if (!(buttons = (QMessageBox::StandardButton)(style & CClientUIInterface::BTN_MASK))) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index ecb3244ad5..3faf6d948c 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -124,11 +124,10 @@ public slots: /** Notify the user of an event from the core network or transaction handling code. @param[in] title the message box / notification title @param[in] message the displayed text - @param[in] modal true to use a message box, false to use a notification - @param[in] style style definitions (icon and used buttons - buttons only for message boxes) + @param[in] style modality and style definitions (icon and used buttons - buttons only for message boxes) @see CClientUIInterface::MessageBoxFlags */ - void message(const QString &title, const QString &message, bool modal, unsigned int style); + void message(const QString &title, const QString &message, unsigned int style); /** Asks the user whether to pay the transaction fee or to cancel the transaction. It is currently not possible to pass a return value to another thread through BlockingQueuedConnection, so an indirected pointer is used. diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index f8fa412019..ce112803f8 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -84,7 +84,7 @@ void ClientModel::updateAlert(const QString &hash, int status) CAlert alert = CAlert::getAlertByHash(hash_256); if(!alert.IsNull()) { - emit message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), false, CClientUIInterface::ICON_ERROR); + emit message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR); } } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index b16b2d5004..1afccb7859 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -71,7 +71,7 @@ signals: void alertsChanged(const QString &warnings); //! Asynchronous message notification - void message(const QString &title, const QString &message, bool modal, unsigned int style); + void message(const QString &title, const QString &message, unsigned int style); public slots: void updateTimer(); diff --git a/src/qt/notificator.h b/src/qt/notificator.h index abb47109b3..833b52cb15 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -46,11 +46,11 @@ public slots: private: QWidget *parent; enum Mode { - None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ - Freedesktop, /**< Use DBus org.freedesktop.Notifications */ - QSystemTray, /**< Use QSystemTray::showMessage */ + None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ + Freedesktop, /**< Use DBus org.freedesktop.Notifications */ + QSystemTray, /**< Use QSystemTray::showMessage */ Growl12, /**< Use the Growl 1.2 notification system (Mac only) */ - Growl13 /**< Use the Growl 1.3 notification system (Mac only) */ + Growl13 /**< Use the Growl 1.3 notification system (Mac only) */ }; QString programName; Mode mode; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 3568616cd3..9d5a2c04ff 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -189,7 +189,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie } return TransactionCreationFailed; } - if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString())) + if(!uiInterface.ThreadSafeAskFee(nFeeRequired)) { return Aborted; } diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 3c8d5903b0..fd5c8c4d4f 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -148,7 +148,7 @@ signals: void requireUnlock(); // Asynchronous message notification - void message(const QString &title, const QString &message, bool modal, unsigned int style); + void message(const QString &title, const QString &message, unsigned int style); public slots: /* Wallet status might have changed */ diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index d597e5e3f7..90a68f560a 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -3,14 +3,18 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <boost/assign/list_of.hpp> + #include "wallet.h" #include "walletdb.h" #include "bitcoinrpc.h" #include "init.h" #include "base58.h" -using namespace json_spirit; using namespace std; +using namespace boost; +using namespace boost::assign; +using namespace json_spirit; int64 nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; @@ -1497,3 +1501,74 @@ Value validateaddress(const Array& params, bool fHelp) return ret; } +Value lockunspent(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "lockunspent unlock? [array-of-Objects]\n" + "Updates list of temporarily unspendable outputs."); + + if (params.size() == 1) + RPCTypeCheck(params, list_of(bool_type)); + else + RPCTypeCheck(params, list_of(bool_type)(array_type)); + + bool fUnlock = params[0].get_bool(); + + if (params.size() == 1) { + if (fUnlock) + pwalletMain->UnlockAllCoins(); + return true; + } + + Array outputs = params[1].get_array(); + BOOST_FOREACH(Value& output, outputs) + { + if (output.type() != obj_type) + throw JSONRPCError(-8, "Invalid parameter, expected object"); + const Object& o = output.get_obj(); + + RPCTypeCheck(o, map_list_of("txid", str_type)("vout", int_type)); + + string txid = find_value(o, "txid").get_str(); + if (!IsHex(txid)) + throw JSONRPCError(-8, "Invalid parameter, expected hex txid"); + + int nOutput = find_value(o, "vout").get_int(); + if (nOutput < 0) + throw JSONRPCError(-8, "Invalid parameter, vout must be positive"); + + COutPoint outpt(uint256(txid), nOutput); + + if (fUnlock) + pwalletMain->UnlockCoin(outpt); + else + pwalletMain->LockCoin(outpt); + } + + return true; +} + +Value listlockunspent(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 0) + throw runtime_error( + "listlockunspent\n" + "Returns list of temporarily unspendable outputs."); + + vector<COutPoint> vOutpts; + pwalletMain->ListLockedCoins(vOutpts); + + Array ret; + + BOOST_FOREACH(COutPoint &outpt, vOutpts) { + Object o; + + o.push_back(Pair("txid", outpt.hash.GetHex())); + o.push_back(Pair("vout", (int)outpt.n)); + ret.push_back(o); + } + + return ret; +} + diff --git a/src/test/bignum_tests.cpp b/src/test/bignum_tests.cpp index 744681871f..5b898d1499 100644 --- a/src/test/bignum_tests.cpp +++ b/src/test/bignum_tests.cpp @@ -122,4 +122,57 @@ BOOST_AUTO_TEST_CASE(bignum_setint64) } } + +BOOST_AUTO_TEST_CASE(bignum_SetCompact) +{ + CBigNum num; + num.SetCompact(0); + BOOST_CHECK_EQUAL(num.GetHex(), "0"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0); + + num.SetCompact(0x00123456); + BOOST_CHECK_EQUAL(num.GetHex(), "0"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0); + + num.SetCompact(0x01123456); + BOOST_CHECK_EQUAL(num.GetHex(), "12"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x01120000); + + // Make sure that we don't generate compacts with the 0x00800000 bit set + num = 0x80; + BOOST_CHECK_EQUAL(num.GetCompact(), 0x02008000); + + num.SetCompact(0x01fedcba); + BOOST_CHECK_EQUAL(num.GetHex(), "-7e"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x01fe0000); + + num.SetCompact(0x02123456); + BOOST_CHECK_EQUAL(num.GetHex(), "1234"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x02123400); + + num.SetCompact(0x03123456); + BOOST_CHECK_EQUAL(num.GetHex(), "123456"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x03123456); + + num.SetCompact(0x04123456); + BOOST_CHECK_EQUAL(num.GetHex(), "12345600"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x04123456); + + num.SetCompact(0x04923456); + BOOST_CHECK_EQUAL(num.GetHex(), "-12345600"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x04923456); + + num.SetCompact(0x05009234); + BOOST_CHECK_EQUAL(num.GetHex(), "92340000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x05009234); + + num.SetCompact(0x20123456); + BOOST_CHECK_EQUAL(num.GetHex(), "1234560000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x20123456); + + num.SetCompact(0xff123456); + BOOST_CHECK_EQUAL(num.GetHex(), "123456000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0xff123456); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/ui_interface.h b/src/ui_interface.h index 693411aa6d..703e15f095 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -62,7 +62,7 @@ public: MODAL = 0x10000000U, /** Predefined combinations for certain default usage cases */ - MSG_INFORMATION = (ICON_INFORMATION | BTN_OK), + MSG_INFORMATION = ICON_INFORMATION, MSG_WARNING = (ICON_WARNING | BTN_OK | MODAL), MSG_ERROR = (ICON_ERROR | BTN_OK | MODAL) }; @@ -71,7 +71,7 @@ public: boost::signals2::signal<void (const std::string& message, const std::string& caption, unsigned int style)> ThreadSafeMessageBox; /** Ask the user whether they want to pay a fee or not. */ - boost::signals2::signal<bool (int64 nFeeRequired, const std::string& strCaption), boost::signals2::last_value<bool> > ThreadSafeAskFee; + boost::signals2::signal<bool (int64 nFeeRequired), boost::signals2::last_value<bool> > ThreadSafeAskFee; /** Handle a URL passed at the command line. */ boost::signals2::signal<void (const std::string& strURI)> ThreadSafeHandleURI; diff --git a/src/util.cpp b/src/util.cpp index bd8ad8acd0..3cbc6b196b 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -64,7 +64,7 @@ bool fDebug = false; bool fDebugNet = false; bool fPrintToConsole = false; bool fPrintToDebugger = false; -bool fRequestShutdown = false; +volatile bool fRequestShutdown = false; bool fShutdown = false; bool fDaemon = false; bool fServer = false; diff --git a/src/util.h b/src/util.h index ada0dd3790..ab921e6f05 100644 --- a/src/util.h +++ b/src/util.h @@ -132,7 +132,7 @@ extern bool fDebug; extern bool fDebugNet; extern bool fPrintToConsole; extern bool fPrintToDebugger; -extern bool fRequestShutdown; +extern volatile bool fRequestShutdown; extern bool fShutdown; extern bool fDaemon; extern bool fServer; @@ -330,6 +330,12 @@ inline int64 GetTimeMillis() boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds(); } +inline int64 GetTimeMicros() +{ + return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - + boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds(); +} + inline std::string DateTimeStrFormat(const char* pszFormat, int64 nTime) { time_t n = nTime; diff --git a/src/wallet.cpp b/src/wallet.cpp index 1a74e7bb4c..c07adff6c6 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -957,9 +957,11 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed) const if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) continue; - for (unsigned int i = 0; i < pcoin->vout.size(); i++) - if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && pcoin->vout[i].nValue > 0) + for (unsigned int i = 0; i < pcoin->vout.size(); i++) { + if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && + !IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0) vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain())); + } } } } @@ -1310,7 +1312,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, return strError; } - if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired, _("Sending..."))) + if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired)) return "ABORTED"; if (!CommitTransaction(wtxNew, reservekey)) @@ -1770,3 +1772,35 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) NotifyTransactionChanged(this, hashTx, CT_UPDATED); } } + +void CWallet::LockCoin(COutPoint& output) +{ + setLockedCoins.insert(output); +} + +void CWallet::UnlockCoin(COutPoint& output) +{ + setLockedCoins.erase(output); +} + +void CWallet::UnlockAllCoins() +{ + setLockedCoins.clear(); +} + +bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const +{ + COutPoint outpt(hash, n); + + return (setLockedCoins.count(outpt) > 0); +} + +void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) +{ + for (std::set<COutPoint>::iterator it = setLockedCoins.begin(); + it != setLockedCoins.end(); it++) { + COutPoint outpt = (*it); + vOutpts.push_back(outpt); + } +} + diff --git a/src/wallet.h b/src/wallet.h index 05d60056f4..ecfdafe2eb 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -119,11 +119,18 @@ public: CPubKey vchDefaultKey; + std::set<COutPoint> setLockedCoins; + // check whether we are allowed to upgrade (or already support) to the named feature bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; } void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true) const; bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const; + bool IsLockedCoin(uint256 hash, unsigned int n) const; + void LockCoin(COutPoint& output); + void UnlockCoin(COutPoint& output); + void UnlockAllCoins(); + void ListLockedCoins(std::vector<COutPoint>& vOutpts); // keystore implementation // Generate a new key |