aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/alert.cpp4
-rw-r--r--src/allocators.h13
-rw-r--r--src/base58.h22
-rw-r--r--src/bitcoinrpc.cpp34
-rw-r--r--src/bitcoinrpc.h10
-rw-r--r--src/checkpoints.cpp8
-rw-r--r--src/checkpoints.h2
-rw-r--r--src/clientversion.h6
-rw-r--r--src/crypter.cpp6
-rw-r--r--src/crypter.h4
-rw-r--r--src/db.cpp2
-rw-r--r--src/hash.h11
-rw-r--r--src/init.cpp43
-rw-r--r--src/key.cpp461
-rw-r--r--src/key.h255
-rw-r--r--src/keystore.cpp86
-rw-r--r--src/keystore.h21
-rw-r--r--src/main.cpp81
-rw-r--r--src/main.h24
-rw-r--r--src/qt/addressbookpage.cpp5
-rw-r--r--src/qt/bitcoin.cpp23
-rw-r--r--src/qt/bitcoingui.cpp78
-rw-r--r--src/qt/bitcoingui.h6
-rw-r--r--src/qt/guiutil.cpp20
-rw-r--r--src/qt/locale/bitcoin_ar.ts2
-rw-r--r--src/qt/macdockiconhandler.mm30
-rw-r--r--src/qt/macnotificationhandler.h25
-rw-r--r--src/qt/macnotificationhandler.mm65
-rw-r--r--src/qt/notificator.cpp43
-rw-r--r--src/qt/notificator.h12
-rw-r--r--src/qt/paymentserver.cpp2
-rw-r--r--src/qt/qrcodedialog.cpp2
-rw-r--r--src/qt/rpcconsole.cpp2
-rw-r--r--src/qt/sendcoinsdialog.cpp4
-rw-r--r--src/qt/signverifymessagedialog.cpp6
-rw-r--r--src/qt/splashscreen.cpp3
-rw-r--r--src/qt/transactionview.cpp4
-rw-r--r--src/qt/walletframe.cpp4
-rw-r--r--src/qt/walletframe.h3
-rw-r--r--src/qt/walletstack.h1
-rw-r--r--src/qt/walletview.cpp8
-rw-r--r--src/rpcblockchain.cpp5
-rw-r--r--src/rpcdump.cpp19
-rw-r--r--src/rpcmining.cpp46
-rw-r--r--src/rpcrawtransaction.cpp5
-rw-r--r--src/rpcwallet.cpp97
-rw-r--r--src/script.cpp54
-rw-r--r--src/script.h10
-rw-r--r--src/test/base58_tests.cpp10
-rw-r--r--src/test/bloom_tests.cpp11
-rw-r--r--src/test/checkblock_tests.cpp2
-rw-r--r--src/test/getarg_tests.cpp26
-rw-r--r--src/test/key_tests.cpp96
-rw-r--r--src/test/multisig_tests.cpp2
-rw-r--r--src/test/rpc_tests.cpp35
-rw-r--r--src/test/script_P2SH_tests.cpp14
-rw-r--r--src/test/script_tests.cpp8
-rw-r--r--src/test/sigopcount_tests.cpp4
-rw-r--r--src/test/util_tests.cpp24
-rw-r--r--src/util.cpp7
-rw-r--r--src/util.h9
-rw-r--r--src/wallet.cpp25
-rw-r--r--src/wallet.h4
-rw-r--r--src/walletdb.cpp59
-rw-r--r--src/walletdb.h10
65 files changed, 1118 insertions, 905 deletions
diff --git a/src/alert.cpp b/src/alert.cpp
index 4b029840dd..44f4d5eec6 100644
--- a/src/alert.cpp
+++ b/src/alert.cpp
@@ -144,9 +144,7 @@ bool CAlert::RelayTo(CNode* pnode) const
bool CAlert::CheckSignature() const
{
- CKey key;
- if (!key.SetPubKey(ParseHex(fTestNet ? pszTestKey : pszMainKey)))
- return error("CAlert::CheckSignature() : SetPubKey failed");
+ CPubKey key(ParseHex(fTestNet ? pszTestKey : pszMainKey));
if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
return error("CAlert::CheckSignature() : verify signature failed");
diff --git a/src/allocators.h b/src/allocators.h
index eb2aed6721..85af8fe376 100644
--- a/src/allocators.h
+++ b/src/allocators.h
@@ -177,6 +177,19 @@ private:
};
//
+// Functions for directly locking/unlocking memory objects.
+// Intended for non-dynamically allocated structures.
+//
+template<typename T> void LockObject(const T &t) {
+ LockedPageManager::instance.LockRange((void*)(&t), sizeof(T));
+}
+
+template<typename T> void UnlockObject(const T &t) {
+ OPENSSL_cleanse((void*)(&t), sizeof(T));
+ LockedPageManager::instance.UnlockRange((void*)(&t), sizeof(T));
+}
+
+//
// Allocator that locks its contents from being paged
// out of memory and clears its contents before deletion.
//
diff --git a/src/base58.h b/src/base58.h
index be8a541f67..efe3a95ebd 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -398,21 +398,19 @@ bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const {
class CBitcoinSecret : public CBase58Data
{
public:
- void SetSecret(const CSecret& vchSecret, bool fCompressed)
+ void SetKey(const CKey& vchSecret)
{
- assert(vchSecret.size() == 32);
- SetData(fTestNet ? 239 : 128, &vchSecret[0], vchSecret.size());
- if (fCompressed)
+ assert(vchSecret.IsValid());
+ SetData(fTestNet ? 239 : 128, vchSecret.begin(), vchSecret.size());
+ if (vchSecret.IsCompressed())
vchData.push_back(1);
}
- CSecret GetSecret(bool &fCompressedOut)
+ CKey GetKey()
{
- CSecret vchSecret;
- vchSecret.resize(32);
- memcpy(&vchSecret[0], &vchData[0], 32);
- fCompressedOut = vchData.size() == 33;
- return vchSecret;
+ CKey ret;
+ ret.Set(&vchData[0], &vchData[32], vchData.size() > 32 && vchData[32] == 1);
+ return ret;
}
bool IsValid() const
@@ -443,9 +441,9 @@ public:
return SetString(strSecret.c_str());
}
- CBitcoinSecret(const CSecret& vchSecret, bool fCompressed)
+ CBitcoinSecret(const CKey& vchSecret)
{
- SetSecret(vchSecret, fCompressed);
+ SetKey(vchSecret);
}
CBitcoinSecret()
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index a9b73fd5a6..c99b74f183 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -11,17 +11,17 @@
#include "bitcoinrpc.h"
#include "db.h"
+#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ip/v6_only.hpp>
+#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
#include <boost/foreach.hpp>
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
-#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
-#include <boost/asio/ssl.hpp>
-#include <boost/filesystem/fstream.hpp>
#include <boost/shared_ptr.hpp>
#include <list>
@@ -34,6 +34,7 @@ static std::string strRPCUserColonPass;
// These are created by StartRPCThreads, destroyed in StopRPCThreads
static asio::io_service* rpc_io_service = NULL;
+static map<string, boost::shared_ptr<deadline_timer> > deadlineTimers;
static ssl::context* rpc_ssl_context = NULL;
static boost::thread_group* rpc_worker_group = NULL;
@@ -756,7 +757,7 @@ void StartRPCThreads()
rpc_io_service = new asio::io_service();
rpc_ssl_context = new ssl::context(*rpc_io_service, ssl::context::sslv23);
- const bool fUseSSL = GetBoolArg("-rpcssl");
+ const bool fUseSSL = GetBoolArg("-rpcssl", false);
if (fUseSSL)
{
@@ -843,6 +844,7 @@ void StopRPCThreads()
{
if (rpc_io_service == NULL) return;
+ deadlineTimers.clear();
rpc_io_service->stop();
rpc_worker_group->join_all();
delete rpc_worker_group; rpc_worker_group = NULL;
@@ -850,6 +852,26 @@ void StopRPCThreads()
delete rpc_io_service; rpc_io_service = NULL;
}
+void RPCRunHandler(const boost::system::error_code& err, boost::function<void(void)> func)
+{
+ if (!err)
+ func();
+}
+
+void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64 nSeconds)
+{
+ assert(rpc_io_service != NULL);
+
+ if (deadlineTimers.count(name) == 0)
+ {
+ deadlineTimers.insert(make_pair(name,
+ boost::shared_ptr<deadline_timer>(new deadline_timer(*rpc_io_service))));
+ }
+ deadlineTimers[name]->expires_from_now(posix_time::seconds(nSeconds));
+ deadlineTimers[name]->async_wait(boost::bind(RPCRunHandler, _1, func));
+}
+
+
class JSONRequest
{
public:
@@ -1015,7 +1037,7 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s
// Observe safe mode
string strWarning = GetWarnings("rpc");
- if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
+ if (strWarning != "" && !GetBoolArg("-disablesafemode", false) &&
!pcmd->okSafeMode)
throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
@@ -1049,7 +1071,7 @@ Object CallRPC(const string& strMethod, const Array& params)
GetConfigFile().string().c_str()));
// Connect to localhost
- bool fUseSSL = GetBoolArg("-rpcssl");
+ bool fUseSSL = GetBoolArg("-rpcssl", false);
asio::io_service io_service;
ssl::context context(io_service, ssl::context::sslv23);
context.set_options(ssl::context::no_sslv2);
diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h
index 315fd92383..44c657f8dc 100644
--- a/src/bitcoinrpc.h
+++ b/src/bitcoinrpc.h
@@ -11,6 +11,7 @@
#include <map>
class CBlockIndex;
+class CReserveKey;
#include "json/json_spirit_reader_template.h"
#include "json/json_spirit_writer_template.h"
@@ -88,6 +89,12 @@ void RPCTypeCheck(const json_spirit::Array& params,
void RPCTypeCheck(const json_spirit::Object& o,
const std::map<std::string, json_spirit::Value_type>& typesExpected, bool fAllowNull=false);
+/*
+ Run func nSeconds from now. Uses boost deadline timers.
+ Overrides previous timer <name> (if any).
+ */
+void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64 nSeconds);
+
typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp);
class CRPCCommand
@@ -123,6 +130,9 @@ public:
extern const CRPCTable tableRPC;
+extern void InitRPCMining();
+extern void ShutdownRPCMining();
+
extern int64 nWalletUnlockTime;
extern int64 AmountFromValue(const json_spirit::Value& value);
extern json_spirit::Value ValueFromAmount(int64 amount);
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 9e8e0f7024..7643ec5df8 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -28,6 +28,8 @@ namespace Checkpoints
double fTransactionsPerDay;
};
+ bool fEnabled = true;
+
// What makes a good checkpoint block?
// + Is surrounded by blocks with reasonable timestamps
// (no blocks before with a timestamp after, none after with
@@ -74,7 +76,7 @@ namespace Checkpoints
bool CheckBlock(int nHeight, const uint256& hash)
{
- if (!GetBoolArg("-checkpoints", true))
+ if (!fEnabled)
return true;
const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
@@ -117,7 +119,7 @@ namespace Checkpoints
int GetTotalBlocksEstimate()
{
- if (!GetBoolArg("-checkpoints", true))
+ if (!fEnabled)
return 0;
const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
@@ -127,7 +129,7 @@ namespace Checkpoints
CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
{
- if (!GetBoolArg("-checkpoints", true))
+ if (!fEnabled)
return NULL;
const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
diff --git a/src/checkpoints.h b/src/checkpoints.h
index 3d56885556..a49a908a38 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -24,6 +24,8 @@ namespace Checkpoints
CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex);
double GuessVerificationProgress(CBlockIndex *pindex);
+
+ extern bool fEnabled;
}
#endif
diff --git a/src/clientversion.h b/src/clientversion.h
index aabab4c726..30c0c4072b 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -8,11 +8,11 @@
// These need to be macros, as version.cpp's and bitcoin-qt.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 0
#define CLIENT_VERSION_MINOR 8
-#define CLIENT_VERSION_REVISION 2
-#define CLIENT_VERSION_BUILD 1
+#define CLIENT_VERSION_REVISION 99
+#define CLIENT_VERSION_BUILD 0
// Set to true for release, false for prerelease or test build
-#define CLIENT_VERSION_IS_RELEASE true
+#define CLIENT_VERSION_IS_RELEASE false
// Copyright year (2009-this)
// Todo: update this when changing our copyright comments in the source
diff --git a/src/crypter.cpp b/src/crypter.cpp
index a2b62a87c8..32baabd674 100644
--- a/src/crypter.cpp
+++ b/src/crypter.cpp
@@ -100,17 +100,17 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
}
-bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
+bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
return false;
- return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext);
+ return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
}
-bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext)
+bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
diff --git a/src/crypter.h b/src/crypter.h
index 6f75170bac..4134c1b49b 100644
--- a/src/crypter.h
+++ b/src/crypter.h
@@ -101,7 +101,7 @@ public:
}
};
-bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
-bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char> &vchCiphertext, const uint256& nIV, CSecret &vchPlaintext);
+bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
+bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);
#endif
diff --git a/src/db.cpp b/src/db.cpp
index 3133d99bf8..fd4c67d552 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -541,6 +541,8 @@ bool CAddrDB::Read(CAddrMan& addr)
// use file size to size memory buffer
int fileSize = GetFilesize(filein);
int dataSize = fileSize - sizeof(uint256);
+ //Don't try to resize to a negative number if file is small
+ if ( dataSize < 0 ) dataSize = 0;
vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
diff --git a/src/hash.h b/src/hash.h
index eaa1780c04..536ab71165 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -105,15 +105,22 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL
return ss.GetHash();
}
-inline uint160 Hash160(const std::vector<unsigned char>& vch)
+template<typename T1>
+inline uint160 Hash160(const T1 pbegin, const T1 pend)
{
+ static unsigned char pblank[1];
uint256 hash1;
- SHA256(&vch[0], vch.size(), (unsigned char*)&hash1);
+ SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1);
uint160 hash2;
RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
return hash2;
}
+inline uint160 Hash160(const std::vector<unsigned char>& vch)
+{
+ return Hash160(vch.begin(), vch.end());
+}
+
unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash);
#endif
diff --git a/src/init.cpp b/src/init.cpp
index ebd9dee7b2..78f838f7cb 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -10,6 +10,7 @@
#include "init.h"
#include "util.h"
#include "ui_interface.h"
+#include "checkpoints.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@@ -96,11 +97,13 @@ void Shutdown()
RenameThread("bitcoin-shutoff");
nTransactionsUpdated++;
StopRPCThreads();
+ ShutdownRPCMining();
bitdb.Flush(false);
StopNode();
{
LOCK(cs_main);
- pwalletMain->SetBestChain(CBlockLocator(pindexBest));
+ if (pwalletMain)
+ pwalletMain->SetBestChain(CBlockLocator(pindexBest));
if (pblocktree)
pblocktree->Flush();
if (pcoinsTip)
@@ -195,7 +198,7 @@ bool AppInit(int argc, char* argv[])
exit(ret);
}
#if !defined(WIN32)
- fDaemon = GetBoolArg("-daemon");
+ fDaemon = GetBoolArg("-daemon", false);
if (fDaemon)
{
// Daemonize
@@ -492,7 +495,8 @@ bool AppInit2(boost::thread_group& threadGroup)
// ********************************************************* Step 2: parameter interactions
- fTestNet = GetBoolArg("-testnet");
+ fTestNet = GetBoolArg("-testnet", false);
+ Checkpoints::fEnabled = GetBoolArg("-checkpoints", true);
if (mapArgs.count("-bind")) {
// when specifying an explicit binding address, you want to listen on it
@@ -522,7 +526,7 @@ bool AppInit2(boost::thread_group& threadGroup)
SoftSetBoolArg("-discover", false);
}
- if (GetBoolArg("-salvagewallet")) {
+ if (GetBoolArg("-salvagewallet", false)) {
// Rewrite just private keys: rescan to find transactions
SoftSetBoolArg("-rescan", true);
}
@@ -530,7 +534,7 @@ bool AppInit2(boost::thread_group& threadGroup)
// Make sure enough file descriptors are available
int nBind = std::max((int)mapArgs.count("-bind"), 1);
nMaxConnections = GetArg("-maxconnections", 125);
- nMaxConnections = std::max(std::min(nMaxConnections, FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS), 0);
+ nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
if (nFD < MIN_CORE_FILEDESCRIPTORS)
return InitError(_("Not enough file descriptors available."));
@@ -539,8 +543,8 @@ bool AppInit2(boost::thread_group& threadGroup)
// ********************************************************* Step 3: parameter-to-internal-flags
- fDebug = GetBoolArg("-debug");
- fBenchmark = GetBoolArg("-benchmark");
+ fDebug = GetBoolArg("-debug", false);
+ fBenchmark = GetBoolArg("-benchmark", false);
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
nScriptCheckThreads = GetArg("-par", 0);
@@ -555,20 +559,20 @@ bool AppInit2(boost::thread_group& threadGroup)
if (fDebug)
fDebugNet = true;
else
- fDebugNet = GetBoolArg("-debugnet");
+ fDebugNet = GetBoolArg("-debugnet", false);
if (fDaemon)
fServer = true;
else
- fServer = GetBoolArg("-server");
+ fServer = GetBoolArg("-server", false);
/* force fServer when running without GUI */
#if !defined(QT_GUI)
fServer = true;
#endif
- fPrintToConsole = GetBoolArg("-printtoconsole");
- fPrintToDebugger = GetBoolArg("-printtodebugger");
- fLogTimestamps = GetBoolArg("-logtimestamps");
+ fPrintToConsole = GetBoolArg("-printtoconsole", false);
+ fPrintToDebugger = GetBoolArg("-printtodebugger", false);
+ fLogTimestamps = GetBoolArg("-logtimestamps", false);
if (mapArgs.count("-timeout"))
{
@@ -673,7 +677,7 @@ bool AppInit2(boost::thread_group& threadGroup)
}
}
- if (GetBoolArg("-salvagewallet"))
+ if (GetBoolArg("-salvagewallet", false))
{
// Recover readable keypairs:
if (!CWalletDB::Recover(bitdb, "wallet.dat", true))
@@ -795,7 +799,7 @@ bool AppInit2(boost::thread_group& threadGroup)
// ********************************************************* Step 7: load block chain
- fReindex = GetBoolArg("-reindex");
+ fReindex = GetBoolArg("-reindex", false);
// Upgrading to 0.8; hard-link the old blknnnn.dat files into /blocks/
filesystem::path blocksDir = GetDataDir() / "blocks";
@@ -863,6 +867,11 @@ bool AppInit2(boost::thread_group& threadGroup)
break;
}
+ // If the loaded chain has a wrong genesis, bail out immediately
+ // (we're likely using a testnet datadir, or the other way around).
+ if (!mapBlockIndex.empty() && pindexGenesisBlock == NULL)
+ return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
+
// Initialize the block index (no-op if non-empty database was already loaded)
if (!InitBlockIndex()) {
strLoadError = _("Error initializing block database");
@@ -913,7 +922,7 @@ bool AppInit2(boost::thread_group& threadGroup)
}
printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
- if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree"))
+ if (GetBoolArg("-printblockindex", false) || GetBoolArg("-printblocktree", false))
{
PrintBlockTree();
return false;
@@ -1009,7 +1018,7 @@ bool AppInit2(boost::thread_group& threadGroup)
RegisterWallet(pwalletMain);
CBlockIndex *pindexRescan = pindexBest;
- if (GetBoolArg("-rescan"))
+ if (GetBoolArg("-rescan", false))
pindexRescan = pindexGenesisBlock;
else
{
@@ -1080,6 +1089,8 @@ bool AppInit2(boost::thread_group& threadGroup)
StartNode(threadGroup);
+ // InitRPCMining is needed here so getwork/getblocktemplate in the GUI debug console works properly.
+ InitRPCMining();
if (fServer)
StartRPCThreads();
diff --git a/src/key.cpp b/src/key.cpp
index 20114e6bb2..f73708199a 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -2,13 +2,16 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <map>
-
#include <openssl/ecdsa.h>
+#include <openssl/rand.h>
#include <openssl/obj_mac.h>
#include "key.h"
+
+// anonymous namespace with local implementation code (OpenSSL interaction)
+namespace {
+
// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{
@@ -120,287 +123,273 @@ err:
return ret;
}
-void CKey::SetCompressedPubKey(bool fCompressed)
-{
- EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
- fCompressedPubKey = true;
-}
+// RAII Wrapper around OpenSSL's EC_KEY
+class CECKey {
+private:
+ EC_KEY *pkey;
-void CKey::Reset()
-{
- fCompressedPubKey = false;
- if (pkey != NULL)
+public:
+ CECKey() {
+ pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
+ assert(pkey != NULL);
+ }
+
+ ~CECKey() {
EC_KEY_free(pkey);
- pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
- if (pkey == NULL)
- throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
- fSet = false;
-}
+ }
-CKey::CKey()
-{
- pkey = NULL;
- Reset();
-}
+ void GetSecretBytes(unsigned char vch[32]) const {
+ const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
+ assert(bn);
+ int nBytes = BN_num_bytes(bn);
+ int n=BN_bn2bin(bn,&vch[32 - nBytes]);
+ assert(n == nBytes);
+ memset(vch, 0, 32 - nBytes);
+ }
-CKey::CKey(const CKey& b)
-{
- pkey = EC_KEY_dup(b.pkey);
- if (pkey == NULL)
- throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");
- fSet = b.fSet;
-}
+ void SetSecretBytes(const unsigned char vch[32]) {
+ BIGNUM bn;
+ BN_init(&bn);
+ assert(BN_bin2bn(vch, 32, &bn));
+ assert(EC_KEY_regenerate_key(pkey, &bn));
+ BN_clear_free(&bn);
+ }
-CKey& CKey::operator=(const CKey& b)
-{
- if (!EC_KEY_copy(pkey, b.pkey))
- throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");
- fSet = b.fSet;
- return (*this);
-}
+ void GetPrivKey(CPrivKey &privkey) {
+ int nSize = i2d_ECPrivateKey(pkey, NULL);
+ assert(nSize);
+ privkey.resize(nSize);
+ unsigned char* pbegin = &privkey[0];
+ int nSize2 = i2d_ECPrivateKey(pkey, &pbegin);
+ assert(nSize == nSize2);
+ }
-CKey::~CKey()
-{
- EC_KEY_free(pkey);
-}
+ bool SetPrivKey(const CPrivKey &privkey) {
+ const unsigned char* pbegin = &privkey[0];
+ if (d2i_ECPrivateKey(&pkey, &pbegin, privkey.size())) {
+ // d2i_ECPrivateKey returns true if parsing succeeds.
+ // This doesn't necessarily mean the key is valid.
+ if (EC_KEY_check_key(pkey))
+ return true;
+ }
+ return false;
+ }
-bool CKey::IsNull() const
-{
- return !fSet;
-}
+ void GetPubKey(CPubKey &pubkey, bool fCompressed) {
+ EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
+ int nSize = i2o_ECPublicKey(pkey, NULL);
+ assert(nSize);
+ assert(nSize <= 65);
+ unsigned char c[65];
+ unsigned char *pbegin = c;
+ int nSize2 = i2o_ECPublicKey(pkey, &pbegin);
+ assert(nSize == nSize2);
+ pubkey.Set(&c[0], &c[nSize]);
+ }
-bool CKey::IsCompressed() const
-{
- return fCompressedPubKey;
-}
+ bool SetPubKey(const CPubKey &pubkey) {
+ const unsigned char* pbegin = pubkey.begin();
+ return o2i_ECPublicKey(&pkey, &pbegin, pubkey.size());
+ }
-void CKey::MakeNewKey(bool fCompressed)
-{
- if (!EC_KEY_generate_key(pkey))
- throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
- if (fCompressed)
- SetCompressedPubKey();
- fSet = true;
-}
+ bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) {
+ unsigned int nSize = ECDSA_size(pkey);
+ vchSig.resize(nSize); // Make sure it is big enough
+ assert(ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey));
+ vchSig.resize(nSize); // Shrink to fit actual size
+ return true;
+ }
-bool CKey::SetPrivKey(const CPrivKey& vchPrivKey)
-{
- const unsigned char* pbegin = &vchPrivKey[0];
- if (d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
- {
- // In testing, d2i_ECPrivateKey can return true
- // but fill in pkey with a key that fails
- // EC_KEY_check_key, so:
- if (EC_KEY_check_key(pkey))
- {
- fSet = true;
- return true;
+ bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
+ // -1 = error, 0 = bad sig, 1 = good
+ if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
+ return false;
+ return true;
+ }
+
+ bool SignCompact(const uint256 &hash, unsigned char *p64, int &rec) {
+ bool fOk = false;
+ ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
+ if (sig==NULL)
+ return false;
+ memset(p64, 0, 64);
+ int nBitsR = BN_num_bits(sig->r);
+ int nBitsS = BN_num_bits(sig->s);
+ if (nBitsR <= 256 && nBitsS <= 256) {
+ CPubKey pubkey;
+ GetPubKey(pubkey, true);
+ for (int i=0; i<4; i++) {
+ CECKey keyRec;
+ if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) {
+ CPubKey pubkeyRec;
+ keyRec.GetPubKey(pubkeyRec, true);
+ if (pubkeyRec == pubkey) {
+ rec = i;
+ fOk = true;
+ break;
+ }
+ }
+ }
+ assert(fOk);
+ BN_bn2bin(sig->r,&p64[32-(nBitsR+7)/8]);
+ BN_bn2bin(sig->s,&p64[64-(nBitsS+7)/8]);
}
+ ECDSA_SIG_free(sig);
+ return fOk;
}
- // If vchPrivKey data is bad d2i_ECPrivateKey() can
- // leave pkey in a state where calling EC_KEY_free()
- // crashes. To avoid that, set pkey to NULL and
- // leak the memory (a leak is better than a crash)
- pkey = NULL;
- Reset();
- return false;
-}
-bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed)
-{
- EC_KEY_free(pkey);
- pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
- if (pkey == NULL)
- throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
- if (vchSecret.size() != 32)
- throw key_error("CKey::SetSecret() : secret must be 32 bytes");
- BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
- if (bn == NULL)
- throw key_error("CKey::SetSecret() : BN_bin2bn failed");
- if (!EC_KEY_regenerate_key(pkey,bn))
+ // reconstruct public key from a compact signature
+ // This is only slightly more CPU intensive than just verifying it.
+ // If this function succeeds, the recovered public key is guaranteed to be valid
+ // (the signature is a valid signature of the given data for that key)
+ bool Recover(const uint256 &hash, const unsigned char *p64, int rec)
{
- BN_clear_free(bn);
- throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
+ if (rec<0 || rec>=3)
+ return false;
+ ECDSA_SIG *sig = ECDSA_SIG_new();
+ BN_bin2bn(&p64[0], 32, sig->r);
+ BN_bin2bn(&p64[32], 32, sig->s);
+ bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
+ ECDSA_SIG_free(sig);
+ return ret;
+ }
+};
+
+}; // end of anonymous namespace
+
+bool CKey::Check(const unsigned char *vch) {
+ // Do not convert to OpenSSL's data structures for range-checking keys,
+ // it's easy enough to do directly.
+ static const unsigned char vchMax[32] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
+ 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
+ 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
+ };
+ bool fIsZero = true;
+ for (int i=0; i<32 && fIsZero; i++)
+ if (vch[i] != 0)
+ fIsZero = false;
+ if (fIsZero)
+ return false;
+ for (int i=0; i<32; i++) {
+ if (vch[i] < vchMax[i])
+ return true;
+ if (vch[i] > vchMax[i])
+ return false;
}
- BN_clear_free(bn);
- fSet = true;
- if (fCompressed || fCompressedPubKey)
- SetCompressedPubKey();
return true;
}
-CSecret CKey::GetSecret(bool &fCompressed) const
-{
- CSecret vchRet;
- vchRet.resize(32);
- const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
- int nBytes = BN_num_bytes(bn);
- if (bn == NULL)
- throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
- int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
- if (n != nBytes)
- throw key_error("CKey::GetSecret(): BN_bn2bin failed");
- fCompressed = fCompressedPubKey;
- return vchRet;
+void CKey::MakeNewKey(bool fCompressedIn) {
+ do {
+ RAND_bytes(vch, sizeof(vch));
+ } while (!Check(vch));
+ fValid = true;
+ fCompressed = fCompressedIn;
}
-CPrivKey CKey::GetPrivKey() const
-{
- int nSize = i2d_ECPrivateKey(pkey, NULL);
- if (!nSize)
- throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
- CPrivKey vchPrivKey(nSize, 0);
- unsigned char* pbegin = &vchPrivKey[0];
- if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)
- throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
- return vchPrivKey;
+bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
+ CECKey key;
+ if (!key.SetPrivKey(privkey))
+ return false;
+ key.GetSecretBytes(vch);
+ fCompressed = fCompressedIn;
+ fValid = true;
+ return true;
}
-bool CKey::SetPubKey(const CPubKey& vchPubKey)
-{
- const unsigned char* pbegin = &vchPubKey.vchPubKey[0];
- if (o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size()))
- {
- fSet = true;
- if (vchPubKey.vchPubKey.size() == 33)
- SetCompressedPubKey();
- return true;
- }
- pkey = NULL;
- Reset();
- return false;
+CPrivKey CKey::GetPrivKey() const {
+ assert(fValid);
+ CECKey key;
+ key.SetSecretBytes(vch);
+ CPrivKey privkey;
+ key.GetPrivKey(privkey);
+ return privkey;
}
-CPubKey CKey::GetPubKey() const
-{
- int nSize = i2o_ECPublicKey(pkey, NULL);
- if (!nSize)
- throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
- std::vector<unsigned char> vchPubKey(nSize, 0);
- unsigned char* pbegin = &vchPubKey[0];
- if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
- throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
- return CPubKey(vchPubKey);
+CPubKey CKey::GetPubKey() const {
+ assert(fValid);
+ CECKey key;
+ key.SetSecretBytes(vch);
+ CPubKey pubkey;
+ key.GetPubKey(pubkey, fCompressed);
+ return pubkey;
}
-bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig)
-{
- unsigned int nSize = ECDSA_size(pkey);
- vchSig.resize(nSize); // Make sure it is big enough
- if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))
- {
- vchSig.clear();
+bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
+ if (!fValid)
return false;
- }
- vchSig.resize(nSize); // Shrink to fit actual size
- return true;
+ CECKey key;
+ key.SetSecretBytes(vch);
+ return key.Sign(hash, vchSig);
}
-// create a compact signature (65 bytes), which allows reconstructing the used public key
-// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
-// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
-// 0x1D = second key with even y, 0x1E = second key with odd y
-bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
-{
- bool fOk = false;
- ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
- if (sig==NULL)
+bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
+ if (!fValid)
return false;
- vchSig.clear();
- vchSig.resize(65,0);
- int nBitsR = BN_num_bits(sig->r);
- int nBitsS = BN_num_bits(sig->s);
- if (nBitsR <= 256 && nBitsS <= 256)
- {
- int nRecId = -1;
- for (int i=0; i<4; i++)
- {
- CKey keyRec;
- keyRec.fSet = true;
- if (fCompressedPubKey)
- keyRec.SetCompressedPubKey();
- if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
- if (keyRec.GetPubKey() == this->GetPubKey())
- {
- nRecId = i;
- break;
- }
- }
-
- if (nRecId == -1)
- throw key_error("CKey::SignCompact() : unable to construct recoverable key");
+ CECKey key;
+ key.SetSecretBytes(vch);
+ vchSig.resize(65);
+ int rec = -1;
+ if (!key.SignCompact(hash, &vchSig[1], rec))
+ return false;
+ assert(rec != -1);
+ vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
+ return true;
+}
- vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);
- BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
- BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
- fOk = true;
- }
- ECDSA_SIG_free(sig);
- return fOk;
+bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
+ if (!IsValid())
+ return false;
+ CECKey key;
+ if (!key.SetPubKey(*this))
+ return false;
+ if (!key.Verify(hash, vchSig))
+ return false;
+ return true;
}
-// reconstruct public key from a compact signature
-// This is only slightly more CPU intensive than just verifying it.
-// If this function succeeds, the recovered public key is guaranteed to be valid
-// (the signature is a valid signature of the given data for that key)
-bool CKey::SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
-{
+bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
if (vchSig.size() != 65)
return false;
- int nV = vchSig[0];
- if (nV<27 || nV>=35)
+ CECKey key;
+ if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
return false;
- ECDSA_SIG *sig = ECDSA_SIG_new();
- BN_bin2bn(&vchSig[1],32,sig->r);
- BN_bin2bn(&vchSig[33],32,sig->s);
-
- EC_KEY_free(pkey);
- pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
- if (nV >= 31)
- {
- SetCompressedPubKey();
- nV -= 4;
- }
- if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)
- {
- fSet = true;
- ECDSA_SIG_free(sig);
- return true;
- }
- return false;
+ key.GetPubKey(*this, (vchSig[0] - 27) & 4);
+ return true;
}
-bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
-{
- // -1 = error, 0 = bad sig, 1 = good
- if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
+bool CPubKey::VerifyCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
+ if (!IsValid())
+ return false;
+ if (vchSig.size() != 65)
+ return false;
+ CECKey key;
+ if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
+ return false;
+ CPubKey pubkeyRec;
+ key.GetPubKey(pubkeyRec, IsCompressed());
+ if (*this != pubkeyRec)
return false;
-
return true;
}
-bool CKey::VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
-{
- CKey key;
- if (!key.SetCompactSignature(hash, vchSig))
+bool CPubKey::IsFullyValid() const {
+ if (!IsValid())
return false;
- if (GetPubKey() != key.GetPubKey())
+ CECKey key;
+ if (!key.SetPubKey(*this))
return false;
-
return true;
}
-bool CKey::IsValid()
-{
- if (!fSet)
+bool CPubKey::Decompress() {
+ if (!IsValid())
return false;
-
- if (!EC_KEY_check_key(pkey))
+ CECKey key;
+ if (!key.SetPubKey(*this))
return false;
-
- bool fCompr;
- CSecret secret = GetSecret(fCompr);
- CKey key2;
- key2.SetSecret(secret, fCompr);
- return GetPubKey() == key2.GetPubKey();
+ key.GetPubKey(*this, false);
+ return true;
}
diff --git a/src/key.h b/src/key.h
index 4da16b9cdb..ce469ad298 100644
--- a/src/key.h
+++ b/src/key.h
@@ -1,11 +1,10 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2012 The Bitcoin developers
+// Copyright (c) 2009-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KEY_H
#define BITCOIN_KEY_H
-#include <stdexcept>
#include <vector>
#include "allocators.h"
@@ -13,23 +12,6 @@
#include "uint256.h"
#include "hash.h"
-#include <openssl/ec.h> // for EC_KEY definition
-
-// secp160k1
-// const unsigned int PRIVATE_KEY_SIZE = 192;
-// const unsigned int PUBLIC_KEY_SIZE = 41;
-// const unsigned int SIGNATURE_SIZE = 48;
-//
-// secp192k1
-// const unsigned int PRIVATE_KEY_SIZE = 222;
-// const unsigned int PUBLIC_KEY_SIZE = 49;
-// const unsigned int SIGNATURE_SIZE = 57;
-//
-// secp224k1
-// const unsigned int PRIVATE_KEY_SIZE = 250;
-// const unsigned int PUBLIC_KEY_SIZE = 57;
-// const unsigned int SIGNATURE_SIZE = 66;
-//
// secp256k1:
// const unsigned int PRIVATE_KEY_SIZE = 279;
// const unsigned int PUBLIC_KEY_SIZE = 65;
@@ -38,12 +20,6 @@
// see www.keylength.com
// script supports up to 75 for single byte push
-class key_error : public std::runtime_error
-{
-public:
- 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
{
@@ -63,99 +39,218 @@ public:
/** An encapsulated public key. */
class CPubKey {
private:
- std::vector<unsigned char> vchPubKey;
- friend class CKey;
+ // Just store the serialized data.
+ // Its length can very cheaply be computed from the first byte.
+ unsigned char vch[65];
+
+ // Compute the length of a pubkey with a given first byte.
+ unsigned int static GetLen(unsigned char chHeader) {
+ if (chHeader == 2 || chHeader == 3)
+ return 33;
+ if (chHeader == 4 || chHeader == 6 || chHeader == 7)
+ return 65;
+ return 0;
+ }
+
+ // Set this key data to be invalid
+ void Invalidate() {
+ vch[0] = 0xFF;
+ }
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; }
+ // Construct an invalid public key.
+ CPubKey() {
+ Invalidate();
+ }
- IMPLEMENT_SERIALIZE(
- READWRITE(vchPubKey);
- )
+ // Initialize a public key using begin/end iterators to byte data.
+ template<typename T>
+ void Set(const T pbegin, const T pend) {
+ int len = pend == pbegin ? 0 : GetLen(pbegin[0]);
+ if (len && len == (pend-pbegin))
+ memcpy(vch, (unsigned char*)&pbegin[0], len);
+ else
+ Invalidate();
+ }
+
+ // Construct a public key using begin/end iterators to byte data.
+ template<typename T>
+ CPubKey(const T pbegin, const T pend) {
+ Set(pbegin, pend);
+ }
+
+ // Construct a public key from a byte vector.
+ CPubKey(const std::vector<unsigned char> &vch) {
+ Set(vch.begin(), vch.end());
+ }
+
+ // Simple read-only vector-like interface to the pubkey data.
+ unsigned int size() const { return GetLen(vch[0]); }
+ const unsigned char *begin() const { return vch; }
+ const unsigned char *end() const { return vch+size(); }
+ const unsigned char &operator[](unsigned int pos) const { return vch[pos]; }
+
+ // Comparator implementation.
+ friend bool operator==(const CPubKey &a, const CPubKey &b) {
+ return a.vch[0] == b.vch[0] &&
+ memcmp(a.vch, b.vch, a.size()) == 0;
+ }
+ friend bool operator!=(const CPubKey &a, const CPubKey &b) {
+ return !(a == b);
+ }
+ friend bool operator<(const CPubKey &a, const CPubKey &b) {
+ return a.vch[0] < b.vch[0] ||
+ (a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0);
+ }
+
+ // Implement serialization, as if this was a byte vector.
+ unsigned int GetSerializeSize(int nType, int nVersion) const {
+ return size() + 1;
+ }
+ template<typename Stream> void Serialize(Stream &s, int nType, int nVersion) const {
+ unsigned int len = size();
+ ::WriteCompactSize(s, len);
+ s.write((char*)vch, len);
+ }
+ template<typename Stream> void Unserialize(Stream &s, int nType, int nVersion) {
+ unsigned int len = ::ReadCompactSize(s);
+ if (len <= 65) {
+ s.read((char*)vch, len);
+ } else {
+ // invalid pubkey, skip available data
+ char dummy;
+ while (len--)
+ s.read(&dummy, 1);
+ Invalidate();
+ }
+ }
+ // Get the KeyID of this public key (hash of its serialization)
CKeyID GetID() const {
- return CKeyID(Hash160(vchPubKey));
+ return CKeyID(Hash160(vch, vch+size()));
}
+ // Get the 256-bit hash of this public key.
uint256 GetHash() const {
- return Hash(vchPubKey.begin(), vchPubKey.end());
+ return Hash(vch, vch+size());
}
+ // just check syntactic correctness.
bool IsValid() const {
- return vchPubKey.size() == 33 || vchPubKey.size() == 65;
+ return size() > 0;
}
+ // fully validate whether this is a valid public key (more expensive than IsValid())
+ bool IsFullyValid() const;
+
+ // Check whether this is a compressed public key.
bool IsCompressed() const {
- return vchPubKey.size() == 33;
+ return size() == 33;
}
- std::vector<unsigned char> Raw() const {
- return vchPubKey;
- }
+ // Verify a DER signature (~72 bytes).
+ // If this public key is not fully valid, the return value will be false.
+ bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const;
+
+ // Verify a compact signature (~65 bytes).
+ // See CKey::SignCompact.
+ bool VerifyCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) const;
+
+ // Recover a public key from a compact signature.
+ bool RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig);
+
+ // Turn this public key into an uncompressed public key.
+ bool Decompress();
};
// secure_allocator is defined in allocators.h
// CPrivKey is a serialized private key, with all parameters included (279 bytes)
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
-// CSecret is a serialization of just the secret parameter (32 bytes)
-typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
-/** An encapsulated OpenSSL Elliptic Curve key (public and/or private) */
-class CKey
-{
-protected:
- EC_KEY* pkey;
- bool fSet;
- bool fCompressedPubKey;
+/** An encapsulated private key. */
+class CKey {
+private:
+ // Whether this private key is valid. We check for correctness when modifying the key
+ // data, so fValid should always correspond to the actual state.
+ bool fValid;
+ // Whether the public key corresponding to this private key is (to be) compressed.
+ bool fCompressed;
+
+ // The actual byte data
+ unsigned char vch[32];
+
+ // Check whether the 32-byte array pointed to be vch is valid keydata.
+ bool static Check(const unsigned char *vch);
public:
- void SetCompressedPubKey(bool fCompressed = true);
- void Reset();
+ // Construct an invalid private key.
+ CKey() : fValid(false) {
+ LockObject(vch);
+ }
+
+ // Copy constructor. This is necessary because of memlocking.
+ CKey(const CKey &secret) : fValid(secret.fValid), fCompressed(secret.fCompressed) {
+ LockObject(vch);
+ memcpy(vch, secret.vch, sizeof(vch));
+ }
+
+ // Destructor (again necessary because of memlocking).
+ ~CKey() {
+ UnlockObject(vch);
+ }
+
+ // Initialize using begin and end iterators to byte data.
+ template<typename T>
+ void Set(const T pbegin, const T pend, bool fCompressedIn) {
+ if (pend - pbegin != 32) {
+ fValid = false;
+ return;
+ }
+ if (Check(&pbegin[0])) {
+ memcpy(vch, (unsigned char*)&pbegin[0], 32);
+ fValid = true;
+ fCompressed = fCompressedIn;
+ } else {
+ fValid = false;
+ }
+ }
- CKey();
- CKey(const CKey& b);
+ // Simple read-only vector-like interface.
+ unsigned int size() const { return (fValid ? 32 : 0); }
+ const unsigned char *begin() const { return vch; }
+ const unsigned char *end() const { return vch + size(); }
- CKey& operator=(const CKey& b);
+ // Check whether this private key is valid.
+ bool IsValid() const { return fValid; }
- ~CKey();
+ // Check whether the public key corresponding to this private key is (to be) compressed.
+ bool IsCompressed() const { return fCompressed; }
- bool IsNull() const;
- bool IsCompressed() const;
+ // Initialize from a CPrivKey (serialized OpenSSL private key data).
+ bool SetPrivKey(const CPrivKey &vchPrivKey, bool fCompressed);
+ // Generate a new private key using a cryptographic PRNG.
void MakeNewKey(bool fCompressed);
- bool SetPrivKey(const CPrivKey& vchPrivKey);
- bool SetSecret(const CSecret& vchSecret, bool fCompressed = false);
- CSecret GetSecret(bool &fCompressed) const;
+
+ // Convert the private key to a CPrivKey (serialized OpenSSL private key data).
+ // This is expensive.
CPrivKey GetPrivKey() const;
- bool SetPubKey(const CPubKey& vchPubKey);
+
+ // Compute the public key from a private key.
+ // This is expensive.
CPubKey GetPubKey() const;
- bool Sign(uint256 hash, std::vector<unsigned char>& vchSig);
+ // Create a DER-serialized signature.
+ bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const;
- // create a compact signature (65 bytes), which allows reconstructing the used public key
+ // Create a compact signature (65 bytes), which allows reconstructing the used public key.
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
- // 0x1D = second key with even y, 0x1E = second key with odd y
- bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig);
-
- // reconstruct public key from a compact signature
- // This is only slightly more CPU intensive than just verifying it.
- // If this function succeeds, the recovered public key is guaranteed to be valid
- // (the signature is a valid signature of the given data for that key)
- bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig);
-
- bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig);
-
- // Verify a compact signature
- bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig);
-
- bool IsValid();
+ // 0x1D = second key with even y, 0x1E = second key with odd y,
+ // add 0x04 for compressed keys.
+ bool SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const;
};
#endif
diff --git a/src/keystore.cpp b/src/keystore.cpp
index e0cf805a19..808f8c24ef 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -15,61 +15,50 @@ bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
return true;
}
-bool CBasicKeyStore::AddKey(const CKey& key)
+bool CKeyStore::AddKey(const CKey &key) {
+ return AddKeyPubKey(key, key.GetPubKey());
+}
+
+bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
{
- bool fCompressed = false;
- CSecret secret = key.GetSecret(fCompressed);
- {
- LOCK(cs_KeyStore);
- mapKeys[key.GetPubKey().GetID()] = make_pair(secret, fCompressed);
- }
+ LOCK(cs_KeyStore);
+ mapKeys[pubkey.GetID()] = key;
return true;
}
bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
{
- {
- LOCK(cs_KeyStore);
- mapScripts[redeemScript.GetID()] = redeemScript;
- }
+ LOCK(cs_KeyStore);
+ mapScripts[redeemScript.GetID()] = redeemScript;
return true;
}
bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const
{
- bool result;
- {
- LOCK(cs_KeyStore);
- result = (mapScripts.count(hash) > 0);
- }
- return result;
+ LOCK(cs_KeyStore);
+ return mapScripts.count(hash) > 0;
}
-
bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
{
+ LOCK(cs_KeyStore);
+ ScriptMap::const_iterator mi = mapScripts.find(hash);
+ if (mi != mapScripts.end())
{
- LOCK(cs_KeyStore);
- ScriptMap::const_iterator mi = mapScripts.find(hash);
- if (mi != mapScripts.end())
- {
- redeemScriptOut = (*mi).second;
- return true;
- }
+ redeemScriptOut = (*mi).second;
+ return true;
}
return false;
}
bool CCryptoKeyStore::SetCrypted()
{
- {
- LOCK(cs_KeyStore);
- if (fUseCrypto)
- return true;
- if (!mapKeys.empty())
- return false;
- fUseCrypto = true;
- }
+ LOCK(cs_KeyStore);
+ if (fUseCrypto)
+ return true;
+ if (!mapKeys.empty())
+ return false;
+ fUseCrypto = true;
return true;
}
@@ -99,14 +88,13 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
- CSecret vchSecret;
+ CKeyingMaterial vchSecret;
if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
return false;
if (vchSecret.size() != 32)
return false;
CKey key;
- key.SetPubKey(vchPubKey);
- key.SetSecret(vchSecret);
+ key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
if (key.GetPubKey() == vchPubKey)
break;
return false;
@@ -117,23 +105,22 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
return true;
}
-bool CCryptoKeyStore::AddKey(const CKey& key)
+bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
{
{
LOCK(cs_KeyStore);
if (!IsCrypted())
- return CBasicKeyStore::AddKey(key);
+ return CBasicKeyStore::AddKeyPubKey(key, pubkey);
if (IsLocked())
return false;
std::vector<unsigned char> vchCryptedSecret;
- CPubKey vchPubKey = key.GetPubKey();
- bool fCompressed;
- if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
+ CKeyingMaterial vchSecret(key.begin(), key.end());
+ if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
return false;
- if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
+ if (!AddCryptedKey(pubkey, vchCryptedSecret))
return false;
}
return true;
@@ -164,13 +151,12 @@ bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
- CSecret vchSecret;
+ CKeyingMaterial vchSecret;
if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
return false;
if (vchSecret.size() != 32)
return false;
- keyOut.SetPubKey(vchPubKey);
- keyOut.SetSecret(vchSecret);
+ keyOut.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
return true;
}
}
@@ -204,13 +190,11 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
fUseCrypto = true;
BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
{
- CKey key;
- if (!key.SetSecret(mKey.second.first, mKey.second.second))
- return false;
- const CPubKey vchPubKey = key.GetPubKey();
+ const CKey &key = mKey.second;
+ CPubKey vchPubKey = key.GetPubKey();
+ CKeyingMaterial vchSecret(key.begin(), key.end());
std::vector<unsigned char> vchCryptedSecret;
- bool fCompressed;
- if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
+ if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
return false;
if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
diff --git a/src/keystore.h b/src/keystore.h
index ab369bbf47..49a7bf569d 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -21,7 +21,8 @@ public:
virtual ~CKeyStore() {}
// Add a key to the store.
- virtual bool AddKey(const CKey& key) =0;
+ virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) =0;
+ virtual bool AddKey(const CKey &key);
// Check whether a key corresponding to a given address is present in the store.
virtual bool HaveKey(const CKeyID &address) const =0;
@@ -33,18 +34,9 @@ public:
virtual bool AddCScript(const CScript& redeemScript) =0;
virtual bool HaveCScript(const CScriptID &hash) const =0;
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0;
-
- virtual bool GetSecret(const CKeyID &address, CSecret& vchSecret, bool &fCompressed) const
- {
- CKey key;
- if (!GetKey(address, key))
- return false;
- vchSecret = key.GetSecret(fCompressed);
- return true;
- }
};
-typedef std::map<CKeyID, std::pair<CSecret, bool> > KeyMap;
+typedef std::map<CKeyID, CKey> KeyMap;
typedef std::map<CScriptID, CScript > ScriptMap;
/** Basic key store, that keeps keys in an address->secret map */
@@ -55,7 +47,7 @@ protected:
ScriptMap mapScripts;
public:
- bool AddKey(const CKey& key);
+ bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
bool HaveKey(const CKeyID &address) const
{
bool result;
@@ -85,8 +77,7 @@ public:
KeyMap::const_iterator mi = mapKeys.find(address);
if (mi != mapKeys.end())
{
- keyOut.Reset();
- keyOut.SetSecret((*mi).second.first, (*mi).second.second);
+ keyOut = mi->second;
return true;
}
}
@@ -146,7 +137,7 @@ public:
bool Lock();
virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
- bool AddKey(const CKey& key);
+ bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
bool HaveKey(const CKeyID &address) const
{
{
diff --git a/src/main.cpp b/src/main.cpp
index b7efac53b1..a98b83b6af 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -31,6 +31,7 @@ CTxMemPool mempool;
unsigned int nTransactionsUpdated = 0;
map<uint256, CBlockIndex*> mapBlockIndex;
+std::vector<CBlockIndex*> vBlockIndexByHeight;
uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
CBlockIndex* pindexGenesisBlock = NULL;
@@ -1036,19 +1037,9 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
static CBlockIndex* pblockindexFBBHLast;
CBlockIndex* FindBlockByHeight(int nHeight)
{
- CBlockIndex *pblockindex;
- if (nHeight < nBestHeight / 2)
- pblockindex = pindexGenesisBlock;
- else
- pblockindex = pindexBest;
- if (pblockindexFBBHLast && abs(nHeight - pblockindex->nHeight) > abs(nHeight - pblockindexFBBHLast->nHeight))
- pblockindex = pblockindexFBBHLast;
- while (pblockindex->nHeight > nHeight)
- pblockindex = pblockindex->pprev;
- while (pblockindex->nHeight < nHeight)
- pblockindex = pblockindex->pnext;
- pblockindexFBBHLast = pblockindex;
- return pblockindex;
+ if (nHeight >= (int)vBlockIndexByHeight.size())
+ return NULL;
+ return vBlockIndexByHeight[nHeight];
}
bool CBlock::ReadFromDisk(const CBlockIndex* pindex)
@@ -1231,7 +1222,7 @@ void static InvalidBlockFound(CBlockIndex *pindex) {
pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex));
setBlockIndexValid.erase(pindex);
InvalidChainFound(pindex);
- if (pindex->pnext) {
+ if (pindex->GetNextInMainChain()) {
CValidationState stateDummy;
ConnectBestBlock(stateDummy); // reorganise away from the failed block
}
@@ -1271,7 +1262,7 @@ bool ConnectBestBlock(CValidationState &state) {
if (pindexBest == NULL || pindexTest->nChainWork > pindexBest->nChainWork)
vAttach.push_back(pindexTest);
- if (pindexTest->pprev == NULL || pindexTest->pnext != NULL) {
+ if (pindexTest->pprev == NULL || pindexTest->GetNextInMainChain()) {
reverse(vAttach.begin(), vAttach.end());
BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) {
boost::this_thread::interruption_point();
@@ -1846,15 +1837,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
// At this point, all changes have been done to the database.
// Proceed by updating the memory structures.
- // Disconnect shorter branch
- BOOST_FOREACH(CBlockIndex* pindex, vDisconnect)
- if (pindex->pprev)
- pindex->pprev->pnext = NULL;
-
- // Connect longer branch
+ // Register new best chain
+ vBlockIndexByHeight.resize(pindexNew->nHeight + 1);
BOOST_FOREACH(CBlockIndex* pindex, vConnect)
- if (pindex->pprev)
- pindex->pprev->pnext = pindex;
+ vBlockIndexByHeight[pindex->nHeight] = pindex;
// Resurrect memory transactions that were in the disconnected branch
BOOST_FOREACH(CTransaction& tx, vResurrect) {
@@ -2073,25 +2059,6 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk
if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return state.DoS(100, error("CheckBlock() : size limits failed"));
- // Special short-term limits to avoid 10,000 BDB lock limit:
- if (GetBlockTime() >= 1363867200 && // start enforcing 21 March 2013, noon GMT
- GetBlockTime() < 1368576000) // stop enforcing 15 May 2013 00:00:00
- {
- // Rule is: #unique txids referenced <= 4,500
- // ... to prevent 10,000 BDB lock exhaustion on old clients
- set<uint256> setTxIn;
- for (size_t i = 0; i < vtx.size(); i++)
- {
- setTxIn.insert(vtx[i].GetHash());
- if (i == 0) continue; // skip coinbase txin
- BOOST_FOREACH(const CTxIn& txin, vtx[i].vin)
- setTxIn.insert(txin.prevout.hash);
- }
- size_t nTxids = setTxIn.size();
- if (nTxids > 4500)
- return error("CheckBlock() : 15 May maxlocks violation");
- }
-
// Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits))
return state.DoS(50, error("CheckBlock() : proof of work failed"));
@@ -2606,12 +2573,12 @@ bool static LoadBlockIndexDB()
nBestHeight = pindexBest->nHeight;
nBestChainWork = pindexBest->nChainWork;
- // set 'next' pointers in best chain
+ // register best chain
CBlockIndex *pindex = pindexBest;
- while(pindex != NULL && pindex->pprev != NULL) {
- CBlockIndex *pindexPrev = pindex->pprev;
- pindexPrev->pnext = pindex;
- pindex = pindexPrev;
+ vBlockIndexByHeight.resize(pindexBest->nHeight + 1);
+ while(pindex != NULL) {
+ vBlockIndexByHeight[pindex->nHeight] = pindex;
+ pindex = pindex->pprev;
}
printf("LoadBlockIndexDB(): hashBestChain=%s height=%d date=%s\n",
hashBestChain.ToString().c_str(), nBestHeight,
@@ -2680,7 +2647,7 @@ bool VerifyDB() {
CBlockIndex *pindex = pindexState;
while (pindex != pindexBest) {
boost::this_thread::interruption_point();
- pindex = pindex->pnext;
+ pindex = pindex->GetNextInMainChain();
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
@@ -2856,7 +2823,7 @@ void PrintBlockTree()
vector<CBlockIndex*>& vNext = mapNext[pindex];
for (unsigned int i = 0; i < vNext.size(); i++)
{
- if (vNext[i]->pnext)
+ if (vNext[i]->GetNextInMainChain())
{
swap(vNext[0], vNext[i]);
break;
@@ -2964,7 +2931,7 @@ string GetWarnings(string strFor)
string strStatusBar;
string strRPC;
- if (GetBoolArg("-testsafemode"))
+ if (GetBoolArg("-testsafemode", false))
strRPC = "test";
if (!CLIENT_VERSION_IS_RELEASE)
@@ -3437,10 +3404,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Send the rest of the chain
if (pindex)
- pindex = pindex->pnext;
+ pindex = pindex->GetNextInMainChain();
int nLimit = 500;
printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str(), nLimit);
- for (; pindex; pindex = pindex->pnext)
+ for (; pindex; pindex = pindex->GetNextInMainChain())
{
if (pindex->GetBlockHash() == hashStop)
{
@@ -3480,14 +3447,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Find the last block the caller has in the main chain
pindex = locator.GetBlockIndex();
if (pindex)
- pindex = pindex->pnext;
+ pindex = pindex->GetNextInMainChain();
}
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
vector<CBlock> vHeaders;
int nLimit = 2000;
printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str());
- for (; pindex; pindex = pindex->pnext)
+ for (; pindex; pindex = pindex->GetNextInMainChain())
{
vHeaders.push_back(pindex->GetBlockHeader());
if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
@@ -4188,10 +4155,6 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
// Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity:
nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize));
- // Special compatibility rule before 15 May: limit size to 500,000 bytes:
- if (GetAdjustedTime() < 1368576000)
- nBlockMaxSize = std::min(nBlockMaxSize, (unsigned int)(MAX_BLOCK_SIZE_GEN));
-
// How much of the block should be dedicated to high-priority transactions,
// included regardless of the fees they pay
unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", 27000);
@@ -4212,7 +4175,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
// Priority order to process transactions
list<COrphan> vOrphan; // list memory doesn't move
map<uint256, vector<COrphan*> > mapDependers;
- bool fPrintPriority = GetBoolArg("-printpriority");
+ bool fPrintPriority = GetBoolArg("-printpriority", false);
// This vector will be sorted into a priority queue:
vector<TxPriority> vecPriority;
diff --git a/src/main.h b/src/main.h
index 8e71e66cc8..679ae75a47 100644
--- a/src/main.h
+++ b/src/main.h
@@ -69,6 +69,7 @@ extern CScript COINBASE_FLAGS;
extern CCriticalSection cs_main;
extern std::map<uint256, CBlockIndex*> mapBlockIndex;
+extern std::vector<CBlockIndex*> vBlockIndexByHeight;
extern std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid;
extern uint256 hashGenesisBlock;
extern CBlockIndex* pindexGenesisBlock;
@@ -1589,10 +1590,8 @@ enum BlockStatus {
/** The block chain is a tree shaped structure starting with the
* genesis block at the root, with each block potentially having multiple
- * candidates to be the next block. pprev and pnext link a path through the
- * main/longest chain. A blockindex may have multiple pprev pointing back
- * to it, but pnext will only point forward to the longest branch, or will
- * be null if the block is not part of the longest chain.
+ * candidates to be the next block. A blockindex may have multiple pprev pointing
+ * to it, but at most one of them can be part of the currently active branch.
*/
class CBlockIndex
{
@@ -1603,9 +1602,6 @@ public:
// pointer to the index of the predecessor of this block
CBlockIndex* pprev;
- // (memory only) pointer to the index of the *active* successor of this block
- CBlockIndex* pnext;
-
// height of the entry in the chain. The genesis block has height 0
int nHeight;
@@ -1643,7 +1639,6 @@ public:
{
phashBlock = NULL;
pprev = NULL;
- pnext = NULL;
nHeight = 0;
nFile = 0;
nDataPos = 0;
@@ -1664,7 +1659,6 @@ public:
{
phashBlock = NULL;
pprev = NULL;
- pnext = NULL;
nHeight = 0;
nFile = 0;
nDataPos = 0;
@@ -1733,7 +1727,11 @@ public:
bool IsInMainChain() const
{
- return (pnext || this == pindexBest);
+ return nHeight < (int)vBlockIndexByHeight.size() && vBlockIndexByHeight[nHeight] == this;
+ }
+
+ CBlockIndex *GetNextInMainChain() const {
+ return nHeight+1 >= (int)vBlockIndexByHeight.size() ? NULL : vBlockIndexByHeight[nHeight+1];
}
bool CheckIndex() const
@@ -1762,9 +1760,9 @@ public:
const CBlockIndex* pindex = this;
for (int i = 0; i < nMedianTimeSpan/2; i++)
{
- if (!pindex->pnext)
+ if (!pindex->GetNextInMainChain())
return GetBlockTime();
- pindex = pindex->pnext;
+ pindex = pindex->GetNextInMainChain();
}
return pindex->GetMedianTimePast();
}
@@ -1779,7 +1777,7 @@ public:
std::string ToString() const
{
return strprintf("CBlockIndex(pprev=%p, pnext=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
- pprev, pnext, nHeight,
+ pprev, GetNextInMainChain(), nHeight,
hashMerkleRoot.ToString().c_str(),
GetBlockHash().ToString().c_str());
}
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index 8529c88b39..8906174d7d 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -143,8 +143,13 @@ void AddressBookPage::setModel(AddressTableModel *model)
ui->tableView->sortByColumn(0, Qt::AscendingOrder);
// Set column widths
+#if QT_VERSION < 0x050000
ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
+#else
+ ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
+ ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
+#endif
connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(selectionChanged()));
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index f525d1bb38..9bcac59798 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -17,16 +17,14 @@
#include "splashscreen.h"
#include <QMessageBox>
+#if QT_VERSION < 0x050000
#include <QTextCodec>
+#endif
#include <QLocale>
#include <QTimer>
#include <QTranslator>
#include <QLibraryInfo>
-#ifdef Q_OS_MAC
-#include "macdockiconhandler.h"
-#endif
-
#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
#define _BITCOIN_QT_PLUGINS_INCLUDED
#define __INSURE__
@@ -118,9 +116,11 @@ int main(int argc, char *argv[])
// Command-line options take precedence:
ParseParameters(argc, argv);
+#if QT_VERSION < 0x050000
// Internal string conversion is all UTF-8
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
+#endif
Q_INIT_RESOURCE(bitcoin);
QApplication app(argc, argv);
@@ -152,7 +152,7 @@ int main(int argc, char *argv[])
// as it is used to locate QSettings)
QApplication::setOrganizationName("Bitcoin");
QApplication::setOrganizationDomain("bitcoin.org");
- if(GetBoolArg("-testnet")) // Separate UI settings for testnet
+ if (GetBoolArg("-testnet", false)) // Separate UI settings for testnet
QApplication::setApplicationName("Bitcoin-Qt-testnet");
else
QApplication::setApplicationName("Bitcoin-Qt");
@@ -202,15 +202,8 @@ int main(int argc, char *argv[])
return 1;
}
-#ifdef Q_OS_MAC
- // on mac, also change the icon now because it would look strange to have a testnet splash (green) and a std app icon (orange)
- if(GetBoolArg("-testnet")) {
- MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet"));
- }
-#endif
-
SplashScreen splash(QPixmap(), 0);
- if (GetBoolArg("-splash", true) && !GetBoolArg("-min"))
+ if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false))
{
splash.show();
splash.setAutoFillBackground(true);
@@ -228,7 +221,7 @@ int main(int argc, char *argv[])
boost::thread_group threadGroup;
- BitcoinGUI window;
+ BitcoinGUI window(GetBoolArg("-testnet", false), 0);
guiref = &window;
QTimer* pollShutdownTimer = new QTimer(guiref);
@@ -254,7 +247,7 @@ int main(int argc, char *argv[])
window.setCurrentWallet("~Default");
// If -min option passed, start window minimized.
- if(GetBoolArg("-min"))
+ if(GetBoolArg("-min", false))
{
window.showMinimized();
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 78a69af8b0..190da6caf8 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -44,7 +44,9 @@
#include <QMovie>
#include <QTimer>
#include <QDragEnterEvent>
+#if QT_VERSION < 0x050000
#include <QUrl>
+#endif
#include <QMimeData>
#include <QStyle>
#include <QSettings>
@@ -55,7 +57,7 @@
const QString BitcoinGUI::DEFAULT_WALLET = "~Default";
-BitcoinGUI::BitcoinGUI(QWidget *parent) :
+BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
QMainWindow(parent),
clientModel(0),
encryptWalletAction(0),
@@ -67,14 +69,30 @@ BitcoinGUI::BitcoinGUI(QWidget *parent) :
prevBlocks(0)
{
restoreWindowGeometry();
- setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet"));
+
#ifndef Q_OS_MAC
- QApplication::setWindowIcon(QIcon(":icons/bitcoin"));
- setWindowIcon(QIcon(":icons/bitcoin"));
+ if (!fIsTestnet)
+ {
+ setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet"));
+ QApplication::setWindowIcon(QIcon(":icons/bitcoin"));
+ setWindowIcon(QIcon(":icons/bitcoin"));
+ }
+ else
+ {
+ setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet") + " " + tr("[testnet]"));
+ QApplication::setWindowIcon(QIcon(":icons/bitcoin_testnet"));
+ setWindowIcon(QIcon(":icons/bitcoin_testnet"));
+ }
#else
setUnifiedTitleAndToolBarOnMac(true);
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
+
+ if (!fIsTestnet)
+ MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin"));
+ else
+ MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet"));
#endif
+
// Create wallet frame and make it the central widget
walletFrame = new WalletFrame(this);
setCentralWidget(walletFrame);
@@ -84,7 +102,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent) :
// Create actions for the toolbar, menu bar and tray/dock icon
// Needs walletFrame to be initialized
- createActions();
+ createActions(fIsTestnet);
// Create application menu bar
createMenuBar();
@@ -93,7 +111,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent) :
createToolBars();
// Create system tray icon and notification
- createTrayIcon();
+ createTrayIcon(fIsTestnet);
// Create status bar
statusBar();
@@ -157,7 +175,7 @@ BitcoinGUI::~BitcoinGUI()
#endif
}
-void BitcoinGUI::createActions()
+void BitcoinGUI::createActions(bool fIsTestnet)
{
QActionGroup *tabGroup = new QActionGroup(this);
@@ -211,7 +229,10 @@ void BitcoinGUI::createActions()
quitAction->setStatusTip(tr("Quit application"));
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
quitAction->setMenuRole(QAction::QuitRole);
- aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About Bitcoin"), this);
+ if (!fIsTestnet)
+ aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About Bitcoin"), this);
+ else
+ aboutAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&About Bitcoin"), this);
aboutAction->setStatusTip(tr("Show information about Bitcoin"));
aboutAction->setMenuRole(QAction::AboutRole);
aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this);
@@ -220,7 +241,10 @@ void BitcoinGUI::createActions()
optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin"));
optionsAction->setMenuRole(QAction::PreferencesRole);
- toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this);
+ if (!fIsTestnet)
+ toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this);
+ else
+ toggleHideAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&Show / Hide"), this);
toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
@@ -297,27 +321,6 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
this->clientModel = clientModel;
if(clientModel)
{
- // Replace some strings and icons, when using the testnet
- if(clientModel->isTestNet())
- {
- setWindowTitle(windowTitle() + QString(" ") + tr("[testnet]"));
-#ifndef Q_OS_MAC
- QApplication::setWindowIcon(QIcon(":icons/bitcoin_testnet"));
- setWindowIcon(QIcon(":icons/bitcoin_testnet"));
-#else
- MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet"));
-#endif
- if(trayIcon)
- {
- // Just attach " [testnet]" to the existing tooltip
- trayIcon->setToolTip(trayIcon->toolTip() + QString(" ") + tr("[testnet]"));
- trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
- }
-
- toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet"));
- aboutAction->setIcon(QIcon(":/icons/toolbar_testnet"));
- }
-
// Create system tray menu (or setup the dock menu) that late to prevent users from calling actions,
// while the client has not yet fully loaded
createTrayIconMenu();
@@ -352,13 +355,22 @@ void BitcoinGUI::removeAllWallets()
walletFrame->removeAllWallets();
}
-void BitcoinGUI::createTrayIcon()
+void BitcoinGUI::createTrayIcon(bool fIsTestnet)
{
#ifndef Q_OS_MAC
trayIcon = new QSystemTrayIcon(this);
- trayIcon->setToolTip(tr("Bitcoin client"));
- trayIcon->setIcon(QIcon(":/icons/toolbar"));
+ if (!fIsTestnet)
+ {
+ trayIcon->setToolTip(tr("Bitcoin client"));
+ trayIcon->setIcon(QIcon(":/icons/toolbar"));
+ }
+ else
+ {
+ trayIcon->setToolTip(tr("Bitcoin client") + " " + tr("[testnet]"));
+ trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
+ }
+
trayIcon->show();
#endif
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index f361a62a41..685ce8b430 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -43,7 +43,7 @@ class BitcoinGUI : public QMainWindow
public:
static const QString DEFAULT_WALLET;
- explicit BitcoinGUI(QWidget *parent = 0);
+ explicit BitcoinGUI(bool fIsTestnet = false, QWidget *parent = 0);
~BitcoinGUI();
/** Set the client model.
@@ -113,13 +113,13 @@ private:
int prevBlocks;
/** Create the main UI actions. */
- void createActions();
+ void createActions(bool fIsTestnet);
/** Create the menu bar and sub-menus. */
void createMenuBar();
/** Create the toolbars */
void createToolBars();
/** Create system tray icon and notification */
- void createTrayIcon();
+ void createTrayIcon(bool fIsTestnet);
/** Create system tray menu (or setup the dock menu) */
void createTrayIconMenu();
/** Save window size and position */
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 2105f0730e..6937febfee 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -13,8 +13,12 @@
#include <QDoubleValidator>
#include <QFont>
#include <QLineEdit>
+#if QT_VERSION >= 0x050000
+#include <QUrlQuery>
+#else
#include <QUrl>
-#include <QTextDocument> // For Qt::escape
+#endif
+#include <QTextDocument> // for Qt::mightBeRichText
#include <QAbstractItemView>
#include <QClipboard>
#include <QFileDialog>
@@ -86,7 +90,13 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
SendCoinsRecipient rv;
rv.address = uri.path();
rv.amount = 0;
+
+#if QT_VERSION < 0x050000
QList<QPair<QString, QString> > items = uri.queryItems();
+#else
+ QUrlQuery uriQuery(uri);
+ QList<QPair<QString, QString> > items = uriQuery.queryItems();
+#endif
for (QList<QPair<QString, QString> >::iterator i = items.begin(); i != items.end(); i++)
{
bool fShouldReturnFalse = false;
@@ -139,7 +149,11 @@ bool parseBitcoinURI(QString uri, SendCoinsRecipient *out)
QString HtmlEscape(const QString& str, bool fMultiLine)
{
+#if QT_VERSION < 0x050000
QString escaped = Qt::escape(str);
+#else
+ QString escaped = str.toHtmlEscaped();
+#endif
if(fMultiLine)
{
escaped = escaped.replace("\n", "<br>\n");
@@ -176,7 +190,11 @@ QString getSaveFileName(QWidget *parent, const QString &caption,
QString myDir;
if(dir.isEmpty()) // Default to user documents location
{
+#if QT_VERSION < 0x050000
myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
+#else
+ myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
+#endif
}
else
{
diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts
index 028080d545..741a25a4da 100644
--- a/src/qt/locale/bitcoin_ar.ts
+++ b/src/qt/locale/bitcoin_ar.ts
@@ -38,7 +38,7 @@ This product includes software developed by the OpenSSL Project for use in the O
<message>
<location filename="../forms/addressbookpage.ui" line="+14"/>
<source>Address Book</source>
- <translation>كتاب العنوانين</translation>
+ <translation>دفتر العناوين</translation>
</message>
<message>
<location line="+19"/>
diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm
index b6ea8e1d03..53b49c42e6 100644
--- a/src/qt/macdockiconhandler.mm
+++ b/src/qt/macdockiconhandler.mm
@@ -2,8 +2,8 @@
#include <QMenu>
#include <QWidget>
-
-extern void qt_mac_set_dock_menu(QMenu*);
+#include <QTemporaryFile>
+#include <QImageWriter>
#undef slots
#include <Cocoa/Cocoa.h>
@@ -47,11 +47,11 @@ extern void qt_mac_set_dock_menu(QMenu*);
MacDockIconHandler::MacDockIconHandler() : QObject()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- this->m_dockIconClickEventHandler = [[DockIconClickEventHandler alloc] initWithDockIconHandler:this];
+ this->m_dockIconClickEventHandler = [[DockIconClickEventHandler alloc] initWithDockIconHandler:this];
this->m_dummyWidget = new QWidget();
this->m_dockMenu = new QMenu(this->m_dummyWidget);
- qt_mac_set_dock_menu(this->m_dockMenu);
+
[pool release];
}
@@ -74,15 +74,29 @@ QMenu *MacDockIconHandler::dockMenu()
void MacDockIconHandler::setIcon(const QIcon &icon)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSImage *image;
+ NSImage *image = nil;
if (icon.isNull())
image = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
else {
+ // generate NSImage from QIcon and use this as dock icon.
QSize size = icon.actualSize(QSize(128, 128));
QPixmap pixmap = icon.pixmap(size);
- CGImageRef cgImage = pixmap.toMacCGImageRef();
- image = [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize];
- CFRelease(cgImage);
+
+ // write temp file hack (could also be done through QIODevice [memory])
+ QTemporaryFile notificationIconFile;
+ if (!pixmap.isNull() && notificationIconFile.open()) {
+ QImageWriter writer(&notificationIconFile, "PNG");
+ if (writer.write(pixmap.toImage())) {
+ const char *cString = notificationIconFile.fileName().toUtf8().data();
+ NSString *macString = [NSString stringWithCString:cString encoding:NSUTF8StringEncoding];
+ image = [[NSImage alloc] initWithContentsOfFile:macString];
+ }
+ }
+
+ if(!image) {
+ // if testnet image could not be created, load std. app icon
+ image = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
+ }
}
[NSApp setApplicationIconImage:image];
diff --git a/src/qt/macnotificationhandler.h b/src/qt/macnotificationhandler.h
new file mode 100644
index 0000000000..cd8064c61c
--- /dev/null
+++ b/src/qt/macnotificationhandler.h
@@ -0,0 +1,25 @@
+#ifndef MACNOTIFICATIONHANDLER_H
+#define MACNOTIFICATIONHANDLER_H
+#include <QObject>
+
+/** Macintosh-specific notification handler (supports UserNotificationCenter and Growl).
+ */
+class MacNotificationHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ /** shows a 10.8+ UserNotification in the UserNotificationCenter
+ */
+ void showNotification(const QString &title, const QString &text);
+
+ /** executes AppleScript */
+ void sendAppleScript(const QString &script);
+
+ /** check if OS can handle UserNotifications */
+ bool hasUserNotificationCenterSupport(void);
+ static MacNotificationHandler *instance();
+};
+
+
+#endif // MACNOTIFICATIONHANDLER_H
diff --git a/src/qt/macnotificationhandler.mm b/src/qt/macnotificationhandler.mm
new file mode 100644
index 0000000000..8bb9b887a1
--- /dev/null
+++ b/src/qt/macnotificationhandler.mm
@@ -0,0 +1,65 @@
+#include "macnotificationhandler.h"
+
+#undef slots
+#include <Cocoa/Cocoa.h>
+
+void MacNotificationHandler::showNotification(const QString &title, const QString &text)
+{
+ // check if users OS has support for NSUserNotification
+ if(this->hasUserNotificationCenterSupport()) {
+ // okay, seems like 10.8+
+ QByteArray utf8 = title.toUtf8();
+ char* cString = (char *)utf8.constData();
+ NSString *titleMac = [[NSString alloc] initWithUTF8String:cString];
+
+ utf8 = text.toUtf8();
+ cString = (char *)utf8.constData();
+ NSString *textMac = [[NSString alloc] initWithUTF8String:cString];
+
+ // do everything weak linked (because we will keep <10.8 compatibility)
+ id userNotification = [[NSClassFromString(@"NSUserNotification") alloc] init];
+ [userNotification performSelector:@selector(setTitle:) withObject:titleMac];
+ [userNotification performSelector:@selector(setInformativeText:) withObject:textMac];
+
+ id notificationCenterInstance = [NSClassFromString(@"NSUserNotificationCenter") performSelector:@selector(defaultUserNotificationCenter)];
+ [notificationCenterInstance performSelector:@selector(deliverNotification:) withObject:userNotification];
+
+ [titleMac release];
+ [textMac release];
+ [userNotification release];
+ }
+}
+
+// sendAppleScript just take a QString and executes it as apple script
+void MacNotificationHandler::sendAppleScript(const QString &script)
+{
+ QByteArray utf8 = script.toUtf8();
+ char* cString = (char *)utf8.constData();
+ NSString *scriptApple = [[NSString alloc] initWithUTF8String:cString];
+
+ NSAppleScript *as = [[NSAppleScript alloc] initWithSource:scriptApple];
+ NSDictionary *err = nil;
+ [as executeAndReturnError:&err];
+ [as release];
+ [scriptApple release];
+}
+
+bool MacNotificationHandler::hasUserNotificationCenterSupport(void)
+{
+ Class possibleClass = NSClassFromString(@"NSUserNotificationCenter");
+
+ // check if users OS has support for NSUserNotification
+ if(possibleClass!=nil) {
+ return true;
+ }
+ return false;
+}
+
+
+MacNotificationHandler *MacNotificationHandler::instance()
+{
+ static MacNotificationHandler *s_instance = NULL;
+ if (!s_instance)
+ s_instance = new MacNotificationHandler();
+ return s_instance;
+}
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index 397e7aa4a0..7cfaef6079 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -18,7 +18,7 @@
#ifdef Q_OS_MAC
#include <ApplicationServices/ApplicationServices.h>
-extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret);
+#include "macnotificationhandler.h"
#endif
// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
@@ -47,19 +47,25 @@ Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon,
}
#endif
#ifdef Q_OS_MAC
- // Check if Growl is installed (based on Qt's tray icon implementation)
- CFURLRef cfurl;
- OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
- if (status != kLSApplicationNotFoundErr) {
- CFBundleRef bundle = CFBundleCreate(0, cfurl);
- if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) {
- if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/")))
- mode = Growl13;
- else
- mode = Growl12;
+ // check if users OS has support for NSUserNotification
+ if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) {
+ mode = UserNotificationCenter;
+ }
+ else {
+ // Check if Growl is installed (based on Qt's tray icon implementation)
+ CFURLRef cfurl;
+ OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
+ if (status != kLSApplicationNotFoundErr) {
+ CFBundleRef bundle = CFBundleCreate(0, cfurl);
+ if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) {
+ if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/")))
+ mode = Growl13;
+ else
+ mode = Growl12;
+ }
+ CFRelease(cfurl);
+ CFRelease(bundle);
}
- CFRelease(cfurl);
- CFRelease(bundle);
}
#endif
}
@@ -269,8 +275,14 @@ void Notificator::notifyGrowl(Class cls, const QString &title, const QString &te
quotedTitle.replace("\\", "\\\\").replace("\"", "\\");
quotedText.replace("\\", "\\\\").replace("\"", "\\");
QString growlApp(this->mode == Notificator::Growl13 ? "Growl" : "GrowlHelperApp");
- qt_mac_execute_apple_script(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp), 0);
+ MacNotificationHandler::instance()->sendAppleScript(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp));
+}
+
+void Notificator::notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon) {
+ // icon is not supported by the user notification center yet. OSX will use the app icon.
+ MacNotificationHandler::instance()->showNotification(title, text);
}
+
#endif
void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
@@ -286,6 +298,9 @@ void Notificator::notify(Class cls, const QString &title, const QString &text, c
notifySystray(cls, title, text, icon, millisTimeout);
break;
#ifdef Q_OS_MAC
+ case UserNotificationCenter:
+ notifyMacUserNotificationCenter(cls, title, text, icon);
+ break;
case Growl12:
case Growl13:
notifyGrowl(cls, title, text, icon);
diff --git a/src/qt/notificator.h b/src/qt/notificator.h
index d20673abb6..d1fe37fea5 100644
--- a/src/qt/notificator.h
+++ b/src/qt/notificator.h
@@ -46,11 +46,12 @@ public slots:
private:
QWidget *parent;
enum Mode {
- None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */
- Freedesktop, /**< Use DBus org.freedesktop.Notifications */
- QSystemTray, /**< Use QSystemTray::showMessage */
- Growl12, /**< Use the Growl 1.2 notification system (Mac only) */
- Growl13 /**< Use the Growl 1.3 notification system (Mac only) */
+ None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */
+ Freedesktop, /**< Use DBus org.freedesktop.Notifications */
+ QSystemTray, /**< Use QSystemTray::showMessage */
+ Growl12, /**< Use the Growl 1.2 notification system (Mac only) */
+ Growl13, /**< Use the Growl 1.3 notification system (Mac only) */
+ UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */
};
QString programName;
Mode mode;
@@ -63,6 +64,7 @@ private:
void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout);
#ifdef Q_OS_MAC
void notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon);
+ void notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon);
#endif
};
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index a92e6fc329..0b0bce55bb 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -18,7 +18,9 @@
#include <QLocalServer>
#include <QLocalSocket>
#include <QStringList>
+#if QT_VERSION < 0x050000
#include <QUrl>
+#endif
using namespace boost;
diff --git a/src/qt/qrcodedialog.cpp b/src/qt/qrcodedialog.cpp
index ca94975128..6ddcaaf5d9 100644
--- a/src/qt/qrcodedialog.cpp
+++ b/src/qt/qrcodedialog.cpp
@@ -7,7 +7,9 @@
#include "optionsmodel.h"
#include <QPixmap>
+#if QT_VERSION < 0x050000
#include <QUrl>
+#endif
#include <qrencode.h>
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 50f22b877a..7f90f4a551 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -8,7 +8,9 @@
#include <QTime>
#include <QThread>
#include <QKeyEvent>
+#if QT_VERSION < 0x050000
#include <QUrl>
+#endif
#include <QScrollBar>
#include <openssl/crypto.h>
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index eb3ce48a6e..2c7bab2045 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -93,7 +93,11 @@ void SendCoinsDialog::on_sendButton_clicked()
QStringList formatted;
foreach(const SendCoinsRecipient &rcp, recipients)
{
+#if QT_VERSION < 0x050000
formatted.append(tr("<b>%1</b> to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), Qt::escape(rcp.label), rcp.address));
+#else
+ formatted.append(tr("<b>%1</b> to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), rcp.label.toHtmlEscaped(), rcp.address));
+#endif
}
fNewRecipientAllowed = false;
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 7c43e5839e..9118770f4c 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -218,8 +218,8 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
ss << strMessageMagic;
ss << ui->messageIn_VM->document()->toPlainText().toStdString();
- CKey key;
- if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
+ CPubKey pubkey;
+ if (!pubkey.RecoverCompact(Hash(ss.begin(), ss.end()), vchSig))
{
ui->signatureIn_VM->setValid(false);
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
@@ -227,7 +227,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
return;
}
- if (!(CBitcoinAddress(key.GetPubKey().GetID()) == addr))
+ if (!(CBitcoinAddress(pubkey.GetID()) == addr))
{
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>"));
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index f8d16699ca..e400278123 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -3,6 +3,7 @@
#include "util.h"
#include <QPainter>
+#undef loop /* ugh, remove this when the #define loop is gone from util.h */
#include <QApplication>
SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f) :
@@ -26,7 +27,7 @@ SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f) :
// load the bitmap for writing some text over it
QPixmap newPixmap;
- if(GetBoolArg("-testnet")) {
+ if(GetBoolArg("-testnet", false)) {
newPixmap = QPixmap(":/images/splash_testnet");
}
else {
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 9240b71c71..a43e29c476 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -176,7 +176,11 @@ void TransactionView::setModel(WalletModel *model)
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Status, 23);
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Date, 120);
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Type, 120);
+#if QT_VERSION < 0x050000
transactionView->horizontalHeader()->setResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch);
+#else
+ transactionView->horizontalHeader()->setSectionResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch);
+#endif
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Amount, 100);
}
}
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 83e4255c9f..50c03ac62d 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -8,11 +8,9 @@
#include "bitcoingui.h"
#include "walletstack.h"
-#include <QVBoxLayout>
+#include <QHBoxLayout>
#include <QMessageBox>
-#include <stdio.h>
-
WalletFrame::WalletFrame(BitcoinGUI *_gui) :
QFrame(_gui),
gui(_gui),
diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h
index 3649185e8a..d7092f9879 100644
--- a/src/qt/walletframe.h
+++ b/src/qt/walletframe.h
@@ -17,8 +17,9 @@ class WalletStack;
class WalletFrame : public QFrame
{
Q_OBJECT
+
public:
- explicit WalletFrame(BitcoinGUI *_gui);
+ explicit WalletFrame(BitcoinGUI *_gui = 0);
~WalletFrame();
void setClientModel(ClientModel *clientModel);
diff --git a/src/qt/walletstack.h b/src/qt/walletstack.h
index ea4cc121d1..506d595c0f 100644
--- a/src/qt/walletstack.h
+++ b/src/qt/walletstack.h
@@ -40,6 +40,7 @@ QT_END_NAMESPACE
class WalletStack : public QStackedWidget
{
Q_OBJECT
+
public:
explicit WalletStack(QWidget *parent = 0);
~WalletStack();
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 6d44c174b7..277c056693 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -21,7 +21,11 @@
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QAction>
+#if QT_VERSION < 0x050000
#include <QDesktopServices>
+#else
+#include <QStandardPaths>
+#endif
#include <QFileDialog>
#include <QPushButton>
@@ -232,7 +236,11 @@ void WalletView::encryptWallet(bool status)
void WalletView::backupWallet()
{
+#if QT_VERSION < 0x050000
QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
+#else
+ QString saveDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
+#endif
QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)"));
if (!filename.isEmpty()) {
if (!walletModel->backupWallet(filename)) {
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 11af1abf5d..b1b0c1ac16 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -65,8 +65,9 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
- if (blockindex->pnext)
- result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
+ CBlockIndex *pnext = blockindex->GetNextInMainChain();
+ if (pnext)
+ result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));
return result;
}
diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp
index 77cef02736..d46309eaa4 100644
--- a/src/rpcdump.cpp
+++ b/src/rpcdump.cpp
@@ -54,20 +54,18 @@ Value importprivkey(const Array& params, bool fHelp)
if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
- CKey key;
- bool fCompressed;
- CSecret secret = vchSecret.GetSecret(fCompressed);
- key.SetSecret(secret, fCompressed);
- CKeyID vchAddress = key.GetPubKey().GetID();
+ CKey key = vchSecret.GetKey();
+ CPubKey pubkey = key.GetPubKey();
+ CKeyID vchAddress = pubkey.GetID();
{
LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->MarkDirty();
pwalletMain->SetAddressBookName(vchAddress, strLabel);
- if (!pwalletMain->AddKey(key))
+ if (!pwalletMain->AddKeyPubKey(key, pubkey))
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
-
+
if (fRescan) {
pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
pwalletMain->ReacceptWalletTransactions();
@@ -91,9 +89,8 @@ Value dumpprivkey(const Array& params, bool fHelp)
CKeyID keyID;
if (!address.GetKeyID(keyID))
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
- CSecret vchSecret;
- bool fCompressed;
- if (!pwalletMain->GetSecret(keyID, vchSecret, fCompressed))
+ CKey vchSecret;
+ if (!pwalletMain->GetKey(keyID, vchSecret))
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
- return CBitcoinSecret(vchSecret, fCompressed).ToString();
+ return CBitcoinSecret(vchSecret).ToString();
}
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index fddda8b5f4..d2cac68706 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -11,6 +11,21 @@
using namespace json_spirit;
using namespace std;
+// Key used by getwork/getblocktemplate miners.
+// Allocated in InitRPCMining, free'd in ShutdownRPCMining
+static CReserveKey* pMiningKey = NULL;
+
+void InitRPCMining()
+{
+ // getwork/getblocktemplate mining rewards paid here:
+ pMiningKey = new CReserveKey(pwalletMain);
+}
+
+void ShutdownRPCMining()
+{
+ delete pMiningKey; pMiningKey = NULL;
+}
+
Value getgenerate(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -18,7 +33,7 @@ Value getgenerate(const Array& params, bool fHelp)
"getgenerate\n"
"Returns true or false.");
- return GetBoolArg("-gen");
+ return GetBoolArg("-gen", false);
}
@@ -69,16 +84,16 @@ Value getmininginfo(const Array& params, bool fHelp)
"Returns an object containing mining-related information.");
Object obj;
- obj.push_back(Pair("blocks", (int)nBestHeight));
- obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
- obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
- obj.push_back(Pair("difficulty", (double)GetDifficulty()));
- obj.push_back(Pair("errors", GetWarnings("statusbar")));
- obj.push_back(Pair("generate", GetBoolArg("-gen")));
- obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
- obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
- obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
- obj.push_back(Pair("testnet", fTestNet));
+ obj.push_back(Pair("blocks", (int)nBestHeight));
+ obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize));
+ obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx));
+ obj.push_back(Pair("difficulty", (double)GetDifficulty()));
+ obj.push_back(Pair("errors", GetWarnings("statusbar")));
+ obj.push_back(Pair("generate", GetBoolArg("-gen", false)));
+ obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
+ obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
+ obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
+ obj.push_back(Pair("testnet", fTestNet));
return obj;
}
@@ -104,7 +119,6 @@ Value getwork(const Array& params, bool fHelp)
typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
static mapNewBlock_t mapNewBlock; // FIXME: thread safety
static vector<CBlockTemplate*> vNewBlockTemplate;
- static CReserveKey reservekey(pwalletMain);
if (params.size() == 0)
{
@@ -134,7 +148,7 @@ Value getwork(const Array& params, bool fHelp)
nStart = GetTime();
// Create new block
- pblocktemplate = CreateNewBlock(reservekey);
+ pblocktemplate = CreateNewBlock(*pMiningKey);
if (!pblocktemplate)
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
vNewBlockTemplate.push_back(pblocktemplate);
@@ -192,7 +206,7 @@ Value getwork(const Array& params, bool fHelp)
pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
- return CheckWork(pblock, *pwalletMain, reservekey);
+ return CheckWork(pblock, *pwalletMain, *pMiningKey);
}
}
@@ -243,8 +257,6 @@ Value getblocktemplate(const Array& params, bool fHelp)
if (IsInitialBlockDownload())
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Bitcoin is downloading blocks...");
- static CReserveKey reservekey(pwalletMain);
-
// Update block
static unsigned int nTransactionsUpdatedLast;
static CBlockIndex* pindexPrev;
@@ -267,7 +279,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
delete pblocktemplate;
pblocktemplate = NULL;
}
- pblocktemplate = CreateNewBlock(reservekey);
+ pblocktemplate = CreateNewBlock(*pMiningKey);
if (!pblocktemplate)
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index fb9811b921..c1e05466e5 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -407,10 +407,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
bool fGood = vchSecret.SetString(k.get_str());
if (!fGood)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
- CKey key;
- bool fCompressed;
- CSecret secret = vchSecret.GetSecret(fCompressed);
- key.SetSecret(secret, fCompressed);
+ CKey key = vchSecret.GetKey();
tempKeystore.AddKey(key);
}
}
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 5fd400c6bb..fbad1944de 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -84,7 +84,7 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
if (pwalletMain->IsCrypted())
- obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
+ obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
return obj;
}
@@ -374,11 +374,11 @@ Value verifymessage(const Array& params, bool fHelp)
ss << strMessageMagic;
ss << strMessage;
- CKey key;
- if (!key.SetCompactSignature(ss.GetHash(), vchSig))
+ CPubKey pubkey;
+ if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
return false;
- return (key.GetPubKey().GetID() == keyID);
+ return (pubkey.GetID() == keyID);
}
@@ -719,7 +719,7 @@ static CScript _createmultisig(const Array& params)
throw runtime_error(
strprintf("not enough keys supplied "
"(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired));
- std::vector<CKey> pubkeys;
+ std::vector<CPubKey> pubkeys;
pubkeys.resize(keys.size());
for (unsigned int i = 0; i < keys.size(); i++)
{
@@ -737,16 +737,18 @@ static CScript _createmultisig(const Array& params)
if (!pwalletMain->GetPubKey(keyID, vchPubKey))
throw runtime_error(
strprintf("no full public key for address %s",ks.c_str()));
- if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
+ if (!vchPubKey.IsFullyValid())
throw runtime_error(" Invalid public key: "+ks);
+ pubkeys[i] = vchPubKey;
}
// Case 2: hex public key
else if (IsHex(ks))
{
CPubKey vchPubKey(ParseHex(ks));
- if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
+ if (!vchPubKey.IsFullyValid())
throw runtime_error(" Invalid public key: "+ks);
+ pubkeys[i] = vchPubKey;
}
else
{
@@ -811,6 +813,7 @@ struct tallyitem
{
int64 nAmount;
int nConf;
+ vector<uint256> txids;
tallyitem()
{
nAmount = 0;
@@ -852,6 +855,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
tallyitem& item = mapTally[address];
item.nAmount += txout.nValue;
item.nConf = min(item.nConf, nDepth);
+ item.txids.push_back(wtx.GetHash());
}
}
@@ -887,6 +891,15 @@ Value ListReceived(const Array& params, bool fByAccounts)
obj.push_back(Pair("account", strAccount));
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
+ Array transactions;
+ if (it != mapTally.end())
+ {
+ BOOST_FOREACH(const uint256& item, (*it).second.txids)
+ {
+ transactions.push_back(item.GetHex());
+ }
+ }
+ obj.push_back(Pair("txids", transactions));
ret.push_back(obj);
}
}
@@ -919,7 +932,8 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
" \"address\" : receiving address\n"
" \"account\" : the account of the receiving address\n"
" \"amount\" : total amount received by the address\n"
- " \"confirmations\" : number of confirmations of the most recent transaction included");
+ " \"confirmations\" : number of confirmations of the most recent transaction included\n"
+ " \"txids\" : list of transactions with outputs to the address\n");
return ListReceived(params, false);
}
@@ -1256,56 +1270,11 @@ Value keypoolrefill(const Array& params, bool fHelp)
}
-void ThreadTopUpKeyPool(void* parg)
-{
- // Make this thread recognisable as the key-topping-up thread
- RenameThread("bitcoin-key-top");
-
- pwalletMain->TopUpKeyPool();
-}
-
-void ThreadCleanWalletPassphrase(void* parg)
+static void LockWallet(CWallet* pWallet)
{
- // Make this thread recognisable as the wallet relocking thread
- RenameThread("bitcoin-lock-wa");
-
- int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
-
- ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
-
- if (nWalletUnlockTime == 0)
- {
- nWalletUnlockTime = nMyWakeTime;
-
- do
- {
- if (nWalletUnlockTime==0)
- break;
- int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
- if (nToSleep <= 0)
- break;
-
- LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
- MilliSleep(nToSleep);
- ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
-
- } while(1);
-
- if (nWalletUnlockTime)
- {
- nWalletUnlockTime = 0;
- pwalletMain->Lock();
- }
- }
- else
- {
- if (nWalletUnlockTime < nMyWakeTime)
- nWalletUnlockTime = nMyWakeTime;
- }
-
- LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
-
- delete (int64*)parg;
+ LOCK(cs_nWalletUnlockTime);
+ nWalletUnlockTime = 0;
+ pWallet->Lock();
}
Value walletpassphrase(const Array& params, bool fHelp)
@@ -1319,9 +1288,6 @@ Value walletpassphrase(const Array& params, bool fHelp)
if (!pwalletMain->IsCrypted())
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
- if (!pwalletMain->IsLocked())
- throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked.");
-
// Note that the walletpassphrase is stored in params[0] which is not mlock()ed
SecureString strWalletPass;
strWalletPass.reserve(100);
@@ -1339,9 +1305,12 @@ Value walletpassphrase(const Array& params, bool fHelp)
"walletpassphrase <passphrase> <timeout>\n"
"Stores the wallet decryption key in memory for <timeout> seconds.");
- NewThread(ThreadTopUpKeyPool, NULL);
- int64* pnSleepTime = new int64(params[1].get_int64());
- NewThread(ThreadCleanWalletPassphrase, pnSleepTime);
+ pwalletMain->TopUpKeyPool();
+
+ int64 nSleepTime = params[1].get_int64();
+ LOCK(cs_nWalletUnlockTime);
+ nWalletUnlockTime = GetTime() + nSleepTime;
+ RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
return Value::null;
}
@@ -1445,7 +1414,7 @@ public:
CPubKey vchPubKey;
pwalletMain->GetPubKey(keyID, vchPubKey);
obj.push_back(Pair("isscript", false));
- obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
+ obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
return obj;
}
diff --git a/src/script.cpp b/src/script.cpp
index 90066efd33..b411666353 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -16,7 +16,7 @@ using namespace boost;
#include "sync.h"
#include "util.h"
-bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags);
+bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags);
@@ -1033,13 +1033,13 @@ class CSignatureCache
{
private:
// sigdata_type is (signature hash, signature, public key):
- typedef boost::tuple<uint256, std::vector<unsigned char>, std::vector<unsigned char> > sigdata_type;
+ typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type;
std::set< sigdata_type> setValid;
boost::shared_mutex cs_sigcache;
public:
bool
- Get(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)
+ Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
{
boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
@@ -1050,7 +1050,7 @@ public:
return false;
}
- void Set(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)
+ void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
{
// DoS prevention: limit cache size to less than 10MB
// (~200 bytes per cache entry times 50,000 entries)
@@ -1081,11 +1081,15 @@ public:
}
};
-bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode,
+bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode,
const CTransaction& txTo, unsigned int nIn, int nHashType, int flags)
{
static CSignatureCache signatureCache;
+ CPubKey pubkey(vchPubKey);
+ if (!pubkey.IsValid())
+ return false;
+
// Hash type is one byte tacked on to the end of the signature
if (vchSig.empty())
return false;
@@ -1097,18 +1101,14 @@ bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CSc
uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType);
- if (signatureCache.Get(sighash, vchSig, vchPubKey))
+ if (signatureCache.Get(sighash, vchSig, pubkey))
return true;
- CKey key;
- if (!key.SetPubKey(vchPubKey))
- return false;
-
- if (!key.Verify(sighash, vchSig))
+ if (!pubkey.Verify(sighash, vchSig))
return false;
if (!(flags & SCRIPT_VERIFY_NOCACHE))
- signatureCache.Set(sighash, vchSig, vchPubKey);
+ signatureCache.Set(sighash, vchSig, pubkey);
return true;
}
@@ -1770,13 +1770,13 @@ void CScript::SetDestination(const CTxDestination& dest)
boost::apply_visitor(CScriptVisitor(this), dest);
}
-void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys)
+void CScript::SetMultisig(int nRequired, const std::vector<CPubKey>& keys)
{
this->clear();
*this << EncodeOP_N(nRequired);
- BOOST_FOREACH(const CKey& key, keys)
- *this << key.GetPubKey();
+ BOOST_FOREACH(const CPubKey& key, keys)
+ *this << key;
*this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
}
@@ -1801,20 +1801,17 @@ bool CScriptCompressor::IsToScriptID(CScriptID &hash) const
return false;
}
-bool CScriptCompressor::IsToPubKey(std::vector<unsigned char> &pubkey) const
+bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const
{
if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG
&& (script[1] == 0x02 || script[1] == 0x03)) {
- pubkey.resize(33);
- memcpy(&pubkey[0], &script[1], 33);
+ pubkey.Set(&script[1], &script[34]);
return true;
}
if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG
&& script[1] == 0x04) {
- pubkey.resize(65);
- memcpy(&pubkey[0], &script[1], 65);
- CKey key;
- return (key.SetPubKey(CPubKey(pubkey))); // SetPubKey fails if this is not a valid public key, a case that would not be compressible
+ pubkey.Set(&script[1], &script[66]);
+ return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible
}
return false;
}
@@ -1835,7 +1832,7 @@ bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const
memcpy(&out[1], &scriptID, 20);
return true;
}
- std::vector<unsigned char> pubkey;
+ CPubKey pubkey;
if (IsToPubKey(pubkey)) {
out.resize(33);
memcpy(&out[1], &pubkey[1], 32);
@@ -1888,17 +1885,16 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigne
return true;
case 0x04:
case 0x05:
- std::vector<unsigned char> vch(33, 0x00);
+ unsigned char vch[33] = {};
vch[0] = nSize - 2;
memcpy(&vch[1], &in[0], 32);
- CKey key;
- if (!key.SetPubKey(CPubKey(vch)))
+ CPubKey pubkey(&vch[0], &vch[33]);
+ if (!pubkey.Decompress())
return false;
- key.SetCompressedPubKey(false); // Decompress public key
- CPubKey pubkey = key.GetPubKey();
+ assert(pubkey.size() == 65);
script.resize(67);
script[0] = 65;
- memcpy(&script[1], &pubkey.Raw()[0], 65);
+ memcpy(&script[1], pubkey.begin(), 65);
script[66] = OP_CHECKSIG;
return true;
}
diff --git a/src/script.h b/src/script.h
index 4b29f6273c..3cbb2cf322 100644
--- a/src/script.h
+++ b/src/script.h
@@ -348,8 +348,10 @@ public:
CScript& operator<<(const CPubKey& key)
{
- std::vector<unsigned char> vchKey = key.Raw();
- return (*this) << vchKey;
+ assert(key.size() < OP_PUSHDATA1);
+ insert(end(), (unsigned char)key.size());
+ insert(end(), key.begin(), key.end());
+ return *this;
}
CScript& operator<<(const CBigNum& b)
@@ -548,7 +550,7 @@ public:
void SetDestination(const CTxDestination& address);
- void SetMultisig(int nRequired, const std::vector<CKey>& keys);
+ void SetMultisig(int nRequired, const std::vector<CPubKey>& keys);
void PrintHex() const
@@ -619,7 +621,7 @@ protected:
// form).
bool IsToKeyID(CKeyID &hash) const;
bool IsToScriptID(CScriptID &hash) const;
- bool IsToPubKey(std::vector<unsigned char> &pubkey) const;
+ bool IsToPubKey(CPubKey &pubkey) const;
bool Compress(std::vector<unsigned char> &out) const;
unsigned int GetSpecialSize(unsigned int nSize) const;
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index 7602fa93a6..2741672a88 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -133,9 +133,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
// Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not!
BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest);
BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest);
- bool fCompressedOut = false;
- CSecret privkey = secret.GetSecret(fCompressedOut);
- BOOST_CHECK_MESSAGE(fCompressedOut == isCompressed, "compressed mismatch:" + strTest);
+ CKey privkey = secret.GetKey();
+ BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);
BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
// Private key must be invalid public key
@@ -187,8 +186,11 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
if(isPrivkey)
{
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
+ CKey key;
+ key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
+ assert(key.IsValid());
CBitcoinSecret secret;
- secret.SetSecret(CSecret(exp_payload.begin(), exp_payload.end()), isCompressed);
+ secret.SetKey(key);
BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest);
}
else
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 4a2851cf46..0d349a990c 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -73,14 +73,13 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_key)
CBitcoinSecret vchSecret;
BOOST_CHECK(vchSecret.SetString(strSecret));
- CKey key;
- bool fCompressed;
- CSecret secret = vchSecret.GetSecret(fCompressed);
- key.SetSecret(secret, fCompressed);
+ CKey key = vchSecret.GetKey();
+ CPubKey pubkey = key.GetPubKey();
+ vector<unsigned char> vchPubKey(pubkey.begin(), pubkey.end());
CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL);
- filter.insert(key.GetPubKey().Raw());
- uint160 hash = key.GetPubKey().GetID();
+ filter.insert(vchPubKey);
+ uint160 hash = pubkey.GetID();
filter.insert(vector<unsigned char>(hash.begin(), hash.end()));
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp
index 3cfb6dbfa4..d626f9a6f4 100644
--- a/src/test/checkblock_tests.cpp
+++ b/src/test/checkblock_tests.cpp
@@ -52,8 +52,6 @@ BOOST_AUTO_TEST_CASE(May15)
if (read_block("Mar12Fork.dat", forkingBlock))
{
CValidationState state;
- forkingBlock.nTime = tMay15-1; // Invalidates PoW
- BOOST_CHECK(!forkingBlock.CheckBlock(state, false, false));
// After May 15'th, big blocks are OK:
forkingBlock.nTime = tMay15; // Invalidates PoW
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 78953d296f..c89d218f80 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -6,8 +6,7 @@
BOOST_AUTO_TEST_SUITE(getarg_tests)
-static void
-ResetArgs(const std::string& strArg)
+static void ResetArgs(const std::string& strArg)
{
std::vector<std::string> vecArg;
boost::split(vecArg, strArg, boost::is_space(), boost::token_compress_on);
@@ -26,62 +25,50 @@ ResetArgs(const std::string& strArg)
BOOST_AUTO_TEST_CASE(boolarg)
{
ResetArgs("-foo");
- BOOST_CHECK(GetBoolArg("-foo"));
BOOST_CHECK(GetBoolArg("-foo", false));
BOOST_CHECK(GetBoolArg("-foo", true));
- BOOST_CHECK(!GetBoolArg("-fo"));
BOOST_CHECK(!GetBoolArg("-fo", false));
BOOST_CHECK(GetBoolArg("-fo", true));
- BOOST_CHECK(!GetBoolArg("-fooo"));
BOOST_CHECK(!GetBoolArg("-fooo", false));
BOOST_CHECK(GetBoolArg("-fooo", true));
ResetArgs("-foo=0");
- BOOST_CHECK(!GetBoolArg("-foo"));
BOOST_CHECK(!GetBoolArg("-foo", false));
BOOST_CHECK(!GetBoolArg("-foo", true));
ResetArgs("-foo=1");
- BOOST_CHECK(GetBoolArg("-foo"));
BOOST_CHECK(GetBoolArg("-foo", false));
BOOST_CHECK(GetBoolArg("-foo", true));
// New 0.6 feature: auto-map -nosomething to !-something:
ResetArgs("-nofoo");
- BOOST_CHECK(!GetBoolArg("-foo"));
BOOST_CHECK(!GetBoolArg("-foo", false));
BOOST_CHECK(!GetBoolArg("-foo", true));
ResetArgs("-nofoo=1");
- BOOST_CHECK(!GetBoolArg("-foo"));
BOOST_CHECK(!GetBoolArg("-foo", false));
BOOST_CHECK(!GetBoolArg("-foo", true));
ResetArgs("-foo -nofoo"); // -foo should win
- BOOST_CHECK(GetBoolArg("-foo"));
BOOST_CHECK(GetBoolArg("-foo", false));
BOOST_CHECK(GetBoolArg("-foo", true));
ResetArgs("-foo=1 -nofoo=1"); // -foo should win
- BOOST_CHECK(GetBoolArg("-foo"));
BOOST_CHECK(GetBoolArg("-foo", false));
BOOST_CHECK(GetBoolArg("-foo", true));
ResetArgs("-foo=0 -nofoo=0"); // -foo should win
- BOOST_CHECK(!GetBoolArg("-foo"));
BOOST_CHECK(!GetBoolArg("-foo", false));
BOOST_CHECK(!GetBoolArg("-foo", true));
// New 0.6 feature: treat -- same as -:
ResetArgs("--foo=1");
- BOOST_CHECK(GetBoolArg("-foo"));
BOOST_CHECK(GetBoolArg("-foo", false));
BOOST_CHECK(GetBoolArg("-foo", true));
ResetArgs("--nofoo=1");
- BOOST_CHECK(!GetBoolArg("-foo"));
BOOST_CHECK(!GetBoolArg("-foo", false));
BOOST_CHECK(!GetBoolArg("-foo", true));
@@ -133,7 +120,7 @@ BOOST_AUTO_TEST_CASE(intarg)
BOOST_AUTO_TEST_CASE(doubledash)
{
ResetArgs("--foo");
- BOOST_CHECK_EQUAL(GetBoolArg("-foo"), true);
+ BOOST_CHECK_EQUAL(GetBoolArg("-foo", false), true);
ResetArgs("--foo=verbose --bar=1");
BOOST_CHECK_EQUAL(GetArg("-foo", ""), "verbose");
@@ -143,25 +130,24 @@ BOOST_AUTO_TEST_CASE(doubledash)
BOOST_AUTO_TEST_CASE(boolargno)
{
ResetArgs("-nofoo");
- BOOST_CHECK(!GetBoolArg("-foo"));
BOOST_CHECK(!GetBoolArg("-foo", true));
BOOST_CHECK(!GetBoolArg("-foo", false));
ResetArgs("-nofoo=1");
- BOOST_CHECK(!GetBoolArg("-foo"));
BOOST_CHECK(!GetBoolArg("-foo", true));
BOOST_CHECK(!GetBoolArg("-foo", false));
ResetArgs("-nofoo=0");
- BOOST_CHECK(GetBoolArg("-foo"));
BOOST_CHECK(GetBoolArg("-foo", true));
BOOST_CHECK(GetBoolArg("-foo", false));
ResetArgs("-foo --nofoo");
- BOOST_CHECK(GetBoolArg("-foo"));
+ BOOST_CHECK(GetBoolArg("-foo", true));
+ BOOST_CHECK(GetBoolArg("-foo", false));
ResetArgs("-nofoo -foo"); // foo always wins:
- BOOST_CHECK(GetBoolArg("-foo"));
+ BOOST_CHECK(GetBoolArg("-foo", true));
+ BOOST_CHECK(GetBoolArg("-foo", false));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 0a6df88fef..c004521d1a 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -26,8 +26,8 @@ static const string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF");
#ifdef KEY_TESTS_DUMPINFO
void dumpKeyInfo(uint256 privkey)
{
- CSecret secret;
- secret.resize(32);
+ CKey key;
+ key.resize(32);
memcpy(&secret[0], &privkey, 32);
vector<unsigned char> sec;
sec.resize(32);
@@ -62,29 +62,24 @@ BOOST_AUTO_TEST_CASE(key_test1)
BOOST_CHECK( bsecret2C.SetString(strSecret2C));
BOOST_CHECK(!baddress1.SetString(strAddressBad));
- bool fCompressed;
- CSecret secret1 = bsecret1.GetSecret (fCompressed);
- BOOST_CHECK(fCompressed == false);
- CSecret secret2 = bsecret2.GetSecret (fCompressed);
- BOOST_CHECK(fCompressed == false);
- CSecret secret1C = bsecret1C.GetSecret(fCompressed);
- BOOST_CHECK(fCompressed == true);
- CSecret secret2C = bsecret2C.GetSecret(fCompressed);
- BOOST_CHECK(fCompressed == true);
-
- BOOST_CHECK(secret1 == secret1C);
- BOOST_CHECK(secret2 == secret2C);
-
- CKey key1, key2, key1C, key2C;
- key1.SetSecret(secret1, false);
- key2.SetSecret(secret2, false);
- key1C.SetSecret(secret1, true);
- key2C.SetSecret(secret2, true);
-
- BOOST_CHECK(addr1.Get() == CTxDestination(key1.GetPubKey().GetID()));
- BOOST_CHECK(addr2.Get() == CTxDestination(key2.GetPubKey().GetID()));
- BOOST_CHECK(addr1C.Get() == CTxDestination(key1C.GetPubKey().GetID()));
- BOOST_CHECK(addr2C.Get() == CTxDestination(key2C.GetPubKey().GetID()));
+ CKey key1 = bsecret1.GetKey();
+ BOOST_CHECK(key1.IsCompressed() == false);
+ CKey key2 = bsecret2.GetKey();
+ BOOST_CHECK(key2.IsCompressed() == false);
+ CKey key1C = bsecret1C.GetKey();
+ BOOST_CHECK(key1C.IsCompressed() == true);
+ CKey key2C = bsecret2C.GetKey();
+ BOOST_CHECK(key1C.IsCompressed() == true);
+
+ CPubKey pubkey1 = key1. GetPubKey();
+ CPubKey pubkey2 = key2. GetPubKey();
+ CPubKey pubkey1C = key1C.GetPubKey();
+ CPubKey pubkey2C = key2C.GetPubKey();
+
+ BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID()));
+ BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID()));
+ BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID()));
+ BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID()));
for (int n=0; n<16; n++)
{
@@ -100,25 +95,25 @@ BOOST_AUTO_TEST_CASE(key_test1)
BOOST_CHECK(key1C.Sign(hashMsg, sign1C));
BOOST_CHECK(key2C.Sign(hashMsg, sign2C));
- BOOST_CHECK( key1.Verify(hashMsg, sign1));
- BOOST_CHECK(!key1.Verify(hashMsg, sign2));
- BOOST_CHECK( key1.Verify(hashMsg, sign1C));
- BOOST_CHECK(!key1.Verify(hashMsg, sign2C));
+ BOOST_CHECK( pubkey1.Verify(hashMsg, sign1));
+ BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2));
+ BOOST_CHECK( pubkey1.Verify(hashMsg, sign1C));
+ BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2C));
- BOOST_CHECK(!key2.Verify(hashMsg, sign1));
- BOOST_CHECK( key2.Verify(hashMsg, sign2));
- BOOST_CHECK(!key2.Verify(hashMsg, sign1C));
- BOOST_CHECK( key2.Verify(hashMsg, sign2C));
+ BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1));
+ BOOST_CHECK( pubkey2.Verify(hashMsg, sign2));
+ BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1C));
+ BOOST_CHECK( pubkey2.Verify(hashMsg, sign2C));
- BOOST_CHECK( key1C.Verify(hashMsg, sign1));
- BOOST_CHECK(!key1C.Verify(hashMsg, sign2));
- BOOST_CHECK( key1C.Verify(hashMsg, sign1C));
- BOOST_CHECK(!key1C.Verify(hashMsg, sign2C));
+ BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1));
+ BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2));
+ BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1C));
+ BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2C));
- BOOST_CHECK(!key2C.Verify(hashMsg, sign1));
- BOOST_CHECK( key2C.Verify(hashMsg, sign2));
- BOOST_CHECK(!key2C.Verify(hashMsg, sign1C));
- BOOST_CHECK( key2C.Verify(hashMsg, sign2C));
+ BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1));
+ BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2));
+ BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1C));
+ BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2C));
// compact signatures (with key recovery)
@@ -129,18 +124,17 @@ BOOST_AUTO_TEST_CASE(key_test1)
BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C));
BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C));
- CKey rkey1, rkey2, rkey1C, rkey2C;
+ CPubKey rkey1, rkey2, rkey1C, rkey2C;
- BOOST_CHECK(rkey1.SetCompactSignature (hashMsg, csign1));
- BOOST_CHECK(rkey2.SetCompactSignature (hashMsg, csign2));
- BOOST_CHECK(rkey1C.SetCompactSignature(hashMsg, csign1C));
- BOOST_CHECK(rkey2C.SetCompactSignature(hashMsg, csign2C));
+ BOOST_CHECK(rkey1.RecoverCompact (hashMsg, csign1));
+ BOOST_CHECK(rkey2.RecoverCompact (hashMsg, csign2));
+ BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C));
+ BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C));
-
- BOOST_CHECK(rkey1.GetPubKey() == key1.GetPubKey());
- BOOST_CHECK(rkey2.GetPubKey() == key2.GetPubKey());
- BOOST_CHECK(rkey1C.GetPubKey() == key1C.GetPubKey());
- BOOST_CHECK(rkey2C.GetPubKey() == key2C.GetPubKey());
+ BOOST_CHECK(rkey1 == pubkey1);
+ BOOST_CHECK(rkey2 == pubkey2);
+ BOOST_CHECK(rkey1C == pubkey1C);
+ BOOST_CHECK(rkey2C == pubkey2C);
}
}
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index d6f836d367..9ef932b5b4 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -30,7 +30,7 @@ sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction,
CScript result;
result << OP_0; // CHECKMULTISIG bug workaround
- BOOST_FOREACH(CKey key, keys)
+ BOOST_FOREACH(const CKey &key, keys)
{
vector<unsigned char> vchSig;
BOOST_CHECK(key.Sign(hash, vchSig));
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index f8fe443b87..35eabed0e2 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -79,23 +79,44 @@ static Value CallRPC(string args)
}
}
-BOOST_AUTO_TEST_CASE(rpc_rawparams)
+BOOST_AUTO_TEST_CASE(rpc_wallet)
{
- // Test raw transaction API argument handling
+ // Test RPC calls for various wallet statistics
Value r;
- BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), runtime_error);
-
BOOST_CHECK_NO_THROW(CallRPC("listunspent"));
BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error);
BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error);
BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []"));
- BOOST_CHECK_THROW(r=CallRPC("listunspent 0 1 [] extra"), runtime_error);
BOOST_CHECK(r.get_array().empty());
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress"));
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0"));
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true"));
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error);
+
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount"));
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0"));
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true"));
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error);
+}
+
+
+BOOST_AUTO_TEST_CASE(rpc_rawparams)
+{
+ // Test raw transaction API argument handling
+ Value r;
+
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), runtime_error);
+
BOOST_CHECK_THROW(CallRPC("createrawtransaction"), runtime_error);
BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), runtime_error);
BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), runtime_error);
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index ee0d25a2f5..65f0ad0cdc 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -145,19 +145,19 @@ BOOST_AUTO_TEST_CASE(set)
// Test the CScript::Set* methods
CBasicKeyStore keystore;
CKey key[4];
- std::vector<CKey> keys;
+ std::vector<CPubKey> keys;
for (int i = 0; i < 4; i++)
{
key[i].MakeNewKey(true);
keystore.AddKey(key[i]);
- keys.push_back(key[i]);
+ keys.push_back(key[i].GetPubKey());
}
CScript inner[4];
inner[0].SetDestination(key[0].GetPubKey().GetID());
- inner[1].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+2));
- inner[2].SetMultisig(1, std::vector<CKey>(keys.begin(), keys.begin()+2));
- inner[3].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+3));
+ inner[1].SetMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+2));
+ inner[2].SetMultisig(1, std::vector<CPubKey>(keys.begin(), keys.begin()+2));
+ inner[3].SetMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+3));
CScript outer[4];
for (int i = 0; i < 4; i++)
@@ -248,12 +248,12 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
CCoinsViewCache coins(coinsDummy);
CBasicKeyStore keystore;
CKey key[3];
- vector<CKey> keys;
+ vector<CPubKey> keys;
for (int i = 0; i < 3; i++)
{
key[i].MakeNewKey(true);
keystore.AddKey(key[i]);
- keys.push_back(key[i]);
+ keys.push_back(key[i].GetPubKey());
}
CTransaction txFrom;
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 5d5a1525f7..e7ad52627c 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -211,7 +211,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
// and vice-versa)
//
result << OP_0;
- BOOST_FOREACH(CKey key, keys)
+ BOOST_FOREACH(const CKey &key, keys)
{
vector<unsigned char> vchSig;
BOOST_CHECK(key.Sign(hash, vchSig));
@@ -221,7 +221,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
return result;
}
CScript
-sign_multisig(CScript scriptPubKey, CKey key, CTransaction transaction)
+sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction)
{
std::vector<CKey> keys;
keys.push_back(key);
@@ -333,11 +333,13 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
// Test the CombineSignatures function
CBasicKeyStore keystore;
vector<CKey> keys;
+ vector<CPubKey> pubkeys;
for (int i = 0; i < 3; i++)
{
CKey key;
key.MakeNewKey(i%2 == 1);
keys.push_back(key);
+ pubkeys.push_back(key.GetPubKey());
keystore.AddKey(key);
}
@@ -390,7 +392,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
BOOST_CHECK(combined == scriptSig);
// Hardest case: Multisig 2-of-3
- scriptPubKey.SetMultisig(2, keys);
+ scriptPubKey.SetMultisig(2, pubkeys);
keystore.AddCScript(scriptPubKey);
SignSignature(keystore, txFrom, txTo, 0);
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);
diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp
index 1762680adf..5a87f17600 100644
--- a/src/test/sigopcount_tests.cpp
+++ b/src/test/sigopcount_tests.cpp
@@ -37,12 +37,12 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount)
scriptSig << OP_0 << Serialize(s1);
BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U);
- std::vector<CKey> keys;
+ std::vector<CPubKey> keys;
for (int i = 0; i < 3; i++)
{
CKey k;
k.MakeNewKey(true);
- keys.push_back(k);
+ keys.push_back(k.GetPubKey());
}
CScript s2;
s2.SetMultisig(1, keys);
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 1b0ccad511..64bd3a1b28 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -31,7 +31,7 @@ BOOST_AUTO_TEST_CASE(util_criticalsection)
}
BOOST_AUTO_TEST_CASE(util_MedianFilter)
-{
+{
CMedianFilter<int> filter(5, 15);
BOOST_CHECK_EQUAL(filter.median(), 15);
@@ -56,10 +56,10 @@ BOOST_AUTO_TEST_CASE(util_MedianFilter)
}
static const unsigned char ParseHex_expected[65] = {
- 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7,
- 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde,
- 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12,
- 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d,
+ 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7,
+ 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde,
+ 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12,
+ 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d,
0x5f
};
BOOST_AUTO_TEST_CASE(util_ParseHex)
@@ -123,13 +123,13 @@ BOOST_AUTO_TEST_CASE(util_ParseParameters)
BOOST_CHECK(mapArgs.empty() && mapMultiArgs.empty());
ParseParameters(5, (char**)argv_test);
- // expectation: -ignored is ignored (program name argument),
+ // expectation: -ignored is ignored (program name argument),
// -a, -b and -ccc end up in map, -d ignored because it is after
// a non-option argument (non-GNU option parsing)
BOOST_CHECK(mapArgs.size() == 3 && mapMultiArgs.size() == 3);
- BOOST_CHECK(mapArgs.count("-a") && mapArgs.count("-b") && mapArgs.count("-ccc")
+ BOOST_CHECK(mapArgs.count("-a") && mapArgs.count("-b") && mapArgs.count("-ccc")
&& !mapArgs.count("f") && !mapArgs.count("-d"));
- BOOST_CHECK(mapMultiArgs.count("-a") && mapMultiArgs.count("-b") && mapMultiArgs.count("-ccc")
+ BOOST_CHECK(mapMultiArgs.count("-a") && mapMultiArgs.count("-b") && mapMultiArgs.count("-ccc")
&& !mapMultiArgs.count("f") && !mapMultiArgs.count("-d"));
BOOST_CHECK(mapArgs["-a"] == "" && mapArgs["-ccc"] == "multiple");
@@ -154,10 +154,10 @@ BOOST_AUTO_TEST_CASE(util_GetArg)
BOOST_CHECK_EQUAL(GetArg("inttest1", -1), 12345);
BOOST_CHECK_EQUAL(GetArg("inttest2", -1), 81985529216486895LL);
BOOST_CHECK_EQUAL(GetArg("inttest3", -1), -1);
- BOOST_CHECK_EQUAL(GetBoolArg("booltest1"), true);
- BOOST_CHECK_EQUAL(GetBoolArg("booltest2"), false);
- BOOST_CHECK_EQUAL(GetBoolArg("booltest3"), false);
- BOOST_CHECK_EQUAL(GetBoolArg("booltest4"), true);
+ BOOST_CHECK_EQUAL(GetBoolArg("booltest1", false), true);
+ BOOST_CHECK_EQUAL(GetBoolArg("booltest2", false), false);
+ BOOST_CHECK_EQUAL(GetBoolArg("booltest3", false), false);
+ BOOST_CHECK_EQUAL(GetBoolArg("booltest4", false), true);
}
BOOST_AUTO_TEST_CASE(util_WildcardMatch)
diff --git a/src/util.cpp b/src/util.cpp
index 4c9b897f57..0bd2960233 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -518,7 +518,7 @@ static void InterpretNegativeSetting(string name, map<string, string>& mapSettin
positive.append(name.begin()+3, name.end());
if (mapSettingsRet.count(positive) == 0)
{
- bool value = !GetBoolArg(name);
+ bool value = !GetBoolArg(name, false);
mapSettingsRet[positive] = (value ? "1" : "0");
}
}
@@ -1171,7 +1171,6 @@ bool TruncateFile(FILE *file, unsigned int length) {
#endif
}
-
// this function tries to raise the file descriptor limit to the requested number.
// It returns the actual file descriptor limit (which may be more or less than nMinFD)
int RaiseFileDescriptorLimit(int nMinFD) {
@@ -1257,8 +1256,8 @@ void ShrinkDebugFile()
fclose(file);
}
}
- else if(file != NULL)
- fclose(file);
+ else if (file != NULL)
+ fclose(file);
}
diff --git a/src/util.h b/src/util.h
index 3d25364505..941e0d99ac 100644
--- a/src/util.h
+++ b/src/util.h
@@ -7,12 +7,12 @@
#include "uint256.h"
+#include <stdarg.h>
+
#ifndef WIN32
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
-#else
-typedef int pid_t; /* define for Windows compatibility */
#endif
#include <map>
#include <list>
@@ -298,7 +298,8 @@ std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
return rv;
}
-inline std::string HexStr(const std::vector<unsigned char>& vch, bool fSpaces=false)
+template<typename T>
+inline std::string HexStr(const T& vch, bool fSpaces=false)
{
return HexStr(vch.begin(), vch.end(), fSpaces);
}
@@ -389,7 +390,7 @@ int64 GetArg(const std::string& strArg, int64 nDefault);
* @param default (true or false)
* @return command-line argument or default value
*/
-bool GetBoolArg(const std::string& strArg, bool fDefault=false);
+bool GetBoolArg(const std::string& strArg, bool fDefault);
/**
* Set an argument if it doesn't already have a value
diff --git a/src/wallet.cpp b/src/wallet.cpp
index c70ea20e88..27aab08ecb 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -32,26 +32,28 @@ CPubKey CWallet::GenerateNewKey()
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
RandAddSeedPerfmon();
- CKey key;
- key.MakeNewKey(fCompressed);
+ CKey secret;
+ secret.MakeNewKey(fCompressed);
// Compressed public keys were introduced in version 0.6.0
if (fCompressed)
SetMinVersion(FEATURE_COMPRPUBKEY);
- if (!AddKey(key))
+ CPubKey pubkey = secret.GetPubKey();
+ if (!AddKeyPubKey(secret, pubkey))
throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
- return key.GetPubKey();
+ return pubkey;
}
-bool CWallet::AddKey(const CKey& key)
+bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
{
- if (!CCryptoKeyStore::AddKey(key))
+ if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
return false;
if (!fFileBacked)
return true;
- if (!IsCrypted())
- return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
+ if (!IsCrypted()) {
+ return CWalletDB(strWalletFile).WriteKey(pubkey, secret.GetPrivKey());
+ }
return true;
}
@@ -87,9 +89,6 @@ bool CWallet::AddCScript(const CScript& redeemScript)
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
- if (!IsLocked())
- return false;
-
CCrypter crypter;
CKeyingMaterial vMasterKey;
@@ -100,7 +99,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase)
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
- return false;
+ continue; // try another master key
if (CCryptoKeyStore::Unlock(vMasterKey))
return true;
}
@@ -780,7 +779,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
ret++;
}
- pindex = pindex->pnext;
+ pindex = pindex->GetNextInMainChain();
}
}
return ret;
diff --git a/src/wallet.h b/src/wallet.h
index dcba4675eb..7fcb8e13ce 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -136,9 +136,9 @@ public:
// Generate a new key
CPubKey GenerateNewKey();
// Adds a key to the store, and saves it to disk.
- bool AddKey(const CKey& key);
+ bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
// Adds a key to the store, without saving it to disk (used by LoadWallet)
- bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); }
+ bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index 81a21443a1..4a73413d26 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -262,52 +262,33 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
else if (strType == "key" || strType == "wkey")
{
- vector<unsigned char> vchPubKey;
+ CPubKey vchPubKey;
ssKey >> vchPubKey;
+ if (!vchPubKey.IsValid())
+ {
+ strErr = "Error reading wallet database: CPubKey corrupt";
+ return false;
+ }
CKey key;
+ CPrivKey pkey;
if (strType == "key")
- {
- CPrivKey pkey;
ssValue >> pkey;
- key.SetPubKey(vchPubKey);
- if (!key.SetPrivKey(pkey))
- {
- strErr = "Error reading wallet database: CPrivKey corrupt";
- return false;
- }
- if (key.GetPubKey() != vchPubKey)
- {
- strErr = "Error reading wallet database: CPrivKey pubkey inconsistency";
- return false;
- }
- if (!key.IsValid())
- {
- strErr = "Error reading wallet database: invalid CPrivKey";
- return false;
- }
- }
- else
- {
+ else {
CWalletKey wkey;
ssValue >> wkey;
- key.SetPubKey(vchPubKey);
- if (!key.SetPrivKey(wkey.vchPrivKey))
- {
- strErr = "Error reading wallet database: CPrivKey corrupt";
- return false;
- }
- if (key.GetPubKey() != vchPubKey)
- {
- strErr = "Error reading wallet database: CWalletKey pubkey inconsistency";
- return false;
- }
- if (!key.IsValid())
- {
- strErr = "Error reading wallet database: invalid CWalletKey";
- return false;
- }
+ pkey = wkey.vchPrivKey;
+ }
+ if (!key.SetPrivKey(pkey, vchPubKey.IsCompressed()))
+ {
+ strErr = "Error reading wallet database: CPrivKey corrupt";
+ return false;
+ }
+ if (key.GetPubKey() != vchPubKey)
+ {
+ strErr = "Error reading wallet database: CPrivKey pubkey inconsistency";
+ return false;
}
- if (!pwallet->LoadKey(key))
+ if (!pwallet->LoadKey(key, vchPubKey))
{
strErr = "Error reading wallet database: LoadKey failed";
return false;
diff --git a/src/walletdb.h b/src/walletdb.h
index a3e779ab9d..8ae6c3ff49 100644
--- a/src/walletdb.h
+++ b/src/walletdb.h
@@ -53,18 +53,18 @@ public:
bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey)
{
nWalletDBUpdated++;
- return Write(std::make_pair(std::string("key"), vchPubKey.Raw()), vchPrivKey, false);
+ return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
}
bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
{
nWalletDBUpdated++;
- if (!Write(std::make_pair(std::string("ckey"), vchPubKey.Raw()), vchCryptedSecret, false))
+ if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
return false;
if (fEraseUnencryptedKey)
{
- Erase(std::make_pair(std::string("key"), vchPubKey.Raw()));
- Erase(std::make_pair(std::string("wkey"), vchPubKey.Raw()));
+ Erase(std::make_pair(std::string("key"), vchPubKey));
+ Erase(std::make_pair(std::string("wkey"), vchPubKey));
}
return true;
}
@@ -101,7 +101,7 @@ public:
bool WriteDefaultKey(const CPubKey& vchPubKey)
{
nWalletDBUpdated++;
- return Write(std::string("defaultkey"), vchPubKey.Raw());
+ return Write(std::string("defaultkey"), vchPubKey);
}
bool ReadPool(int64 nPool, CKeyPool& keypool)