aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bitcoin-qt.pro2
-rw-r--r--doc/readme-qt.rst14
-rw-r--r--src/bignum.h68
-rw-r--r--src/bitcoinrpc.cpp4
-rw-r--r--src/bitcoinrpc.h2
-rw-r--r--src/checkpoints.cpp9
-rw-r--r--src/init.cpp16
-rwxr-xr-xsrc/leveldb/build_detect_platform10
-rw-r--r--src/main.cpp131
-rw-r--r--src/main.h16
-rw-r--r--src/makefile.mingw2
-rw-r--r--src/noui.cpp2
-rw-r--r--src/qt/bitcoin.cpp4
-rw-r--r--src/qt/bitcoingui.cpp8
-rw-r--r--src/qt/bitcoingui.h5
-rw-r--r--src/qt/clientmodel.cpp2
-rw-r--r--src/qt/clientmodel.h2
-rw-r--r--src/qt/notificator.h8
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/qt/walletmodel.h2
-rw-r--r--src/rpcwallet.cpp77
-rw-r--r--src/test/bignum_tests.cpp53
-rw-r--r--src/ui_interface.h4
-rw-r--r--src/util.cpp2
-rw-r--r--src/util.h8
-rw-r--r--src/wallet.cpp40
-rw-r--r--src/wallet.h7
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