--- /dev/null
+src/version.cpp export-subst
src/*.exe
src/bitcoin
src/bitcoind
+src/build.h
.*.swp
*.*~*
*.bak
TEMPLATE = app
TARGET =
-VERSION = 0.6.0.7
+VERSION = 0.6.1
INCLUDEPATH += src src/json src/qt
DEFINES += QT_GUI BOOST_THREAD_USE_LIB
CONFIG += no_include_pwd
QT += dbus
}
-# use: qmake "USE_SSL=1"
-contains(USE_SSL, 1) {
- message(Building with SSL support for RPC)
- DEFINES += USE_SSL
-}
-
# use: qmake "FIRST_CLASS_MESSAGING=1"
contains(FIRST_CLASS_MESSAGING, 1) {
message(Building with first-class messaging)
# do not enable this on windows, as it will result in a non-working executable!
}
-# disable quite some warnings because bitcoin core "sins" a lot
-QMAKE_CXXFLAGS_WARN_ON = -fdiagnostics-show-option -Wall -Wno-strict-aliasing -Wno-invalid-offsetof -Wno-unused-variable -Wno-unused-parameter -Wno-sign-compare -Wno-char-subscripts -Wno-unused-value -Wno-sequence-point -Wno-parentheses -Wno-unknown-pragmas -Wno-switch
+# regenerate src/build.h
+!windows || contains(USE_BUILD_INFO, 1) {
+ genbuild.depends = FORCE
+ genbuild.commands = cd $$PWD; share/genbuild.sh $$OUT_PWD/build/build.h
+ genbuild.target = genbuildhook
+ PRE_TARGETDEPS += genbuildhook
+ QMAKE_EXTRA_TARGETS += genbuild
+ DEFINES += HAVE_BUILD_INFO
+}
+
+QMAKE_CXXFLAGS_WARN_ON = -fdiagnostics-show-option -Wall -Wextra -Wformat -Wformat-security -Wno-invalid-offsetof -Wno-sign-compare -Wno-unused-parameter
# Input
DEPENDPATH += src src/json src/qt
src/net.h \
src/key.h \
src/db.h \
+ src/walletdb.h \
src/script.h \
- src/noui.h \
src/init.h \
- src/headers.h \
src/irc.h \
src/mruset.h \
src/json/json_spirit_writer_template.h \
src/qt/guiconstants.h \
src/qt/optionsmodel.h \
src/qt/monitoreddatamapper.h \
- src/qtui.h \
src/qt/transactiondesc.h \
src/qt/transactiondescdialog.h \
src/qt/bitcoinamountfield.h \
src/qt/askpassphrasedialog.h \
src/protocol.h \
src/qt/notificator.h \
- src/qt/qtipcserver.h
+ src/qt/qtipcserver.h \
+ src/allocators.h \
+ src/ui_interface.h
SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/qt/transactiontablemodel.cpp \
src/qt/aboutdialog.cpp \
src/qt/editaddressdialog.cpp \
src/qt/bitcoinaddressvalidator.cpp \
+ src/version.cpp \
src/util.cpp \
src/netbase.cpp \
src/key.cpp \
src/checkpoints.cpp \
src/addrman.cpp \
src/db.cpp \
+ src/walletdb.cpp \
src/json/json_spirit_writer.cpp \
src/json/json_spirit_value.cpp \
src/json/json_spirit_reader.cpp \
cd src; $(MAKE) -f makefile.unix clean
override_dh_auto_configure:
- qmake bitcoin-qt.pro USE_SSL=1 USE_QRCODE=1
+ qmake bitcoin-qt.pro USE_QRCODE=1
override_dh_auto_test:
cd src; $(MAKE) -f makefile.unix test_bitcoin
#
cd bitcoin
mkdir -p $OUTDIR/src
- cp -a . $OUTDIR/src
- rm -rf $OUTDIR/src/.git
+ git archive HEAD | tar -x -C $OUTDIR/src
cp $OUTDIR/src/doc/README_windows.txt $OUTDIR/readme.txt
cp $OUTDIR/src/COPYING $OUTDIR/license.txt
export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1
export FAKETIME=$REFERENCE_DATETIME
export TZ=UTC
- $HOME/qt/src/bin/qmake -spec unsupported/win32-g++-cross USE_SSL=1 MINIUPNPC_LIB_PATH=$HOME/build/miniupnpc MINIUPNPC_INCLUDE_PATH=$HOME/build/ BDB_LIB_PATH=$HOME/build/db-4.8.30.NC/build_unix BDB_INCLUDE_PATH=$HOME/build/db-4.8.30.NC/build_unix BOOST_LIB_PATH=$HOME/build/boost_1_47_0/stage/lib BOOST_INCLUDE_PATH=$HOME/build/boost_1_47_0 BOOST_LIB_SUFFIX=-mt-s BOOST_THREAD_LIB_SUFFIX=_win32-mt-s OPENSSL_LIB_PATH=$HOME/build/openssl-1.0.1b OPENSSL_INCLUDE_PATH=$HOME/build/openssl-1.0.1b/include QRENCODE_LIB_PATH=$HOME/build/qrencode-3.2.0/.libs QRENCODE_INCLUDE_PATH=$HOME/build/qrencode-3.2.0 USE_QRCODE=1 INCLUDEPATH=$HOME/build DEFINES=BOOST_THREAD_USE_LIB BITCOIN_NEED_QT_PLUGINS=1 QMAKE_LRELEASE=lrelease QMAKE_CXXFLAGS=-frandom-seed=bitcoin QMAKE_LFLAGS=-frandom-seed=bitcoin
+ $HOME/qt/src/bin/qmake -spec unsupported/win32-g++-cross MINIUPNPC_LIB_PATH=$HOME/build/miniupnpc MINIUPNPC_INCLUDE_PATH=$HOME/build/ BDB_LIB_PATH=$HOME/build/db-4.8.30.NC/build_unix BDB_INCLUDE_PATH=$HOME/build/db-4.8.30.NC/build_unix BOOST_LIB_PATH=$HOME/build/boost_1_47_0/stage/lib BOOST_INCLUDE_PATH=$HOME/build/boost_1_47_0 BOOST_LIB_SUFFIX=-mt-s BOOST_THREAD_LIB_SUFFIX=_win32-mt-s OPENSSL_LIB_PATH=$HOME/build/openssl-1.0.1b OPENSSL_INCLUDE_PATH=$HOME/build/openssl-1.0.1b/include QRENCODE_LIB_PATH=$HOME/build/qrencode-3.2.0/.libs QRENCODE_INCLUDE_PATH=$HOME/build/qrencode-3.2.0 USE_QRCODE=1 INCLUDEPATH=$HOME/build DEFINES=BOOST_THREAD_USE_LIB BITCOIN_NEED_QT_PLUGINS=1 QMAKE_LRELEASE=lrelease QMAKE_CXXFLAGS=-frandom-seed=bitcoin QMAKE_LFLAGS=-frandom-seed=bitcoin USE_BUILD_INFO=1
make $MAKEOPTS
cp release/bitcoin-qt.exe $OUTDIR/
#
cd src
- sed 's/$(DEBUGFLAGS)/-frandom-seed=bitcoin/' -i makefile.linux-mingw
export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1
export FAKETIME=$REFERENCE_DATETIME
export TZ=UTC
- make -f makefile.linux-mingw $MAKEOPTS DEPSDIR=$HOME/build bitcoind.exe USE_SSL=1 USE_UPNP=0
+ make -f makefile.linux-mingw $MAKEOPTS DEPSDIR=$HOME/build bitcoind.exe USE_UPNP=0 DEBUGFLAGS="-frandom-seed=bitcoin"
i586-mingw32msvc-strip bitcoind.exe
- makensis ../share/setup.nsi
- cp ../share/bitcoin-*-win32-setup.exe $OUTDIR/
mkdir $OUTDIR/daemon
cp bitcoind.exe $OUTDIR/daemon
+ cd ..
+ mkdir nsis
+ git archive HEAD | tar -x -C nsis
+ cd nsis/src
+ mkdir ../release
+ cp ../../release/* ../release/
+ cp ../../src/*.exe .
+ makensis ../share/setup.nsi
+ cp ../share/bitcoin-*-win32-setup.exe $OUTDIR/
#
cd bitcoin
mkdir -p $OUTDIR/src
- cp -a . $OUTDIR/src
- rm -rf $OUTDIR/src/.git
+ git archive HEAD | tar -x -C $OUTDIR/src
cp $OUTDIR/src/doc/README $OUTDIR
cp $OUTDIR/src/COPYING $OUTDIR
cd src
- sed 's/$(DEBUGFLAGS)//' -i makefile.unix
- make -f makefile.unix STATIC=1 OPENSSL_INCLUDE_PATH="$INSTDIR/include" OPENSSL_LIB_PATH="$INSTDIR/lib" $MAKEOPTS bitcoind USE_UPNP=0 USE_SSL=1
+ make -f makefile.unix STATIC=1 OPENSSL_INCLUDE_PATH="$INSTDIR/include" OPENSSL_LIB_PATH="$INSTDIR/lib" $MAKEOPTS bitcoind USE_UPNP=0 DEBUGFLAGS=
mkdir -p $OUTDIR/bin/$GBUILD_BITS
install -s bitcoind $OUTDIR/bin/$GBUILD_BITS
cd ..
- qmake INCLUDEPATH="$INSTDIR/include" LIBS="-L$INSTDIR/lib" RELEASE=1 USE_SSL=1 USE_QRCODE=1
+ qmake INCLUDEPATH="$INSTDIR/include" LIBS="-L$INSTDIR/lib" RELEASE=1 USE_QRCODE=1
make $MAKEOPTS
install bitcoin-qt $OUTDIR/bin/$GBUILD_BITS
-Bitcoin 0.6.0.7 BETA
+Bitcoin 0.6.1 BETA
Copyright (c) 2009-2012 Bitcoin Developers
Distributed under the MIT/X11 software license, see the accompanying
-Bitcoin 0.6.0.7 BETA\r
+Bitcoin 0.6.1 BETA\r
\r
Copyright (c) 2009-2012 Bitcoin Developers\r
Distributed under the MIT/X11 software license, see the accompanying\r
* update (commit) version in sources
bitcoin-qt.pro
- src/main.h (CLIENT_VERSION : PROTOCOL_VERSION in serialize.h is updated only on protocol changes)
+ src/version.h
share/setup.nsi
doc/README*
Gavin also had trouble with the macports py27-appscript package; he
ended up installing a version that worked with: /usr/bin/easy_install-2.7 appscript
- qmake RELEASE=1 USE_SSL=1 USE_UPNP=1 USE_QRCODE=1 bitcoin-qt.pro
+ qmake RELEASE=1 USE_UPNP=1 USE_QRCODE=1 bitcoin-qt.pro
make
export QTDIR=/opt/local/share/qt4 # needed to find translations/qt_*.qm files
T=$(contrib/qt_translations.py $QTDIR/translations src/qt/locale)
+++ /dev/null
-make_windows_icon.sh
\ No newline at end of file
--- /dev/null
+#!/bin/sh
+
+if [ $# -gt 0 ]; then
+ FILE="$1"
+ shift
+ if [ -f "$FILE" ]; then
+ INFO="$(head -n 1 "$FILE")"
+ fi
+else
+ echo "Usage: $0 <filename>"
+ exit 1
+fi
+
+if [ -e "$(which git)" ]; then
+ # clean 'dirty' status of touched files that haven't been modified
+ git diff >/dev/null 2>/dev/null
+
+ # get a string like "v0.6.0-66-g59887e8-dirty"
+ DESC="$(git describe --dirty 2>/dev/null)"
+
+ # get a string like "2012-04-10 16:27:19 +0200"
+ TIME="$(git log -n 1 --format="%ci")"
+fi
+
+if [ -n "$DESC" ]; then
+ NEWINFO="#define BUILD_DESC \"$DESC\""
+else
+ NEWINFO="// No build information available"
+fi
+
+# only update build.h if necessary
+if [ "$INFO" != "$NEWINFO" ]; then
+ echo "$NEWINFO" >"$FILE"
+ echo "#define BUILD_DATE \"$TIME\"" >>"$FILE"
+fi
they can be picked up by Qt linguist.
'''
from subprocess import Popen, PIPE
+import glob
OUT_CPP="src/qt/bitcoinstrings.cpp"
EMPTY=['""']
return messages
-files = ['src/base58.h', 'src/bignum.h', 'src/db.cpp', 'src/db.h', 'src/headers.h', 'src/init.cpp', 'src/init.h', 'src/irc.cpp', 'src/irc.h', 'src/key.h', 'src/main.cpp', 'src/main.h', 'src/net.cpp', 'src/net.h', 'src/noui.h', 'src/script.cpp', 'src/script.h', 'src/serialize.h', 'src/strlcpy.h', 'src/uint256.h', 'src/util.cpp', 'src/util.h']
+files = glob.glob('src/*.cpp') + glob.glob('src/*.h')
# xgettext -n --keyword=_ $FILES
child = Popen(['xgettext','--output=-','-n','--keyword=_'] + files, stdout=PIPE)
\r
# General Symbol Definitions\r
!define REGKEY "SOFTWARE\$(^Name)"\r
-!define VERSION 0.6.0.7\r
+!define VERSION 0.6.1\r
!define COMPANY "Bitcoin project"\r
!define URL http://www.bitcoin.org/\r
\r
!insertmacro MUI_LANGUAGE English\r
\r
# Installer attributes\r
-OutFile bitcoin-0.6.0.7-win32-setup.exe\r
+OutFile bitcoin-0.6.1-win32-setup.exe\r
InstallDir $PROGRAMFILES\Bitcoin\r
CRCCheck on\r
XPStyle on\r
BrandingText " "\r
ShowInstDetails show\r
-VIProductVersion 0.6.0.7\r
+VIProductVersion 0.6.1.3\r
VIAddVersionKey ProductName Bitcoin\r
VIAddVersionKey ProductVersion "${VERSION}"\r
VIAddVersionKey CompanyName "${COMPANY}"\r
int CAddrInfo::GetTriedBucket(const std::vector<unsigned char> &nKey) const
{
- CDataStream ss1(SER_GETHASH);
+ CDataStream ss1(SER_GETHASH, 0);
std::vector<unsigned char> vchKey = GetKey();
ss1 << nKey << vchKey;
uint64 hash1 = Hash(ss1.begin(), ss1.end()).Get64();
- CDataStream ss2(SER_GETHASH);
+ CDataStream ss2(SER_GETHASH, 0);
std::vector<unsigned char> vchGroupKey = GetGroup();
ss2 << nKey << vchGroupKey << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP);
uint64 hash2 = Hash(ss2.begin(), ss2.end()).Get64();
int CAddrInfo::GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAddr& src) const
{
- CDataStream ss1(SER_GETHASH);
+ CDataStream ss1(SER_GETHASH, 0);
std::vector<unsigned char> vchGroupKey = GetGroup();
std::vector<unsigned char> vchSourceGroupKey = src.GetGroup();
ss1 << nKey << vchGroupKey << vchSourceGroupKey;
uint64 hash1 = Hash(ss1.begin(), ss1.end()).Get64();
- CDataStream ss2(SER_GETHASH);
+ CDataStream ss2(SER_GETHASH, 0);
ss2 << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP);
uint64 hash2 = Hash(ss2.begin(), ss2.end()).Get64();
return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
//
// This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
// changes to the ADDRMAN_ parameters without breaking the on-disk structure.
- CRITICAL_BLOCK(cs)
{
+ LOCK(cs);
unsigned char nVersion = 0;
READWRITE(nVersion);
READWRITE(nKey);
void Check()
{
#ifdef DEBUG_ADDRMAN
- CRITICAL_BLOCK(cs)
{
+ LOCK(cs);
int err;
if ((err=Check_()))
printf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
bool Add(const CAddress &addr, const CNetAddr& source, int64 nTimePenalty = 0)
{
bool fRet = false;
- CRITICAL_BLOCK(cs)
{
+ LOCK(cs);
Check();
fRet |= Add_(addr, source, nTimePenalty);
Check();
bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64 nTimePenalty = 0)
{
int nAdd = 0;
- CRITICAL_BLOCK(cs)
{
+ LOCK(cs);
Check();
for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
// Mark an entry as accessible.
void Good(const CService &addr, int64 nTime = GetAdjustedTime())
{
- CRITICAL_BLOCK(cs)
{
+ LOCK(cs);
Check();
Good_(addr, nTime);
Check();
// Mark an entry as connection attempted to.
void Attempt(const CService &addr, int64 nTime = GetAdjustedTime())
{
- CRITICAL_BLOCK(cs)
{
+ LOCK(cs);
Check();
Attempt_(addr, nTime);
Check();
CAddress Select(int nUnkBias = 50)
{
CAddress addrRet;
- CRITICAL_BLOCK(cs)
{
+ LOCK(cs);
Check();
addrRet = Select_(nUnkBias);
Check();
{
Check();
std::vector<CAddress> vAddr;
- CRITICAL_BLOCK(cs)
+ {
+ LOCK(cs);
GetAddr_(vAddr);
+ }
Check();
return vAddr;
}
// Mark an entry as currently-connected-to.
void Connected(const CService &addr, int64 nTime = GetAdjustedTime())
{
- CRITICAL_BLOCK(cs)
{
+ LOCK(cs);
Check();
Connected_(addr, nTime);
Check();
--- /dev/null
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2012 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_ALLOCATORS_H
+#define BITCOIN_ALLOCATORS_H
+
+#include <string.h>
+#include <string>
+
+#ifdef WIN32
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0501
+#define WIN32_LEAN_AND_MEAN 1
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <windows.h>
+// This is used to attempt to keep keying material out of swap
+// Note that VirtualLock does not provide this as a guarantee on Windows,
+// but, in practice, memory that has been VirtualLock'd almost never gets written to
+// the pagefile except in rare circumstances where memory is extremely low.
+#define mlock(p, n) VirtualLock((p), (n));
+#define munlock(p, n) VirtualUnlock((p), (n));
+#else
+#include <sys/mman.h>
+#include <limits.h>
+/* This comes from limits.h if it's not defined there set a sane default */
+#ifndef PAGESIZE
+#include <unistd.h>
+#define PAGESIZE sysconf(_SC_PAGESIZE)
+#endif
+#define mlock(a,b) \
+ mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
+ (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
+#define munlock(a,b) \
+ munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
+ (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
+#endif
+
+//
+// Allocator that locks its contents from being paged
+// out of memory and clears its contents before deletion.
+//
+template<typename T>
+struct secure_allocator : public std::allocator<T>
+{
+ // MSVC8 default copy constructor is broken
+ typedef std::allocator<T> base;
+ typedef typename base::size_type size_type;
+ typedef typename base::difference_type difference_type;
+ typedef typename base::pointer pointer;
+ typedef typename base::const_pointer const_pointer;
+ typedef typename base::reference reference;
+ typedef typename base::const_reference const_reference;
+ typedef typename base::value_type value_type;
+ secure_allocator() throw() {}
+ secure_allocator(const secure_allocator& a) throw() : base(a) {}
+ template <typename U>
+ secure_allocator(const secure_allocator<U>& a) throw() : base(a) {}
+ ~secure_allocator() throw() {}
+ template<typename _Other> struct rebind
+ { typedef secure_allocator<_Other> other; };
+
+ T* allocate(std::size_t n, const void *hint = 0)
+ {
+ T *p;
+ p = std::allocator<T>::allocate(n, hint);
+ if (p != NULL)
+ mlock(p, sizeof(T) * n);
+ return p;
+ }
+
+ void deallocate(T* p, std::size_t n)
+ {
+ if (p != NULL)
+ {
+ memset(p, 0, sizeof(T) * n);
+ munlock(p, sizeof(T) * n);
+ }
+ std::allocator<T>::deallocate(p, n);
+ }
+};
+
+
+//
+// Allocator that clears its contents before deletion.
+//
+template<typename T>
+struct zero_after_free_allocator : public std::allocator<T>
+{
+ // MSVC8 default copy constructor is broken
+ typedef std::allocator<T> base;
+ typedef typename base::size_type size_type;
+ typedef typename base::difference_type difference_type;
+ typedef typename base::pointer pointer;
+ typedef typename base::const_pointer const_pointer;
+ typedef typename base::reference reference;
+ typedef typename base::const_reference const_reference;
+ typedef typename base::value_type value_type;
+ zero_after_free_allocator() throw() {}
+ zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {}
+ template <typename U>
+ zero_after_free_allocator(const zero_after_free_allocator<U>& a) throw() : base(a) {}
+ ~zero_after_free_allocator() throw() {}
+ template<typename _Other> struct rebind
+ { typedef zero_after_free_allocator<_Other> other; };
+
+ void deallocate(T* p, std::size_t n)
+ {
+ if (p != NULL)
+ memset(p, 0, sizeof(T) * n);
+ std::allocator<T>::deallocate(p, n);
+ }
+};
+
+// This is exactly like std::string, but with a custom allocator.
+// (secure_allocator<> is defined in serialize.h)
+typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
+
+#endif
--- a/src/allocators.h
#include <vector>
#include <openssl/bn.h>
-#include "util.h"
+#include "util.h" // for uint64
/** Errors thrown by the bignum class */
class bignum_error : public std::runtime_error
};
-/** C++ wrapper for BIGNUM (OpenSSl bignum) */
+/** C++ wrapper for BIGNUM (OpenSSL bignum) */
class CBigNum : public BIGNUM
{
public:
{
unsigned long n = BN_get_word(this);
if (!BN_is_negative(this))
- return (n > std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n);
+ return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n);
else
- return (n > std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n);
+ return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n);
}
void setint64(int64 n)
if (vch.size() > 4)
vch[4] &= 0x7f;
uint256 n = 0;
- for (int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--)
+ for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--)
((unsigned char*)&n)[i] = vch[j];
return n;
}
// 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 "main.h"
+#include "wallet.h"
#include "db.h"
+#include "walletdb.h"
#include "net.h"
#include "init.h"
+#include "ui_interface.h"
+#include "bitcoinrpc.h"
+
#undef printf
#include <boost/asio.hpp>
#include <boost/filesystem.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
-#ifdef USE_SSL
#include <boost/asio/ssl.hpp>
-#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
-#endif
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_writer_template.h"
-#include "json/json_spirit_utils.h"
+
#define printf OutputDebugStringF
// MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
// precompiled in headers.h. The problem might be when the pch file goes over
using namespace json_spirit;
void ThreadRPCServer2(void* parg);
-typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
-extern map<string, rpcfn_type> mapCallTable;
static std::string strRPCUserColonPass;
{
Object result;
result.push_back(Pair("hash", block.GetHash().GetHex()));
- result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK)));
+ result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion));
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
/// Note: This interface may still be subject to change.
///
-
-Value help(const Array& params, bool fHelp)
+string CRPCTable::help(string strCommand) const
{
- if (fHelp || params.size() > 1)
- throw runtime_error(
- "help [command]\n"
- "List commands, or get help for a command.");
-
- string strCommand;
- if (params.size() > 0)
- strCommand = params[0].get_str();
-
string strRet;
set<rpcfn_type> setDone;
- for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
+ for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
{
- string strMethod = (*mi).first;
+ const CRPCCommand *pcmd = mi->second;
+ string strMethod = mi->first;
// We already filter duplicates, but these deprecated screw up the sort order
if (strMethod == "getamountreceived" ||
strMethod == "getallreceived" ||
try
{
Array params;
- rpcfn_type pfn = (*mi).second;
+ rpcfn_type pfn = pcmd->actor;
if (setDone.insert(pfn).second)
(*pfn)(params, true);
}
return strRet;
}
+Value help(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 1)
+ throw runtime_error(
+ "help [command]\n"
+ "List commands, or get help for a command.");
+
+ string strCommand;
+ if (params.size() > 0)
+ strCommand = params[0].get_str();
+
+ return tableRPC.help(strCommand);
+}
+
Value stop(const Array& params, bool fHelp)
{
throw runtime_error(
"stop\n"
"Stop bitcoin server.");
-#ifndef QT_GUI
// Shutdown will take long enough that the response should get back
- CreateThread(Shutdown, NULL);
+ QueueShutdown();
return "bitcoin server stopping";
-#else
- throw runtime_error("NYI: cannot shut down GUI with RPC command");
-#endif
}
obj.push_back(Pair("generate", GetBoolArg("-gen")));
obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
- obj.push_back(Pair("pooledtx", (uint64_t)nPooledTx));
+ obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
obj.push_back(Pair("testnet", fTestNet));
return obj;
}
if (!pwalletMain->GetKey(addr, key))
throw JSONRPCError(-4, "Private key not available");
- CDataStream ss(SER_GETHASH);
+ CDataStream ss(SER_GETHASH, 0);
ss << strMessageMagic;
ss << strMessage;
if (fInvalid)
throw JSONRPCError(-5, "Malformed base64 encoding");
- CDataStream ss(SER_GETHASH);
+ CDataStream ss(SER_GETHASH, 0);
ss << strMessageMagic;
ss << strMessage;
"If [account] is specified, assign address to [account].";
throw runtime_error(msg);
}
- if (!fTestNet)
- throw runtime_error("addmultisigaddress available only when running -testnet\n");
int nRequired = params[0].get_int();
const Array& keys = params[1].get_array();
// Gather public keys
if (nRequired < 1)
throw runtime_error("a multisignature address must require at least one key to redeem");
- if (keys.size() < nRequired)
+ if ((int)keys.size() < nRequired)
throw runtime_error(
strprintf("not enough keys supplied "
"(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
}
// ret is newest to oldest
- if (nFrom > ret.size()) nFrom = ret.size();
- if (nFrom+nCount > ret.size()) nCount = ret.size()-nFrom;
+ if (nFrom > (int)ret.size())
+ nFrom = ret.size();
+ if ((nFrom + nCount) > (int)ret.size())
+ nCount = ret.size() - nFrom;
Array::iterator first = ret.begin();
std::advance(first, nFrom);
Array::iterator last = ret.begin();
if (!pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
- CRITICAL_BLOCK(cs_nWalletUnlockTime)
{
+ LOCK(cs_nWalletUnlockTime);
pwalletMain->Lock();
nWalletUnlockTime = 0;
}
if (pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
-#ifdef QT_GUI
- // shutting down via RPC while the GUI is running does not work (yet):
- throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
-#endif
-
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
// Alternately, find a way to make params[0] mlock()'d to begin with.
SecureString strWalletPass;
// BDB seems to have a bad habit of writing old data into
// slack space in .dat files; that is bad if the old data is
// unencrypted private keys. So:
- CreateThread(Shutdown, NULL);
+ QueueShutdown();
return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
}
if(tx.IsCoinBase())
continue;
- CDataStream ssTx;
+ CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << tx;
transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
else
{
// Parse parameters
- CDataStream ssBlock(ParseHex(params[0].get_str()));
+ CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
CBlock pblock;
ssBlock >> pblock;
// Call Table
//
-pair<string, rpcfn_type> pCallTable[] =
-{
- make_pair("help", &help),
- make_pair("stop", &stop),
- make_pair("getblockcount", &getblockcount),
- make_pair("getblocknumber", &getblocknumber),
- make_pair("getconnectioncount", &getconnectioncount),
- make_pair("getdifficulty", &getdifficulty),
- make_pair("getgenerate", &getgenerate),
- make_pair("setgenerate", &setgenerate),
- make_pair("gethashespersec", &gethashespersec),
- make_pair("getinfo", &getinfo),
- make_pair("getmininginfo", &getmininginfo),
- make_pair("getnewaddress", &getnewaddress),
- make_pair("getaccountaddress", &getaccountaddress),
- make_pair("setaccount", &setaccount),
- make_pair("getaccount", &getaccount),
- make_pair("getaddressesbyaccount", &getaddressesbyaccount),
- make_pair("sendtoaddress", &sendtoaddress),
- make_pair("getreceivedbyaddress", &getreceivedbyaddress),
- make_pair("getreceivedbyaccount", &getreceivedbyaccount),
- make_pair("listreceivedbyaddress", &listreceivedbyaddress),
- make_pair("listreceivedbyaccount", &listreceivedbyaccount),
- make_pair("backupwallet", &backupwallet),
- make_pair("keypoolrefill", &keypoolrefill),
- make_pair("walletpassphrase", &walletpassphrase),
- make_pair("walletpassphrasechange", &walletpassphrasechange),
- make_pair("walletlock", &walletlock),
- make_pair("encryptwallet", &encryptwallet),
- make_pair("validateaddress", &validateaddress),
- make_pair("getbalance", &getbalance),
- make_pair("move", &movecmd),
- make_pair("sendfrom", &sendfrom),
- make_pair("sendmany", &sendmany),
- make_pair("addmultisigaddress", &addmultisigaddress),
- make_pair("getblock", &getblock),
- make_pair("getblockhash", &getblockhash),
- make_pair("gettransaction", &gettransaction),
- make_pair("listtransactions", &listtransactions),
- make_pair("signmessage", &signmessage),
- make_pair("verifymessage", &verifymessage),
- make_pair("getwork", &getwork),
- make_pair("listaccounts", &listaccounts),
- make_pair("settxfee", &settxfee),
- make_pair("getmemorypool", &getmemorypool),
- make_pair("listsinceblock", &listsinceblock),
- make_pair("dumpprivkey", &dumpprivkey),
- make_pair("importprivkey", &importprivkey)
-};
-map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
-
-string pAllowInSafeMode[] =
-{
- "help",
- "stop",
- "getblockcount",
- "getblocknumber", // deprecated
- "getconnectioncount",
- "getdifficulty",
- "getgenerate",
- "setgenerate",
- "gethashespersec",
- "getinfo",
- "getmininginfo",
- "getnewaddress",
- "getaccountaddress",
- "getaccount",
- "getaddressesbyaccount",
- "backupwallet",
- "keypoolrefill",
- "walletpassphrase",
- "walletlock",
- "validateaddress",
- "getwork",
- "getmemorypool",
+
+static const CRPCCommand vRPCCommands[] =
+{ // name function safe mode?
+ // ------------------------ ----------------------- ----------
+ { "help", &help, true },
+ { "stop", &stop, true },
+ { "getblockcount", &getblockcount, true },
+ { "getblocknumber", &getblocknumber, true },
+ { "getconnectioncount", &getconnectioncount, true },
+ { "getdifficulty", &getdifficulty, true },
+ { "getgenerate", &getgenerate, true },
+ { "setgenerate", &setgenerate, true },
+ { "gethashespersec", &gethashespersec, true },
+ { "getinfo", &getinfo, true },
+ { "getmininginfo", &getmininginfo, true },
+ { "getnewaddress", &getnewaddress, true },
+ { "getaccountaddress", &getaccountaddress, true },
+ { "setaccount", &setaccount, true },
+ { "getaccount", &getaccount, false },
+ { "getaddressesbyaccount", &getaddressesbyaccount, true },
+ { "sendtoaddress", &sendtoaddress, false },
+ { "getreceivedbyaddress", &getreceivedbyaddress, false },
+ { "getreceivedbyaccount", &getreceivedbyaccount, false },
+ { "listreceivedbyaddress", &listreceivedbyaddress, false },
+ { "listreceivedbyaccount", &listreceivedbyaccount, false },
+ { "backupwallet", &backupwallet, true },
+ { "keypoolrefill", &keypoolrefill, true },
+ { "walletpassphrase", &walletpassphrase, true },
+ { "walletpassphrasechange", &walletpassphrasechange, false },
+ { "walletlock", &walletlock, true },
+ { "encryptwallet", &encryptwallet, false },
+ { "validateaddress", &validateaddress, true },
+ { "getbalance", &getbalance, false },
+ { "move", &movecmd, false },
+ { "sendfrom", &sendfrom, false },
+ { "sendmany", &sendmany, false },
+ { "addmultisigaddress", &addmultisigaddress, false },
+ { "getblock", &getblock, false },
+ { "getblockhash", &getblockhash, false },
+ { "gettransaction", &gettransaction, false },
+ { "listtransactions", &listtransactions, false },
+ { "signmessage", &signmessage, false },
+ { "verifymessage", &verifymessage, false },
+ { "getwork", &getwork, true },
+ { "listaccounts", &listaccounts, false },
+ { "settxfee", &settxfee, false },
+ { "getmemorypool", &getmemorypool, true },
+ { "listsinceblock", &listsinceblock, false },
+ { "dumpprivkey", &dumpprivkey, false },
+ { "importprivkey", &importprivkey, false },
};
-set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
+CRPCTable::CRPCTable()
+{
+ unsigned int vcidx;
+ for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
+ {
+ const CRPCCommand *pcmd;
+ pcmd = &vRPCCommands[vcidx];
+ mapCommands[pcmd->name] = pcmd;
+ }
+}
+const CRPCCommand *CRPCTable::operator[](string name) const
+{
+ map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
+ if (it == mapCommands.end())
+ return NULL;
+ return (*it).second;
+}
//
// HTTP protocol
// Read header
int nLen = ReadHTTPHeader(stream, mapHeadersRet);
- if (nLen < 0 || nLen > MAX_SIZE)
+ if (nLen < 0 || nLen > (int)MAX_SIZE)
return 500;
// Read message
return false;
}
-#ifdef USE_SSL
//
// IOStream device that speaks SSL but can also speak non-SSL
//
bool fUseSSL;
SSLStream& stream;
};
-#endif
void ThreadRPCServer(void* parg)
{
printf("ThreadRPCServer exiting\n");
}
-#ifdef QT_GUI
-extern bool HACK_SHUTDOWN;
-#endif
-
void ThreadRPCServer2(void* parg)
{
printf("ThreadRPCServer started\n");
"(you do not need to remember this password)\n"
"If the file does not exist, create it with owner-readable-only file permissions.\n"),
strWhatAmI.c_str(),
- GetConfigFile().c_str(),
+ GetConfigFile().string().c_str(),
EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
_("Error"), wxOK | wxMODAL);
-#ifndef QT_GUI
- CreateThread(Shutdown, NULL);
-#endif
+ QueueShutdown();
return;
}
asio::io_service io_service;
ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
-#ifndef QT_GUI
- ip::tcp::acceptor acceptor(io_service, endpoint);
-
- acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
-#else
ip::tcp::acceptor acceptor(io_service);
try
{
}
catch(boost::system::system_error &e)
{
- HACK_SHUTDOWN = true;
ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
_("Error"), wxOK | wxMODAL);
+ QueueShutdown();
return;
}
-#endif
-#ifdef USE_SSL
ssl::context context(io_service, ssl::context::sslv23);
if (fUseSSL)
{
context.set_options(ssl::context::no_sslv2);
- filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
- if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
- if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
- else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
- filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
- if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
- if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
- else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
-
- string ciphers = GetArg("-rpcsslciphers",
- "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
- SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
- }
-#else
- if (fUseSSL)
- throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
-#endif
+
+ filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
+ if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
+ if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
+ else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
+
+ filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
+ if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
+ if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
+ else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
+
+ string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
+ SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
+ }
loop
{
// Accept connection
-#ifdef USE_SSL
SSLStream sslStream(io_service, context);
SSLIOStreamDevice d(sslStream, fUseSSL);
iostreams::stream<SSLIOStreamDevice> stream(d);
-#else
- ip::tcp::iostream stream;
-#endif
ip::tcp::endpoint peer;
vnThreadsRunning[THREAD_RPCSERVER]--;
-#ifdef USE_SSL
acceptor.accept(sslStream.lowest_layer(), peer);
-#else
- acceptor.accept(*stream.rdbuf(), peer);
-#endif
vnThreadsRunning[4]++;
if (fShutdown)
return;
throw JSONRPCError(-32600, "Params must be an array");
// Find method
- map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
- if (mi == mapCallTable.end())
+ const CRPCCommand *pcmd = tableRPC[strMethod];
+ if (!pcmd)
throw JSONRPCError(-32601, "Method not found");
// Observe safe mode
string strWarning = GetWarnings("rpc");
- if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
+ if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
+ !pcmd->okSafeMode)
throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
try
{
// Execute
Value result;
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(pwalletMain->cs_wallet)
- result = (*(*mi).second)(params, false);
+ {
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+ result = pcmd->actor(params, false);
+ }
// Send reply
string strReply = JSONRPCReply(result, Value::null, id);
throw runtime_error(strprintf(
_("You must set rpcpassword=<password> in the configuration file:\n%s\n"
"If the file does not exist, create it with owner-readable-only file permissions."),
- GetConfigFile().c_str()));
+ GetConfigFile().string().c_str()));
// Connect to localhost
bool fUseSSL = GetBoolArg("-rpcssl");
-#ifdef USE_SSL
asio::io_service io_service;
ssl::context context(io_service, ssl::context::sslv23);
context.set_options(ssl::context::no_sslv2);
iostreams::stream<SSLIOStreamDevice> stream(d);
if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
throw runtime_error("couldn't connect to server");
-#else
- if (fUseSSL)
- throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
-
- ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
- if (stream.fail())
- throw runtime_error("couldn't connect to server");
-#endif
-
// HTTP basic authentication
string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
return 0;
}
#endif
+
+const CRPCTable tableRPC;
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+#ifndef _BITCOINRPC_H_
+#define _BITCOINRPC_H_ 1
+
+#include <string>
+#include <map>
+
+#include "json/json_spirit_reader_template.h"
+#include "json/json_spirit_writer_template.h"
+#include "json/json_spirit_utils.h"
+
void ThreadRPCServer(void* parg);
int CommandLineRPC(int argc, char *argv[]);
+
+typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp);
+
+class CRPCCommand
+{
+public:
+ std::string name;
+ rpcfn_type actor;
+ bool okSafeMode;
+};
+
+class CRPCTable
+{
+private:
+ std::map<std::string, const CRPCCommand*> mapCommands;
+public:
+ CRPCTable();
+ const CRPCCommand* operator[](std::string name) const;
+ std::string help(std::string name) const;
+};
+
+extern const CRPCTable tableRPC;
+
+#endif
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>
-#include "headers.h"
#include "checkpoints.h"
+#include "main.h"
+#include "uint256.h"
+
namespace Checkpoints
{
typedef std::map<int, uint256> MapCheckpoints;
#define BITCOIN_CHECKPOINT_H
#include <map>
-#include "util.h"
class uint256;
class CBlockIndex;
#ifndef _BITCOIN_COMPAT_H
#define _BITCOIN_COMPAT_H 1
+#ifdef WIN32
+#define _WIN32_WINNT 0x0501
+#define WIN32_LEAN_AND_MEAN 1
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <winsock2.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <ifaddrs.h>
+#endif
+
typedef u_int SOCKET;
#ifdef WIN32
#define MSG_NOSIGNAL 0
}
#define closesocket(s) myclosesocket(s)
+
#endif
#include <openssl/evp.h>
#include <vector>
#include <string>
-#include "headers.h"
#ifdef WIN32
#include <windows.h>
#endif
#include "crypter.h"
-#include "main.h"
-#include "util.h"
bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
{
#ifndef __CRYPTER_H__
#define __CRYPTER_H__
-#include "util.h" /* for SecureString */
+#include "allocators.h" /* for SecureString */
#include "key.h"
+#include "serialize.h"
const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
// 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 "db.h"
-#include "net.h"
+#include "util.h"
+#include "main.h"
#include <boost/version.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
+#ifndef WIN32
+#include "sys/stat.h"
+#endif
+
using namespace std;
using namespace boost;
unsigned int nWalletDBUpdated;
-uint64 nAccountingEntryNumber = 0;
// CDB
//
-static CCriticalSection cs_db;
+CCriticalSection cs_db;
static bool fDbEnvInit = false;
+bool fDetachDB = false;
DbEnv dbenv(0);
-static map<string, int> mapFileUseCount;
+map<string, int> mapFileUseCount;
static map<string, Db*> mapDb;
-static int64 nTxn = 0;
static void EnvShutdown()
{
{
printf("EnvShutdown exception: %s (%d)\n", e.what(), e.get_errno());
}
- DbEnv(0).remove(GetDataDir().c_str(), 0);
+ DbEnv(0).remove(GetDataDir().string().c_str(), 0);
}
class CDBInit
instance_of_cdbinit;
-CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL)
+CDB::CDB(const char *pszFile, const char* pszMode) : pdb(NULL)
{
int ret;
if (pszFile == NULL)
if (fCreate)
nFlags |= DB_CREATE;
- CRITICAL_BLOCK(cs_db)
{
+ LOCK(cs_db);
if (!fDbEnvInit)
{
if (fShutdown)
return;
- string strDataDir = GetDataDir();
- string strLogDir = strDataDir + "/database";
- filesystem::create_directory(strLogDir.c_str());
- string strErrorFile = strDataDir + "/db.log";
- printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str());
+ filesystem::path pathDataDir = GetDataDir();
+ filesystem::path pathLogDir = pathDataDir / "database";
+ filesystem::create_directory(pathLogDir);
+ filesystem::path pathErrorFile = pathDataDir / "db.log";
+ printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str());
int nDbCache = GetArg("-dbcache", 25);
- dbenv.set_lg_dir(strLogDir.c_str());
+ dbenv.set_lg_dir(pathLogDir.string().c_str());
dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
dbenv.set_lg_bsize(1048576);
dbenv.set_lg_max(10485760);
dbenv.set_lk_max_locks(10000);
dbenv.set_lk_max_objects(10000);
- dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug
+ dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
dbenv.set_flags(DB_AUTO_COMMIT, 1);
dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
- ret = dbenv.open(strDataDir.c_str(),
+ ret = dbenv.open(pathDataDir.string().c_str(),
DB_CREATE |
DB_INIT_LOCK |
DB_INIT_LOG |
{
delete pdb;
pdb = NULL;
- CRITICAL_BLOCK(cs_db)
+ {
+ LOCK(cs_db);
--mapFileUseCount[strFile];
+ }
strFile = "";
throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret));
}
nMinutes = 1;
if (strFile == "addr.dat")
nMinutes = 2;
+ if (strFile == "blkindex.dat")
+ nMinutes = 2;
if (strFile == "blkindex.dat" && IsInitialBlockDownload())
nMinutes = 5;
- if (nMinutes == 0 || nTxn > 200000)
- {
- nTxn = 0;
- nMinutes = 0;
- }
-
- dbenv.txn_checkpoint(0, nMinutes, 0);
+ dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0);
- CRITICAL_BLOCK(cs_db)
+ {
+ LOCK(cs_db);
--mapFileUseCount[strFile];
+ }
}
-void static CloseDb(const string& strFile)
+void CloseDb(const string& strFile)
{
- CRITICAL_BLOCK(cs_db)
{
+ LOCK(cs_db);
if (mapDb[strFile] != NULL)
{
// Close the database handle
{
while (!fShutdown)
{
- CRITICAL_BLOCK(cs_db)
{
+ LOCK(cs_db);
if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0)
{
// Flush log data to the dat file
if (pcursor)
while (fSuccess)
{
- CDataStream ssKey;
- CDataStream ssValue;
+ CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+ CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
if (ret == DB_NOTFOUND)
{
printf("DBFlush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started");
if (!fDbEnvInit)
return;
- CRITICAL_BLOCK(cs_db)
{
+ LOCK(cs_db);
map<string, int>::iterator mi = mapFileUseCount.begin();
while (mi != mapFileUseCount.end())
{
{
// Move log data to the dat file
CloseDb(strFile);
+ printf("%s checkpoint\n", strFile.c_str());
dbenv.txn_checkpoint(0, 0, 0);
- printf("%s flush\n", strFile.c_str());
- dbenv.lsn_reset(strFile.c_str(), 0);
+ if ((strFile != "blkindex.dat" && strFile != "addr.dat") || fDetachDB) {
+ printf("%s detach\n", strFile.c_str());
+ dbenv.lsn_reset(strFile.c_str(), 0);
+ }
+ printf("%s closed\n", strFile.c_str());
mapFileUseCount.erase(mi++);
}
else
bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
{
assert(!fClient);
- nTxn++;
return Write(make_pair(string("tx"), hash), txindex);
}
// Add to tx index
uint256 hash = tx.GetHash();
CTxIndex txindex(pos, tx.vout.size());
- nTxn++;
return Write(make_pair(string("tx"), hash), txindex);
}
loop
{
// Read next record
- CDataStream ssKey;
+ CDataStream ssKey(SER_DISK, CLIENT_VERSION);
if (fFlags == DB_SET_RANGE)
ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0);
- CDataStream ssValue;
+ CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
fFlags = DB_NEXT;
if (ret == DB_NOTFOUND)
loop
{
// Read next record
- CDataStream ssKey;
+ CDataStream ssKey(SER_DISK, CLIENT_VERSION);
if (fFlags == DB_SET_RANGE)
ssKey << make_pair(string("blockindex"), uint256(0));
- CDataStream ssValue;
+ CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
fFlags = DB_NEXT;
if (ret == DB_NOTFOUND)
// Unserialize
string strType;
ssKey >> strType;
- if (strType == "blockindex")
+ if (strType == "blockindex" && !fRequestShutdown)
{
CDiskBlockIndex diskindex;
ssValue >> diskindex;
}
else
{
- break;
+ break; // if shutdown requested or finished loading block index
}
}
pcursor->close();
+ if (fRequestShutdown)
+ return true;
+
// Calculate bnChainWork
vector<pair<int, CBlockIndex*> > vSortedByHeight;
vSortedByHeight.reserve(mapBlockIndex.size());
}
}
// check level 4: check whether spent txouts were spent within the main chain
- int nOutput = 0;
+ unsigned int nOutput = 0;
if (nCheckLevel>3)
{
BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent)
loop
{
// Read next record
- CDataStream ssKey;
- CDataStream ssValue;
+ CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+ CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int ret = ReadAtCursor(pcursor, ssKey, ssValue);
if (ret == DB_NOTFOUND)
break;
}
-
-
-//
-// CWalletDB
-//
-
-bool CWalletDB::WriteName(const string& strAddress, const string& strName)
-{
- nWalletDBUpdated++;
- return Write(make_pair(string("name"), strAddress), strName);
-}
-
-bool CWalletDB::EraseName(const string& strAddress)
-{
- // This should only be used for sending addresses, never for receiving addresses,
- // receiving addresses must always have an address book entry if they're not change return.
- nWalletDBUpdated++;
- return Erase(make_pair(string("name"), strAddress));
-}
-
-bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
-{
- account.SetNull();
- return Read(make_pair(string("acc"), strAccount), account);
-}
-
-bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
-{
- return Write(make_pair(string("acc"), strAccount), account);
-}
-
-bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
-{
- return Write(boost::make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry);
-}
-
-int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
-{
- list<CAccountingEntry> entries;
- ListAccountCreditDebit(strAccount, entries);
-
- int64 nCreditDebit = 0;
- BOOST_FOREACH (const CAccountingEntry& entry, entries)
- nCreditDebit += entry.nCreditDebit;
-
- return nCreditDebit;
-}
-
-void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
-{
- bool fAllAccounts = (strAccount == "*");
-
- Dbc* pcursor = GetCursor();
- if (!pcursor)
- throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
- unsigned int fFlags = DB_SET_RANGE;
- loop
- {
- // Read next record
- CDataStream ssKey;
- if (fFlags == DB_SET_RANGE)
- ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0));
- CDataStream ssValue;
- int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
- fFlags = DB_NEXT;
- if (ret == DB_NOTFOUND)
- break;
- else if (ret != 0)
- {
- pcursor->close();
- throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB");
- }
-
- // Unserialize
- string strType;
- ssKey >> strType;
- if (strType != "acentry")
- break;
- CAccountingEntry acentry;
- ssKey >> acentry.strAccount;
- if (!fAllAccounts && acentry.strAccount != strAccount)
- break;
-
- ssValue >> acentry;
- entries.push_back(acentry);
- }
-
- pcursor->close();
-}
-
-
-int CWalletDB::LoadWallet(CWallet* pwallet)
-{
- pwallet->vchDefaultKey.clear();
- int nFileVersion = 0;
- vector<uint256> vWalletUpgrade;
- bool fIsEncrypted = false;
-
- //// todo: shouldn't we catch exceptions and try to recover and continue?
- CRITICAL_BLOCK(pwallet->cs_wallet)
- {
- int nMinVersion = 0;
- if (Read((string)"minversion", nMinVersion))
- {
- if (nMinVersion > CLIENT_VERSION)
- return DB_TOO_NEW;
- pwallet->LoadMinVersion(nMinVersion);
- }
-
- // Get cursor
- Dbc* pcursor = GetCursor();
- if (!pcursor)
- {
- printf("Error getting wallet database cursor\n");
- return DB_CORRUPT;
- }
-
- loop
- {
- // Read next record
- CDataStream ssKey;
- CDataStream ssValue;
- int ret = ReadAtCursor(pcursor, ssKey, ssValue);
- if (ret == DB_NOTFOUND)
- break;
- else if (ret != 0)
- {
- printf("Error reading next record from wallet database\n");
- return DB_CORRUPT;
- }
-
- // Unserialize
- // Taking advantage of the fact that pair serialization
- // is just the two items serialized one after the other
- string strType;
- ssKey >> strType;
- if (strType == "name")
- {
- string strAddress;
- ssKey >> strAddress;
- ssValue >> pwallet->mapAddressBook[strAddress];
- }
- else if (strType == "tx")
- {
- uint256 hash;
- ssKey >> hash;
- CWalletTx& wtx = pwallet->mapWallet[hash];
- ssValue >> wtx;
- wtx.BindWallet(pwallet);
-
- if (wtx.GetHash() != hash)
- printf("Error in wallet.dat, hash mismatch\n");
-
- // Undo serialize changes in 31600
- if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
- {
- if (!ssValue.empty())
- {
- char fTmp;
- char fUnused;
- ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
- printf("LoadWallet() upgrading tx ver=%d %d '%s' %s\n", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str());
- wtx.fTimeReceivedIsTxTime = fTmp;
- }
- else
- {
- printf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str());
- wtx.fTimeReceivedIsTxTime = 0;
- }
- vWalletUpgrade.push_back(hash);
- }
-
- //// debug print
- //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str());
- //printf(" %12"PRI64d" %s %s %s\n",
- // wtx.vout[0].nValue,
- // DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
- // wtx.hashBlock.ToString().substr(0,20).c_str(),
- // wtx.mapValue["message"].c_str());
- }
- else if (strType == "acentry")
- {
- string strAccount;
- ssKey >> strAccount;
- uint64 nNumber;
- ssKey >> nNumber;
- if (nNumber > nAccountingEntryNumber)
- nAccountingEntryNumber = nNumber;
- }
- else if (strType == "key" || strType == "wkey")
- {
- vector<unsigned char> vchPubKey;
- ssKey >> vchPubKey;
- CKey key;
- if (strType == "key")
- {
- CPrivKey pkey;
- ssValue >> pkey;
- key.SetPubKey(vchPubKey);
- key.SetPrivKey(pkey);
- if (key.GetPubKey() != vchPubKey)
- {
- printf("Error reading wallet database: CPrivKey pubkey inconsistency\n");
- return DB_CORRUPT;
- }
- if (!key.IsValid())
- {
- printf("Error reading wallet database: invalid CPrivKey\n");
- return DB_CORRUPT;
- }
- }
- else
- {
- CWalletKey wkey;
- ssValue >> wkey;
- key.SetPubKey(vchPubKey);
- key.SetPrivKey(wkey.vchPrivKey);
- if (key.GetPubKey() != vchPubKey)
- {
- printf("Error reading wallet database: CWalletKey pubkey inconsistency\n");
- return DB_CORRUPT;
- }
- if (!key.IsValid())
- {
- printf("Error reading wallet database: invalid CWalletKey\n");
- return DB_CORRUPT;
- }
- }
- if (!pwallet->LoadKey(key))
- {
- printf("Error reading wallet database: LoadKey failed\n");
- return DB_CORRUPT;
- }
- }
- else if (strType == "mkey")
- {
- unsigned int nID;
- ssKey >> nID;
- CMasterKey kMasterKey;
- ssValue >> kMasterKey;
- if(pwallet->mapMasterKeys.count(nID) != 0)
- {
- printf("Error reading wallet database: duplicate CMasterKey id %u\n", nID);
- return DB_CORRUPT;
- }
- pwallet->mapMasterKeys[nID] = kMasterKey;
- if (pwallet->nMasterKeyMaxID < nID)
- pwallet->nMasterKeyMaxID = nID;
- }
- else if (strType == "ckey")
- {
- vector<unsigned char> vchPubKey;
- ssKey >> vchPubKey;
- vector<unsigned char> vchPrivKey;
- ssValue >> vchPrivKey;
- if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
- {
- printf("Error reading wallet database: LoadCryptedKey failed\n");
- return DB_CORRUPT;
- }
- fIsEncrypted = true;
- }
- else if (strType == "defaultkey")
- {
- ssValue >> pwallet->vchDefaultKey;
- }
- else if (strType == "pool")
- {
- int64 nIndex;
- ssKey >> nIndex;
- pwallet->setKeyPool.insert(nIndex);
- }
- else if (strType == "version")
- {
- ssValue >> nFileVersion;
- if (nFileVersion == 10300)
- nFileVersion = 300;
- }
- else if (strType == "cscript")
- {
- uint160 hash;
- ssKey >> hash;
- CScript script;
- ssValue >> script;
- if (!pwallet->LoadCScript(script))
- {
- printf("Error reading wallet database: LoadCScript failed\n");
- return DB_CORRUPT;
- }
- }
- }
- pcursor->close();
- }
-
- BOOST_FOREACH(uint256 hash, vWalletUpgrade)
- WriteTx(hash, pwallet->mapWallet[hash]);
-
- printf("nFileVersion = %d\n", nFileVersion);
-
-
- // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
- if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000))
- return DB_NEED_REWRITE;
-
- if (nFileVersion < CLIENT_VERSION) // Update
- {
- // Get rid of old debug.log file in current directory
- if (nFileVersion <= 105 && !pszSetDataDir[0])
- unlink("debug.log");
-
- WriteVersion(CLIENT_VERSION);
- }
-
- return DB_LOAD_OK;
-}
-
-void ThreadFlushWalletDB(void* parg)
-{
- const string& strFile = ((const string*)parg)[0];
- static bool fOneThread;
- if (fOneThread)
- return;
- fOneThread = true;
- if (!GetBoolArg("-flushwallet", true))
- return;
-
- unsigned int nLastSeen = nWalletDBUpdated;
- unsigned int nLastFlushed = nWalletDBUpdated;
- int64 nLastWalletUpdate = GetTime();
- while (!fShutdown)
- {
- Sleep(500);
-
- if (nLastSeen != nWalletDBUpdated)
- {
- nLastSeen = nWalletDBUpdated;
- nLastWalletUpdate = GetTime();
- }
-
- if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
- {
- TRY_CRITICAL_BLOCK(cs_db)
- {
- // Don't do this if any databases are in use
- int nRefCount = 0;
- map<string, int>::iterator mi = mapFileUseCount.begin();
- while (mi != mapFileUseCount.end())
- {
- nRefCount += (*mi).second;
- mi++;
- }
-
- if (nRefCount == 0 && !fShutdown)
- {
- map<string, int>::iterator mi = mapFileUseCount.find(strFile);
- if (mi != mapFileUseCount.end())
- {
- printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
- printf("Flushing wallet.dat\n");
- nLastFlushed = nWalletDBUpdated;
- int64 nStart = GetTimeMillis();
-
- // Flush wallet.dat so it's self contained
- CloseDb(strFile);
- dbenv.txn_checkpoint(0, 0, 0);
- dbenv.lsn_reset(strFile.c_str(), 0);
-
- mapFileUseCount.erase(mi++);
- printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart);
- }
- }
- }
- }
- }
-}
-
-bool BackupWallet(const CWallet& wallet, const string& strDest)
-{
- if (!wallet.fFileBacked)
- return false;
- while (!fShutdown)
- {
- CRITICAL_BLOCK(cs_db)
- {
- if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0)
- {
- // Flush log data to the dat file
- CloseDb(wallet.strWalletFile);
- dbenv.txn_checkpoint(0, 0, 0);
- dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0);
- mapFileUseCount.erase(wallet.strWalletFile);
-
- // Copy wallet.dat
- filesystem::path pathSrc(GetDataDir() + "/" + wallet.strWalletFile);
- filesystem::path pathDest(strDest);
- if (filesystem::is_directory(pathDest))
- pathDest = pathDest / wallet.strWalletFile;
-
- try {
-#if BOOST_VERSION >= 104000
- filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
-#else
- filesystem::copy_file(pathSrc, pathDest);
-#endif
- printf("copied wallet.dat to %s\n", pathDest.string().c_str());
- return true;
- } catch(const filesystem::filesystem_error &e) {
- printf("error copying wallet.dat to %s - %s\n", pathDest.string().c_str(), e.what());
- return false;
- }
- }
- }
- Sleep(100);
- }
- return false;
-}
#ifndef BITCOIN_DB_H
#define BITCOIN_DB_H
-#include "key.h"
+#include "main.h"
#include <map>
#include <string>
#include <db_cxx.h>
-class CAccount;
-class CAccountingEntry;
class CAddress;
class CAddrMan;
class CBlockLocator;
class CWalletTx;
extern unsigned int nWalletDBUpdated;
+extern bool fDetachDB;
extern DbEnv dbenv;
extern void DBFlush(bool fShutdown);
return false;
// Key
- CDataStream ssKey(SER_DISK);
+ CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
Dbt datKey(&ssKey[0], ssKey.size());
return false;
// Unserialize value
- CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK);
+ CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
ssValue >> value;
// Clear and free memory
assert(!"Write called on database in read-only mode");
// Key
- CDataStream ssKey(SER_DISK);
+ CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
Dbt datKey(&ssKey[0], ssKey.size());
// Value
- CDataStream ssValue(SER_DISK);
+ CDataStream ssValue(SER_DISK, CLIENT_VERSION);
ssValue.reserve(10000);
ssValue << value;
Dbt datValue(&ssValue[0], ssValue.size());
assert(!"Erase called on database in read-only mode");
// Key
- CDataStream ssKey(SER_DISK);
+ CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
Dbt datKey(&ssKey[0], ssKey.size());
return false;
// Key
- CDataStream ssKey(SER_DISK);
+ CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
Dbt datKey(&ssKey[0], ssKey.size());
bool LoadAddresses();
-/** A key pool entry */
-class CKeyPool
-{
-public:
- int64 nTime;
- std::vector<unsigned char> vchPubKey;
-
- CKeyPool()
- {
- nTime = GetTime();
- }
-
- CKeyPool(const std::vector<unsigned char>& vchPubKeyIn)
- {
- nTime = GetTime();
- vchPubKey = vchPubKeyIn;
- }
-
- IMPLEMENT_SERIALIZE
- (
- if (!(nType & SER_GETHASH))
- READWRITE(nVersion);
- READWRITE(nTime);
- READWRITE(vchPubKey);
- )
-};
-
-
-
-/** Error statuses for the wallet database */
-enum DBErrors
-{
- DB_LOAD_OK,
- DB_CORRUPT,
- DB_TOO_NEW,
- DB_LOAD_FAIL,
- DB_NEED_REWRITE
-};
-
-/** Access to the wallet database (wallet.dat) */
-class CWalletDB : public CDB
-{
-public:
- CWalletDB(std::string strFilename, const char* pszMode="r+") : CDB(strFilename.c_str(), pszMode)
- {
- }
-private:
- CWalletDB(const CWalletDB&);
- void operator=(const CWalletDB&);
-public:
- bool ReadName(const std::string& strAddress, std::string& strName)
- {
- strName = "";
- return Read(std::make_pair(std::string("name"), strAddress), strName);
- }
-
- bool WriteName(const std::string& strAddress, const std::string& strName);
-
- bool EraseName(const std::string& strAddress);
-
- bool ReadTx(uint256 hash, CWalletTx& wtx)
- {
- return Read(std::make_pair(std::string("tx"), hash), wtx);
- }
-
- bool WriteTx(uint256 hash, const CWalletTx& wtx)
- {
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("tx"), hash), wtx);
- }
-
- bool EraseTx(uint256 hash)
- {
- nWalletDBUpdated++;
- return Erase(std::make_pair(std::string("tx"), hash));
- }
-
- bool ReadKey(const std::vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)
- {
- vchPrivKey.clear();
- return Read(std::make_pair(std::string("key"), vchPubKey), vchPrivKey);
- }
-
- bool WriteKey(const std::vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
- {
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
- }
-
- bool WriteCryptedKey(const std::vector<unsigned char>& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
- {
- nWalletDBUpdated++;
- if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
- return false;
- if (fEraseUnencryptedKey)
- {
- Erase(std::make_pair(std::string("key"), vchPubKey));
- Erase(std::make_pair(std::string("wkey"), vchPubKey));
- }
- return true;
- }
-
- bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
- {
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
- }
-
- // Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013
- bool ReadCScript(const uint160 &hash, CScript& redeemScript)
- {
- redeemScript.clear();
- return Read(std::make_pair(std::string("cscript"), hash), redeemScript);
- }
-
- bool WriteCScript(const uint160& hash, const CScript& redeemScript)
- {
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
- }
-
- bool WriteBestBlock(const CBlockLocator& locator)
- {
- nWalletDBUpdated++;
- return Write(std::string("bestblock"), locator);
- }
-
- bool ReadBestBlock(CBlockLocator& locator)
- {
- return Read(std::string("bestblock"), locator);
- }
-
- bool ReadDefaultKey(std::vector<unsigned char>& vchPubKey)
- {
- vchPubKey.clear();
- return Read(std::string("defaultkey"), vchPubKey);
- }
-
- bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey)
- {
- nWalletDBUpdated++;
- return Write(std::string("defaultkey"), vchPubKey);
- }
-
- bool ReadPool(int64 nPool, CKeyPool& keypool)
- {
- return Read(std::make_pair(std::string("pool"), nPool), keypool);
- }
-
- bool WritePool(int64 nPool, const CKeyPool& keypool)
- {
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("pool"), nPool), keypool);
- }
-
- bool ErasePool(int64 nPool)
- {
- nWalletDBUpdated++;
- return Erase(std::make_pair(std::string("pool"), nPool));
- }
-
- // Settings are no longer stored in wallet.dat; these are
- // used only for backwards compatibility:
- template<typename T>
- bool ReadSetting(const std::string& strKey, T& value)
- {
- return Read(std::make_pair(std::string("setting"), strKey), value);
- }
- template<typename T>
- bool WriteSetting(const std::string& strKey, const T& value)
- {
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("setting"), strKey), value);
- }
- bool EraseSetting(const std::string& strKey)
- {
- nWalletDBUpdated++;
- return Erase(std::make_pair(std::string("setting"), strKey));
- }
-
- bool WriteMinVersion(int nVersion)
- {
- return Write(std::string("minversion"), nVersion);
- }
-
- bool ReadAccount(const std::string& strAccount, CAccount& account);
- bool WriteAccount(const std::string& strAccount, const CAccount& account);
- bool WriteAccountingEntry(const CAccountingEntry& acentry);
- int64 GetAccountCreditDebit(const std::string& strAccount);
- void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
-
- int LoadWallet(CWallet* pwallet);
-};
-
-#endif
+#endif // BITCOIN_DB_H
+++ /dev/null
-// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2012 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.
-
-#ifdef _MSC_VER
-#pragma warning(disable:4786)
-#pragma warning(disable:4804)
-#pragma warning(disable:4805)
-#pragma warning(disable:4717)
-#endif
-#ifdef _WIN32_WINNT
-#undef _WIN32_WINNT
-#endif
-#define _WIN32_WINNT 0x0501
-#ifdef _WIN32_IE
-#undef _WIN32_IE
-#endif
-#define _WIN32_IE 0x0400
-#define WIN32_LEAN_AND_MEAN 1
-
-// Include boost/foreach here as it defines __STDC_LIMIT_MACROS on some systems.
-#include <boost/foreach.hpp>
-
-#if (defined(__unix__) || defined(unix)) && !defined(USG)
-#include <sys/param.h> // to get BSD define
-#endif
-#ifdef MAC_OSX
-#ifndef BSD
-#define BSD 1
-#endif
-#endif
-#include <openssl/buffer.h>
-#include <openssl/ecdsa.h>
-#include <openssl/evp.h>
-#include <openssl/rand.h>
-#include <openssl/sha.h>
-#include <openssl/ripemd.h>
-#include <db_cxx.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <math.h>
-#include <float.h>
-#include <assert.h>
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <vector>
-#include <list>
-#include <deque>
-#include <map>
-
-#ifdef WIN32
-#include <windows.h>
-#include <winsock2.h>
-#include <mswsock.h>
-#include <shlobj.h>
-#include <shlwapi.h>
-#include <io.h>
-#include <process.h>
-#include <malloc.h>
-#else
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <errno.h>
-#include <net/if.h>
-#include <ifaddrs.h>
-#include <fcntl.h>
-#include <signal.h>
-#endif
-#ifdef BSD
-#include <netinet/in.h>
-#endif
-
-
-#include "serialize.h"
-#include "uint256.h"
-#include "util.h"
-#include "bignum.h"
-#include "base58.h"
-#include "main.h"
-#ifdef QT_GUI
-#include "qtui.h"
-#else
-#include "noui.h"
-#endif
+++ b/src/headers.h
// Copyright (c) 2009-2012 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 "headers.h"
#include "db.h"
+#include "walletdb.h"
#include "bitcoinrpc.h"
#include "net.h"
#include "init.h"
-#include "strlcpy.h"
+#include "util.h"
+#include "ui_interface.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
-#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
-#define _BITCOIN_QT_PLUGINS_INCLUDED
-#define __INSURE__
-#include <QtPlugin>
-Q_IMPORT_PLUGIN(qcncodecs)
-Q_IMPORT_PLUGIN(qjpcodecs)
-Q_IMPORT_PLUGIN(qtwcodecs)
-Q_IMPORT_PLUGIN(qkrcodecs)
-Q_IMPORT_PLUGIN(qtaccessiblewidgets)
+#ifndef WIN32
+#include <signal.h>
#endif
using namespace std;
static CCriticalSection cs_Shutdown;
static bool fTaken;
bool fFirstThread = false;
- TRY_CRITICAL_BLOCK(cs_Shutdown)
{
- fFirstThread = !fTaken;
- fTaken = true;
+ TRY_LOCK(cs_Shutdown, lockShutdown);
+ if (lockShutdown)
+ {
+ fFirstThread = !fTaken;
+ fTaken = true;
+ }
}
static bool fExit;
if (fFirstThread)
// If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
#if !defined(QT_GUI)
ParseParameters(argc, argv);
- if (!ReadConfigFile(mapArgs, mapMultiArgs))
+ if (!boost::filesystem::is_directory(GetDataDir(false)))
{
fprintf(stderr, "Error: Specified directory does not exist\n");
Shutdown(NULL);
}
+ ReadConfigFile(mapArgs, mapMultiArgs);
#endif
if (mapArgs.count("-?") || mapArgs.count("--help"))
" -splash \t\t " + _("Show splash screen on startup (default: 1)") + "\n" +
" -datadir=<dir> \t\t " + _("Specify data directory") + "\n" +
" -dbcache=<n> \t\t " + _("Set database cache size in megabytes (default: 25)") + "\n" +
+ " -dblogsize=<n> \t\t " + _("Set database disk log size in megabytes (default: 100)") + "\n" +
" -timeout=<n> \t " + _("Specify connection timeout (in milliseconds)") + "\n" +
" -proxy=<ip:port> \t " + _("Connect through socks4 proxy") + "\n" +
" -dns \t " + _("Allow DNS lookups for addnode and connect") + "\n" +
#else
" -upnp \t " + _("Use Universal Plug and Play to map the listening port (default: 0)") + "\n" +
#endif
+ " -detachdb \t " + _("Detach block and address databases. Increases shutdown time (default: 0)") + "\n" +
#endif
" -paytxfee=<amt> \t " + _("Fee per KB to add to transactions you send") + "\n" +
#ifdef QT_GUI
" -checkblocks=<n> \t\t " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" +
" -checklevel=<n> \t\t " + _("How thorough the block verification is (0-6, default: 1)") + "\n";
-#ifdef USE_SSL
strUsage += string() +
_("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n" +
" -rpcssl \t " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n" +
" -rpcsslcertificatechainfile=<file.cert>\t " + _("Server certificate file (default: server.cert)") + "\n" +
" -rpcsslprivatekeyfile=<file.pem> \t " + _("Server private key (default: server.pem)") + "\n" +
" -rpcsslciphers=<ciphers> \t " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)") + "\n";
-#endif
strUsage += string() +
" -? \t\t " + _("This help message") + "\n";
strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
#if defined(QT_GUI) && defined(WIN32)
// On windows, show a message box, as there is no stderr
- wxMessageBox(strUsage, "Usage");
+ ThreadSafeMessageBox(strUsage, _("Usage"), wxOK | wxMODAL);
#else
fprintf(stderr, "%s", strUsage.c_str());
#endif
}
fDebug = GetBoolArg("-debug");
+ fDetachDB = GetBoolArg("-detachdb", false);
#if !defined(WIN32) && !defined(QT_GUI)
fDaemon = GetBoolArg("-daemon");
}
#endif
- if (!fDebug && !pszSetDataDir[0])
+ if (!fDebug)
ShrinkDebugFile();
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
- printf("Bitcoin version %s\n", FormatFullVersion().c_str());
- printf("Default data directory %s\n", GetDefaultDataDir().c_str());
+ printf("Bitcoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str());
+ printf("Default data directory %s\n", GetDefaultDataDir().string().c_str());
if (GetBoolArg("-loadblockindextest"))
{
}
// Make sure only a single bitcoin process is using the data directory.
- string strLockFile = GetDataDir() + "/.lock";
- FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist.
+ boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
+ FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
if (file) fclose(file);
- static boost::interprocess::file_lock lock(strLockFile.c_str());
+ static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
if (!lock.try_lock())
{
- wxMessageBox(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().c_str()), "Bitcoin");
+ ThreadSafeMessageBox(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().string().c_str()), _("Bitcoin"), wxOK|wxMODAL);
return false;
}
nStart = GetTimeMillis();
if (!LoadBlockIndex())
strErrors << _("Error loading blkindex.dat") << "\n";
+
+ // as LoadBlockIndex can take several minutes, it's possible the user
+ // requested to kill bitcoin-qt during the last operation. If so, exit.
+ // As the program has not fully started yet, Shutdown() is possibly overkill.
+ if (fRequestShutdown)
+ {
+ printf("Shutdown requested. Exiting.\n");
+ return false;
+ }
printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
InitMessage(_("Loading wallet..."));
{
strErrors << _("Wallet needed to be rewritten: restart Bitcoin to complete") << "\n";
printf("%s", strErrors.str().c_str());
- wxMessageBox(strErrors.str(), "Bitcoin", wxOK | wxICON_ERROR);
+ ThreadSafeMessageBox(strErrors.str(), _("Bitcoin"), wxOK | wxICON_ERROR | wxMODAL);
return false;
}
else
if (!strErrors.str().empty())
{
- wxMessageBox(strErrors.str(), "Bitcoin", wxOK | wxICON_ERROR);
+ ThreadSafeMessageBox(strErrors.str(), _("Bitcoin"), wxOK | wxICON_ERROR | wxMODAL);
return false;
}
addrProxy = CService(mapArgs["-proxy"], 9050);
if (!addrProxy.IsValid())
{
- wxMessageBox(_("Invalid -proxy address"), "Bitcoin");
+ ThreadSafeMessageBox(_("Invalid -proxy address"), _("Bitcoin"), wxOK | wxMODAL);
return false;
}
}
std::string strError;
if (!BindListenPort(strError))
{
- wxMessageBox(strError, "Bitcoin");
+ ThreadSafeMessageBox(strError, _("Bitcoin"), wxOK | wxMODAL);
return false;
}
}
{
if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
{
- wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "Bitcoin");
+ ThreadSafeMessageBox(_("Invalid amount for -paytxfee=<amount>"), _("Bitcoin"), wxOK | wxMODAL);
return false;
}
if (nTransactionFee > 0.25 * COIN)
- wxMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION);
+ ThreadSafeMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), _("Bitcoin"), wxOK | wxICON_EXCLAMATION | wxMODAL);
}
//
RandAddSeedPerfmon();
if (!CreateThread(StartNode, NULL))
- wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin");
+ ThreadSafeMessageBox(_("Error: CreateThread(StartNode) failed"), _("Bitcoin"), wxOK | wxMODAL);
if (fServer)
CreateThread(ThreadRPCServer, NULL);
#ifdef QT_GUI
- if(GetStartOnSystemStartup())
- SetStartOnSystemStartup(true); // Remove startup links to bitcoin-wx
+ if (GetStartOnSystemStartup())
+ SetStartOnSystemStartup(true); // Remove startup links
#endif
#if !defined(QT_GUI)
return true;
}
-#ifdef WIN32
-string StartupShortcutPath()
-{
- return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
-}
-
-bool GetStartOnSystemStartup()
-{
- return filesystem::exists(StartupShortcutPath().c_str());
-}
-
-bool SetStartOnSystemStartup(bool fAutoStart)
-{
- // If the shortcut exists already, remove it for updating
- remove(StartupShortcutPath().c_str());
-
- if (fAutoStart)
- {
- CoInitialize(NULL);
-
- // Get a pointer to the IShellLink interface.
- IShellLink* psl = NULL;
- HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
- CLSCTX_INPROC_SERVER, IID_IShellLink,
- reinterpret_cast<void**>(&psl));
-
- if (SUCCEEDED(hres))
- {
- // Get the current executable path
- TCHAR pszExePath[MAX_PATH];
- GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
-
- TCHAR pszArgs[5] = TEXT("-min");
-
- // Set the path to the shortcut target
- psl->SetPath(pszExePath);
- PathRemoveFileSpec(pszExePath);
- psl->SetWorkingDirectory(pszExePath);
- psl->SetShowCmd(SW_SHOWMINNOACTIVE);
- psl->SetArguments(pszArgs);
-
- // Query IShellLink for the IPersistFile interface for
- // saving the shortcut in persistent storage.
- IPersistFile* ppf = NULL;
- hres = psl->QueryInterface(IID_IPersistFile,
- reinterpret_cast<void**>(&ppf));
- if (SUCCEEDED(hres))
- {
- WCHAR pwsz[MAX_PATH];
- // Ensure that the string is ANSI.
- MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);
- // Save the link by calling IPersistFile::Save.
- hres = ppf->Save(pwsz, TRUE);
- ppf->Release();
- psl->Release();
- CoUninitialize();
- return true;
- }
- psl->Release();
- }
- CoUninitialize();
- return false;
- }
- return true;
-}
-
-#elif defined(LINUX)
-
-// Follow the Desktop Application Autostart Spec:
-// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
-
-boost::filesystem::path GetAutostartDir()
-{
- namespace fs = boost::filesystem;
-
- char* pszConfigHome = getenv("XDG_CONFIG_HOME");
- if (pszConfigHome) return fs::path(pszConfigHome) / fs::path("autostart");
- char* pszHome = getenv("HOME");
- if (pszHome) return fs::path(pszHome) / fs::path(".config/autostart");
- return fs::path();
-}
-
-boost::filesystem::path GetAutostartFilePath()
-{
- return GetAutostartDir() / boost::filesystem::path("bitcoin.desktop");
-}
-
-bool GetStartOnSystemStartup()
-{
- boost::filesystem::ifstream optionFile(GetAutostartFilePath());
- if (!optionFile.good())
- return false;
- // Scan through file for "Hidden=true":
- string line;
- while (!optionFile.eof())
- {
- getline(optionFile, line);
- if (line.find("Hidden") != string::npos &&
- line.find("true") != string::npos)
- return false;
- }
- optionFile.close();
-
- return true;
-}
-
-bool SetStartOnSystemStartup(bool fAutoStart)
-{
- if (!fAutoStart)
- {
-#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3
- unlink(GetAutostartFilePath().string().c_str());
-#else
- unlink(GetAutostartFilePath().native_file_string().c_str());
-#endif
- }
- else
- {
- char pszExePath[MAX_PATH+1];
- memset(pszExePath, 0, sizeof(pszExePath));
- if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
- return false;
-
- boost::filesystem::create_directories(GetAutostartDir());
-
- boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc);
- if (!optionFile.good())
- return false;
- // Write a bitcoin.desktop file to the autostart directory:
- optionFile << "[Desktop Entry]\n";
- optionFile << "Type=Application\n";
- optionFile << "Name=Bitcoin\n";
- optionFile << "Exec=" << pszExePath << " -min\n";
- optionFile << "Terminal=false\n";
- optionFile << "Hidden=false\n";
- optionFile.close();
- }
- return true;
-}
-#else
-
-// TODO: OSX startup stuff; see:
-// http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
-
-bool GetStartOnSystemStartup() { return false; }
-bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
-
-#endif
#ifndef BITCOIN_INIT_H
#define BITCOIN_INIT_H
+#include "wallet.h"
+
extern CWallet* pwalletMain;
void Shutdown(void* parg);
// 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 "irc.h"
#include "net.h"
#include "strlcpy.h"
+#include "base58.h"
using namespace std;
using namespace boost;
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
-#include "serialize.h"
+#include "allocators.h"
#include "uint256.h"
// secp160k1
// 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 "crypter.h"
-#include "db.h"
+#include "keystore.h"
#include "script.h"
bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char> &vchPubKeyOut) const
{
bool fCompressed = false;
CSecret secret = key.GetSecret(fCompressed);
- CRITICAL_BLOCK(cs_KeyStore)
+ {
+ LOCK(cs_KeyStore);
mapKeys[CBitcoinAddress(key.GetPubKey())] = make_pair(secret, fCompressed);
+ }
return true;
}
bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
{
- CRITICAL_BLOCK(cs_KeyStore)
+ {
+ LOCK(cs_KeyStore);
mapScripts[Hash160(redeemScript)] = redeemScript;
+ }
return true;
}
bool CBasicKeyStore::HaveCScript(const uint160& hash) const
{
bool result;
- CRITICAL_BLOCK(cs_KeyStore)
+ {
+ LOCK(cs_KeyStore);
result = (mapScripts.count(hash) > 0);
+ }
return result;
}
bool CBasicKeyStore::GetCScript(const uint160 &hash, CScript& redeemScriptOut) const
{
- CRITICAL_BLOCK(cs_KeyStore)
{
+ LOCK(cs_KeyStore);
ScriptMap::const_iterator mi = mapScripts.find(hash);
if (mi != mapScripts.end())
{
bool CCryptoKeyStore::SetCrypted()
{
- CRITICAL_BLOCK(cs_KeyStore)
{
+ LOCK(cs_KeyStore);
if (fUseCrypto)
return true;
if (!mapKeys.empty())
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
{
- CRITICAL_BLOCK(cs_KeyStore)
{
+ LOCK(cs_KeyStore);
if (!SetCrypted())
return false;
bool CCryptoKeyStore::AddKey(const CKey& key)
{
- CRITICAL_BLOCK(cs_KeyStore)
{
+ LOCK(cs_KeyStore);
if (!IsCrypted())
return CBasicKeyStore::AddKey(key);
bool CCryptoKeyStore::AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
- CRITICAL_BLOCK(cs_KeyStore)
{
+ LOCK(cs_KeyStore);
if (!SetCrypted())
return false;
bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const
{
- CRITICAL_BLOCK(cs_KeyStore)
{
+ LOCK(cs_KeyStore);
if (!IsCrypted())
return CBasicKeyStore::GetKey(address, keyOut);
bool CCryptoKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const
{
- CRITICAL_BLOCK(cs_KeyStore)
{
+ LOCK(cs_KeyStore);
if (!IsCrypted())
return CKeyStore::GetPubKey(address, vchPubKeyOut);
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
{
- CRITICAL_BLOCK(cs_KeyStore)
{
+ LOCK(cs_KeyStore);
if (!mapCryptedKeys.empty() || IsCrypted())
return false;
#define BITCOIN_KEYSTORE_H
#include "crypter.h"
-#include "script.h"
+#include "util.h"
+#include "base58.h"
+
+class CScript;
/** A virtual base class for key stores */
class CKeyStore
bool HaveKey(const CBitcoinAddress &address) const
{
bool result;
- CRITICAL_BLOCK(cs_KeyStore)
+ {
+ LOCK(cs_KeyStore);
result = (mapKeys.count(address) > 0);
+ }
return result;
}
void GetKeys(std::set<CBitcoinAddress> &setAddress) const
{
setAddress.clear();
- CRITICAL_BLOCK(cs_KeyStore)
{
+ LOCK(cs_KeyStore);
KeyMap::const_iterator mi = mapKeys.begin();
while (mi != mapKeys.end())
{
}
bool GetKey(const CBitcoinAddress &address, CKey &keyOut) const
{
- CRITICAL_BLOCK(cs_KeyStore)
{
+ LOCK(cs_KeyStore);
KeyMap::const_iterator mi = mapKeys.find(address);
if (mi != mapKeys.end())
{
if (!IsCrypted())
return false;
bool result;
- CRITICAL_BLOCK(cs_KeyStore)
+ {
+ LOCK(cs_KeyStore);
result = vMasterKey.empty();
+ }
return result;
}
if (!SetCrypted())
return false;
- CRITICAL_BLOCK(cs_KeyStore)
+ {
+ LOCK(cs_KeyStore);
vMasterKey.clear();
+ }
return true;
}
bool AddKey(const CKey& key);
bool HaveKey(const CBitcoinAddress &address) const
{
- CRITICAL_BLOCK(cs_KeyStore)
{
+ LOCK(cs_KeyStore);
if (!IsCrypted())
return CBasicKeyStore::HaveKey(address);
return mapCryptedKeys.count(address) > 0;
// Copyright (c) 2009-2012 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 "headers.h"
#include "checkpoints.h"
#include "db.h"
#include "net.h"
#include "init.h"
+#include "ui_interface.h"
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
// Global state
//
-// Name of client reported in the 'version' message. Report the same name
-// for both bitcoind and bitcoin-qt, to make it harder for attackers to
-// target servers or GUI users specifically.
-const std::string CLIENT_NAME("Satoshi");
-
CCriticalSection cs_setpwalletRegistered;
set<CWallet*> setpwalletRegistered;
CCriticalSection cs_main;
-static map<uint256, CTransaction> mapTransactions;
-CCriticalSection cs_mapTransactions;
+CTxMemPool mempool;
unsigned int nTransactionsUpdated = 0;
-map<COutPoint, CInPoint> mapNextTx;
map<uint256, CBlockIndex*> mapBlockIndex;
uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
void RegisterWallet(CWallet* pwalletIn)
{
- CRITICAL_BLOCK(cs_setpwalletRegistered)
{
+ LOCK(cs_setpwalletRegistered);
setpwalletRegistered.insert(pwalletIn);
}
}
void UnregisterWallet(CWallet* pwalletIn)
{
- CRITICAL_BLOCK(cs_setpwalletRegistered)
{
+ LOCK(cs_setpwalletRegistered);
setpwalletRegistered.erase(pwalletIn);
}
}
mapOrphanTransactions.erase(hash);
}
-int LimitOrphanTxSize(int nMaxOrphans)
+unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
{
- int nEvicted = 0;
+ unsigned int nEvicted = 0;
while (mapOrphanTransactions.size() > nMaxOrphans)
{
// Evict a random orphan:
return true;
}
-int
+unsigned int
CTransaction::GetLegacySigOpCount() const
{
- int nSigOps = 0;
+ unsigned int nSigOps = 0;
BOOST_FOREACH(const CTxIn& txin, vin)
{
nSigOps += txin.scriptSig.GetSigOpCount(false);
hashBlock = pblock->GetHash();
// Locate the transaction
- for (nIndex = 0; nIndex < pblock->vtx.size(); nIndex++)
+ for (nIndex = 0; nIndex < (int)pblock->vtx.size(); nIndex++)
if (pblock->vtx[nIndex] == *(CTransaction*)this)
break;
- if (nIndex == pblock->vtx.size())
+ if (nIndex == (int)pblock->vtx.size())
{
vMerkleBranch.clear();
nIndex = -1;
if (vout.empty())
return DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
// Size limits
- if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
+ if (::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
// Check for negative or overflow output values
return true;
}
-bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)
+bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs,
+ bool* pfMissingInputs)
{
if (pfMissingInputs)
*pfMissingInputs = false;
- if (!CheckTransaction())
- return error("AcceptToMemoryPool() : CheckTransaction failed");
+ if (!tx.CheckTransaction())
+ return error("CTxMemPool::accept() : CheckTransaction failed");
// Coinbase is only valid in a block, not as a loose transaction
- if (IsCoinBase())
- return DoS(100, error("AcceptToMemoryPool() : coinbase as individual tx"));
+ if (tx.IsCoinBase())
+ return tx.DoS(100, error("CTxMemPool::accept() : coinbase as individual tx"));
// To help v0.1.5 clients who would see it as a negative number
- if ((int64)nLockTime > std::numeric_limits<int>::max())
- return error("AcceptToMemoryPool() : not accepting nLockTime beyond 2038 yet");
+ if ((int64)tx.nLockTime > std::numeric_limits<int>::max())
+ return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet");
// Rather not work on nonstandard transactions (unless -testnet)
- if (!fTestNet && !IsStandard())
- return error("AcceptToMemoryPool() : nonstandard transaction type");
+ if (!fTestNet && !tx.IsStandard())
+ return error("CTxMemPool::accept() : nonstandard transaction type");
// Do we already have it?
- uint256 hash = GetHash();
- CRITICAL_BLOCK(cs_mapTransactions)
- if (mapTransactions.count(hash))
+ uint256 hash = tx.GetHash();
+ {
+ LOCK(cs);
+ if (mapTx.count(hash))
return false;
+ }
if (fCheckInputs)
if (txdb.ContainsTx(hash))
return false;
// Check for conflicts with in-memory transactions
CTransaction* ptxOld = NULL;
- for (unsigned int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
{
- COutPoint outpoint = vin[i].prevout;
+ COutPoint outpoint = tx.vin[i].prevout;
if (mapNextTx.count(outpoint))
{
// Disable replacement feature for now
ptxOld = mapNextTx[outpoint].ptx;
if (ptxOld->IsFinal())
return false;
- if (!IsNewerThan(*ptxOld))
+ if (!tx.IsNewerThan(*ptxOld))
return false;
- for (unsigned int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
{
- COutPoint outpoint = vin[i].prevout;
+ COutPoint outpoint = tx.vin[i].prevout;
if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
return false;
}
MapPrevTx mapInputs;
map<uint256, CTxIndex> mapUnused;
bool fInvalid = false;
- if (!FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
+ if (!tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
{
if (fInvalid)
- return error("AcceptToMemoryPool() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str());
+ return error("CTxMemPool::accept() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str());
if (pfMissingInputs)
*pfMissingInputs = true;
- return error("AcceptToMemoryPool() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str());
+ return error("CTxMemPool::accept() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str());
}
// Check for non-standard pay-to-script-hash in inputs
- if (!AreInputsStandard(mapInputs) && !fTestNet)
- return error("AcceptToMemoryPool() : nonstandard transaction input");
+ if (!tx.AreInputsStandard(mapInputs) && !fTestNet)
+ return error("CTxMemPool::accept() : nonstandard transaction input");
// Note: if you modify this code to accept non-standard transactions, then
// you should add code here to check that the transaction does a
// reasonable number of ECDSA signature verifications.
- int64 nFees = GetValueIn(mapInputs)-GetValueOut();
- unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
+ int64 nFees = tx.GetValueIn(mapInputs)-tx.GetValueOut();
+ unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
// Don't accept it if it can't get into a block
- if (nFees < GetMinFee(1000, true, GMF_RELAY))
- return error("AcceptToMemoryPool() : not enough fees");
+ if (nFees < tx.GetMinFee(1000, true, GMF_RELAY))
+ return error("CTxMemPool::accept() : not enough fees");
// Continuously rate-limit free transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
static int64 nLastTime;
int64 nNow = GetTime();
- CRITICAL_BLOCK(cs)
{
+ LOCK(cs);
// Use an exponentially decaying ~10-minute window:
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
- if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(*this))
- return error("AcceptToMemoryPool() : free transaction rejected by rate limiter");
+ if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(tx))
+ return error("CTxMemPool::accept() : free transaction rejected by rate limiter");
if (fDebug)
printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize;
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false))
+ if (!tx.ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false))
{
- return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
+ return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
}
}
// Store transaction in memory
- CRITICAL_BLOCK(cs_mapTransactions)
{
+ LOCK(cs);
if (ptxOld)
{
- printf("AcceptToMemoryPool() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
- ptxOld->RemoveFromMemoryPool();
+ printf("CTxMemPool::accept() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
+ remove(*ptxOld);
}
- AddToMemoryPoolUnchecked();
+ addUnchecked(tx);
}
///// are we sure this is ok when loading transactions or restoring block txes
if (ptxOld)
EraseFromWallets(ptxOld->GetHash());
- printf("AcceptToMemoryPool(): accepted %s\n", hash.ToString().substr(0,10).c_str());
+ printf("CTxMemPool::accept() : accepted %s\n", hash.ToString().substr(0,10).c_str());
return true;
}
-bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool* pfMissingInputs)
+bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)
{
- CTxDB txdb("r");
- return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs);
+ return mempool.accept(txdb, *this, fCheckInputs, pfMissingInputs);
}
-uint64 nPooledTx = 0;
-
-bool CTransaction::AddToMemoryPoolUnchecked()
+bool CTxMemPool::addUnchecked(CTransaction &tx)
{
- printf("AcceptToMemoryPoolUnchecked(): size %lu\n", mapTransactions.size());
+ printf("addUnchecked(): size %lu\n", mapTx.size());
// Add to memory pool without checking anything. Don't call this directly,
- // call AcceptToMemoryPool to properly check the transaction first.
- CRITICAL_BLOCK(cs_mapTransactions)
+ // call CTxMemPool::accept to properly check the transaction first.
{
- uint256 hash = GetHash();
- mapTransactions[hash] = *this;
- for (unsigned int i = 0; i < vin.size(); i++)
- mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i);
+ LOCK(cs);
+ uint256 hash = tx.GetHash();
+ mapTx[hash] = tx;
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ mapNextTx[tx.vin[i].prevout] = CInPoint(&mapTx[hash], i);
nTransactionsUpdated++;
- ++nPooledTx;
}
return true;
}
-bool CTransaction::RemoveFromMemoryPool()
+bool CTxMemPool::remove(CTransaction &tx)
{
// Remove transaction from memory pool
- CRITICAL_BLOCK(cs_mapTransactions)
{
- uint256 hash = GetHash();
- if (mapTransactions.count(hash))
+ LOCK(cs);
+ uint256 hash = tx.GetHash();
+ if (mapTx.count(hash))
{
- BOOST_FOREACH(const CTxIn& txin, vin)
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapNextTx.erase(txin.prevout);
- mapTransactions.erase(hash);
+ mapTx.erase(hash);
nTransactionsUpdated++;
- --nPooledTx;
}
}
return true;
bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
{
- CRITICAL_BLOCK(cs_mapTransactions)
+
{
+ LOCK(mempool.cs);
// Add previous supporting transactions first
BOOST_FOREACH(CMerkleTx& tx, vtxPrev)
{
if (!tx.IsCoinBase())
{
uint256 hash = tx.GetHash();
- if (!mapTransactions.count(hash) && !txdb.ContainsTx(hash))
+ if (!mempool.exists(hash) && !txdb.ContainsTx(hash))
tx.AcceptToMemoryPool(txdb, fCheckInputs);
}
}
if (!fFound || txindex.pos == CDiskTxPos(1,1,1))
{
// Get prev tx from single transactions in memory
- CRITICAL_BLOCK(cs_mapTransactions)
{
- if (!mapTransactions.count(prevout.hash))
- return error("FetchInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
- txPrev = mapTransactions[prevout.hash];
+ LOCK(mempool.cs);
+ if (!mempool.exists(prevout.hash))
+ return error("FetchInputs() : %s mempool Tx prev not found %s", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
+ txPrev = mempool.lookup(prevout.hash);
}
if (!fFound)
txindex.vSpent.resize(txPrev.vout.size());
}
-int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const
+unsigned int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const
{
if (IsCoinBase())
return 0;
- int nSigOps = 0;
+ unsigned int nSigOps = 0;
for (unsigned int i = 0; i < vin.size(); i++)
{
const CTxOut& prevout = GetOutputFor(vin[i], inputs);
return false;
// Take over previous transactions' spent pointers
- CRITICAL_BLOCK(cs_mapTransactions)
{
+ LOCK(mempool.cs);
int64 nValueIn = 0;
for (unsigned int i = 0; i < vin.size(); i++)
{
// Get prev tx from single transactions in memory
COutPoint prevout = vin[i].prevout;
- if (!mapTransactions.count(prevout.hash))
+ if (!mempool.exists(prevout.hash))
return false;
- CTransaction& txPrev = mapTransactions[prevout.hash];
+ CTransaction& txPrev = mempool.lookup(prevout.hash);
if (prevout.n >= txPrev.vout.size())
return false;
if (!VerifySignature(txPrev, *this, i, true, 0))
return error("ConnectInputs() : VerifySignature failed");
- ///// this is redundant with the mapNextTx stuff, not sure which I want to get rid of
+ ///// this is redundant with the mempool.mapNextTx stuff,
+ ///// not sure which I want to get rid of
///// this has to go away now that posNext is gone
// // Check for conflicts
// if (!txPrev.vout[prevout.n].posNext.IsNull())
bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime);
//// issue here: it doesn't know the version
- unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size());
+ unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - 1 + GetSizeOfCompactSize(vtx.size());
map<uint256, CTxIndex> mapQueuedChanges;
int64 nFees = 0;
- int nSigOps = 0;
+ unsigned int nSigOps = 0;
BOOST_FOREACH(CTransaction& tx, vtx)
{
nSigOps += tx.GetLegacySigOpCount();
return DoS(100, error("ConnectBlock() : too many sigops"));
CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
- nTxPos += ::GetSerializeSize(tx, SER_DISK);
+ nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
MapPrevTx mapInputs;
if (!tx.IsCoinBase())
// Delete redundant memory transactions that are in the connected branch
BOOST_FOREACH(CTransaction& tx, vDelete)
- tx.RemoveFromMemoryPool();
+ mempool.remove(tx);
printf("REORGANIZE: done\n");
// Delete redundant memory transactions
BOOST_FOREACH(CTransaction& tx, vtx)
- tx.RemoveFromMemoryPool();
+ mempool.remove(tx);
return true;
}
// that can be verified before saving an orphan block.
// Size limits
- if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
+ if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return DoS(100, error("CheckBlock() : size limits failed"));
// Check proof of work matches claimed amount
if (uniqueTx.size() != vtx.size())
return DoS(100, error("CheckBlock() : duplicate transaction"));
- int nSigOps = 0;
+ unsigned int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, vtx)
{
nSigOps += tx.GetLegacySigOpCount();
return DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight));
// Write block to history file
- if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))
+ if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION)))
return error("AcceptBlock() : out of disk space");
unsigned int nFile = -1;
unsigned int nBlockPos = 0;
// Relay inventory, but don't relay old inventory during initial block download
int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
if (hashBestChain == hash)
- CRITICAL_BLOCK(cs_vNodes)
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
- pnode->PushInventory(CInv(MSG_BLOCK, hash));
+ {
+ LOCK(cs_vNodes);
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
+ pnode->PushInventory(CInv(MSG_BLOCK, hash));
+ }
return true;
}
string strMessage = _("Warning: Disk space is low ");
strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str());
- ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
- CreateThread(Shutdown, NULL);
+ ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION | wxMODAL);
+ QueueShutdown();
return false;
}
return true;
{
if (nFile == -1)
return NULL;
- FILE* file = fopen(strprintf("%s/blk%04d.dat", GetDataDir().c_str(), nFile).c_str(), pszMode);
+ FILE* file = fopen((GetDataDir() / strprintf("blk%04d.dat", nFile)).string().c_str(), pszMode);
if (!file)
return NULL;
if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w'))
}
// Alerts
- CRITICAL_BLOCK(cs_mapAlerts)
{
+ LOCK(cs_mapAlerts);
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
{
const CAlert& alert = item.second;
if (!IsInEffect())
return false;
- CRITICAL_BLOCK(cs_mapAlerts)
{
+ LOCK(cs_mapAlerts);
// Cancel previous alerts
for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
{
case MSG_TX:
{
bool txInMap = false;
- CRITICAL_BLOCK(cs_mapTransactions)
- {
- txInMap = (mapTransactions.count(inv.hash) != 0);
- }
+ {
+ LOCK(mempool.cs);
+ txInMap = (mempool.exists(inv.hash));
+ }
return txInMap ||
mapOrphanTransactions.count(inv.hash) ||
txdb.ContainsTx(inv.hash);
}
- case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash);
+ case MSG_BLOCK:
+ return mapBlockIndex.count(inv.hash) ||
+ mapOrphanBlocks.count(inv.hash);
}
// Don't know what it is, just say we already got one
return true;
CAddress addrFrom;
uint64 nNonce = 1;
vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
- if (pfrom->nVersion < 209)
+ if (pfrom->nVersion < MIN_PROTO_VERSION)
{
// Since February 20, 2012, the protocol is initiated at version 209,
// and earlier versions are no longer supported
}
// Get recent addresses
- if (pfrom->nVersion >= 31402 || addrman.size() < 1000)
+ if (pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000)
{
pfrom->PushMessage("getaddr");
pfrom->fGetAddr = true;
// Ask the first connected node for block updates
static int nAskedForBlocks = 0;
if (!pfrom->fClient &&
- (pfrom->nVersion < 32000 || pfrom->nVersion >= 32400) &&
+ (pfrom->nVersion < NOBLKS_VERSION_START ||
+ pfrom->nVersion >= NOBLKS_VERSION_END) &&
(nAskedForBlocks < 1 || vNodes.size() <= 1))
{
nAskedForBlocks++;
}
// Relay alerts
- CRITICAL_BLOCK(cs_mapAlerts)
+ {
+ LOCK(cs_mapAlerts);
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
item.second.RelayTo(pfrom);
+ }
pfrom->fSuccessfullyConnected = true;
vRecv >> vAddr;
// Don't want addr from older versions unless seeding
- if (pfrom->nVersion < 31402 && addrman.size() > 1000)
+ if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000)
return true;
if (vAddr.size() > 1000)
{
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{
// Relay to a limited number of other nodes
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
// Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the setAddrKnowns of the chosen nodes prevent repeats
static uint256 hashSalt;
multimap<uint256, CNode*> mapMix;
BOOST_FOREACH(CNode* pnode, vNodes)
{
- if (pnode->nVersion < 31402)
+ if (pnode->nVersion < CADDR_TIME_VERSION)
continue;
unsigned int nPointer;
memcpy(&nPointer, &pnode, sizeof(nPointer));
else if (inv.IsKnownType())
{
// Send stream from relay memory
- CRITICAL_BLOCK(cs_mapRelay)
{
+ LOCK(cs_mapRelay);
map<CInv, CDataStream>::iterator mi = mapRelay.find(inv);
if (mi != mapRelay.end())
pfrom->PushMessage(inv.GetCommand(), (*mi).second);
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
CBlock block;
block.ReadFromDisk(pindex, true);
- nBytes += block.GetSerializeSize(SER_NETWORK);
+ nBytes += block.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION);
if (--nLimit <= 0 || nBytes >= SendBufferSize()/2)
{
// When this block is requested, we'll send an inv that'll make them
}
vector<CBlock> vHeaders;
- int nLimit = 2000 + locator.GetDistanceBack();
- printf("getheaders %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
+ int nLimit = 2000;
+ printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str());
for (; pindex; pindex = pindex->pnext)
{
vHeaders.push_back(pindex->GetBlockHeader());
{
vector<uint256> vWorkQueue;
CDataStream vMsg(vRecv);
+ CTxDB txdb("r");
CTransaction tx;
vRecv >> tx;
pfrom->AddInventoryKnown(inv);
bool fMissingInputs = false;
- if (tx.AcceptToMemoryPool(true, &fMissingInputs))
+ if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs))
{
SyncWithWallets(tx, NULL, true);
RelayMessage(inv, vMsg);
CDataStream(vMsg) >> tx;
CInv inv(MSG_TX, tx.GetHash());
- if (tx.AcceptToMemoryPool(true))
+ if (tx.AcceptToMemoryPool(txdb, true))
{
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
SyncWithWallets(tx, NULL, true);
AddOrphanTx(vMsg);
// DoS prevention: do not allow mapOrphanTransactions to grow unbounded
- int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS);
+ unsigned int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS);
if (nEvicted > 0)
- printf("mapOrphan overflow, removed %d tx\n", nEvicted);
+ printf("mapOrphan overflow, removed %u tx\n", nEvicted);
}
if (tx.nDoS) pfrom->Misbehaving(tx.nDoS);
}
vRecv >> hashReply;
CRequestTracker tracker;
- CRITICAL_BLOCK(pfrom->cs_mapRequests)
{
+ LOCK(pfrom->cs_mapRequests);
map<uint256, CRequestTracker>::iterator mi = pfrom->mapRequests.find(hashReply);
if (mi != pfrom->mapRequests.end())
{
else if (strCommand == "ping")
{
+ if (pfrom->nVersion > BIP0031_VERSION)
+ {
+ uint64 nonce = 0;
+ vRecv >> nonce;
+ // Echo the message back with the nonce. This allows for two useful features:
+ //
+ // 1) A remote node can quickly check if the connection is operational
+ // 2) Remote nodes can measure the latency of the network thread. If this node
+ // is overloaded it won't respond to pings quickly and the remote node can
+ // avoid sending us more work, like chain download requests.
+ //
+ // The nonce stops the remote getting confused between different pings: without
+ // it, if the remote node sends a ping once per second and this node takes 5
+ // seconds to respond to each, the 5th ping the remote sends would appear to
+ // return very quickly.
+ pfrom->PushMessage("pong", nonce);
+ }
}
{
// Relay
pfrom->setKnown.insert(alert.GetHash());
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
alert.RelayTo(pnode);
+ }
}
}
int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
if (vRecv.end() - pstart < nHeaderSize)
{
- if (vRecv.size() > nHeaderSize)
+ if ((int)vRecv.size() > nHeaderSize)
{
printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
bool fRet = false;
try
{
- CRITICAL_BLOCK(cs_main)
+ {
+ LOCK(cs_main);
fRet = ProcessMessage(pfrom, strCommand, vMsg);
+ }
if (fShutdown)
return true;
}
bool SendMessages(CNode* pto, bool fSendTrickle)
{
- TRY_CRITICAL_BLOCK(cs_main)
- {
+ TRY_LOCK(cs_main, lockMain);
+ if (lockMain) {
// Don't send anything until we get their version message
if (pto->nVersion == 0)
return true;
- // Keep-alive ping
- if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty())
- pto->PushMessage("ping");
+ // Keep-alive ping. We send a nonce of zero because we don't use it anywhere
+ // right now.
+ if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) {
+ if (pto->nVersion > BIP0031_VERSION)
+ pto->PushMessage("ping", 0);
+ else
+ pto->PushMessage("ping");
+ }
// Resend wallet transactions that haven't gotten in a block yet
ResendWalletTransactions();
static int64 nLastRebroadcast;
if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60))
{
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
// Periodically clear setAddrKnown to allow refresh broadcasts
//
vector<CInv> vInv;
vector<CInv> vInvWait;
- CRITICAL_BLOCK(pto->cs_inventory)
{
+ LOCK(pto->cs_inventory);
vInv.reserve(pto->vInventoryToSend.size());
vInvWait.reserve(pto->vInventoryToSend.size());
BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend)
if ((nNonce & 0xffff) == 0)
{
nHashesDone = 0xffff+1;
- return -1;
+ return (unsigned int) -1;
}
}
}
// Collect memory pool transactions into the block
int64 nFees = 0;
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(cs_mapTransactions)
{
+ LOCK2(cs_main, mempool.cs);
CTxDB txdb("r");
// Priority order to process transactions
list<COrphan> vOrphan; // list memory doesn't move
map<uint256, vector<COrphan*> > mapDependers;
multimap<double, CTransaction*> mapPriority;
- for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi)
+ for (map<uint256, CTransaction>::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi)
{
CTransaction& tx = (*mi).second;
if (tx.IsCoinBase() || !tx.IsFinal())
}
// Priority is sum(valuein * age) / txsize
- dPriority /= ::GetSerializeSize(tx, SER_NETWORK);
+ dPriority /= ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
if (porphan)
porphan->dPriority = dPriority;
mapPriority.erase(mapPriority.begin());
// Size limits
- unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK);
+ unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN)
continue;
// Legacy limits on sigOps:
- int nTxSigOps = tx.GetLegacySigOpCount();
+ unsigned int nTxSigOps = tx.GetLegacySigOpCount();
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue;
printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str());
// Found a solution
- CRITICAL_BLOCK(cs_main)
{
+ LOCK(cs_main);
if (pblock->hashPrevBlock != hashBestChain)
return error("BitcoinMiner : generated block is stale");
reservekey.KeepKey();
// Track how many getdata requests this block gets
- CRITICAL_BLOCK(wallet.cs_wallet)
+ {
+ LOCK(wallet.cs_wallet);
wallet.mapRequestCount[pblock->GetHash()] = 0;
+ }
// Process this block the same as if we had received it from another node
if (!ProcessBlock(NULL, pblock))
while (fGenerateBitcoins)
{
- if (AffinityBugWorkaround(ThreadBitcoinMiner))
- return;
if (fShutdown)
return;
while (vNodes.empty() || IsInitialBlockDownload())
(char*)&hash, nHashesDone);
// Check if something found
- if (nNonceFound != -1)
+ if (nNonceFound != (unsigned int) -1)
{
for (unsigned int i = 0; i < sizeof(hash)/4; i++)
((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]);
if (GetTimeMillis() - nHPSTimerStart > 4000)
{
static CCriticalSection cs;
- CRITICAL_BLOCK(cs)
{
+ LOCK(cs);
if (GetTimeMillis() - nHPSTimerStart > 4000)
{
dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
nHPSTimerStart = GetTimeMillis();
nHashCounter = 0;
- string strStatus = strprintf(" %.0f khash/s", dHashesPerSec/1000.0);
- UIThreadCall(boost::bind(CalledSetStatusBar, strStatus, 0));
static int64 nLogTime;
if (GetTime() - nLogTime > 30 * 60)
{
vnThreadsRunning[THREAD_MINER]--;
PrintException(NULL, "ThreadBitcoinMiner()");
}
- UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
nHPSTimerStart = 0;
if (vnThreadsRunning[THREAD_MINER] == 0)
dHashesPerSec = 0;
#include "bignum.h"
#include "net.h"
-#include "key.h"
#include "script.h"
-#include "db.h"
+
+#ifdef WIN32
+#include <io.h> /* for _commit */
+#endif
#include <list>
+class CWallet;
class CBlock;
class CBlockIndex;
-class CWalletTx;
-class CWallet;
class CKeyItem;
class CReserveKey;
-class CWalletDB;
class CAddress;
class CInv;
class CRequestTracker;
class CNode;
-static const int CLIENT_VERSION = 60007;
-static const bool VERSION_IS_BETA = true;
-extern const std::string CLIENT_NAME;
-
static const unsigned int MAX_BLOCK_SIZE = 1000000;
static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
-static const int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
-static const int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
-static const int64 COIN = 100000000;
-static const int64 CENT = 1000000;
+static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
+static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
static const int64 MIN_TX_FEE = 50000;
static const int64 MIN_RELAY_TX_FEE = 10000;
static const int64 MAX_MONEY = 21000000 * COIN;
extern CBigNum bnBestInvalidWork;
extern uint256 hashBestChain;
extern CBlockIndex* pindexBest;
-extern uint64 nPooledTx;
extern unsigned int nTransactionsUpdated;
extern uint64 nLastBlockTx;
extern uint64 nLastBlockSize;
std::string ToString() const
{
if (IsNull())
- return strprintf("null");
+ return "null";
else
return strprintf("(nFile=%d, nBlockPos=%d, nTxPos=%d)", nFile, nBlockPos, nTxPos);
}
std::string ToString() const
{
std::string str;
- str += strprintf("CTxIn(");
+ str += "CTxIn(";
str += prevout.ToString();
if (prevout.IsNull())
str += strprintf(", coinbase %s", HexStr(scriptSig).c_str());
nBlockHeight = nBestHeight;
if (nBlockTime == 0)
nBlockTime = GetAdjustedTime();
- if ((int64)nLockTime < (nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
+ if ((int64)nLockTime < ((int64)nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
return true;
BOOST_FOREACH(const CTxIn& txin, vin)
if (!txin.IsFinal())
@return number of sigops this transaction's outputs will produce when spent
@see CTransaction::FetchInputs
*/
- int GetLegacySigOpCount() const;
+ unsigned int GetLegacySigOpCount() const;
/** Count ECDSA signature operations in pay-to-script-hash inputs.
@return maximum number of sigops required to validate this transaction's inputs
@see CTransaction::FetchInputs
*/
- int GetP2SHSigOpCount(const MapPrevTx& mapInputs) const;
+ unsigned int GetP2SHSigOpCount(const MapPrevTx& mapInputs) const;
/** Amount of bitcoins spent by this transaction.
@return sum of all outputs (note: does not include fees)
// Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE
int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE;
- unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK);
+ unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
unsigned int nNewBlockSize = nBlockSize + nBytes;
int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee;
bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL)
{
- CAutoFile filein = OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb");
+ CAutoFile filein = CAutoFile(OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb"), SER_DISK, CLIENT_VERSION);
if (!filein)
return error("CTransaction::ReadFromDisk() : OpenBlockFile failed");
bool ClientConnectInputs();
bool CheckTransaction() const;
bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
- bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL);
protected:
const CTxOut& GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const;
- bool AddToMemoryPoolUnchecked();
-public:
- bool RemoveFromMemoryPool();
};
int nIndex;
// memory only
- mutable char fMerkleVerified;
+ mutable bool fMerkleVerified;
CMerkleTx()
bool WriteToDisk(unsigned int& nFileRet, unsigned int& nBlockPosRet)
{
// Open history file to append
- CAutoFile fileout = AppendBlockFile(nFileRet);
+ CAutoFile fileout = CAutoFile(AppendBlockFile(nFileRet), SER_DISK, CLIENT_VERSION);
if (!fileout)
return error("CBlock::WriteToDisk() : AppendBlockFile failed");
SetNull();
// Open history file to read
- CAutoFile filein = OpenBlockFile(nFile, nBlockPos, "rb");
+ CAutoFile filein = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb"), SER_DISK, CLIENT_VERSION);
if (!filein)
return error("CBlock::ReadFromDisk() : OpenBlockFile failed");
if (!fReadTransactions)
bool EraseBlockFromDisk()
{
// Open history file
- CAutoFile fileout = OpenBlockFile(nFile, nBlockPos, "rb+");
+ CAutoFile fileout = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb+"), SER_DISK, CLIENT_VERSION);
if (!fileout)
return false;
return error("CAlert::CheckSignature() : verify signature failed");
// Now unserialize the data
- CDataStream sMsg(vchMsg);
+ CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
sMsg >> *(CUnsignedAlert*)this;
return true;
}
bool ProcessAlert();
};
+class CTxMemPool
+{
+public:
+ mutable CCriticalSection cs;
+ std::map<uint256, CTransaction> mapTx;
+ std::map<COutPoint, CInPoint> mapNextTx;
+
+ bool accept(CTxDB& txdb, CTransaction &tx,
+ bool fCheckInputs, bool* pfMissingInputs);
+ bool addUnchecked(CTransaction &tx);
+ bool remove(CTransaction &tx);
+
+ unsigned long size()
+ {
+ LOCK(cs);
+ return mapTx.size();
+ }
+
+ bool exists(uint256 hash)
+ {
+ return (mapTx.count(hash) != 0);
+ }
+
+ CTransaction& lookup(uint256 hash)
+ {
+ return mapTx[hash];
+ }
+};
+
+extern CTxMemPool mempool;
+
#endif
-I"$(DEPSDIR)/boost_1_47_0" \
-I"$(DEPSDIR)/db-4.8.30.NC/build_unix" \
-I"$(DEPSDIR)/openssl-1.0.1b/include" \
- -I"$(DEPSDIR)"
+ -I"$(DEPSDIR)" \
+ -I"$(CURDIR)"/obj \
LIBPATHS= \
-L"$(DEPSDIR)/boost_1_47_0/stage/lib" \
-l ssl \
-l crypto
-DEFS=-D_MT -DWIN32 -D_WINDOWS -DNOPCH -DUSE_SSL -DBOOST_THREAD_USE_LIB
+DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB
DEBUGFLAGS=-g
CFLAGS=-O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
+TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data)
ifdef USE_UPNP
LIBPATHS += -L"$(DEPSDIR)/miniupnpc"
HEADERS = $(wildcard *.h)
OBJS= \
+ obj/version.o \
obj/checkpoints.o \
obj/netbase.o \
obj/addrman.o \
obj/rpcdump.o \
obj/script.o \
obj/util.o \
- obj/wallet.o
+ obj/wallet.o \
+ obj/walletdb.o \
+ obj/noui.o
all: bitcoind.exe
+obj/build.h: FORCE
+ ../share/genbuild.sh obj/build.h
+version.cpp: obj/build.h
+DEFS += -DHAVE_BUILD_INFO
+
obj/%.o: %.cpp $(HEADERS)
i586-mingw32msvc-g++ -c $(CFLAGS) -o $@ $<
bitcoind.exe: $(OBJS:obj/%=obj/%)
i586-mingw32msvc-g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
+TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
-obj/test/%.o: obj/test/%.cpp $(HEADERS)
- i586-mingw32msvc-g++ -c $(CFLAGS) -o $@ $<
+obj-test/%.o: test/%.cpp $(HEADERS)
+ i586-mingw32msvc-g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $<
-test_bitcoin.exe: obj/test/test_bitcoin.o $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
- i586-mingw32msvc-g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) -lboost_unit_test_framework-mt-s
+test_bitcoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
+ i586-mingw32msvc-g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework $(LIBS)
clean:
-rm -f obj/*.o
- -rm -f obj/test/*.o
- -rm -f test/*.o
- -rm -f headers.h.gch
-rm -f bitcoind.exe
+ -rm -f obj-test/*.o
-rm -f test_bitcoin.exe
+ -rm -f src/build.h
+
+FORCE:
-l ssl \
-l crypto
-DEFS=-DWIN32 -D_WINDOWS -DNOPCH -DUSE_SSL -DBOOST_THREAD_USE_LIB
+DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB
DEBUGFLAGS=-g
CFLAGS=-mthreads -O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
+TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data)
ifdef USE_UPNP
INCLUDEPATHS += -I"C:\miniupnpc-1.6-mgw"
HEADERS = $(wildcard *.h)
OBJS= \
+ obj/version.o \
obj/checkpoints.o \
obj/netbase.o \
obj/addrman.o \
obj/rpcdump.o \
obj/script.o \
obj/util.o \
- obj/wallet.o
+ obj/wallet.o \
+ obj/walletdb.o \
+ obj/noui.o
all: bitcoind.exe
bitcoind.exe: $(OBJS:obj/%=obj/%)
g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
-obj/test/test_bitcoin.o: $(wildcard test/*.cpp) $(HEADERS)
- g++ -c $(CFLAGS) -o $@ test/test_bitcoin.cpp
+TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
-test_bitcoin.exe: obj/test/test_bitcoin.o $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
- g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
+obj-test/%.o: test/%.cpp $(HEADERS)
+ g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $<
+
+test_bitcoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
+ g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework $(LIBS)
clean:
-del /Q bitcoind test_bitcoin
-del /Q obj\*
- -del /Q obj\nogui\*
- -del /Q obj\test\*
- -del /Q test\*.o
- -del /Q headers.h.gch
+ -del /Q obj-test\*
+ -del /Q build.h
INCLUDEPATHS= \
-I"$(CURDIR)" \
+ -I"$(CURDIR)"/obj \
-I"$(DEPSDIR)/include" \
-I"$(DEPSDIR)/include/db48"
USE_UPNP:=1
LIBS= -dead_strip
+
+TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data)
+
ifdef STATIC
# Build STATIC if you are redistributing the bitcoind binary
TESTLIBS += \
TESTDEFS += -DBOOST_TEST_DYN_LINK
endif
-DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DUSE_SSL
+DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0
+
+ifdef RELEASE
+# Compile for maximum compatibility and smallest size.
+# This requires that dependencies are compiled
+# the same way.
+CFLAGS = -mmacosx-version-min=10.5 -arch i386 -O3
+else
+CFLAGS = -g
+endif
-DEBUGFLAGS=-g
# ppc doesn't work because we don't support big-endian
-CFLAGS=-mmacosx-version-min=10.5 -arch i386 -O3 \
- -Wextra -Wno-sign-compare -Wno-char-subscripts -Wno-invalid-offsetof -Wformat-security \
+CFLAGS += -Wextra -Wno-sign-compare -Wno-invalid-offsetof -Wformat-security \
$(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
OBJS= \
+ obj/version.o \
obj/checkpoints.o \
obj/netbase.o \
obj/addrman.o \
obj/rpcdump.o \
obj/script.o \
obj/util.o \
- obj/wallet.o
+ obj/wallet.o \
+ obj/walletdb.o \
+ obj/noui.o
ifdef USE_UPNP
DEFS += -DUSE_UPNP=$(USE_UPNP)
-include obj/*.P
-include obj-test/*.P
+obj/build.h: FORCE
+ ../share/genbuild.sh obj/build.h
+version.cpp: obj/build.h
+DEFS += -DHAVE_BUILD_INFO
+
obj/%.o: %.cpp
$(CXX) -c $(CFLAGS) -MMD -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
-rm -f obj-test/*.o
-rm -f obj/*.P
-rm -f obj-test/*.P
+ -rm -f src/build.h
+
+FORCE:
USE_UPNP:=0
-DEFS=-DNOPCH
+DEFS=
-DEFS += $(addprefix -I,$(CURDIR) $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH))
+DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH))
LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH))
+TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data)
+
LMODE = dynamic
LMODE2 = dynamic
ifdef STATIC
DEFS += -DUSE_UPNP=$(USE_UPNP)
endif
-ifneq (${USE_SSL}, 0)
- DEFS += -DUSE_SSL
-endif
-
LIBS+= \
-Wl,-B$(LMODE2) \
-l z \
DEBUGFLAGS=-g
CXXFLAGS=-O2
-xCXXFLAGS=-pthread -Wextra -Wno-sign-compare -Wno-char-subscripts -Wno-invalid-offsetof -Wformat -Wformat-security \
+xCXXFLAGS=-pthread -Wall -Wextra -Wno-sign-compare -Wno-invalid-offsetof -Wno-unused-parameter -Wformat -Wformat-security \
$(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS)
OBJS= \
+ obj/version.o \
obj/checkpoints.o \
obj/netbase.o \
obj/addrman.o \
obj/rpcdump.o \
obj/script.o \
obj/util.o \
- obj/wallet.o
+ obj/wallet.o \
+ obj/walletdb.o \
+ obj/noui.o
all: bitcoind
-include obj/*.P
-include obj-test/*.P
+obj/build.h: FORCE
+ ../share/genbuild.sh obj/build.h
+version.cpp: obj/build.h
+DEFS += -DHAVE_BUILD_INFO
+
obj/%.o: %.cpp
$(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
-rm -f obj-test/*.o
-rm -f obj/*.P
-rm -f obj-test/*.P
+ -rm -f src/build.h
+
+FORCE:
// 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 "irc.h"
#include "db.h"
#include "net.h"
#include "init.h"
#include "strlcpy.h"
#include "addrman.h"
+#include "ui_interface.h"
#ifdef WIN32
#include <string.h>
-#else
-#include <netinet/in.h>
#endif
#ifdef USE_UPNP
set<CNetAddr> setservAddNodeAddresses;
CCriticalSection cs_setservAddNodeAddresses;
+static CWaitableCriticalSection csOutbound;
+static int nOutbound = 0;
+static CConditionVariable condOutbound;
unsigned short GetListenPort()
// setAddrKnown automatically filters any duplicate sends.
CAddress addr(addrLocalHost);
addr.nTime = GetAdjustedTime();
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
pnode->PushAddress(addr);
+ }
}
}
}
-void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
-{
- // If the dialog might get closed before the reply comes back,
- // call this in the destructor so it doesn't get called after it's deleted.
- CRITICAL_BLOCK(cs_vNodes)
- {
- BOOST_FOREACH(CNode* pnode, vNodes)
- {
- CRITICAL_BLOCK(pnode->cs_mapRequests)
- {
- for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
- {
- CRequestTracker& tracker = (*mi).second;
- if (tracker.fn == fn && tracker.param1 == param1)
- pnode->mapRequests.erase(mi++);
- else
- mi++;
- }
- }
- }
- }
-}
-
-
-
-
-
-
-
-//
-// Subscription methods for the broadcast and subscription system.
-// Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT.
-//
-// The subscription system uses a meet-in-the-middle strategy.
-// With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
-// subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
-//
-
-bool AnySubscribed(unsigned int nChannel)
-{
- if (pnodeLocalHost->IsSubscribed(nChannel))
- return true;
- CRITICAL_BLOCK(cs_vNodes)
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->IsSubscribed(nChannel))
- return true;
- return false;
-}
-
-bool CNode::IsSubscribed(unsigned int nChannel)
-{
- if (nChannel >= vfSubscribe.size())
- return false;
- return vfSubscribe[nChannel];
-}
-
-void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
-{
- if (nChannel >= vfSubscribe.size())
- return;
-
- if (!AnySubscribed(nChannel))
- {
- // Relay subscribe
- CRITICAL_BLOCK(cs_vNodes)
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode != this)
- pnode->PushMessage("subscribe", nChannel, nHops);
- }
-
- vfSubscribe[nChannel] = true;
-}
-
-void CNode::CancelSubscribe(unsigned int nChannel)
-{
- if (nChannel >= vfSubscribe.size())
- return;
-
- // Prevent from relaying cancel if wasn't subscribed
- if (!vfSubscribe[nChannel])
- return;
- vfSubscribe[nChannel] = false;
-
- if (!AnySubscribed(nChannel))
- {
- // Relay subscription cancel
- CRITICAL_BLOCK(cs_vNodes)
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode != this)
- pnode->PushMessage("sub-cancel", nChannel);
- }
-}
-
-
-
-
-
-
-
CNode* FindNode(const CNetAddr& ip)
{
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
if ((CNetAddr)pnode->addr == ip)
return (pnode);
CNode* FindNode(const CService& addr)
{
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
if ((CService)pnode->addr == addr)
return (pnode);
pnode->AddRef(nTimeout);
else
pnode->AddRef();
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
vNodes.push_back(pnode);
+ }
+ {
+ WAITABLE_LOCK(csOutbound);
+ nOutbound++;
+ }
pnode->nTimeConnected = GetTime();
return pnode;
void CNode::Cleanup()
{
- // All of a nodes broadcasts and subscriptions are automatically torn down
- // when it goes down, so a node has to stay up to keep its broadcast going.
-
- // Cancel subscriptions
- for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
- if (vfSubscribe[nChannel])
- CancelSubscribe(nChannel);
}
bool CNode::IsBanned(CNetAddr ip)
{
bool fResult = false;
- CRITICAL_BLOCK(cs_setBanned)
{
+ LOCK(cs_setBanned);
std::map<CNetAddr, int64>::iterator i = setBanned.find(ip);
if (i != setBanned.end())
{
if (nMisbehavior >= GetArg("-banscore", 100))
{
int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
- CRITICAL_BLOCK(cs_setBanned)
+ {
+ LOCK(cs_setBanned);
if (setBanned[addr] < banTime)
setBanned[addr] = banTime;
+ }
CloseSocketDisconnect();
printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
return true;
{
printf("ThreadSocketHandler started\n");
list<CNode*> vNodesDisconnected;
- int nPrevNodeCount = 0;
+ unsigned int nPrevNodeCount = 0;
loop
{
//
// Disconnect nodes
//
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
// Disconnect unused nodes
vector<CNode*> vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
// remove from vNodes
vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
+ if (!pnode->fInbound)
+ {
+ WAITABLE_LOCK(csOutbound);
+ nOutbound--;
+
+ // Connection slot(s) were removed, notify connection creator(s)
+ NOTIFY(condOutbound);
+ }
+
// close socket and cleanup
pnode->CloseSocketDisconnect();
pnode->Cleanup();
if (pnode->GetRefCount() <= 0)
{
bool fDelete = false;
- TRY_CRITICAL_BLOCK(pnode->cs_vSend)
- TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
- TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
- TRY_CRITICAL_BLOCK(pnode->cs_inventory)
- fDelete = true;
+ {
+ TRY_LOCK(pnode->cs_vSend, lockSend);
+ if (lockSend)
+ {
+ TRY_LOCK(pnode->cs_vRecv, lockRecv);
+ if (lockRecv)
+ {
+ TRY_LOCK(pnode->cs_mapRequests, lockReq);
+ if (lockReq)
+ {
+ TRY_LOCK(pnode->cs_inventory, lockInv);
+ if (lockInv)
+ fDelete = true;
+ }
+ }
+ }
+ }
if (fDelete)
{
vNodesDisconnected.remove(pnode);
if(hListenSocket != INVALID_SOCKET)
FD_SET(hListenSocket, &fdsetRecv);
hSocketMax = max(hSocketMax, hListenSocket);
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
if (pnode->hSocket == INVALID_SOCKET)
FD_SET(pnode->hSocket, &fdsetRecv);
FD_SET(pnode->hSocket, &fdsetError);
hSocketMax = max(hSocketMax, pnode->hSocket);
- TRY_CRITICAL_BLOCK(pnode->cs_vSend)
- if (!pnode->vSend.empty())
+ {
+ TRY_LOCK(pnode->cs_vSend, lockSend);
+ if (lockSend && !pnode->vSend.empty())
FD_SET(pnode->hSocket, &fdsetSend);
+ }
}
}
if (hSocket != INVALID_SOCKET)
addr = CAddress(sockaddr);
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->fInbound)
- nInbound++;
+ if (pnode->fInbound)
+ nInbound++;
+ }
if (hSocket == INVALID_SOCKET)
{
}
else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
{
- CRITICAL_BLOCK(cs_setservAddNodeAddresses)
+ {
+ LOCK(cs_setservAddNodeAddresses);
if (!setservAddNodeAddresses.count(addr))
closesocket(hSocket);
+ }
}
else if (CNode::IsBanned(addr))
{
printf("accepted connection %s\n", addr.ToString().c_str());
CNode* pnode = new CNode(hSocket, addr, true);
pnode->AddRef();
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
vNodes.push_back(pnode);
+ }
}
}
// Service each socket
//
vector<CNode*> vNodesCopy;
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->AddRef();
continue;
if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
{
- TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
+ TRY_LOCK(pnode->cs_vRecv, lockRecv);
+ if (lockRecv)
{
CDataStream& vRecv = pnode->vRecv;
unsigned int nPos = vRecv.size();
continue;
if (FD_ISSET(pnode->hSocket, &fdsetSend))
{
- TRY_CRITICAL_BLOCK(pnode->cs_vSend)
+ TRY_LOCK(pnode->cs_vSend, lockSend);
+ if (lockSend)
{
CDataStream& vSend = pnode->vSend;
if (!vSend.empty())
}
}
}
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->Release();
}
int64 nStart = GetTime();
loop
{
- int nOutbound = 0;
-
vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
Sleep(500);
vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
return;
// Limit outbound connections
- loop
+ int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125));
+ vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
{
- nOutbound = 0;
- CRITICAL_BLOCK(cs_vNodes)
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (!pnode->fInbound)
- nOutbound++;
- int nMaxOutboundConnections = MAX_OUTBOUND_CONNECTIONS;
- nMaxOutboundConnections = min(nMaxOutboundConnections, (int)GetArg("-maxconnections", 125));
- if (nOutbound < nMaxOutboundConnections)
- break;
- vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
- Sleep(2000);
- vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
- if (fShutdown)
- return;
+ WAITABLE_LOCK(csOutbound);
+ WAIT(condOutbound, fShutdown || nOutbound < nMaxOutbound);
}
+ vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
+ if (fShutdown)
+ return;
// Add seed nodes if IRC isn't working
bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050);
// Only connect to one address per a.b.?.? range.
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
set<vector<unsigned char> > setConnected;
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
setConnected.insert(pnode->addr.GetGroup());
+ }
int64 nANow = GetAdjustedTime();
if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fAllowDNS, 0))
{
vservAddressesToAdd.push_back(vservNode);
- CRITICAL_BLOCK(cs_setservAddNodeAddresses)
+ {
+ LOCK(cs_setservAddNodeAddresses);
BOOST_FOREACH(CService& serv, vservNode)
setservAddNodeAddresses.insert(serv);
+ }
}
}
loop
vector<vector<CService> > vservConnectAddresses = vservAddressesToAdd;
// Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
// (keeping in mind that addnode entries can have many IPs if fAllowDNS)
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
for (vector<vector<CService> >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++)
BOOST_FOREACH(CService& addrNode, *(it))
it--;
break;
}
+ }
BOOST_FOREACH(vector<CService>& vserv, vservConnectAddresses)
{
OpenNetworkConnection(CAddress(*(vserv.begin())));
while (!fShutdown)
{
vector<CNode*> vNodesCopy;
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->AddRef();
BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
// Receive messages
- TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
- ProcessMessages(pnode);
+ {
+ TRY_LOCK(pnode->cs_vRecv, lockRecv);
+ if (lockRecv)
+ ProcessMessages(pnode);
+ }
if (fShutdown)
return;
// Send messages
- TRY_CRITICAL_BLOCK(pnode->cs_vSend)
- SendMessages(pnode, pnode == pnodeTrickle);
+ {
+ TRY_LOCK(pnode->cs_vSend, lockSend);
+ if (lockSend)
+ SendMessages(pnode, pnode == pnodeTrickle);
+ }
if (fShutdown)
return;
}
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->Release();
}
{
vector<CNetAddr> vaddr;
if (LookupHost(pszHostName, vaddr))
+ {
BOOST_FOREACH (const CNetAddr &addr, vaddr)
+ {
if (!addr.IsLocal())
{
addrLocalHost.SetIP(addr);
break;
}
+ }
+ }
}
#else
// Get local host ip
fShutdown = true;
nTransactionsUpdated++;
int64 nStart = GetTime();
+ NOTIFY_ALL(condOutbound);
do
{
int nThreadsRunning = 0;
inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); }
inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
-static const unsigned int PUBLISH_HOPS = 5;
bool RecvLine(SOCKET hSocket, std::string& strLine);
bool GetMyExternalIP(CNetAddr& ipRet);
CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
-void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
-bool AnySubscribed(unsigned int nChannel);
void MapPort(bool fMapPort);
bool BindListenPort(std::string& strError=REF(std::string()));
void StartNode(void* parg);
int64 nLastRecv;
int64 nLastSendEmpty;
int64 nTimeConnected;
- signed int nHeaderStart;
+ int nHeaderStart;
unsigned int nMessageStart;
CAddress addr;
int nVersion;
CCriticalSection cs_inventory;
std::multimap<int64, CInv> mapAskFor;
- // publish and subscription
- std::vector<char> vfSubscribe;
-
- CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
+ CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) : vSend(SER_NETWORK, MIN_PROTO_VERSION), vRecv(SER_NETWORK, MIN_PROTO_VERSION)
{
nServices = 0;
hSocket = hSocketIn;
- vSend.SetType(SER_NETWORK);
- vRecv.SetType(SER_NETWORK);
- vSend.SetVersion(209);
- vRecv.SetVersion(209);
nLastSend = 0;
nLastRecv = 0;
nLastSendEmpty = GetTime();
hashLastGetBlocksEnd = 0;
nStartingHeight = -1;
fGetAddr = false;
- vfSubscribe.assign(256, false);
nMisbehavior = 0;
setInventoryKnown.max_size(SendBufferSize() / 1000);
void AddInventoryKnown(const CInv& inv)
{
- CRITICAL_BLOCK(cs_inventory)
+ {
+ LOCK(cs_inventory);
setInventoryKnown.insert(inv);
+ }
}
void PushInventory(const CInv& inv)
{
- CRITICAL_BLOCK(cs_inventory)
+ {
+ LOCK(cs_inventory);
if (!setInventoryKnown.count(inv))
vInventoryToSend.push_back(inv);
+ }
}
void AskFor(const CInv& inv)
void AbortMessage()
{
- if (nHeaderStart == -1)
+ if (nHeaderStart < 0)
return;
vSend.resize(nHeaderStart);
nHeaderStart = -1;
return;
}
- if (nHeaderStart == -1)
+ if (nHeaderStart < 0)
return;
// Set the size
void EndMessageAbortIfEmpty()
{
- if (nHeaderStart == -1)
+ if (nHeaderStart < 0)
return;
int nSize = vSend.size() - nMessageStart;
if (nSize > 0)
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
- CRITICAL_BLOCK(cs_mapRequests)
+ {
+ LOCK(cs_mapRequests);
mapRequests[hashReply] = CRequestTracker(fn, param1);
+ }
PushMessage(pszCommand, hashReply);
}
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
- CRITICAL_BLOCK(cs_mapRequests)
+ {
+ LOCK(cs_mapRequests);
mapRequests[hashReply] = CRequestTracker(fn, param1);
+ }
PushMessage(pszCommand, hashReply, a1);
}
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
- CRITICAL_BLOCK(cs_mapRequests)
+ {
+ LOCK(cs_mapRequests);
mapRequests[hashReply] = CRequestTracker(fn, param1);
+ }
PushMessage(pszCommand, hashReply, a1, a2);
}
inline void RelayInventory(const CInv& inv)
{
// Put on lists to offer to the other nodes
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
pnode->PushInventory(inv);
+ }
}
template<typename T>
void RelayMessage(const CInv& inv, const T& a)
{
- CDataStream ss(SER_NETWORK);
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(10000);
ss << a;
RelayMessage(inv, ss);
template<>
inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
{
- CRITICAL_BLOCK(cs_mapRelay)
{
+ LOCK(cs_mapRelay);
// Expire old relay messages
while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
{
}
// Save original serialized message so newer versions are preserved
- mapRelay[inv] = ss;
+ mapRelay.insert(std::make_pair(inv, ss));
vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
}
}
-
-
-
-
-
-
-//
-// Templates for the publish and subscription system.
-// The object being published as T& obj needs to have:
-// a set<unsigned int> setSources member
-// specializations of AdvertInsert and AdvertErase
-// Currently implemented for CTable and CProduct.
-//
-
-template<typename T>
-void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
-{
- // Add to sources
- obj.setSources.insert(pfrom->addr.ip);
-
- if (!AdvertInsert(obj))
- return;
-
- // Relay
- CRITICAL_BLOCK(cs_vNodes)
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
- pnode->PushMessage("publish", nChannel, nHops, obj);
-}
-
-template<typename T>
-void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
-{
- uint256 hash = obj.GetHash();
-
- CRITICAL_BLOCK(cs_vNodes)
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
- pnode->PushMessage("pub-cancel", nChannel, nHops, hash);
-
- AdvertErase(obj);
-}
-
-template<typename T>
-void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
-{
- // Remove a source
- obj.setSources.erase(pfrom->addr.ip);
-
- // If no longer supported by any sources, cancel it
- if (obj.setSources.empty())
- AdvertStopPublish(pfrom, nChannel, nHops, obj);
-}
-
#endif
#include <string>
#include <vector>
-#ifdef WIN32
-#define _WIN32_WINNT 0x0501
-#include <winsock2.h>
-#include <mswsock.h>
-#include <ws2tcpip.h>
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <net/if.h>
-#include <ifaddrs.h>
-#include <netinet/in.h>
-#endif
-
#include "serialize.h"
#include "compat.h"
extern int nConnectTimeout;
+#ifdef WIN32
+// In MSVC, this is defined as a macro, undefine it to prevent a compile and link error
+#undef SetPort
+#endif
/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */
class CNetAddr
)
};
-/** A combnation of a network address (CNetAddr) and a (TCP) port */
+/** A combination of a network address (CNetAddr) and a (TCP) port */
class CService : public CNetAddr
{
protected:
--- /dev/null
+// Copyright (c) 2010 Satoshi Nakamoto
+// Copyright (c) 2009-2012 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 "ui_interface.h"
+
+#include <string>
+#include "init.h"
+
+int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
+{
+ printf("%s: %s\n", caption.c_str(), message.c_str());
+ fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
+ return 4;
+}
+
+bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
+{
+ return true;
+}
+
+void MainFrameRepaint()
+{
+}
+
+void AddressBookRepaint()
+{
+}
+
+void InitMessage(const std::string &message)
+{
+}
+
+std::string _(const char* psz)
+{
+ return psz;
+}
+
+void QueueShutdown()
+{
+ // Without UI, Shutdown can simply be started in a new thread
+ CreateThread(Shutdown, NULL);
+}
+
--- a/src/noui.cpp
+++ /dev/null
-// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2012 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_NOUI_H
-#define BITCOIN_NOUI_H
-
-#include <string>
-#include <boost/function.hpp>
-#include "wallet.h"
-
-typedef void wxWindow;
-#define wxYES 0x00000002
-#define wxOK 0x00000004
-#define wxNO 0x00000008
-#define wxYES_NO (wxYES|wxNO)
-#define wxCANCEL 0x00000010
-#define wxAPPLY 0x00000020
-#define wxCLOSE 0x00000040
-#define wxOK_DEFAULT 0x00000000
-#define wxYES_DEFAULT 0x00000000
-#define wxNO_DEFAULT 0x00000080
-#define wxCANCEL_DEFAULT 0x80000000
-#define wxICON_EXCLAMATION 0x00000100
-#define wxICON_HAND 0x00000200
-#define wxICON_WARNING wxICON_EXCLAMATION
-#define wxICON_ERROR wxICON_HAND
-#define wxICON_QUESTION 0x00000400
-#define wxICON_INFORMATION 0x00000800
-#define wxICON_STOP wxICON_HAND
-#define wxICON_ASTERISK wxICON_INFORMATION
-#define wxICON_MASK (0x00000100|0x00000200|0x00000400|0x00000800)
-#define wxFORWARD 0x00001000
-#define wxBACKWARD 0x00002000
-#define wxRESET 0x00004000
-#define wxHELP 0x00008000
-#define wxMORE 0x00010000
-#define wxSETUP 0x00020000
-// Force blocking, modal message box dialog (not just notification)
-#define wxMODAL 0x00040000
-
-inline int MyMessageBox(const std::string& message, const std::string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1)
-{
- printf("%s: %s\n", caption.c_str(), message.c_str());
- fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
- return 4;
-}
-#define wxMessageBox MyMessageBox
-
-inline int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1)
-{
- return MyMessageBox(message, caption, style, parent, x, y);
-}
-
-inline bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent)
-{
- return true;
-}
-
-inline void CalledSetStatusBar(const std::string& strText, int nField)
-{
-}
-
-inline void UIThreadCall(boost::function0<void> fn)
-{
-}
-
-inline void MainFrameRepaint()
-{
-}
-
-inline void InitMessage(const std::string &message)
-{
-}
-
-#endif
+++ /dev/null
-*
-!.gitignore
+++ /dev/null
-*
-!.gitignore
+++ b/src/obj/test/.gitignore
bool CInv::IsKnownType() const
{
- return (type >= 1 && type < ARRAYLEN(ppszTypeName));
+ return (type >= 1 && type < (int)ARRAYLEN(ppszTypeName));
}
const char* CInv::GetCommand() const
#include "serialize.h"
#include "netbase.h"
-#include "util.h"
#include <string>
#include "uint256.h"
if (fRead)
pthis->Init();
if (nType & SER_DISK)
- READWRITE(nVersion);
- if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH)))
- READWRITE(nTime);
+ READWRITE(nVersion);
+ if ((nType & SER_DISK) ||
+ (nVersion >= CADDR_TIME_VERSION && !(nType & SER_GETHASH)))
+ READWRITE(nTime);
READWRITE(nServices);
READWRITE(*pip);
)
#include "ui_aboutdialog.h"
#include "clientmodel.h"
+#include "version.h"
+
AboutDialog::AboutDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::AboutDialog)
ui->tableView->setFocus();
break;
case ForEditing:
- ui->buttonBox->hide();
+ ui->buttonBox->setVisible(false);
break;
}
switch(tab)
{
case SendingTab:
- ui->labelExplanation->hide();
+ ui->labelExplanation->setVisible(false);
+ ui->deleteButton->setVisible(true);
+ ui->signMessage->setVisible(false);
break;
case ReceivingTab:
+ ui->deleteButton->setVisible(false);
+ ui->signMessage->setVisible(true);
break;
}
ui->tableView->setTabKeyNavigation(false);
this->model = model;
if(!model)
return;
- // Refresh list from core
- model->updateList();
proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(model);
{
GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
}
+
void AddressBookPage::onCopyLabelAction()
{
GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
case SendingTab:
// In sending tab, allow deletion of selection
ui->deleteButton->setEnabled(true);
+ ui->deleteButton->setVisible(true);
deleteAction->setEnabled(true);
ui->signMessage->setEnabled(false);
+ ui->signMessage->setVisible(false);
break;
case ReceivingTab:
// Deleting receiving addresses, however, is not allowed
ui->deleteButton->setEnabled(false);
+ ui->deleteButton->setVisible(false);
deleteAction->setEnabled(false);
ui->signMessage->setEnabled(true);
+ ui->signMessage->setVisible(true);
break;
}
ui->copyToClipboard->setEnabled(true);
QTableView *table = ui->tableView;
QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
-
- QRCodeDialog *d;
foreach (QModelIndex index, indexes)
{
- QString address = index.data().toString(),
- label = index.sibling(index.row(), 0).data(Qt::EditRole).toString(),
- title = QString("%1%2<< %3 >>").arg(label).arg(label.isEmpty() ? "" : " ").arg(address);
+ QString address = index.data().toString(), label = index.sibling(index.row(), 0).data(Qt::EditRole).toString();
- QRCodeDialog *d = new QRCodeDialog(title, address, label, tab == ReceivingTab, this);
- d->show();
+ QRCodeDialog *dialog = new QRCodeDialog(address, label, tab == ReceivingTab, this);
+ dialog->show();
}
#endif
}
#include "guiutil.h"
#include "walletmodel.h"
-#include "headers.h"
+#include "wallet.h"
#include <QFont>
#include <QColor>
{
cachedAddressTable.clear();
- CRITICAL_BLOCK(wallet->cs_wallet)
{
+ LOCK(wallet->cs_wallet);
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, std::string)& item, wallet->mapAddressBook)
{
const CBitcoinAddress& address = item.first;
// Double-check that we're not overwriting a receiving address
if(rec->type == AddressTableEntry::Sending)
{
- CRITICAL_BLOCK(wallet->cs_wallet)
{
+ LOCK(wallet->cs_wallet);
// Remove old entry
wallet->DelAddressBookName(rec->address.toStdString());
// Add new entry with new address
}
}
-void AddressTableModel::updateList()
+void AddressTableModel::update()
{
// Update address book model from Bitcoin core
beginResetModel();
return QString();
}
// Check for duplicate addresses
- CRITICAL_BLOCK(wallet->cs_wallet)
{
+ LOCK(wallet->cs_wallet);
if(wallet->mapAddressBook.count(strAddress))
{
editStatus = DUPLICATE_ADDRESS;
{
return QString();
}
- // Add entry and update list
- CRITICAL_BLOCK(wallet->cs_wallet)
+ // Add entry
+ {
+ LOCK(wallet->cs_wallet);
wallet->SetAddressBookName(strAddress, strLabel);
- updateList();
+ }
return QString::fromStdString(strAddress);
}
// Also refuse to remove receiving addresses.
return false;
}
- CRITICAL_BLOCK(wallet->cs_wallet)
{
+ LOCK(wallet->cs_wallet);
wallet->DelAddressBookName(rec->address.toStdString());
}
- updateList();
return true;
}
-void AddressTableModel::update()
-{
-
-}
-
/* Look up label for address in address book, if not found return empty string.
*/
QString AddressTableModel::labelForAddress(const QString &address) const
{
- CRITICAL_BLOCK(wallet->cs_wallet)
{
+ LOCK(wallet->cs_wallet);
CBitcoinAddress address_parsed(address.toStdString());
std::map<CBitcoinAddress, std::string>::iterator mi = wallet->mapAddressBook.find(address_parsed);
if (mi != wallet->mapAddressBook.end())
*/
QString addRow(const QString &type, const QString &label, const QString &address);
- /* Update address list from core. Invalidates any indices.
- */
- void updateList();
-
/* Look up label for address in address book, if not found return empty string.
*/
QString labelForAddress(const QString &address) const;
void defaultAddressChanged(const QString &address);
public slots:
+ /* Update address list from core. Invalidates any indices.
+ */
void update();
};
#include "clientmodel.h"
#include "walletmodel.h"
#include "optionsmodel.h"
+#include "guiutil.h"
-#include "headers.h"
#include "init.h"
+#include "ui_interface.h"
#include "qtipcserver.h"
-#include "util.h"
#include <QApplication>
#include <QMessageBox>
-#include <QThread>
#include <QTextCodec>
#include <QLocale>
#include <QTranslator>
#include <boost/interprocess/ipc/message_queue.hpp>
-// Need a global reference for the notifications to find the GUI
-BitcoinGUI *guiref;
-QSplashScreen *splashref;
+#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
+#define _BITCOIN_QT_PLUGINS_INCLUDED
+#define __INSURE__
+#include <QtPlugin>
+Q_IMPORT_PLUGIN(qcncodecs)
+Q_IMPORT_PLUGIN(qjpcodecs)
+Q_IMPORT_PLUGIN(qtwcodecs)
+Q_IMPORT_PLUGIN(qkrcodecs)
+Q_IMPORT_PLUGIN(qtaccessiblewidgets)
+#endif
-int MyMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
-{
- // Message from AppInit2(), always in main thread before main window is constructed
- QMessageBox::critical(0, QString::fromStdString(caption),
- QString::fromStdString(message),
- QMessageBox::Ok, QMessageBox::Ok);
- return 4;
-}
+// Need a global reference for the notifications to find the GUI
+static BitcoinGUI *guiref;
+static QSplashScreen *splashref;
+static WalletModel *walletmodel;
+static ClientModel *clientmodel;
-int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
+int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
{
- bool modal = style & wxMODAL;
-
- if (modal)
- while (!guiref)
- Sleep(1000);
-
// Message from network thread
if(guiref)
{
- QMetaObject::invokeMethod(guiref, "error", Qt::QueuedConnection,
+ bool modal = (style & wxMODAL);
+ // in case of modal message, use blocking connection to wait for user to click OK
+ QMetaObject::invokeMethod(guiref, "error",
+ modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, QString::fromStdString(message)),
Q_ARG(bool, modal));
return 4;
}
-bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent)
+bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
{
if(!guiref)
return false;
return true;
bool payFee = false;
- // Call slot on GUI thread.
- // If called from another thread, use a blocking QueuedConnection.
- Qt::ConnectionType connectionType = Qt::DirectConnection;
- if(QThread::currentThread() != QCoreApplication::instance()->thread())
- {
- connectionType = Qt::BlockingQueuedConnection;
- }
-
- QMetaObject::invokeMethod(guiref, "askFee", connectionType,
+ QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(),
Q_ARG(qint64, nFeeRequired),
Q_ARG(bool*, &payFee));
if(!guiref)
return;
- // Call slot on GUI thread.
- // If called from another thread, use a blocking QueuedConnection.
- Qt::ConnectionType connectionType = Qt::DirectConnection;
- if(QThread::currentThread() != QCoreApplication::instance()->thread())
- {
- connectionType = Qt::BlockingQueuedConnection;
- }
- QMetaObject::invokeMethod(guiref, "handleURI", connectionType,
+ QMetaObject::invokeMethod(guiref, "handleURI", GUIUtil::blockingGUIThreadConnection(),
Q_ARG(QString, QString::fromStdString(strURI)));
}
-void CalledSetStatusBar(const std::string& strText, int nField)
+void MainFrameRepaint()
{
- // Only used for built-in mining, which is disabled, simple ignore
+ if(clientmodel)
+ QMetaObject::invokeMethod(clientmodel, "update", Qt::QueuedConnection);
+ if(walletmodel)
+ QMetaObject::invokeMethod(walletmodel, "update", Qt::QueuedConnection);
}
-void UIThreadCall(boost::function0<void> fn)
+void AddressBookRepaint()
{
- // Only used for built-in mining, which is disabled, simple ignore
-}
-
-void MainFrameRepaint()
-{
- if(guiref)
- QMetaObject::invokeMethod(guiref, "refreshStatusBar", Qt::QueuedConnection);
+ if(walletmodel)
+ QMetaObject::invokeMethod(walletmodel, "updateAddressList", Qt::QueuedConnection);
}
void InitMessage(const std::string &message)
}
}
+void QueueShutdown()
+{
+ QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
+}
+
/*
Translate string to current locale using Qt.
*/
exit(1);
}
+#ifdef WIN32
+#define strncasecmp strnicmp
+#endif
#ifndef BITCOIN_QT_TEST
int main(int argc, char *argv[])
{
ParseParameters(argc, argv);
// ... then bitcoin.conf:
- if (!ReadConfigFile(mapArgs, mapMultiArgs))
+ if (!boost::filesystem::is_directory(GetDataDir(false)))
{
fprintf(stderr, "Error: Specified directory does not exist\n");
return 1;
}
+ ReadConfigFile(mapArgs, mapMultiArgs);
// Application identification (must be set before OptionsModel is initialized,
// as it is used to locate QSettings)
try
{
+ BitcoinGUI window;
+ guiref = &window;
if(AppInit2(argc, argv))
{
{
- // Put this in a block, so that BitcoinGUI is cleaned up properly before
- // calling Shutdown() in case of exceptions.
+ // Put this in a block, so that the Model objects are cleaned up before
+ // calling Shutdown().
optionsModel.Upgrade(); // Must be done after AppInit2
- BitcoinGUI window;
if (splashref)
splash.finish(&window);
ClientModel clientModel(&optionsModel);
+ clientmodel = &clientModel;
WalletModel walletModel(pwalletMain, &optionsModel);
+ walletmodel = &walletModel;
- guiref = &window;
window.setClientModel(&clientModel);
window.setWalletModel(&walletModel);
#endif
app.exec();
+ window.setClientModel(0);
+ window.setWalletModel(0);
guiref = 0;
+ clientmodel = 0;
+ walletmodel = 0;
}
Shutdown(NULL);
}
<RCC>
- <qresource prefix="/icons" lang="edit">
+ <qresource prefix="/icons">
<file alias="bitcoin">res/icons/bitcoin.png</file>
<file alias="address-book">res/icons/address-book.png</file>
<file alias="quit">res/icons/quit.png</file>
* W.J. van der Laan 20011-2012
* The Bitcoin Developers 20011-2012
*/
-
-#include "checkpoints.h"
-
#include "bitcoingui.h"
#include "transactiontablemodel.h"
#include "addressbookpage.h"
#include "guiconstants.h"
#include "askpassphrasedialog.h"
#include "notificator.h"
+#include "guiutil.h"
#ifdef Q_WS_MAC
#include "macdockiconhandler.h"
frameBlocksLayout->addWidget(labelBlocksIcon);
frameBlocksLayout->addStretch();
- // Progress bar for blocks download
- progressBarLabel = new QLabel(tr("Synchronizing with network..."));
+ // Progress bar and label for blocks download
+ progressBarLabel = new QLabel();
progressBarLabel->setVisible(false);
progressBar = new QProgressBar();
- progressBar->setToolTip(tr("Block chain synchronization in progress"));
+ progressBar->setAlignment(Qt::AlignCenter);
progressBar->setVisible(false);
statusBar()->addWidget(progressBarLabel);
optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
optionsAction->setToolTip(tr("Modify configuration options for bitcoin"));
optionsAction->setMenuRole(QAction::PreferencesRole);
- openBitcoinAction = new QAction(QIcon(":/icons/bitcoin"), tr("Open &Bitcoin"), this);
- openBitcoinAction->setToolTip(tr("Show the Bitcoin window"));
+ toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("Show/Hide &Bitcoin"), this);
+ toggleHideAction->setToolTip(tr("Show or hide the Bitcoin window"));
exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
exportAction->setToolTip(tr("Export the data in the current tab to a file"));
encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet"), this);
connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
- connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
+ connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden()));
connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet()));
connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
// Report errors from network/worker thread
- connect(clientModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
+ connect(clientModel, SIGNAL(error(QString,QString, bool)), this, SLOT(error(QString,QString,bool)));
}
}
if(walletModel)
{
// Report errors from wallet thread
- connect(walletModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
+ connect(walletModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
// Put transaction list in tabs
transactionView->setModel(walletModel);
trayIcon = new QSystemTrayIcon(this);
trayIconMenu = new QMenu(this);
trayIcon->setContextMenu(trayIconMenu);
- trayIcon->setToolTip("Bitcoin client");
+ trayIcon->setToolTip(tr("Bitcoin client"));
trayIcon->setIcon(QIcon(":/icons/toolbar"));
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
#else
// Note: On Mac, the dock icon is used to provide the tray's functionality.
MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
- connect(dockIconHandler, SIGNAL(dockIconClicked()), openBitcoinAction, SLOT(trigger()));
+ connect(dockIconHandler, SIGNAL(dockIconClicked()), toggleHideAction, SLOT(trigger()));
trayIconMenu = dockIconHandler->dockMenu();
#endif
// Configuration of the tray icon (or dock icon) icon menu
- trayIconMenu->addAction(openBitcoinAction);
+ trayIconMenu->addAction(toggleHideAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(messageAction);
#ifndef FIRST_CLASS_MESSAGING
{
if(reason == QSystemTrayIcon::Trigger)
{
- // Click on system tray icon triggers "open bitcoin"
- openBitcoinAction->trigger();
+ // Click on system tray icon triggers "show/hide bitcoin"
+ toggleHideAction->trigger();
}
}
#endif
+void BitcoinGUI::toggleHidden()
+{
+ // activateWindow() (sometimes) helps with keyboard focus on Windows
+ if (isHidden())
+ {
+ show();
+ activateWindow();
+ }
+ else if (isMinimized())
+ {
+ showNormal();
+ activateWindow();
+ }
+ else if (GUIUtil::isObscured(this))
+ {
+ raise();
+ activateWindow();
+ }
+ else
+ hide();
+}
+
void BitcoinGUI::optionsClicked()
{
if(!clientModel || !clientModel->getOptionsModel())
void BitcoinGUI::setNumBlocks(int count)
{
- if(!clientModel)
+ // don't show / hide progressBar and it's label if we have no connection(s) to the network
+ if (!clientModel || clientModel->getNumConnections() == 0)
+ {
+ progressBarLabel->setVisible(false);
+ progressBar->setVisible(false);
+
return;
- int total = clientModel->getNumBlocksOfPeers();
+ }
+
+ int nTotalBlocks = clientModel->getNumBlocksOfPeers();
QString tooltip;
- if(count < total)
+ if(count < nTotalBlocks)
{
+ int nRemainingBlocks = nTotalBlocks - count;
+ float nPercentageDone = count / (nTotalBlocks * 0.01f);
+
if (clientModel->getStatusBarWarnings() == "")
{
- progressBarLabel->setVisible(true);
progressBarLabel->setText(tr("Synchronizing with network..."));
- progressBar->setVisible(true);
- progressBar->setMaximum(total);
+ progressBarLabel->setVisible(true);
+ progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks));
+ progressBar->setMaximum(nTotalBlocks);
progressBar->setValue(count);
+ progressBar->setVisible(true);
}
else
{
progressBarLabel->setVisible(true);
progressBar->setVisible(false);
}
- tooltip = tr("Downloaded %1 of %2 blocks of transaction history.").arg(count).arg(total);
+ tooltip = tr("Downloaded %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
}
else
{
}
// Set icon state: spinning if catching up, tick otherwise
- if(secs < 90*60 && count >= Checkpoints::GetTotalBlocksEstimate())
+ if(secs < 90*60 && count >= nTotalBlocks)
{
tooltip = tr("Up to date") + QString(".\n") + tooltip;
- labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
}
else
{
progressBar->setToolTip(tooltip);
}
-void BitcoinGUI::refreshStatusBar()
-{
- /* Might display multiple times in the case of multiple alerts
- static QString prevStatusBar;
- QString newStatusBar = clientModel->getStatusBarWarnings();
- if (prevStatusBar != newStatusBar)
- {
- prevStatusBar = newStatusBar;
- error(tr("Network Alert"), newStatusBar);
- }*/
- setNumBlocks(clientModel->getNumBlocks());
-}
-
-bool HACK_SHUTDOWN = false;
-
void BitcoinGUI::error(const QString &title, const QString &message, bool modal)
{
// Report errors from network/worker thread
- if (modal)
+ if(modal)
{
QMessageBox::critical(this, title, message, QMessageBox::Ok, QMessageBox::Ok);
- if (HACK_SHUTDOWN)
- QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
} else {
notificator->notify(Notificator::Critical, title, message);
}
QAction *aboutAction;
QAction *receiveCoinsAction;
QAction *optionsAction;
- QAction *openBitcoinAction;
+ QAction *toggleHideAction;
QAction *exportAction;
QAction *encryptWalletAction;
QAction *backupWalletAction;
@see WalletModel::EncryptionStatus
*/
void setEncryptionStatus(int status);
- /** Set the status bar text if there are any warnings (removes sync progress bar if applicable) */
- void refreshStatusBar();
/** Notify the user of an error in the network or transaction handling code. */
- void error(const QString &title, const QString &message, bool modal = false);
+ void error(const QString &title, const QString &message, bool modal);
/** 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.
/** Show window if hidden, unminimize when minimized */
void showNormalIfMinimized();
+ /** Hide window if visible, show if hidden */
+ void toggleHidden();
};
#endif
#else
#define UNUSED
#endif
-static const char UNUSED *bitcoin_strings[] = {QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin version"),
+static const char UNUSED *bitcoin_strings[] = {QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Unable to bind to port %d on this computer. Bitcoin is probably already "
+"running."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Disk space is low "),
+QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin version"),
QT_TRANSLATE_NOOP("bitcoin-core", "Usage:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send command to -server or bitcoind"),
QT_TRANSLATE_NOOP("bitcoin-core", "List commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins"),
QT_TRANSLATE_NOOP("bitcoin-core", "Don't generate coins"),
QT_TRANSLATE_NOOP("bitcoin-core", "Start minimized"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Show splash screen on startup (default: 1)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify data directory"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Set database cache size in megabytes (default: 25)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Set database disk log size in megabytes (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout (in milliseconds)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect through socks4 proxy"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for addnode and connect"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on <port> (default: 8333 or testnet: 18333)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maintain at most <n> connections to peers (default: 125)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep the connection open"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect only to the specified node"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Don't accept connections from outside"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Don't bootstrap list of peers using DNS"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using internet relay chat (default: 0)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Accept connections from outside (default: 1)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Set language, for example \"de_DE\" (default: system locale)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using DNS lookup (default: 1)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Number of seconds to keep misbehaving peers from reconnecting (default: "
"86400)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Don't attempt to use UPnP to map the listening port"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to use UPnP to map the listening port"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Fee per kB to add to transactions you send"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Use Universal Plug and Play to map the listening port (default: 1)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Use Universal Plug and Play to map the listening port (default: 0)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Fee per KB to add to transactions you send"),
QT_TRANSLATE_NOOP("bitcoin-core", "Accept command line and JSON-RPC commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use the test network"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for JSON-RPC connections on <port> (default: 8332)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow JSON-RPC connections from specified IP address"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send commands to node running on <ip> (default: 127.0.0.1)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Execute command when the best block changes (%s in cmd is replaced by block "
+"hash)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Upgrade wallet to latest format"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to <n> (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions"),
+QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: 2500, 0 = all)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "How thorough the block verification is (0-6, default: 1)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"\n"
"SSL options: (see the Bitcoin Wiki for SSL setup instructions)"),
"Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:"
"@STRENGTH)"),
QT_TRANSLATE_NOOP("bitcoin-core", "This help message"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Usage"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot obtain a lock on data directory %s. Bitcoin is probably already "
"running."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading addr.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet requires newer version of Bitcoin"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart Bitcoin to complete"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Cannot initialize keypool"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write default address"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address"),
"Warning: -paytxfee is set very high. This is the transaction fee you will "
"pay if you send a transaction."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: CreateThread(StartNode) failed"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Disk space is low "),
+QT_TRANSLATE_NOOP("bitcoin-core", "To use the %s option"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Unable to bind to port %d on this computer. Bitcoin is probably already "
-"running."),
+"%s, you must set a rpcpassword in the configuration file:\n"
+" %s\n"
+"It is recommended you use the following random password:\n"
+"rpcuser=bitcoinrpc\n"
+"rpcpassword=%s\n"
+"(you do not need to remember this password)\n"
+"If the file does not exist, create it with owner-readable-only file "
+"permissions.\n"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error"),
+QT_TRANSLATE_NOOP("bitcoin-core", "An error occured while setting up the RPC port %i for listening: %s"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"You must set rpcpassword=<password> in the configuration file:\n"
+"%s\n"
+"If the file does not exist, create it with owner-readable-only file "
+"permissions."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: Please check that your computer's date and time are correct. If "
"your clock is wrong Bitcoin will not work properly."),
-QT_TRANSLATE_NOOP("bitcoin-core", "beta"),
-};
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction "),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Error: This transaction requires a transaction fee of at least %s because of "
+"its amount, complexity, or use of recently received funds "),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Transaction creation failed "),
+QT_TRANSLATE_NOOP("bitcoin-core", "Sending..."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Error: The transaction was rejected. This might happen if some of the coins "
+"in your wallet were already spent, such as if you used a copy of wallet.dat "
+"and coins were spent in the copy but not marked as spent here."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"),
+};
\ No newline at end of file
#include "addresstablemodel.h"
#include "transactiontablemodel.h"
-#include "headers.h"
+#include "main.h"
-#include <QTimer>
#include <QDateTime>
ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
QObject(parent), optionsModel(optionsModel),
cachedNumConnections(0), cachedNumBlocks(0)
{
- // Until signal notifications is built into the bitcoin core,
- // simply update everything after polling using a timer.
- QTimer *timer = new QTimer(this);
- connect(timer, SIGNAL(timeout()), this, SLOT(update()));
- timer->start(MODEL_UPDATE_DELAY);
-
numBlocksAtStartup = -1;
}
{
int newNumConnections = getNumConnections();
int newNumBlocks = getNumBlocks();
+ QString newStatusBar = getStatusBarWarnings();
if(cachedNumConnections != newNumConnections)
emit numConnectionsChanged(newNumConnections);
- if(cachedNumBlocks != newNumBlocks)
+ if(cachedNumBlocks != newNumBlocks || cachedStatusBar != newStatusBar)
+ {
+ // Simply emit a numBlocksChanged for now in case the status message changes,
+ // so that the view updates the status bar.
+ // TODO: It should send a notification.
+ // (However, this might generate looped notifications and needs to be thought through and tested carefully)
+ // error(tr("Network Alert"), newStatusBar);
emit numBlocksChanged(newNumBlocks);
+ }
cachedNumConnections = newNumConnections;
cachedNumBlocks = newNumBlocks;
+ cachedStatusBar = newStatusBar;
}
bool ClientModel::isTestNet() const
{
return QString::fromStdString(FormatFullVersion());
}
+
+QString ClientModel::formatBuildDate() const
+{
+ return QString::fromStdString(CLIENT_DATE);
+}
QString getStatusBarWarnings() const;
QString formatFullVersion() const;
+ QString formatBuildDate() const;
private:
OptionsModel *optionsModel;
int cachedNumConnections;
int cachedNumBlocks;
+ QString cachedStatusBar;
int numBlocksAtStartup;
void numBlocksChanged(int count);
//! Asynchronous error notification
- void error(const QString &title, const QString &message);
+ void error(const QString &title, const QString &message, bool modal);
public slots:
<property name="text">
<string><b>Bitcoin</b> version</string>
</property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
</widget>
</item>
<item>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
</widget>
</item>
<item>
<property name="wordWrap">
<bool>true</bool>
</property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
</widget>
</item>
<item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
- <widget class="QCheckBox" name="chkReq">
+ <widget class="QCheckBox" name="chkReqPayment">
<property name="enabled">
<bool>true</bool>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
- <widget class="QLabel" name="lblAm1">
+ <widget class="QLabel" name="lblAmount">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
</widget>
</item>
<item>
- <widget class="QLabel" name="lblAm2">
+ <widget class="QLabel" name="lblBTC">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
- <widget class="QLabel" name="label_3">
+ <widget class="QLabel" name="lblLabel">
<property name="text">
<string>Label:</string>
</property>
</widget>
</item>
<item row="1" column="0">
- <widget class="QLabel" name="label_4">
+ <widget class="QLabel" name="lblMessage">
<property name="text">
<string>Message:</string>
</property>
<resources/>
<connections>
<connection>
- <sender>chkReq</sender>
+ <sender>chkReqPayment</sender>
<signal>clicked(bool)</signal>
<receiver>lnReqAmount</receiver>
<slot>setEnabled(bool)</slot>
#include "walletmodel.h"
#include "bitcoinunits.h"
-#include "headers.h"
-
#include <QString>
#include <QDateTime>
#include <QDoubleValidator>
#include <QClipboard>
#include <QFileDialog>
#include <QDesktopServices>
+#include <QThread>
+
+namespace GUIUtil {
-QString GUIUtil::dateTimeStr(qint64 nTime)
+QString dateTimeStr(const QDateTime &date)
{
- return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
+ return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm");
}
-QString GUIUtil::dateTimeStr(const QDateTime &date)
+QString dateTimeStr(qint64 nTime)
{
- return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm");
+ return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
}
-QFont GUIUtil::bitcoinAddressFont()
+QFont bitcoinAddressFont()
{
QFont font("Monospace");
font.setStyleHint(QFont::TypeWriter);
return font;
}
-void GUIUtil::setupAddressWidget(QLineEdit *widget, QWidget *parent)
+void setupAddressWidget(QLineEdit *widget, QWidget *parent)
{
widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength);
widget->setValidator(new BitcoinAddressValidator(parent));
widget->setFont(bitcoinAddressFont());
}
-void GUIUtil::setupAmountWidget(QLineEdit *widget, QWidget *parent)
+void setupAmountWidget(QLineEdit *widget, QWidget *parent)
{
QDoubleValidator *amountValidator = new QDoubleValidator(parent);
amountValidator->setDecimals(8);
widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
}
-bool GUIUtil::parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
+bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
{
if(uri.scheme() != QString("bitcoin"))
return false;
return true;
}
-bool GUIUtil::parseBitcoinURI(QString uri, SendCoinsRecipient *out)
+bool parseBitcoinURI(QString uri, SendCoinsRecipient *out)
{
// Convert bitcoin:// to bitcoin:
//
return parseBitcoinURI(uriInstance, out);
}
-QString GUIUtil::HtmlEscape(const QString& str, bool fMultiLine)
+QString HtmlEscape(const QString& str, bool fMultiLine)
{
QString escaped = Qt::escape(str);
if(fMultiLine)
return escaped;
}
-QString GUIUtil::HtmlEscape(const std::string& str, bool fMultiLine)
+QString HtmlEscape(const std::string& str, bool fMultiLine)
{
return HtmlEscape(QString::fromStdString(str), fMultiLine);
}
-void GUIUtil::copyEntryData(QAbstractItemView *view, int column, int role)
+void copyEntryData(QAbstractItemView *view, int column, int role)
{
if(!view || !view->selectionModel())
return;
}
}
-QString GUIUtil::getSaveFileName(QWidget *parent, const QString &caption,
+QString getSaveFileName(QWidget *parent, const QString &caption,
const QString &dir,
const QString &filter,
QString *selectedSuffixOut)
return result;
}
+Qt::ConnectionType blockingGUIThreadConnection()
+{
+ if(QThread::currentThread() != QCoreApplication::instance()->thread())
+ {
+ return Qt::BlockingQueuedConnection;
+ }
+ else
+ {
+ return Qt::DirectConnection;
+ }
+}
+
+bool checkPoint(const QPoint &p, const QWidget *w)
+{
+ QWidget *atW = qApp->widgetAt(w->mapToGlobal(p));
+ if(!atW) return false;
+ return atW->topLevelWidget() == w;
+}
+
+bool isObscured(QWidget *w)
+{
+
+ return !(checkPoint(QPoint(0, 0), w)
+ && checkPoint(QPoint(w->width() - 1, 0), w)
+ && checkPoint(QPoint(0, w->height() - 1), w)
+ && checkPoint(QPoint(w->width() - 1, w->height() - 1), w)
+ && checkPoint(QPoint(w->width()/2, w->height()/2), w));
+}
+
+} // namespace GUIUtil
+
QT_END_NAMESPACE
class SendCoinsRecipient;
-/** Static utility functions used by the Bitcoin Qt UI.
+/** Utility functions used by the Bitcoin Qt UI.
*/
-class GUIUtil
+namespace GUIUtil
{
-public:
// Create human-readable string from date
- static QString dateTimeStr(qint64 nTime);
- static QString dateTimeStr(const QDateTime &datetime);
+ QString dateTimeStr(const QDateTime &datetime);
+ QString dateTimeStr(qint64 nTime);
// Render bitcoin addresses in monospace font
- static QFont bitcoinAddressFont();
+ QFont bitcoinAddressFont();
// Set up widgets for address and amounts
- static void setupAddressWidget(QLineEdit *widget, QWidget *parent);
- static void setupAmountWidget(QLineEdit *widget, QWidget *parent);
+ void setupAddressWidget(QLineEdit *widget, QWidget *parent);
+ void setupAmountWidget(QLineEdit *widget, QWidget *parent);
// Parse "bitcoin:" URI into recipient object, return true on succesful parsing
// See Bitcoin URI definition discussion here: https://bitcointalk.org/index.php?topic=33490.0
- static bool parseBitcoinURI(const QUrl &, SendCoinsRecipient *out);
- static bool parseBitcoinURI(QString uri, SendCoinsRecipient *out);
+ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out);
+ bool parseBitcoinURI(QString uri, SendCoinsRecipient *out);
// HTML escaping for rich text controls
- static QString HtmlEscape(const QString& str, bool fMultiLine=false);
- static QString HtmlEscape(const std::string& str, bool fMultiLine=false);
+ QString HtmlEscape(const QString& str, bool fMultiLine=false);
+ QString HtmlEscape(const std::string& str, bool fMultiLine=false);
/** Copy a field of the currently selected entry of a view to the clipboard. Does nothing if nothing
is selected.
@param[in] role Data role to extract from the model
@see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
*/
- static void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole);
+ void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole);
/** Get save file name, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
when no suffix is provided by the user.
@param[out] selectedSuffixOut Pointer to return the suffix (file type) that was selected (or 0).
Can be useful when choosing the save file format based on suffix.
*/
- static QString getSaveFileName(QWidget *parent=0, const QString &caption=QString(),
+ QString getSaveFileName(QWidget *parent=0, const QString &caption=QString(),
const QString &dir=QString(), const QString &filter=QString(),
QString *selectedSuffixOut=0);
-};
+ /** Get connection type to call object slot in GUI thread with invokeMethod. The call will be blocking.
+
+ @returns If called from the GUI thread, return a Qt::DirectConnection.
+ If called from another thread, return a Qt::BlockingQueuedConnection.
+ */
+ Qt::ConnectionType blockingGUIThreadConnection();
+
+ // Determine whether a widget is hidden behind other windows
+ bool isObscured(QWidget *w);
+
+} // namespace GUIUtil
#endif // GUIUTIL_H
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
-<TS version="2.0" language="en_US">
+<TS version="2.0" language="en">
<defaultcodec>UTF-8</defaultcodec>
<context>
<name>AboutDialog</name>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../forms/aboutdialog.ui" line="85"/>
+ <location filename="../forms/aboutdialog.ui" line="91"/>
<source>Copyright © 2009-2012 Bitcoin Developers
This is experimental software.
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../addressbookpage.cpp" line="61"/>
+ <location filename="../addressbookpage.cpp" line="65"/>
<source>Copy address</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../addressbookpage.cpp" line="62"/>
+ <location filename="../addressbookpage.cpp" line="66"/>
<source>Copy label</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../addressbookpage.cpp" line="63"/>
+ <location filename="../addressbookpage.cpp" line="67"/>
<source>Edit</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../addressbookpage.cpp" line="64"/>
+ <location filename="../addressbookpage.cpp" line="68"/>
<source>Delete</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../addressbookpage.cpp" line="281"/>
+ <location filename="../addressbookpage.cpp" line="288"/>
<source>Export Address Book Data</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../addressbookpage.cpp" line="282"/>
+ <location filename="../addressbookpage.cpp" line="289"/>
<source>Comma separated file (*.csv)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../addressbookpage.cpp" line="295"/>
+ <location filename="../addressbookpage.cpp" line="302"/>
<source>Error exporting</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../addressbookpage.cpp" line="295"/>
+ <location filename="../addressbookpage.cpp" line="302"/>
<source>Could not write to file %1.</source>
<translation type="unfinished"></translation>
</message>
<context>
<name>BitcoinGUI</name>
<message>
- <location filename="../bitcoingui.cpp" line="69"/>
+ <location filename="../bitcoingui.cpp" line="70"/>
<source>Bitcoin Wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="142"/>
- <location filename="../bitcoingui.cpp" line="464"/>
- <source>Synchronizing with network...</source>
+ <location filename="../bitcoingui.cpp" line="243"/>
+ <source>Show/Hide &Bitcoin</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="145"/>
- <source>Block chain synchronization in progress</source>
+ <location filename="../bitcoingui.cpp" line="499"/>
+ <source>Synchronizing with network...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="176"/>
+ <location filename="../bitcoingui.cpp" line="180"/>
<source>&Overview</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="177"/>
+ <location filename="../bitcoingui.cpp" line="181"/>
<source>Show general overview of wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="182"/>
+ <location filename="../bitcoingui.cpp" line="186"/>
<source>&Transactions</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="183"/>
+ <location filename="../bitcoingui.cpp" line="187"/>
<source>Browse transaction history</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="188"/>
+ <location filename="../bitcoingui.cpp" line="192"/>
<source>&Address Book</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="189"/>
+ <location filename="../bitcoingui.cpp" line="193"/>
<source>Edit the list of stored addresses and labels</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="194"/>
+ <location filename="../bitcoingui.cpp" line="198"/>
<source>&Receive coins</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="195"/>
+ <location filename="../bitcoingui.cpp" line="199"/>
<source>Show the list of addresses for receiving payments</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="200"/>
+ <location filename="../bitcoingui.cpp" line="204"/>
<source>&Send coins</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="201"/>
+ <location filename="../bitcoingui.cpp" line="205"/>
<source>Send coins to a bitcoin address</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="206"/>
+ <location filename="../bitcoingui.cpp" line="210"/>
<source>Sign &message</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="207"/>
+ <location filename="../bitcoingui.cpp" line="211"/>
<source>Prove you control an address</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="226"/>
+ <location filename="../bitcoingui.cpp" line="230"/>
<source>E&xit</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="227"/>
+ <location filename="../bitcoingui.cpp" line="231"/>
<source>Quit application</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="230"/>
+ <location filename="../bitcoingui.cpp" line="234"/>
<source>&About %1</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="231"/>
+ <location filename="../bitcoingui.cpp" line="235"/>
<source>Show information about Bitcoin</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="233"/>
+ <location filename="../bitcoingui.cpp" line="237"/>
<source>About &Qt</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="234"/>
+ <location filename="../bitcoingui.cpp" line="238"/>
<source>Show information about Qt</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="236"/>
+ <location filename="../bitcoingui.cpp" line="240"/>
<source>&Options...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="237"/>
+ <location filename="../bitcoingui.cpp" line="241"/>
<source>Modify configuration options for bitcoin</source>
<translation type="unfinished"></translation>
</message>
+ <message numerus="yes">
+ <location filename="../bitcoingui.cpp" line="501"/>
+ <source>~%n block(s) remaining</source>
+ <translation>
+ <numerusform>~%n block remaining</numerusform>
+ <numerusform>~%n blocks remaining</numerusform>
+ </translation>
+ </message>
<message>
- <location filename="../bitcoingui.cpp" line="239"/>
- <source>Open &Bitcoin</source>
+ <location filename="../bitcoingui.cpp" line="512"/>
+ <source>Downloaded %1 of %2 blocks of transaction history (%3% done).</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="240"/>
- <source>Show the Bitcoin window</source>
+ <location filename="../bitcoingui.cpp" line="245"/>
+ <source>&Export...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="241"/>
- <source>&Export...</source>
+ <location filename="../bitcoingui.cpp" line="244"/>
+ <source>Show or hide the Bitcoin window</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="242"/>
+ <location filename="../bitcoingui.cpp" line="246"/>
<source>Export the data in the current tab to a file</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="243"/>
+ <location filename="../bitcoingui.cpp" line="247"/>
<source>&Encrypt Wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="244"/>
+ <location filename="../bitcoingui.cpp" line="248"/>
<source>Encrypt or decrypt wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="246"/>
+ <location filename="../bitcoingui.cpp" line="250"/>
<source>&Backup Wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="247"/>
+ <location filename="../bitcoingui.cpp" line="251"/>
<source>Backup wallet to another location</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="248"/>
+ <location filename="../bitcoingui.cpp" line="252"/>
<source>&Change Passphrase</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="249"/>
+ <location filename="../bitcoingui.cpp" line="253"/>
<source>Change the passphrase used for wallet encryption</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="272"/>
+ <location filename="../bitcoingui.cpp" line="276"/>
<source>&File</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="281"/>
+ <location filename="../bitcoingui.cpp" line="285"/>
<source>&Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="287"/>
+ <location filename="../bitcoingui.cpp" line="291"/>
<source>&Help</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="294"/>
+ <location filename="../bitcoingui.cpp" line="298"/>
<source>Tabs toolbar</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="305"/>
+ <location filename="../bitcoingui.cpp" line="309"/>
<source>Actions toolbar</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="317"/>
+ <location filename="../bitcoingui.cpp" line="321"/>
<source>[testnet]</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="407"/>
+ <location filename="../bitcoingui.cpp" line="383"/>
+ <source>Bitcoin client</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoingui.cpp" line="411"/>
<source>bitcoin-qt</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location filename="../bitcoingui.cpp" line="449"/>
+ <location filename="../bitcoingui.cpp" line="475"/>
<source>%n active connection(s) to Bitcoin network</source>
- <translation type="unfinished">
+ <translation>
<numerusform>%n active connection to Bitcoin network</numerusform>
<numerusform>%n active connections to Bitcoin network</numerusform>
</translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="475"/>
- <source>Downloaded %1 of %2 blocks of transaction history.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../bitcoingui.cpp" line="487"/>
+ <location filename="../bitcoingui.cpp" line="524"/>
<source>Downloaded %1 blocks of transaction history.</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location filename="../bitcoingui.cpp" line="502"/>
+ <location filename="../bitcoingui.cpp" line="539"/>
<source>%n second(s) ago</source>
- <translation type="unfinished">
+ <translation>
<numerusform>%n second ago</numerusform>
<numerusform>%n seconds ago</numerusform>
</translation>
</message>
<message numerus="yes">
- <location filename="../bitcoingui.cpp" line="506"/>
+ <location filename="../bitcoingui.cpp" line="543"/>
<source>%n minute(s) ago</source>
- <translation type="unfinished">
+ <translation>
<numerusform>%n minute ago</numerusform>
<numerusform>%n minutes ago</numerusform>
</translation>
</message>
<message numerus="yes">
- <location filename="../bitcoingui.cpp" line="510"/>
+ <location filename="../bitcoingui.cpp" line="547"/>
<source>%n hour(s) ago</source>
- <translation type="unfinished">
+ <translation>
<numerusform>%n hour ago</numerusform>
<numerusform>%n hours ago</numerusform>
</translation>
</message>
<message numerus="yes">
- <location filename="../bitcoingui.cpp" line="514"/>
+ <location filename="../bitcoingui.cpp" line="551"/>
<source>%n day(s) ago</source>
- <translation type="unfinished">
+ <translation>
<numerusform>%n day ago</numerusform>
<numerusform>%n days ago</numerusform>
</translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="520"/>
+ <location filename="../bitcoingui.cpp" line="557"/>
<source>Up to date</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="525"/>
+ <location filename="../bitcoingui.cpp" line="562"/>
<source>Catching up...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="533"/>
+ <location filename="../bitcoingui.cpp" line="570"/>
<source>Last received block was generated %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="597"/>
+ <location filename="../bitcoingui.cpp" line="626"/>
<source>This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="602"/>
+ <location filename="../bitcoingui.cpp" line="631"/>
<source>Sending...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="629"/>
+ <location filename="../bitcoingui.cpp" line="658"/>
<source>Sent transaction</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="630"/>
+ <location filename="../bitcoingui.cpp" line="659"/>
<source>Incoming transaction</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="631"/>
+ <location filename="../bitcoingui.cpp" line="660"/>
<source>Date: %1
Amount: %2
Type: %3
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="751"/>
+ <location filename="../bitcoingui.cpp" line="785"/>
<source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="759"/>
+ <location filename="../bitcoingui.cpp" line="793"/>
<source>Wallet is <b>encrypted</b> and currently <b>locked</b></source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="782"/>
+ <location filename="../bitcoingui.cpp" line="816"/>
<source>Backup Wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="782"/>
+ <location filename="../bitcoingui.cpp" line="816"/>
<source>Wallet Data (*.dat)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="785"/>
+ <location filename="../bitcoingui.cpp" line="819"/>
<source>Backup Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoingui.cpp" line="785"/>
+ <location filename="../bitcoingui.cpp" line="819"/>
<source>There was an error trying to save the wallet data to the new location.</source>
<translation type="unfinished"></translation>
</message>
<context>
<name>DisplayOptionsPage</name>
<message>
- <location filename="../optionsdialog.cpp" line="270"/>
+ <location filename="../optionsdialog.cpp" line="268"/>
<source>&Unit to show amounts in: </source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="274"/>
+ <location filename="../optionsdialog.cpp" line="272"/>
<source>Choose the default subdivision unit to show in the interface, and when sending coins</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="281"/>
+ <location filename="../optionsdialog.cpp" line="279"/>
<source>Display addresses in transaction list</source>
<translation type="unfinished"></translation>
</message>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="180"/>
+ <location filename="../optionsdialog.cpp" line="184"/>
<source>Map port using &UPnP</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="181"/>
+ <location filename="../optionsdialog.cpp" line="185"/>
<source>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="185"/>
+ <location filename="../optionsdialog.cpp" line="179"/>
<source>M&inimize on close</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="186"/>
+ <location filename="../optionsdialog.cpp" line="180"/>
<source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="190"/>
+ <location filename="../optionsdialog.cpp" line="188"/>
<source>&Connect through SOCKS4 proxy:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="191"/>
+ <location filename="../optionsdialog.cpp" line="189"/>
<source>Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="196"/>
+ <location filename="../optionsdialog.cpp" line="194"/>
<source>Proxy &IP: </source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="202"/>
+ <location filename="../optionsdialog.cpp" line="200"/>
<source>IP address of the proxy (e.g. 127.0.0.1)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="205"/>
+ <location filename="../optionsdialog.cpp" line="203"/>
<source>&Port: </source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="211"/>
+ <location filename="../optionsdialog.cpp" line="209"/>
<source>Port of the proxy (e.g. 1234)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="217"/>
+ <location filename="../optionsdialog.cpp" line="215"/>
<source>Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="223"/>
+ <location filename="../optionsdialog.cpp" line="221"/>
<source>Pay transaction &fee</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="226"/>
+ <location filename="../optionsdialog.cpp" line="224"/>
<source>Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended.</source>
<translation type="unfinished"></translation>
</message>
</message>
<message>
<location filename="../forms/messagepage.ui" line="38"/>
- <source>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source>
+ <source>The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source>
<translation type="unfinished"></translation>
</message>
<message>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../forms/qrcodedialog.ui" line="52"/>
+ <location filename="../forms/qrcodedialog.ui" line="55"/>
<source>Request Payment</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../forms/qrcodedialog.ui" line="67"/>
+ <location filename="../forms/qrcodedialog.ui" line="70"/>
<source>Amount:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../forms/qrcodedialog.ui" line="102"/>
+ <location filename="../forms/qrcodedialog.ui" line="105"/>
<source>BTC</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../forms/qrcodedialog.ui" line="118"/>
+ <location filename="../forms/qrcodedialog.ui" line="121"/>
<source>Label:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../forms/qrcodedialog.ui" line="141"/>
+ <location filename="../forms/qrcodedialog.ui" line="144"/>
<source>Message:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../forms/qrcodedialog.ui" line="183"/>
+ <location filename="../forms/qrcodedialog.ui" line="186"/>
<source>&Save As...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../qrcodedialog.cpp" line="101"/>
+ <location filename="../qrcodedialog.cpp" line="59"/>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../qrcodedialog.cpp" line="116"/>
<source>Save Image...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../qrcodedialog.cpp" line="101"/>
+ <location filename="../qrcodedialog.cpp" line="116"/>
<source>PNG Images (*.png)</source>
<translation type="unfinished"></translation>
</message>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="47"/>
+ <location filename="../transactiondesc.cpp" line="48"/>
<source><b>Status:</b> </source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="52"/>
+ <location filename="../transactiondesc.cpp" line="53"/>
<source>, has not been successfully broadcast yet</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="54"/>
+ <location filename="../transactiondesc.cpp" line="55"/>
<source>, broadcast through %1 node</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="56"/>
+ <location filename="../transactiondesc.cpp" line="57"/>
<source>, broadcast through %1 nodes</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="60"/>
+ <location filename="../transactiondesc.cpp" line="61"/>
<source><b>Date:</b> </source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="67"/>
+ <location filename="../transactiondesc.cpp" line="68"/>
<source><b>Source:</b> Generated<br></source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="73"/>
- <location filename="../transactiondesc.cpp" line="90"/>
+ <location filename="../transactiondesc.cpp" line="74"/>
+ <location filename="../transactiondesc.cpp" line="91"/>
<source><b>From:</b> </source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="90"/>
+ <location filename="../transactiondesc.cpp" line="91"/>
<source>unknown</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="91"/>
- <location filename="../transactiondesc.cpp" line="114"/>
- <location filename="../transactiondesc.cpp" line="173"/>
+ <location filename="../transactiondesc.cpp" line="92"/>
+ <location filename="../transactiondesc.cpp" line="115"/>
+ <location filename="../transactiondesc.cpp" line="174"/>
<source><b>To:</b> </source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="94"/>
+ <location filename="../transactiondesc.cpp" line="95"/>
<source> (yours, label: </source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="96"/>
+ <location filename="../transactiondesc.cpp" line="97"/>
<source> (yours)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="131"/>
- <location filename="../transactiondesc.cpp" line="145"/>
- <location filename="../transactiondesc.cpp" line="190"/>
- <location filename="../transactiondesc.cpp" line="207"/>
+ <location filename="../transactiondesc.cpp" line="132"/>
+ <location filename="../transactiondesc.cpp" line="146"/>
+ <location filename="../transactiondesc.cpp" line="191"/>
+ <location filename="../transactiondesc.cpp" line="208"/>
<source><b>Credit:</b> </source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="133"/>
+ <location filename="../transactiondesc.cpp" line="134"/>
<source>(%1 matures in %2 more blocks)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="137"/>
+ <location filename="../transactiondesc.cpp" line="138"/>
<source>(not accepted)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="181"/>
- <location filename="../transactiondesc.cpp" line="189"/>
- <location filename="../transactiondesc.cpp" line="204"/>
+ <location filename="../transactiondesc.cpp" line="182"/>
+ <location filename="../transactiondesc.cpp" line="190"/>
+ <location filename="../transactiondesc.cpp" line="205"/>
<source><b>Debit:</b> </source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="195"/>
+ <location filename="../transactiondesc.cpp" line="196"/>
<source><b>Transaction fee:</b> </source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="211"/>
+ <location filename="../transactiondesc.cpp" line="212"/>
<source><b>Net amount:</b> </source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="217"/>
+ <location filename="../transactiondesc.cpp" line="218"/>
<source>Message:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="219"/>
+ <location filename="../transactiondesc.cpp" line="220"/>
<source>Comment:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="221"/>
+ <location filename="../transactiondesc.cpp" line="222"/>
<source>Transaction ID:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiondesc.cpp" line="224"/>
+ <location filename="../transactiondesc.cpp" line="225"/>
<source>Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location filename="../transactiontablemodel.cpp" line="274"/>
<source>Open for %n block(s)</source>
- <translation type="unfinished">
+ <translation>
<numerusform>Open for %n block</numerusform>
<numerusform>Open for %n blocks</numerusform>
</translation>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location filename="../transactiontablemodel.cpp" line="295"/>
+ <location filename="../transactiontablemodel.cpp" line="294"/>
<source>Mined balance will be available in %n more blocks</source>
- <translation type="unfinished">
+ <translation>
<numerusform>Mined balance will be available in %n more block</numerusform>
<numerusform>Mined balance will be available in %n more blocks</numerusform>
</translation>
</message>
<message>
- <location filename="../transactiontablemodel.cpp" line="301"/>
+ <location filename="../transactiontablemodel.cpp" line="300"/>
<source>This block was not received by any other nodes and will probably not be accepted!</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiontablemodel.cpp" line="304"/>
+ <location filename="../transactiontablemodel.cpp" line="303"/>
<source>Generated but not accepted</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiontablemodel.cpp" line="347"/>
+ <location filename="../transactiontablemodel.cpp" line="346"/>
<source>Received with</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiontablemodel.cpp" line="349"/>
+ <location filename="../transactiontablemodel.cpp" line="348"/>
<source>Received from</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiontablemodel.cpp" line="352"/>
+ <location filename="../transactiontablemodel.cpp" line="351"/>
<source>Sent to</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiontablemodel.cpp" line="354"/>
+ <location filename="../transactiontablemodel.cpp" line="353"/>
<source>Payment to yourself</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiontablemodel.cpp" line="356"/>
+ <location filename="../transactiontablemodel.cpp" line="355"/>
<source>Mined</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiontablemodel.cpp" line="394"/>
+ <location filename="../transactiontablemodel.cpp" line="393"/>
<source>(n/a)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiontablemodel.cpp" line="593"/>
+ <location filename="../transactiontablemodel.cpp" line="592"/>
<source>Transaction status. Hover over this field to show number of confirmations.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiontablemodel.cpp" line="595"/>
+ <location filename="../transactiontablemodel.cpp" line="594"/>
<source>Date and time that the transaction was received.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiontablemodel.cpp" line="597"/>
+ <location filename="../transactiontablemodel.cpp" line="596"/>
<source>Type of transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiontablemodel.cpp" line="599"/>
+ <location filename="../transactiontablemodel.cpp" line="598"/>
<source>Destination address of transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../transactiontablemodel.cpp" line="601"/>
+ <location filename="../transactiontablemodel.cpp" line="600"/>
<source>Amount removed from or added to balance.</source>
<translation type="unfinished"></translation>
</message>
<context>
<name>WalletModel</name>
<message>
- <location filename="../walletmodel.cpp" line="145"/>
+ <location filename="../walletmodel.cpp" line="143"/>
<source>Sending...</source>
<translation type="unfinished"></translation>
</message>
<context>
<name>bitcoin-core</name>
<message>
- <location filename="../bitcoinstrings.cpp" line="3"/>
- <source>Bitcoin version</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../bitcoinstrings.cpp" line="4"/>
- <source>Usage:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../bitcoinstrings.cpp" line="5"/>
- <source>Send command to -server or bitcoind</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../bitcoinstrings.cpp" line="6"/>
- <source>List commands</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<location filename="../bitcoinstrings.cpp" line="7"/>
- <source>Get help for a command</source>
+ <source>Bitcoin version</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="8"/>
- <source>Options:</source>
+ <source>Usage:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="9"/>
- <source>Specify configuration file (default: bitcoin.conf)</source>
+ <source>Send command to -server or bitcoind</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="10"/>
- <source>Specify pid file (default: bitcoind.pid)</source>
+ <source>List commands</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="11"/>
- <source>Generate coins</source>
+ <source>Get help for a command</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="12"/>
- <source>Don't generate coins</source>
+ <source>Options:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="13"/>
- <source>Start minimized</source>
+ <source>Specify configuration file (default: bitcoin.conf)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="14"/>
- <source>Specify data directory</source>
+ <source>Specify pid file (default: bitcoind.pid)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="15"/>
- <source>Specify connection timeout (in milliseconds)</source>
+ <source>Generate coins</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="16"/>
- <source>Connect through socks4 proxy</source>
+ <source>Don't generate coins</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="17"/>
- <source>Allow DNS lookups for addnode and connect</source>
+ <source>Start minimized</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="18"/>
- <source>Listen for connections on <port> (default: 8333 or testnet: 18333)</source>
+ <source>Show splash screen on startup (default: 1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="19"/>
- <source>Maintain at most <n> connections to peers (default: 125)</source>
+ <source>Specify data directory</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="20"/>
- <source>Add a node to connect to</source>
+ <source>Set database cache size in megabytes (default: 25)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="21"/>
- <source>Connect only to the specified node</source>
+ <source>Set database disk log size in megabytes (default: 100)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="22"/>
- <source>Don't accept connections from outside</source>
+ <source>Specify connection timeout (in milliseconds)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="23"/>
- <source>Don't bootstrap list of peers using DNS</source>
+ <source>Connect through socks4 proxy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="24"/>
- <source>Threshold for disconnecting misbehaving peers (default: 100)</source>
+ <source>Allow DNS lookups for addnode and connect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="25"/>
- <source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source>
+ <source>Listen for connections on <port> (default: 8333 or testnet: 18333)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="26"/>
+ <source>Maintain at most <n> connections to peers (default: 125)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoinstrings.cpp" line="28"/>
- <source>Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)</source>
+ <source>Connect only to the specified node</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="29"/>
- <source>Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)</source>
+ <location filename="../bitcoinstrings.cpp" line="33"/>
+ <source>Threshold for disconnecting misbehaving peers (default: 100)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="30"/>
- <source>Don't attempt to use UPnP to map the listening port</source>
+ <location filename="../bitcoinstrings.cpp" line="34"/>
+ <source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="31"/>
- <source>Attempt to use UPnP to map the listening port</source>
+ <location filename="../bitcoinstrings.cpp" line="37"/>
+ <source>Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="32"/>
- <source>Fee per kB to add to transactions you send</source>
+ <location filename="../bitcoinstrings.cpp" line="38"/>
+ <source>Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="33"/>
+ <location filename="../bitcoinstrings.cpp" line="42"/>
<source>Accept command line and JSON-RPC commands</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="34"/>
+ <location filename="../bitcoinstrings.cpp" line="43"/>
<source>Run in the background as a daemon and accept commands</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="35"/>
+ <location filename="../bitcoinstrings.cpp" line="44"/>
<source>Use the test network</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="36"/>
+ <location filename="../bitcoinstrings.cpp" line="45"/>
<source>Output extra debugging information</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="37"/>
+ <location filename="../bitcoinstrings.cpp" line="46"/>
<source>Prepend debug output with timestamp</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="38"/>
+ <location filename="../bitcoinstrings.cpp" line="47"/>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="39"/>
+ <location filename="../bitcoinstrings.cpp" line="48"/>
<source>Send trace/debug info to debugger</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="40"/>
+ <location filename="../bitcoinstrings.cpp" line="49"/>
<source>Username for JSON-RPC connections</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="41"/>
+ <location filename="../bitcoinstrings.cpp" line="50"/>
<source>Password for JSON-RPC connections</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="42"/>
+ <location filename="../bitcoinstrings.cpp" line="51"/>
<source>Listen for JSON-RPC connections on <port> (default: 8332)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="43"/>
+ <location filename="../bitcoinstrings.cpp" line="52"/>
<source>Allow JSON-RPC connections from specified IP address</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="44"/>
+ <location filename="../bitcoinstrings.cpp" line="53"/>
<source>Send commands to node running on <ip> (default: 127.0.0.1)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="45"/>
+ <location filename="../bitcoinstrings.cpp" line="54"/>
+ <source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="57"/>
+ <source>Upgrade wallet to latest format</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="58"/>
<source>Set key pool size to <n> (default: 100)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="46"/>
+ <location filename="../bitcoinstrings.cpp" line="59"/>
<source>Rescan the block chain for missing wallet transactions</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="47"/>
+ <location filename="../bitcoinstrings.cpp" line="60"/>
+ <source>How many blocks to check at startup (default: 2500, 0 = all)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="61"/>
+ <source>How thorough the block verification is (0-6, default: 1)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="62"/>
<source>
SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="50"/>
+ <location filename="../bitcoinstrings.cpp" line="65"/>
<source>Use OpenSSL (https) for JSON-RPC connections</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="51"/>
+ <location filename="../bitcoinstrings.cpp" line="66"/>
<source>Server certificate file (default: server.cert)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="52"/>
+ <location filename="../bitcoinstrings.cpp" line="67"/>
<source>Server private key (default: server.pem)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="53"/>
+ <location filename="../bitcoinstrings.cpp" line="68"/>
<source>Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="56"/>
+ <location filename="../bitcoinstrings.cpp" line="71"/>
<source>This help message</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="57"/>
+ <location filename="../bitcoinstrings.cpp" line="72"/>
+ <source>Usage</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="73"/>
<source>Cannot obtain a lock on data directory %s. Bitcoin is probably already running.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="60"/>
+ <location filename="../bitcoinstrings.cpp" line="76"/>
+ <source>Bitcoin</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="77"/>
<source>Loading addresses...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="61"/>
+ <location filename="../bitcoinstrings.cpp" line="78"/>
<source>Error loading addr.dat</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="63"/>
+ <location filename="../bitcoinstrings.cpp" line="80"/>
<source>Error loading blkindex.dat</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="65"/>
+ <location filename="../bitcoinstrings.cpp" line="82"/>
<source>Error loading wallet.dat: Wallet corrupted</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="66"/>
+ <location filename="../bitcoinstrings.cpp" line="83"/>
<source>Error loading wallet.dat: Wallet requires newer version of Bitcoin</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="67"/>
+ <location filename="../bitcoinstrings.cpp" line="84"/>
<source>Wallet needed to be rewritten: restart Bitcoin to complete</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="68"/>
+ <location filename="../bitcoinstrings.cpp" line="85"/>
<source>Error loading wallet.dat</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="62"/>
+ <location filename="../bitcoinstrings.cpp" line="117"/>
+ <source>Error: Wallet locked, unable to create transaction </source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="118"/>
+ <source>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds </source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="121"/>
+ <source>Error: Transaction creation failed </source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="122"/>
+ <source>Sending...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="123"/>
+ <source>Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="127"/>
+ <source>Invalid amount</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="128"/>
+ <source>Insufficient funds</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="79"/>
<source>Loading block index...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="64"/>
+ <location filename="../bitcoinstrings.cpp" line="27"/>
+ <source>Add a node to connect to and attempt to keep the connection open</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="29"/>
+ <source>Find peers using internet relay chat (default: 0)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="30"/>
+ <source>Accept connections from outside (default: 1)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="31"/>
+ <source>Set language, for example "de_DE" (default: system locale)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="32"/>
+ <source>Find peers using DNS lookup (default: 1)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="39"/>
+ <source>Use Universal Plug and Play to map the listening port (default: 1)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="40"/>
+ <source>Use Universal Plug and Play to map the listening port (default: 0)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="41"/>
+ <source>Fee per KB to add to transactions you send</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="81"/>
<source>Loading wallet...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="69"/>
+ <location filename="../bitcoinstrings.cpp" line="86"/>
+ <source>Cannot downgrade wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="87"/>
+ <source>Cannot initialize keypool</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="88"/>
+ <source>Cannot write default address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="89"/>
<source>Rescanning...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="70"/>
+ <location filename="../bitcoinstrings.cpp" line="90"/>
<source>Done loading</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="71"/>
+ <location filename="../bitcoinstrings.cpp" line="91"/>
<source>Invalid -proxy address</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="72"/>
+ <location filename="../bitcoinstrings.cpp" line="92"/>
<source>Invalid amount for -paytxfee=<amount></source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="73"/>
+ <location filename="../bitcoinstrings.cpp" line="93"/>
<source>Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="76"/>
+ <location filename="../bitcoinstrings.cpp" line="96"/>
<source>Error: CreateThread(StartNode) failed</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="77"/>
+ <location filename="../bitcoinstrings.cpp" line="6"/>
<source>Warning: Disk space is low </source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="78"/>
+ <location filename="../bitcoinstrings.cpp" line="3"/>
<source>Unable to bind to port %d on this computer. Bitcoin is probably already running.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="81"/>
- <source>Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly.</source>
+ <location filename="../bitcoinstrings.cpp" line="97"/>
+ <source>To use the %s option</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoinstrings.cpp" line="84"/>
- <source>beta</source>
+ <location filename="../bitcoinstrings.cpp" line="98"/>
+ <source>%s, you must set a rpcpassword in the configuration file:
+ %s
+It is recommended you use the following random password:
+rpcuser=bitcoinrpc
+rpcpassword=%s
+(you do not need to remember this password)
+If the file does not exist, create it with owner-readable-only file permissions.
+</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="107"/>
+ <source>Error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="108"/>
+ <source>An error occured while setting up the RPC port %i for listening: %s</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="109"/>
+ <source>You must set rpcpassword=<password> in the configuration file:
+%s
+If the file does not exist, create it with owner-readable-only file permissions.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../bitcoinstrings.cpp" line="114"/>
+ <source>Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly.</source>
<translation type="unfinished"></translation>
</message>
</context>
return;
}
- CDataStream ss(SER_GETHASH);
+ CDataStream ss(SER_GETHASH, 0);
ss << strMessageMagic;
ss << ui->message->document()->toPlainText().toStdString();
QCheckBox *minimize_on_close;
#endif
QCheckBox *connect_socks4;
+ QCheckBox *detach_database;
QLineEdit *proxy_ip;
QLineEdit *proxy_port;
BitcoinAmountField *fee_edit;
minimize_to_tray = new QCheckBox(tr("&Minimize to the tray instead of the taskbar"));
minimize_to_tray->setToolTip(tr("Show only a tray icon after minimizing the window"));
layout->addWidget(minimize_to_tray);
-#endif
-
- map_port_upnp = new QCheckBox(tr("Map port using &UPnP"));
- map_port_upnp->setToolTip(tr("Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled."));
- layout->addWidget(map_port_upnp);
-#ifndef Q_WS_MAC
minimize_on_close = new QCheckBox(tr("M&inimize on close"));
minimize_on_close->setToolTip(tr("Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu."));
layout->addWidget(minimize_on_close);
#endif
+ map_port_upnp = new QCheckBox(tr("Map port using &UPnP"));
+ map_port_upnp->setToolTip(tr("Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled."));
+ layout->addWidget(map_port_upnp);
+
connect_socks4 = new QCheckBox(tr("&Connect through SOCKS4 proxy:"));
connect_socks4->setToolTip(tr("Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor)"));
layout->addWidget(connect_socks4);
layout->addLayout(fee_hbox);
+ detach_database = new QCheckBox(tr("Detach databases at shutdown"));
+ detach_database->setToolTip(tr("Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached."));
+ layout->addWidget(detach_database);
+
layout->addStretch(1); // Extra space at bottom
setLayout(layout);
mapper->addMapping(proxy_ip, OptionsModel::ProxyIP);
mapper->addMapping(proxy_port, OptionsModel::ProxyPort);
mapper->addMapping(fee_edit, OptionsModel::Fee);
+ mapper->addMapping(detach_database, OptionsModel::DetachDatabases);
}
DisplayOptionsPage::DisplayOptionsPage(QWidget *parent):
#include "bitcoinunits.h"
#include <QSettings>
-#include "headers.h"
#include "init.h"
+#include "walletdb.h"
OptionsModel::OptionsModel(QObject *parent) :
QAbstractListModel(parent)
SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool());
if (settings.contains("addrProxy") && settings.value("fUseProxy").toBool())
SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString());
+ if (settings.contains("detachDB"))
+ SoftSetBoolArg("-detachdb", settings.value("detachDB").toBool());
}
bool OptionsModel::Upgrade()
return QVariant(nDisplayUnit);
case DisplayAddresses:
return QVariant(bDisplayAddresses);
+ case DetachDatabases:
+ return QVariant(fDetachDB);
default:
return QVariant();
}
settings.setValue("bDisplayAddresses", bDisplayAddresses);
}
break;
+ case DetachDatabases: {
+ fDetachDB = value.toBool();
+ settings.setValue("detachDB", fDetachDB);
+ }
+ break;
default:
break;
}
Fee, // qint64
DisplayUnit, // BitcoinUnits::Unit
DisplayAddresses, // bool
- OptionIDRowCount
+ DetachDatabases, // bool
+ OptionIDRowCount,
};
void Init();
#include <qrencode.h>
-#define EXPORT_IMAGE_SIZE 256
+#define EXPORT_IMAGE_SIZE 256
-QRCodeDialog::QRCodeDialog(const QString &title, const QString &addr, const QString &label, bool enableReq, QWidget *parent) :
- QDialog(parent),
- ui(new Ui::QRCodeDialog),
- address(addr)
+QRCodeDialog::QRCodeDialog(const QString &addr, const QString &label, bool enableReq, QWidget *parent) :
+ QDialog(parent), ui(new Ui::QRCodeDialog), address(addr)
{
ui->setupUi(this);
- setWindowTitle(title);
+ setWindowTitle(QString("%1").arg(address));
setAttribute(Qt::WA_DeleteOnClose);
- ui->chkReq->setVisible(enableReq);
+ ui->chkReqPayment->setVisible(enableReq);
ui->lnReqAmount->setVisible(enableReq);
- ui->lblAm1->setVisible(enableReq);
- ui->lblAm2->setVisible(enableReq);
+ ui->lblAmount->setVisible(enableReq);
+ ui->lblBTC->setVisible(enableReq);
ui->lnLabel->setText(label);
void QRCodeDialog::genCode()
{
QString uri = getURI();
- //qDebug() << "Encoding:" << uri.toUtf8().constData();
+ if (uri != "")
{
ui->lblQRCode->setText("");
QRcode_free(code);
ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300));
}
+ else
+ ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message."));
}
QString QRCodeDialog::getURI()
QString ret = QString("bitcoin:%1").arg(address);
int paramCount = 0;
- if(ui->chkReq->isChecked() && ui->lnReqAmount->text().isEmpty() == false) {
- bool ok= false;
- double amount = ui->lnReqAmount->text().toDouble(&ok);
- if(ok) {
- ret += QString("?amount=%1X8").arg(ui->lnReqAmount->text());
+ if (ui->chkReqPayment->isChecked() && !ui->lnReqAmount->text().isEmpty())
+ {
+ bool ok = false;
+ ui->lnReqAmount->text().toDouble(&ok);
+ if (ok)
+ {
+ ret += QString("?amount=%1").arg(ui->lnReqAmount->text());
paramCount++;
}
}
- if(ui->lnLabel->text().isEmpty() == false) {
+ if (!ui->lnLabel->text().isEmpty())
+ {
QString lbl(QUrl::toPercentEncoding(ui->lnLabel->text()));
ret += QString("%1label=%2").arg(paramCount == 0 ? "?" : "&").arg(lbl);
paramCount++;
}
- if(ui->lnMessage->text().isEmpty() == false) {
+ if (!ui->lnMessage->text().isEmpty())
+ {
QString msg(QUrl::toPercentEncoding(ui->lnMessage->text()));
ret += QString("%1message=%2").arg(paramCount == 0 ? "?" : "&").arg(msg);
paramCount++;
}
- return ret;
+ // limit URI length to 255 chars, to prevent a DoS against the QR-Code dialog
+ if (ret.length() < 256)
+ return ret;
+ else
+ return QString("");
}
-void QRCodeDialog::on_lnReqAmount_textChanged(const QString &)
+void QRCodeDialog::on_lnReqAmount_textChanged(const QString &arg1)
{
genCode();
}
-void QRCodeDialog::on_lnLabel_textChanged(const QString &)
+void QRCodeDialog::on_lnLabel_textChanged(const QString &arg1)
{
genCode();
}
-void QRCodeDialog::on_lnMessage_textChanged(const QString &)
+void QRCodeDialog::on_lnMessage_textChanged(const QString &arg1)
{
genCode();
}
void QRCodeDialog::on_btnSaveAs_clicked()
{
QString fn = GUIUtil::getSaveFileName(this, tr("Save Image..."), QString(), tr("PNG Images (*.png)"));
- if(!fn.isEmpty()) {
+ if (!fn.isEmpty())
myImage.scaled(EXPORT_IMAGE_SIZE, EXPORT_IMAGE_SIZE).save(fn);
- }
}
-void QRCodeDialog::on_chkReq_toggled(bool)
+void QRCodeDialog::on_chkReqPayment_toggled(bool)
{
genCode();
}
Q_OBJECT
public:
- explicit QRCodeDialog(const QString &title, const QString &address, const QString &label, bool allowReq, QWidget *parent = 0);
+ explicit QRCodeDialog(const QString &addr, const QString &label, bool enableReq, QWidget *parent = 0);
~QRCodeDialog();
private slots:
void on_lnMessage_textChanged(const QString &arg1);
void on_btnSaveAs_clicked();
- void on_chkReq_toggled(bool checked);
+ void on_chkReqPayment_toggled(bool checked);
private:
Ui::QRCodeDialog *ui;
#include <boost/tokenizer.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
-#include "headers.h"
+#include "ui_interface.h"
+#include "util.h"
#include "qtipcserver.h"
using namespace boost::interprocess;
-#include <transactiondesc.h>
+#include "transactiondesc.h"
#include "guiutil.h"
#include "bitcoinunits.h"
-#include "headers.h"
-#include "qtui.h"
+#include "main.h"
+#include "wallet.h"
+#include "db.h"
+#include "ui_interface.h"
#include <QString>
QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
{
QString strHTML;
- CRITICAL_BLOCK(wallet->cs_wallet)
+
{
+ LOCK(wallet->cs_wallet);
strHTML.reserve(4000);
strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
strHTML += "<br><b>Inputs:</b>";
strHTML += "<ul>";
- CRITICAL_BLOCK(wallet->cs_wallet)
+
{
+ LOCK(wallet->cs_wallet);
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
{
COutPoint prevout = txin.prevout;
#include "transactionrecord.h"
-#include "headers.h"
+#include "wallet.h"
/* Return positive answer if transaction should be shown in list.
*/
QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx)
{
QList<TransactionRecord> parts;
- int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
+ int64 nTime = wtx.GetTxTime();
int64 nCredit = wtx.GetCredit(true);
int64 nDebit = wtx.GetDebit();
int64 nNet = nCredit - nDebit;
//
// Mixed debit transaction, can't break down payees
//
- bool fAllMine = true;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- fAllMine = fAllMine && wallet->IsMine(txout);
- BOOST_FOREACH(const CTxIn& txin, wtx.vin)
- fAllMine = fAllMine && wallet->IsMine(txin);
-
parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
}
}
#include "addresstablemodel.h"
#include "bitcoinunits.h"
-#include "headers.h"
+#include "wallet.h"
#include <QLocale>
#include <QList>
qDebug() << "refreshWallet";
#endif
cachedWallet.clear();
- CRITICAL_BLOCK(wallet->cs_wallet)
{
+ LOCK(wallet->cs_wallet);
for(std::map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it)
{
cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second));
QList<uint256> updated_sorted = updated;
qSort(updated_sorted);
- CRITICAL_BLOCK(wallet->cs_wallet)
{
+ LOCK(wallet->cs_wallet);
for(int update_idx = updated_sorted.size()-1; update_idx >= 0; --update_idx)
{
const uint256 &hash = updated_sorted.at(update_idx);
// simply re-use the cached status.
if(rec->statusUpdateNeeded())
{
- CRITICAL_BLOCK(wallet->cs_wallet)
{
+ LOCK(wallet->cs_wallet);
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
if(mi != wallet->mapWallet.end())
QString describe(TransactionRecord *rec)
{
- CRITICAL_BLOCK(wallet->cs_wallet)
{
+ LOCK(wallet->cs_wallet);
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
if(mi != wallet->mapWallet.end())
{
QList<uint256> updated;
// Check if there are changes to wallet map
- TRY_CRITICAL_BLOCK(wallet->cs_wallet)
{
- if(!wallet->vWalletUpdated.empty())
+ TRY_LOCK(wallet->cs_wallet, lockWallet);
+ if (lockWallet && !wallet->vWalletUpdated.empty())
{
BOOST_FOREACH(uint256 hash, wallet->vWalletUpdated)
{
#include "addresstablemodel.h"
#include "transactiontablemodel.h"
-#include "headers.h"
-#include "db.h" // for BackupWallet
+#include "ui_interface.h"
+#include "wallet.h"
+#include "walletdb.h" // for BackupWallet
-#include <QTimer>
#include <QSet>
WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
cachedBalance(0), cachedUnconfirmedBalance(0), cachedNumTransactions(0),
cachedEncryptionStatus(Unencrypted)
{
- // Until signal notifications is built into the bitcoin core,
- // simply update everything after polling using a timer.
- QTimer *timer = new QTimer(this);
- connect(timer, SIGNAL(timeout()), this, SLOT(update()));
- timer->start(MODEL_UPDATE_DELAY);
-
addressTableModel = new AddressTableModel(wallet, this);
transactionTableModel = new TransactionTableModel(wallet, this);
}
int WalletModel::getNumTransactions() const
{
int numTransactions = 0;
- CRITICAL_BLOCK(wallet->cs_wallet)
{
+ LOCK(wallet->cs_wallet);
numTransactions = wallet->mapWallet.size();
}
return numTransactions;
cachedBalance = newBalance;
cachedUnconfirmedBalance = newUnconfirmedBalance;
cachedNumTransactions = newNumTransactions;
+}
+void WalletModel::updateAddressList()
+{
addressTableModel->update();
}
return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee);
}
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(wallet->cs_wallet)
{
+ LOCK2(cs_main, wallet->cs_wallet);
+
// Sendmany
std::vector<std::pair<CScript, int64> > vecSend;
foreach(const SendCoinsRecipient &rcp, recipients)
}
return TransactionCreationFailed;
}
- if(!ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString(), NULL))
+ if(!ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString()))
{
return Aborted;
}
foreach(const SendCoinsRecipient &rcp, recipients)
{
std::string strAddress = rcp.address.toStdString();
- CRITICAL_BLOCK(wallet->cs_wallet)
{
+ LOCK(wallet->cs_wallet);
if (!wallet->mapAddressBook.count(strAddress))
wallet->SetAddressBookName(strAddress, rcp.label.toStdString());
}
}
- // Update our model of the address table
- addressTableModel->updateList();
-
return SendCoinsReturn(OK, 0, hex);
}
bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
{
bool retval;
- CRITICAL_BLOCK(wallet->cs_wallet)
{
+ LOCK(wallet->cs_wallet);
wallet->Lock(); // Make sure wallet is locked before attempting pass change
retval = wallet->ChangeWalletPassphrase(oldPass, newPass);
}
#include <QObject>
-#include "util.h"
+#include "allocators.h" /* for SecureString */
class OptionsModel;
class AddressTableModel;
class TransactionTableModel;
class CWallet;
-struct SendCoinsRecipient
+class SendCoinsRecipient
{
+public:
QString address;
QString label;
qint64 amount;
void requireUnlock();
// Asynchronous error notification
- void error(const QString &title, const QString &message);
+ void error(const QString &title, const QString &message, bool modal);
public slots:
-
-private slots:
void update();
+ void updateAddressList();
};
// 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 "init.h" // for pwalletMain
#include "bitcoinrpc.h"
+#include "ui_interface.h"
-// #include <boost/asio.hpp>
-// #include <boost/iostreams/concepts.hpp>
-// #include <boost/iostreams/stream.hpp>
#include <boost/lexical_cast.hpp>
-// #ifdef USE_SSL
-// #include <boost/asio/ssl.hpp>
-// typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
-// #endif
-// #include <boost/xpressive/xpressive_dynamic.hpp>
+
#include "json/json_spirit_reader_template.h"
#include "json/json_spirit_writer_template.h"
#include "json/json_spirit_utils.h"
key.SetSecret(secret, fCompressed);
CBitcoinAddress vchAddress = CBitcoinAddress(key.GetPubKey());
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(pwalletMain->cs_wallet)
{
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
pwalletMain->MarkDirty();
pwalletMain->SetAddressBookName(vchAddress, strLabel);
// Copyright (c) 2009-2012 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 "headers.h"
+#include <boost/foreach.hpp>
using namespace std;
using namespace boost;
+#include "script.h"
+#include "keystore.h"
+#include "bignum.h"
+#include "key.h"
+#include "main.h"
+
bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
bool CastToBool(const valtype& vch)
{
- for (int i = 0; i < vch.size(); i++)
+ for (unsigned int i = 0; i < vch.size(); i++)
{
if (vch[i] != 0)
{
return false;
int n = CastToBigNum(stacktop(-1)).getint();
popstack(stack);
- if (n < 0 || n >= stack.size())
+ if (n < 0 || n >= (int)stack.size())
return false;
valtype vch = stacktop(-n-1);
if (opcode == OP_ROLL)
int nEnd = nBegin + CastToBigNum(stacktop(-1)).getint();
if (nBegin < 0 || nEnd < nBegin)
return false;
- if (nBegin > vch.size())
+ if (nBegin > (int)vch.size())
nBegin = vch.size();
- if (nEnd > vch.size())
+ if (nEnd > (int)vch.size())
nEnd = vch.size();
vch.erase(vch.begin() + nEnd, vch.end());
vch.erase(vch.begin(), vch.begin() + nBegin);
int nSize = CastToBigNum(stacktop(-1)).getint();
if (nSize < 0)
return false;
- if (nSize > vch.size())
+ if (nSize > (int)vch.size())
nSize = vch.size();
if (opcode == OP_LEFT)
vch.erase(vch.begin() + nSize, vch.end());
if (stack.size() < 1)
return false;
valtype& vch = stacktop(-1);
- for (int i = 0; i < vch.size(); i++)
+ for (unsigned int i = 0; i < vch.size(); i++)
vch[i] = ~vch[i];
}
break;
MakeSameSize(vch1, vch2);
if (opcode == OP_AND)
{
- for (int i = 0; i < vch1.size(); i++)
+ for (unsigned int i = 0; i < vch1.size(); i++)
vch1[i] &= vch2[i];
}
else if (opcode == OP_OR)
{
- for (int i = 0; i < vch1.size(); i++)
+ for (unsigned int i = 0; i < vch1.size(); i++)
vch1[i] |= vch2[i];
}
else if (opcode == OP_XOR)
{
- for (int i = 0; i < vch1.size(); i++)
+ for (unsigned int i = 0; i < vch1.size(); i++)
vch1[i] ^= vch2[i];
}
popstack(stack);
scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR));
// Blank out other inputs' signatures
- for (int i = 0; i < txTmp.vin.size(); i++)
+ for (unsigned int i = 0; i < txTmp.vin.size(); i++)
txTmp.vin[i].scriptSig = CScript();
txTmp.vin[nIn].scriptSig = scriptCode;
txTmp.vout.clear();
// Let the others update at will
- for (int i = 0; i < txTmp.vin.size(); i++)
+ for (unsigned int i = 0; i < txTmp.vin.size(); i++)
if (i != nIn)
txTmp.vin[i].nSequence = 0;
}
return 1;
}
txTmp.vout.resize(nOut+1);
- for (int i = 0; i < nOut; i++)
+ for (unsigned int i = 0; i < nOut; i++)
txTmp.vout[i].SetNull();
// Let the others update at will
- for (int i = 0; i < txTmp.vin.size(); i++)
+ for (unsigned int i = 0; i < txTmp.vin.size(); i++)
if (i != nIn)
txTmp.vin[i].nSequence = 0;
}
}
// Serialize and hash
- CDataStream ss(SER_GETHASH);
+ CDataStream ss(SER_GETHASH, 0);
ss.reserve(10000);
ss << txTmp << nHashType;
return Hash(ss.begin(), ss.end());
}
-int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
+unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
{
- int nResult = 0;
+ unsigned int nResult = 0;
BOOST_FOREACH(const valtype& pubkey, pubkeys)
{
CBitcoinAddress address;
if (typeRet == TX_MULTISIG)
{
nRequiredRet = vSolutions.front()[0];
- for (int i = 1; i < vSolutions.size()-1; i++)
+ for (unsigned int i = 1; i < vSolutions.size()-1; i++)
{
CBitcoinAddress address;
address.SetPubKey(vSolutions[i]);
return true;
}
-int CScript::GetSigOpCount(bool fAccurate) const
+unsigned int CScript::GetSigOpCount(bool fAccurate) const
{
- int n = 0;
+ unsigned int n = 0;
const_iterator pc = begin();
opcodetype lastOpcode = OP_INVALIDOPCODE;
while (pc < end())
return n;
}
-int CScript::GetSigOpCount(const CScript& scriptSig) const
+unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
{
if (!IsPayToScriptHash())
return GetSigOpCount(true);
enum opcodetype
{
// push value
- OP_0=0,
- OP_FALSE=OP_0,
- OP_PUSHDATA1=76,
- OP_PUSHDATA2,
- OP_PUSHDATA4,
- OP_1NEGATE,
- OP_RESERVED,
- OP_1,
+ OP_0 = 0x00,
+ OP_FALSE = OP_0,
+ OP_PUSHDATA1 = 0x4c,
+ OP_PUSHDATA2 = 0x4d,
+ OP_PUSHDATA4 = 0x4e,
+ OP_1NEGATE = 0x4f,
+ OP_RESERVED = 0x50,
+ OP_1 = 0x51,
OP_TRUE=OP_1,
- OP_2,
- OP_3,
- OP_4,
- OP_5,
- OP_6,
- OP_7,
- OP_8,
- OP_9,
- OP_10,
- OP_11,
- OP_12,
- OP_13,
- OP_14,
- OP_15,
- OP_16,
+ OP_2 = 0x52,
+ OP_3 = 0x53,
+ OP_4 = 0x54,
+ OP_5 = 0x55,
+ OP_6 = 0x56,
+ OP_7 = 0x57,
+ OP_8 = 0x58,
+ OP_9 = 0x59,
+ OP_10 = 0x5a,
+ OP_11 = 0x5b,
+ OP_12 = 0x5c,
+ OP_13 = 0x5d,
+ OP_14 = 0x5e,
+ OP_15 = 0x5f,
+ OP_16 = 0x60,
// control
- OP_NOP,
- OP_VER,
- OP_IF,
- OP_NOTIF,
- OP_VERIF,
- OP_VERNOTIF,
- OP_ELSE,
- OP_ENDIF,
- OP_VERIFY,
- OP_RETURN,
+ OP_NOP = 0x61,
+ OP_VER = 0x62,
+ OP_IF = 0x63,
+ OP_NOTIF = 0x64,
+ OP_VERIF = 0x65,
+ OP_VERNOTIF = 0x66,
+ OP_ELSE = 0x67,
+ OP_ENDIF = 0x68,
+ OP_VERIFY = 0x69,
+ OP_RETURN = 0x6a,
// stack ops
- OP_TOALTSTACK,
- OP_FROMALTSTACK,
- OP_2DROP,
- OP_2DUP,
- OP_3DUP,
- OP_2OVER,
- OP_2ROT,
- OP_2SWAP,
- OP_IFDUP,
- OP_DEPTH,
- OP_DROP,
- OP_DUP,
- OP_NIP,
- OP_OVER,
- OP_PICK,
- OP_ROLL,
- OP_ROT,
- OP_SWAP,
- OP_TUCK,
+ OP_TOALTSTACK = 0x6b,
+ OP_FROMALTSTACK = 0x6c,
+ OP_2DROP = 0x6d,
+ OP_2DUP = 0x6e,
+ OP_3DUP = 0x6f,
+ OP_2OVER = 0x70,
+ OP_2ROT = 0x71,
+ OP_2SWAP = 0x72,
+ OP_IFDUP = 0x73,
+ OP_DEPTH = 0x74,
+ OP_DROP = 0x75,
+ OP_DUP = 0x76,
+ OP_NIP = 0x77,
+ OP_OVER = 0x78,
+ OP_PICK = 0x79,
+ OP_ROLL = 0x7a,
+ OP_ROT = 0x7b,
+ OP_SWAP = 0x7c,
+ OP_TUCK = 0x7d,
// splice ops
- OP_CAT,
- OP_SUBSTR,
- OP_LEFT,
- OP_RIGHT,
- OP_SIZE,
+ OP_CAT = 0x7e,
+ OP_SUBSTR = 0x7f,
+ OP_LEFT = 0x80,
+ OP_RIGHT = 0x81,
+ OP_SIZE = 0x82,
// bit logic
- OP_INVERT,
- OP_AND,
- OP_OR,
- OP_XOR,
- OP_EQUAL,
- OP_EQUALVERIFY,
- OP_RESERVED1,
- OP_RESERVED2,
+ OP_INVERT = 0x83,
+ OP_AND = 0x84,
+ OP_OR = 0x85,
+ OP_XOR = 0x86,
+ OP_EQUAL = 0x87,
+ OP_EQUALVERIFY = 0x88,
+ OP_RESERVED1 = 0x89,
+ OP_RESERVED2 = 0x8a,
// numeric
- OP_1ADD,
- OP_1SUB,
- OP_2MUL,
- OP_2DIV,
- OP_NEGATE,
- OP_ABS,
- OP_NOT,
- OP_0NOTEQUAL,
-
- OP_ADD,
- OP_SUB,
- OP_MUL,
- OP_DIV,
- OP_MOD,
- OP_LSHIFT,
- OP_RSHIFT,
-
- OP_BOOLAND,
- OP_BOOLOR,
- OP_NUMEQUAL,
- OP_NUMEQUALVERIFY,
- OP_NUMNOTEQUAL,
- OP_LESSTHAN,
- OP_GREATERTHAN,
- OP_LESSTHANOREQUAL,
- OP_GREATERTHANOREQUAL,
- OP_MIN,
- OP_MAX,
-
- OP_WITHIN,
+ OP_1ADD = 0x8b,
+ OP_1SUB = 0x8c,
+ OP_2MUL = 0x8d,
+ OP_2DIV = 0x8e,
+ OP_NEGATE = 0x8f,
+ OP_ABS = 0x90,
+ OP_NOT = 0x91,
+ OP_0NOTEQUAL = 0x92,
+
+ OP_ADD = 0x93,
+ OP_SUB = 0x94,
+ OP_MUL = 0x95,
+ OP_DIV = 0x96,
+ OP_MOD = 0x97,
+ OP_LSHIFT = 0x98,
+ OP_RSHIFT = 0x99,
+
+ OP_BOOLAND = 0x9a,
+ OP_BOOLOR = 0x9b,
+ OP_NUMEQUAL = 0x9c,
+ OP_NUMEQUALVERIFY = 0x9d,
+ OP_NUMNOTEQUAL = 0x9e,
+ OP_LESSTHAN = 0x9f,
+ OP_GREATERTHAN = 0xa0,
+ OP_LESSTHANOREQUAL = 0xa1,
+ OP_GREATERTHANOREQUAL = 0xa2,
+ OP_MIN = 0xa3,
+ OP_MAX = 0xa4,
+
+ OP_WITHIN = 0xa5,
// crypto
- OP_RIPEMD160,
- OP_SHA1,
- OP_SHA256,
- OP_HASH160,
- OP_HASH256,
- OP_CODESEPARATOR,
- OP_CHECKSIG,
- OP_CHECKSIGVERIFY,
- OP_CHECKMULTISIG,
- OP_CHECKMULTISIGVERIFY,
+ OP_RIPEMD160 = 0xa6,
+ OP_SHA1 = 0xa7,
+ OP_SHA256 = 0xa8,
+ OP_HASH160 = 0xa9,
+ OP_HASH256 = 0xaa,
+ OP_CODESEPARATOR = 0xab,
+ OP_CHECKSIG = 0xac,
+ OP_CHECKSIGVERIFY = 0xad,
+ OP_CHECKMULTISIG = 0xae,
+ OP_CHECKMULTISIGVERIFY = 0xaf,
// expansion
- OP_NOP1,
- OP_NOP2,
- OP_NOP3,
- OP_NOP4,
- OP_NOP5,
- OP_NOP6,
- OP_NOP7,
- OP_NOP8,
- OP_NOP9,
- OP_NOP10,
+ OP_NOP1 = 0xb0,
+ OP_NOP2 = 0xb1,
+ OP_NOP3 = 0xb2,
+ OP_NOP4 = 0xb3,
+ OP_NOP5 = 0xb4,
+ OP_NOP6 = 0xb5,
+ OP_NOP7 = 0xb6,
+ OP_NOP8 = 0xb7,
+ OP_NOP9 = 0xb8,
+ OP_NOP10 = 0xb9,
opcodetype opcode;
do
{
- while (end() - pc >= b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
+ while (end() - pc >= (long)b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
{
erase(pc, pc + b.size());
++nFound;
// CHECKMULTISIGs serialized in scriptSigs are
// counted more accurately, assuming they are of the form
// ... OP_N CHECKMULTISIG ...
- int GetSigOpCount(bool fAccurate) const;
+ unsigned int GetSigOpCount(bool fAccurate) const;
// Accurately count sigOps, including sigOps in
// pay-to-script-hash transactions:
- int GetSigOpCount(const CScript& scriptSig) const;
+ unsigned int GetSigOpCount(const CScript& scriptSig) const;
bool IsPayToScriptHash() const;
#include <boost/tuple/tuple_comparison.hpp>
#include <boost/tuple/tuple_io.hpp>
+#include "allocators.h"
+#include "version.h"
+
typedef long long int64;
typedef unsigned long long uint64;
-#ifdef WIN32
-#define _WIN32_WINNT 0x0501
-#include <windows.h>
-// This is used to attempt to keep keying material out of swap
-// Note that VirtualLock does not provide this as a guarantee on Windows,
-// but, in practice, memory that has been VirtualLock'd almost never gets written to
-// the pagefile except in rare circumstances where memory is extremely low.
-#include <windows.h>
-#define mlock(p, n) VirtualLock((p), (n));
-#define munlock(p, n) VirtualUnlock((p), (n));
-#else
-#include <sys/mman.h>
-#include <limits.h>
-/* This comes from limits.h if it's not defined there set a sane default */
-#ifndef PAGESIZE
-#include <unistd.h>
-#define PAGESIZE sysconf(_SC_PAGESIZE)
-#endif
-#define mlock(a,b) \
- mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
- (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
-#define munlock(a,b) \
- munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
- (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
-#endif
-
class CScript;
class CDataStream;
class CAutoFile;
static const unsigned int MAX_SIZE = 0x02000000;
-static const int PROTOCOL_VERSION = 60000;
-
// Used to bypass the rule against non-const reference to temporary
// where it makes sense with wrappers such as CFlatData or CTxDB
template<typename T>
};
#define IMPLEMENT_SERIALIZE(statements) \
- unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const \
+ unsigned int GetSerializeSize(int nType, int nVersion) const \
{ \
CSerActionGetSerializeSize ser_action; \
const bool fGetSize = true; \
return nSerSize; \
} \
template<typename Stream> \
- void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const \
+ void Serialize(Stream& s, int nType, int nVersion) const \
{ \
CSerActionSerialize ser_action; \
const bool fGetSize = false; \
{statements} \
} \
template<typename Stream> \
- void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) \
+ void Unserialize(Stream& s, int nType, int nVersion) \
{ \
CSerActionUnserialize ser_action; \
const bool fGetSize = false; \
}
};
-
-
-/** string stored as a fixed length field */
-template<std::size_t LEN>
-class CFixedFieldString
-{
-protected:
- const std::string* pcstr;
- std::string* pstr;
-public:
- explicit CFixedFieldString(const std::string& str) : pcstr(&str), pstr(NULL) { }
- explicit CFixedFieldString(std::string& str) : pcstr(&str), pstr(&str) { }
-
- unsigned int GetSerializeSize(int, int=0) const
- {
- return LEN;
- }
-
- template<typename Stream>
- void Serialize(Stream& s, int, int=0) const
- {
- char pszBuf[LEN];
- strncpy(pszBuf, pcstr->c_str(), LEN);
- s.write(pszBuf, LEN);
- }
-
- template<typename Stream>
- void Unserialize(Stream& s, int, int=0)
- {
- if (pstr == NULL)
- throw std::ios_base::failure("CFixedFieldString::Unserialize : trying to unserialize to const string");
- char pszBuf[LEN+1];
- s.read(pszBuf, LEN);
- pszBuf[LEN] = '\0';
- *pstr = pszBuf;
- }
-};
-
-
-
-
-
//
// Forward declarations
//
// vector
template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
-template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion);
template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
-template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion);
template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
-template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion);
// others derived from vector
-extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion=PROTOCOL_VERSION);
-template<typename Stream> void Serialize(Stream& os, const CScript& v, int nType, int nVersion=PROTOCOL_VERSION);
-template<typename Stream> void Unserialize(Stream& is, CScript& v, int nType, int nVersion=PROTOCOL_VERSION);
+extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion);
+template<typename Stream> void Serialize(Stream& os, const CScript& v, int nType, int nVersion);
+template<typename Stream> void Unserialize(Stream& is, CScript& v, int nType, int nVersion);
// pair
-template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION);
-template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION);
-template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion);
+template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion);
+template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion);
// 3 tuple
-template<typename T0, typename T1, typename T2> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION);
-template<typename Stream, typename T0, typename T1, typename T2> void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION);
-template<typename Stream, typename T0, typename T1, typename T2> void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename T0, typename T1, typename T2> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion);
+template<typename Stream, typename T0, typename T1, typename T2> void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion);
+template<typename Stream, typename T0, typename T1, typename T2> void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion);
// 4 tuple
-template<typename T0, typename T1, typename T2, typename T3> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION);
-template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION);
-template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename T0, typename T1, typename T2, typename T3> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion);
+template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion);
+template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion);
// map
-template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
-template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
-template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion);
+template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion);
+template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion);
// set
-template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
-template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
-template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
+template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion);
+template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion);
+template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion);
// Thanks to Boost serialization for this idea.
//
template<typename T>
-inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion=PROTOCOL_VERSION)
+inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion)
{
return a.GetSerializeSize((int)nType, nVersion);
}
template<typename Stream, typename T>
-inline void Serialize(Stream& os, const T& a, long nType, int nVersion=PROTOCOL_VERSION)
+inline void Serialize(Stream& os, const T& a, long nType, int nVersion)
{
a.Serialize(os, (int)nType, nVersion);
}
template<typename Stream, typename T>
-inline void Unserialize(Stream& is, T& a, long nType, int nVersion=PROTOCOL_VERSION)
+inline void Unserialize(Stream& is, T& a, long nType, int nVersion)
{
a.Unserialize(is, (int)nType, nVersion);
}
template<typename Stream, typename T, typename A>
void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
{
- //unsigned int nSize = ReadCompactSize(is);
- //v.resize(nSize);
- //is.read((char*)&v[0], nSize * sizeof(T));
-
// Limit size per read so bogus size value won't cause out of memory
v.clear();
unsigned int nSize = ReadCompactSize(is);
template<typename Stream, typename T, typename A>
void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
{
- //unsigned int nSize = ReadCompactSize(is);
- //v.resize(nSize);
- //for (std::vector<T, A>::iterator vi = v.begin(); vi != v.end(); ++vi)
- // Unserialize(is, (*vi), nType, nVersion);
-
v.clear();
unsigned int nSize = ReadCompactSize(is);
unsigned int i = 0;
-//
-// Allocator that locks its contents from being paged
-// out of memory and clears its contents before deletion.
-//
-template<typename T>
-struct secure_allocator : public std::allocator<T>
-{
- // MSVC8 default copy constructor is broken
- typedef std::allocator<T> base;
- typedef typename base::size_type size_type;
- typedef typename base::difference_type difference_type;
- typedef typename base::pointer pointer;
- typedef typename base::const_pointer const_pointer;
- typedef typename base::reference reference;
- typedef typename base::const_reference const_reference;
- typedef typename base::value_type value_type;
- secure_allocator() throw() {}
- secure_allocator(const secure_allocator& a) throw() : base(a) {}
- template <typename U>
- secure_allocator(const secure_allocator<U>& a) throw() : base(a) {}
- ~secure_allocator() throw() {}
- template<typename _Other> struct rebind
- { typedef secure_allocator<_Other> other; };
-
- T* allocate(std::size_t n, const void *hint = 0)
- {
- T *p;
- p = std::allocator<T>::allocate(n, hint);
- if (p != NULL)
- mlock(p, sizeof(T) * n);
- return p;
- }
-
- void deallocate(T* p, std::size_t n)
- {
- if (p != NULL)
- {
- memset(p, 0, sizeof(T) * n);
- munlock(p, sizeof(T) * n);
- }
- std::allocator<T>::deallocate(p, n);
- }
-};
-
-
-//
-// Allocator that clears its contents before deletion.
-//
-template<typename T>
-struct zero_after_free_allocator : public std::allocator<T>
-{
- // MSVC8 default copy constructor is broken
- typedef std::allocator<T> base;
- typedef typename base::size_type size_type;
- typedef typename base::difference_type difference_type;
- typedef typename base::pointer pointer;
- typedef typename base::const_pointer const_pointer;
- typedef typename base::reference reference;
- typedef typename base::const_reference const_reference;
- typedef typename base::value_type value_type;
- zero_after_free_allocator() throw() {}
- zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {}
- template <typename U>
- zero_after_free_allocator(const zero_after_free_allocator<U>& a) throw() : base(a) {}
- ~zero_after_free_allocator() throw() {}
- template<typename _Other> struct rebind
- { typedef zero_after_free_allocator<_Other> other; };
-
- void deallocate(T* p, std::size_t n)
- {
- if (p != NULL)
- memset(p, 0, sizeof(T) * n);
- std::allocator<T>::deallocate(p, n);
- }
-};
typedef vector_type::const_iterator const_iterator;
typedef vector_type::reverse_iterator reverse_iterator;
- explicit CDataStream(int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION)
+ explicit CDataStream(int nTypeIn, int nVersionIn)
{
Init(nTypeIn, nVersionIn);
}
- CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(pbegin, pend)
+ CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
{
Init(nTypeIn, nVersionIn);
}
#if !defined(_MSC_VER) || _MSC_VER >= 1300
- CDataStream(const char* pbegin, const char* pend, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(pbegin, pend)
+ CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
{
Init(nTypeIn, nVersionIn);
}
#endif
- CDataStream(const vector_type& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end())
+ CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
{
Init(nTypeIn, nVersionIn);
}
- CDataStream(const std::vector<char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end())
+ CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
{
Init(nTypeIn, nVersionIn);
}
- CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0])
+ CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0])
{
Init(nTypeIn, nVersionIn);
}
- void Init(int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION)
+ void Init(int nTypeIn, int nVersionIn)
{
nReadPos = 0;
nType = nTypeIn;
}
template<typename Stream>
- void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const
+ void Serialize(Stream& s, int nType, int nVersion) const
{
// Special case: stream << stream concatenates like stream += stream
if (!vch.empty())
int nType;
int nVersion;
- CAutoFile(FILE* filenew=NULL, int nTypeIn=SER_DISK, int nVersionIn=PROTOCOL_VERSION)
+ CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn)
{
file = filenew;
nType = nTypeIn;
void ReadVersion() { *this >> nVersion; }
void WriteVersion() { *this << nVersion; }
- CAutoFile& read(char* pch, int nSize)
+ CAutoFile& read(char* pch, size_t nSize)
{
if (!file)
throw std::ios_base::failure("CAutoFile::read : file handle is NULL");
return (*this);
}
- CAutoFile& write(const char* pch, int nSize)
+ CAutoFile& write(const char* pch, size_t nSize)
{
if (!file)
throw std::ios_base::failure("CAutoFile::write : file handle is NULL");
*/
#ifndef BITCOIN_STRLCPY_H
#define BITCOIN_STRLCPY_H
+
+#include <stdlib.h>
+#include <string.h>
+
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
// Tests this internal-to-main.cpp method:
extern void AddOrphanTx(const CDataStream& vMsg);
-extern int LimitOrphanTxSize(int nMaxOrphans);
+extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
extern std::map<uint256, CDataStream*> mapOrphanTransactions;
extern std::multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey());
- CDataStream ds;
+ CDataStream ds(SER_DISK, CLIENT_VERSION);
ds << tx;
AddOrphanTx(ds);
}
tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey());
SignSignature(keystore, txPrev, tx, 0);
- CDataStream ds;
+ CDataStream ds(SER_DISK, CLIENT_VERSION);
ds << tx;
AddOrphanTx(ds);
}
--- /dev/null
+[
+["", ""],
+["", "NOP"],
+["NOP", ""],
+["NOP","NOP"],
+["0 1","EQUAL"],
+["1 1 ADD", "0 EQUAL"],
+["11 1 ADD 12 SUB", "11 EQUAL"],
+
+["2147483648 0 ADD", "NOP", "arithmetic operands must be in range [-2^31...2^31] "],
+["-2147483648 0 ADD", "NOP", "arithmetic operands must be in range [-2^31...2^31] "],
+["2147483647 DUP ADD", "4294967294 NUMEQUAL", "NUMEQUAL must be in numeric range"],
+["0xaabbccddeeff NOT", "0 EQUAL", "NOT is an arithmetic operand"],
+
+["2 DUP MUL", "4 EQUAL", "disabled"],
+["2 DUP DIV", "1 EQUAL", "disabled"],
+["2 2MUL", "4 EQUAL", "disabled"],
+["2 2DIV", "1 EQUAL", "disabled"],
+["7 3 MOD", "1 EQUAL", "disabled"],
+["2 2 LSHIFT", "8 EQUAL", "disabled"],
+["2 1 RSHIFT", "1 EQUAL", "disabled"],
+
+
+["NOP1","NOP10"]
+]
--- /dev/null
+[
+["2 -2 ADD", "0 EQUAL"],
+["2147483647 -2147483647 ADD", "0 EQUAL"],
+["-1 -1 ADD", "-2 EQUAL"],
+
+["1","NOP"],
+["0 0","EQUAL"],
+["1 1 ADD", "2 EQUAL"],
+["1 1ADD", "2 EQUAL"],
+["111 1SUB", "110 EQUAL"],
+["111 1 ADD 12 SUB", "100 EQUAL"],
+["0 ABS", "0 EQUAL"],
+["16 ABS", "16 EQUAL"],
+["-16 ABS", "-16 NEGATE EQUAL"],
+["0 NOT", "NOP"],
+["1 NOT", "0 EQUAL"],
+["11 NOT", "0 EQUAL"],
+["0 0NOTEQUAL", "0 EQUAL"],
+["1 0NOTEQUAL", "1 EQUAL"],
+["111 0NOTEQUAL", "1 EQUAL"],
+["-111 0NOTEQUAL", "1 EQUAL"],
+["1 1 BOOLAND", "NOP"],
+["1 0 BOOLAND", "NOT"],
+["0 1 BOOLAND", "NOT"],
+["0 0 BOOLAND", "NOT"],
+["16 17 BOOLAND", "NOP"],
+["1 1 BOOLOR", "NOP"],
+["1 0 BOOLOR", "NOP"],
+["0 1 BOOLOR", "NOP"],
+["0 0 BOOLOR", "NOT"],
+["16 17 BOOLOR", "NOP"],
+["11 10 1 ADD", "NUMEQUAL"],
+["11 10 1 ADD", "NUMEQUALVERIFY 1"],
+["11 10 1 ADD", "NUMNOTEQUAL NOT"],
+["111 10 1 ADD", "NUMNOTEQUAL"],
+["11 10", "LESSTHAN NOT"],
+["4 4", "LESSTHAN NOT"],
+["10 11", "LESSTHAN"],
+["-11 11", "LESSTHAN"],
+["-11 -10", "LESSTHAN"],
+["11 10", "GREATERTHAN"],
+["4 4", "GREATERTHAN NOT"],
+["10 11", "GREATERTHAN NOT"],
+["-11 11", "GREATERTHAN NOT"],
+["-11 -10", "GREATERTHAN NOT"],
+["11 10", "LESSTHANOREQUAL NOT"],
+["4 4", "LESSTHANOREQUAL"],
+["10 11", "LESSTHANOREQUAL"],
+["-11 11", "LESSTHANOREQUAL"],
+["-11 -10", "LESSTHANOREQUAL"],
+["11 10", "GREATERTHANOREQUAL"],
+["4 4", "GREATERTHANOREQUAL"],
+["10 11", "GREATERTHANOREQUAL NOT"],
+["-11 11", "GREATERTHANOREQUAL NOT"],
+["-11 -10", "GREATERTHANOREQUAL NOT"],
+["1 0 MIN", "0 NUMEQUAL"],
+["0 1 MIN", "0 NUMEQUAL"],
+["-1 0 MIN", "-1 NUMEQUAL"],
+["0 -2147483647 MIN", "-2147483647 NUMEQUAL"],
+["2147483647 0 MAX", "2147483647 NUMEQUAL"],
+["0 100 MAX", "100 NUMEQUAL"],
+["-100 0 MAX", "0 NUMEQUAL"],
+["0 -2147483647 MAX", "0 NUMEQUAL"],
+["0 0 1", "WITHIN"],
+["1 0 1", "WITHIN NOT"],
+["0 -2147483647 2147483647", "WITHIN"],
+["-1 -100 100", "WITHIN"],
+["11 -100 100", "WITHIN"],
+["-2147483647 -100 100", "WITHIN NOT"],
+["2147483647 -100 100", "WITHIN NOT"],
+
+["2147483647 2147483647 SUB", "0 EQUAL"],
+["2147483647 DUP ADD", "4294967294 EQUAL", ">32 bit EQUAL is valid"],
+["2147483647 NEGATE DUP ADD", "-4294967294 EQUAL"],
+
+
+["NOP","1"]
+]
--- a/src/test/data/script_valid.json
#include <boost/test/unit_test.hpp>
#include "uint256.h"
+#include "util.h"
extern void SHA256Transform(void* pstate, void* pinput, const void* pinit);
unsigned int pSHA256InitState[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
- unsigned char pstate[32];
+ // unsigned char pstate[32];
unsigned char pinput[64];
int i;
#include "base58.h"
#include "util.h"
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_writer_template.h"
-#include "json/json_spirit_utils.h"
+#include "bitcoinrpc.h"
using namespace std;
using namespace json_spirit;
-typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
-extern map<string, rpcfn_type> mapCallTable;
-
BOOST_AUTO_TEST_SUITE(rpc_tests)
static Array
BOOST_FIXTURE_TEST_CASE(rpc_addmultisig, TestNetFixture)
{
- rpcfn_type addmultisig = mapCallTable["addmultisigaddress"];
+ rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor;
// old, 65-byte-long:
const char* address1Hex = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8";
+#include <iostream>
+#include <fstream>
#include <vector>
-#include <boost/test/unit_test.hpp>
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/algorithm/string/split.hpp>
#include <boost/foreach.hpp>
+#include <boost/preprocessor/stringize.hpp>
+#include <boost/test/unit_test.hpp>
+#include "json/json_spirit_reader_template.h"
+#include "json/json_spirit_writer_template.h"
+#include "json/json_spirit_utils.h"
#include "main.h"
#include "wallet.h"
using namespace std;
+using namespace json_spirit;
+using namespace boost::algorithm;
+
extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
bool fValidatePayToScriptHash, int nHashType);
+CScript
+ParseScript(string s)
+{
+ CScript result;
+
+ static map<string, opcodetype> mapOpNames;
+
+ if (mapOpNames.size() == 0)
+ {
+ for (int op = OP_NOP; op <= OP_NOP10; op++)
+ {
+ const char* name = GetOpName((opcodetype)op);
+ if (strcmp(name, "OP_UNKNOWN") == 0)
+ continue;
+ string strName(name);
+ mapOpNames[strName] = (opcodetype)op;
+ // Convenience: OP_ADD and just ADD are both recognized:
+ replace_first(strName, "OP_", "");
+ mapOpNames[strName] = (opcodetype)op;
+ }
+ }
+
+ vector<string> words;
+ split(words, s, is_any_of(" \t\n"), token_compress_on);
+
+ BOOST_FOREACH(string w, words)
+ {
+ if (all(w, is_digit()) ||
+ (starts_with(w, "-") && all(string(w.begin()+1, w.end()), is_digit())))
+ {
+ // Number
+ int64 n = atoi64(w);
+ result << n;
+ }
+ else if (starts_with(w, "0x") && IsHex(string(w.begin()+2, w.end())))
+ {
+ // Hex data:
+ result << ParseHex(string(w.begin()+2, w.end()));
+ }
+ else if (s.size() >= 2 && starts_with(w, "'") && ends_with(w, "'"))
+ {
+ // Single-quoted string, pushed as data:
+ std::vector<unsigned char> value(s.begin()+1, s.end()-1);
+ result << value;
+ }
+ else if (mapOpNames.count(w))
+ {
+ // opcode, e.g. OP_ADD or OP_1:
+ result << mapOpNames[w];
+ }
+ else
+ {
+ BOOST_ERROR("Parse error: " << s);
+ return CScript();
+ }
+ }
+
+ return result;
+}
+
+Array
+read_json(const std::string& filename)
+{
+ namespace fs = boost::filesystem;
+ fs::path testFile = fs::current_path() / "test" / "data" / filename;
+
+#ifdef TEST_DATA_DIR
+ if (!fs::exists(testFile))
+ {
+ testFile = fs::path(BOOST_PP_STRINGIZE(TEST_DATA_DIR)) / filename;
+ }
+#endif
+
+ ifstream ifs(testFile.string().c_str(), ifstream::in);
+ Value v;
+ if (!read_stream(ifs, v))
+ {
+ BOOST_ERROR("Cound not find/open " << filename);
+ return Array();
+ }
+ if (v.type() != array_type)
+ {
+ BOOST_ERROR(filename << " does not contain a json array");
+ return Array();
+ }
+
+ return v.get_array();
+}
+
BOOST_AUTO_TEST_SUITE(script_tests)
+BOOST_AUTO_TEST_CASE(script_valid)
+{
+ // Read tests from test/data/script_valid.json
+ // Format is an array of arrays
+ // Inner arrays are [ "scriptSig", "scriptPubKey" ]
+ // ... where scriptSig and scriptPubKey are stringified
+ // scripts.
+ Array tests = read_json("script_valid.json");
+
+ BOOST_FOREACH(Value& tv, tests)
+ {
+ Array test = tv.get_array();
+ string strTest = write_string(tv, false);
+ if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments)
+ {
+ BOOST_ERROR("Bad test: " << strTest);
+ continue;
+ }
+ string scriptSigString = test[0].get_str();
+ CScript scriptSig = ParseScript(scriptSigString);
+ string scriptPubKeyString = test[1].get_str();
+ CScript scriptPubKey = ParseScript(scriptPubKeyString);
+
+ CTransaction tx;
+ BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(script_invalid)
+{
+ // Scripts that should evaluate as invalid
+ Array tests = read_json("script_invalid.json");
+
+ BOOST_FOREACH(Value& tv, tests)
+ {
+ Array test = tv.get_array();
+ string strTest = write_string(tv, false);
+ if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments)
+ {
+ BOOST_ERROR("Bad test: " << strTest);
+ continue;
+ }
+ string scriptSigString = test[0].get_str();
+ CScript scriptSig = ParseScript(scriptSigString);
+ string scriptPubKeyString = test[1].get_str();
+ CScript scriptPubKey = ParseScript(scriptPubKeyString);
+
+ CTransaction tx;
+ BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest);
+ }
+}
+
BOOST_AUTO_TEST_CASE(script_PushData)
{
// Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on
// Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436)
unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00};
vector<unsigned char> vch(ch, ch + sizeof(ch) -1);
- CDataStream stream(vch);
+ CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
CTransaction tx;
stream >> tx;
BOOST_CHECK_MESSAGE(tx.CheckTransaction(), "Simple deserialized transaction should be valid.");
CCriticalSection cs;
do {
- CRITICAL_BLOCK(cs)
- break;
+ LOCK(cs);
+ break;
BOOST_ERROR("break was swallowed!");
} while(0);
do {
- TRY_CRITICAL_BLOCK(cs)
+ TRY_LOCK(cs, lockTest);
+ if (lockTest)
break;
BOOST_ERROR("break was swallowed!");
BOOST_CHECK_EQUAL(
HexStr(ParseHex_expected, ParseHex_expected + 5, true),
"04 67 8a fd b0");
+
+ BOOST_CHECK_EQUAL(
+ HexStr(ParseHex_expected, ParseHex_expected, true),
+ "");
+
+ std::vector<unsigned char> ParseHex_vec(ParseHex_expected, ParseHex_expected + 5);
+
+ BOOST_CHECK_EQUAL(
+ HexStr(ParseHex_vec, true),
+ "04 67 8a fd b0");
}
+
BOOST_AUTO_TEST_CASE(util_DateTimeStrFormat)
{
BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0), "01/01/70 00:00:00");
// Copyright (c) 2010 Satoshi Nakamoto
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_EXTERNUI_H
-#define BITCOIN_EXTERNUI_H
+#ifndef BITCOIN_UI_INTERFACE_H
+#define BITCOIN_UI_INTERFACE_H
#include <string>
-#include <boost/function/function0.hpp>
-#include "wallet.h"
+#include "util.h" // for int64
-typedef void wxWindow;
#define wxYES 0x00000002
#define wxOK 0x00000004
#define wxNO 0x00000008
// Force blocking, modal message box dialog (not just notification)
#define wxMODAL 0x00040000
-extern int MyMessageBox(const std::string& message, const std::string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1);
-#define wxMessageBox MyMessageBox
-extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1);
-extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent);
+/* These UI communication functions are implemented in bitcoin.cpp (for ui) and noui.cpp (no ui) */
+
+extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK);
+extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption);
extern void ThreadSafeHandleURI(const std::string& strURI);
-extern void CalledSetStatusBar(const std::string& strText, int nField);
-extern void UIThreadCall(boost::function0<void> fn);
extern void MainFrameRepaint();
+extern void AddressBookRepaint();
+extern void QueueShutdown();
extern void InitMessage(const std::string &message);
extern std::string _(const char* psz);
#ifndef BITCOIN_UINT256_H
#define BITCOIN_UINT256_H
-#include "serialize.h"
-
#include <limits.h>
#include <stdio.h>
+#include <string.h>
#include <string>
#include <vector>
return pn[2*n] | (uint64)pn[2*n+1] << 32;
}
- unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const
+// unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const
+ unsigned int GetSerializeSize(int nType, int nVersion) const
{
return sizeof(pn);
}
template<typename Stream>
- void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const
+// void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const
+ void Serialize(Stream& s, int nType, int nVersion) const
{
s.write((char*)pn, sizeof(pn));
}
template<typename Stream>
- void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION)
+// void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION)
+ void Unserialize(Stream& s, int nType, int nVersion)
{
s.read((char*)pn, sizeof(pn));
}
// Copyright (c) 2009-2012 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 "headers.h"
+
+#include "util.h"
#include "strlcpy.h"
+#include "version.h"
+#include "ui_interface.h"
#include <boost/algorithm/string/join.hpp>
// Work around clang compilation problem in Boost 1.46:
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/foreach.hpp>
+#include <openssl/crypto.h>
+#include <openssl/rand.h>
+
+#ifdef WIN32
+#ifdef _MSC_VER
+#pragma warning(disable:4786)
+#pragma warning(disable:4804)
+#pragma warning(disable:4805)
+#pragma warning(disable:4717)
+#endif
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0501
+#ifdef _WIN32_IE
+#undef _WIN32_IE
+#endif
+#define _WIN32_IE 0x0400
+#define WIN32_LEAN_AND_MEAN 1
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include "shlobj.h"
+#include "shlwapi.h"
+#endif
using namespace std;
using namespace boost;
bool fDebug = false;
bool fPrintToConsole = false;
bool fPrintToDebugger = false;
-char pszSetDataDir[MAX_PATH] = "";
bool fRequestShutdown = false;
bool fShutdown = false;
bool fDaemon = false;
bool fLogTimestamps = false;
CMedianFilter<int64> vTimeOffsets(200,0);
-
-
-// Workaround for "multiple definition of `_tls_used'"
-// http://svn.boost.org/trac/boost/ticket/4258
-extern "C" void tss_cleanup_implemented() { }
-
-
-
-
-
// Init openssl library multithreading support
static boost::interprocess::interprocess_mutex** ppmutexOpenSSL;
void locking_callback(int mode, int i, const char* file, int line)
if (!fileout)
{
- char pszFile[MAX_PATH+100];
- GetDataDir(pszFile);
- strlcat(pszFile, "/debug.log", sizeof(pszFile));
- fileout = fopen(pszFile, "a");
+ boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
+ fileout = fopen(pathDebug.string().c_str(), "a");
if (fileout) setbuf(fileout, NULL); // unbuffered
}
if (fileout)
static CCriticalSection cs_OutputDebugStringF;
// accumulate a line at a time
- CRITICAL_BLOCK(cs_OutputDebugStringF)
{
+ LOCK(cs_OutputDebugStringF);
static char pszBuffer[50000];
static char* pend;
if (pend == NULL)
va_start(arg_ptr, format);
int ret = _vsnprintf(buffer, limit, format, arg_ptr);
va_end(arg_ptr);
- if (ret < 0 || ret >= limit)
+ if (ret < 0 || ret >= (int)limit)
{
ret = limit - 1;
buffer[limit-1] = 0;
return ret;
}
-string strprintf(const std::string &format, ...)
+string real_strprintf(const std::string &format, int dummy, ...)
{
char buffer[50000];
char* p = buffer;
loop
{
va_list arg_ptr;
- va_start(arg_ptr, format);
+ va_start(arg_ptr, dummy);
ret = _vsnprintf(p, limit, format.c_str(), arg_ptr);
va_end(arg_ptr);
if (ret >= 0 && ret < limit)
return str;
}
-bool error(const std::string &format, ...)
+bool error(const char *format, ...)
{
char buffer[50000];
int limit = sizeof(buffer);
va_list arg_ptr;
va_start(arg_ptr, format);
- int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
+ int ret = _vsnprintf(buffer, limit, format, arg_ptr);
va_end(arg_ptr);
if (ret < 0 || ret >= limit)
{
- ret = limit - 1;
buffer[limit-1] = 0;
}
printf("ERROR: %s\n", buffer);
}
#ifdef WIN32
-string MyGetSpecialFolderPath(int nFolder, bool fCreate)
+boost::filesystem::path MyGetSpecialFolderPath(int nFolder, bool fCreate)
{
+ namespace fs = boost::filesystem;
+
char pszPath[MAX_PATH] = "";
if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))
{
- return pszPath;
+ return fs::path(pszPath);
}
else if (nFolder == CSIDL_STARTUP)
{
- return string(getenv("USERPROFILE")) + "\\Start Menu\\Programs\\Startup";
+ return fs::path(getenv("USERPROFILE")) / "Start Menu" / "Programs" / "Startup";
}
else if (nFolder == CSIDL_APPDATA)
{
- return getenv("APPDATA");
+ return fs::path(getenv("APPDATA"));
}
- return "";
+ return fs::path("");
}
#endif
-string GetDefaultDataDir()
+boost::filesystem::path GetDefaultDataDir()
{
+ namespace fs = boost::filesystem;
+
// Windows: C:\Documents and Settings\username\Application Data\Bitcoin
// Mac: ~/Library/Application Support/Bitcoin
// Unix: ~/.bitcoin
#ifdef WIN32
// Windows
- return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin";
+ return MyGetSpecialFolderPath(CSIDL_APPDATA, true) / "Bitcoin";
#else
+ fs::path pathRet;
char* pszHome = getenv("HOME");
if (pszHome == NULL || strlen(pszHome) == 0)
- pszHome = (char*)"/";
- string strHome = pszHome;
- if (strHome[strHome.size()-1] != '/')
- strHome += '/';
+ pathRet = fs::path("/");
+ else
+ pathRet = fs::path(pszHome);
#ifdef MAC_OSX
// Mac
- strHome += "Library/Application Support/";
- filesystem::create_directory(strHome.c_str());
- return strHome + "Bitcoin";
+ pathRet /= "Library/Application Support";
+ filesystem::create_directory(pathRet);
+ return pathRet / "Bitcoin";
#else
// Unix
- return strHome + ".bitcoin";
+ return pathRet / ".bitcoin";
#endif
#endif
}
-void GetDataDir(char* pszDir)
+const boost::filesystem::path &GetDataDir(bool fNetSpecific)
{
- // pszDir must be at least MAX_PATH length.
- int nVariation;
- if (pszSetDataDir[0] != 0)
- {
- strlcpy(pszDir, pszSetDataDir, MAX_PATH);
- nVariation = 0;
- }
- else
- {
- // This can be called during exceptions by printf, so we cache the
- // value so we don't have to do memory allocations after that.
- static char pszCachedDir[MAX_PATH];
- if (pszCachedDir[0] == 0)
- strlcpy(pszCachedDir, GetDefaultDataDir().c_str(), sizeof(pszCachedDir));
- strlcpy(pszDir, pszCachedDir, MAX_PATH);
- nVariation = 1;
- }
- if (fTestNet)
- {
- char* p = pszDir + strlen(pszDir);
- if (p > pszDir && p[-1] != '/' && p[-1] != '\\')
- *p++ = '/';
- strcpy(p, "testnet");
- nVariation += 2;
- }
- static bool pfMkdir[4];
- if (!pfMkdir[nVariation])
- {
- pfMkdir[nVariation] = true;
- boost::filesystem::create_directory(pszDir);
+ namespace fs = boost::filesystem;
+
+ static fs::path pathCached[2];
+ static CCriticalSection csPathCached;
+ static bool cachedPath[2] = {false, false};
+
+ fs::path &path = pathCached[fNetSpecific];
+
+ // This can be called during exceptions by printf, so we cache the
+ // value so we don't have to do memory allocations after that.
+ if (cachedPath[fNetSpecific])
+ return path;
+
+ LOCK(csPathCached);
+
+ if (mapArgs.count("-datadir")) {
+ path = fs::system_complete(mapArgs["-datadir"]);
+ if (!fs::is_directory(path)) {
+ path = "";
+ return path;
+ }
+ } else {
+ path = GetDefaultDataDir();
}
-}
+ if (fNetSpecific && GetBoolArg("-testnet", false))
+ path /= "testnet";
-string GetDataDir()
-{
- char pszDir[MAX_PATH];
- GetDataDir(pszDir);
- return pszDir;
+ fs::create_directory(path);
+
+ cachedPath[fNetSpecific]=true;
+ return path;
}
-string GetConfigFile()
+boost::filesystem::path GetConfigFile()
{
namespace fs = boost::filesystem;
- fs::path pathConfig(GetArg("-conf", "bitcoin.conf"));
- if (!pathConfig.is_complete())
- pathConfig = fs::path(GetDataDir()) / pathConfig;
- return pathConfig.string();
+
+ fs::path pathConfigFile(GetArg("-conf", "bitcoin.conf"));
+ if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile;
+ return pathConfigFile;
}
-bool ReadConfigFile(map<string, string>& mapSettingsRet,
+void ReadConfigFile(map<string, string>& mapSettingsRet,
map<string, vector<string> >& mapMultiSettingsRet)
{
namespace fs = boost::filesystem;
namespace pod = boost::program_options::detail;
- if (mapSettingsRet.count("-datadir"))
- {
- if (fs::is_directory(fs::system_complete(mapSettingsRet["-datadir"])))
- {
- fs::path pathDataDir = fs::system_complete(mapSettingsRet["-datadir"]);
- strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));
- }
- else
- {
- return false;
- }
- }
-
fs::ifstream streamConfig(GetConfigFile());
if (!streamConfig.good())
- return true; // No bitcoin.conf file is OK
+ return; // No bitcoin.conf file is OK
set<string> setOptions;
setOptions.insert("*");
-
+
for (pod::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
{
// Don't overwrite existing settings so command line settings override bitcoin.conf
}
mapMultiSettingsRet[strKey].push_back(it->value[0]);
}
- return true;
}
-string GetPidFile()
+boost::filesystem::path GetPidFile()
{
namespace fs = boost::filesystem;
- fs::path pathConfig(GetArg("-pid", "bitcoind.pid"));
- if (!pathConfig.is_complete())
- pathConfig = fs::path(GetDataDir()) / pathConfig;
- return pathConfig.string();
+
+ fs::path pathPidFile(GetArg("-pid", "bitcoind.pid"));
+ if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;
+ return pathPidFile;
}
-void CreatePidFile(string pidFile, pid_t pid)
+void CreatePidFile(const boost::filesystem::path &path, pid_t pid)
{
- FILE* file = fopen(pidFile.c_str(), "w");
+ FILE* file = fopen(path.string().c_str(), "w");
if (file)
{
fprintf(file, "%d\n", pid);
void ShrinkDebugFile()
{
// Scroll debug.log if it's getting too big
- string strFile = GetDataDir() + "/debug.log";
- FILE* file = fopen(strFile.c_str(), "r");
+ boost::filesystem::path pathLog = GetDataDir() / "debug.log";
+ FILE* file = fopen(pathLog.string().c_str(), "r");
if (file && GetFilesize(file) > 10 * 1000000)
{
// Restart the file with some of the end
int nBytes = fread(pch, 1, sizeof(pch), file);
fclose(file);
- file = fopen(strFile.c_str(), "w");
+ file = fopen(pathLog.string().c_str(), "w");
if (file)
{
fwrite(pch, 1, nBytes, file);
string strMessage = _("Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly.");
strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str());
- boost::thread(boost::bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1));
+ ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION);
}
}
}
string FormatFullVersion()
{
- string s = FormatVersion(CLIENT_VERSION);
- if (VERSION_IS_BETA) {
- s += "-";
- s += _("beta");
- }
- return s;
+ return CLIENT_BUILD;
}
// Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014)
return ss.str();
}
+#ifdef WIN32
+boost::filesystem::path static StartupShortcutPath()
+{
+ return MyGetSpecialFolderPath(CSIDL_STARTUP, true) / "Bitcoin.lnk";
+}
+
+bool GetStartOnSystemStartup()
+{
+ return filesystem::exists(StartupShortcutPath());
+}
+
+bool SetStartOnSystemStartup(bool fAutoStart)
+{
+ // If the shortcut exists already, remove it for updating
+ boost::filesystem::remove(StartupShortcutPath());
+
+ if (fAutoStart)
+ {
+ CoInitialize(NULL);
+
+ // Get a pointer to the IShellLink interface.
+ IShellLink* psl = NULL;
+ HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
+ CLSCTX_INPROC_SERVER, IID_IShellLink,
+ reinterpret_cast<void**>(&psl));
+
+ if (SUCCEEDED(hres))
+ {
+ // Get the current executable path
+ TCHAR pszExePath[MAX_PATH];
+ GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
+
+ TCHAR pszArgs[5] = TEXT("-min");
+
+ // Set the path to the shortcut target
+ psl->SetPath(pszExePath);
+ PathRemoveFileSpec(pszExePath);
+ psl->SetWorkingDirectory(pszExePath);
+ psl->SetShowCmd(SW_SHOWMINNOACTIVE);
+ psl->SetArguments(pszArgs);
+
+ // Query IShellLink for the IPersistFile interface for
+ // saving the shortcut in persistent storage.
+ IPersistFile* ppf = NULL;
+ hres = psl->QueryInterface(IID_IPersistFile,
+ reinterpret_cast<void**>(&ppf));
+ if (SUCCEEDED(hres))
+ {
+ WCHAR pwsz[MAX_PATH];
+ // Ensure that the string is ANSI.
+ MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH);
+ // Save the link by calling IPersistFile::Save.
+ hres = ppf->Save(pwsz, TRUE);
+ ppf->Release();
+ psl->Release();
+ CoUninitialize();
+ return true;
+ }
+ psl->Release();
+ }
+ CoUninitialize();
+ return false;
+ }
+ return true;
+}
+
+#elif defined(LINUX)
+
+// Follow the Desktop Application Autostart Spec:
+// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
+
+boost::filesystem::path static GetAutostartDir()
+{
+ namespace fs = boost::filesystem;
+
+ char* pszConfigHome = getenv("XDG_CONFIG_HOME");
+ if (pszConfigHome) return fs::path(pszConfigHome) / "autostart";
+ char* pszHome = getenv("HOME");
+ if (pszHome) return fs::path(pszHome) / ".config" / "autostart";
+ return fs::path();
+}
+
+boost::filesystem::path static GetAutostartFilePath()
+{
+ return GetAutostartDir() / "bitcoin.desktop";
+}
+
+bool GetStartOnSystemStartup()
+{
+ boost::filesystem::ifstream optionFile(GetAutostartFilePath());
+ if (!optionFile.good())
+ return false;
+ // Scan through file for "Hidden=true":
+ string line;
+ while (!optionFile.eof())
+ {
+ getline(optionFile, line);
+ if (line.find("Hidden") != string::npos &&
+ line.find("true") != string::npos)
+ return false;
+ }
+ optionFile.close();
+
+ return true;
+}
+
+bool SetStartOnSystemStartup(bool fAutoStart)
+{
+ if (!fAutoStart)
+ boost::filesystem::remove(GetAutostartFilePath());
+ else
+ {
+ char pszExePath[MAX_PATH+1];
+ memset(pszExePath, 0, sizeof(pszExePath));
+ if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
+ return false;
+
+ boost::filesystem::create_directories(GetAutostartDir());
+
+ boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc);
+ if (!optionFile.good())
+ return false;
+ // Write a bitcoin.desktop file to the autostart directory:
+ optionFile << "[Desktop Entry]\n";
+ optionFile << "Type=Application\n";
+ optionFile << "Name=Bitcoin\n";
+ optionFile << "Exec=" << pszExePath << " -min\n";
+ optionFile << "Terminal=false\n";
+ optionFile << "Hidden=false\n";
+ optionFile.close();
+ }
+ return true;
+}
+#else
+
+// TODO: OSX startup stuff; see:
+// http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
+
+bool GetStartOnSystemStartup() { return false; }
+bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
+
+#endif
+
#ifdef DEBUG_LOCKORDER
int sourceLine;
};
-typedef std::vector< std::pair<CCriticalSection*, CLockLocation> > LockStack;
+typedef std::vector< std::pair<void*, CLockLocation> > LockStack;
static boost::interprocess::interprocess_mutex dd_mutex;
-static std::map<std::pair<CCriticalSection*, CCriticalSection*>, LockStack> lockorders;
+static std::map<std::pair<void*, void*>, LockStack> lockorders;
static boost::thread_specific_ptr<LockStack> lockstack;
-static void potential_deadlock_detected(const std::pair<CCriticalSection*, CCriticalSection*>& mismatch, const LockStack& s1, const LockStack& s2)
+static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
printf("POTENTIAL DEADLOCK DETECTED\n");
printf("Previous lock order was:\n");
- BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s2)
+ BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s2)
{
if (i.first == mismatch.first) printf(" (1)");
if (i.first == mismatch.second) printf(" (2)");
printf(" %s\n", i.second.ToString().c_str());
}
printf("Current lock order is:\n");
- BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s1)
+ BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s1)
{
if (i.first == mismatch.first) printf(" (1)");
if (i.first == mismatch.second) printf(" (2)");
}
}
-static void push_lock(CCriticalSection* c, const CLockLocation& locklocation)
+static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
{
bool fOrderOK = true;
if (lockstack.get() == NULL)
(*lockstack).push_back(std::make_pair(c, locklocation));
- BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, (*lockstack))
+ if (!fTry) BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, (*lockstack))
{
if (i.first == c) break;
- std::pair<CCriticalSection*, CCriticalSection*> p1 = std::make_pair(i.first, c);
+ std::pair<void*, void*> p1 = std::make_pair(i.first, c);
if (lockorders.count(p1))
continue;
lockorders[p1] = (*lockstack);
- std::pair<CCriticalSection*, CCriticalSection*> p2 = std::make_pair(c, i.first);
+ std::pair<void*, void*> p2 = std::make_pair(c, i.first);
if (lockorders.count(p2))
{
potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
dd_mutex.unlock();
}
-void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine)
-{
- push_lock(this, CLockLocation(pszName, pszFile, nLine));
-#ifdef DEBUG_LOCKCONTENTION
- bool result = mutex.try_lock();
- if (!result)
- {
- printf("LOCKCONTENTION: %s\n", pszName);
- printf("Locker: %s:%d\n", pszFile, nLine);
- mutex.lock();
- printf("Locked\n");
- }
-#else
- mutex.lock();
-#endif
-}
-void CCriticalSection::Leave()
+void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
- mutex.unlock();
- pop_lock();
-}
-bool CCriticalSection::TryEnter(const char* pszName, const char* pszFile, int nLine)
-{
- push_lock(this, CLockLocation(pszName, pszFile, nLine));
- bool result = mutex.try_lock();
- if (!result) pop_lock();
- return result;
-}
-
-#else
-
-void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine)
-{
-#ifdef DEBUG_LOCKCONTENTION
- bool result = mutex.try_lock();
- if (!result)
- {
- printf("LOCKCONTENTION: %s\n", pszName);
- printf("Locker: %s:%d\n", pszFile, nLine);
- mutex.lock();
- }
-#else
- mutex.lock();
-#endif
-}
-
-void CCriticalSection::Leave()
-{
- mutex.unlock();
+ push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry);
}
-bool CCriticalSection::TryEnter(const char*, const char*, int)
+void LeaveCritical()
{
- bool result = mutex.try_lock();
- return result;
+ pop_lock();
}
#endif /* DEBUG_LOCKORDER */
-
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
+#else
+typedef int pid_t; /* define for windows compatiblity */
#endif
#include <map>
#include <vector>
#include <string>
#include <boost/thread.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <boost/interprocess/sync/interprocess_condition.hpp>
+#include <boost/interprocess/sync/lock_options.hpp>
#include <boost/date_time/gregorian/gregorian_types.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <openssl/sha.h>
#include <openssl/ripemd.h>
-#include "netbase.h"
+#include "netbase.h" // for AddTimeData
typedef long long int64;
typedef unsigned long long uint64;
+static const int64 COIN = 100000000;
+static const int64 CENT = 1000000;
+
#define loop for (;;)
#define BEGIN(a) ((char*)&(a))
#define END(a) ((char*)&((&(a))[1]))
}
#endif
-#if !defined(QT_GUI)
-inline const char* _(const char* psz)
-{
- return psz;
-}
-#endif
-
extern bool fDebug;
extern bool fPrintToConsole;
extern bool fPrintToDebugger;
-extern char pszSetDataDir[MAX_PATH];
extern bool fRequestShutdown;
extern bool fShutdown;
extern bool fDaemon;
void RandAddSeedPerfmon();
int OutputDebugStringF(const char* pszFormat, ...);
int my_snprintf(char* buffer, size_t limit, const char* format, ...);
-std::string strprintf(const std::string &format, ...);
-bool error(const std::string &format, ...);
+
+/* It is not allowed to use va_start with a pass-by-reference argument.
+ (C++ standard, 18.7, paragraph 3). Use a dummy argument to work around this, and use a
+ macro to keep similar semantics.
+*/
+std::string real_strprintf(const std::string &format, int dummy, ...);
+#define strprintf(format, ...) real_strprintf(format, 0, __VA_ARGS__)
+
+bool error(const char *format, ...);
void LogException(std::exception* pex, const char* pszThread);
void PrintException(std::exception* pex, const char* pszThread);
void PrintExceptionContinue(std::exception* pex, const char* pszThread);
bool WildcardMatch(const char* psz, const char* mask);
bool WildcardMatch(const std::string& str, const std::string& mask);
int GetFilesize(FILE* file);
-void GetDataDir(char* pszDirRet);
-std::string GetConfigFile();
-std::string GetPidFile();
-void CreatePidFile(std::string pidFile, pid_t pid);
-bool ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
-#ifdef WIN32
-std::string MyGetSpecialFolderPath(int nFolder, bool fCreate);
-#endif
-std::string GetDefaultDataDir();
-std::string GetDataDir();
+boost::filesystem::path GetDefaultDataDir();
+const boost::filesystem::path &GetDataDir(bool fNetSpecific = true);
+boost::filesystem::path GetConfigFile();
+boost::filesystem::path GetPidFile();
+void CreatePidFile(const boost::filesystem::path &path, pid_t pid);
+void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
+bool GetStartOnSystemStartup();
+bool SetStartOnSystemStartup(bool fAutoStart);
void ShrinkDebugFile();
int GetRandInt(int nMax);
uint64 GetRand(uint64 nMax);
+/** Wrapped boost mutex: supports recursive locking, but no waiting */
+typedef boost::interprocess::interprocess_recursive_mutex CCriticalSection;
-/** Wrapper to automatically initialize mutex. */
-class CCriticalSection
-{
-protected:
- boost::interprocess::interprocess_recursive_mutex mutex;
-public:
- explicit CCriticalSection() { }
- ~CCriticalSection() { }
- void Enter(const char* pszName, const char* pszFile, int nLine);
- void Leave();
- bool TryEnter(const char* pszName, const char* pszFile, int nLine);
-};
+/** Wrapped boost mutex: supports waiting but not recursive locking */
+typedef boost::interprocess::interprocess_mutex CWaitableCriticalSection;
-/** RAII object that acquires mutex. Needed for exception safety. */
-class CCriticalBlock
-{
-protected:
- CCriticalSection* pcs;
+#ifdef DEBUG_LOCKORDER
+void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
+void LeaveCritical();
+#else
+void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
+void static inline LeaveCritical() {}
+#endif
+/** Wrapper around boost::interprocess::scoped_lock */
+template<typename Mutex>
+class CMutexLock
+{
+private:
+ boost::interprocess::scoped_lock<Mutex> lock;
public:
- CCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine)
+
+ void Enter(const char* pszName, const char* pszFile, int nLine)
{
- pcs = &csIn;
- pcs->Enter(pszName, pszFile, nLine);
+ if (!lock.owns())
+ {
+ EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
+#ifdef DEBUG_LOCKCONTENTION
+ if (!lock.try_lock())
+ {
+ printf("LOCKCONTENTION: %s\n", pszName);
+ printf("Locker: %s:%d\n", pszFile, nLine);
+ }
+#endif
+ lock.lock();
+ }
}
- operator bool() const
+ void Leave()
{
- return true;
+ if (lock.owns())
+ {
+ lock.unlock();
+ LeaveCritical();
+ }
}
- ~CCriticalBlock()
+ bool TryEnter(const char* pszName, const char* pszFile, int nLine)
{
- pcs->Leave();
+ if (!lock.owns())
+ {
+ EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
+ lock.try_lock();
+ if (!lock.owns())
+ LeaveCritical();
+ }
+ return lock.owns();
}
-};
-
-#define CRITICAL_BLOCK(cs) \
- if (CCriticalBlock criticalblock = CCriticalBlock(cs, #cs, __FILE__, __LINE__))
-#define ENTER_CRITICAL_SECTION(cs) \
- (cs).Enter(#cs, __FILE__, __LINE__)
-
-#define LEAVE_CRITICAL_SECTION(cs) \
- (cs).Leave()
-
-/** RAII object that tries to acquire mutex. Needed for exception safety. */
-class CTryCriticalBlock
-{
-protected:
- CCriticalSection* pcs;
+ CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::interprocess::defer_lock)
+ {
+ if (fTry)
+ TryEnter(pszName, pszFile, nLine);
+ else
+ Enter(pszName, pszFile, nLine);
+ }
-public:
- CTryCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine)
+ ~CMutexLock()
{
- pcs = (csIn.TryEnter(pszName, pszFile, nLine) ? &csIn : NULL);
+ if (lock.owns())
+ LeaveCritical();
}
- operator bool() const
+ operator bool()
{
- return Entered();
+ return lock.owns();
}
- ~CTryCriticalBlock()
+ boost::interprocess::scoped_lock<Mutex> &GetLock()
{
- if (pcs)
- {
- pcs->Leave();
- }
+ return lock;
}
- bool Entered() const { return pcs != NULL; }
};
-#define TRY_CRITICAL_BLOCK(cs) \
- if (CTryCriticalBlock criticalblock = CTryCriticalBlock(cs, #cs, __FILE__, __LINE__))
-
+typedef CMutexLock<CCriticalSection> CCriticalBlock;
+typedef CMutexLock<CWaitableCriticalSection> CWaitableCriticalBlock;
+typedef boost::interprocess::interprocess_condition CConditionVariable;
+/** Wait for a given condition inside a WAITABLE_CRITICAL_BLOCK */
+#define WAIT(name,condition) \
+ do { while(!(condition)) { (name).wait(waitablecriticalblock.GetLock()); } } while(0)
+/** Notify waiting threads that a condition may hold now */
+#define NOTIFY(name) \
+ do { (name).notify_one(); } while(0)
+#define NOTIFY_ALL(name) \
+ do { (name).notify_all(); } while(0)
+#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
+#define LOCK2(cs1,cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__),criticalblock2(cs2, #cs2, __FILE__, __LINE__)
+#define TRY_LOCK(cs,name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
+#define WAITABLE_LOCK(cs) CWaitableCriticalBlock waitablecriticalblock(cs, #cs, __FILE__, __LINE__)
-// This is exactly like std::string, but with a custom allocator.
-// (secure_allocator<> is defined in serialize.h)
-typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
-
-
+#define ENTER_CRITICAL_SECTION(cs) \
+ { \
+ EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
+ (cs).lock(); \
+ }
+#define LEAVE_CRITICAL_SECTION(cs) \
+ { \
+ (cs).unlock(); \
+ LeaveCritical(); \
+ }
inline std::string i64tostr(int64 n)
template<typename T>
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
{
- if (itbegin == itend)
- return "";
- const unsigned char* pbegin = (const unsigned char*)&itbegin[0];
- const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]);
- std::string str;
- str.reserve((pend-pbegin) * (fSpaces ? 3 : 2));
- for (const unsigned char* p = pbegin; p != pend; p++)
- str += strprintf((fSpaces && p != pend-1 ? "%02x " : "%02x"), *p);
- return str;
+ std::vector<char> rv;
+ static char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+ rv.reserve((itend-itbegin)*3);
+ for(T it = itbegin; it < itend; ++it)
+ {
+ unsigned char val = (unsigned char)(*it);
+ if(fSpaces && it != itbegin)
+ rv.push_back(' ');
+ rv.push_back(hexmap[val>>4]);
+ rv.push_back(hexmap[val&15]);
+ }
+
+ return std::string(rv.begin(), rv.end());
}
inline std::string HexStr(const std::vector<unsigned char>& vch, bool fSpaces=false)
private:
std::vector<T> vValues;
std::vector<T> vSorted;
- int nSize;
+ unsigned int nSize;
public:
- CMedianFilter(int size, T initial_value):
+ CMedianFilter(unsigned int size, T initial_value):
nSize(size)
{
vValues.reserve(size);
-inline bool AffinityBugWorkaround(void(*pfn)(void*))
-{
-#ifdef WIN32
- // Sometimes after a few hours affinity gets stuck on one processor
- DWORD_PTR dwProcessAffinityMask = -1;
- DWORD_PTR dwSystemAffinityMask = -1;
- GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask);
- DWORD dwPrev1 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
- DWORD dwPrev2 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
- if (dwPrev2 != dwProcessAffinityMask)
- {
- printf("AffinityBugWorkaround() : SetThreadAffinityMask=%d, ProcessAffinityMask=%d, restarting thread\n", dwPrev2, dwProcessAffinityMask);
- if (!CreateThread(pfn, NULL))
- printf("Error: CreateThread() failed\n");
- return true;
- }
-#endif
- return false;
-}
-
inline uint32_t ByteReverse(uint32_t value)
{
value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
--- /dev/null
+// Copyright (c) 2012 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 <string>
+
+#include "version.h"
+
+// Name of client reported in the 'version' message. Report the same name
+// for both bitcoind and bitcoin-qt, to make it harder for attackers to
+// target servers or GUI users specifically.
+const std::string CLIENT_NAME("Satoshi");
+
+// Client version number
+#define CLIENT_VERSION_SUFFIX "-beta"
+
+
+// The following part of the code determines the CLIENT_BUILD variable.
+// Several mechanisms are used for this:
+// * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is
+// generated by the build environment, possibly containing the output
+// of git-describe in a macro called BUILD_DESC
+// * secondly, if this is an exported version of the code, GIT_ARCHIVE will
+// be defined (automatically using the export-subst git attribute), and
+// GIT_COMMIT will contain the commit id.
+// * then, three options exist for determining CLIENT_BUILD:
+// * if BUILD_DESC is defined, use that literally (output of git-describe)
+// * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit]
+// * otherwise, use v[maj].[min].[rev].[build]-unk
+// finally CLIENT_VERSION_SUFFIX is added
+
+// First, include build.h if requested
+#ifdef HAVE_BUILD_INFO
+# include "build.h"
+#endif
+
+// git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$
+#ifdef GIT_ARCHIVE
+# define GIT_COMMIT_ID "$Format:%h$"
+# define GIT_COMMIT_DATE "$Format:%cD"
+#endif
+
+#define STRINGIFY(s) #s
+
+#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
+ "v" STRINGIFY(maj) "." STRINGIFY(min) "." STRINGIFY(rev) "." STRINGIFY(build) "-g" commit
+
+#define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \
+ "v" STRINGIFY(maj) "." STRINGIFY(min) "." STRINGIFY(rev) "." STRINGIFY(build) "-unk"
+
+#ifndef BUILD_DESC
+# ifdef GIT_COMMIT_ID
+# define BUILD_DESC BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)
+# else
+# define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD)
+# endif
+#endif
+
+#ifndef BUILD_DATE
+# ifdef GIT_COMMIT_DATE
+# define BUILD_DATE GIT_COMMIT_DATE
+# else
+# define BUILD_DATE __DATE__ ", " __TIME__
+# endif
+#endif
+
+const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
+const std::string CLIENT_DATE(BUILD_DATE);
--- /dev/null
+// Copyright (c) 2012 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_VERSION_H
+#define BITCOIN_VERSION_H
+
+#include <string>
+
+//
+// client versioning
+//
+
+static const int CLIENT_VERSION_MAJOR = 0;
+static const int CLIENT_VERSION_MINOR = 6;
+static const int CLIENT_VERSION_REVISION = 1;
+static const int CLIENT_VERSION_BUILD = 3;
+
+static const int CLIENT_VERSION =
+ 1000000 * CLIENT_VERSION_MAJOR
+ + 10000 * CLIENT_VERSION_MINOR
+ + 100 * CLIENT_VERSION_REVISION
+ + 1 * CLIENT_VERSION_BUILD;
+
+extern const std::string CLIENT_NAME;
+extern const std::string CLIENT_BUILD;
+extern const std::string CLIENT_DATE;
+
+//
+// network protocol versioning
+//
+
+static const int PROTOCOL_VERSION = 60001;
+
+// earlier versions not supported as of Feb 2012, and are disconnected
+static const int MIN_PROTO_VERSION = 209;
+
+// nTime field added to CAddress, starting with this version;
+// if possible, avoid requesting addresses nodes older than this
+static const int CADDR_TIME_VERSION = 31402;
+
+// only request blocks from nodes outside this range of versions
+static const int NOBLKS_VERSION_START = 32000;
+static const int NOBLKS_VERSION_END = 32400;
+
+// BIP 0031, pong message, is enabled for all versions AFTER this one
+static const int BIP0031_VERSION = 60000;
+
+#endif
--- a/src/version.h
// 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 "db.h"
+#include "wallet.h"
+#include "walletdb.h"
#include "crypter.h"
+#include "ui_interface.h"
using namespace std;
return false;
if (!fFileBacked)
return true;
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
if (pwalletdbEncryption)
return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
else
CCrypter crypter;
CKeyingMaterial vMasterKey;
- CRITICAL_BLOCK(cs_wallet)
+ {
+ LOCK(cs_wallet);
BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
if (CCryptoKeyStore::Unlock(vMasterKey))
return true;
}
+ }
return false;
}
{
bool fWasLocked = IsLocked();
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
Lock();
CCrypter crypter;
return false;
}
+void CWallet::SetBestChain(const CBlockLocator& loc)
+{
+ CWalletDB walletdb(strWalletFile);
+ walletdb.WriteBestBlock(loc);
+}
// This class implements an addrIncoming entry that causes pre-0.4
// clients to crash on startup if reading a private-key-encrypted wallet.
if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
return false;
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
if (fFileBacked)
{
// Anytime a signature is successfully verified, it's proof the outpoint is spent.
// Update the wallet spent flag if it doesn't know due to wallet.dat being
// restored from backup or the user making copies of wallet.dat.
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
void CWallet::MarkDirty()
{
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
item.second.MarkDirty();
}
bool CWallet::AddToWallet(const CWalletTx& wtxIn)
{
uint256 hash = wtxIn.GetHash();
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
// Inserts only if not already there, returns tx inserted or tx found
pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
CWalletTx& wtx = (*ret.first).second;
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock)
{
uint256 hash = tx.GetHash();
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
bool fExisted = mapWallet.count(hash);
if (fExisted && !fUpdate) return false;
if (fExisted || IsMine(tx) || IsFromMe(tx))
{
if (!fFileBacked)
return false;
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
if (mapWallet.erase(hash))
CWalletDB(strWalletFile).EraseTx(hash);
}
bool CWallet::IsMine(const CTxIn &txin) const
{
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
{
int64 CWallet::GetDebit(const CTxIn &txin) const
{
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
{
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
// which output, if any, was change).
if (ExtractAddress(txout.scriptPubKey, address) && HaveKey(address))
- CRITICAL_BLOCK(cs_wallet)
- if (!mapAddressBook.count(address))
- return true;
+ {
+ LOCK(cs_wallet);
+ if (!mapAddressBook.count(address))
+ return true;
+ }
return false;
}
{
// Returns -1 if it wasn't being tracked
int nRequests = -1;
- CRITICAL_BLOCK(pwallet->cs_wallet)
{
+ LOCK(pwallet->cs_wallet);
if (IsCoinBase())
{
// Generated block
nSent += s.second;
nFee = allFee;
}
- CRITICAL_BLOCK(pwallet->cs_wallet)
{
+ LOCK(pwallet->cs_wallet);
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
{
if (pwallet->mapAddressBook.count(r.first))
vWorkQueue.push_back(txin.prevout.hash);
// This critsect is OK because txdb is already open
- CRITICAL_BLOCK(pwallet->cs_wallet)
{
+ LOCK(pwallet->cs_wallet);
map<uint256, const CMerkleTx*> mapWalletPrev;
set<uint256> setAlreadyDone;
for (unsigned int i = 0; i < vWorkQueue.size(); i++)
int ret = 0;
CBlockIndex* pindex = pindexStart;
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
while (pindex)
{
CBlock block;
{
CTxDB txdb("r");
bool fRepeat = true;
- while (fRepeat) CRITICAL_BLOCK(cs_wallet)
+ while (fRepeat)
{
+ LOCK(cs_wallet);
fRepeat = false;
vector<CDiskTxPos> vMissingTx;
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
// Rebroadcast any of our txes that aren't in a block yet
printf("ResendWalletTransactions()\n");
CTxDB txdb("r");
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
// Sort them in chronological order
multimap<unsigned int, CWalletTx*> mapSorted;
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
int64 CWallet::GetBalance() const
{
int64 nTotal = 0;
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
int64 CWallet::GetUnconfirmedBalance() const
{
int64 nTotal = 0;
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
int64 nTotalLower = 0;
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
vector<const CWalletTx*> vCoins;
vCoins.reserve(mapWallet.size());
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
wtxNew.BindWallet(this);
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK2(cs_main, cs_wallet);
// txdb must be opened before the mapWallet lock
CTxDB txdb("r");
{
return false;
// Limit size
- unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
+ unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
return false;
dPriority /= nBytes;
// Call after CreateTransaction unless you want to abort
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
{
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK2(cs_main, cs_wallet);
printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
{
// This is only to keep the database open to defeat the auto-flush for the
return strError;
}
- if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
+ if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending...")))
return "ABORTED";
if (!CommitTransaction(wtxNew, reservekey))
bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName)
{
mapAddressBook[address] = strName;
+ AddressBookRepaint();
if (!fFileBacked)
return false;
return CWalletDB(strWalletFile).WriteName(address.ToString(), strName);
bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
{
mapAddressBook.erase(address);
+ AddressBookRepaint();
if (!fFileBacked)
return false;
return CWalletDB(strWalletFile).EraseName(address.ToString());
void CWallet::PrintWallet(const CBlock& block)
{
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
if (mapWallet.count(block.vtx[0].GetHash()))
{
CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
{
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
if (mi != mapWallet.end())
{
//
bool CWallet::NewKeyPool()
{
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
CWalletDB walletdb(strWalletFile);
BOOST_FOREACH(int64 nIndex, setKeyPool)
walletdb.ErasePool(nIndex);
bool CWallet::TopUpKeyPool()
{
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
+
if (IsLocked())
return false;
CWalletDB walletdb(strWalletFile);
// Top up key pool
- int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
- while (setKeyPool.size() < nTargetSize+1)
+ unsigned int nTargetSize = max(GetArg("-keypool", 100), 0LL);
+ while (setKeyPool.size() < (nTargetSize + 1))
{
int64 nEnd = 1;
if (!setKeyPool.empty())
{
nIndex = -1;
keypool.vchPubKey.clear();
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
+
if (!IsLocked())
TopUpKeyPool();
int64 CWallet::AddReserveKey(const CKeyPool& keypool)
{
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK2(cs_main, cs_wallet);
CWalletDB walletdb(strWalletFile);
int64 nIndex = 1 + *(--setKeyPool.end());
void CWallet::ReturnKey(int64 nIndex)
{
// Return to key pool
- CRITICAL_BLOCK(cs_wallet)
+ {
+ LOCK(cs_wallet);
setKeyPool.insert(nIndex);
+ }
printf("keypool return %"PRI64d"\n", nIndex);
}
{
int64 nIndex = 0;
CKeyPool keypool;
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex == -1)
{
CWalletDB walletdb(strWalletFile);
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(cs_wallet)
+ LOCK2(cs_main, cs_wallet);
BOOST_FOREACH(const int64& id, setKeyPool)
{
CKeyPool keypool;
#ifndef BITCOIN_WALLET_H
#define BITCOIN_WALLET_H
-#include "bignum.h"
+#include "main.h"
#include "key.h"
#include "keystore.h"
#include "script.h"
FEATURE_LATEST = 60000
};
+
+/** A key pool entry */
+class CKeyPool
+{
+public:
+ int64 nTime;
+ std::vector<unsigned char> vchPubKey;
+
+ CKeyPool()
+ {
+ nTime = GetTime();
+ }
+
+ CKeyPool(const std::vector<unsigned char>& vchPubKeyIn)
+ {
+ nTime = GetTime();
+ vchPubKey = vchPubKeyIn;
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ READWRITE(nTime);
+ READWRITE(vchPubKey);
+ )
+};
+
/** A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
*/
}
return nChange;
}
- void SetBestChain(const CBlockLocator& loc)
- {
- CWalletDB walletdb(strWalletFile);
- walletdb.WriteBestBlock(loc);
- }
+ void SetBestChain(const CBlockLocator& loc);
int LoadWallet(bool& fFirstRunRet);
void UpdatedTransaction(const uint256 &hashTx)
{
- CRITICAL_BLOCK(cs_wallet)
+ {
+ LOCK(cs_wallet);
vWalletUpdated.push_back(hashTx);
+ }
}
void PrintWallet(const CBlock& block);
void Inventory(const uint256 &hash)
{
- CRITICAL_BLOCK(cs_wallet)
{
+ LOCK(cs_wallet);
std::map<uint256, int>::iterator mi = mapRequestCount.find(hash);
if (mi != mapRequestCount.end())
(*mi).second++;
std::vector<char> vfSpent; // which outputs are already spent
// memory only
- mutable char fDebitCached;
- mutable char fCreditCached;
- mutable char fAvailableCreditCached;
- mutable char fChangeCached;
+ mutable bool fDebitCached;
+ mutable bool fCreditCached;
+ mutable bool fAvailableCreditCached;
+ mutable bool fChangeCached;
mutable int64 nDebitCached;
mutable int64 nCreditCached;
mutable int64 nAvailableCreditCached;
mutable int64 nChangeCached;
- // memory only UI hints
- mutable unsigned int nTimeDisplayed;
- mutable int nLinesDisplayed;
- mutable char fConfirmedDisplayed;
-
CWalletTx()
{
Init(NULL);
nCreditCached = 0;
nAvailableCreditCached = 0;
nChangeCached = 0;
- nTimeDisplayed = 0;
- nLinesDisplayed = 0;
- fConfirmedDisplayed = false;
}
IMPLEMENT_SERIALIZE
--- /dev/null
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2012 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 "walletdb.h"
+#include "wallet.h"
+#include <boost/filesystem.hpp>
+
+using namespace std;
+using namespace boost;
+
+
+static uint64 nAccountingEntryNumber = 0;
+
+extern CCriticalSection cs_db;
+extern map<string, int> mapFileUseCount;
+extern void CloseDb(const string& strFile);
+
+//
+// CWalletDB
+//
+
+bool CWalletDB::WriteName(const string& strAddress, const string& strName)
+{
+ nWalletDBUpdated++;
+ return Write(make_pair(string("name"), strAddress), strName);
+}
+
+bool CWalletDB::EraseName(const string& strAddress)
+{
+ // This should only be used for sending addresses, never for receiving addresses,
+ // receiving addresses must always have an address book entry if they're not change return.
+ nWalletDBUpdated++;
+ return Erase(make_pair(string("name"), strAddress));
+}
+
+bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
+{
+ account.SetNull();
+ return Read(make_pair(string("acc"), strAccount), account);
+}
+
+bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
+{
+ return Write(make_pair(string("acc"), strAccount), account);
+}
+
+bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
+{
+ return Write(boost::make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry);
+}
+
+int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
+{
+ list<CAccountingEntry> entries;
+ ListAccountCreditDebit(strAccount, entries);
+
+ int64 nCreditDebit = 0;
+ BOOST_FOREACH (const CAccountingEntry& entry, entries)
+ nCreditDebit += entry.nCreditDebit;
+
+ return nCreditDebit;
+}
+
+void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
+{
+ bool fAllAccounts = (strAccount == "*");
+
+ Dbc* pcursor = GetCursor();
+ if (!pcursor)
+ throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
+ unsigned int fFlags = DB_SET_RANGE;
+ loop
+ {
+ // Read next record
+ CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+ if (fFlags == DB_SET_RANGE)
+ ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0));
+ CDataStream ssValue(SER_DISK, CLIENT_VERSION);
+ int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
+ fFlags = DB_NEXT;
+ if (ret == DB_NOTFOUND)
+ break;
+ else if (ret != 0)
+ {
+ pcursor->close();
+ throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB");
+ }
+
+ // Unserialize
+ string strType;
+ ssKey >> strType;
+ if (strType != "acentry")
+ break;
+ CAccountingEntry acentry;
+ ssKey >> acentry.strAccount;
+ if (!fAllAccounts && acentry.strAccount != strAccount)
+ break;
+
+ ssValue >> acentry;
+ entries.push_back(acentry);
+ }
+
+ pcursor->close();
+}
+
+
+int CWalletDB::LoadWallet(CWallet* pwallet)
+{
+ pwallet->vchDefaultKey.clear();
+ int nFileVersion = 0;
+ vector<uint256> vWalletUpgrade;
+ bool fIsEncrypted = false;
+
+ //// todo: shouldn't we catch exceptions and try to recover and continue?
+ {
+ LOCK(pwallet->cs_wallet);
+ int nMinVersion = 0;
+ if (Read((string)"minversion", nMinVersion))
+ {
+ if (nMinVersion > CLIENT_VERSION)
+ return DB_TOO_NEW;
+ pwallet->LoadMinVersion(nMinVersion);
+ }
+
+ // Get cursor
+ Dbc* pcursor = GetCursor();
+ if (!pcursor)
+ {
+ printf("Error getting wallet database cursor\n");
+ return DB_CORRUPT;
+ }
+
+ loop
+ {
+ // Read next record
+ CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+ CDataStream ssValue(SER_DISK, CLIENT_VERSION);
+ int ret = ReadAtCursor(pcursor, ssKey, ssValue);
+ if (ret == DB_NOTFOUND)
+ break;
+ else if (ret != 0)
+ {
+ printf("Error reading next record from wallet database\n");
+ return DB_CORRUPT;
+ }
+
+ // Unserialize
+ // Taking advantage of the fact that pair serialization
+ // is just the two items serialized one after the other
+ string strType;
+ ssKey >> strType;
+ if (strType == "name")
+ {
+ string strAddress;
+ ssKey >> strAddress;
+ ssValue >> pwallet->mapAddressBook[strAddress];
+ }
+ else if (strType == "tx")
+ {
+ uint256 hash;
+ ssKey >> hash;
+ CWalletTx& wtx = pwallet->mapWallet[hash];
+ ssValue >> wtx;
+ wtx.BindWallet(pwallet);
+
+ if (wtx.GetHash() != hash)
+ printf("Error in wallet.dat, hash mismatch\n");
+
+ // Undo serialize changes in 31600
+ if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
+ {
+ if (!ssValue.empty())
+ {
+ char fTmp;
+ char fUnused;
+ ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
+ printf("LoadWallet() upgrading tx ver=%d %d '%s' %s\n", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str());
+ wtx.fTimeReceivedIsTxTime = fTmp;
+ }
+ else
+ {
+ printf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str());
+ wtx.fTimeReceivedIsTxTime = 0;
+ }
+ vWalletUpgrade.push_back(hash);
+ }
+
+ //// debug print
+ //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str());
+ //printf(" %12"PRI64d" %s %s %s\n",
+ // wtx.vout[0].nValue,
+ // DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
+ // wtx.hashBlock.ToString().substr(0,20).c_str(),
+ // wtx.mapValue["message"].c_str());
+ }
+ else if (strType == "acentry")
+ {
+ string strAccount;
+ ssKey >> strAccount;
+ uint64 nNumber;
+ ssKey >> nNumber;
+ if (nNumber > nAccountingEntryNumber)
+ nAccountingEntryNumber = nNumber;
+ }
+ else if (strType == "key" || strType == "wkey")
+ {
+ vector<unsigned char> vchPubKey;
+ ssKey >> vchPubKey;
+ CKey key;
+ if (strType == "key")
+ {
+ CPrivKey pkey;
+ ssValue >> pkey;
+ key.SetPubKey(vchPubKey);
+ key.SetPrivKey(pkey);
+ if (key.GetPubKey() != vchPubKey)
+ {
+ printf("Error reading wallet database: CPrivKey pubkey inconsistency\n");
+ return DB_CORRUPT;
+ }
+ if (!key.IsValid())
+ {
+ printf("Error reading wallet database: invalid CPrivKey\n");
+ return DB_CORRUPT;
+ }
+ }
+ else
+ {
+ CWalletKey wkey;
+ ssValue >> wkey;
+ key.SetPubKey(vchPubKey);
+ key.SetPrivKey(wkey.vchPrivKey);
+ if (key.GetPubKey() != vchPubKey)
+ {
+ printf("Error reading wallet database: CWalletKey pubkey inconsistency\n");
+ return DB_CORRUPT;
+ }
+ if (!key.IsValid())
+ {
+ printf("Error reading wallet database: invalid CWalletKey\n");
+ return DB_CORRUPT;
+ }
+ }
+ if (!pwallet->LoadKey(key))
+ {
+ printf("Error reading wallet database: LoadKey failed\n");
+ return DB_CORRUPT;
+ }
+ }
+ else if (strType == "mkey")
+ {
+ unsigned int nID;
+ ssKey >> nID;
+ CMasterKey kMasterKey;
+ ssValue >> kMasterKey;
+ if(pwallet->mapMasterKeys.count(nID) != 0)
+ {
+ printf("Error reading wallet database: duplicate CMasterKey id %u\n", nID);
+ return DB_CORRUPT;
+ }
+ pwallet->mapMasterKeys[nID] = kMasterKey;
+ if (pwallet->nMasterKeyMaxID < nID)
+ pwallet->nMasterKeyMaxID = nID;
+ }
+ else if (strType == "ckey")
+ {
+ vector<unsigned char> vchPubKey;
+ ssKey >> vchPubKey;
+ vector<unsigned char> vchPrivKey;
+ ssValue >> vchPrivKey;
+ if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
+ {
+ printf("Error reading wallet database: LoadCryptedKey failed\n");
+ return DB_CORRUPT;
+ }
+ fIsEncrypted = true;
+ }
+ else if (strType == "defaultkey")
+ {
+ ssValue >> pwallet->vchDefaultKey;
+ }
+ else if (strType == "pool")
+ {
+ int64 nIndex;
+ ssKey >> nIndex;
+ pwallet->setKeyPool.insert(nIndex);
+ }
+ else if (strType == "version")
+ {
+ ssValue >> nFileVersion;
+ if (nFileVersion == 10300)
+ nFileVersion = 300;
+ }
+ else if (strType == "cscript")
+ {
+ uint160 hash;
+ ssKey >> hash;
+ CScript script;
+ ssValue >> script;
+ if (!pwallet->LoadCScript(script))
+ {
+ printf("Error reading wallet database: LoadCScript failed\n");
+ return DB_CORRUPT;
+ }
+ }
+ }
+ pcursor->close();
+ }
+
+ BOOST_FOREACH(uint256 hash, vWalletUpgrade)
+ WriteTx(hash, pwallet->mapWallet[hash]);
+
+ printf("nFileVersion = %d\n", nFileVersion);
+
+
+ // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
+ if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000))
+ return DB_NEED_REWRITE;
+
+ if (nFileVersion < CLIENT_VERSION) // Update
+ WriteVersion(CLIENT_VERSION);
+
+ return DB_LOAD_OK;
+}
+
+void ThreadFlushWalletDB(void* parg)
+{
+ const string& strFile = ((const string*)parg)[0];
+ static bool fOneThread;
+ if (fOneThread)
+ return;
+ fOneThread = true;
+ if (!GetBoolArg("-flushwallet", true))
+ return;
+
+ unsigned int nLastSeen = nWalletDBUpdated;
+ unsigned int nLastFlushed = nWalletDBUpdated;
+ int64 nLastWalletUpdate = GetTime();
+ while (!fShutdown)
+ {
+ Sleep(500);
+
+ if (nLastSeen != nWalletDBUpdated)
+ {
+ nLastSeen = nWalletDBUpdated;
+ nLastWalletUpdate = GetTime();
+ }
+
+ if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
+ {
+ TRY_LOCK(cs_db,lockDb);
+ if (lockDb)
+ {
+ // Don't do this if any databases are in use
+ int nRefCount = 0;
+ map<string, int>::iterator mi = mapFileUseCount.begin();
+ while (mi != mapFileUseCount.end())
+ {
+ nRefCount += (*mi).second;
+ mi++;
+ }
+
+ if (nRefCount == 0 && !fShutdown)
+ {
+ map<string, int>::iterator mi = mapFileUseCount.find(strFile);
+ if (mi != mapFileUseCount.end())
+ {
+ printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
+ printf("Flushing wallet.dat\n");
+ nLastFlushed = nWalletDBUpdated;
+ int64 nStart = GetTimeMillis();
+
+ // Flush wallet.dat so it's self contained
+ CloseDb(strFile);
+ dbenv.txn_checkpoint(0, 0, 0);
+ dbenv.lsn_reset(strFile.c_str(), 0);
+
+ mapFileUseCount.erase(mi++);
+ printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart);
+ }
+ }
+ }
+ }
+ }
+}
+
+bool BackupWallet(const CWallet& wallet, const string& strDest)
+{
+ if (!wallet.fFileBacked)
+ return false;
+ while (!fShutdown)
+ {
+ {
+ LOCK(cs_db);
+ if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0)
+ {
+ // Flush log data to the dat file
+ CloseDb(wallet.strWalletFile);
+ dbenv.txn_checkpoint(0, 0, 0);
+ dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0);
+ mapFileUseCount.erase(wallet.strWalletFile);
+
+ // Copy wallet.dat
+ filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile;
+ filesystem::path pathDest(strDest);
+ if (filesystem::is_directory(pathDest))
+ pathDest /= wallet.strWalletFile;
+
+ try {
+#if BOOST_VERSION >= 104000
+ filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
+#else
+ filesystem::copy_file(pathSrc, pathDest);
+#endif
+ printf("copied wallet.dat to %s\n", pathDest.string().c_str());
+ return true;
+ } catch(const filesystem::filesystem_error &e) {
+ printf("error copying wallet.dat to %s - %s\n", pathDest.string().c_str(), e.what());
+ return false;
+ }
+ }
+ }
+ Sleep(100);
+ }
+ return false;
+}
--- /dev/null
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2012 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_WALLETDB_H
+#define BITCOIN_WALLETDB_H
+
+#include "db.h"
+
+class CKeyPool;
+class CAccount;
+class CAccountingEntry;
+
+/** Error statuses for the wallet database */
+enum DBErrors
+{
+ DB_LOAD_OK,
+ DB_CORRUPT,
+ DB_TOO_NEW,
+ DB_LOAD_FAIL,
+ DB_NEED_REWRITE
+};
+
+/** Access to the wallet database (wallet.dat) */
+class CWalletDB : public CDB
+{
+public:
+ CWalletDB(std::string strFilename, const char* pszMode="r+") : CDB(strFilename.c_str(), pszMode)
+ {
+ }
+private:
+ CWalletDB(const CWalletDB&);
+ void operator=(const CWalletDB&);
+public:
+ bool ReadName(const std::string& strAddress, std::string& strName)
+ {
+ strName = "";
+ return Read(std::make_pair(std::string("name"), strAddress), strName);
+ }
+
+ bool WriteName(const std::string& strAddress, const std::string& strName);
+
+ bool EraseName(const std::string& strAddress);
+
+ bool ReadTx(uint256 hash, CWalletTx& wtx)
+ {
+ return Read(std::make_pair(std::string("tx"), hash), wtx);
+ }
+
+ bool WriteTx(uint256 hash, const CWalletTx& wtx)
+ {
+ nWalletDBUpdated++;
+ return Write(std::make_pair(std::string("tx"), hash), wtx);
+ }
+
+ bool EraseTx(uint256 hash)
+ {
+ nWalletDBUpdated++;
+ return Erase(std::make_pair(std::string("tx"), hash));
+ }
+
+ bool ReadKey(const std::vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)
+ {
+ vchPrivKey.clear();
+ return Read(std::make_pair(std::string("key"), vchPubKey), vchPrivKey);
+ }
+
+ bool WriteKey(const std::vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
+ {
+ nWalletDBUpdated++;
+ return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
+ }
+
+ bool WriteCryptedKey(const std::vector<unsigned char>& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
+ {
+ nWalletDBUpdated++;
+ if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
+ return false;
+ if (fEraseUnencryptedKey)
+ {
+ Erase(std::make_pair(std::string("key"), vchPubKey));
+ Erase(std::make_pair(std::string("wkey"), vchPubKey));
+ }
+ return true;
+ }
+
+ bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
+ {
+ nWalletDBUpdated++;
+ return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
+ }
+
+ // Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013
+ bool ReadCScript(const uint160 &hash, CScript& redeemScript)
+ {
+ redeemScript.clear();
+ return Read(std::make_pair(std::string("cscript"), hash), redeemScript);
+ }
+
+ bool WriteCScript(const uint160& hash, const CScript& redeemScript)
+ {
+ nWalletDBUpdated++;
+ return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
+ }
+
+ bool WriteBestBlock(const CBlockLocator& locator)
+ {
+ nWalletDBUpdated++;
+ return Write(std::string("bestblock"), locator);
+ }
+
+ bool ReadBestBlock(CBlockLocator& locator)
+ {
+ return Read(std::string("bestblock"), locator);
+ }
+
+ bool ReadDefaultKey(std::vector<unsigned char>& vchPubKey)
+ {
+ vchPubKey.clear();
+ return Read(std::string("defaultkey"), vchPubKey);
+ }
+
+ bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey)
+ {
+ nWalletDBUpdated++;
+ return Write(std::string("defaultkey"), vchPubKey);
+ }
+
+ bool ReadPool(int64 nPool, CKeyPool& keypool)
+ {
+ return Read(std::make_pair(std::string("pool"), nPool), keypool);
+ }
+
+ bool WritePool(int64 nPool, const CKeyPool& keypool)
+ {
+ nWalletDBUpdated++;
+ return Write(std::make_pair(std::string("pool"), nPool), keypool);
+ }
+
+ bool ErasePool(int64 nPool)
+ {
+ nWalletDBUpdated++;
+ return Erase(std::make_pair(std::string("pool"), nPool));
+ }
+
+ // Settings are no longer stored in wallet.dat; these are
+ // used only for backwards compatibility:
+ template<typename T>
+ bool ReadSetting(const std::string& strKey, T& value)
+ {
+ return Read(std::make_pair(std::string("setting"), strKey), value);
+ }
+ template<typename T>
+ bool WriteSetting(const std::string& strKey, const T& value)
+ {
+ nWalletDBUpdated++;
+ return Write(std::make_pair(std::string("setting"), strKey), value);
+ }
+ bool EraseSetting(const std::string& strKey)
+ {
+ nWalletDBUpdated++;
+ return Erase(std::make_pair(std::string("setting"), strKey));
+ }
+
+ bool WriteMinVersion(int nVersion)
+ {
+ return Write(std::string("minversion"), nVersion);
+ }
+
+ bool ReadAccount(const std::string& strAccount, CAccount& account);
+ bool WriteAccount(const std::string& strAccount, const CAccount& account);
+ bool WriteAccountingEntry(const CAccountingEntry& acentry);
+ int64 GetAccountCreditDebit(const std::string& strAccount);
+ void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
+
+ int LoadWallet(CWallet* pwallet);
+};
+
+#endif // BITCOIN_WALLETDB_H