Merge branch 'master' into async-ipv6-rpc

Conflicts:
	src/bitcoinrpc.cpp

Signed-off-by: Giel van Schijndel <me@mortis.eu>
This commit is contained in:
Giel van Schijndel 2012-06-17 14:30:37 +02:00
commit 07368a9e3c
123 changed files with 41314 additions and 24934 deletions

View file

@ -234,7 +234,8 @@ FORMS += \
src/qt/forms/sendcoinsentry.ui \ src/qt/forms/sendcoinsentry.ui \
src/qt/forms/askpassphrasedialog.ui \ src/qt/forms/askpassphrasedialog.ui \
src/qt/forms/rpcconsole.ui \ src/qt/forms/rpcconsole.ui \
src/qt/forms/verifymessagedialog.ui src/qt/forms/verifymessagedialog.ui \
src/qt/forms/optionsdialog.ui
contains(USE_QRCODE, 1) { contains(USE_QRCODE, 1) {
HEADERS += src/qt/qrcodedialog.h HEADERS += src/qt/qrcodedialog.h

View file

@ -0,0 +1,115 @@
# bash programmable completion for bitcoind(1)
# Copyright (c) 2012 Christian von Roques <roques@mti.ag>
# Distributed under the MIT/X11 software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
have bitcoind && {
# call $bitcoind for RPC
_bitcoin_rpc() {
# determine already specified args necessary for RPC
local rpcargs=()
for i in ${COMP_LINE}; do
case "$i" in
-conf=*|-proxy*|-rpc*)
rpcargs=( "${rpcargs[@]}" "$i" )
;;
esac
done
$bitcoind "${rpcargs[@]}" "$@"
}
# Add bitcoin accounts to COMPREPLY
_bitcoin_accounts() {
local accounts
accounts=$(_bitcoin_rpc listaccounts | awk '/".*"/ { a=$1; gsub(/"/, "", a); print a}')
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "$accounts" -- "$cur" ) )
}
_bitcoind() {
local cur prev words=() cword
local bitcoind
# save and use original argument to invoke bitcoind
# bitcoind might not be in $PATH
bitcoind="$1"
COMPREPLY=()
_get_comp_words_by_ref -n = cur prev words cword
if ((cword > 2)); then
case ${words[cword-2]} in
listreceivedbyaccount|listreceivedbyaddress)
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
return 0
;;
move|setaccount)
_bitcoin_accounts
return 0
;;
esac
fi
case "$prev" in
backupwallet)
_filedir
return 0
;;
setgenerate)
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
return 0
;;
getaccountaddress|getaddressesbyaccount|getbalance|getnewaddress|getreceivedbyaccount|listtransactions|move|sendfrom|sendmany)
_bitcoin_accounts
return 0
;;
esac
case "$cur" in
-conf=*|-pid=*|-rpcsslcertificatechainfile=*|-rpcsslprivatekeyfile=*)
cur="${cur#*=}"
_filedir
return 0
;;
-datadir=*)
cur="${cur#*=}"
_filedir -d
return 0
;;
-*=*) # prevent nonsense completions
return 0
;;
*)
local helpopts commands
# only parse --help if senseful
if [[ -z "$cur" || "$cur" =~ ^- ]]; then
helpopts=$($bitcoind --help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' )
fi
# only parse help if senseful
if [[ -z "$cur" || "$cur" =~ ^[a-z] ]]; then
commands=$(_bitcoin_rpc help 2>/dev/null | awk '{ print $1; }')
fi
COMPREPLY=( $( compgen -W "$helpopts $commands" -- "$cur" ) )
# Prevent space if an argument is desired
if [[ $COMPREPLY == *= ]]; then
compopt -o nospace
fi
return 0
;;
esac
}
complete -F _bitcoind bitcoind
}
# Local variables:
# mode: shell-script
# sh-basic-offset: 4
# sh-indent-comment: t
# indent-tabs-mode: nil
# End:
# ex: ts=4 sw=4 et filetype=sh

View file

@ -1,16 +0,0 @@
#!/bin/sh
set -e
umask 077
basedir=~/.bitcoin
dbfile="$basedir/DB_CONFIG"
cfgfile="$basedir/bitcoin.conf"
[ -e "$basedir" ] || mkdir "$basedir"
# Bitcoin does not clean up DB log files by default
[ -e "$dbfile" ] || echo 'set_flags DB_LOG_AUTOREMOVE' > "$dbfile"
exec /usr/lib/bitcoin/bitcoin-qt "$@"

View file

@ -5,14 +5,10 @@ set -e
umask 077 umask 077
basedir=~/.bitcoin basedir=~/.bitcoin
dbfile="$basedir/DB_CONFIG"
cfgfile="$basedir/bitcoin.conf" cfgfile="$basedir/bitcoin.conf"
[ -e "$basedir" ] || mkdir "$basedir" [ -e "$basedir" ] || mkdir "$basedir"
[ -e "$cfgfile" ] || perl -le 'print"rpcpassword=",map{(a..z,A..Z,0..9)[rand 62]}0..9' > "$cfgfile" [ -e "$cfgfile" ] || perl -le 'print"rpcpassword=",map{(a..z,A..Z,0..9)[rand 62]}0..9' > "$cfgfile"
# Bitcoin does not clean up DB log files by default
[ -e "$dbfile" ] || echo 'set_flags DB_LOG_AUTOREMOVE' > "$dbfile"
exec /usr/lib/bitcoin/bitcoind "$@" exec /usr/lib/bitcoin/bitcoind "$@"

View file

@ -1,5 +1,4 @@
debian/bin/bitcoin-qt usr/bin bitcoin-qt usr/bin
bitcoin-qt usr/lib/bitcoin
share/pixmaps/bitcoin32.xpm usr/share/pixmaps share/pixmaps/bitcoin32.xpm usr/share/pixmaps
share/pixmaps/bitcoin80.xpm usr/share/pixmaps share/pixmaps/bitcoin80.xpm usr/share/pixmaps
debian/bitcoin-qt.desktop usr/share/applications debian/bitcoin-qt.desktop usr/share/applications

View file

@ -0,0 +1 @@
contrib/bitcoind.bash-completion bitcoind

View file

@ -1,3 +1,15 @@
bitcoin (0.6.2-natty1) natty; urgency=low
* Update package description and launch scripts.
-- Matt Corallo <matt@bluematt.me> Sat, 2 Jun 2012 16:41:00 +0200
bitcoin (0.6.2-natty0) natty; urgency=low
* New upstream release.
-- Matt Corallo <matt@bluematt.me> Tue, 8 May 2012 16:27:00 -0500
bitcoin (0.6.1-natty0) natty; urgency=low bitcoin (0.6.1-natty0) natty; urgency=low
* New upstream release. * New upstream release.

View file

@ -5,6 +5,7 @@ Maintainer: Jonas Smedegaard <dr@jones.dk>
Uploaders: Micah Anderson <micah@debian.org> Uploaders: Micah Anderson <micah@debian.org>
Build-Depends: debhelper, Build-Depends: debhelper,
devscripts, devscripts,
bash-completion,
libboost-system-dev (>> 1.35) | libboost-system1.35-dev, libboost-system-dev (>> 1.35) | libboost-system1.35-dev,
libdb4.8++-dev, libdb4.8++-dev,
libssl-dev, libssl-dev,
@ -35,7 +36,7 @@ Description: peer-to-peer network based digital currency - daemon
By default connects to an IRC network to discover other peers. By default connects to an IRC network to discover other peers.
. .
Full transaction history is stored locally at each client. This Full transaction history is stored locally at each client. This
requires 150+ MB of space, slowly growing. requires 2+ GB of space, slowly growing.
. .
This package provides bitcoind, a combined daemon and CLI tool to This package provides bitcoind, a combined daemon and CLI tool to
interact with the daemon. interact with the daemon.
@ -53,6 +54,6 @@ Description: peer-to-peer network based digital currency - QT GUI
By default connects to an IRC network to discover other peers. By default connects to an IRC network to discover other peers.
. .
Full transaction history is stored locally at each client. This Full transaction history is stored locally at each client. This
requires 150+ MB of space, slowly growing. requires 2+ GB of space, slowly growing.
. .
This package provides bitcoin-qt, a GUI for Bitcoin based on QT. This package provides bitcoin-qt, a GUI for Bitcoin based on QT.

View file

@ -9,7 +9,7 @@ DEB_INSTALL_EXAMPLES_bitcoind += debian/examples/*
DEB_INSTALL_MANPAGES_bitcoind += debian/manpages/* DEB_INSTALL_MANPAGES_bitcoind += debian/manpages/*
%: %:
dh $@ dh --with bash-completion $@
override_dh_auto_build: override_dh_auto_build:
cd src; $(MAKE) -f makefile.unix bitcoind cd src; $(MAKE) -f makefile.unix bitcoind

View file

@ -31,7 +31,7 @@ signers:
weight: 40 weight: 40
name: "Gavin Andresen" name: "Gavin Andresen"
key: gavinandresen key: gavinandresen
71A3B16735405025D447E8F274810B012346C9A6 71A3B16735405025D447E8F274810B012346C9A6:
weight: 40 weight: 40
name: "Wladimir J. van der Laan" name: "Wladimir J. van der Laan"
key: laanwj key: laanwj

View file

@ -31,7 +31,7 @@ signers:
weight: 40 weight: 40
name: "Gavin Andresen" name: "Gavin Andresen"
key: gavinandresen key: gavinandresen
71A3B16735405025D447E8F274810B012346C9A6 71A3B16735405025D447E8F274810B012346C9A6:
weight: 40 weight: 40
name: "Wladimir J. van der Laan" name: "Wladimir J. van der Laan"
key: laanwj key: laanwj

View file

@ -24,7 +24,7 @@ Dependencies
Libraries you need to download separately and build: Libraries you need to download separately and build:
default path download default path download
OpenSSL \openssl-1.0.1b-mgw http://www.openssl.org/source/ OpenSSL \openssl-1.0.1d-mgw http://www.openssl.org/source/
Berkeley DB \db-4.8.30.NC-mgw http://www.oracle.com/technology/software/products/berkeley-db/index.html Berkeley DB \db-4.8.30.NC-mgw http://www.oracle.com/technology/software/products/berkeley-db/index.html
Boost \boost-1.47.0-mgw http://www.boost.org/users/download/ Boost \boost-1.47.0-mgw http://www.boost.org/users/download/
miniupnpc \miniupnpc-1.6-mgw http://miniupnp.tuxfamily.org/files/ miniupnpc \miniupnpc-1.6-mgw http://miniupnp.tuxfamily.org/files/
@ -36,7 +36,7 @@ Boost MIT-like license
miniupnpc New (3-clause) BSD license miniupnpc New (3-clause) BSD license
Versions used in this release: Versions used in this release:
OpenSSL 1.0.1b OpenSSL 1.0.1d
Berkeley DB 4.8.30.NC Berkeley DB 4.8.30.NC
Boost 1.47.0 Boost 1.47.0
miniupnpc 1.6 miniupnpc 1.6
@ -48,7 +48,7 @@ MSYS shell:
un-tar sources with MSYS 'tar xfz' to avoid issue with symlinks (OpenSSL ticket 2377) un-tar sources with MSYS 'tar xfz' to avoid issue with symlinks (OpenSSL ticket 2377)
change 'MAKE' env. variable from 'C:\MinGW32\bin\mingw32-make.exe' to '/c/MinGW32/bin/mingw32-make.exe' change 'MAKE' env. variable from 'C:\MinGW32\bin\mingw32-make.exe' to '/c/MinGW32/bin/mingw32-make.exe'
cd /c/openssl-1.0.1b-mgw cd /c/openssl-1.0.1d-mgw
./config ./config
make make

View file

@ -33,7 +33,7 @@ Dependencies
miniupnpc may be used for UPnP port mapping. It can be downloaded from miniupnpc may be used for UPnP port mapping. It can be downloaded from
http://miniupnp.tuxfamily.org/files/. UPnP support is compiled in and http://miniupnp.tuxfamily.org/files/. UPnP support is compiled in and
turned off by default. Set USE_UPNP to a different value to control this: turned off by default. Set USE_UPNP to a different value to control this:
USE_UPNP= No UPnP support - miniupnp not required USE_UPNP=- No UPnP support - miniupnp not required
USE_UPNP=0 (the default) UPnP support turned off by default at runtime USE_UPNP=0 (the default) UPnP support turned off by default at runtime
USE_UPNP=1 UPnP support turned on by default at runtime USE_UPNP=1 UPnP support turned on by default at runtime

View file

@ -99,6 +99,8 @@
* update wiki download links * update wiki download links
* update wiki changelog: https://en.bitcoin.it/wiki/Changelog
* Commit your signature to gitian.sigs: * Commit your signature to gitian.sigs:
pushd gitian.sigs pushd gitian.sigs
git add ${VERSION}/${SIGNER} git add ${VERSION}/${SIGNER}

33
doc/unit-tests.txt Normal file
View file

@ -0,0 +1,33 @@
Compiling/runing bitcoind unit tests
------------------------------------
bitcoind unit tests are in the src/test/ directory; they
use the Boost::Test unit-testing framework.
To compile and run the tests:
cd src
make -f makefile.unix test_bitcoin # Replace makefile.unix if you're not on unix
./test_bitcoin # Runs the unit tests
If all tests succeed the last line of output will be:
*** No errors detected
To add more tests, add BOOST_AUTO_TEST_CASE's to the existing
.cpp files in the test/ directory or add new .cpp files that
implement new BOOST_AUTO_TEST_SUITE's (the makefiles are
set up to add test/*.cpp to test_bitcoin automatically).
Compiling/running Bitcoin-Qt unit tests
---------------------------------------
Bitcoin-Qt unit tests are in the src/qt/test/ directory; they
use the Qt unit-testing framework.
To compile and run the tests:
qmake bitcoin-qt.pro BITCOIN_QT_TEST=1
make
./bitcoin-qt_test
To add more tests, add them to the src/qt/test/ directory,
the src/qt/test/test_main.cpp file, and bitcoin-qt.pro.

View file

@ -5,6 +5,7 @@ they can be picked up by Qt linguist.
''' '''
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
import glob import glob
import operator
OUT_CPP="src/qt/bitcoinstrings.cpp" OUT_CPP="src/qt/bitcoinstrings.cpp"
EMPTY=['""'] EMPTY=['""']
@ -62,7 +63,8 @@ f.write("""#include <QtGlobal>
#define UNUSED #define UNUSED
#endif #endif
""") """)
f.write('static const char UNUSED *bitcoin_strings[] = {') f.write('static const char UNUSED *bitcoin_strings[] = {\n')
messages.sort(key=operator.itemgetter(0))
for (msgid, msgstr) in messages: for (msgid, msgstr) in messages:
if msgid != EMPTY: if msgid != EMPTY:
f.write('QT_TRANSLATE_NOOP("bitcoin-core", %s),\n' % ('\n'.join(msgid))) f.write('QT_TRANSLATE_NOOP("bitcoin-core", %s),\n' % ('\n'.join(msgid)))

View file

@ -117,7 +117,6 @@ struct zero_after_free_allocator : public std::allocator<T>
}; };
// This is exactly like std::string, but with a custom allocator. // 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; typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
#endif #endif

View file

@ -19,6 +19,7 @@
#include <vector> #include <vector>
#include "bignum.h" #include "bignum.h"
#include "key.h" #include "key.h"
#include "script.h"
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
@ -258,6 +259,18 @@ public:
* Script-hash-addresses have version 5 (or 196 testnet). * Script-hash-addresses have version 5 (or 196 testnet).
* The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
*/ */
class CBitcoinAddress;
class CBitcoinAddressVisitor : public boost::static_visitor<bool>
{
private:
CBitcoinAddress *addr;
public:
CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { }
bool operator()(const CKeyID &id) const;
bool operator()(const CScriptID &id) const;
bool operator()(const CNoDestination &no) const;
};
class CBitcoinAddress : public CBase58Data class CBitcoinAddress : public CBase58Data
{ {
public: public:
@ -269,21 +282,19 @@ public:
SCRIPT_ADDRESS_TEST = 196, SCRIPT_ADDRESS_TEST = 196,
}; };
bool SetHash160(const uint160& hash160) bool Set(const CKeyID &id) {
{ SetData(fTestNet ? PUBKEY_ADDRESS_TEST : PUBKEY_ADDRESS, &id, 20);
SetData(fTestNet ? PUBKEY_ADDRESS_TEST : PUBKEY_ADDRESS, &hash160, 20);
return true; return true;
} }
void SetPubKey(const std::vector<unsigned char>& vchPubKey) bool Set(const CScriptID &id) {
{ SetData(fTestNet ? SCRIPT_ADDRESS_TEST : SCRIPT_ADDRESS, &id, 20);
SetHash160(Hash160(vchPubKey)); return true;
} }
bool SetScriptHash160(const uint160& hash160) bool Set(const CTxDestination &dest)
{ {
SetData(fTestNet ? SCRIPT_ADDRESS_TEST : SCRIPT_ADDRESS, &hash160, 20); return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
return true;
} }
bool IsValid() const bool IsValid() const
@ -315,27 +326,14 @@ public:
} }
return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize; return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize;
} }
bool IsScript() const
{
if (!IsValid())
return false;
if (fTestNet)
return nVersion == SCRIPT_ADDRESS_TEST;
return nVersion == SCRIPT_ADDRESS;
}
CBitcoinAddress() CBitcoinAddress()
{ {
} }
CBitcoinAddress(uint160 hash160In) CBitcoinAddress(const CTxDestination &dest)
{ {
SetHash160(hash160In); Set(dest);
}
CBitcoinAddress(const std::vector<unsigned char>& vchPubKey)
{
SetPubKey(vchPubKey);
} }
CBitcoinAddress(const std::string& strAddress) CBitcoinAddress(const std::string& strAddress)
@ -348,15 +346,58 @@ public:
SetString(pszAddress); SetString(pszAddress);
} }
uint160 GetHash160() const CTxDestination Get() const {
{ if (!IsValid())
assert(vchData.size() == 20); return CNoDestination();
uint160 hash160; switch (nVersion) {
memcpy(&hash160, &vchData[0], 20); case PUBKEY_ADDRESS:
return hash160; case PUBKEY_ADDRESS_TEST: {
uint160 id;
memcpy(&id, &vchData[0], 20);
return CKeyID(id);
}
case SCRIPT_ADDRESS:
case SCRIPT_ADDRESS_TEST: {
uint160 id;
memcpy(&id, &vchData[0], 20);
return CScriptID(id);
}
}
return CNoDestination();
}
bool GetKeyID(CKeyID &keyID) const {
if (!IsValid())
return false;
switch (nVersion) {
case PUBKEY_ADDRESS:
case PUBKEY_ADDRESS_TEST: {
uint160 id;
memcpy(&id, &vchData[0], 20);
keyID = CKeyID(id);
return true;
}
default: return false;
}
}
bool IsScript() const {
if (!IsValid())
return false;
switch (nVersion) {
case SCRIPT_ADDRESS:
case SCRIPT_ADDRESS_TEST: {
return true;
}
default: return false;
}
} }
}; };
bool inline CBitcoinAddressVisitor::operator()(const CKeyID &id) const { return addr->Set(id); }
bool inline CBitcoinAddressVisitor::operator()(const CScriptID &id) const { return addr->Set(id); }
bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const { return false; }
/** A base58-encoded secret key */ /** A base58-encoded secret key */
class CBitcoinSecret : public CBase58Data class CBitcoinSecret : public CBase58Data
{ {

View file

@ -10,6 +10,7 @@
#include "net.h" #include "net.h"
#include "init.h" #include "init.h"
#include "ui_interface.h" #include "ui_interface.h"
#include "base58.h"
#include "bitcoinrpc.h" #include "bitcoinrpc.h"
#undef printf #undef printf
@ -188,10 +189,10 @@ ScriptSigToJSON(const CTxIn& txin, Object& out)
return; return;
txnouttype type; txnouttype type;
vector<CBitcoinAddress> addresses; vector<CTxDestination> addresses;
int nRequired; int nRequired;
if (!ExtractAddresses(txprev.vout[txin.prevout.n].scriptPubKey, type, if (!ExtractDestinations(txprev.vout[txin.prevout.n].scriptPubKey, type,
addresses, nRequired)) addresses, nRequired))
{ {
out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD))); out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
@ -206,8 +207,8 @@ ScriptSigToJSON(const CTxIn& txin, Object& out)
} }
Array a; Array a;
BOOST_FOREACH(const CBitcoinAddress& addr, addresses) BOOST_FOREACH(const CTxDestination& addr, addresses)
a.push_back(addr.ToString()); a.push_back(CBitcoinAddress(addr).ToString());
out.push_back(Pair("addresses", a)); out.push_back(Pair("addresses", a));
} }
@ -215,13 +216,13 @@ void
ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out) ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
{ {
txnouttype type; txnouttype type;
vector<CBitcoinAddress> addresses; vector<CTxDestination> addresses;
int nRequired; int nRequired;
out.push_back(Pair("asm", scriptPubKey.ToString())); out.push_back(Pair("asm", scriptPubKey.ToString()));
out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
if (!ExtractAddresses(scriptPubKey, type, addresses, nRequired)) if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
{ {
out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD))); out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
return; return;
@ -231,8 +232,8 @@ ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
out.push_back(Pair("type", GetTxnOutputType(type))); out.push_back(Pair("type", GetTxnOutputType(type)));
Array a; Array a;
BOOST_FOREACH(const CBitcoinAddress& addr, addresses) BOOST_FOREACH(const CTxDestination& addr, addresses)
a.push_back(addr.ToString()); a.push_back(CBitcoinAddress(addr).ToString());
out.push_back(Pair("addresses", a)); out.push_back(Pair("addresses", a));
} }
@ -439,7 +440,7 @@ Value stop(const Array& params, bool fHelp)
"stop\n" "stop\n"
"Stop Bitcoin server."); "Stop Bitcoin server.");
// Shutdown will take long enough that the response should get back // Shutdown will take long enough that the response should get back
uiInterface.QueueShutdown(); StartShutdown();
return "Bitcoin server stopping"; return "Bitcoin server stopping";
} }
@ -534,6 +535,9 @@ Value getinfo(const Array& params, bool fHelp)
"getinfo\n" "getinfo\n"
"Returns an object containing various state info."); "Returns an object containing various state info.");
CService addrProxy;
GetProxy(NET_IPV4, addrProxy);
Object obj; Object obj;
obj.push_back(Pair("version", (int)CLIENT_VERSION)); obj.push_back(Pair("version", (int)CLIENT_VERSION));
obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION)); obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
@ -541,7 +545,7 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
obj.push_back(Pair("blocks", (int)nBestHeight)); obj.push_back(Pair("blocks", (int)nBestHeight));
obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string()))); obj.push_back(Pair("proxy", (addrProxy.IsValid() ? addrProxy.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("testnet", fTestNet)); obj.push_back(Pair("testnet", fTestNet));
obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
@ -594,14 +598,14 @@ Value getnewaddress(const Array& params, bool fHelp)
pwalletMain->TopUpKeyPool(); pwalletMain->TopUpKeyPool();
// Generate a new key that is added to wallet // Generate a new key that is added to wallet
std::vector<unsigned char> newKey; CPubKey newKey;
if (!pwalletMain->GetKeyFromPool(newKey, false)) if (!pwalletMain->GetKeyFromPool(newKey, false))
throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first"); throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
CBitcoinAddress address(newKey); CKeyID keyID = newKey.GetID();
pwalletMain->SetAddressBookName(address, strAccount); pwalletMain->SetAddressBookName(keyID, strAccount);
return address.ToString(); return CBitcoinAddress(keyID).ToString();
} }
@ -615,12 +619,12 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
bool bKeyUsed = false; bool bKeyUsed = false;
// Check if the current key has been used // Check if the current key has been used
if (!account.vchPubKey.empty()) if (account.vchPubKey.IsValid())
{ {
CScript scriptPubKey; CScript scriptPubKey;
scriptPubKey.SetBitcoinAddress(account.vchPubKey); scriptPubKey.SetDestination(account.vchPubKey.GetID());
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty(); it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
++it) ++it)
{ {
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
@ -631,16 +635,16 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
} }
// Generate a new key // Generate a new key
if (account.vchPubKey.empty() || bForceNew || bKeyUsed) if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
{ {
if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false)) if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first"); throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount); pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
walletdb.WriteAccount(strAccount, account); walletdb.WriteAccount(strAccount, account);
} }
return CBitcoinAddress(account.vchPubKey); return CBitcoinAddress(account.vchPubKey.GetID());
} }
Value getaccountaddress(const Array& params, bool fHelp) Value getaccountaddress(const Array& params, bool fHelp)
@ -679,14 +683,14 @@ Value setaccount(const Array& params, bool fHelp)
strAccount = AccountFromValue(params[1]); strAccount = AccountFromValue(params[1]);
// Detect when changing the account of an address that is the 'unused current key' of another account: // Detect when changing the account of an address that is the 'unused current key' of another account:
if (pwalletMain->mapAddressBook.count(address)) if (pwalletMain->mapAddressBook.count(address.Get()))
{ {
string strOldAccount = pwalletMain->mapAddressBook[address]; string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
if (address == GetAccountAddress(strOldAccount)) if (address == GetAccountAddress(strOldAccount))
GetAccountAddress(strOldAccount, true); GetAccountAddress(strOldAccount, true);
} }
pwalletMain->SetAddressBookName(address, strAccount); pwalletMain->SetAddressBookName(address.Get(), strAccount);
return Value::null; return Value::null;
} }
@ -704,7 +708,7 @@ Value getaccount(const Array& params, bool fHelp)
throw JSONRPCError(-5, "Invalid Bitcoin address"); throw JSONRPCError(-5, "Invalid Bitcoin address");
string strAccount; string strAccount;
map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address); map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty()) if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
strAccount = (*mi).second; strAccount = (*mi).second;
return strAccount; return strAccount;
@ -773,7 +777,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
if (pwalletMain->IsLocked()) if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first."); throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx); string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
if (strError != "") if (strError != "")
throw JSONRPCError(-4, strError); throw JSONRPCError(-4, strError);
@ -796,8 +800,12 @@ Value signmessage(const Array& params, bool fHelp)
if (!addr.IsValid()) if (!addr.IsValid())
throw JSONRPCError(-3, "Invalid address"); throw JSONRPCError(-3, "Invalid address");
CKeyID keyID;
if (!addr.GetKeyID(keyID))
throw JSONRPCError(-3, "Address does not refer to key");
CKey key; CKey key;
if (!pwalletMain->GetKey(addr, key)) if (!pwalletMain->GetKey(keyID, key))
throw JSONRPCError(-4, "Private key not available"); throw JSONRPCError(-4, "Private key not available");
CDataStream ss(SER_GETHASH, 0); CDataStream ss(SER_GETHASH, 0);
@ -826,6 +834,10 @@ Value verifymessage(const Array& params, bool fHelp)
if (!addr.IsValid()) if (!addr.IsValid())
throw JSONRPCError(-3, "Invalid address"); throw JSONRPCError(-3, "Invalid address");
CKeyID keyID;
if (!addr.GetKeyID(keyID))
throw JSONRPCError(-3, "Address does not refer to key");
bool fInvalid = false; bool fInvalid = false;
vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid); vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
@ -840,7 +852,7 @@ Value verifymessage(const Array& params, bool fHelp)
if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig)) if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
return false; return false;
return (CBitcoinAddress(key.GetPubKey()) == addr); return (key.GetPubKey().GetID() == keyID);
} }
@ -856,7 +868,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
CScript scriptPubKey; CScript scriptPubKey;
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(-5, "Invalid Bitcoin address"); throw JSONRPCError(-5, "Invalid Bitcoin address");
scriptPubKey.SetBitcoinAddress(address); scriptPubKey.SetDestination(address.Get());
if (!IsMine(*pwalletMain,scriptPubKey)) if (!IsMine(*pwalletMain,scriptPubKey))
return (double)0.0; return (double)0.0;
@ -883,18 +895,17 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
} }
void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress) void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
{ {
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook) BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
{ {
const CBitcoinAddress& address = item.first; const CTxDestination& address = item.first;
const string& strName = item.second; const string& strName = item.second;
if (strName == strAccount) if (strName == strAccount)
setAddress.insert(address); setAddress.insert(address);
} }
} }
Value getreceivedbyaccount(const Array& params, bool fHelp) Value getreceivedbyaccount(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() < 1 || params.size() > 2) if (fHelp || params.size() < 1 || params.size() > 2)
@ -909,7 +920,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
// Get the set of pub keys assigned to account // Get the set of pub keys assigned to account
string strAccount = AccountFromValue(params[0]); string strAccount = AccountFromValue(params[0]);
set<CBitcoinAddress> setAddress; set<CTxDestination> setAddress;
GetAccountAddresses(strAccount, setAddress); GetAccountAddresses(strAccount, setAddress);
// Tally // Tally
@ -922,8 +933,8 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{ {
CBitcoinAddress address; CTxDestination address;
if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address)) if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
if (wtx.GetDepthInMainChain() >= nMinDepth) if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue; nAmount += txout.nValue;
} }
@ -994,15 +1005,15 @@ Value getbalance(const Array& params, bool fHelp)
int64 allGeneratedImmature, allGeneratedMature, allFee; int64 allGeneratedImmature, allGeneratedMature, allFee;
allGeneratedImmature = allGeneratedMature = allFee = 0; allGeneratedImmature = allGeneratedMature = allFee = 0;
string strSentAccount; string strSentAccount;
list<pair<CBitcoinAddress, int64> > listReceived; list<pair<CTxDestination, int64> > listReceived;
list<pair<CBitcoinAddress, int64> > listSent; list<pair<CTxDestination, int64> > listSent;
wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount); wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
if (wtx.GetDepthInMainChain() >= nMinDepth) if (wtx.GetDepthInMainChain() >= nMinDepth)
{ {
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived) BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
nBalance += r.second; nBalance += r.second;
} }
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent) BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent)
nBalance -= r.second; nBalance -= r.second;
nBalance -= allFee; nBalance -= allFee;
nBalance += allGeneratedMature; nBalance += allGeneratedMature;
@ -1098,7 +1109,7 @@ Value sendfrom(const Array& params, bool fHelp)
throw JSONRPCError(-6, "Account has insufficient funds"); throw JSONRPCError(-6, "Account has insufficient funds");
// Send // Send
string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx); string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
if (strError != "") if (strError != "")
throw JSONRPCError(-4, strError); throw JSONRPCError(-4, strError);
@ -1140,7 +1151,7 @@ Value sendmany(const Array& params, bool fHelp)
setAddress.insert(address); setAddress.insert(address);
CScript scriptPubKey; CScript scriptPubKey;
scriptPubKey.SetBitcoinAddress(address); scriptPubKey.SetDestination(address.Get());
int64 nAmount = AmountFromValue(s.value_); int64 nAmount = AmountFromValue(s.value_);
totalAmount += nAmount; totalAmount += nAmount;
@ -1204,22 +1215,23 @@ Value addmultisigaddress(const Array& params, bool fHelp)
CBitcoinAddress address(ks); CBitcoinAddress address(ks);
if (address.IsValid()) if (address.IsValid())
{ {
if (address.IsScript()) CKeyID keyID;
if (!address.GetKeyID(keyID))
throw runtime_error( throw runtime_error(
strprintf("%s is a pay-to-script address",ks.c_str())); strprintf("%s does not refer to a key",ks.c_str()));
std::vector<unsigned char> vchPubKey; CPubKey vchPubKey;
if (!pwalletMain->GetPubKey(address, vchPubKey)) if (!pwalletMain->GetPubKey(keyID, vchPubKey))
throw runtime_error( throw runtime_error(
strprintf("no full public key for address %s",ks.c_str())); strprintf("no full public key for address %s",ks.c_str()));
if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey)) if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
throw runtime_error(" Invalid public key: "+ks); throw runtime_error(" Invalid public key: "+ks);
} }
// Case 2: hex public key // Case 2: hex public key
else if (IsHex(ks)) else if (IsHex(ks))
{ {
vector<unsigned char> vchPubKey = ParseHex(ks); CPubKey vchPubKey(ParseHex(ks));
if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey)) if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
throw runtime_error(" Invalid public key: "+ks); throw runtime_error(" Invalid public key: "+ks);
} }
else else
@ -1231,16 +1243,11 @@ Value addmultisigaddress(const Array& params, bool fHelp)
// Construct using pay-to-script-hash: // Construct using pay-to-script-hash:
CScript inner; CScript inner;
inner.SetMultisig(nRequired, pubkeys); inner.SetMultisig(nRequired, pubkeys);
CScriptID innerID = inner.GetID();
uint160 scriptHash = Hash160(inner);
CScript scriptPubKey;
scriptPubKey.SetPayToScriptHash(inner);
pwalletMain->AddCScript(inner); pwalletMain->AddCScript(inner);
CBitcoinAddress address;
address.SetScriptHash160(scriptHash);
pwalletMain->SetAddressBookName(address, strAccount); pwalletMain->SetAddressBookName(innerID, strAccount);
return address.ToString(); return CBitcoinAddress(innerID).ToString();
} }
@ -1282,8 +1289,8 @@ Value ListReceived(const Array& params, bool fByAccounts)
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{ {
CBitcoinAddress address; CTxDestination address;
if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid()) if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
continue; continue;
tallyitem& item = mapTally[address]; tallyitem& item = mapTally[address];
@ -1380,8 +1387,8 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
{ {
int64 nGeneratedImmature, nGeneratedMature, nFee; int64 nGeneratedImmature, nGeneratedMature, nFee;
string strSentAccount; string strSentAccount;
list<pair<CBitcoinAddress, int64> > listReceived; list<pair<CTxDestination, int64> > listReceived;
list<pair<CBitcoinAddress, int64> > listSent; list<pair<CTxDestination, int64> > listSent;
wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount); wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
@ -1410,11 +1417,11 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
// Sent // Sent
if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
{ {
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent) BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
{ {
Object entry; Object entry;
entry.push_back(Pair("account", strSentAccount)); entry.push_back(Pair("account", strSentAccount));
entry.push_back(Pair("address", s.first.ToString())); entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString()));
entry.push_back(Pair("category", "send")); entry.push_back(Pair("category", "send"));
entry.push_back(Pair("amount", ValueFromAmount(-s.second))); entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
entry.push_back(Pair("fee", ValueFromAmount(-nFee))); entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
@ -1427,7 +1434,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
// Received // Received
if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
{ {
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived) BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
{ {
string account; string account;
if (pwalletMain->mapAddressBook.count(r.first)) if (pwalletMain->mapAddressBook.count(r.first))
@ -1436,7 +1443,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
{ {
Object entry; Object entry;
entry.push_back(Pair("account", account)); entry.push_back(Pair("account", account));
entry.push_back(Pair("address", r.first.ToString())); entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString()));
entry.push_back(Pair("category", "receive")); entry.push_back(Pair("category", "receive"));
entry.push_back(Pair("amount", ValueFromAmount(r.second))); entry.push_back(Pair("amount", ValueFromAmount(r.second)));
if (fLong) if (fLong)
@ -1551,8 +1558,8 @@ Value listaccounts(const Array& params, bool fHelp)
nMinDepth = params[0].get_int(); nMinDepth = params[0].get_int();
map<string, int64> mapAccountBalances; map<string, int64> mapAccountBalances;
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) { BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
if (pwalletMain->HaveKey(entry.first)) // This address belongs to me if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
mapAccountBalances[entry.second] = 0; mapAccountBalances[entry.second] = 0;
} }
@ -1561,16 +1568,16 @@ Value listaccounts(const Array& params, bool fHelp)
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
int64 nGeneratedImmature, nGeneratedMature, nFee; int64 nGeneratedImmature, nGeneratedMature, nFee;
string strSentAccount; string strSentAccount;
list<pair<CBitcoinAddress, int64> > listReceived; list<pair<CTxDestination, int64> > listReceived;
list<pair<CBitcoinAddress, int64> > listSent; list<pair<CTxDestination, int64> > listSent;
wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount); wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
mapAccountBalances[strSentAccount] -= nFee; mapAccountBalances[strSentAccount] -= nFee;
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent) BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
mapAccountBalances[strSentAccount] -= s.second; mapAccountBalances[strSentAccount] -= s.second;
if (wtx.GetDepthInMainChain() >= nMinDepth) if (wtx.GetDepthInMainChain() >= nMinDepth)
{ {
mapAccountBalances[""] += nGeneratedMature; mapAccountBalances[""] += nGeneratedMature;
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived) BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
if (pwalletMain->mapAddressBook.count(r.first)) if (pwalletMain->mapAddressBook.count(r.first))
mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second; mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
else else
@ -1932,10 +1939,44 @@ Value encryptwallet(const Array& params, bool fHelp)
// BDB seems to have a bad habit of writing old data into // 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 // slack space in .dat files; that is bad if the old data is
// unencrypted private keys. So: // unencrypted private keys. So:
uiInterface.QueueShutdown(); StartShutdown();
return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet"; return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet";
} }
class DescribeAddressVisitor : public boost::static_visitor<Object>
{
public:
Object operator()(const CNoDestination &dest) const { return Object(); }
Object operator()(const CKeyID &keyID) const {
Object obj;
CPubKey vchPubKey;
pwalletMain->GetPubKey(keyID, vchPubKey);
obj.push_back(Pair("isscript", false));
obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
return obj;
}
Object operator()(const CScriptID &scriptID) const {
Object obj;
obj.push_back(Pair("isscript", true));
CScript subscript;
pwalletMain->GetCScript(scriptID, subscript);
std::vector<CTxDestination> addresses;
txnouttype whichType;
int nRequired;
ExtractDestinations(subscript, whichType, addresses, nRequired);
obj.push_back(Pair("script", GetTxnOutputType(whichType)));
Array a;
BOOST_FOREACH(const CTxDestination& addr, addresses)
a.push_back(CBitcoinAddress(addr).ToString());
obj.push_back(Pair("addresses", a));
if (whichType == TX_MULTISIG)
obj.push_back(Pair("sigsrequired", nRequired));
return obj;
}
};
Value validateaddress(const Array& params, bool fHelp) Value validateaddress(const Array& params, bool fHelp)
{ {
@ -1951,42 +1992,17 @@ Value validateaddress(const Array& params, bool fHelp)
ret.push_back(Pair("isvalid", isValid)); ret.push_back(Pair("isvalid", isValid));
if (isValid) if (isValid)
{ {
// Call Hash160ToAddress() so we always return current ADDRESSVERSION CTxDestination dest = address.Get();
// version of the address:
string currentAddress = address.ToString(); string currentAddress = address.ToString();
ret.push_back(Pair("address", currentAddress)); ret.push_back(Pair("address", currentAddress));
if (pwalletMain->HaveKey(address)) bool fMine = IsMine(*pwalletMain, dest);
{ ret.push_back(Pair("ismine", fMine));
ret.push_back(Pair("ismine", true)); if (fMine) {
std::vector<unsigned char> vchPubKey; Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
pwalletMain->GetPubKey(address, vchPubKey); ret.insert(ret.end(), detail.begin(), detail.end());
ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
CKey key;
key.SetPubKey(vchPubKey);
ret.push_back(Pair("iscompressed", key.IsCompressed()));
} }
else if (pwalletMain->HaveCScript(address.GetHash160())) if (pwalletMain->mapAddressBook.count(dest))
{ ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
ret.push_back(Pair("isscript", true));
CScript subscript;
pwalletMain->GetCScript(address.GetHash160(), subscript);
ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
std::vector<CBitcoinAddress> addresses;
txnouttype whichType;
int nRequired;
ExtractAddresses(subscript, whichType, addresses, nRequired);
ret.push_back(Pair("script", GetTxnOutputType(whichType)));
Array a;
BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
a.push_back(addr.ToString());
ret.push_back(Pair("addresses", a));
if (whichType == TX_MULTISIG)
ret.push_back(Pair("sigsrequired", nRequired));
}
else
ret.push_back(Pair("ismine", false));
if (pwalletMain->mapAddressBook.count(address))
ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
} }
return ret; return ret;
} }
@ -2252,7 +2268,7 @@ Value sendrawtx(const Array& params, bool fHelp)
CInv inv(MSG_TX, tx.GetHash()); CInv inv(MSG_TX, tx.GetHash());
RelayInventory(inv); RelayInventory(inv);
return true; return tx.GetHash().GetHex();
} }
@ -2791,7 +2807,7 @@ void ThreadRPCServer2(void* parg)
GetConfigFile().string().c_str(), GetConfigFile().string().c_str(),
EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()), EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
_("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL); _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
uiInterface.QueueShutdown(); StartShutdown();
return; return;
} }
@ -2863,12 +2879,13 @@ void ThreadRPCServer2(void* parg)
{ {
uiInterface.ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()), uiInterface.ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
_("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL); _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
uiInterface.QueueShutdown(); StartShutdown();
return; return;
} }
vnThreadsRunning[THREAD_RPCLISTENER]--; vnThreadsRunning[THREAD_RPCLISTENER]--;
io_service.run(); while (!fShutdown)
io_service.run_one();
vnThreadsRunning[THREAD_RPCLISTENER]++; vnThreadsRunning[THREAD_RPCLISTENER]++;
// Terminate all outstanding accept-requests // Terminate all outstanding accept-requests
@ -3111,24 +3128,11 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]); if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]); if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]); if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "sendmany" && n > 1) if (strMethod == "sendmany" && n > 1) ConvertTo<Object>(params[1]);
{ if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
string s = params[1].get_str(); if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
Value v; if (strMethod == "addmultisigaddress" && n > 1) ConvertTo<Array>(params[1]);
if (!read_string(s, v) || v.type() != obj_type)
throw runtime_error("type mismatch");
params[1] = v.get_obj();
}
if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "addmultisigaddress" && n > 1)
{
string s = params[1].get_str();
Value v;
if (!read_string(s, v) || v.type() != array_type)
throw runtime_error("type mismatch "+s);
params[1] = v.get_array();
}
return params; return params;
} }

View file

@ -35,27 +35,32 @@ namespace Checkpoints
(168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")) (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
; ;
static MapCheckpoints mapCheckpointsTestnet =
boost::assign::map_list_of
( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
;
bool CheckBlock(int nHeight, const uint256& hash) bool CheckBlock(int nHeight, const uint256& hash)
{ {
if (fTestNet) return true; // Testnet has no checkpoints MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
MapCheckpoints::const_iterator i = mapCheckpoints.find(nHeight); MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
if (i == mapCheckpoints.end()) return true; if (i == checkpoints.end()) return true;
return hash == i->second; return hash == i->second;
} }
int GetTotalBlocksEstimate() int GetTotalBlocksEstimate()
{ {
if (fTestNet) return 0; MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
return mapCheckpoints.rbegin()->first; return checkpoints.rbegin()->first;
} }
CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex) CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
{ {
if (fTestNet) return NULL; MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints) BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
{ {
const uint256& hash = i.second; const uint256& hash = i.second;
std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash); std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);

View file

@ -38,6 +38,17 @@ void ExitTimeout(void* parg)
#endif #endif
} }
void StartShutdown()
{
#ifdef QT_GUI
// ensure we leave the Qt main loop for a clean GUI exit (Shutdown() is called in bitcoin.cpp afterwards)
uiInterface.QueueShutdown();
#else
// Without UI, Shutdown() can simply be started in a new thread
CreateThread(Shutdown, NULL);
#endif
}
void Shutdown(void* parg) void Shutdown(void* parg)
{ {
static CCriticalSection cs_Shutdown; static CCriticalSection cs_Shutdown;
@ -66,7 +77,10 @@ void Shutdown(void* parg)
Sleep(50); Sleep(50);
printf("Bitcoin exited\n\n"); printf("Bitcoin exited\n\n");
fExit = true; fExit = true;
#ifndef QT_GUI
// ensure non UI client get's exited here, but let Bitcoin-Qt reach return 0; in bitcoin.cpp
exit(0); exit(0);
#endif
} }
else else
{ {
@ -182,12 +196,15 @@ bool static InitWarning(const std::string &str)
} }
bool static Bind(const CService &addr) { bool static Bind(const CService &addr, bool fError = true) {
if (IsLimited(addr)) if (IsLimited(addr))
return false; return false;
std::string strError; std::string strError;
if (!BindListenPort(addr, strError)) if (!BindListenPort(addr, strError)) {
return InitError(strError); if (fError)
return InitError(strError);
return false;
}
return true; return true;
} }
@ -204,20 +221,18 @@ std::string HelpMessage()
" -dblogsize=<n> " + _("Set database disk log size in megabytes (default: 100)") + "\n" + " -dblogsize=<n> " + _("Set database disk log size in megabytes (default: 100)") + "\n" +
" -timeout=<n> " + _("Specify connection timeout (in milliseconds)") + "\n" + " -timeout=<n> " + _("Specify connection timeout (in milliseconds)") + "\n" +
" -proxy=<ip:port> " + _("Connect through socks proxy") + "\n" + " -proxy=<ip:port> " + _("Connect through socks proxy") + "\n" +
" -socks=<n> " + _("Select the version of socks proxy to use (4 or 5, 5 is default)") + "\n" + " -socks=<n> " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n" +
" -noproxy=<net> " + _("Do not use proxy for connections to network <net> (IPv4 or IPv6)") + "\n" +
" -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n" + " -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n" +
" -proxydns " + _("Pass DNS requests to (SOCKS5) proxy") + "\n" +
" -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n" + " -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n" +
" -maxconnections=<n> " + _("Maintain at most <n> connections to peers (default: 125)") + "\n" + " -maxconnections=<n> " + _("Maintain at most <n> connections to peers (default: 125)") + "\n" +
" -addnode=<ip> " + _("Add a node to connect to and attempt to keep the connection open") + "\n" + " -addnode=<ip> " + _("Add a node to connect to and attempt to keep the connection open") + "\n" +
" -connect=<ip> " + _("Connect only to the specified node") + "\n" + " -connect=<ip> " + _("Connect only to the specified node(s)") + "\n" +
" -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n" + " -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n" +
" -externalip=<ip> " + _("Specify your own public address") + "\n" + " -externalip=<ip> " + _("Specify your own public address") + "\n" +
" -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4 or IPv6)") + "\n" + " -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4 or IPv6)") + "\n" +
" -discover " + _("Try to discover public IP address (default: 1)") + "\n" + " -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n" +
" -irc " + _("Find peers using internet relay chat (default: 0)") + "\n" + " -irc " + _("Find peers using internet relay chat (default: 0)") + "\n" +
" -listen " + _("Accept connections from outside (default: 1)") + "\n" + " -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n" +
" -bind=<addr> " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" + " -bind=<addr> " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" +
" -dnsseed " + _("Find peers using DNS lookup (default: 1)") + "\n" + " -dnsseed " + _("Find peers using DNS lookup (default: 1)") + "\n" +
" -banscore=<n> " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" + " -banscore=<n> " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" +
@ -226,9 +241,9 @@ std::string HelpMessage()
" -maxsendbuffer=<n> " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)") + "\n" + " -maxsendbuffer=<n> " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)") + "\n" +
#ifdef USE_UPNP #ifdef USE_UPNP
#if USE_UPNP #if USE_UPNP
" -upnp " + _("Use Universal Plug and Play to map the listening port (default: 1)") + "\n" + " -upnp " + _("Use UPnP to map the listening port (default: 1 when listening)") + "\n" +
#else #else
" -upnp " + _("Use Universal Plug and Play to map the listening port (default: 0)") + "\n" + " -upnp " + _("Use UPnP to map the listening port (default: 0)") + "\n" +
#endif #endif
#endif #endif
" -detachdb " + _("Detach block and address databases. Increases shutdown time (default: 0)") + "\n" + " -detachdb " + _("Detach block and address databases. Increases shutdown time (default: 0)") + "\n" +
@ -308,30 +323,38 @@ bool AppInit2()
// ********************************************************* Step 2: parameter interactions // ********************************************************* Step 2: parameter interactions
fTestNet = GetBoolArg("-testnet"); fTestNet = GetBoolArg("-testnet");
if (fTestNet) if (fTestNet) {
{
SoftSetBoolArg("-irc", true); SoftSetBoolArg("-irc", true);
} }
if (mapArgs.count("-connect")) if (mapArgs.count("-bind")) {
SoftSetBoolArg("-dnsseed", false); // when specifying an explicit binding address, you want to listen on it
// even when -connect or -proxy is specified
// even in Tor mode, if -bind is specified, you really want -listen
if (mapArgs.count("-bind"))
SoftSetBoolArg("-listen", true); SoftSetBoolArg("-listen", true);
}
bool fTor = (fUseProxy && addrProxy.GetPort() == 9050); if (mapArgs.count("-connect")) {
if (fTor) // when only connecting to trusted nodes, do not seed via DNS, or listen by default
{ SoftSetBoolArg("-dnsseed", false);
// Use SoftSetBoolArg here so user can override any of these if they wish.
// Note: the GetBoolArg() calls for all of these must happen later.
SoftSetBoolArg("-listen", false); SoftSetBoolArg("-listen", false);
SoftSetBoolArg("-irc", false); }
SoftSetBoolArg("-proxydns", true);
if (mapArgs.count("-proxy")) {
// to protect privacy, do not listen by default if a proxy server is specified
SoftSetBoolArg("-listen", false);
}
if (GetBoolArg("-listen", true)) {
// do not map ports or try to retrieve public IP when not listening (pointless)
SoftSetBoolArg("-upnp", false); SoftSetBoolArg("-upnp", false);
SoftSetBoolArg("-discover", false); SoftSetBoolArg("-discover", false);
} }
if (mapArgs.count("-externalip")) {
// if an explicit public IP is specified, do not try to find others
SoftSetBoolArg("-discover", false);
}
// ********************************************************* Step 3: parameter-to-internal-flags // ********************************************************* Step 3: parameter-to-internal-flags
fDebug = GetBoolArg("-debug"); fDebug = GetBoolArg("-debug");
@ -414,7 +437,9 @@ bool AppInit2()
ShrinkDebugFile(); ShrinkDebugFile();
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); 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 (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str()); printf("Bitcoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str());
printf("Startup time: %s\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("Default data directory %s\n", GetDefaultDataDir().string().c_str()); printf("Default data directory %s\n", GetDefaultDataDir().string().c_str());
printf("Used data directory %s\n", GetDataDir().string().c_str());
std::ostringstream strErrors; std::ostringstream strErrors;
if (fDaemon) if (fDaemon)
@ -424,30 +449,8 @@ bool AppInit2()
// ********************************************************* Step 5: network initialization // ********************************************************* Step 5: network initialization
if (mapArgs.count("-proxy")) int nSocksVersion = GetArg("-socks", 5);
{
fUseProxy = true;
addrProxy = CService(mapArgs["-proxy"], 9050);
if (!addrProxy.IsValid())
return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"].c_str()));
}
if (mapArgs.count("-noproxy"))
{
BOOST_FOREACH(std::string snet, mapMultiArgs["-noproxy"]) {
enum Network net = ParseNetwork(snet);
if (net == NET_UNROUTABLE)
return InitError(strprintf(_("Unknown network specified in -noproxy: '%s'"), snet.c_str()));
SetNoProxy(net);
}
}
fNameLookup = GetBoolArg("-dns");
fProxyNameLookup = GetBoolArg("-proxydns");
if (fProxyNameLookup)
fNameLookup = true;
fNoListen = !GetBoolArg("-listen", true);
nSocksVersion = GetArg("-socks", 5);
if (nSocksVersion != 4 && nSocksVersion != 5) if (nSocksVersion != 4 && nSocksVersion != 5)
return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion)); return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));
@ -466,8 +469,29 @@ bool AppInit2()
} }
} }
BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"]) if (mapArgs.count("-proxy")) {
AddOneShot(strDest); CService addrProxy = CService(mapArgs["-proxy"], 9050);
if (!addrProxy.IsValid())
return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"].c_str()));
if (!IsLimited(NET_IPV4))
SetProxy(NET_IPV4, addrProxy, nSocksVersion);
if (nSocksVersion > 4) {
#ifdef USE_IPV6
if (!IsLimited(NET_IPV6))
SetProxy(NET_IPV6, addrProxy, nSocksVersion);
#endif
SetNameProxy(addrProxy, nSocksVersion);
}
}
// see Step 2: parameter interactions for more information about these
fNoListen = !GetBoolArg("-listen", true);
fDiscover = GetBoolArg("-discover", true);
fNameLookup = GetBoolArg("-dns", true);
#ifdef USE_UPNP
fUseUPnP = GetBoolArg("-upnp", USE_UPNP);
#endif
bool fBound = false; bool fBound = false;
if (!fNoListen) if (!fNoListen)
@ -483,15 +507,15 @@ bool AppInit2()
} else { } else {
struct in_addr inaddr_any; struct in_addr inaddr_any;
inaddr_any.s_addr = INADDR_ANY; inaddr_any.s_addr = INADDR_ANY;
if (!IsLimited(NET_IPV4))
fBound |= Bind(CService(inaddr_any, GetListenPort()));
#ifdef USE_IPV6 #ifdef USE_IPV6
if (!IsLimited(NET_IPV6)) if (!IsLimited(NET_IPV6))
fBound |= Bind(CService(in6addr_any, GetListenPort())); fBound |= Bind(CService(in6addr_any, GetListenPort()), false);
#endif #endif
if (!IsLimited(NET_IPV4))
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound);
} }
if (!fBound) if (!fBound)
return InitError(_("Not listening on any port")); return InitError(_("Failed to listen on any port. Use -listen=0 if you want this."));
} }
if (mapArgs.count("-externalip")) if (mapArgs.count("-externalip"))
@ -504,6 +528,9 @@ bool AppInit2()
} }
} }
BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"])
AddOneShot(strDest);
// ********************************************************* Step 6: load blockchain // ********************************************************* Step 6: load blockchain
if (GetBoolArg("-loadblockindextest")) if (GetBoolArg("-loadblockindextest"))
@ -604,11 +631,11 @@ bool AppInit2()
// Create new keyUser and set as default key // Create new keyUser and set as default key
RandAddSeedPerfmon(); RandAddSeedPerfmon();
std::vector<unsigned char> newDefaultKey; CPubKey newDefaultKey;
if (!pwalletMain->GetKeyFromPool(newDefaultKey, false)) if (!pwalletMain->GetKeyFromPool(newDefaultKey, false))
strErrors << _("Cannot initialize keypool") << "\n"; strErrors << _("Cannot initialize keypool") << "\n";
pwalletMain->SetDefaultKey(newDefaultKey); pwalletMain->SetDefaultKey(newDefaultKey);
if (!pwalletMain->SetAddressBookName(CBitcoinAddress(pwalletMain->vchDefaultKey), "")) if (!pwalletMain->SetAddressBookName(pwalletMain->vchDefaultKey.GetID(), ""))
strErrors << _("Cannot write default address") << "\n"; strErrors << _("Cannot write default address") << "\n";
} }

View file

@ -9,6 +9,7 @@
extern CWallet* pwalletMain; extern CWallet* pwalletMain;
void StartShutdown();
void Shutdown(void* parg); void Shutdown(void* parg);
bool AppInit2(); bool AppInit2();
std::string HelpMessage(); std::string HelpMessage();

View file

@ -176,8 +176,6 @@ bool GetIPFromIRC(SOCKET hSocket, string strMyName, CNetAddr& ipRet)
// Hybrid IRC used by lfnet always returns IP when you userhost yourself, // Hybrid IRC used by lfnet always returns IP when you userhost yourself,
// but in case another IRC is ever used this should work. // but in case another IRC is ever used this should work.
printf("GetIPFromIRC() got userhost %s\n", strHost.c_str()); printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
if (fUseProxy)
return false;
CNetAddr addr(strHost, true); CNetAddr addr(strHost, true);
if (!addr.IsValid()) if (!addr.IsValid())
return false; return false;
@ -281,7 +279,7 @@ void ThreadIRCSeed2(void* parg)
if (GetIPFromIRC(hSocket, strMyName, addrFromIRC)) if (GetIPFromIRC(hSocket, strMyName, addrFromIRC))
{ {
printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToString().c_str()); printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToString().c_str());
if (!fUseProxy && addrFromIRC.IsRoutable()) if (addrFromIRC.IsRoutable())
{ {
// IRC lets you to re-nick // IRC lets you to re-nick
AddLocal(addrFromIRC, LOCAL_IRC); AddLocal(addrFromIRC, LOCAL_IRC);
@ -291,8 +289,8 @@ void ThreadIRCSeed2(void* parg)
} }
if (fTestNet) { if (fTestNet) {
Send(hSocket, "JOIN #bitcoinTEST\r"); Send(hSocket, "JOIN #bitcoinTEST3\r");
Send(hSocket, "WHO #bitcoinTEST\r"); Send(hSocket, "WHO #bitcoinTEST3\r");
} else { } else {
// randomly join #bitcoin00-#bitcoin99 // randomly join #bitcoin00-#bitcoin99
int channel_number = GetRandInt(100); int channel_number = GetRandInt(100);

View file

@ -239,18 +239,18 @@ CPrivKey CKey::GetPrivKey() const
return vchPrivKey; return vchPrivKey;
} }
bool CKey::SetPubKey(const std::vector<unsigned char>& vchPubKey) bool CKey::SetPubKey(const CPubKey& vchPubKey)
{ {
const unsigned char* pbegin = &vchPubKey[0]; const unsigned char* pbegin = &vchPubKey.vchPubKey[0];
if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size())) if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size()))
return false; return false;
fSet = true; fSet = true;
if (vchPubKey.size() == 33) if (vchPubKey.vchPubKey.size() == 33)
SetCompressedPubKey(); SetCompressedPubKey();
return true; return true;
} }
std::vector<unsigned char> CKey::GetPubKey() const CPubKey CKey::GetPubKey() const
{ {
int nSize = i2o_ECPublicKey(pkey, NULL); int nSize = i2o_ECPublicKey(pkey, NULL);
if (!nSize) if (!nSize)
@ -259,7 +259,7 @@ std::vector<unsigned char> CKey::GetPubKey() const
unsigned char* pbegin = &vchPubKey[0]; unsigned char* pbegin = &vchPubKey[0];
if (i2o_ECPublicKey(pkey, &pbegin) != nSize) if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size"); throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
return vchPubKey; return CPubKey(vchPubKey);
} }
bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig) bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig)

View file

@ -9,7 +9,9 @@
#include <vector> #include <vector>
#include "allocators.h" #include "allocators.h"
#include "serialize.h"
#include "uint256.h" #include "uint256.h"
#include "util.h"
#include <openssl/ec.h> // for EC_KEY definition #include <openssl/ec.h> // for EC_KEY definition
@ -42,6 +44,60 @@ public:
explicit key_error(const std::string& str) : std::runtime_error(str) {} explicit key_error(const std::string& str) : std::runtime_error(str) {}
}; };
/** A reference to a CKey: the Hash160 of its serialized public key */
class CKeyID : public uint160
{
public:
CKeyID() : uint160(0) { }
CKeyID(const uint160 &in) : uint160(in) { }
};
/** A reference to a CScript: the Hash160 of its serialization (see script.h) */
class CScriptID : public uint160
{
public:
CScriptID() : uint160(0) { }
CScriptID(const uint160 &in) : uint160(in) { }
};
/** An encapsulated public key. */
class CPubKey {
private:
std::vector<unsigned char> vchPubKey;
friend class CKey;
public:
CPubKey() { }
CPubKey(const std::vector<unsigned char> &vchPubKeyIn) : vchPubKey(vchPubKeyIn) { }
friend bool operator==(const CPubKey &a, const CPubKey &b) { return a.vchPubKey == b.vchPubKey; }
friend bool operator!=(const CPubKey &a, const CPubKey &b) { return a.vchPubKey != b.vchPubKey; }
friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vchPubKey < b.vchPubKey; }
IMPLEMENT_SERIALIZE(
READWRITE(vchPubKey);
)
CKeyID GetID() const {
return CKeyID(Hash160(vchPubKey));
}
uint256 GetHash() const {
return Hash(vchPubKey.begin(), vchPubKey.end());
}
bool IsValid() const {
return vchPubKey.size() == 33 || vchPubKey.size() == 65;
}
bool IsCompressed() const {
return vchPubKey.size() == 33;
}
std::vector<unsigned char> Raw() const {
return vchPubKey;
}
};
// secure_allocator is defined in serialize.h // secure_allocator is defined in serialize.h
// CPrivKey is a serialized private key, with all parameters included (279 bytes) // CPrivKey is a serialized private key, with all parameters included (279 bytes)
@ -78,8 +134,8 @@ public:
bool SetSecret(const CSecret& vchSecret, bool fCompressed = false); bool SetSecret(const CSecret& vchSecret, bool fCompressed = false);
CSecret GetSecret(bool &fCompressed) const; CSecret GetSecret(bool &fCompressed) const;
CPrivKey GetPrivKey() const; CPrivKey GetPrivKey() const;
bool SetPubKey(const std::vector<unsigned char>& vchPubKey); bool SetPubKey(const CPubKey& vchPubKey);
std::vector<unsigned char> GetPubKey() const; CPubKey GetPubKey() const;
bool Sign(uint256 hash, std::vector<unsigned char>& vchSig); bool Sign(uint256 hash, std::vector<unsigned char>& vchSig);

View file

@ -6,7 +6,7 @@
#include "keystore.h" #include "keystore.h"
#include "script.h" #include "script.h"
bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char> &vchPubKeyOut) const bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
{ {
CKey key; CKey key;
if (!GetKey(address, key)) if (!GetKey(address, key))
@ -21,7 +21,7 @@ bool CBasicKeyStore::AddKey(const CKey& key)
CSecret secret = key.GetSecret(fCompressed); CSecret secret = key.GetSecret(fCompressed);
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
mapKeys[CBitcoinAddress(key.GetPubKey())] = make_pair(secret, fCompressed); mapKeys[key.GetPubKey().GetID()] = make_pair(secret, fCompressed);
} }
return true; return true;
} }
@ -30,12 +30,12 @@ bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
{ {
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
mapScripts[Hash160(redeemScript)] = redeemScript; mapScripts[redeemScript.GetID()] = redeemScript;
} }
return true; return true;
} }
bool CBasicKeyStore::HaveCScript(const uint160& hash) const bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const
{ {
bool result; bool result;
{ {
@ -46,7 +46,7 @@ bool CBasicKeyStore::HaveCScript(const uint160& hash) const
} }
bool CBasicKeyStore::GetCScript(const uint160 &hash, CScript& redeemScriptOut) const bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
{ {
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
@ -97,10 +97,10 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin(); CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
for (; mi != mapCryptedKeys.end(); ++mi) for (; mi != mapCryptedKeys.end(); ++mi)
{ {
const std::vector<unsigned char> &vchPubKey = (*mi).second.first; const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second; const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
CSecret vchSecret; CSecret vchSecret;
if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret)) if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
return false; return false;
if (vchSecret.size() != 32) if (vchSecret.size() != 32)
return false; return false;
@ -128,9 +128,9 @@ bool CCryptoKeyStore::AddKey(const CKey& key)
return false; return false;
std::vector<unsigned char> vchCryptedSecret; std::vector<unsigned char> vchCryptedSecret;
std::vector<unsigned char> vchPubKey = key.GetPubKey(); CPubKey vchPubKey = key.GetPubKey();
bool fCompressed; bool fCompressed;
if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret)) if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
return false; return false;
if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret)) if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
@ -140,19 +140,19 @@ bool CCryptoKeyStore::AddKey(const CKey& key)
} }
bool CCryptoKeyStore::AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{ {
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
if (!SetCrypted()) if (!SetCrypted())
return false; return false;
mapCryptedKeys[CBitcoinAddress(vchPubKey)] = make_pair(vchPubKey, vchCryptedSecret); mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
} }
return true; return true;
} }
bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
{ {
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
@ -162,10 +162,10 @@ bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end()) if (mi != mapCryptedKeys.end())
{ {
const std::vector<unsigned char> &vchPubKey = (*mi).second.first; const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second; const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
CSecret vchSecret; CSecret vchSecret;
if (!DecryptSecret(vMasterKey, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret)) if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
return false; return false;
if (vchSecret.size() != 32) if (vchSecret.size() != 32)
return false; return false;
@ -177,7 +177,7 @@ bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const
return false; return false;
} }
bool CCryptoKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
{ {
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
@ -207,10 +207,10 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
CKey key; CKey key;
if (!key.SetSecret(mKey.second.first, mKey.second.second)) if (!key.SetSecret(mKey.second.first, mKey.second.second))
return false; return false;
const std::vector<unsigned char> vchPubKey = key.GetPubKey(); const CPubKey vchPubKey = key.GetPubKey();
std::vector<unsigned char> vchCryptedSecret; std::vector<unsigned char> vchCryptedSecret;
bool fCompressed; bool fCompressed;
if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret)) if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
return false; return false;
if (!AddCryptedKey(vchPubKey, vchCryptedSecret)) if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
return false; return false;

View file

@ -7,7 +7,6 @@
#include "crypter.h" #include "crypter.h"
#include "sync.h" #include "sync.h"
#include "base58.h"
#include <boost/signals2/signal.hpp> #include <boost/signals2/signal.hpp>
class CScript; class CScript;
@ -25,17 +24,17 @@ public:
virtual bool AddKey(const CKey& key) =0; virtual bool AddKey(const CKey& key) =0;
// Check whether a key corresponding to a given address is present in the store. // Check whether a key corresponding to a given address is present in the store.
virtual bool HaveKey(const CBitcoinAddress &address) const =0; virtual bool HaveKey(const CKeyID &address) const =0;
virtual bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const =0; virtual bool GetKey(const CKeyID &address, CKey& keyOut) const =0;
virtual void GetKeys(std::set<CBitcoinAddress> &setAddress) const =0; virtual void GetKeys(std::set<CKeyID> &setAddress) const =0;
virtual bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const; virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
// Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013 // Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013
virtual bool AddCScript(const CScript& redeemScript) =0; virtual bool AddCScript(const CScript& redeemScript) =0;
virtual bool HaveCScript(const uint160 &hash) const =0; virtual bool HaveCScript(const CScriptID &hash) const =0;
virtual bool GetCScript(const uint160 &hash, CScript& redeemScriptOut) const =0; virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0;
virtual bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret, bool &fCompressed) const virtual bool GetSecret(const CKeyID &address, CSecret& vchSecret, bool &fCompressed) const
{ {
CKey key; CKey key;
if (!GetKey(address, key)) if (!GetKey(address, key))
@ -45,8 +44,8 @@ public:
} }
}; };
typedef std::map<CBitcoinAddress, std::pair<CSecret, bool> > KeyMap; typedef std::map<CKeyID, std::pair<CSecret, bool> > KeyMap;
typedef std::map<uint160, CScript > ScriptMap; typedef std::map<CScriptID, CScript > ScriptMap;
/** Basic key store, that keeps keys in an address->secret map */ /** Basic key store, that keeps keys in an address->secret map */
class CBasicKeyStore : public CKeyStore class CBasicKeyStore : public CKeyStore
@ -57,7 +56,7 @@ protected:
public: public:
bool AddKey(const CKey& key); bool AddKey(const CKey& key);
bool HaveKey(const CBitcoinAddress &address) const bool HaveKey(const CKeyID &address) const
{ {
bool result; bool result;
{ {
@ -66,7 +65,7 @@ public:
} }
return result; return result;
} }
void GetKeys(std::set<CBitcoinAddress> &setAddress) const void GetKeys(std::set<CKeyID> &setAddress) const
{ {
setAddress.clear(); setAddress.clear();
{ {
@ -79,7 +78,7 @@ public:
} }
} }
} }
bool GetKey(const CBitcoinAddress &address, CKey &keyOut) const bool GetKey(const CKeyID &address, CKey &keyOut) const
{ {
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
@ -94,11 +93,11 @@ public:
return false; return false;
} }
virtual bool AddCScript(const CScript& redeemScript); virtual bool AddCScript(const CScript& redeemScript);
virtual bool HaveCScript(const uint160 &hash) const; virtual bool HaveCScript(const CScriptID &hash) const;
virtual bool GetCScript(const uint160 &hash, CScript& redeemScriptOut) const; virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const;
}; };
typedef std::map<CBitcoinAddress, std::pair<std::vector<unsigned char>, std::vector<unsigned char> > > CryptedKeyMap; typedef std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap;
/** Keystore which keeps the private keys encrypted. /** Keystore which keeps the private keys encrypted.
* It derives from the basic key store, which is used if no encryption is active. * It derives from the basic key store, which is used if no encryption is active.
@ -146,9 +145,9 @@ public:
bool Lock(); bool Lock();
virtual bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddKey(const CKey& key); bool AddKey(const CKey& key);
bool HaveKey(const CBitcoinAddress &address) const bool HaveKey(const CKeyID &address) const
{ {
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
@ -158,9 +157,9 @@ public:
} }
return false; return false;
} }
bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const; bool GetKey(const CKeyID &address, CKey& keyOut) const;
bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const; bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
void GetKeys(std::set<CBitcoinAddress> &setAddress) const void GetKeys(std::set<CKeyID> &setAddress) const
{ {
if (!IsCrypted()) if (!IsCrypted())
{ {

View file

@ -865,12 +865,12 @@ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBl
// Only change once per interval // Only change once per interval
if ((pindexLast->nHeight+1) % nInterval != 0) if ((pindexLast->nHeight+1) % nInterval != 0)
{ {
// Special rules for testnet after 15 Feb 2012: // Special difficulty rule for testnet:
if (fTestNet && pblock->nTime > 1329264000) if (fTestNet)
{ {
// If the new block's timestamp is more than 2* 10 minutes // If the new block's timestamp is more than 2* 10 minutes
// then allow mining of a min-difficulty block. // then allow mining of a min-difficulty block.
if (pblock->nTime - pindexLast->nTime > nTargetSpacing*2) if (pblock->nTime > pindexLast->nTime + nTargetSpacing*2)
return nProofOfWorkLimit; return nProofOfWorkLimit;
else else
{ {
@ -1875,7 +1875,7 @@ bool CheckDiskSpace(uint64 nAdditionalBytes)
strMiscWarning = strMessage; strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str()); printf("*** %s\n", strMessage.c_str());
uiInterface.ThreadSafeMessageBox(strMessage, "Bitcoin", CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL); uiInterface.ThreadSafeMessageBox(strMessage, "Bitcoin", CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
uiInterface.QueueShutdown(); StartShutdown();
return false; return false;
} }
return true; return true;
@ -1926,12 +1926,11 @@ bool LoadBlockIndex(bool fAllowNew)
{ {
if (fTestNet) if (fTestNet)
{ {
hashGenesisBlock = uint256("0x00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008");
bnProofOfWorkLimit = CBigNum(~uint256(0) >> 28);
pchMessageStart[0] = 0xfa; pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf; pchMessageStart[1] = 0xbf;
pchMessageStart[2] = 0xb5; pchMessageStart[2] = 0xb5;
pchMessageStart[3] = 0xda; pchMessageStart[3] = 0xda;
hashGenesisBlock = uint256("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943");
} }
// //
@ -1977,8 +1976,7 @@ bool LoadBlockIndex(bool fAllowNew)
if (fTestNet) if (fTestNet)
{ {
block.nTime = 1296688602; block.nTime = 1296688602;
block.nBits = 0x1d07fff8; block.nNonce = 414098458;
block.nNonce = 384568319;
} }
//// debug print //// debug print
@ -2304,7 +2302,7 @@ unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{ {
static map<CService, vector<unsigned char> > mapReuseKey; static map<CService, CPubKey> mapReuseKey;
RandAddSeedPerfmon(); RandAddSeedPerfmon();
if (fDebug) if (fDebug)
printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size()); printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size());
@ -2379,7 +2377,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (!pfrom->fInbound) if (!pfrom->fInbound)
{ {
// Advertise our address // Advertise our address
if (!fNoListen && !fUseProxy && !IsInitialBlockDownload()) if (!fNoListen && !IsInitialBlockDownload())
{ {
CAddress addr = GetLocalAddress(&pfrom->addr); CAddress addr = GetLocalAddress(&pfrom->addr);
if (addr.IsRoutable()) if (addr.IsRoutable())
@ -3015,8 +3013,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// Keep-alive ping. We send a nonce of zero because we don't use it anywhere // Keep-alive ping. We send a nonce of zero because we don't use it anywhere
// right now. // right now.
if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) { if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) {
uint64 nonce = 0;
if (pto->nVersion > BIP0031_VERSION) if (pto->nVersion > BIP0031_VERSION)
pto->PushMessage("ping", 0); pto->PushMessage("ping", nonce);
else else
pto->PushMessage("ping"); pto->PushMessage("ping");
} }
@ -3037,7 +3036,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pnode->setAddrKnown.clear(); pnode->setAddrKnown.clear();
// Rebroadcast our address // Rebroadcast our address
if (!fNoListen && !fUseProxy) if (!fNoListen)
{ {
CAddress addr = GetLocalAddress(&pnode->addr); CAddress addr = GetLocalAddress(&pnode->addr);
if (addr.IsRoutable()) if (addr.IsRoutable())

View file

@ -47,7 +47,8 @@ struct LocalServiceInfo {
// Global state variables // Global state variables
// //
bool fClient = false; bool fClient = false;
static bool fUseUPnP = false; bool fDiscover = true;
bool fUseUPnP = false;
uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
static CCriticalSection cs_mapLocalHost; static CCriticalSection cs_mapLocalHost;
static map<CNetAddr, LocalServiceInfo> mapLocalHost; static map<CNetAddr, LocalServiceInfo> mapLocalHost;
@ -99,7 +100,7 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
// find 'best' local address for a particular peer // find 'best' local address for a particular peer
bool GetLocal(CService& addr, const CNetAddr *paddrPeer) bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
{ {
if (fUseProxy || mapArgs.count("-connect") || fNoListen) if (fNoListen)
return false; return false;
int nBestScore = -1; int nBestScore = -1;
@ -211,7 +212,7 @@ bool AddLocal(const CService& addr, int nScore)
if (!addr.IsRoutable()) if (!addr.IsRoutable())
return false; return false;
if (!GetBoolArg("-discover", true) && nScore < LOCAL_MANUAL) if (!fDiscover && nScore < LOCAL_MANUAL)
return false; return false;
if (IsLimited(addr)) if (IsLimited(addr))
@ -345,9 +346,6 @@ bool GetMyExternalIP(CNetAddr& ipRet)
const char* pszGet; const char* pszGet;
const char* pszKeyword; const char* pszKeyword;
if (fNoListen||fUseProxy)
return false;
for (int nLookup = 0; nLookup <= 1; nLookup++) for (int nLookup = 0; nLookup <= 1; nLookup++)
for (int nHost = 1; nHost <= 2; nHost++) for (int nHost = 1; nHost <= 2; nHost++)
{ {
@ -542,7 +540,7 @@ void CNode::PushVersion()
{ {
/// when NTP implemented, change to just nTime = GetAdjustedTime() /// when NTP implemented, change to just nTime = GetAdjustedTime()
int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
CAddress addrYou = (fUseProxy ? CAddress(CService("0.0.0.0",0)) : addr); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0)));
CAddress addrMe = GetLocalAddress(&addr); CAddress addrMe = GetLocalAddress(&addr);
RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
@ -1016,7 +1014,7 @@ void ThreadMapPort2(void* parg)
r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
if (r == 1) if (r == 1)
{ {
if (GetBoolArg("-discover", true)) { if (fDiscover) {
char externalIPAddress[40]; char externalIPAddress[40];
r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
if(r != UPNPCOMMAND_SUCCESS) if(r != UPNPCOMMAND_SUCCESS)
@ -1093,12 +1091,8 @@ void ThreadMapPort2(void* parg)
} }
} }
void MapPort(bool fMapPort) void MapPort()
{ {
if (fUseUPnP != fMapPort)
{
fUseUPnP = fMapPort;
}
if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1) if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1)
{ {
if (!CreateThread(ThreadMapPort, NULL)) if (!CreateThread(ThreadMapPort, NULL))
@ -1106,7 +1100,7 @@ void MapPort(bool fMapPort)
} }
} }
#else #else
void MapPort(bool /* unused fMapPort */) void MapPort()
{ {
// Intentionally left blank. // Intentionally left blank.
} }
@ -1160,7 +1154,7 @@ void ThreadDNSAddressSeed2(void* parg)
printf("Loading addresses from DNS seeds (could take a while)\n"); printf("Loading addresses from DNS seeds (could take a while)\n");
for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) { for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
if (fProxyNameLookup) { if (GetNameProxy()) {
AddOneShot(strDNSSeed[seed_idx][1]); AddOneShot(strDNSSeed[seed_idx][1]);
} else { } else {
vector<CNetAddr> vaddr; vector<CNetAddr> vaddr;
@ -1394,8 +1388,7 @@ void ThreadOpenConnections2(void* parg)
return; return;
// Add seed nodes if IRC isn't working // Add seed nodes if IRC isn't working
bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050); if (addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet)
if (addrman.size()==0 && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
{ {
std::vector<CAddress> vAdd; std::vector<CAddress> vAdd;
for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++) for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++)
@ -1492,7 +1485,7 @@ void ThreadOpenAddedConnections2(void* parg)
if (mapArgs.count("-addnode") == 0) if (mapArgs.count("-addnode") == 0)
return; return;
if (fProxyNameLookup) { if (GetNameProxy()) {
while(!fShutdown) { while(!fShutdown) {
BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) { BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) {
CAddress addr; CAddress addr;
@ -1665,7 +1658,7 @@ void ThreadMessageHandler2(void* parg)
vnThreadsRunning[THREAD_MESSAGEHANDLER]--; vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
Sleep(100); Sleep(100);
if (fRequestShutdown) if (fRequestShutdown)
Shutdown(NULL); StartShutdown();
vnThreadsRunning[THREAD_MESSAGEHANDLER]++; vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
if (fShutdown) if (fShutdown)
return; return;
@ -1778,7 +1771,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
vhListenSocket.push_back(hListenSocket); vhListenSocket.push_back(hListenSocket);
if (addrBind.IsRoutable() && GetBoolArg("-discover", true)) if (addrBind.IsRoutable() && fDiscover)
AddLocal(addrBind, LOCAL_BIND); AddLocal(addrBind, LOCAL_BIND);
return true; return true;
@ -1786,7 +1779,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
void static Discover() void static Discover()
{ {
if (!GetBoolArg("-discover", true)) if (!fDiscover)
return; return;
#ifdef WIN32 #ifdef WIN32
@ -1835,22 +1828,11 @@ void static Discover()
} }
#endif #endif
if (!fUseProxy && !mapArgs.count("-connect") && !fNoListen) CreateThread(ThreadGetMyExternalIP, NULL);
{
CreateThread(ThreadGetMyExternalIP, NULL);
}
} }
void StartNode(void* parg) void StartNode(void* parg)
{ {
#ifdef USE_UPNP
#if USE_UPNP
fUseUPnP = GetBoolArg("-upnp", true);
#else
fUseUPnP = GetBoolArg("-upnp", false);
#endif
#endif
if (semOutbound == NULL) { if (semOutbound == NULL) {
// initialize semaphore // initialize semaphore
int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125)); int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125));
@ -1873,8 +1855,8 @@ void StartNode(void* parg)
printf("Error: CreateThread(ThreadDNSAddressSeed) failed\n"); printf("Error: CreateThread(ThreadDNSAddressSeed) failed\n");
// Map ports with UPnP // Map ports with UPnP
if (fHaveUPnP) if (fUseUPnP)
MapPort(fUseUPnP); MapPort();
// Get addresses from IRC and advertise ours // Get addresses from IRC and advertise ours
if (!CreateThread(ThreadIRCSeed, NULL)) if (!CreateThread(ThreadIRCSeed, NULL))
@ -1930,7 +1912,9 @@ bool StopNode()
if (vnThreadsRunning[THREAD_MINER] > 0) printf("ThreadBitcoinMiner still running\n"); if (vnThreadsRunning[THREAD_MINER] > 0) printf("ThreadBitcoinMiner still running\n");
if (vnThreadsRunning[THREAD_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n"); if (vnThreadsRunning[THREAD_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n");
if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n"); if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n");
if (fHaveUPnP && vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n"); #ifdef USE_UPNP
if (vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n");
#endif
if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n"); if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n");
if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n"); if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n"); if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n");

View file

@ -36,7 +36,7 @@ void AddressCurrentlyConnected(const CService& addr);
CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CService& ip); CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL, int64 nTimeout=0); CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL, int64 nTimeout=0);
void MapPort(bool fMapPort); void MapPort();
unsigned short GetListenPort(); unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string())); bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
void StartNode(void* parg); void StartNode(void* parg);
@ -110,6 +110,8 @@ enum threadId
}; };
extern bool fClient; extern bool fClient;
extern bool fDiscover;
extern bool fUseUPnP;
extern uint64 nLocalServices; extern uint64 nLocalServices;
extern uint64 nLocalHostNonce; extern uint64 nLocalHostNonce;
extern boost::array<int, THREAD_MAX> vnThreadsRunning; extern boost::array<int, THREAD_MAX> vnThreadsRunning;

View file

@ -16,14 +16,11 @@
using namespace std; using namespace std;
// Settings // Settings
int nSocksVersion = 5; typedef std::pair<CService, int> proxyType;
int fUseProxy = false; static proxyType proxyInfo[NET_MAX];
bool fProxyNameLookup = false; static proxyType nameproxyInfo;
bool fNameLookup = false;
CService addrProxy("127.0.0.1",9050);
int nConnectTimeout = 5000; int nConnectTimeout = 5000;
static bool vfNoProxy[NET_MAX] = {}; bool fNameLookup = false;
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
@ -36,11 +33,6 @@ enum Network ParseNetwork(std::string net) {
return NET_UNROUTABLE; return NET_UNROUTABLE;
} }
void SetNoProxy(enum Network net, bool fNoProxy) {
assert(net >= 0 && net < NET_MAX);
vfNoProxy[net] = fNoProxy;
}
bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup) bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
{ {
vIP.clear(); vIP.clear();
@ -431,29 +423,71 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
return true; return true;
} }
bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion) {
assert(net >= 0 && net < NET_MAX);
if (nSocksVersion != 0 && nSocksVersion != 4 && nSocksVersion != 5)
return false;
if (nSocksVersion != 0 && !addrProxy.IsValid())
return false;
proxyInfo[net] = std::make_pair(addrProxy, nSocksVersion);
return true;
}
bool GetProxy(enum Network net, CService &addrProxy) {
assert(net >= 0 && net < NET_MAX);
if (!proxyInfo[net].second)
return false;
addrProxy = proxyInfo[net].first;
return true;
}
bool SetNameProxy(CService addrProxy, int nSocksVersion) {
if (nSocksVersion != 0 && nSocksVersion != 5)
return false;
if (nSocksVersion != 0 && !addrProxy.IsValid())
return false;
nameproxyInfo = std::make_pair(addrProxy, nSocksVersion);
return true;
}
bool GetNameProxy() {
return nameproxyInfo.second != 0;
}
bool IsProxy(const CNetAddr &addr) {
for (int i=0; i<NET_MAX; i++) {
if (proxyInfo[i].second && (addr == (CNetAddr)proxyInfo[i].first))
return true;
}
return false;
}
bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
{ {
SOCKET hSocket = INVALID_SOCKET; const proxyType &proxy = proxyInfo[addrDest.GetNetwork()];
bool fProxy = (fUseProxy && addrDest.IsRoutable() && !vfNoProxy[addrDest.GetNetwork()]);
if (!ConnectSocketDirectly(fProxy ? addrProxy : addrDest, hSocket, nTimeout)) // no proxy needed
if (!proxy.second)
return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout);
SOCKET hSocket = INVALID_SOCKET;
// first connect to proxy server
if (!ConnectSocketDirectly(proxy.first, hSocket, nTimeout))
return false; return false;
if (fProxy) // do socks negotiation
{ switch (proxy.second) {
switch(nSocksVersion) case 4:
{ if (!Socks4(addrDest, hSocket))
case 4: return false;
if (!Socks4(addrDest, hSocket)) break;
return false; case 5:
break; if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket))
return false;
case 5: break;
default: default:
if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket)) return false;
return false;
break;
}
} }
hSocketRet = hSocket; hSocketRet = hSocket;
@ -465,6 +499,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
string strDest(pszDest); string strDest(pszDest);
int port = portDefault; int port = portDefault;
// split hostname and port
size_t colon = strDest.find_last_of(':'); size_t colon = strDest.find_last_of(':');
if (colon != strDest.npos) { if (colon != strDest.npos) {
char *endp = NULL; char *endp = NULL;
@ -479,26 +514,26 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
strDest = strDest.substr(1, strDest.size()-2); strDest = strDest.substr(1, strDest.size()-2);
SOCKET hSocket = INVALID_SOCKET; SOCKET hSocket = INVALID_SOCKET;
CService addrResolved(CNetAddr(strDest, fNameLookup && !fProxyNameLookup), port); CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxyInfo.second), port);
if (addrResolved.IsValid()) { if (addrResolved.IsValid()) {
addr = addrResolved; addr = addrResolved;
return ConnectSocket(addr, hSocketRet, nTimeout); return ConnectSocket(addr, hSocketRet, nTimeout);
} }
addr = CService("0.0.0.0:0"); addr = CService("0.0.0.0:0");
if (!fNameLookup) if (!nameproxyInfo.second)
return false; return false;
if (!ConnectSocketDirectly(addrProxy, hSocket, nTimeout)) if (!ConnectSocketDirectly(nameproxyInfo.first, hSocket, nTimeout))
return false; return false;
switch(nSocksVersion) switch(nameproxyInfo.second)
{ {
case 4: return false; default:
case 5: case 4: return false;
default: case 5:
if (!Socks5(strDest, port, hSocket)) if (!Socks5(strDest, port, hSocket))
return false; return false;
break; break;
} }
hSocketRet = hSocket; hSocketRet = hSocket;
return true; return true;
@ -975,7 +1010,7 @@ bool operator<(const CService& a, const CService& b)
bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
{ {
if (IsIPv4()) { if (IsIPv4()) {
if (*addrlen < sizeof(struct sockaddr_in)) if (*addrlen < (socklen_t)sizeof(struct sockaddr_in))
return false; return false;
*addrlen = sizeof(struct sockaddr_in); *addrlen = sizeof(struct sockaddr_in);
struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr; struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr;
@ -988,7 +1023,7 @@ bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
} }
#ifdef USE_IPV6 #ifdef USE_IPV6
if (IsIPv6()) { if (IsIPv6()) {
if (*addrlen < sizeof(struct sockaddr_in6)) if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6))
return false; return false;
*addrlen = sizeof(struct sockaddr_in6); *addrlen = sizeof(struct sockaddr_in6);
struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr; struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr;

View file

@ -28,8 +28,8 @@ enum Network
NET_MAX NET_MAX
}; };
enum Network ParseNetwork(std::string net); extern int nConnectTimeout;
void SetNoProxy(enum Network net, bool fNoProxy = true); extern bool fNameLookup;
/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */ /** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */
class CNetAddr class CNetAddr
@ -132,6 +132,12 @@ class CService : public CNetAddr
) )
}; };
enum Network ParseNetwork(std::string net);
bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5);
bool GetProxy(enum Network net, CService &addrProxy);
bool IsProxy(const CNetAddr &addr);
bool SetNameProxy(CService addrProxy, int nSocksVersion = 5);
bool GetNameProxy();
bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true);
bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0); bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0);
bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true); bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true);
@ -140,11 +146,4 @@ bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0);
bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout); bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout);
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout); bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout);
// Settings
extern int nSocksVersion;
extern int fUseProxy;
extern bool fProxyNameLookup;
extern bool fNameLookup;
extern CService addrProxy;
#endif #endif

View file

@ -20,16 +20,9 @@ static bool noui_ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCapt
return true; return true;
} }
static void noui_QueueShutdown()
{
// Without UI, Shutdown can simply be started in a new thread
CreateThread(Shutdown, NULL);
}
void noui_connect() void noui_connect()
{ {
// Connect bitcoind signal handlers // Connect bitcoind signal handlers
uiInterface.ThreadSafeMessageBox.connect(noui_ThreadSafeMessageBox); uiInterface.ThreadSafeMessageBox.connect(noui_ThreadSafeMessageBox);
uiInterface.ThreadSafeAskFee.connect(noui_ThreadSafeAskFee); uiInterface.ThreadSafeAskFee.connect(noui_ThreadSafeAskFee);
uiInterface.QueueShutdown.connect(noui_QueueShutdown);
} }

View file

@ -136,11 +136,6 @@ void AddressBookPage::setModel(AddressTableModel *model)
connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(selectNewAddress(QModelIndex,int,int))); this, SLOT(selectNewAddress(QModelIndex,int,int)));
if(mode == ForSending)
{
// Auto-select first row when in sending mode
ui->tableView->selectRow(0);
}
selectionChanged(); selectionChanged();
} }

View file

@ -3,6 +3,7 @@
#include "walletmodel.h" #include "walletmodel.h"
#include "wallet.h" #include "wallet.h"
#include "base58.h"
#include <QFont> #include <QFont>
#include <QColor> #include <QColor>
@ -58,11 +59,11 @@ public:
cachedAddressTable.clear(); cachedAddressTable.clear();
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, std::string)& item, wallet->mapAddressBook) BOOST_FOREACH(const PAIRTYPE(CTxDestination, std::string)& item, wallet->mapAddressBook)
{ {
const CBitcoinAddress& address = item.first; const CBitcoinAddress& address = item.first;
const std::string& strName = item.second; const std::string& strName = item.second;
bool fMine = wallet->HaveKey(address); bool fMine = IsMine(*wallet, address.Get());
cachedAddressTable.append(AddressTableEntry(fMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending, cachedAddressTable.append(AddressTableEntry(fMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending,
QString::fromStdString(strName), QString::fromStdString(strName),
QString::fromStdString(address.ToString()))); QString::fromStdString(address.ToString())));
@ -220,7 +221,8 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu
switch(index.column()) switch(index.column())
{ {
case Label: case Label:
wallet->SetAddressBookName(rec->address.toStdString(), value.toString().toStdString()); wallet->SetAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get(), value.toString().toStdString());
rec->label = value.toString();
break; break;
case Address: case Address:
// Refuse to set invalid address, set error status and return false // Refuse to set invalid address, set error status and return false
@ -235,9 +237,9 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
// Remove old entry // Remove old entry
wallet->DelAddressBookName(rec->address.toStdString()); wallet->DelAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get());
// Add new entry with new address // Add new entry with new address
wallet->SetAddressBookName(value.toString().toStdString(), rec->label.toStdString()); wallet->SetAddressBookName(CBitcoinAddress(value.toString().toStdString()).Get(), rec->label.toStdString());
} }
} }
break; break;
@ -314,7 +316,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
// Check for duplicate addresses // Check for duplicate addresses
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
if(wallet->mapAddressBook.count(strAddress)) if(wallet->mapAddressBook.count(CBitcoinAddress(strAddress).Get()))
{ {
editStatus = DUPLICATE_ADDRESS; editStatus = DUPLICATE_ADDRESS;
return QString(); return QString();
@ -331,13 +333,13 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
editStatus = WALLET_UNLOCK_FAILURE; editStatus = WALLET_UNLOCK_FAILURE;
return QString(); return QString();
} }
std::vector<unsigned char> newKey; CPubKey newKey;
if(!wallet->GetKeyFromPool(newKey, true)) if(!wallet->GetKeyFromPool(newKey, true))
{ {
editStatus = KEY_GENERATION_FAILURE; editStatus = KEY_GENERATION_FAILURE;
return QString(); return QString();
} }
strAddress = CBitcoinAddress(newKey).ToString(); strAddress = CBitcoinAddress(newKey.GetID()).ToString();
} }
else else
{ {
@ -346,7 +348,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
// Add entry // Add entry
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
wallet->SetAddressBookName(strAddress, strLabel); wallet->SetAddressBookName(CBitcoinAddress(strAddress).Get(), strLabel);
} }
return QString::fromStdString(strAddress); return QString::fromStdString(strAddress);
} }
@ -363,7 +365,7 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex & paren
} }
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
wallet->DelAddressBookName(rec->address.toStdString()); wallet->DelAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get());
} }
return true; return true;
} }
@ -375,7 +377,7 @@ QString AddressTableModel::labelForAddress(const QString &address) const
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
CBitcoinAddress address_parsed(address.toStdString()); CBitcoinAddress address_parsed(address.toStdString());
std::map<CBitcoinAddress, std::string>::iterator mi = wallet->mapAddressBook.find(address_parsed); std::map<CTxDestination, std::string>::iterator mi = wallet->mapAddressBook.find(address_parsed.Get());
if (mi != wallet->mapAddressBook.end()) if (mi != wallet->mapAddressBook.end())
{ {
return QString::fromStdString(mi->second); return QString::fromStdString(mi->second);

View file

@ -113,54 +113,6 @@ static void handleRunawayException(std::exception *e)
exit(1); exit(1);
} }
/** Help message for Bitcoin-Qt, shown with --help. */
class HelpMessageBox: public QMessageBox
{
Q_OBJECT
public:
HelpMessageBox(QWidget *parent = 0);
void exec();
private:
QString header;
QString coreOptions;
QString uiOptions;
};
HelpMessageBox::HelpMessageBox(QWidget *parent):
QMessageBox(parent)
{
header = tr("Bitcoin-Qt") + " " + tr("version") + " " +
QString::fromStdString(FormatFullVersion()) + "\n\n" +
tr("Usage:") + "\n" +
" bitcoin-qt [" + tr("options") + "] " + "\n";
coreOptions = QString::fromStdString(HelpMessage());
uiOptions = tr("UI options") + ":\n" +
" -lang=<lang> " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
" -min " + tr("Start minimized") + "\n" +
" -splash " + tr("Show splash screen on startup (default: 1)") + "\n";
setWindowTitle(tr("Bitcoin-Qt"));
setTextFormat(Qt::PlainText);
// setMinimumWidth is ignored for QMessageBox so put in nonbreaking spaces to make it wider.
QChar em_space(0x2003);
setText(header + QString(em_space).repeated(40));
setDetailedText(coreOptions + "\n" + uiOptions);
}
#include "bitcoin.moc"
void HelpMessageBox::exec()
{
#if defined(WIN32)
// On windows, show a message box, as there is no stderr in windowed applications
QMessageBox::exec();
#else
// On other operating systems, the expected action is to print the message to the console.
QString strUsage = header + "\n" + coreOptions + "\n" + uiOptions;
fprintf(stderr, "%s", strUsage.toStdString().c_str());
#endif
}
#ifndef BITCOIN_QT_TEST #ifndef BITCOIN_QT_TEST
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -259,7 +211,7 @@ int main(int argc, char *argv[])
// but before showing splash screen. // but before showing splash screen.
if (mapArgs.count("-?") || mapArgs.count("--help")) if (mapArgs.count("-?") || mapArgs.count("--help"))
{ {
HelpMessageBox help; GUIUtil::HelpMessageBox help;
help.exec(); help.exec();
return 1; return 1;
} }
@ -338,6 +290,7 @@ int main(int argc, char *argv[])
window.setWalletModel(0); window.setWalletModel(0);
guiref = 0; guiref = 0;
} }
// Shutdown the core and it's threads, but don't exit Bitcoin-Qt here
Shutdown(NULL); Shutdown(NULL);
} }
else else

View file

@ -65,7 +65,6 @@
<file alias="fi">locale/bitcoin_fi.qm</file> <file alias="fi">locale/bitcoin_fi.qm</file>
<file alias="fr">locale/bitcoin_fr.qm</file> <file alias="fr">locale/bitcoin_fr.qm</file>
<file alias="fr_CA">locale/bitcoin_fr_CA.qm</file> <file alias="fr_CA">locale/bitcoin_fr_CA.qm</file>
<file alias="fr_FR">locale/bitcoin_fr_FR.qm</file>
<file alias="he">locale/bitcoin_he.qm</file> <file alias="he">locale/bitcoin_he.qm</file>
<file alias="hr">locale/bitcoin_hr.qm</file> <file alias="hr">locale/bitcoin_hr.qm</file>
<file alias="hu">locale/bitcoin_hu.qm</file> <file alias="hu">locale/bitcoin_hu.qm</file>

View file

@ -409,17 +409,17 @@ void BitcoinGUI::createTrayIcon()
// Configuration of the tray icon (or dock icon) icon menu // Configuration of the tray icon (or dock icon) icon menu
trayIconMenu->addAction(toggleHideAction); trayIconMenu->addAction(toggleHideAction);
trayIconMenu->addAction(openRPCConsoleAction);
trayIconMenu->addSeparator(); trayIconMenu->addSeparator();
trayIconMenu->addAction(messageAction); trayIconMenu->addAction(sendCoinsAction);
trayIconMenu->addAction(verifyMessageAction); trayIconMenu->addAction(receiveCoinsAction);
#ifndef FIRST_CLASS_MESSAGING #ifndef FIRST_CLASS_MESSAGING
trayIconMenu->addSeparator(); trayIconMenu->addSeparator();
#endif #endif
trayIconMenu->addAction(sendCoinsAction); trayIconMenu->addAction(messageAction);
trayIconMenu->addAction(receiveCoinsAction); trayIconMenu->addAction(verifyMessageAction);
trayIconMenu->addSeparator(); trayIconMenu->addSeparator();
trayIconMenu->addAction(optionsAction); trayIconMenu->addAction(optionsAction);
trayIconMenu->addAction(openRPCConsoleAction);
#ifndef Q_WS_MAC // This is built-in on Mac #ifndef Q_WS_MAC // This is built-in on Mac
trayIconMenu->addSeparator(); trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction); trayIconMenu->addAction(quitAction);
@ -439,28 +439,6 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
} }
#endif #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() void BitcoinGUI::optionsClicked()
{ {
if(!clientModel || !clientModel->getOptionsModel()) if(!clientModel || !clientModel->getOptionsModel())
@ -766,12 +744,19 @@ void BitcoinGUI::dropEvent(QDropEvent *event)
{ {
if(event->mimeData()->hasUrls()) if(event->mimeData()->hasUrls())
{ {
gotoSendCoinsPage(); int nValidUrisFound = 0;
QList<QUrl> uris = event->mimeData()->urls(); QList<QUrl> uris = event->mimeData()->urls();
foreach(const QUrl &uri, uris) foreach(const QUrl &uri, uris)
{ {
sendCoinsPage->handleURI(uri.toString()); if (sendCoinsPage->handleURI(uri.toString()))
nValidUrisFound++;
} }
// if valid URIs were found
if (nValidUrisFound)
gotoSendCoinsPage();
else
notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."));
} }
event->acceptProposedAction(); event->acceptProposedAction();
@ -779,13 +764,14 @@ void BitcoinGUI::dropEvent(QDropEvent *event)
void BitcoinGUI::handleURI(QString strURI) void BitcoinGUI::handleURI(QString strURI)
{ {
gotoSendCoinsPage(); // URI has to be valid
sendCoinsPage->handleURI(strURI); if (sendCoinsPage->handleURI(strURI))
{
if(!isActiveWindow()) showNormalIfMinimized();
activateWindow(); gotoSendCoinsPage();
}
showNormalIfMinimized(); else
notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."));
} }
void BitcoinGUI::setEncryptionStatus(int status) void BitcoinGUI::setEncryptionStatus(int status)
@ -849,7 +835,7 @@ void BitcoinGUI::changePassphrase()
void BitcoinGUI::verifyMessage() void BitcoinGUI::verifyMessage()
{ {
VerifyMessageDialog *dlg = new VerifyMessageDialog(walletModel->getAddressTableModel(), this); VerifyMessageDialog *dlg = new VerifyMessageDialog(this);
dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->show(); dlg->show();
} }
@ -867,10 +853,29 @@ void BitcoinGUI::unlockWallet()
} }
} }
void BitcoinGUI::showNormalIfMinimized() void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)
{ {
if(!isVisible()) // Show, if hidden // activateWindow() (sometimes) helps with keyboard focus on Windows
if (isHidden())
{
show(); show();
if(isMinimized()) // Unminimize, if minimized activateWindow();
}
else if (isMinimized())
{
showNormal(); showNormal();
activateWindow();
}
else if (GUIUtil::isObscured(this))
{
raise();
activateWindow();
}
else if(fToggleHidden)
hide();
}
void BitcoinGUI::toggleHidden()
{
showNormalIfMinimized(true);
} }

View file

@ -169,9 +169,9 @@ private slots:
/** Ask for pass phrase to unlock wallet temporarily */ /** Ask for pass phrase to unlock wallet temporarily */
void unlockWallet(); void unlockWallet();
/** Show window if hidden, unminimize when minimized */ /** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */
void showNormalIfMinimized(); void showNormalIfMinimized(bool fToggleHidden = false);
/** Hide window if visible, show if hidden */ /** simply calls showNormalIfMinimized(true) for use in SLOT() macro */
void toggleHidden(); void toggleHidden();
}; };

View file

@ -6,114 +6,6 @@
#define UNUSED #define UNUSED
#endif #endif
static const char UNUSED *bitcoin_strings[] = {QT_TRANSLATE_NOOP("bitcoin-core", "" static const char UNUSED *bitcoin_strings[] = {QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unable to bind to %s on this computer. Bitcoin is probably already running."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %d, %s)"),
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", "Get help for a command"),
QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin"),
QT_TRANSLATE_NOOP("bitcoin-core", "Options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify configuration file (default: bitcoin.conf)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: bitcoind.pid)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins"),
QT_TRANSLATE_NOOP("bitcoin-core", "Don't generate coins"),
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 socks proxy"),
QT_TRANSLATE_NOOP("bitcoin-core", "Select the version of socks proxy to use (4 or 5, 5 is default)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Do not use proxy for connections to network <net> (IPv4 or IPv6)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"),
QT_TRANSLATE_NOOP("bitcoin-core", "Pass DNS requests to (SOCKS5) proxy"),
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 and attempt to keep the connection open"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect only to the specified node"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect to a node to retrieve peer addresses, and disconnect"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify your own public address"),
QT_TRANSLATE_NOOP("bitcoin-core", "Only connect to nodes in network <net> (IPv4 or IPv6)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Try to discover public IP address (default: 1)"),
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", "Bind to given address. Use [host]:port notation for IPv6"),
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", "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", ""
"Detach block and address databases. Increases shutdown time (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", "Output extra debugging information"),
QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to console instead of debug.log file"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to debugger"),
QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Password for JSON-RPC connections"),
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", "Imports blocks from external blk000?.dat file"),
QT_TRANSLATE_NOOP("bitcoin-core", "This help message"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"\n"
"SSL options: (see the Bitcoin Wiki for SSL setup instructions)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use OpenSSL (https) for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Server certificate file (default: server.cert)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Server private key (default: server.pem)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:"
"@STRENGTH)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot obtain a lock on data directory %s. Bitcoin is probably already "
"running."),
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 blkindex.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted"),
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: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -noproxy: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown -socks proxy version requested: %i"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -bind address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Not listening on any port"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -externalip address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"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: could not start node"),
QT_TRANSLATE_NOOP("bitcoin-core", "To use the %s option"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"%s, you must set a rpcpassword in the configuration file:\n" "%s, you must set a rpcpassword in the configuration file:\n"
" %s\n" " %s\n"
"It is recommended you use the following random password:\n" "It is recommended you use the following random password:\n"
@ -122,26 +14,130 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"(you do not need to remember this password)\n" "(you do not need to remember this password)\n"
"If the file does not exist, create it with owner-readable-only file " "If the file does not exist, create it with owner-readable-only file "
"permissions.\n"), "permissions.\n"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error"), QT_TRANSLATE_NOOP("bitcoin-core", ""
QT_TRANSLATE_NOOP("bitcoin-core", "An error occured while setting up the RPC port %i for listening: %s"), "Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:"
"@STRENGTH)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot obtain a lock on data directory %s. Bitcoin is probably already "
"running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Detach block and address databases. Increases shutdown time (default: 0)"),
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", ""
"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", ""
"Execute command when the best block changes (%s in cmd is replaced by block "
"hash)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Number of seconds to keep misbehaving peers from reconnecting (default: "
"86400)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unable to bind to %s on this computer. Bitcoin is probably already running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: -paytxfee is set very high. This is the transaction fee you will "
"pay if you send a transaction."),
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", "" QT_TRANSLATE_NOOP("bitcoin-core", ""
"You must set rpcpassword=<password> in the configuration file:\n" "You must set rpcpassword=<password> in the configuration file:\n"
"%s\n" "%s\n"
"If the file does not exist, create it with owner-readable-only file " "If the file does not exist, create it with owner-readable-only file "
"permissions."), "permissions."),
QT_TRANSLATE_NOOP("bitcoin-core", "" QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: Please check that your computer's date and time are correct. If " "\n"
"your clock is wrong Bitcoin will not work properly."), "SSL options: (see the Bitcoin Wiki for SSL setup instructions)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction "), QT_TRANSLATE_NOOP("bitcoin-core", "Accept command line and JSON-RPC commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "" QT_TRANSLATE_NOOP("bitcoin-core", "Accept connections from outside (default: 1 if no -proxy or -connect)"),
"Error: This transaction requires a transaction fee of at least %s because of " QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep the connection open"),
"its amount, complexity, or use of recently received funds "), QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow JSON-RPC connections from specified IP address"),
QT_TRANSLATE_NOOP("bitcoin-core", "An error occured while setting up the RPC port %i for listening: %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Bind to given address. Use [host]:port notation for IPv6"),
QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin version"),
QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot initialize keypool"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -bind address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -externalip address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write default address"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect only to the specified node(s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect through socks proxy"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect to a node to retrieve peer addresses, and disconnect"),
QT_TRANSLATE_NOOP("bitcoin-core", "Discover own IP address (default: 1 when listening and no -externalip)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Don't generate coins"),
QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading blkindex.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet requires newer version of Bitcoin"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Transaction creation failed "), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Transaction creation failed "),
QT_TRANSLATE_NOOP("bitcoin-core", "Sending..."), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction "),
QT_TRANSLATE_NOOP("bitcoin-core", "" QT_TRANSLATE_NOOP("bitcoin-core", "Error: could not start node"),
"Error: The transaction was rejected. This might happen if some of the coins " QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."),
"in your wallet were already spent, such as if you used a copy of wallet.dat " QT_TRANSLATE_NOOP("bitcoin-core", "Fee per KB to add to transactions you send"),
"and coins were spent in the copy but not marked as spent here."), QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using DNS lookup (default: 1)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount"), QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using internet relay chat (default: 0)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins"),
QT_TRANSLATE_NOOP("bitcoin-core", "Get help for a command"),
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", "Imports blocks from external blk000?.dat file"),
QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"), QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount"),
QT_TRANSLATE_NOOP("bitcoin-core", "List commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for JSON-RPC connections on <port> (default: 8332)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on <port> (default: 8333 or testnet: 18333)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Maintain at most <n> connections to peers (default: 125)"),
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", "Only connect to nodes in network <net> (IPv4 or IPv6)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Output extra debugging information"),
QT_TRANSLATE_NOOP("bitcoin-core", "Password for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Select the version of socks proxy to use (4-5, default: 5)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send command to -server or bitcoind"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send commands to node running on <ip> (default: 127.0.0.1)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to console instead of debug.log file"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to debugger"),
QT_TRANSLATE_NOOP("bitcoin-core", "Sending..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Server certificate file (default: server.cert)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Server private key (default: server.pem)"),
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", "Set key pool size to <n> (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify configuration file (default: bitcoin.conf)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout (in milliseconds)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify data directory"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: bitcoind.pid)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify your own public address"),
QT_TRANSLATE_NOOP("bitcoin-core", "This help message"),
QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", "To use the %s option"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %d, %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown -socks proxy version requested: %i"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Upgrade wallet to latest format"),
QT_TRANSLATE_NOOP("bitcoin-core", "Usage:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use OpenSSL (https) for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: 0)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: 1 when listening)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use the test network"),
QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart Bitcoin to complete"),
QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Disk space is low"),
}; };

View file

@ -130,9 +130,9 @@ QString ClientModel::clientName() const
return QString::fromStdString(CLIENT_NAME); return QString::fromStdString(CLIENT_NAME);
} }
QDateTime ClientModel::formatClientStartupTime() const QString ClientModel::formatClientStartupTime() const
{ {
return QDateTime::fromTime_t(nClientStartupTime); return QDateTime::fromTime_t(nClientStartupTime).toString();
} }
// Handlers for core signals // Handlers for core signals

View file

@ -41,7 +41,7 @@ public:
QString formatFullVersion() const; QString formatFullVersion() const;
QString formatBuildDate() const; QString formatBuildDate() const;
QString clientName() const; QString clientName() const;
QDateTime formatClientStartupTime() const; QString formatClientStartupTime() const;
private: private:
OptionsModel *optionsModel; OptionsModel *optionsModel;

View file

@ -0,0 +1,466 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OptionsDialog</class>
<widget class="QDialog" name="OptionsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>540</width>
<height>380</height>
</rect>
</property>
<property name="windowTitle">
<string>Options</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="tabPosition">
<enum>QTabWidget::North</enum>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabMain">
<attribute name="title">
<string>&amp;Main</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_Main">
<item>
<widget class="QLabel" name="transactionFeeInfoLabel">
<property name="text">
<string>Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended.</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_Main">
<item>
<widget class="QLabel" name="transactionFeeLabel">
<property name="text">
<string>Pay transaction &amp;fee</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>transactionFee</cstring>
</property>
</widget>
</item>
<item>
<widget class="BitcoinAmountField" name="transactionFee"/>
</item>
<item>
<spacer name="horizontalSpacer_Main">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="bitcoinAtStartup">
<property name="toolTip">
<string>Automatically start Bitcoin after logging in to the system.</string>
</property>
<property name="text">
<string>&amp;Start Bitcoin on system login</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="detachDatabases">
<property name="toolTip">
<string>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.</string>
</property>
<property name="text">
<string>&amp;Detach databases at shutdown</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_Main">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabNetwork">
<attribute name="title">
<string>&amp;Network</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_Network">
<item>
<widget class="QCheckBox" name="mapPortUpnp">
<property name="toolTip">
<string>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</string>
</property>
<property name="text">
<string>Map port using &amp;UPnP</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="connectSocks">
<property name="toolTip">
<string>Connect to the Bitcon network through a SOCKS proxy (e.g. when connecting through Tor).</string>
</property>
<property name="text">
<string>&amp;Connect through SOCKS proxy:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_Network">
<item>
<widget class="QLabel" name="proxyIpLabel">
<property name="text">
<string>Proxy &amp;IP:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>proxyIp</cstring>
</property>
</widget>
</item>
<item>
<widget class="QValidatedLineEdit" name="proxyIp">
<property name="maximumSize">
<size>
<width>140</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>IP address of the proxy (e.g. 127.0.0.1)</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="proxyPortLabel">
<property name="text">
<string>&amp;Port:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>proxyPort</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="proxyPort">
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Port of the proxy (e.g. 9050)</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="socksVersionLabel">
<property name="text">
<string>SOCKS &amp;Version:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>socksVersion</cstring>
</property>
</widget>
</item>
<item>
<widget class="QValueComboBox" name="socksVersion">
<property name="toolTip">
<string>SOCKS version of the proxy (e.g. 5)</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_Network">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_Network">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabWindow">
<attribute name="title">
<string>&amp;Window</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_Window">
<item>
<widget class="QCheckBox" name="minimizeToTray">
<property name="toolTip">
<string>Show only a tray icon after minimizing the window.</string>
</property>
<property name="text">
<string>&amp;Minimize to the tray instead of the taskbar</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="minimizeOnClose">
<property name="toolTip">
<string>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.</string>
</property>
<property name="text">
<string>M&amp;inimize on close</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_Window">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabDisplay">
<attribute name="title">
<string>&amp;Display</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_Display">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_1_Display">
<item>
<widget class="QLabel" name="langLabel">
<property name="text">
<string>User Interface &amp;language:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>lang</cstring>
</property>
</widget>
</item>
<item>
<widget class="QValueComboBox" name="lang">
<property name="toolTip">
<string>The user interface language can be set here. This setting will take effect after restarting Bitcoin.</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2_Display">
<item>
<widget class="QLabel" name="unitLabel">
<property name="text">
<string>&amp;Unit to show amounts in:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>unit</cstring>
</property>
</widget>
</item>
<item>
<widget class="QValueComboBox" name="unit">
<property name="toolTip">
<string>Choose the default subdivision unit to show in the interface and when sending coins.</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="displayAddresses">
<property name="toolTip">
<string>Whether to show Bitcoin addresses in the transaction list or not.</string>
</property>
<property name="text">
<string>&amp;Display addresses in transaction list</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_Display">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_Buttons">
<item>
<spacer name="horizontalSpacer_1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>48</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="statusLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>48</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="okButton">
<property name="text">
<string>&amp;OK</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="text">
<string>&amp;Cancel</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="applyButton">
<property name="text">
<string>&amp;Apply</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="default">
<bool>false</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>BitcoinAmountField</class>
<extends>QSpinBox</extends>
<header>bitcoinamountfield.h</header>
</customwidget>
<customwidget>
<class>QValueComboBox</class>
<extends>QComboBox</extends>
<header>qvaluecombobox.h</header>
</customwidget>
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
<header>qvalidatedlineedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>552</width> <width>573</width>
<height>342</height> <height>342</height>
</rect> </rect>
</property> </property>
@ -105,7 +105,7 @@
<string>Your current balance</string> <string>Your current balance</string>
</property> </property>
<property name="text"> <property name="text">
<string notr="true">123.456 BTC</string> <string notr="true">0 BTC</string>
</property> </property>
<property name="textInteractionFlags"> <property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
@ -141,14 +141,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="3" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>Number of transactions:</string> <string>Number of transactions:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="3" column="1">
<widget class="QLabel" name="labelNumTransactions"> <widget class="QLabel" name="labelNumTransactions">
<property name="toolTip"> <property name="toolTip">
<string>Total number of transactions in wallet</string> <string>Total number of transactions in wallet</string>
@ -158,6 +158,32 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<widget class="QLabel" name="labelImmatureText">
<property name="text">
<string>Immature:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="labelImmature">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Mined balance that has not yet matured</string>
</property>
<property name="text">
<string notr="true">0 BTC</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>

View file

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>706</width> <width>740</width>
<height>446</height> <height>450</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -301,9 +301,38 @@
<property name="text"> <property name="text">
<string>&amp;Open</string> <string>&amp;Open</string>
</property> </property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
<item row="15" column="0"> <item row="15" column="0">
<widget class="QLabel" name="labelCLOptions">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Command-line options</string>
</property>
</widget>
</item>
<item row="16" column="0">
<widget class="QPushButton" name="showCLOptionsButton">
<property name="toolTip">
<string>Show the Bitcoin-Qt help message to get a list with possible Bitcoin command-line options.</string>
</property>
<property name="text">
<string>&amp;Show</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="17" column="0">
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>

View file

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>494</width> <width>650</width>
<height>342</height> <height>380</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -17,7 +17,7 @@
<item> <item>
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
<string>Enter the message and signature below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to obtain the Bitcoin address used to sign the message.</string> <string>Enter the signing address, signature and message below (be careful to correctly copy newlines, spaces, tabs and other invisible characters) to verify the message.</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
@ -27,39 +27,29 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QValidatedLineEdit" name="lnAddress">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QValidatedLineEdit" name="lnSig">
<property name="text">
<string/>
</property>
</widget>
</item>
<item> <item>
<widget class="QPlainTextEdit" name="edMessage"/> <widget class="QPlainTextEdit" name="edMessage"/>
</item> </item>
<item>
<widget class="QLineEdit" name="lnSig">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lnAddress">
<property name="text">
<string/>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblStatus">
<property name="text">
<string/>
</property>
</widget>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QPushButton" name="verifyMessage"> <widget class="QPushButton" name="verifyMessage">
<property name="toolTip"> <property name="toolTip">
<string>Verify a message and obtain the Bitcoin address used to sign the message</string> <string>Verify a message to ensure it was signed with the specified Bitcoin address</string>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Verify Message</string> <string>&amp;Verify Message</string>
@ -70,23 +60,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="copyToClipboard">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Copy the currently selected address to the system clipboard</string>
</property>
<property name="text">
<string>&amp;Copy Address</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/editcopy</normaloff>:/icons/editcopy</iconset>
</property>
</widget>
</item>
<item> <item>
<widget class="QPushButton" name="clearButton"> <widget class="QPushButton" name="clearButton">
<property name="toolTip"> <property name="toolTip">
@ -101,6 +74,41 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="lblStatus">
<property name="minimumSize">
<size>
<width>0</width>
<height>48</height>
</size>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
@ -118,6 +126,13 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
<header>qvalidatedlineedit.h</header>
</customwidget>
</customwidgets>
<resources> <resources>
<include location="../bitcoin.qrc"/> <include location="../bitcoin.qrc"/>
</resources> </resources>

View file

@ -3,6 +3,8 @@
#include "walletmodel.h" #include "walletmodel.h"
#include "bitcoinunits.h" #include "bitcoinunits.h"
#include "util.h" #include "util.h"
#include "init.h"
#include "base58.h"
#include <QString> #include <QString>
#include <QDateTime> #include <QDateTime>
@ -35,6 +37,8 @@
#define NOMINMAX #define NOMINMAX
#endif #endif
#include "shlwapi.h" #include "shlwapi.h"
#include "shlobj.h"
#include "shellapi.h"
#endif #endif
namespace GUIUtil { namespace GUIUtil {
@ -77,6 +81,11 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
if(uri.scheme() != QString("bitcoin")) if(uri.scheme() != QString("bitcoin"))
return false; return false;
// check if the address is valid
CBitcoinAddress addressFromUri(uri.path().toStdString());
if (!addressFromUri.IsValid())
return false;
SendCoinsRecipient rv; SendCoinsRecipient rv;
rv.address = uri.path(); rv.address = uri.path();
rv.amount = 0; rv.amount = 0;
@ -219,30 +228,27 @@ Qt::ConnectionType blockingGUIThreadConnection()
bool checkPoint(const QPoint &p, const QWidget *w) bool checkPoint(const QPoint &p, const QWidget *w)
{ {
QWidget *atW = qApp->widgetAt(w->mapToGlobal(p)); QWidget *atW = qApp->widgetAt(w->mapToGlobal(p));
if(!atW) return false; if (!atW) return false;
return atW->topLevelWidget() == w; return atW->topLevelWidget() == w;
} }
bool isObscured(QWidget *w) bool isObscured(QWidget *w)
{ {
return !(checkPoint(QPoint(0, 0), w)
return !(checkPoint(QPoint(0, 0), w) && checkPoint(QPoint(w->width() - 1, 0), w)
&& checkPoint(QPoint(w->width() - 1, 0), w) && checkPoint(QPoint(0, w->height() - 1), w)
&& checkPoint(QPoint(0, w->height() - 1), w) && checkPoint(QPoint(w->width() - 1, w->height() - 1), w)
&& checkPoint(QPoint(w->width() - 1, w->height() - 1), w) && checkPoint(QPoint(w->width() / 2, w->height() / 2), w));
&& checkPoint(QPoint(w->width()/2, w->height()/2), w));
} }
void openDebugLogfile() void openDebugLogfile()
{ {
boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
#ifdef WIN32 /* Open debug.log with the associated application */
if (boost::filesystem::exists(pathDebug)) if (boost::filesystem::exists(pathDebug))
/* Open debug.log with the associated application */ QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(pathDebug.string())));
ShellExecuteA((HWND)0, (LPCSTR)"open", (LPCSTR)pathDebug.string().c_str(), NULL, NULL, SW_SHOWNORMAL);
#endif
} }
ToolTipToRichTextFilter::ToolTipToRichTextFilter(int size_threshold, QObject *parent) : ToolTipToRichTextFilter::ToolTipToRichTextFilter(int size_threshold, QObject *parent) :
@ -413,5 +419,39 @@ bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
#endif #endif
HelpMessageBox::HelpMessageBox(QWidget *parent) :
QMessageBox(parent)
{
header = tr("Bitcoin-Qt") + " " + tr("version") + " " +
QString::fromStdString(FormatFullVersion()) + "\n\n" +
tr("Usage:") + "\n" +
" bitcoin-qt [" + tr("command-line options") + "] " + "\n";
coreOptions = QString::fromStdString(HelpMessage());
uiOptions = tr("UI options") + ":\n" +
" -lang=<lang> " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
" -min " + tr("Start minimized") + "\n" +
" -splash " + tr("Show splash screen on startup (default: 1)") + "\n";
setWindowTitle(tr("Bitcoin-Qt"));
setTextFormat(Qt::PlainText);
// setMinimumWidth is ignored for QMessageBox so put in nonbreaking spaces to make it wider.
setText(header + QString(QChar(0x2003)).repeated(50));
setDetailedText(coreOptions + "\n" + uiOptions);
}
void HelpMessageBox::exec()
{
#if defined(WIN32)
// On windows, show a message box, as there is no stderr in windowed applications
QMessageBox::exec();
#else
// On other operating systems, the expected action is to print the message to the console.
QString strUsage = header + "\n" + coreOptions + "\n" + uiOptions;
fprintf(stderr, "%s", strUsage.toStdString().c_str());
#endif
}
} // namespace GUIUtil } // namespace GUIUtil

View file

@ -3,6 +3,7 @@
#include <QString> #include <QString>
#include <QObject> #include <QObject>
#include <QMessageBox>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QFont; class QFont;
@ -80,6 +81,7 @@ namespace GUIUtil
class ToolTipToRichTextFilter : public QObject class ToolTipToRichTextFilter : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit ToolTipToRichTextFilter(int size_threshold, QObject *parent = 0); explicit ToolTipToRichTextFilter(int size_threshold, QObject *parent = 0);
@ -93,6 +95,22 @@ namespace GUIUtil
bool GetStartOnSystemStartup(); bool GetStartOnSystemStartup();
bool SetStartOnSystemStartup(bool fAutoStart); bool SetStartOnSystemStartup(bool fAutoStart);
/** Help message for Bitcoin-Qt, shown with --help. */
class HelpMessageBox : public QMessageBox
{
Q_OBJECT
public:
HelpMessageBox(QWidget *parent = 0);
void exec();
private:
QString header;
QString coreOptions;
QString uiOptions;
};
} // namespace GUIUtil } // namespace GUIUtil
#endif // GUIUTIL_H #endif // GUIUTIL_H

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,7 @@
#include "main.h" #include "main.h"
#include "wallet.h" #include "wallet.h"
#include "init.h" #include "init.h"
#include "base58.h"
#include "messagepage.h" #include "messagepage.h"
#include "ui_messagepage.h" #include "ui_messagepage.h"
@ -83,6 +84,13 @@ void MessagePage::on_signMessage_clicked()
QMessageBox::Abort, QMessageBox::Abort); QMessageBox::Abort, QMessageBox::Abort);
return; return;
} }
CKeyID keyID;
if (!addr.GetKeyID(keyID))
{
QMessageBox::critical(this, tr("Error signing"), tr("%1 does not refer to a key.").arg(address),
QMessageBox::Abort, QMessageBox::Abort);
return;
}
WalletModel::UnlockContext ctx(model->requestUnlock()); WalletModel::UnlockContext ctx(model->requestUnlock());
if(!ctx.isValid()) if(!ctx.isValid())
@ -92,7 +100,7 @@ void MessagePage::on_signMessage_clicked()
} }
CKey key; CKey key;
if (!pwalletMain->GetKey(addr, key)) if (!pwalletMain->GetKey(keyID, key))
{ {
QMessageBox::critical(this, tr("Error signing"), tr("Private key for %1 is not available.").arg(address), QMessageBox::critical(this, tr("Error signing"), tr("Private key for %1 is not available.").arg(address),
QMessageBox::Abort, QMessageBox::Abort); QMessageBox::Abort, QMessageBox::Abort);

View file

@ -1,396 +1,218 @@
#include "optionsdialog.h" #include "optionsdialog.h"
#include "optionsmodel.h" #include "ui_optionsdialog.h"
#include "bitcoinamountfield.h" #include "bitcoinamountfield.h"
#include "monitoreddatamapper.h"
#include "guiutil.h"
#include "bitcoinunits.h" #include "bitcoinunits.h"
#include "monitoreddatamapper.h"
#include "netbase.h"
#include "optionsmodel.h"
#include "qvalidatedlineedit.h"
#include "qvaluecombobox.h" #include "qvaluecombobox.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QListWidget>
#include <QStackedWidget>
#include <QCheckBox> #include <QCheckBox>
#include <QDir>
#include <QIntValidator>
#include <QLabel> #include <QLabel>
#include <QLineEdit> #include <QLineEdit>
#include <QIntValidator>
#include <QDoubleValidator>
#include <QRegExpValidator>
#include <QDialogButtonBox>
#include <QDir>
#include <QMessageBox> #include <QMessageBox>
#include <QPushButton>
#include <QRegExp>
#include <QRegExpValidator>
#include <QTabWidget>
#include <QWidget>
class OptionsPage: public QWidget OptionsDialog::OptionsDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::OptionsDialog),
model(0),
mapper(0),
fRestartWarningDisplayed_Proxy(false),
fRestartWarningDisplayed_Lang(false),
fProxyIpValid(true)
{ {
Q_OBJECT ui->setupUi(this);
public:
explicit OptionsPage(QWidget *parent=0): QWidget(parent) {}
virtual void setMapper(MonitoredDataMapper *mapper) = 0; /* Network elements init */
}; #ifndef USE_UPNP
ui->mapPortUpnp->setEnabled(false);
class MainOptionsPage: public OptionsPage
{
Q_OBJECT
public:
explicit MainOptionsPage(QWidget *parent=0);
virtual void setMapper(MonitoredDataMapper *mapper);
private:
BitcoinAmountField *fee_edit;
QCheckBox *bitcoin_at_startup;
QCheckBox *detach_database;
};
class WindowOptionsPage: public OptionsPage
{
Q_OBJECT
public:
explicit WindowOptionsPage(QWidget *parent=0);
virtual void setMapper(MonitoredDataMapper *mapper);
private:
#ifndef Q_WS_MAC
QCheckBox *minimize_to_tray;
QCheckBox *minimize_on_close;
#endif #endif
};
class DisplayOptionsPage: public OptionsPage ui->socksVersion->setEnabled(false);
{ ui->socksVersion->addItem("5", 5);
Q_OBJECT ui->socksVersion->addItem("4", 4);
public: ui->socksVersion->setCurrentIndex(0);
explicit DisplayOptionsPage(QWidget *parent=0);
virtual void setMapper(MonitoredDataMapper *mapper); ui->proxyIp->setEnabled(false);
private: ui->proxyPort->setEnabled(false);
QValueComboBox *lang; ui->proxyPort->setValidator(new QIntValidator(0, 65535, this));
QValueComboBox *unit;
QCheckBox *display_addresses;
bool restart_warning_displayed;
private slots:
void showRestartWarning();
};
class NetworkOptionsPage: public OptionsPage connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->socksVersion, SLOT(setEnabled(bool)));
{ connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool)));
Q_OBJECT connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool)));
public:
explicit NetworkOptionsPage(QWidget *parent=0);
virtual void setMapper(MonitoredDataMapper *mapper); ui->proxyIp->installEventFilter(this);
private:
QCheckBox *map_port_upnp;
QCheckBox *connect_socks4;
QLineEdit *proxy_ip;
QLineEdit *proxy_port;
};
/* Window elements init */
#include "optionsdialog.moc" #ifdef Q_WS_MAC
ui->tabWindow->setVisible(false);
OptionsDialog::OptionsDialog(QWidget *parent):
QDialog(parent), contents_widget(0), pages_widget(0),
model(0)
{
contents_widget = new QListWidget();
contents_widget->setMaximumWidth(128);
pages_widget = new QStackedWidget();
pages_widget->setMinimumWidth(500);
pages_widget->setMinimumHeight(300);
pages.append(new MainOptionsPage(this));
pages.append(new NetworkOptionsPage(this));
#ifndef Q_WS_MAC
/* Hide Window options on Mac as there are currently none available */
pages.append(new WindowOptionsPage(this));
#endif #endif
pages.append(new DisplayOptionsPage(this));
foreach(OptionsPage *page, pages) /* Display elements init */
QDir translations(":translations");
ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
foreach(const QString &langStr, translations.entryList())
{ {
QListWidgetItem *item = new QListWidgetItem(page->windowTitle()); ui->lang->addItem(langStr, QVariant(langStr));
contents_widget->addItem(item);
pages_widget->addWidget(page);
} }
contents_widget->setCurrentRow(0); ui->unit->setModel(new BitcoinUnits(this));
QHBoxLayout *main_layout = new QHBoxLayout(); connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning_Proxy()));
main_layout->addWidget(contents_widget); connect(ui->lang, SIGNAL(activated(int)), this, SLOT(showRestartWarning_Lang()));
main_layout->addWidget(pages_widget, 1);
QVBoxLayout *layout = new QVBoxLayout();
layout->addLayout(main_layout);
QDialogButtonBox *buttonbox = new QDialogButtonBox();
buttonbox->setStandardButtons(QDialogButtonBox::Apply|QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
apply_button = buttonbox->button(QDialogButtonBox::Apply);
layout->addWidget(buttonbox);
setLayout(layout);
setWindowTitle(tr("Options"));
/* Widget-to-option mapper */ /* Widget-to-option mapper */
mapper = new MonitoredDataMapper(this); mapper = new MonitoredDataMapper(this);
mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
mapper->setOrientation(Qt::Vertical); mapper->setOrientation(Qt::Vertical);
/* enable apply button when data modified */
connect(mapper, SIGNAL(viewModified()), this, SLOT(enableApply()));
/* disable apply button when new data loaded */
connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(disableApply()));
/* Event bindings */ /* enable save buttons when data modified */
connect(contents_widget, SIGNAL(currentRowChanged(int)), this, SLOT(changePage(int))); connect(mapper, SIGNAL(viewModified()), this, SLOT(enableSaveButtons()));
connect(buttonbox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(okClicked())); /* disable save buttons when new data loaded */
connect(buttonbox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(cancelClicked())); connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(disableSaveButtons()));
connect(buttonbox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(applyClicked())); /* disable/enable save buttons when proxy IP is invalid/valid */
connect(this, SIGNAL(proxyIpValid(bool)), this, SLOT(setSaveButtonState(bool)));
}
OptionsDialog::~OptionsDialog()
{
delete ui;
} }
void OptionsDialog::setModel(OptionsModel *model) void OptionsDialog::setModel(OptionsModel *model)
{ {
this->model = model; this->model = model;
mapper->setModel(model); if(model)
foreach(OptionsPage *page, pages)
{ {
page->setMapper(mapper); connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
mapper->setModel(model);
setMapper();
mapper->toFirst();
} }
mapper->toFirst(); // update the display unit, to not use the default ("BTC")
updateDisplayUnit();
} }
void OptionsDialog::changePage(int index) void OptionsDialog::setMapper()
{ {
pages_widget->setCurrentIndex(index); /* Main */
mapper->addMapping(ui->transactionFee, OptionsModel::Fee);
mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup);
mapper->addMapping(ui->detachDatabases, OptionsModel::DetachDatabases);
/* Network */
mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);
mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
mapper->addMapping(ui->socksVersion, OptionsModel::ProxySocksVersion);
mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP);
mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
/* Window */
#ifndef Q_WS_MAC
mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose);
#endif
/* Display */
mapper->addMapping(ui->lang, OptionsModel::Language);
mapper->addMapping(ui->unit, OptionsModel::DisplayUnit);
mapper->addMapping(ui->displayAddresses, OptionsModel::DisplayAddresses);
} }
void OptionsDialog::okClicked() void OptionsDialog::enableSaveButtons()
{
// prevent enabling of the save buttons when data modified, if there is an invalid proxy address present
if(fProxyIpValid)
setSaveButtonState(true);
}
void OptionsDialog::disableSaveButtons()
{
setSaveButtonState(false);
}
void OptionsDialog::setSaveButtonState(bool fState)
{
ui->applyButton->setEnabled(fState);
ui->okButton->setEnabled(fState);
}
void OptionsDialog::on_okButton_clicked()
{ {
mapper->submit(); mapper->submit();
accept(); accept();
} }
void OptionsDialog::cancelClicked() void OptionsDialog::on_cancelButton_clicked()
{ {
reject(); reject();
} }
void OptionsDialog::applyClicked() void OptionsDialog::on_applyButton_clicked()
{ {
mapper->submit(); mapper->submit();
apply_button->setEnabled(false); ui->applyButton->setEnabled(false);
} }
void OptionsDialog::enableApply() void OptionsDialog::showRestartWarning_Proxy()
{ {
apply_button->setEnabled(true); if(!fRestartWarningDisplayed_Proxy)
}
void OptionsDialog::disableApply()
{
apply_button->setEnabled(false);
}
/* Main options */
MainOptionsPage::MainOptionsPage(QWidget *parent):
OptionsPage(parent)
{
QVBoxLayout *layout = new QVBoxLayout();
setWindowTitle(tr("Main"));
QLabel *fee_help = new QLabel(tr("Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended."));
fee_help->setWordWrap(true);
layout->addWidget(fee_help);
QHBoxLayout *fee_hbox = new QHBoxLayout();
fee_hbox->addSpacing(18);
QLabel *fee_label = new QLabel(tr("Pay transaction &fee"));
fee_hbox->addWidget(fee_label);
fee_edit = new BitcoinAmountField();
fee_label->setBuddy(fee_edit);
fee_hbox->addWidget(fee_edit);
fee_hbox->addStretch(1);
layout->addLayout(fee_hbox);
bitcoin_at_startup = new QCheckBox(tr("&Start Bitcoin on system login"));
bitcoin_at_startup->setToolTip(tr("Automatically start Bitcoin after logging in to the system"));
layout->addWidget(bitcoin_at_startup);
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);
}
void MainOptionsPage::setMapper(MonitoredDataMapper *mapper)
{
// Map model to widgets
mapper->addMapping(fee_edit, OptionsModel::Fee);
mapper->addMapping(bitcoin_at_startup, OptionsModel::StartAtStartup);
mapper->addMapping(detach_database, OptionsModel::DetachDatabases);
}
/* Display options */
DisplayOptionsPage::DisplayOptionsPage(QWidget *parent):
OptionsPage(parent), restart_warning_displayed(false)
{
setWindowTitle(tr("Display"));
QVBoxLayout *layout = new QVBoxLayout();
QHBoxLayout *lang_hbox = new QHBoxLayout();
lang_hbox->addSpacing(18);
QLabel *lang_label = new QLabel(tr("User Interface &Language:"));
lang_hbox->addWidget(lang_label);
lang = new QValueComboBox(this);
// Make list of languages
QDir translations(":translations");
lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
foreach(const QString &langStr, translations.entryList())
{
lang->addItem(langStr, QVariant(langStr));
}
lang->setToolTip(tr("The user interface language can be set here. This setting will only take effect after restarting Bitcoin."));
connect(lang, SIGNAL(activated(int)), this, SLOT(showRestartWarning()));
lang_label->setBuddy(lang);
lang_hbox->addWidget(lang);
layout->addLayout(lang_hbox);
QHBoxLayout *unit_hbox = new QHBoxLayout();
unit_hbox->addSpacing(18);
QLabel *unit_label = new QLabel(tr("&Unit to show amounts in:"));
unit_hbox->addWidget(unit_label);
unit = new QValueComboBox(this);
unit->setModel(new BitcoinUnits(this));
unit->setToolTip(tr("Choose the default subdivision unit to show in the interface, and when sending coins"));
unit_label->setBuddy(unit);
unit_hbox->addWidget(unit);
layout->addLayout(unit_hbox);
display_addresses = new QCheckBox(tr("&Display addresses in transaction list"), this);
display_addresses->setToolTip(tr("Whether to show Bitcoin addresses in the transaction list"));
layout->addWidget(display_addresses);
layout->addStretch();
setLayout(layout);
}
void DisplayOptionsPage::setMapper(MonitoredDataMapper *mapper)
{
mapper->addMapping(lang, OptionsModel::Language);
mapper->addMapping(unit, OptionsModel::DisplayUnit);
mapper->addMapping(display_addresses, OptionsModel::DisplayAddresses);
}
void DisplayOptionsPage::showRestartWarning()
{
if(!restart_warning_displayed)
{ {
QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting Bitcoin."), QMessageBox::Ok); QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting Bitcoin."), QMessageBox::Ok);
restart_warning_displayed = true; fRestartWarningDisplayed_Proxy = true;
} }
} }
/* Window options */ void OptionsDialog::showRestartWarning_Lang()
WindowOptionsPage::WindowOptionsPage(QWidget *parent):
OptionsPage(parent)
{ {
QVBoxLayout *layout = new QVBoxLayout(); if(!fRestartWarningDisplayed_Lang)
setWindowTitle(tr("Window")); {
QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting Bitcoin."), QMessageBox::Ok);
#ifndef Q_WS_MAC fRestartWarningDisplayed_Lang = true;
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);
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
layout->addStretch(1); // Extra space at bottom
setLayout(layout);
} }
void WindowOptionsPage::setMapper(MonitoredDataMapper *mapper) void OptionsDialog::updateDisplayUnit()
{ {
// Map model to widgets if(model)
#ifndef Q_WS_MAC {
mapper->addMapping(minimize_to_tray, OptionsModel::MinimizeToTray); // Update transactionFee with the current unit
#endif ui->transactionFee->setDisplayUnit(model->getDisplayUnit());
#ifndef Q_WS_MAC }
mapper->addMapping(minimize_on_close, OptionsModel::MinimizeOnClose);
#endif
} }
/* Network options */ bool OptionsDialog::eventFilter(QObject *object, QEvent *event)
NetworkOptionsPage::NetworkOptionsPage(QWidget *parent):
OptionsPage(parent)
{ {
QVBoxLayout *layout = new QVBoxLayout(); if(object == ui->proxyIp && event->type() == QEvent::FocusOut)
setWindowTitle(tr("Network")); {
// Check proxyIP for a valid IPv4/IPv6 address
map_port_upnp = new QCheckBox(tr("Map port using &UPnP")); CService addr;
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.")); if(!LookupNumeric(ui->proxyIp->text().toStdString().c_str(), addr))
layout->addWidget(map_port_upnp); {
ui->proxyIp->setValid(false);
connect_socks4 = new QCheckBox(tr("&Connect through SOCKS4 proxy:")); fProxyIpValid = false;
connect_socks4->setToolTip(tr("Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor)")); ui->statusLabel->setStyleSheet("QLabel { color: red; }");
layout->addWidget(connect_socks4); ui->statusLabel->setText(tr("The supplied proxy address is invalid."));
emit proxyIpValid(false);
QHBoxLayout *proxy_hbox = new QHBoxLayout(); }
proxy_hbox->addSpacing(18); else
QLabel *proxy_ip_label = new QLabel(tr("Proxy &IP:")); {
proxy_hbox->addWidget(proxy_ip_label); fProxyIpValid = true;
proxy_ip = new QLineEdit(); ui->statusLabel->clear();
proxy_ip->setMaximumWidth(140); emit proxyIpValid(true);
proxy_ip->setEnabled(false); }
proxy_ip->setValidator(new QRegExpValidator(QRegExp("[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}"), this)); }
proxy_ip->setToolTip(tr("IP address of the proxy (e.g. 127.0.0.1)")); return QDialog::eventFilter(object, event);
proxy_ip_label->setBuddy(proxy_ip);
proxy_hbox->addWidget(proxy_ip);
QLabel *proxy_port_label = new QLabel(tr("&Port:"));
proxy_hbox->addWidget(proxy_port_label);
proxy_port = new QLineEdit();
proxy_port->setMaximumWidth(55);
proxy_port->setValidator(new QIntValidator(0, 65535, this));
proxy_port->setEnabled(false);
proxy_port->setToolTip(tr("Port of the proxy (e.g. 1234)"));
proxy_port_label->setBuddy(proxy_port);
proxy_hbox->addWidget(proxy_port);
proxy_hbox->addStretch(1);
layout->addLayout(proxy_hbox);
layout->addStretch(1); // Extra space at bottom
setLayout(layout);
connect(connect_socks4, SIGNAL(toggled(bool)), proxy_ip, SLOT(setEnabled(bool)));
connect(connect_socks4, SIGNAL(toggled(bool)), proxy_port, SLOT(setEnabled(bool)));
#ifndef USE_UPNP
map_port_upnp->setDisabled(true);
#endif
}
void NetworkOptionsPage::setMapper(MonitoredDataMapper *mapper)
{
// Map model to widgets
mapper->addMapping(map_port_upnp, OptionsModel::MapPortUPnP);
mapper->addMapping(connect_socks4, OptionsModel::ConnectSOCKS4);
mapper->addMapping(proxy_ip, OptionsModel::ProxyIP);
mapper->addMapping(proxy_port, OptionsModel::ProxyPort);
} }

View file

@ -2,48 +2,53 @@
#define OPTIONSDIALOG_H #define OPTIONSDIALOG_H
#include <QDialog> #include <QDialog>
#include <QList>
QT_BEGIN_NAMESPACE namespace Ui {
class QStackedWidget; class OptionsDialog;
class QListWidget; }
class QListWidgetItem;
class QPushButton;
QT_END_NAMESPACE
class OptionsModel; class OptionsModel;
class OptionsPage;
class MonitoredDataMapper; class MonitoredDataMapper;
/** Preferences dialog. */ /** Preferences dialog. */
class OptionsDialog : public QDialog class OptionsDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit OptionsDialog(QWidget *parent=0); explicit OptionsDialog(QWidget *parent = 0);
~OptionsDialog();
void setModel(OptionsModel *model); void setModel(OptionsModel *model);
void setMapper();
signals: protected:
bool eventFilter(QObject *object, QEvent *event);
public slots:
/** Change the current page to \a index. */
void changePage(int index);
private slots: private slots:
void okClicked(); /* enable apply button and OK button */
void cancelClicked(); void enableSaveButtons();
void applyClicked(); /* disable apply button and OK button */
void enableApply(); void disableSaveButtons();
void disableApply(); /* set apply button and OK button state (enabled / disabled) */
void setSaveButtonState(bool fState);
void on_okButton_clicked();
void on_cancelButton_clicked();
void on_applyButton_clicked();
void showRestartWarning_Proxy();
void showRestartWarning_Lang();
void updateDisplayUnit();
signals:
void proxyIpValid(bool fValid);
private: private:
QListWidget *contents_widget; Ui::OptionsDialog *ui;
QStackedWidget *pages_widget;
OptionsModel *model; OptionsModel *model;
MonitoredDataMapper *mapper; MonitoredDataMapper *mapper;
QPushButton *apply_button; bool fRestartWarningDisplayed_Proxy;
bool fRestartWarningDisplayed_Lang;
QList<OptionsPage*> pages; bool fProxyIpValid;
}; };
#endif // OPTIONSDIALOG_H #endif // OPTIONSDIALOG_H

View file

@ -12,6 +12,30 @@ OptionsModel::OptionsModel(QObject *parent) :
Init(); Init();
} }
bool static ApplyProxySettings()
{
QSettings settings;
CService addrProxy(settings.value("addrProxy", "127.0.0.1:9050").toString().toStdString());
int nSocksVersion(settings.value("nSocksVersion", 5).toInt());
if (!settings.value("fUseProxy", false).toBool()) {
addrProxy = CService();
nSocksVersion = 0;
return false;
}
if (nSocksVersion && !addrProxy.IsValid())
return false;
if (!IsLimited(NET_IPV4))
SetProxy(NET_IPV4, addrProxy, nSocksVersion);
if (nSocksVersion > 4) {
#ifdef USE_IPV6
if (!IsLimited(NET_IPV6))
SetProxy(NET_IPV6, addrProxy, nSocksVersion);
#endif
SetNameProxy(addrProxy, nSocksVersion);
}
return true;
}
void OptionsModel::Init() void OptionsModel::Init()
{ {
QSettings settings; QSettings settings;
@ -30,6 +54,8 @@ void OptionsModel::Init()
SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()); SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool());
if (settings.contains("addrProxy") && settings.value("fUseProxy").toBool()) if (settings.contains("addrProxy") && settings.value("fUseProxy").toBool())
SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()); SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString());
if (settings.contains("nSocksVersion") && settings.value("fUseProxy").toBool())
SoftSetArg("-socks", settings.value("nSocksVersion").toString().toStdString());
if (settings.contains("detachDB")) if (settings.contains("detachDB"))
SoftSetBoolArg("-detachdb", settings.value("detachDB").toBool()); SoftSetBoolArg("-detachdb", settings.value("detachDB").toBool());
if (!language.isEmpty()) if (!language.isEmpty())
@ -75,20 +101,21 @@ bool OptionsModel::Upgrade()
CAddress addrProxyAddress; CAddress addrProxyAddress;
if (walletdb.ReadSetting("addrProxy", addrProxyAddress)) if (walletdb.ReadSetting("addrProxy", addrProxyAddress))
{ {
addrProxy = addrProxyAddress; settings.setValue("addrProxy", addrProxyAddress.ToStringIPPort().c_str());
settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str());
walletdb.EraseSetting("addrProxy"); walletdb.EraseSetting("addrProxy");
} }
} }
catch (std::ios_base::failure &e) catch (std::ios_base::failure &e)
{ {
// 0.6.0rc1 saved this as a CService, which causes failure when parsing as a CAddress // 0.6.0rc1 saved this as a CService, which causes failure when parsing as a CAddress
CService addrProxy;
if (walletdb.ReadSetting("addrProxy", addrProxy)) if (walletdb.ReadSetting("addrProxy", addrProxy))
{ {
settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str()); settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str());
walletdb.EraseSetting("addrProxy"); walletdb.EraseSetting("addrProxy");
} }
} }
ApplyProxySettings();
Init(); Init();
return true; return true;
@ -115,12 +142,24 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
return settings.value("fUseUPnP", GetBoolArg("-upnp", true)); return settings.value("fUseUPnP", GetBoolArg("-upnp", true));
case MinimizeOnClose: case MinimizeOnClose:
return QVariant(fMinimizeOnClose); return QVariant(fMinimizeOnClose);
case ConnectSOCKS4: case ProxyUse:
return settings.value("fUseProxy", false); return settings.value("fUseProxy", false);
case ProxyIP: case ProxySocksVersion:
return QVariant(QString::fromStdString(addrProxy.ToStringIP())); return settings.value("nSocksVersion", 5);
case ProxyPort: case ProxyIP: {
return QVariant(addrProxy.GetPort()); CService addrProxy;
if (GetProxy(NET_IPV4, addrProxy))
return QVariant(QString::fromStdString(addrProxy.ToStringIP()));
else
return QVariant(QString::fromStdString("127.0.0.1"));
}
case ProxyPort: {
CService addrProxy;
if (GetProxy(NET_IPV4, addrProxy))
return QVariant(addrProxy.GetPort());
else
return 9050;
}
case Fee: case Fee:
return QVariant(nTransactionFee); return QVariant(nTransactionFee);
case DisplayUnit: case DisplayUnit:
@ -137,7 +176,6 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
} }
return QVariant(); return QVariant();
} }
bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role) bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role)
{ {
bool successful = true; /* set to false on parse error */ bool successful = true; /* set to false on parse error */
@ -155,27 +193,33 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
break; break;
case MapPortUPnP: case MapPortUPnP:
{ {
bool bUseUPnP = value.toBool(); fUseUPnP = value.toBool();
settings.setValue("fUseUPnP", bUseUPnP); settings.setValue("fUseUPnP", fUseUPnP);
MapPort(bUseUPnP); MapPort();
} }
break; break;
case MinimizeOnClose: case MinimizeOnClose:
fMinimizeOnClose = value.toBool(); fMinimizeOnClose = value.toBool();
settings.setValue("fMinimizeOnClose", fMinimizeOnClose); settings.setValue("fMinimizeOnClose", fMinimizeOnClose);
break; break;
case ConnectSOCKS4: case ProxyUse:
fUseProxy = value.toBool(); settings.setValue("fUseProxy", value.toBool());
settings.setValue("fUseProxy", fUseProxy); ApplyProxySettings();
break;
case ProxySocksVersion:
settings.setValue("nSocksVersion", value.toInt());
ApplyProxySettings();
break; break;
case ProxyIP: case ProxyIP:
{ {
// Use CAddress to parse and check IP CService addrProxy("127.0.0.1", 9050);
GetProxy(NET_IPV4, addrProxy);
CNetAddr addr(value.toString().toStdString()); CNetAddr addr(value.toString().toStdString());
if (addr.IsValid()) if (addr.IsValid())
{ {
addrProxy.SetIP(addr); addrProxy.SetIP(addr);
settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str()); settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str());
successful = ApplyProxySettings();
} }
else else
{ {
@ -185,11 +229,14 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
break; break;
case ProxyPort: case ProxyPort:
{ {
CService addrProxy("127.0.0.1", 9050);
GetProxy(NET_IPV4, addrProxy);
int nPort = atoi(value.toString().toAscii().data()); int nPort = atoi(value.toString().toAscii().data());
if (nPort > 0 && nPort < std::numeric_limits<unsigned short>::max()) if (nPort > 0 && nPort < std::numeric_limits<unsigned short>::max())
{ {
addrProxy.SetPort(nPort); addrProxy.SetPort(nPort);
settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str()); settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str());
successful = ApplyProxySettings();
} }
else else
{ {

View file

@ -20,7 +20,8 @@ public:
MinimizeToTray, // bool MinimizeToTray, // bool
MapPortUPnP, // bool MapPortUPnP, // bool
MinimizeOnClose, // bool MinimizeOnClose, // bool
ConnectSOCKS4, // bool ProxyUse, // bool
ProxySocksVersion, // int
ProxyIP, // QString ProxyIP, // QString
ProxyPort, // QString ProxyPort, // QString
Fee, // qint64 Fee, // qint64

View file

@ -94,7 +94,9 @@ OverviewPage::OverviewPage(QWidget *parent) :
ui(new Ui::OverviewPage), ui(new Ui::OverviewPage),
currentBalance(-1), currentBalance(-1),
currentUnconfirmedBalance(-1), currentUnconfirmedBalance(-1),
txdelegate(new TxViewDelegate()), filter(0) currentImmatureBalance(-1),
txdelegate(new TxViewDelegate()),
filter(0)
{ {
ui->setupUi(this); ui->setupUi(this);
@ -125,13 +127,21 @@ OverviewPage::~OverviewPage()
delete ui; delete ui;
} }
void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance) void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance)
{ {
int unit = model->getOptionsModel()->getDisplayUnit(); int unit = model->getOptionsModel()->getDisplayUnit();
currentBalance = balance; currentBalance = balance;
currentUnconfirmedBalance = unconfirmedBalance; currentUnconfirmedBalance = unconfirmedBalance;
currentImmatureBalance = immatureBalance;
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance)); ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance));
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance)); ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance));
ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, immatureBalance));
// only show immature (newly mined) balance if it's non-zero, so as not to complicate things
// for the non-mining users
bool showImmature = immatureBalance != 0;
ui->labelImmature->setVisible(showImmature);
ui->labelImmatureText->setVisible(showImmature);
} }
void OverviewPage::setNumTransactions(int count) void OverviewPage::setNumTransactions(int count)
@ -156,8 +166,8 @@ void OverviewPage::setModel(WalletModel *model)
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress); ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
// Keep up to date with wallet // Keep up to date with wallet
setBalance(model->getBalance(), model->getUnconfirmedBalance()); setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance());
connect(model, SIGNAL(balanceChanged(qint64, qint64)), this, SLOT(setBalance(qint64, qint64))); connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64)));
setNumTransactions(model->getNumTransactions()); setNumTransactions(model->getNumTransactions());
connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int))); connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int)));
@ -171,7 +181,7 @@ void OverviewPage::displayUnitChanged()
if(!model || !model->getOptionsModel()) if(!model || !model->getOptionsModel())
return; return;
if(currentBalance != -1) if(currentBalance != -1)
setBalance(currentBalance, currentUnconfirmedBalance); setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance);
txdelegate->unit = model->getOptionsModel()->getDisplayUnit(); txdelegate->unit = model->getOptionsModel()->getDisplayUnit();
ui->listTransactions->update(); ui->listTransactions->update();

View file

@ -27,7 +27,7 @@ public:
void showOutOfSyncWarning(bool fShow); void showOutOfSyncWarning(bool fShow);
public slots: public slots:
void setBalance(qint64 balance, qint64 unconfirmedBalance); void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance);
void setNumTransactions(int count); void setNumTransactions(int count);
signals: signals:
@ -38,6 +38,7 @@ private:
WalletModel *model; WalletModel *model;
qint64 currentBalance; qint64 currentBalance;
qint64 currentUnconfirmedBalance; qint64 currentUnconfirmedBalance;
qint64 currentImmatureBalance;
TxViewDelegate *txdelegate; TxViewDelegate *txdelegate;
TransactionFilterProxy *filter; TransactionFilterProxy *filter;

View file

@ -109,12 +109,9 @@ RPCConsole::RPCConsole(QWidget *parent) :
{ {
ui->setupUi(this); ui->setupUi(this);
#ifdef WIN32 #ifndef Q_WS_MAC
ui->openDebugLogfileButton->setIcon(QIcon(":/icons/export")); ui->openDebugLogfileButton->setIcon(QIcon(":/icons/export"));
#else ui->showCLOptionsButton->setIcon(QIcon(":/icons/options"));
// Show Debug logfile label and Open button only for Windows
ui->labelDebugLogfile->setVisible(false);
ui->openDebugLogfileButton->setVisible(false);
#endif #endif
// Install event filter for up and down arrow // Install event filter for up and down arrow
@ -163,7 +160,7 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->clientVersion->setText(model->formatFullVersion()); ui->clientVersion->setText(model->formatFullVersion());
ui->clientName->setText(model->clientName()); ui->clientName->setText(model->clientName());
ui->buildDate->setText(model->formatBuildDate()); ui->buildDate->setText(model->formatBuildDate());
ui->startupTime->setText(model->formatClientStartupTime().toString()); ui->startupTime->setText(model->formatClientStartupTime());
setNumConnections(model->getNumConnections()); setNumConnections(model->getNumConnections());
ui->isTestNet->setChecked(model->isTestNet()); ui->isTestNet->setChecked(model->isTestNet());
@ -326,3 +323,9 @@ void RPCConsole::scrollToEnd()
QScrollBar *scrollbar = ui->messagesWidget->verticalScrollBar(); QScrollBar *scrollbar = ui->messagesWidget->verticalScrollBar();
scrollbar->setValue(scrollbar->maximum()); scrollbar->setValue(scrollbar->maximum());
} }
void RPCConsole::on_showCLOptionsButton_clicked()
{
GUIUtil::HelpMessageBox help;
help.exec();
}

View file

@ -35,6 +35,8 @@ private slots:
void on_tabWidget_currentChanged(int index); void on_tabWidget_currentChanged(int index);
/** open the debug.log from the current datadir */ /** open the debug.log from the current datadir */
void on_openDebugLogfileButton_clicked(); void on_openDebugLogfileButton_clicked();
/** display messagebox with program parameters (same as bitcoin-qt --help) */
void on_showCLOptionsButton_clicked();
public slots: public slots:
void clear(); void clear();

View file

@ -48,8 +48,8 @@ void SendCoinsDialog::setModel(WalletModel *model)
} }
if(model) if(model)
{ {
setBalance(model->getBalance(), model->getUnconfirmedBalance()); setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance());
connect(model, SIGNAL(balanceChanged(qint64, qint64)), this, SLOT(setBalance(qint64, qint64))); connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64)));
} }
} }
@ -266,20 +266,23 @@ void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
entry->setValue(rv); entry->setValue(rv);
} }
bool SendCoinsDialog::handleURI(const QString &uri)
void SendCoinsDialog::handleURI(const QString &uri)
{ {
SendCoinsRecipient rv; SendCoinsRecipient rv;
if(!GUIUtil::parseBitcoinURI(uri, &rv)) // URI has to be valid
if (GUIUtil::parseBitcoinURI(uri, &rv))
{ {
return; pasteEntry(rv);
return true;
} }
pasteEntry(rv);
return false;
} }
void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance) void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance)
{ {
Q_UNUSED(unconfirmedBalance); Q_UNUSED(unconfirmedBalance);
Q_UNUSED(immatureBalance);
if(!model || !model->getOptionsModel()) if(!model || !model->getOptionsModel())
return; return;

View file

@ -30,7 +30,7 @@ public:
QWidget *setupTabChain(QWidget *prev); QWidget *setupTabChain(QWidget *prev);
void pasteEntry(const SendCoinsRecipient &rv); void pasteEntry(const SendCoinsRecipient &rv);
void handleURI(const QString &uri); bool handleURI(const QString &uri);
public slots: public slots:
void clear(); void clear();
@ -38,7 +38,7 @@ public slots:
void accept(); void accept();
SendCoinsEntry *addEntry(); SendCoinsEntry *addEntry();
void updateRemoveEnabled(); void updateRemoveEnabled();
void setBalance(qint64 balance, qint64 unconfirmedBalance); void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance);
private: private:
Ui::SendCoinsDialog *ui; Ui::SendCoinsDialog *ui;

View file

@ -7,6 +7,7 @@
#include "wallet.h" #include "wallet.h"
#include "db.h" #include "db.h"
#include "ui_interface.h" #include "ui_interface.h"
#include "base58.h"
#include <QString> #include <QString>
@ -85,14 +86,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
{ {
if (wallet->IsMine(txout)) if (wallet->IsMine(txout))
{ {
CBitcoinAddress address; CTxDestination address;
if (ExtractAddress(txout.scriptPubKey, address) && wallet->HaveKey(address)) if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
{ {
if (wallet->mapAddressBook.count(address)) if (wallet->mapAddressBook.count(address))
{ {
strHTML += tr("<b>From:</b> ") + tr("unknown") + "<br>"; strHTML += tr("<b>From:</b> ") + tr("unknown") + "<br>";
strHTML += tr("<b>To:</b> "); strHTML += tr("<b>To:</b> ");
strHTML += GUIUtil::HtmlEscape(address.ToString()); strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
if (!wallet->mapAddressBook[address].empty()) if (!wallet->mapAddressBook[address].empty())
strHTML += tr(" (yours, label: ") + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")"; strHTML += tr(" (yours, label: ") + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
else else
@ -115,8 +116,9 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
// Online transaction // Online transaction
strAddress = wtx.mapValue["to"]; strAddress = wtx.mapValue["to"];
strHTML += tr("<b>To:</b> "); strHTML += tr("<b>To:</b> ");
if (wallet->mapAddressBook.count(strAddress) && !wallet->mapAddressBook[strAddress].empty()) CTxDestination dest = CBitcoinAddress(strAddress).Get();
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[strAddress]) + " "; if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " ";
strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>"; strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
} }
@ -170,13 +172,13 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
if (wtx.mapValue["to"].empty()) if (wtx.mapValue["to"].empty())
{ {
// Offline transaction // Offline transaction
CBitcoinAddress address; CTxDestination address;
if (ExtractAddress(txout.scriptPubKey, address)) if (ExtractDestination(txout.scriptPubKey, address))
{ {
strHTML += tr("<b>To:</b> "); strHTML += tr("<b>To:</b> ");
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty()) if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " "; strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
strHTML += GUIUtil::HtmlEscape(address.ToString()); strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
strHTML += "<br>"; strHTML += "<br>";
} }
} }
@ -224,7 +226,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
strHTML += QString("<b>") + tr("Transaction ID:") + "</b> " + wtx.GetHash().ToString().c_str() + "<br>"; strHTML += QString("<b>") + tr("Transaction ID:") + "</b> " + wtx.GetHash().ToString().c_str() + "<br>";
if (wtx.IsCoinBase()) if (wtx.IsCoinBase())
strHTML += QString("<br>") + tr("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.") + "<br>"; strHTML += QString("<br>") + tr("Generated coins must mature 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's state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>";
// //
// Debug view // Debug view
@ -260,12 +262,12 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
{ {
strHTML += "<li>"; strHTML += "<li>";
const CTxOut &vout = prev.vout[prevout.n]; const CTxOut &vout = prev.vout[prevout.n];
CBitcoinAddress address; CTxDestination address;
if (ExtractAddress(vout.scriptPubKey, address)) if (ExtractDestination(vout.scriptPubKey, address))
{ {
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty()) if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " "; strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
strHTML += QString::fromStdString(address.ToString()); strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
} }
strHTML = strHTML + " Amount=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,vout.nValue); strHTML = strHTML + " Amount=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,vout.nValue);
strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? "true" : "false") + "</li>"; strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? "true" : "false") + "</li>";

View file

@ -1,6 +1,7 @@
#include "transactionrecord.h" #include "transactionrecord.h"
#include "wallet.h" #include "wallet.h"
#include "base58.h"
/* Return positive answer if transaction should be shown in list. /* Return positive answer if transaction should be shown in list.
*/ */
@ -50,7 +51,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
if(wallet->IsMine(txout)) if(wallet->IsMine(txout))
{ {
TransactionRecord sub(hash, nTime); TransactionRecord sub(hash, nTime);
CBitcoinAddress address; CTxDestination address;
sub.idx = parts.size(); // sequence number sub.idx = parts.size(); // sequence number
sub.credit = txout.nValue; sub.credit = txout.nValue;
if (wtx.IsCoinBase()) if (wtx.IsCoinBase())
@ -58,11 +59,11 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
// Generated // Generated
sub.type = TransactionRecord::Generated; sub.type = TransactionRecord::Generated;
} }
else if (ExtractAddress(txout.scriptPubKey, address) && wallet->HaveKey(address)) else if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
{ {
// Received by Bitcoin Address // Received by Bitcoin Address
sub.type = TransactionRecord::RecvWithAddress; sub.type = TransactionRecord::RecvWithAddress;
sub.address = address.ToString(); sub.address = CBitcoinAddress(address).ToString();
} }
else else
{ {
@ -113,12 +114,12 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
continue; continue;
} }
CBitcoinAddress address; CTxDestination address;
if (ExtractAddress(txout.scriptPubKey, address)) if (ExtractDestination(txout.scriptPubKey, address))
{ {
// Sent to Bitcoin Address // Sent to Bitcoin Address
sub.type = TransactionRecord::SendToAddress; sub.type = TransactionRecord::SendToAddress;
sub.address = address.ToString(); sub.address = CBitcoinAddress(address).ToString();
} }
else else
{ {

View file

@ -298,8 +298,7 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons
switch(wtx->status.maturity) switch(wtx->status.maturity)
{ {
case TransactionStatus::Immature: case TransactionStatus::Immature:
status += "\n" + tr("Mined balance will be available in %n more blocks", "", status += "\n" + tr("Mined balance will be available when it matures in %n more block(s)", "", wtx->status.matures_in);
wtx->status.matures_in);
break; break;
case TransactionStatus::Mature: case TransactionStatus::Mature:
break; break;

View file

@ -4,34 +4,36 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <QDialogButtonBox> #include <QDialog>
#include <QAbstractButton> #include <QLabel>
#include <QClipboard> #include <QLineEdit>
#include <QMessageBox> #include <QPlainTextEdit>
#include <QPushButton>
#include "main.h" #include "main.h"
#include "wallet.h" #include "wallet.h"
#include "walletmodel.h" #include "walletmodel.h"
#include "addresstablemodel.h"
#include "guiutil.h" #include "guiutil.h"
#include "base58.h"
VerifyMessageDialog::VerifyMessageDialog(AddressTableModel *addressModel, QWidget *parent) : VerifyMessageDialog::VerifyMessageDialog(QWidget *parent) :
QDialog(parent), QDialog(parent),
ui(new Ui::VerifyMessageDialog), ui(new Ui::VerifyMessageDialog)
model(addressModel)
{ {
ui->setupUi(this); ui->setupUi(this);
#if (QT_VERSION >= 0x040700) #if (QT_VERSION >= 0x040700)
/* Do not move this to the XML file, Qt before 4.7 will choke on it */ /* Do not move this to the XML file, Qt before 4.7 will choke on it */
ui->lnAddress->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)"));
ui->lnSig->setPlaceholderText(tr("Enter Bitcoin signature")); ui->lnSig->setPlaceholderText(tr("Enter Bitcoin signature"));
ui->lnAddress->setPlaceholderText(tr("Click \"Verify Message\" to obtain address"));
#endif #endif
GUIUtil::setupAddressWidget(ui->lnAddress, this); GUIUtil::setupAddressWidget(ui->lnAddress, this);
ui->lnAddress->installEventFilter(this); ui->lnAddress->installEventFilter(this);
ui->edMessage->setFocus(); ui->lnSig->setFont(GUIUtil::bitcoinAddressFont());
ui->lnAddress->setFocus();
} }
VerifyMessageDialog::~VerifyMessageDialog() VerifyMessageDialog::~VerifyMessageDialog()
@ -39,54 +41,65 @@ VerifyMessageDialog::~VerifyMessageDialog()
delete ui; delete ui;
} }
bool VerifyMessageDialog::checkAddress() void VerifyMessageDialog::on_verifyMessage_clicked()
{ {
CBitcoinAddress addr(ui->lnAddress->text().toStdString());
if (!addr.IsValid())
{
ui->lnAddress->setValid(false);
ui->lblStatus->setStyleSheet("QLabel { color: red; }");
ui->lblStatus->setText(tr("\"%1\" is not a valid address.").arg(ui->lnAddress->text()) + QString(" ") + tr("Please check the address and try again."));
return;
}
CKeyID keyID;
if (!addr.GetKeyID(keyID))
{
ui->lnAddress->setValid(false);
ui->lblStatus->setStyleSheet("QLabel { color: red; }");
ui->lblStatus->setText(tr("\"%1\" does not refer to a key.").arg(ui->lnAddress->text()) + QString(" ") + tr("Please check the address and try again."));
return;
}
bool fInvalid = false;
std::vector<unsigned char> vchSig = DecodeBase64(ui->lnSig->text().toStdString().c_str(), &fInvalid);
if (fInvalid)
{
ui->lnSig->setValid(false);
ui->lblStatus->setStyleSheet("QLabel { color: red; }");
ui->lblStatus->setText(tr("The signature could not be decoded.") + QString(" ") + tr("Please check the signature and try again."));
return;
}
CDataStream ss(SER_GETHASH, 0); CDataStream ss(SER_GETHASH, 0);
ss << strMessageMagic; ss << strMessageMagic;
ss << ui->edMessage->document()->toPlainText().toStdString(); ss << ui->edMessage->document()->toPlainText().toStdString();
uint256 hash = Hash(ss.begin(), ss.end());
bool invalid = true;
std::vector<unsigned char> vchSig = DecodeBase64(ui->lnSig->text().toStdString().c_str(), &invalid);
if(invalid)
{
QMessageBox::warning(this, tr("Invalid Signature"), tr("The signature could not be decoded. Please check the signature and try again."));
return false;
}
CKey key; CKey key;
if(!key.SetCompactSignature(hash, vchSig)) if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
{ {
QMessageBox::warning(this, tr("Invalid Signature"), tr("The signature did not match the message digest. Please check the signature and try again.")); ui->lnSig->setValid(false);
return false; ui->lblStatus->setStyleSheet("QLabel { color: red; }");
ui->lblStatus->setText(tr("The signature did not match the message digest.")+ QString(" ") + tr("Please check the signature and try again."));
return;
} }
CBitcoinAddress address(key.GetPubKey()); if (!(CBitcoinAddress(key.GetPubKey().GetID()) == addr))
QString qStringAddress = QString::fromStdString(address.ToString()); {
ui->lnAddress->setText(qStringAddress); ui->lblStatus->setStyleSheet("QLabel { color: red; }");
ui->copyToClipboard->setEnabled(true); ui->lblStatus->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>"));
return;
}
QString label = model->labelForAddress(qStringAddress); ui->lblStatus->setStyleSheet("QLabel { color: green; }");
ui->lblStatus->setText(label.isEmpty() ? tr("Address not found in address book.") : tr("Address found in address book: %1").arg(label)); ui->lblStatus->setText(QString("<nobr>") + tr("Message verified.") + QString("</nobr>"));
return true;
}
void VerifyMessageDialog::on_verifyMessage_clicked()
{
checkAddress();
}
void VerifyMessageDialog::on_copyToClipboard_clicked()
{
QApplication::clipboard()->setText(ui->lnAddress->text());
} }
void VerifyMessageDialog::on_clearButton_clicked() void VerifyMessageDialog::on_clearButton_clicked()
{ {
ui->edMessage->clear();
ui->lnSig->clear();
ui->lnAddress->clear(); ui->lnAddress->clear();
ui->lnSig->clear();
ui->edMessage->clear();
ui->lblStatus->clear(); ui->lblStatus->clear();
ui->edMessage->setFocus(); ui->edMessage->setFocus();
@ -94,9 +107,11 @@ void VerifyMessageDialog::on_clearButton_clicked()
bool VerifyMessageDialog::eventFilter(QObject *object, QEvent *event) bool VerifyMessageDialog::eventFilter(QObject *object, QEvent *event)
{ {
if(object == ui->lnAddress && (event->type() == QEvent::MouseButtonPress || if (object == ui->lnAddress && (event->type() == QEvent::MouseButtonPress ||
event->type() == QEvent::FocusIn)) event->type() == QEvent::FocusIn))
{ {
// set lnAddress to valid, as QEvent::FocusIn would not reach QValidatedLineEdit::focusInEvent
ui->lnAddress->setValid(true);
ui->lnAddress->selectAll(); ui->lnAddress->selectAll();
return true; return true;
} }

View file

@ -16,21 +16,17 @@ class VerifyMessageDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit VerifyMessageDialog(AddressTableModel *addressModel, QWidget *parent = 0); explicit VerifyMessageDialog(QWidget *parent);
~VerifyMessageDialog(); ~VerifyMessageDialog();
protected: protected:
bool eventFilter(QObject *object, QEvent *event); bool eventFilter(QObject *object, QEvent *event);
private: private:
bool checkAddress();
Ui::VerifyMessageDialog *ui; Ui::VerifyMessageDialog *ui;
AddressTableModel *model;
private slots: private slots:
void on_verifyMessage_clicked(); void on_verifyMessage_clicked();
void on_copyToClipboard_clicked();
void on_clearButton_clicked(); void on_clearButton_clicked();
}; };

Some files were not shown because too many files have changed in this diff Show more