aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bitcoin-qt.pro11
-rw-r--r--contrib/debian/changelog38
-rw-r--r--doc/README2
-rw-r--r--doc/README_windows.txt2
-rw-r--r--share/setup.nsi6
-rw-r--r--src/addrman.cpp26
-rw-r--r--src/addrman.h2
-rw-r--r--src/bitcoinrpc.cpp466
-rw-r--r--src/bitcoinrpc.h15
-rw-r--r--src/db.cpp4
-rw-r--r--src/init.cpp13
-rw-r--r--src/init.h3
-rw-r--r--src/main.cpp102
-rw-r--r--src/main.h16
-rw-r--r--src/net.cpp2
-rw-r--r--src/qt/bitcoin.cpp28
-rw-r--r--src/qt/bitcoin.qrc2
-rw-r--r--src/qt/bitcoingui.cpp13
-rw-r--r--src/qt/bitcoingui.h3
-rw-r--r--src/qt/clientmodel.cpp5
-rw-r--r--src/qt/clientmodel.h1
-rw-r--r--src/qt/forms/aboutdialog.ui12
-rw-r--r--src/qt/forms/addressbookpage.ui2
-rw-r--r--src/qt/forms/messagepage.ui19
-rw-r--r--src/qt/forms/overviewpage.ui12
-rw-r--r--src/qt/forms/qrcodedialog.ui6
-rw-r--r--src/qt/forms/rpcconsole.ui323
-rw-r--r--src/qt/messagepage.cpp12
-rw-r--r--src/qt/messagepage.h1
-rw-r--r--src/qt/optionsdialog.cpp1
-rw-r--r--src/qt/res/icons/qrcode.pngbin0 -> 237 bytes
-rw-r--r--src/qt/res/images/qrcode.pngbin5993 -> 0 bytes
-rw-r--r--src/qt/rpcconsole.cpp316
-rw-r--r--src/qt/rpcconsole.h64
-rw-r--r--src/qt/sendcoinsentry.cpp4
-rw-r--r--src/qt/walletmodel.cpp13
-rw-r--r--src/script.cpp6
-rw-r--r--src/util.cpp2
-rw-r--r--src/version.h4
-rw-r--r--src/walletdb.cpp2
40 files changed, 1375 insertions, 184 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro
index f586c53372..c1f0c452ad 100644
--- a/bitcoin-qt.pro
+++ b/bitcoin-qt.pro
@@ -1,6 +1,6 @@
TEMPLATE = app
TARGET =
-VERSION = 0.6.1
+VERSION = 0.6.99
INCLUDEPATH += src src/json src/qt
DEFINES += QT_GUI BOOST_THREAD_USE_LIB
CONFIG += no_include_pwd
@@ -158,7 +158,8 @@ HEADERS += src/qt/bitcoingui.h \
src/qt/notificator.h \
src/qt/qtipcserver.h \
src/allocators.h \
- src/ui_interface.h
+ src/ui_interface.h \
+ src/qt/rpcconsole.h
SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/qt/transactiontablemodel.cpp \
@@ -212,7 +213,8 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/qt/askpassphrasedialog.cpp \
src/protocol.cpp \
src/qt/notificator.cpp \
- src/qt/qtipcserver.cpp
+ src/qt/qtipcserver.cpp \
+ src/qt/rpcconsole.cpp
RESOURCES += \
src/qt/bitcoin.qrc
@@ -226,7 +228,8 @@ FORMS += \
src/qt/forms/transactiondescdialog.ui \
src/qt/forms/overviewpage.ui \
src/qt/forms/sendcoinsentry.ui \
- src/qt/forms/askpassphrasedialog.ui
+ src/qt/forms/askpassphrasedialog.ui \
+ src/qt/forms/rpcconsole.ui
contains(USE_QRCODE, 1) {
HEADERS += src/qt/qrcodedialog.h
diff --git a/contrib/debian/changelog b/contrib/debian/changelog
index db5e2682c6..cdd4a47e91 100644
--- a/contrib/debian/changelog
+++ b/contrib/debian/changelog
@@ -1,13 +1,43 @@
-bitcoin (0.5.1-natty1) natty; urgency=low
+bitcoin (0.6.1-natty0) natty; urgency=low
+
+ * New upstream release.
+
+ -- Matt Corallo <matt@bluematt.me> Sun, 6 May 2012 20:09:00 -0500
+
+bitcoin (0.6.0-natty0) natty; urgency=low
+
+ * New upstream release.
+ * Add GNOME/KDE support for bitcoin-qt's bitcoin: URI support.
+ Thanks to luke-jr for the KDE .protocol file.
+
+ -- Matt Corallo <matt@bluematt.me> Sat, 31 Mar 2012 15:35:00 -0500
+
+bitcoin (0.5.3-natty1) natty; urgency=low
+
+ * Mark for upload to PPA.
+
+ -- Matt Corallo <matt@bluematt.me> Wed, 14 Mar 2012 23:06:00 -0400
+
+bitcoin (0.5.3-natty0) natty; urgency=low
+
+ * New upstream release.
+
+ -- Luke Dashjr <luke+bitcoin+deb@dashjr.org> Tue, 10 Jan 2012 15:57:00 -0500
+
+bitcoin (0.5.2-natty1) natty; urgency=low
* Remove mentions on anonymity in package descriptions and manpage.
These should never have been there, bitcoin isnt anonymous without
a ton of work that virtually no users will ever be willing and
capable of doing
- * Add GNOME/KDE support for bitcoin-qt's bitcoin: URI support.
- Thanks to luke-jr for the KDE .protocol file.
- -- Matt Corallo <matt@bluematt.me> Fri, 23 Dec 2011 20:25:00 -0500
+ -- Matt Corallo <matt@bluematt.me> Sat, 7 Jan 2012 13:37:00 -0500
+
+bitcoin (0.5.2-natty0) natty; urgency=low
+
+ * New upstream release.
+
+ -- Luke Dashjr <luke+bitcoin+deb@dashjr.org> Fri, 16 Dec 2011 17:57:00 -0500
bitcoin (0.5.1-natty0) natty; urgency=low
diff --git a/doc/README b/doc/README
index aa89960959..4eda8bcd76 100644
--- a/doc/README
+++ b/doc/README
@@ -1,4 +1,4 @@
-Bitcoin 0.6.1rc1 BETA
+Bitcoin 0.6.99 BETA
Copyright (c) 2009-2012 Bitcoin Developers
Distributed under the MIT/X11 software license, see the accompanying
diff --git a/doc/README_windows.txt b/doc/README_windows.txt
index 6b48b1d1e5..eec252931d 100644
--- a/doc/README_windows.txt
+++ b/doc/README_windows.txt
@@ -1,4 +1,4 @@
-Bitcoin 0.6.1rc1 BETA
+Bitcoin 0.6.99 BETA
Copyright (c) 2009-2012 Bitcoin Developers
Distributed under the MIT/X11 software license, see the accompanying
diff --git a/share/setup.nsi b/share/setup.nsi
index fa33bd9786..fbbad3769e 100644
--- a/share/setup.nsi
+++ b/share/setup.nsi
@@ -5,7 +5,7 @@ SetCompressor /SOLID lzma
# General Symbol Definitions
!define REGKEY "SOFTWARE\$(^Name)"
-!define VERSION 0.6.1
+!define VERSION 0.6.99
!define COMPANY "Bitcoin project"
!define URL http://www.bitcoin.org/
@@ -45,13 +45,13 @@ Var StartMenuGroup
!insertmacro MUI_LANGUAGE English
# Installer attributes
-OutFile bitcoin-0.6.1rc1-win32-setup.exe
+OutFile bitcoin-0.6.99-win32-setup.exe
InstallDir $PROGRAMFILES\Bitcoin
CRCCheck on
XPStyle on
BrandingText " "
ShowInstDetails show
-VIProductVersion 0.6.1.1
+VIProductVersion 0.6.99.0
VIAddVersionKey ProductName Bitcoin
VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}"
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 345261e229..10d005aae9 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -107,9 +107,15 @@ void CAddrMan::SwapRandom(int nRndPos1, int nRndPos2)
if (nRndPos1 == nRndPos2)
return;
+ assert(nRndPos1 >= 0 && nRndPos2 >= 0);
+ assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
+
int nId1 = vRandom[nRndPos1];
int nId2 = vRandom[nRndPos2];
+ assert(mapInfo.count(nId1) == 1);
+ assert(mapInfo.count(nId2) == 1);
+
mapInfo[nId1].nRandomPos = nRndPos2;
mapInfo[nId2].nRandomPos = nRndPos1;
@@ -124,26 +130,32 @@ int CAddrMan::SelectTried(int nKBucket)
// random shuffle the first few elements (using the entire list)
// find the least recently tried among them
int64 nOldest = -1;
+ int nOldestPos = -1;
for (unsigned int i = 0; i < ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT && i < vTried.size(); i++)
{
int nPos = GetRandInt(vTried.size() - i) + i;
int nTemp = vTried[nPos];
vTried[nPos] = vTried[i];
vTried[i] = nTemp;
- if (nOldest == -1 || mapInfo[nTemp].nLastSuccess < mapInfo[nOldest].nLastSuccess)
+ assert(nOldest == -1 || mapInfo.count(nTemp) == 1);
+ if (nOldest == -1 || mapInfo[nTemp].nLastSuccess < mapInfo[nOldest].nLastSuccess) {
nOldest = nTemp;
+ nOldestPos = nPos;
+ }
}
- return nOldest;
+ return nOldestPos;
}
int CAddrMan::ShrinkNew(int nUBucket)
{
+ assert(nUBucket >= 0 && nUBucket < vvNew.size());
std::set<int> &vNew = vvNew[nUBucket];
// first look for deletable items
for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
{
+ assert(mapInfo.count(*it));
CAddrInfo &info = mapInfo[*it];
if (info.IsTerrible())
{
@@ -168,11 +180,13 @@ int CAddrMan::ShrinkNew(int nUBucket)
{
if (nI == n[0] || nI == n[1] || nI == n[2] || nI == n[3])
{
+ assert(nOldest == -1 || mapInfo.count(*it) == 1);
if (nOldest == -1 || mapInfo[*it].nTime < mapInfo[nOldest].nTime)
nOldest = *it;
}
nI++;
}
+ assert(mapInfo.count(nOldest) == 1);
CAddrInfo &info = mapInfo[nOldest];
if (--info.nRefCount == 0)
{
@@ -189,6 +203,8 @@ int CAddrMan::ShrinkNew(int nUBucket)
void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
{
+ assert(vvNew[nOrigin].count(nId) == 1);
+
// remove the entry from all new buckets
for (std::vector<std::set<int> >::iterator it = vvNew.begin(); it != vvNew.end(); it++)
{
@@ -197,6 +213,8 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
}
nNew--;
+ assert(info.nRefCount == 0);
+
// what tried bucket to move the entry to
int nKBucket = info.GetTriedBucket(nKey);
std::vector<int> &vTried = vvTried[nKBucket];
@@ -214,6 +232,7 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
int nPos = SelectTried(nKBucket);
// find which new bucket it belongs to
+ assert(mapInfo.count(vTried[nPos]) == 1);
int nUBucket = mapInfo[vTried[nPos]].GetNewBucket(nKey);
std::set<int> &vNew = vvNew[nUBucket];
@@ -385,6 +404,7 @@ CAddress CAddrMan::Select_(int nUnkBias)
std::vector<int> &vTried = vvTried[nKBucket];
if (vTried.size() == 0) continue;
int nPos = GetRandInt(vTried.size());
+ assert(mapInfo.count(vTried[nPos]) == 1);
CAddrInfo &info = mapInfo[vTried[nPos]];
if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30))
return info;
@@ -402,6 +422,7 @@ CAddress CAddrMan::Select_(int nUnkBias)
std::set<int>::iterator it = vNew.begin();
while (nPos--)
it++;
+ assert(mapInfo.count(*it) == 1);
CAddrInfo &info = mapInfo[*it];
if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30))
return info;
@@ -481,6 +502,7 @@ void CAddrMan::GetAddr_(std::vector<CAddress> &vAddr)
{
int nRndPos = GetRandInt(vRandom.size() - n) + n;
SwapRandom(n, nRndPos);
+ assert(mapInfo.count(vRandom[n]) == 1);
vAddr.push_back(mapInfo[vRandom[n]]);
}
}
diff --git a/src/addrman.h b/src/addrman.h
index 7652df66ae..3768614cfe 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -62,7 +62,7 @@ public:
nRandomPos = -1;
}
- CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn)
+ CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
{
Init();
}
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 15bcf1da3d..a189b2b2b0 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -44,6 +44,8 @@ static CCriticalSection cs_nWalletUnlockTime;
extern Value dumpprivkey(const Array& params, bool fHelp);
extern Value importprivkey(const Array& params, bool fHelp);
+const Object emptyobj;
+
Object JSONRPCError(int code, const string& message)
{
Object error;
@@ -111,6 +113,33 @@ HexBits(unsigned int nBits)
return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
}
+enum DecomposeMode {
+ DM_NONE = 0,
+ DM_HASH,
+ DM_HEX,
+ DM_ASM,
+ DM_OBJ,
+};
+
+enum DecomposeMode
+FindDecompose(const Object& decompositions, const char* pcType, const char* pcDefault)
+{
+ Value val = find_value(decompositions, pcType);
+ std::string strDecompose = (val.type() == null_type) ? pcDefault : val.get_str();
+
+ if (strDecompose == "no")
+ return DM_NONE;
+ if (strDecompose == "hash")
+ return DM_HASH;
+ if (strDecompose == "hex")
+ return DM_HEX;
+ if (strDecompose == "asm")
+ return DM_ASM;
+ if (strDecompose == "obj")
+ return DM_OBJ;
+ throw JSONRPCError(-18, "Invalid decomposition");
+}
+
void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
{
int confirms = wtx.GetDepthInMainChain();
@@ -126,6 +155,141 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
entry.push_back(Pair(item.first, item.second));
}
+void
+ScriptSigToJSON(const CTxIn& txin, Object& out)
+{
+ out.push_back(Pair("asm", txin.scriptSig.ToString()));
+ out.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
+
+ CTransaction txprev;
+ uint256 hashTxprevBlock;
+ if (!GetTransaction(txin.prevout.hash, txprev, hashTxprevBlock))
+ return;
+
+ txnouttype type;
+ vector<CBitcoinAddress> addresses;
+ int nRequired;
+
+ if (!ExtractAddresses(txprev.vout[txin.prevout.n].scriptPubKey, type,
+ addresses, nRequired))
+ {
+ out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
+ return;
+ }
+
+ out.push_back(Pair("type", GetTxnOutputType(type)));
+ if (type == TX_MULTISIG)
+ {
+ // TODO: Need to handle this specially since not all input addresses are required...
+ return;
+ }
+
+ Array a;
+ BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
+ a.push_back(addr.ToString());
+ out.push_back(Pair("addresses", a));
+}
+
+void
+ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
+{
+ txnouttype type;
+ vector<CBitcoinAddress> addresses;
+ int nRequired;
+
+ out.push_back(Pair("asm", scriptPubKey.ToString()));
+ out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
+
+ if (!ExtractAddresses(scriptPubKey, type, addresses, nRequired))
+ {
+ out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
+ return;
+ }
+
+ out.push_back(Pair("reqSigs", nRequired));
+ out.push_back(Pair("type", GetTxnOutputType(type)));
+
+ Array a;
+ BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
+ a.push_back(addr.ToString());
+ out.push_back(Pair("addresses", a));
+}
+
+void TxToJSON(const CTransaction &tx, Object& entry, const Object& decompositions)
+{
+ entry.push_back(Pair("version", tx.nVersion));
+ entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
+ entry.push_back(Pair("size", (boost::int64_t)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
+
+ enum DecomposeMode decomposeScript = FindDecompose(decompositions, "script", "asm");
+
+ Array vin;
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ {
+ Object in;
+ if (tx.IsCoinBase())
+ in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
+ else
+ {
+ Object prevout;
+ prevout.push_back(Pair("hash", txin.prevout.hash.GetHex()));
+ prevout.push_back(Pair("n", (boost::int64_t)txin.prevout.n));
+ in.push_back(Pair("prevout", prevout));
+ switch (decomposeScript) {
+ case DM_NONE:
+ break;
+ case DM_HEX:
+ in.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
+ break;
+ case DM_ASM:
+ in.push_back(Pair("scriptSig", txin.scriptSig.ToString()));
+ break;
+ case DM_OBJ:
+ {
+ Object o;
+ ScriptSigToJSON(txin, o);
+ in.push_back(Pair("scriptSig", o));
+ break;
+ }
+ default:
+ throw JSONRPCError(-18, "Invalid script decomposition");
+ }
+ }
+ in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence));
+ vin.push_back(in);
+ }
+ entry.push_back(Pair("vin", vin));
+ Array vout;
+ BOOST_FOREACH(const CTxOut& txout, tx.vout)
+ {
+ Object out;
+ out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
+ switch (decomposeScript) {
+ case DM_NONE:
+ break;
+ case DM_HEX:
+ out.push_back(Pair("scriptPubKey", HexStr(txout.scriptPubKey.begin(), txout.scriptPubKey.end())));
+ break;
+ case DM_ASM:
+ out.push_back(Pair("scriptPubKey", txout.scriptPubKey.ToString()));
+ break;
+ case DM_OBJ:
+ {
+ Object o;
+ ScriptPubKeyToJSON(txout.scriptPubKey, o);
+ out.push_back(Pair("scriptPubKey", o));
+ break;
+ }
+ default:
+ throw JSONRPCError(-18, "Invalid script decomposition");
+ }
+ vout.push_back(out);
+ }
+ entry.push_back(Pair("vout", vout));
+}
+
+void AnyTxToJSON(const uint256 hash, const CTransaction* ptx, Object& entry, const Object& decompositions);
+
string AccountFromValue(const Value& value)
{
string strAccount = value.get_str();
@@ -134,10 +298,13 @@ string AccountFromValue(const Value& value)
return strAccount;
}
-Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
+Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, const Object& decompositions)
{
Object result;
result.push_back(Pair("hash", block.GetHash().GetHex()));
+ CMerkleTx txGen(block.vtx[0]);
+ txGen.SetMerkleBranch(&block);
+ result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain()));
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion));
@@ -146,10 +313,38 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
result.push_back(Pair("bits", HexBits(block.nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
- Array txhashes;
- BOOST_FOREACH (const CTransaction&tx, block.vtx)
- txhashes.push_back(tx.GetHash().GetHex());
- result.push_back(Pair("tx", txhashes));
+
+ enum DecomposeMode decomposeTxn = FindDecompose(decompositions, "tx", "hash");
+ if (decomposeTxn)
+ {
+ Array txs;
+ switch (decomposeTxn) {
+ case DM_OBJ:
+ BOOST_FOREACH (const CTransaction&tx, block.vtx)
+ {
+ Object entry;
+ AnyTxToJSON(tx.GetHash(), &tx, entry, decompositions);
+ txs.push_back(entry);
+ }
+ break;
+ case DM_HEX:
+ BOOST_FOREACH (const CTransaction&tx, block.vtx)
+ {
+ CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
+ ssTx << tx;
+
+ txs.push_back(HexStr(ssTx.begin(), ssTx.end()));
+ }
+ break;
+ case DM_HASH:
+ BOOST_FOREACH (const CTransaction&tx, block.vtx)
+ txs.push_back(tx.GetHash().GetHex());
+ break;
+ default:
+ throw JSONRPCError(-18, "Invalid transaction decomposition");
+ }
+ result.push_back(Pair("tx", txs));
+ }
if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
@@ -160,6 +355,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
+
///
/// Note: This interface may still be subject to change.
///
@@ -999,10 +1195,12 @@ Value addmultisigaddress(const Array& params, bool fHelp)
strAccount = AccountFromValue(params[2]);
// Gather public keys
- if ((nRequired < 1) || ((int)keys.size() < nRequired))
+ if (nRequired < 1)
+ throw runtime_error("a multisignature address must require at least one key to redeem");
+ if ((int)keys.size() < nRequired)
throw runtime_error(
- strprintf("wrong number of keys"
- "(got %d, need at least %d)", keys.size(), nRequired));
+ strprintf("not enough keys supplied "
+ "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
std::vector<CKey> pubkeys;
pubkeys.resize(keys.size());
for (unsigned int i = 0; i < keys.size(); i++)
@@ -1462,11 +1660,69 @@ Value listsinceblock(const Array& params, bool fHelp)
return ret;
}
+void
+AnyTxToJSON(const uint256 hash, const CTransaction* ptx, Object& entry, const Object& decompositions)
+{
+ if (pwalletMain->mapWallet.count(hash))
+ {
+ const CWalletTx& wtx = pwalletMain->mapWallet[hash];
+
+ TxToJSON(wtx, entry, decompositions);
+
+ int64 nCredit = wtx.GetCredit();
+ int64 nDebit = wtx.GetDebit();
+ int64 nNet = nCredit - nDebit;
+ int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
+
+ entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
+ if (wtx.IsFromMe())
+ entry.push_back(Pair("fee", ValueFromAmount(nFee)));
+
+ WalletTxToJSON(wtx, entry);
+
+ Array details;
+ ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
+ entry.push_back(Pair("details", details));
+ }
+ else
+ {
+ CTransaction tx;
+ uint256 hashBlock = 0;
+ if ((!ptx) && GetTransaction(hash, tx, hashBlock))
+ ptx = &tx;
+ if (ptx)
+ {
+ entry.push_back(Pair("txid", hash.GetHex()));
+ TxToJSON(*ptx, entry, decompositions);
+ if (hashBlock == 0)
+ entry.push_back(Pair("confirmations", 0));
+ else
+ {
+ entry.push_back(Pair("blockhash", hashBlock.GetHex()));
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
+ if (mi != mapBlockIndex.end() && (*mi).second)
+ {
+ CBlockIndex* pindex = (*mi).second;
+ if (pindex->IsInMainChain())
+ {
+ entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
+ entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
+ }
+ else
+ entry.push_back(Pair("confirmations", 0));
+ }
+ }
+ }
+ else
+ throw JSONRPCError(-5, "No information available about transaction");
+ }
+}
+
Value gettransaction(const Array& params, bool fHelp)
{
- if (fHelp || params.size() != 1)
+ if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
- "gettransaction <txid>\n"
+ "gettransaction <txid> [decompositions]\n"
"Get detailed information about <txid>");
uint256 hash;
@@ -1474,24 +1730,8 @@ Value gettransaction(const Array& params, bool fHelp)
Object entry;
- if (!pwalletMain->mapWallet.count(hash))
- throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
- const CWalletTx& wtx = pwalletMain->mapWallet[hash];
-
- int64 nCredit = wtx.GetCredit();
- int64 nDebit = wtx.GetDebit();
- int64 nNet = nCredit - nDebit;
- int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
-
- entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
- if (wtx.IsFromMe())
- entry.push_back(Pair("fee", ValueFromAmount(nFee)));
-
- WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
-
- Array details;
- ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
- entry.push_back(Pair("details", details));
+ AnyTxToJSON(hash, NULL, entry,
+ (params.size() > 1) ? params[1].get_obj() : emptyobj);
return entry;
}
@@ -1973,9 +2213,9 @@ Value getblockhash(const Array& params, bool fHelp)
Value getblock(const Array& params, bool fHelp)
{
- if (fHelp || params.size() != 1)
+ if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
- "getblock <hash>\n"
+ "getblock <hash> [decompositions]\n"
"Returns details of a block with given block-hash.");
std::string strHash = params[0].get_str();
@@ -1988,7 +2228,8 @@ Value getblock(const Array& params, bool fHelp)
CBlockIndex* pblockindex = mapBlockIndex[hash];
block.ReadFromDisk(pblockindex, true);
- return blockToJSON(block, pblockindex);
+ return blockToJSON(block, pblockindex,
+ (params.size() > 1) ? params[1].get_obj() : emptyobj);
}
@@ -2505,34 +2746,11 @@ void ThreadRPCServer2(void* parg)
else
throw JSONRPCError(-32600, "Params must be an array");
- // Find method
- const CRPCCommand *pcmd = tableRPC[strMethod];
- if (!pcmd)
- throw JSONRPCError(-32601, "Method not found");
-
- // Observe safe mode
- string strWarning = GetWarnings("rpc");
- if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
- !pcmd->okSafeMode)
- throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
+ Value result = tableRPC.execute(strMethod, params);
- try
- {
- // Execute
- Value result;
- {
- LOCK2(cs_main, pwalletMain->cs_wallet);
- result = pcmd->actor(params, false);
- }
-
- // Send reply
- string strReply = JSONRPCReply(result, Value::null, id);
- stream << HTTPReply(200, strReply) << std::flush;
- }
- catch (std::exception& e)
- {
- ErrorReply(stream, JSONRPCError(-1, e.what()), id);
- }
+ // Send reply
+ string strReply = JSONRPCReply(result, Value::null, id);
+ stream << HTTPReply(200, strReply) << std::flush;
}
catch (Object& objError)
{
@@ -2545,7 +2763,34 @@ void ThreadRPCServer2(void* parg)
}
}
+json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_spirit::Array &params) const
+{
+ // Find method
+ const CRPCCommand *pcmd = tableRPC[strMethod];
+ if (!pcmd)
+ throw JSONRPCError(-32601, "Method not found");
+ // Observe safe mode
+ string strWarning = GetWarnings("rpc");
+ if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
+ !pcmd->okSafeMode)
+ throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
+
+ try
+ {
+ // Execute
+ Value result;
+ {
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+ result = pcmd->actor(params, false);
+ }
+ return result;
+ }
+ catch (std::exception& e)
+ {
+ throw JSONRPCError(-1, e.what());
+ }
+}
Object CallRPC(const string& strMethod, const Array& params)
@@ -2619,6 +2864,62 @@ void ConvertTo(Value& value)
}
}
+// Convert strings to command-specific RPC representation
+Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
+{
+ Array params;
+ BOOST_FOREACH(const std::string &param, strParams)
+ params.push_back(param);
+
+ int n = params.size();
+
+ //
+ // Special case non-string parameter types
+ //
+ if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
+ if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
+ if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
+ if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
+ if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
+ if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "getblock" && n > 1) ConvertTo<Object>(params[1]);
+ if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "gettransaction" && n > 1) ConvertTo<Object>(params[1]);
+ if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
+ if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
+ if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
+ if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
+ if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
+ if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "sendmany" && n > 1)
+ {
+ string s = params[1].get_str();
+ Value v;
+ 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;
+}
+
int CommandLineRPC(int argc, char *argv[])
{
string strPrint;
@@ -2638,53 +2939,8 @@ int CommandLineRPC(int argc, char *argv[])
string strMethod = argv[1];
// Parameters default to strings
- Array params;
- for (int i = 2; i < argc; i++)
- params.push_back(argv[i]);
- int n = params.size();
-
- //
- // Special case non-string parameter types
- //
- if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
- if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
- if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
- if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
- if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
- if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
- if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
- if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
- if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
- if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
- if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
- if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
- if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
- if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
- if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "sendmany" && n > 1)
- {
- string s = params[1].get_str();
- Value v;
- 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();
- }
+ std::vector<std::string> strParams(&argv[2], &argv[argc]);
+ Array params = RPCConvertValues(strMethod, strParams);
// Execute
Object reply = CallRPC(strMethod, params);
diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h
index 6b7293ed19..dd18a504f3 100644
--- a/src/bitcoinrpc.h
+++ b/src/bitcoinrpc.h
@@ -16,6 +16,9 @@
void ThreadRPCServer(void* parg);
int CommandLineRPC(int argc, char *argv[]);
+/** Convert parameter values for RPC call from strings to command-specific JSON objects. */
+json_spirit::Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams);
+
typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp);
class CRPCCommand
@@ -26,6 +29,9 @@ public:
bool okSafeMode;
};
+/**
+ * Bitcoin RPC command dispatcher.
+ */
class CRPCTable
{
private:
@@ -34,6 +40,15 @@ public:
CRPCTable();
const CRPCCommand* operator[](std::string name) const;
std::string help(std::string name) const;
+
+ /**
+ * Execute a method.
+ * @param method Method to execute
+ * @param params Array of arguments (JSON objects)
+ * @returns Result of the call.
+ * @throws an exception (json_spirit::Value) when an error happens.
+ */
+ json_spirit::Value execute(const std::string &method, const json_spirit::Array &params) const;
};
extern const CRPCTable tableRPC;
diff --git a/src/db.cpp b/src/db.cpp
index 12647e568a..5bd0528202 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -613,7 +613,7 @@ bool CTxDB::LoadBlockIndex()
map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos;
for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
{
- if (pindex->nHeight < nBestHeight-nCheckDepth)
+ if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
break;
CBlock block;
if (!block.ReadFromDisk(pindex))
@@ -715,7 +715,7 @@ bool CTxDB::LoadBlockIndex()
}
}
}
- if (pindexFork)
+ if (pindexFork && !fRequestShutdown)
{
// Reorg back to the fork
printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
diff --git a/src/init.cpp b/src/init.cpp
index 4696428972..60927f20b3 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -231,7 +231,8 @@ bool AppInit2(int argc, char* argv[])
" -keypool=<n> \t " + _("Set key pool size to <n> (default: 100)") + "\n" +
" -rescan \t " + _("Rescan the block chain for missing wallet transactions") + "\n" +
" -checkblocks=<n> \t\t " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" +
- " -checklevel=<n> \t\t " + _("How thorough the block verification is (0-6, default: 1)") + "\n";
+ " -checklevel=<n> \t\t " + _("How thorough the block verification is (0-6, default: 1)") + "\n" +
+ " -loadblock=<file>\t " + _("Imports blocks from external blk000?.dat file") + "\n";
strUsage += string() +
_("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n" +
@@ -372,6 +373,16 @@ bool AppInit2(int argc, char* argv[])
}
printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
+ if (mapArgs.count("-loadblock"))
+ {
+ BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"])
+ {
+ FILE *file = fopen(strFile.c_str(), "rb");
+ if (file)
+ LoadExternalBlockFile(file);
+ }
+ }
+
InitMessage(_("Loading wallet..."));
printf("Loading wallet...\n");
nStart = GetTimeMillis();
diff --git a/src/init.h b/src/init.h
index e3971c85e3..0a2f0d8932 100644
--- a/src/init.h
+++ b/src/init.h
@@ -13,7 +13,4 @@ void Shutdown(void* parg);
bool AppInit(int argc, char* argv[]);
bool AppInit2(int argc, char* argv[]);
-bool GetStartOnSystemStartup();
-bool SetStartOnSystemStartup(bool fAutoStart);
-
#endif
diff --git a/src/main.cpp b/src/main.cpp
index b5d8f8f270..b337993cc2 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -740,7 +740,31 @@ int CTxIndex::GetDepthInMainChain() const
return 1 + nBestHeight - pindex->nHeight;
}
-
+// Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock
+bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock)
+{
+ {
+ LOCK(cs_main);
+ {
+ LOCK(mempool.cs);
+ if (mempool.exists(hash))
+ {
+ tx = mempool.lookup(hash);
+ return true;
+ }
+ }
+ CTxDB txdb("r");
+ CTxIndex txindex;
+ if (tx.ReadFromDisk(txdb, COutPoint(hash, 0), txindex))
+ {
+ CBlock block;
+ if (block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
+ hashBlock = block.GetHash();
+ return true;
+ }
+ }
+ return false;
+}
@@ -1836,7 +1860,7 @@ bool CheckDiskSpace(uint64 nAdditionalBytes)
FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode)
{
- if (nFile == -1)
+ if ((nFile < 1) || (nFile == (unsigned int) -1))
return NULL;
FILE* file = fopen((GetDataDir() / strprintf("blk%04d.dat", nFile)).string().c_str(), pszMode);
if (!file)
@@ -2028,6 +2052,62 @@ void PrintBlockTree()
}
}
+bool LoadExternalBlockFile(FILE* fileIn)
+{
+ int nLoaded = 0;
+ {
+ LOCK(cs_main);
+ try {
+ CAutoFile blkdat(fileIn, SER_DISK, CLIENT_VERSION);
+ unsigned int nPos = 0;
+ while (nPos != -1 && blkdat.good() && !fRequestShutdown)
+ {
+ unsigned char pchData[65536];
+ do {
+ fseek(blkdat, nPos, SEEK_SET);
+ int nRead = fread(pchData, 1, sizeof(pchData), blkdat);
+ if (nRead <= 8)
+ {
+ nPos = -1;
+ break;
+ }
+ void* nFind = memchr(pchData, pchMessageStart[0], nRead+1-sizeof(pchMessageStart));
+ if (nFind)
+ {
+ if (memcmp(nFind, pchMessageStart, sizeof(pchMessageStart))==0)
+ {
+ nPos += ((unsigned char*)nFind - pchData) + sizeof(pchMessageStart);
+ break;
+ }
+ nPos += ((unsigned char*)nFind - pchData) + 1;
+ }
+ else
+ nPos += sizeof(pchData) - sizeof(pchMessageStart) + 1;
+ } while(!fRequestShutdown);
+ if (nPos == -1)
+ break;
+ fseek(blkdat, nPos, SEEK_SET);
+ unsigned int nSize;
+ blkdat >> nSize;
+ if (nSize > 0 && nSize <= MAX_BLOCK_SIZE)
+ {
+ CBlock block;
+ blkdat >> block;
+ if (ProcessBlock(NULL,&block))
+ {
+ nLoaded++;
+ nPos += 4 + nSize;
+ }
+ }
+ }
+ }
+ catch (std::exception &e)
+ {
+ }
+ }
+ printf("Loaded %i blocks from external file\n", nLoaded);
+ return nLoaded > 0;
+}
@@ -2398,6 +2478,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return error("message inv size() = %d", vInv.size());
}
+ // find last block in inv vector
+ unsigned int nLastBlock = (unsigned int)(-1);
+ for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) {
+ if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK)
+ nLastBlock = vInv.size() - 1 - nInv;
+ }
CTxDB txdb("r");
for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
{
@@ -2414,9 +2500,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Always request the last block in an inv bundle (even if we already have it), as it is the
// trigger for the other side to send further invs. If we are stuck on a (very long) side chain,
// this is necessary to connect earlier received orphan blocks to the chain again.
- if (!fAlreadyHave || (inv.type == MSG_BLOCK && nInv==vInv.size()-1))
+ if (fAlreadyHave && nInv == nLastBlock) {
+ // bypass mapAskFor, and send request directly; it must go through.
+ std::vector<CInv> vGetData(1,inv);
+ pfrom->PushMessage("getdata", vGetData);
+ }
+
+ if (!fAlreadyHave)
pfrom->AskFor(inv);
- if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
+ else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
// Track requests for our stuff
@@ -3195,7 +3287,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
dPriority += (double)nValueIn * nConf;
if (fDebug && GetBoolArg("-printpriority"))
- printf("priority nValueIn=%-12I64d nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority);
+ printf("priority nValueIn=%-12"PRI64d" nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority);
}
// Priority is sum(valuein * age) / txsize
diff --git a/src/main.h b/src/main.h
index 262e77e806..965100d6d4 100644
--- a/src/main.h
+++ b/src/main.h
@@ -69,6 +69,7 @@ extern int64 nHPSTimerStart;
extern int64 nTimeBestReceived;
extern CCriticalSection cs_setpwalletRegistered;
extern std::set<CWallet*> setpwalletRegistered;
+extern unsigned char pchMessageStart[4];
// Settings
extern int64 nTransactionFee;
@@ -91,6 +92,7 @@ bool LoadBlockIndex(bool fAllowNew=true);
void PrintBlockTree();
bool ProcessMessages(CNode* pfrom);
bool SendMessages(CNode* pto, bool fSendTrickle);
+bool LoadExternalBlockFile(FILE* fileIn);
void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
CBlock* CreateNewBlock(CReserveKey& reservekey);
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
@@ -101,7 +103,7 @@ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime);
int GetNumBlocksOfPeers();
bool IsInitialBlockDownload();
std::string GetWarnings(std::string strFor);
-
+bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock);
@@ -136,8 +138,8 @@ public:
}
IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
- void SetNull() { nFile = -1; nBlockPos = 0; nTxPos = 0; }
- bool IsNull() const { return (nFile == -1); }
+ void SetNull() { nFile = (unsigned int) -1; nBlockPos = 0; nTxPos = 0; }
+ bool IsNull() const { return (nFile == (unsigned int) -1); }
friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b)
{
@@ -176,8 +178,8 @@ public:
CInPoint() { SetNull(); }
CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
- void SetNull() { ptx = NULL; n = -1; }
- bool IsNull() const { return (ptx == NULL && n == -1); }
+ void SetNull() { ptx = NULL; n = (unsigned int) -1; }
+ bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); }
};
@@ -192,8 +194,8 @@ public:
COutPoint() { SetNull(); }
COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; }
IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
- void SetNull() { hash = 0; n = -1; }
- bool IsNull() const { return (hash == 0 && n == -1); }
+ void SetNull() { hash = 0; n = (unsigned int) -1; }
+ bool IsNull() const { return (hash == 0 && n == (unsigned int) -1); }
friend bool operator<(const COutPoint& a, const COutPoint& b)
{
diff --git a/src/net.cpp b/src/net.cpp
index c626e49b1b..7efe304fb6 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -716,7 +716,7 @@ void ThreadSocketHandler2(void* parg)
if (nSelect == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
- if (hSocketMax > -1)
+ if (hSocketMax > (SOCKET) -1)
{
printf("socket select error %d\n", nErr);
for (unsigned int i = 0; i <= hSocketMax; i++)
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 7c262e14cd..4a77bf9b70 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -187,30 +187,31 @@ int main(int argc, char *argv[])
// ... then GUI settings:
OptionsModel optionsModel;
- // Get desired locale ("en_US") from command line or system locale
+ // Get desired locale (e.g. "de_DE") from command line or use system locale
QString lang_territory = QString::fromStdString(GetArg("-lang", QLocale::system().name().toStdString()));
- // Load language files for configured locale:
- // - First load the translator for the base language, without territory
- // - Then load the more specific locale translator
QString lang = lang_territory;
+ // Convert to "de" only by truncating "_DE"
+ lang.truncate(lang_territory.lastIndexOf('_'));
- lang.truncate(lang_territory.lastIndexOf('_')); // "en"
QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
+ // Load language files for configured locale:
+ // - First load the translator for the base language, without territory
+ // - Then load the more specific locale translator
- qtTranslatorBase.load(QLibraryInfo::location(QLibraryInfo::TranslationsPath) + "/qt_" + lang);
- if (!qtTranslatorBase.isEmpty())
+ // Load e.g. qt_de.qm
+ if (qtTranslatorBase.load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
app.installTranslator(&qtTranslatorBase);
- qtTranslator.load(QLibraryInfo::location(QLibraryInfo::TranslationsPath) + "/qt_" + lang_territory);
- if (!qtTranslator.isEmpty())
+ // Load e.g. qt_de_DE.qm
+ if (qtTranslator.load("qt_" + lang_territory, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
app.installTranslator(&qtTranslator);
- translatorBase.load(":/translations/"+lang);
- if (!translatorBase.isEmpty())
+ // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc)
+ if (translatorBase.load(lang, ":/translations/"))
app.installTranslator(&translatorBase);
- translator.load(":/translations/"+lang_territory);
- if (!translator.isEmpty())
+ // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc)
+ if (translator.load(lang_territory, ":/translations/"))
app.installTranslator(&translator);
QSplashScreen splash(QPixmap(":/images/splash"), 0);
@@ -281,6 +282,7 @@ int main(int argc, char *argv[])
#endif
app.exec();
+ window.hide();
window.setClientModel(0);
window.setWalletModel(0);
guiref = 0;
diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc
index e631a65155..e696170312 100644
--- a/src/qt/bitcoin.qrc
+++ b/src/qt/bitcoin.qrc
@@ -38,11 +38,11 @@
<file alias="lock_open">res/icons/lock_open.png</file>
<file alias="key">res/icons/key.png</file>
<file alias="filesave">res/icons/filesave.png</file>
+ <file alias="qrcode">res/icons/qrcode.png</file>
</qresource>
<qresource prefix="/images">
<file alias="about">res/images/about.png</file>
<file alias="splash">res/images/splash2.jpg</file>
- <file alias="qrcode">res/images/qrcode.png</file>
</qresource>
<qresource prefix="/movies">
<file alias="update_spinner">res/movies/update_spinner.mng</file>
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index bcf90917ed..007f185d06 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -24,6 +24,7 @@
#include "askpassphrasedialog.h"
#include "notificator.h"
#include "guiutil.h"
+#include "rpcconsole.h"
#ifdef Q_WS_MAC
#include "macdockiconhandler.h"
@@ -64,7 +65,8 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
changePassphraseAction(0),
aboutQtAction(0),
trayIcon(0),
- notificator(0)
+ notificator(0),
+ rpcConsole(0)
{
resize(850, 550);
setWindowTitle(tr("Bitcoin Wallet"));
@@ -158,6 +160,9 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
// Doubleclicking on a transaction on the transaction history page shows details
connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails()));
+ rpcConsole = new RPCConsole(this);
+ connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show()));
+
gotoOverviewPage();
}
@@ -248,6 +253,8 @@ void BitcoinGUI::createActions()
backupWalletAction->setToolTip(tr("Backup wallet to another location"));
changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase"), this);
changePassphraseAction->setToolTip(tr("Change the passphrase used for wallet encryption"));
+ openRPCConsoleAction = new QAction(tr("&Debug window"), this);
+ openRPCConsoleAction->setToolTip(tr("Open debugging and diagnostic console"));
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
@@ -286,6 +293,8 @@ void BitcoinGUI::createMenuBar()
settings->addAction(optionsAction);
QMenu *help = appMenuBar->addMenu(tr("&Help"));
+ help->addAction(openRPCConsoleAction);
+ help->addSeparator();
help->addAction(aboutAction);
help->addAction(aboutQtAction);
}
@@ -338,6 +347,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
// Report errors from network/worker thread
connect(clientModel, SIGNAL(error(QString,QString, bool)), this, SLOT(error(QString,QString,bool)));
+
+ rpcConsole->setClientModel(clientModel);
}
}
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 2cce8d3459..eb4f883496 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -13,6 +13,7 @@ class AddressBookPage;
class SendCoinsDialog;
class MessagePage;
class Notificator;
+class RPCConsole;
QT_BEGIN_NAMESPACE
class QLabel;
@@ -87,10 +88,12 @@ private:
QAction *backupWalletAction;
QAction *changePassphraseAction;
QAction *aboutQtAction;
+ QAction *openRPCConsoleAction;
QSystemTrayIcon *trayIcon;
Notificator *notificator;
TransactionView *transactionView;
+ RPCConsole *rpcConsole;
QMovie *syncIconMovie;
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index cb602ce327..d7172fd9cd 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -93,3 +93,8 @@ QString ClientModel::formatBuildDate() const
{
return QString::fromStdString(CLIENT_DATE);
}
+
+QString ClientModel::clientName() const
+{
+ return QString::fromStdString(CLIENT_NAME);
+}
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 8e7431a2f3..74e0c0688f 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -38,6 +38,7 @@ public:
QString formatFullVersion() const;
QString formatBuildDate() const;
+ QString clientName() const;
private:
OptionsModel *optionsModel;
diff --git a/src/qt/forms/aboutdialog.ui b/src/qt/forms/aboutdialog.ui
index 6e342e5e8a..21fc7b2019 100644
--- a/src/qt/forms/aboutdialog.ui
+++ b/src/qt/forms/aboutdialog.ui
@@ -22,9 +22,6 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <property name="text">
- <string/>
- </property>
<property name="pixmap">
<pixmap resource="../bitcoin.qrc">:/images/about</pixmap>
</property>
@@ -49,6 +46,9 @@
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
<property name="text">
<string>&lt;b&gt;Bitcoin&lt;/b&gt; version</string>
</property>
@@ -59,6 +59,9 @@
</item>
<item>
<widget class="QLabel" name="versionLabel">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
<property name="text">
<string notr="true">0.3.666-beta</string>
</property>
@@ -87,6 +90,9 @@
</item>
<item>
<widget class="QLabel" name="label_2">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
<property name="text">
<string>Copyright © 2009-2012 Bitcoin Developers
diff --git a/src/qt/forms/addressbookpage.ui b/src/qt/forms/addressbookpage.ui
index b31a9ce997..3ccebd40d9 100644
--- a/src/qt/forms/addressbookpage.ui
+++ b/src/qt/forms/addressbookpage.ui
@@ -86,7 +86,7 @@
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
- <normaloff>:/images/qrcode</normaloff>:/images/qrcode</iconset>
+ <normaloff>:/icons/qrcode</normaloff>:/icons/qrcode</iconset>
</property>
</widget>
</item>
diff --git a/src/qt/forms/messagepage.ui b/src/qt/forms/messagepage.ui
index ae1e062fca..512e47ad6d 100644
--- a/src/qt/forms/messagepage.ui
+++ b/src/qt/forms/messagepage.ui
@@ -101,9 +101,6 @@
<italic>true</italic>
</font>
</property>
- <property name="text">
- <string>Click &quot;Sign Message&quot; to get signature</string>
- </property>
<property name="readOnly">
<bool>true</bool>
</property>
@@ -131,7 +128,7 @@
<string>Copy the current signature to the system clipboard</string>
</property>
<property name="text">
- <string>&amp;Copy to Clipboard</string>
+ <string>&amp;Copy Signature</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
@@ -140,6 +137,20 @@
</widget>
</item>
<item>
+ <widget class="QPushButton" name="clearButton">
+ <property name="toolTip">
+ <string>Reset all sign message fields</string>
+ </property>
+ <property name="text">
+ <string>Clear &amp;All</string>
+ </property>
+ <property name="icon">
+ <iconset resource="../bitcoin.qrc">
+ <normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui
index cc67fae533..3cf7dd0ed3 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -78,12 +78,14 @@
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
+ <property name="font">
+ <font>
+ <pointsize>11</pointsize>
+ <bold>true</bold>
+ </font>
+ </property>
<property name="text">
- <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
-&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
-p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Wallet&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>Wallet</string>
</property>
</widget>
</item>
diff --git a/src/qt/forms/qrcodedialog.ui b/src/qt/forms/qrcodedialog.ui
index 714b1d6cd8..ef21841c26 100644
--- a/src/qt/forms/qrcodedialog.ui
+++ b/src/qt/forms/qrcodedialog.ui
@@ -6,12 +6,12 @@
<rect>
<x>0</x>
<y>0</y>
- <width>320</width>
- <height>404</height>
+ <width>334</width>
+ <height>423</height>
</rect>
</property>
<property name="windowTitle">
- <string>Dialog</string>
+ <string>QR-Code Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui
new file mode 100644
index 0000000000..bde607c527
--- /dev/null
+++ b/src/qt/forms/rpcconsole.ui
@@ -0,0 +1,323 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>RPCConsole</class>
+ <widget class="QDialog" name="RPCConsole">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>706</width>
+ <height>382</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Bitcoin debug window</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab">
+ <attribute name="title">
+ <string>Information</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
+ <property name="horizontalSpacing">
+ <number>12</number>
+ </property>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Client name</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="clientName">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Client version</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="clientVersion">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_9">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Version</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_11">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Network</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Number of connections</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLabel" name="numberOfConnections">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>On testnet</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="QCheckBox" name="isTestNet">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="0">
+ <widget class="QLabel" name="label_10">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Block chain</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Current number of blocks</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="1">
+ <widget class="QLabel" name="numberOfBlocks">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="9" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Estimated total blocks</string>
+ </property>
+ </widget>
+ </item>
+ <item row="9" column="1">
+ <widget class="QLabel" name="totalBlocks">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="10" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Last block time</string>
+ </property>
+ </widget>
+ </item>
+ <item row="10" column="1">
+ <widget class="QLabel" name="lastBlockTime">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="11" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_12">
+ <property name="text">
+ <string>Build date</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="buildDate">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_2">
+ <attribute name="title">
+ <string>Console</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QTableWidget" name="messagesWidget">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="tabKeyNavigation">
+ <bool>false</bool>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="columnCount">
+ <number>2</number>
+ </property>
+ <attribute name="horizontalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <column/>
+ <column/>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineEdit"/>
+ </item>
+ <item>
+ <widget class="QPushButton" name="clearButton">
+ <property name="maximumSize">
+ <size>
+ <width>24</width>
+ <height>24</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Clear console</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../bitcoin.qrc">
+ <normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
+ </property>
+ <property name="shortcut">
+ <string notr="true">Ctrl+L</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../bitcoin.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/qt/messagepage.cpp b/src/qt/messagepage.cpp
index 18bb64fe6c..57ad8292dc 100644
--- a/src/qt/messagepage.cpp
+++ b/src/qt/messagepage.cpp
@@ -24,6 +24,11 @@ MessagePage::MessagePage(QWidget *parent) :
ui(new Ui::MessagePage)
{
ui->setupUi(this);
+
+#if (QT_VERSION >= 0x040700)
+ /* Do not move this to the XML file, Qt before 4.7 will choke on it */
+ ui->signature->setPlaceholderText(tr("Click \"Sign Message\" to get signature"));
+#endif
GUIUtil::setupAddressWidget(ui->signFrom, this);
}
@@ -105,3 +110,10 @@ void MessagePage::on_signMessage_clicked()
ui->signature->setText(QString::fromStdString(EncodeBase64(&vchSig[0], vchSig.size())));
ui->signature->setFont(GUIUtil::bitcoinAddressFont());
}
+
+void MessagePage::on_clearButton_clicked()
+{
+ ui->signFrom->clear();
+ ui->message->clear();
+ ui->signature->clear();
+}
diff --git a/src/qt/messagepage.h b/src/qt/messagepage.h
index 55e6228124..b5a38166da 100644
--- a/src/qt/messagepage.h
+++ b/src/qt/messagepage.h
@@ -33,6 +33,7 @@ private slots:
void on_signMessage_clicked();
void on_copyToClipboard_clicked();
+ void on_clearButton_clicked();
};
#endif // MESSAGEPAGE_H
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 59c44ac5f9..416880d462 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -222,7 +222,6 @@ MainOptionsPage::MainOptionsPage(QWidget *parent):
QLabel *fee_label = new QLabel(tr("Pay transaction &fee"));
fee_hbox->addWidget(fee_label);
fee_edit = new BitcoinAmountField();
- fee_edit->setToolTip(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_label->setBuddy(fee_edit);
fee_hbox->addWidget(fee_edit);
diff --git a/src/qt/res/icons/qrcode.png b/src/qt/res/icons/qrcode.png
new file mode 100644
index 0000000000..a8d97174b3
--- /dev/null
+++ b/src/qt/res/icons/qrcode.png
Binary files differ
diff --git a/src/qt/res/images/qrcode.png b/src/qt/res/images/qrcode.png
deleted file mode 100644
index c89a49bbce..0000000000
--- a/src/qt/res/images/qrcode.png
+++ /dev/null
Binary files differ
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
new file mode 100644
index 0000000000..d59f5c6a38
--- /dev/null
+++ b/src/qt/rpcconsole.cpp
@@ -0,0 +1,316 @@
+#include "rpcconsole.h"
+#include "ui_rpcconsole.h"
+
+#include "clientmodel.h"
+#include "bitcoinrpc.h"
+#include "guiutil.h"
+
+#include <QTime>
+#include <QTimer>
+#include <QThread>
+#include <QTextEdit>
+#include <QKeyEvent>
+
+#include <boost/tokenizer.hpp>
+
+// TODO: make it possible to filter out categories (esp debug messages when implemented)
+// TODO: receive errors and debug messages through ClientModel
+
+const int CONSOLE_SCROLLBACK = 50;
+const int CONSOLE_HISTORY = 50;
+
+/* Object for executing console RPC commands in a separate thread.
+*/
+class RPCExecutor: public QObject
+{
+ Q_OBJECT
+public slots:
+ void start();
+ void request(const QString &command);
+signals:
+ void reply(int category, const QString &command);
+};
+
+#include "rpcconsole.moc"
+
+void RPCExecutor::start()
+{
+ // Nothing to do
+}
+
+void RPCExecutor::request(const QString &command)
+{
+ // Parse shell-like command line into separate arguments
+ boost::escaped_list_separator<char> els('\\',' ','\"');
+ std::string strCommand = command.toStdString();
+ boost::tokenizer<boost::escaped_list_separator<char> > tok(strCommand, els);
+
+ std::string strMethod;
+ std::vector<std::string> strParams;
+ int n = 0;
+ for(boost::tokenizer<boost::escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end();++beg,++n)
+ {
+ if(n == 0) // First parameter is the command
+ strMethod = *beg;
+ else
+ strParams.push_back(*beg);
+ }
+
+ try {
+ std::string strPrint;
+ json_spirit::Value result = tableRPC.execute(strMethod, RPCConvertValues(strMethod, strParams));
+
+ // Format result reply
+ if (result.type() == json_spirit::null_type)
+ strPrint = "";
+ else if (result.type() == json_spirit::str_type)
+ strPrint = result.get_str();
+ else
+ strPrint = write_string(result, true);
+
+ emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
+ }
+ catch (json_spirit::Object& objError)
+ {
+ emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false)));
+ }
+ catch (std::exception& e)
+ {
+ emit reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what()));
+ }
+}
+
+RPCConsole::RPCConsole(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::RPCConsole),
+ firstLayout(true),
+ historyPtr(0)
+{
+ ui->setupUi(this);
+ ui->messagesWidget->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch);
+ ui->messagesWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
+
+ // Install event filter for up and down arrow
+ ui->lineEdit->installEventFilter(this);
+
+ // Add "Copy message" to context menu explicitly
+ QAction *copyMessageAction = new QAction(tr("&Copy"), this);
+ copyMessageAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_C));
+ copyMessageAction->setShortcutContext(Qt::WidgetShortcut);
+ connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage()));
+ ui->messagesWidget->addAction(copyMessageAction);
+
+ connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
+
+ startExecutor();
+
+ clear();
+}
+
+RPCConsole::~RPCConsole()
+{
+ emit stopExecutor();
+ delete ui;
+}
+
+bool RPCConsole::event(QEvent *event)
+{
+ int returnValue = QWidget::event(event);
+
+ if (event->type() == QEvent::LayoutRequest && firstLayout)
+ {
+ // Work around QTableWidget issue:
+ // Call resizeRowsToContents on first Layout request with widget visible,
+ // to make sure multiline messages that were added before the console was shown
+ // have the right height.
+ if(ui->messagesWidget->isVisible())
+ {
+ firstLayout = false;
+ ui->messagesWidget->resizeRowsToContents();
+ }
+ return true;
+ }
+
+ return returnValue;
+}
+
+bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
+{
+ if(obj == ui->lineEdit)
+ {
+ if(event->type() == QEvent::KeyPress)
+ {
+ QKeyEvent *key = static_cast<QKeyEvent*>(event);
+ switch(key->key())
+ {
+ case Qt::Key_Up: browseHistory(-1); return true;
+ case Qt::Key_Down: browseHistory(1); return true;
+ }
+ }
+ }
+ return QDialog::eventFilter(obj, event);
+}
+
+void RPCConsole::setClientModel(ClientModel *model)
+{
+ this->clientModel = model;
+ if(model)
+ {
+ // Subscribe to information, replies, messages, errors
+ connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
+ connect(model, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
+
+ // Provide initial values
+ ui->clientVersion->setText(model->formatFullVersion());
+ ui->clientName->setText(model->clientName());
+ ui->buildDate->setText(model->formatBuildDate());
+
+ setNumConnections(model->getNumConnections());
+ ui->isTestNet->setChecked(model->isTestNet());
+
+ setNumBlocks(model->getNumBlocks());
+ }
+}
+
+static QColor categoryColor(int category)
+{
+ switch(category)
+ {
+ case RPCConsole::MC_ERROR: return QColor(255,0,0); break;
+ case RPCConsole::MC_DEBUG: return QColor(192,192,192); break;
+ case RPCConsole::CMD_REQUEST: return QColor(128,128,128); break;
+ case RPCConsole::CMD_REPLY: return QColor(128,255,128); break;
+ case RPCConsole::CMD_ERROR: return QColor(255,128,128); break;
+ default: return QColor(0,0,0);
+ }
+}
+
+void RPCConsole::clear()
+{
+ ui->messagesWidget->clear();
+ ui->messagesWidget->setRowCount(0);
+ ui->lineEdit->clear();
+ ui->lineEdit->setFocus();
+
+ message(CMD_REPLY, tr("Welcome to the bitcoin RPC console.")+"\n"+
+ tr("Use up and down arrows to navigate history, and Ctrl-L to clear screen.")+"\n"+
+ tr("Type \"help\" for an overview of available commands."));
+}
+
+void RPCConsole::message(int category, const QString &message)
+{
+ // Add row to messages widget
+ int row = ui->messagesWidget->rowCount();
+ ui->messagesWidget->setRowCount(row+1);
+
+ QTime time = QTime::currentTime();
+ QTableWidgetItem *newTime = new QTableWidgetItem(time.toString());
+ newTime->setData(Qt::DecorationRole, categoryColor(category));
+ newTime->setForeground(QColor(128,128,128));
+ newTime->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); // make non-editable
+
+ int numLines = message.count("\n") + 1;
+ // As Qt doesn't like very tall cells (they break scrolling) keep only short messages in
+ // the cell text, longer messages trigger a display widget with scroll bar
+ if(numLines < 5)
+ {
+ QTableWidgetItem *newItem = new QTableWidgetItem(message);
+ newItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); // make non-editable
+ if(category == CMD_ERROR) // Coloring error messages in red
+ newItem->setForeground(QColor(255,16,16));
+ ui->messagesWidget->setItem(row, 1, newItem);
+ } else {
+ QTextEdit *newWidget = new QTextEdit;
+ newWidget->setText(message);
+ newWidget->setMaximumHeight(100);
+ newWidget->setReadOnly(true);
+ ui->messagesWidget->setCellWidget(row, 1, newWidget);
+ }
+
+ ui->messagesWidget->setItem(row, 0, newTime);
+ ui->messagesWidget->resizeRowToContents(row);
+ // Preserve only limited scrollback buffer
+ while(ui->messagesWidget->rowCount() > CONSOLE_SCROLLBACK)
+ ui->messagesWidget->removeRow(0);
+ // Scroll to bottom after table is updated
+ QTimer::singleShot(0, ui->messagesWidget, SLOT(scrollToBottom()));
+}
+
+void RPCConsole::setNumConnections(int count)
+{
+ ui->numberOfConnections->setText(QString::number(count));
+}
+
+void RPCConsole::setNumBlocks(int count)
+{
+ ui->numberOfBlocks->setText(QString::number(count));
+ if(clientModel)
+ {
+ ui->totalBlocks->setText(QString::number(clientModel->getNumBlocksOfPeers()));
+ ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString());
+ }
+}
+
+void RPCConsole::on_lineEdit_returnPressed()
+{
+ QString cmd = ui->lineEdit->text();
+ ui->lineEdit->clear();
+
+ if(!cmd.isEmpty())
+ {
+ message(CMD_REQUEST, cmd);
+ emit cmdRequest(cmd);
+ // Truncate history from current position
+ history.erase(history.begin() + historyPtr, history.end());
+ // Append command to history
+ history.append(cmd);
+ // Enforce maximum history size
+ while(history.size() > CONSOLE_HISTORY)
+ history.removeFirst();
+ // Set pointer to end of history
+ historyPtr = history.size();
+ }
+}
+
+void RPCConsole::browseHistory(int offset)
+{
+ historyPtr += offset;
+ if(historyPtr < 0)
+ historyPtr = 0;
+ if(historyPtr > history.size())
+ historyPtr = history.size();
+ QString cmd;
+ if(historyPtr < history.size())
+ cmd = history.at(historyPtr);
+ ui->lineEdit->setText(cmd);
+}
+
+void RPCConsole::startExecutor()
+{
+ QThread* thread = new QThread;
+ RPCExecutor *executor = new RPCExecutor();
+ executor->moveToThread(thread);
+
+ // Notify executor when thread started (in executor thread)
+ connect(thread, SIGNAL(started()), executor, SLOT(start()));
+ // Replies from executor object must go to this object
+ connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString)));
+ // Requests from this object must go to executor
+ connect(this, SIGNAL(cmdRequest(QString)), executor, SLOT(request(QString)));
+ // On stopExecutor signal
+ // - queue executor for deletion (in execution thread)
+ // - quit the Qt event loop in the execution thread
+ connect(this, SIGNAL(stopExecutor()), executor, SLOT(deleteLater()));
+ connect(this, SIGNAL(stopExecutor()), thread, SLOT(quit()));
+ // Queue the thread for deletion (in this thread) when it is finished
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+
+ // Default implementation of QThread::run() simply spins up an event loop in the thread,
+ // which is what we want.
+ thread->start();
+}
+
+void RPCConsole::copyMessage()
+{
+ GUIUtil::copyEntryData(ui->messagesWidget, 1, Qt::EditRole);
+}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
new file mode 100644
index 0000000000..a0a73bedd3
--- /dev/null
+++ b/src/qt/rpcconsole.h
@@ -0,0 +1,64 @@
+#ifndef RPCCONSOLE_H
+#define RPCCONSOLE_H
+
+#include <QDialog>
+
+namespace Ui {
+ class RPCConsole;
+}
+class ClientModel;
+
+/** Local bitcoin RPC console. */
+class RPCConsole: public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit RPCConsole(QWidget *parent = 0);
+ ~RPCConsole();
+
+ void setClientModel(ClientModel *model);
+
+ enum MessageClass {
+ MC_ERROR,
+ MC_DEBUG,
+ CMD_REQUEST,
+ CMD_REPLY,
+ CMD_ERROR
+ };
+
+protected:
+ virtual bool event(QEvent *event);
+ virtual bool eventFilter(QObject* obj, QEvent *event);
+
+private slots:
+ void on_lineEdit_returnPressed();
+
+public slots:
+ void clear();
+ void message(int category, const QString &message);
+ /** Set number of connections shown in the UI */
+ void setNumConnections(int count);
+ /** Set number of blocks shown in the UI */
+ void setNumBlocks(int count);
+ /** Go forward or back in history */
+ void browseHistory(int offset);
+ /** Copy currently selected message to clipboard */
+ void copyMessage();
+
+signals:
+ // For RPC command executor
+ void stopExecutor();
+ void cmdRequest(const QString &command);
+
+private:
+ Ui::RPCConsole *ui;
+ ClientModel *clientModel;
+ bool firstLayout;
+ QStringList history;
+ int historyPtr;
+
+ void startExecutor();
+};
+
+#endif // RPCCONSOLE_H
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index c8242d8352..5960597c77 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -20,10 +20,10 @@ SendCoinsEntry::SendCoinsEntry(QWidget *parent) :
#ifdef Q_WS_MAC
ui->payToLayout->setSpacing(4);
#endif
-
#if QT_VERSION >= 0x040700
- ui->payTo->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)"));
+ /* Do not move this to the XML file, Qt before 4.7 will choke on it */
ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
+ ui->payTo->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)"));
#endif
setFocusPolicy(Qt::TabFocus);
setFocusProxy(ui->payTo);
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index a915274da3..b9ccb06c09 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -150,14 +150,21 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie
hex = QString::fromStdString(wtx.GetHash().GetHex());
}
- // Add addresses that we've sent to to the address book
+ // Add addresses / update labels that we've sent to to the address book
foreach(const SendCoinsRecipient &rcp, recipients)
{
std::string strAddress = rcp.address.toStdString();
+ std::string strLabel = rcp.label.toStdString();
{
LOCK(wallet->cs_wallet);
- if (!wallet->mapAddressBook.count(strAddress))
- wallet->SetAddressBookName(strAddress, rcp.label.toStdString());
+
+ std::map<CBitcoinAddress, std::string>::iterator mi = wallet->mapAddressBook.find(strAddress);
+
+ // Check if we have a new address or an updated label
+ if (mi == wallet->mapAddressBook.end() || mi->second != strLabel)
+ {
+ wallet->SetAddressBookName(strAddress, strLabel);
+ }
}
}
diff --git a/src/script.cpp b/src/script.cpp
index 65e9b7c9a2..0b103a80bc 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -940,7 +940,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
// ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool)
int i = 1;
- if (stack.size() < i)
+ if ((int)stack.size() < i)
return false;
int nKeysCount = CastToBigNum(stacktop(-i)).getint();
@@ -951,7 +951,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
return false;
int ikey = ++i;
i += nKeysCount;
- if (stack.size() < i)
+ if ((int)stack.size() < i)
return false;
int nSigsCount = CastToBigNum(stacktop(-i)).getint();
@@ -959,7 +959,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
return false;
int isig = ++i;
i += nSigsCount;
- if (stack.size() < i)
+ if ((int)stack.size() < i)
return false;
// Subset of script starting at the most recent codeseparator
diff --git a/src/util.cpp b/src/util.cpp
index 3569f22ecd..3d301d21e3 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -43,7 +43,7 @@ namespace boost {
#ifdef _WIN32_IE
#undef _WIN32_IE
#endif
-#define _WIN32_IE 0x0400
+#define _WIN32_IE 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
diff --git a/src/version.h b/src/version.h
index e8d5b5c421..423e885f93 100644
--- a/src/version.h
+++ b/src/version.h
@@ -12,8 +12,8 @@
static const int CLIENT_VERSION_MAJOR = 0;
static const int CLIENT_VERSION_MINOR = 6;
-static const int CLIENT_VERSION_REVISION = 1;
-static const int CLIENT_VERSION_BUILD = 1;
+static const int CLIENT_VERSION_REVISION = 99;
+static const int CLIENT_VERSION_BUILD = 0;
static const int CLIENT_VERSION =
1000000 * CLIENT_VERSION_MAJOR
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index 709ecac184..e5d57288e8 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -189,7 +189,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet)
//// debug print
//printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str());
- //printf(" %12I64d %s %s %s\n",
+ //printf(" %12"PRI64d" %s %s %s\n",
// wtx.vout[0].nValue,
// DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
// wtx.hashBlock.ToString().substr(0,20).c_str(),