diff options
Diffstat (limited to 'src')
78 files changed, 793 insertions, 682 deletions
diff --git a/src/alert.h b/src/alert.h index 25e140f573..e4841f9c3f 100644 --- a/src/alert.h +++ b/src/alert.h @@ -1,5 +1,5 @@ // Copyright (c) 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. diff --git a/src/allocators.cpp b/src/allocators.cpp index b239b623d8..15f34aa2c8 100644 --- a/src/allocators.cpp +++ b/src/allocators.cpp @@ -24,6 +24,9 @@ #include <unistd.h> // for sysconf #endif +LockedPageManager* LockedPageManager::_instance = NULL; +boost::once_flag LockedPageManager::init_flag = BOOST_ONCE_INIT; + /** Determine system page size in bytes */ static inline size_t GetSystemPageSize() { diff --git a/src/allocators.h b/src/allocators.h index fd6f51b27e..a806780ad3 100644 --- a/src/allocators.h +++ b/src/allocators.h @@ -1,5 +1,5 @@ // 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_ALLOCATORS_H @@ -8,6 +8,7 @@ #include <string.h> #include <string> #include <boost/thread/mutex.hpp> +#include <boost/thread/once.hpp> #include <map> #include <openssl/crypto.h> // for OPENSSL_cleanse() @@ -34,6 +35,12 @@ public: page_mask = ~(page_size - 1); } + ~LockedPageManagerBase() + { + assert(this->GetLockedPageCount() == 0); + } + + // For all pages in affected range, increase lock count void LockRange(void *p, size_t size) { @@ -117,13 +124,39 @@ public: /** * Singleton class to keep track of locked (ie, non-swappable) memory pages, for use in * std::allocator templates. + * + * Some implementations of the STL allocate memory in some constructors (i.e., see + * MSVC's vector<T> implementation where it allocates 1 byte of memory in the allocator.) + * Due to the unpredictable order of static initializers, we have to make sure the + * LockedPageManager instance exists before any other STL-based objects that use + * secure_allocator are created. So instead of having LockedPageManager also be + * static-intialized, it is created on demand. */ class LockedPageManager: public LockedPageManagerBase<MemoryPageLocker> { public: - static LockedPageManager instance; // instantiated in util.cpp + static LockedPageManager& Instance() + { + boost::call_once(LockedPageManager::CreateInstance, LockedPageManager::init_flag); + return *LockedPageManager::_instance; + } + private: LockedPageManager(); + + static void CreateInstance() + { + // Using a local static instance guarantees that the object is initialized + // when it's first needed and also deinitialized after all objects that use + // it are done with it. I can think of one unlikely scenario where we may + // have a static deinitialization order/problem, but the check in + // LockedPageManagerBase's destructor helps us detect if that ever happens. + static LockedPageManager instance; + LockedPageManager::_instance = &instance; + } + + static LockedPageManager* _instance; + static boost::once_flag init_flag; }; // @@ -131,12 +164,12 @@ private: // Intended for non-dynamically allocated structures. // template<typename T> void LockObject(const T &t) { - LockedPageManager::instance.LockRange((void*)(&t), sizeof(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)); + LockedPageManager::Instance().UnlockRange((void*)(&t), sizeof(T)); } // @@ -168,7 +201,7 @@ struct secure_allocator : public std::allocator<T> T *p; p = std::allocator<T>::allocate(n, hint); if (p != NULL) - LockedPageManager::instance.LockRange(p, sizeof(T) * n); + LockedPageManager::Instance().LockRange(p, sizeof(T) * n); return p; } @@ -177,7 +210,7 @@ struct secure_allocator : public std::allocator<T> if (p != NULL) { OPENSSL_cleanse(p, sizeof(T) * n); - LockedPageManager::instance.UnlockRange(p, sizeof(T) * n); + LockedPageManager::Instance().UnlockRange(p, sizeof(T) * n); } std::allocator<T>::deallocate(p, n); } diff --git a/src/base58.h b/src/base58.h index aabae8de88..44bf5281e1 100644 --- a/src/base58.h +++ b/src/base58.h @@ -1,5 +1,5 @@ // 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. diff --git a/src/bignum.h b/src/bignum.h index 0881807d70..582e6f1517 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -1,5 +1,5 @@ // 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_BIGNUM_H diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index add3b4e1f0..1b40a868a1 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -1,5 +1,5 @@ // 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. diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 798660dff3..29935d8f6c 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -1,5 +1,5 @@ // Copyright (c) 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. diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 1cad12f14a..275369ddd2 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -1,5 +1,5 @@ // Copyright (c) 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. diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 0795f09765..82f41bcc50 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -1,5 +1,5 @@ // Copyright (c) 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. diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index bb551501f1..76ae911a5c 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -1,4 +1,4 @@ -// 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. diff --git a/src/checkpoints.h b/src/checkpoints.h index a49a908a38..4afd29326b 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -1,4 +1,4 @@ -// 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_CHECKPOINT_H diff --git a/src/compat.h b/src/compat.h index b126df901a..c910f01cb4 100644 --- a/src/compat.h +++ b/src/compat.h @@ -1,5 +1,5 @@ // 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_COMPAT_H diff --git a/src/core.h b/src/core.h index ce21acd59e..9ee8b2edce 100644 --- a/src/core.h +++ b/src/core.h @@ -661,4 +661,38 @@ public: void print() const; }; + +/** Describes a place in the block chain to another node such that if the + * other node doesn't have the same branch, it can find a recent common trunk. + * The further back it is, the further before the fork it may be. + */ +struct CBlockLocator +{ + std::vector<uint256> vHave; + + CBlockLocator() {} + + CBlockLocator(const std::vector<uint256>& vHaveIn) + { + vHave = vHaveIn; + } + + IMPLEMENT_SERIALIZE + ( + if (!(nType & SER_GETHASH)) + READWRITE(nVersion); + READWRITE(vHave); + ) + + void SetNull() + { + vHave.clear(); + } + + bool IsNull() + { + return vHave.empty(); + } +}; + #endif diff --git a/src/crypter.cpp b/src/crypter.cpp index 754de536a9..f3b9396dae 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -1,4 +1,4 @@ -// 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. diff --git a/src/crypter.h b/src/crypter.h index 4134c1b49b..22187791e9 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -1,4 +1,4 @@ -// 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 __CRYPTER_H__ @@ -88,16 +88,16 @@ public: // Try to keep the key data out of swap (and be a bit over-careful to keep the IV that we don't even use out of swap) // Note that this does nothing about suspend-to-disk (which will put all our key data on disk) // Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process. - LockedPageManager::instance.LockRange(&chKey[0], sizeof chKey); - LockedPageManager::instance.LockRange(&chIV[0], sizeof chIV); + LockedPageManager::Instance().LockRange(&chKey[0], sizeof chKey); + LockedPageManager::Instance().LockRange(&chIV[0], sizeof chIV); } ~CCrypter() { CleanKey(); - LockedPageManager::instance.UnlockRange(&chKey[0], sizeof chKey); - LockedPageManager::instance.UnlockRange(&chIV[0], sizeof chIV); + LockedPageManager::Instance().UnlockRange(&chKey[0], sizeof chKey); + LockedPageManager::Instance().UnlockRange(&chIV[0], sizeof chIV); } }; diff --git a/src/db.cpp b/src/db.cpp index f722c52e93..7e58ff45fb 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -1,5 +1,5 @@ // 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. @@ -1,5 +1,5 @@ // 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_DB_H @@ -16,7 +16,7 @@ #include <db_cxx.h> class CAddrMan; -class CBlockLocator; +struct CBlockLocator; class CDiskBlockIndex; class CMasterKey; class COutPoint; diff --git a/src/hash.h b/src/hash.h index 880468a2d2..ff7d57399a 100644 --- a/src/hash.h +++ b/src/hash.h @@ -1,5 +1,5 @@ // 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_HASH_H diff --git a/src/init.cpp b/src/init.cpp index dcd65198c3..2ac610b333 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,5 +1,5 @@ // 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. @@ -116,7 +116,7 @@ void Shutdown() { LOCK(cs_main); if (pwalletMain) - pwalletMain->SetBestChain(CBlockLocator(chainActive.Tip())); + pwalletMain->SetBestChain(chainActive.GetLocator()); if (pblocktree) pblocktree->Flush(); if (pcoinsTip) @@ -185,7 +185,7 @@ std::string HelpMessage() strUsage += " -timeout=<n> " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n"; strUsage += " -proxy=<ip:port> " + _("Connect through socks proxy") + "\n"; strUsage += " -socks=<n> " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n"; - strUsage += " -tor=<ip:port> " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n"; + strUsage += " -onion=<ip:port> " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n"; strUsage += " -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n"; strUsage += " -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n"; strUsage += " -maxconnections=<n> " + _("Maintain at most <n> connections to peers (default: 125)") + "\n"; @@ -642,15 +642,20 @@ bool AppInit2(boost::thread_group& threadGroup) fProxy = true; } - // -tor can override normal proxy, -notor disables tor entirely - if (!(mapArgs.count("-tor") && mapArgs["-tor"] == "0") && (fProxy || mapArgs.count("-tor"))) { + // -onion can override normal proxy, -noonion disables tor entirely + // -tor here is a temporary backwards compatibility measure + if (mapArgs.count("-tor")) + printf("Notice: option -tor has been replaced with -onion and will be removed in a later version.\n"); + if (!(mapArgs.count("-onion") && mapArgs["-onion"] == "0") && + !(mapArgs.count("-tor") && mapArgs["-tor"] == "0") && + (fProxy || mapArgs.count("-onion") || mapArgs.count("-tor"))) { CService addrOnion; - if (!mapArgs.count("-tor")) + if (!mapArgs.count("-onion") && !mapArgs.count("-tor")) addrOnion = addrProxy; else - addrOnion = CService(mapArgs["-tor"], 9050); + addrOnion = mapArgs.count("-onion")?CService(mapArgs["-onion"], 9050):CService(mapArgs["-tor"], 9050); if (!addrOnion.IsValid()) - return InitError(strprintf(_("Invalid -tor address: '%s'"), mapArgs["-tor"].c_str())); + return InitError(strprintf(_("Invalid -onion address: '%s'"), mapArgs.count("-onion")?mapArgs["-onion"].c_str():mapArgs["-tor"].c_str())); SetProxy(NET_TOR, addrOnion, 5); SetReachable(NET_TOR); } @@ -912,7 +917,7 @@ bool AppInit2(boost::thread_group& threadGroup) strErrors << _("Cannot write default address") << "\n"; } - pwalletMain->SetBestChain(CBlockLocator(chainActive.Tip())); + pwalletMain->SetBestChain(chainActive.GetLocator()); } LogPrintf("%s", strErrors.str().c_str()); @@ -928,7 +933,7 @@ bool AppInit2(boost::thread_group& threadGroup) CWalletDB walletdb(strWalletFile); CBlockLocator locator; if (walletdb.ReadBestBlock(locator)) - pindexRescan = locator.GetBlockIndex(); + pindexRescan = chainActive.FindFork(locator); else pindexRescan = chainActive.Genesis(); } @@ -939,7 +944,7 @@ bool AppInit2(boost::thread_group& threadGroup) nStart = GetTimeMillis(); pwalletMain->ScanForWalletTransactions(pindexRescan, true); LogPrintf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); - pwalletMain->SetBestChain(CBlockLocator(chainActive.Tip())); + pwalletMain->SetBestChain(chainActive.GetLocator()); nWalletDBUpdated++; } diff --git a/src/init.h b/src/init.h index a4d5a67252..e5a2a69293 100644 --- a/src/init.h +++ b/src/init.h @@ -1,5 +1,5 @@ // 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_INIT_H diff --git a/src/key.cpp b/src/key.cpp index 8ef1c414c4..996539dca5 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -1,4 +1,4 @@ -// 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. @@ -166,9 +166,12 @@ public: assert(nSize == nSize2); } - bool SetPrivKey(const CPrivKey &privkey) { + bool SetPrivKey(const CPrivKey &privkey, bool fSkipCheck=false) { const unsigned char* pbegin = &privkey[0]; if (d2i_ECPrivateKey(&pkey, &pbegin, privkey.size())) { + if(fSkipCheck) + return true; + // d2i_ECPrivateKey returns true if parsing succeeds. // This doesn't necessarily mean the key is valid. if (EC_KEY_check_key(pkey)) @@ -411,6 +414,24 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) return true; } +bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) { + CECKey key; + if (!key.SetPrivKey(privkey, fSkipCheck)) + return false; + + key.GetSecretBytes(vch); + fCompressed = vchPubKey.IsCompressed(); + fValid = true; + + if (fSkipCheck) + return true; + + if (GetPubKey() != vchPubKey) + return false; + + return true; +} + bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const { if (!IsValid()) return false; @@ -261,6 +261,9 @@ public: // Derive BIP32 child key. bool Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const; + + // Load private key and check that public key matches. + bool Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck); }; struct CExtPubKey { diff --git a/src/keystore.cpp b/src/keystore.cpp index 808f8c24ef..301180737f 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -1,5 +1,5 @@ // 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. diff --git a/src/keystore.h b/src/keystore.h index 49a7bf569d..4f28fba91b 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -1,5 +1,5 @@ // 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_KEYSTORE_H diff --git a/src/main.cpp b/src/main.cpp index f2e6b67f8a..a5a0f031af 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,5 @@ // 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. @@ -190,105 +190,61 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals) ////////////////////////////////////////////////////////////////////////////// // -// CBlockLocator implementation +// CChain implementation // -CBlockLocator::CBlockLocator(uint256 hashBlock) -{ - std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock); - if (mi != mapBlockIndex.end()) - Set((*mi).second); +CBlockIndex *CChain::SetTip(CBlockIndex *pindex) { + if (pindex == NULL) { + vChain.clear(); + return NULL; + } + vChain.resize(pindex->nHeight + 1); + while (pindex && vChain[pindex->nHeight] != pindex) { + vChain[pindex->nHeight] = pindex; + pindex = pindex->pprev; + } + return pindex; } -void CBlockLocator::Set(const CBlockIndex* pindex) -{ - vHave.clear(); +CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const { int nStep = 1; - while (pindex) - { - vHave.push_back(pindex->GetBlockHash()); + std::vector<uint256> vHave; + vHave.reserve(32); - // Exponentially larger steps back - for (int i = 0; pindex && i < nStep; i++) + if (!pindex) + pindex = Tip(); + while (pindex) { + vHave.push_back(pindex->GetBlockHash()); + // Stop when we have added the genesis block. + if (pindex->nHeight == 0) + break; + // Exponentially larger steps back, plus the genesis block. + int nHeight = std::max(pindex->nHeight - nStep, 0); + // In case pindex is not in this chain, iterate pindex->pprev to find blocks. + while (pindex->nHeight > nHeight && !Contains(pindex)) pindex = pindex->pprev; + // If pindex is in this chain, use direct height-based access. + if (pindex->nHeight > nHeight) + pindex = (*this)[nHeight]; if (vHave.size() > 10) nStep *= 2; } - vHave.push_back(Params().HashGenesisBlock()); -} -int CBlockLocator::GetDistanceBack() -{ - // Retrace how far back it was in the sender's branch - int nDistance = 0; - int nStep = 1; - BOOST_FOREACH(const uint256& hash, vHave) - { - std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) - { - CBlockIndex* pindex = (*mi).second; - if (chainActive.Contains(pindex)) - return nDistance; - } - nDistance += nStep; - if (nDistance > 10) - nStep *= 2; - } - return nDistance; + return CBlockLocator(vHave); } -CBlockIndex *CBlockLocator::GetBlockIndex() -{ +CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const { // Find the first block the caller has in the main chain - BOOST_FOREACH(const uint256& hash, vHave) - { + BOOST_FOREACH(const uint256& hash, locator.vHave) { std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { CBlockIndex* pindex = (*mi).second; - if (chainActive.Contains(pindex)) + if (Contains(pindex)) return pindex; } } - return chainActive.Genesis(); -} - -uint256 CBlockLocator::GetBlockHash() -{ - // Find the first block the caller has in the main chain - BOOST_FOREACH(const uint256& hash, vHave) - { - std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) - { - CBlockIndex* pindex = (*mi).second; - if (chainActive.Contains(pindex)) - return hash; - } - } - return Params().HashGenesisBlock(); -} - -int CBlockLocator::GetHeight() -{ - CBlockIndex* pindex = GetBlockIndex(); - if (!pindex) - return 0; - return pindex->nHeight; -} - -CBlockIndex *CChain::SetTip(CBlockIndex *pindex) { - if (pindex == NULL) { - std::vector<CBlockIndex*>().swap(vChain); - return NULL; - } - vChain.resize(pindex->nHeight + 1); - while (pindex && vChain[pindex->nHeight] != pindex) { - vChain[pindex->nHeight] = pindex; - pindex = pindex->pprev; - } - return pindex; + return Genesis(); } ////////////////////////////////////////////////////////////////////////////// @@ -766,15 +722,18 @@ int64 GetMinFee(const CTransaction& tx, bool fAllowFree, enum GetMinFee_mode mod { // There is a free transaction area in blocks created by most miners, // * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000 - // to be considered to fall into this category - // * If we are creating a transaction we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 17000 - // (= 10000) to be considered safe and assume they can likely make it into this section - if (nBytes < (mode == GMF_SEND ? (DEFAULT_BLOCK_PRIORITY_SIZE - 17000) : (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))) + // to be considered to fall into this category. We don't want to encourage sending + // multiple transactions instead of one big transaction to avoid fees. + // * If we are creating a transaction we allow transactions up to 1,000 bytes + // to be considered safe and assume they can likely make it into this section. + if (nBytes < (mode == GMF_SEND ? 1000 : (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))) nMinFee = 0; } - // To limit dust spam, require base fee if any output is less than 0.01 - if (nMinFee < nBaseFee) + // This code can be removed after enough miners have upgraded to version 0.9. + // Until then, be safe when sending and require a fee if any output + // is less than CENT: + if (nMinFee < nBaseFee && mode == GMF_SEND) { BOOST_FOREACH(const CTxOut& txout, tx.vout) if (txout.nValue < CENT) @@ -2156,10 +2115,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) // Update best block in wallet (so we can detect restored wallets) if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0)) - { - const CBlockLocator locator(pindexNew); - ::SetBestChain(locator); - } + ::SetBestChain(chainActive.GetLocator(pindexNew)); // New best block nTimeBestReceived = GetTime(); @@ -2525,7 +2481,7 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd) pnode->pindexLastGetBlocksBegin = pindexBegin; pnode->hashLastGetBlocksEnd = hashEnd; - pnode->PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); + pnode->PushMessage("getblocks", chainActive.GetLocator(pindexBegin), hashEnd); } bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp) @@ -3661,7 +3617,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) LOCK(cs_main); // Find the last block the caller has in the main chain - CBlockIndex* pindex = locator.GetBlockIndex(); + CBlockIndex* pindex = chainActive.FindFork(locator); // Send the rest of the chain if (pindex) @@ -3708,7 +3664,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) else { // Find the last block the caller has in the main chain - pindex = locator.GetBlockIndex(); + pindex = chainActive.FindFork(locator); if (pindex) pindex = chainActive.Next(pindex); } @@ -3731,7 +3687,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { vector<uint256> vWorkQueue; vector<uint256> vEraseQueue; - CDataStream vMsg(vRecv); CTransaction tx; vRecv >> tx; diff --git a/src/main.h b/src/main.h index 46d629044a..76de47071e 100644 --- a/src/main.h +++ b/src/main.h @@ -1,5 +1,5 @@ // 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_MAIN_H @@ -1033,6 +1033,12 @@ public: /** Set/initialize a chain with a given tip. Returns the forking point. */ CBlockIndex *SetTip(CBlockIndex *pindex); + + /** Return a CBlockLocator that refers to a block in this chain (by default the tip). */ + CBlockLocator GetLocator(const CBlockIndex *pindex = NULL) const; + + /** Find the last common block between this chain and a locator. */ + CBlockIndex *FindFork(const CBlockLocator &locator) const; }; /** The currently-connected chain of blocks. */ @@ -1040,59 +1046,6 @@ extern CChain chainActive; -/** Describes a place in the block chain to another node such that if the - * other node doesn't have the same branch, it can find a recent common trunk. - * The further back it is, the further before the fork it may be. - */ -class CBlockLocator -{ -protected: - std::vector<uint256> vHave; -public: - CBlockLocator() {} - - explicit CBlockLocator(const CBlockIndex* pindex) - { - Set(pindex); - } - - explicit CBlockLocator(uint256 hashBlock); - - CBlockLocator(const std::vector<uint256>& vHaveIn) - { - vHave = vHaveIn; - } - - IMPLEMENT_SERIALIZE - ( - if (!(nType & SER_GETHASH)) - READWRITE(nVersion); - READWRITE(vHave); - ) - - void SetNull() - { - vHave.clear(); - } - - bool IsNull() - { - return vHave.empty(); - } - - /** Given a block initialises the locator to that point in the chain. */ - void Set(const CBlockIndex* pindex); - /** Returns the distance in blocks this locator is from our chain head. */ - int GetDistanceBack(); - /** Returns the first best-chain block the locator contains. */ - CBlockIndex* GetBlockIndex(); - /** Returns the hash of the first best chain block the locator contains. */ - uint256 GetBlockHash(); - /** Returns the height of the first best chain block the locator has. */ - int GetHeight(); -}; - - diff --git a/src/miner.cpp b/src/miner.cpp index e9c1d9aff9..dca8609e17 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1,5 +1,5 @@ // 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. @@ -238,9 +238,21 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) } if (fMissingInputs) continue; - // Priority is sum(valuein * age) / txsize + // Priority is sum(valuein * age) / modified_txsize unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); - dPriority /= nTxSize; + unsigned int nTxSizeMod = nTxSize; + // In order to avoid disincentivizing cleaning up the UTXO set we don't count + // the constant overhead for each txin and up to 110 bytes of scriptSig (which + // is enough to cover a compressed pubkey p2sh redemption) for priority. + // Providing any more cleanup incentive than making additional inputs free would + // risk encouraging people to create junk outputs to redeem later. + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + unsigned int offset = 41U + min(110U, (unsigned int)txin.scriptSig.size()); + if (nTxSizeMod > offset) + nTxSizeMod -= offset; + } + dPriority /= nTxSizeMod; // This is a more accurate fee-per-kilobyte than is used by the client code, because the // client code rounds up the size to the nearest 1K. That's good, because it gives an diff --git a/src/miner.h b/src/miner.h index 7e60b9e53b..a2800341d8 100644 --- a/src/miner.h +++ b/src/miner.h @@ -1,5 +1,5 @@ // 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_MINER_H diff --git a/src/net.cpp b/src/net.cpp index e8baa8b383..dd7bf283a9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1,5 +1,5 @@ // 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. @@ -1,5 +1,5 @@ // 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_NET_H diff --git a/src/netbase.cpp b/src/netbase.cpp index 360ecdd959..36b90e0d4c 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -1,5 +1,5 @@ // 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. diff --git a/src/netbase.h b/src/netbase.h index e1f80b4ee8..c14fa5075d 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -1,4 +1,4 @@ -// 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_NETBASE_H diff --git a/src/noui.cpp b/src/noui.cpp index 67eac944c6..06c507d0e5 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -1,5 +1,5 @@ // Copyright (c) 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. diff --git a/src/protocol.cpp b/src/protocol.cpp index ba254be3e1..a841bbc14e 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -1,5 +1,5 @@ // 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. diff --git a/src/protocol.h b/src/protocol.h index ae541dfdba..3d8eae55f9 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -1,5 +1,5 @@ // 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. diff --git a/src/qt/Makefile.am b/src/qt/Makefile.am index e7ae0a905f..5892f6aca0 100644 --- a/src/qt/Makefile.am +++ b/src/qt/Makefile.am @@ -51,7 +51,7 @@ QT_MOC_CPP = moc_aboutdialog.cpp moc_addressbookpage.cpp \ moc_signverifymessagedialog.cpp moc_splashscreen.cpp moc_trafficgraphwidget.cpp moc_transactiondesc.cpp \ moc_transactiondescdialog.cpp moc_transactionfilterproxy.cpp \ moc_transactiontablemodel.cpp moc_transactionview.cpp moc_walletframe.cpp \ - moc_walletmodel.cpp moc_walletstack.cpp moc_walletview.cpp + moc_walletmodel.cpp moc_walletview.cpp BITCOIN_MM = macdockiconhandler.mm macnotificationhandler.mm QR_CPP = qrcodedialog.cpp @@ -75,7 +75,7 @@ BITCOIN_QT_H = aboutdialog.h addressbookpage.h addresstablemodel.h \ sendcoinsdialog.h sendcoinsentry.h signverifymessagedialog.h splashscreen.h \ trafficgraphwidget.h transactiondescdialog.h transactiondesc.h transactionfilterproxy.h \ transactionrecord.h transactiontablemodel.h transactionview.h walletframe.h \ - walletmodel.h walletmodeltransaction.h walletstack.h walletview.h + walletmodel.h walletmodeltransaction.h walletview.h RES_ICONS = res/icons/bitcoin.png res/icons/address-book.png \ res/icons/quit.png res/icons/send.png res/icons/toolbar.png \ @@ -105,7 +105,7 @@ BITCOIN_QT_CPP = aboutdialog.cpp addressbookpage.cpp \ signverifymessagedialog.cpp splashscreen.cpp trafficgraphwidget.cpp transactiondesc.cpp \ transactiondescdialog.cpp transactionfilterproxy.cpp transactionrecord.cpp \ transactiontablemodel.cpp transactionview.cpp walletframe.cpp \ - walletmodel.cpp walletmodeltransaction.cpp walletstack.cpp walletview.cpp + walletmodel.cpp walletmodeltransaction.cpp walletview.cpp RES_IMAGES = res/images/about.png res/images/splash.png \ res/images/splash_testnet.png diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 78693971da..e73a82978a 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -333,8 +333,8 @@ int main(int argc, char *argv[]) paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray))); QObject::connect(paymentServer, SIGNAL(receivedPaymentACK(QString)), &window, SLOT(showPaymentACK(QString))); - QObject::connect(paymentServer, SIGNAL(reportError(QString, QString, unsigned int)), - guiref, SLOT(message(QString, QString, unsigned int))); + QObject::connect(paymentServer, SIGNAL(message(QString,QString,unsigned int)), + guiref, SLOT(message(QString,QString,unsigned int))); QTimer::singleShot(100, paymentServer, SLOT(uiReady())); app.exec(); diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index d9d4e3b23d..37b8743eff 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -130,9 +130,10 @@ void BitcoinAmountField::setValue(qint64 value) setText(BitcoinUnits::format(currentUnit, value)); } -void BitcoinAmountField::setReadOnly(bool fReadeOnly) +void BitcoinAmountField::setReadOnly(bool fReadOnly) { - // TODO ... + amount->setReadOnly(fReadOnly); + unit->setEnabled(!fReadOnly); } void BitcoinAmountField::unitChanged(int idx) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 23a221120f..3336a8afd3 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -447,26 +447,31 @@ void BitcoinGUI::aboutClicked() void BitcoinGUI::gotoOverviewPage() { + overviewAction->setChecked(true); if (walletFrame) walletFrame->gotoOverviewPage(); } void BitcoinGUI::gotoHistoryPage() { + historyAction->setChecked(true); if (walletFrame) walletFrame->gotoHistoryPage(); } void BitcoinGUI::gotoAddressBookPage() { + addressBookAction->setChecked(true); if (walletFrame) walletFrame->gotoAddressBookPage(); } void BitcoinGUI::gotoReceiveCoinsPage() { + receiveCoinsAction->setChecked(true); if (walletFrame) walletFrame->gotoReceiveCoinsPage(); } void BitcoinGUI::gotoSendCoinsPage(QString addr) { + sendCoinsAction->setChecked(true); if (walletFrame) walletFrame->gotoSendCoinsPage(addr); } diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index e2dd5dc6bc..e5a92fed93 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -61,14 +61,6 @@ public: void removeAllWallets(); - /** Used by WalletView to allow access to needed QActions */ - // Todo: Use Qt signals for these - QAction * getOverviewAction() { return overviewAction; } - QAction * getHistoryAction() { return historyAction; } - QAction * getAddressBookAction() { return addressBookAction; } - QAction * getReceiveCoinsAction() { return receiveCoinsAction; } - QAction * getSendCoinsAction() { return sendCoinsAction; } - protected: void changeEvent(QEvent *e); void closeEvent(QCloseEvent *event); diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 2bab488135..212fa6974a 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -65,10 +65,8 @@ QDateTime ClientModel::getLastBlockDate() const { if (chainActive.Tip()) return QDateTime::fromTime_t(chainActive.Tip()->GetBlockTime()); - else if(!isTestNet()) - return QDateTime::fromTime_t(1231006505); // Genesis block's time else - return QDateTime::fromTime_t(1296688602); // Genesis block's time (testnet) + return QDateTime::fromTime_t(Params().GenesisBlock().nTime); // Genesis block's time of current network } double ClientModel::getVerificationProgress() const diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui index 2c1cec600c..5c6afd6c71 100644 --- a/src/qt/forms/sendcoinsentry.ui +++ b/src/qt/forms/sendcoinsentry.ui @@ -621,7 +621,7 @@ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> <property name="buddy"> - <cstring>payAmount</cstring> + <cstring>payAmount_s</cstring> </property> </widget> </item> @@ -640,15 +640,9 @@ </item> <item row="5" column="2"> <widget class="BitcoinAmountField" name="payAmount_s"> - <property name="enabled"> - <bool>false</bool> - </property> <property name="acceptDrops"> <bool>false</bool> </property> - <property name="readOnly"> - <bool>true</bool> - </property> </widget> </item> <item row="3" column="2"> diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 96ba997943..af75d6b4e5 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -1,4 +1,4 @@ -// 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. @@ -189,7 +189,7 @@ bool PaymentServer::ipcSendCommandLine(int argc, char* argv[]) if (arg.startsWith("-")) continue; - if (arg.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // bitcoin: + if (arg.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // bitcoin: URI { savedPaymentRequests.append(arg); @@ -220,9 +220,9 @@ bool PaymentServer::ipcSendCommandLine(int argc, char* argv[]) } else { - qDebug() << "PaymentServer::ipcSendCommandLine : Payment request file does not exist: " << argv[i]; // Printing to debug.log is about the best we can do here, the // GUI hasn't started yet so we can't pop up a message box. + qDebug() << "PaymentServer::ipcSendCommandLine : Payment request file does not exist: " << arg; } } @@ -246,6 +246,7 @@ bool PaymentServer::ipcSendCommandLine(int argc, char* argv[]) delete socket; fResult = true; } + return fResult; } @@ -255,7 +256,9 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : QObject(p // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; - // Install global event filter to catch QFileOpenEvents on the mac (sent when you click bitcoin: links) + // Install global event filter to catch QFileOpenEvents + // on Mac: sent when you click bitcoin: links + // other OSes: helpful when dealing with payment-request files (in the future) if (parent) parent->installEventFilter(this); @@ -310,7 +313,7 @@ void PaymentServer::initNetManager() if (netManager != NULL) delete netManager; - // netManager is used to fetch paymentrequests given in bitcoin: URI's + // netManager is used to fetch paymentrequests given in bitcoin: URIs netManager = new QNetworkAccessManager(this); // Use proxy settings from optionsModel: @@ -360,7 +363,8 @@ void PaymentServer::handleURIOrFile(const QString& s) #endif if (uri.hasQueryItem("request")) { - QByteArray temp; temp.append(uri.queryItemValue("request")); + QByteArray temp; + temp.append(uri.queryItemValue("request")); QString decoded = QUrl::fromPercentEncoding(temp); QUrl fetchUrl(decoded, QUrl::StrictMode); @@ -370,13 +374,17 @@ void PaymentServer::handleURIOrFile(const QString& s) if (fetchUrl.isValid()) fetchRequest(fetchUrl); else - qDebug() << "PaymentServer::handleURIOrFile : Invalid url: " << fetchUrl; + qDebug() << "PaymentServer::handleURIOrFile : Invalid URL: " << fetchUrl; return; } SendCoinsRecipient recipient; if (GUIUtil::parseBitcoinURI(s, &recipient)) emit receivedPaymentRequest(recipient); + else + emit message(tr("URI handling"), + tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."), + CClientUIInterface::ICON_WARNING); return; } @@ -408,10 +416,10 @@ void PaymentServer::handleURIConnection() if (clientConnection->bytesAvailable() < (int)sizeof(quint16)) { return; } - QString message; - in >> message; + QString msg; + in >> msg; - handleURIOrFile(message); + handleURIOrFile(msg); } bool PaymentServer::readPaymentRequest(const QString& filename, PaymentRequestPlus& request) @@ -444,11 +452,11 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, QList<Sen foreach(const PAIRTYPE(CScript, qint64)& sendingTo, sendingTos) { CTxOut txOut(sendingTo.second, sendingTo.first); if (txOut.IsDust(CTransaction::nMinRelayTxFee)) { - QString message = QObject::tr("Requested payment amount (%1) too small") + QString msg = QObject::tr("Requested payment amount (%1) too small") .arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)); - qDebug() << "PaymentServer::processPaymentRequest : " << message; - emit reportError(tr("Payment request error"), message, CClientUIInterface::MODAL); + qDebug() << "PaymentServer::processPaymentRequest : " << msg; + emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR); return false; } @@ -485,9 +493,9 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, QList<Sen // Insecure payments to custom bitcoin addresses are not supported // (there is no good way to tell the user where they are paying in a way // they'd have a chance of understanding). - emit reportError(tr("Payment request error"), - tr("Insecure requests to custom payment scripts unsupported"), - CClientUIInterface::MODAL); + emit message(tr("Payment request error"), + tr("Insecure requests to custom payment scripts unsupported"), + CClientUIInterface::MSG_ERROR); return false; } } @@ -566,11 +574,11 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { - QString message = QObject::tr("Error communicating with %1: %2") + QString msg = QObject::tr("Error communicating with %1: %2") .arg(reply->request().url().toString()) .arg(reply->errorString()); - qDebug() << "PaymentServer::netRequestFinished : " << message; - emit reportError(tr("Network request error"), message, CClientUIInterface::MODAL); + qDebug() << "PaymentServer::netRequestFinished : " << msg; + emit message(tr("Network request error"), msg, CClientUIInterface::MSG_ERROR); return; } @@ -595,10 +603,10 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) payments::PaymentACK paymentACK; if (!paymentACK.ParseFromArray(data.data(), data.size())) { - QString message = QObject::tr("Bad response from server %1") + QString msg = QObject::tr("Bad response from server %1") .arg(reply->request().url().toString()); - qDebug() << "PaymentServer::netRequestFinished : " << message; - emit reportError(tr("Network request error"), message, CClientUIInterface::MODAL); + qDebug() << "PaymentServer::netRequestFinished : " << msg; + emit message(tr("Network request error"), msg, CClientUIInterface::MSG_ERROR); } else { emit receivedPaymentACK(QString::fromStdString(paymentACK.memo())); @@ -615,7 +623,7 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError> qDebug() << "PaymentServer::reportSslErrors : " << err; errString += err.errorString() + "\n"; } - emit reportError(tr("Network request error"), errString, CClientUIInterface::MODAL); + emit message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR); } void PaymentServer::setOptionsModel(OptionsModel *optionsModel) diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index f9d827204b..042c41ef64 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -90,8 +90,8 @@ signals: // Fired when a valid PaymentACK is received void receivedPaymentACK(QString); - // Fired when an error should be reported to the user - void reportError(QString, QString, unsigned int); + // Fired when a message should be reported to the user + void message(const QString &title, const QString &message, unsigned int style); public slots: // Signal this when the main window's UI is ready diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 59724c94f4..188b8860a9 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -60,12 +60,7 @@ void SendCoinsEntry::on_addressBookButton_clicked() void SendCoinsEntry::on_payTo_textChanged(const QString &address) { - if(!model) - return; - // Fill in label from address book, if address has an associated label - QString associatedLabel = model->getAddressTableModel()->labelForAddress(address); - if(!associatedLabel.isEmpty()) - ui->addAsLabel->setText(associatedLabel); + updateLabel(address); } void SendCoinsEntry::setModel(WalletModel *model) @@ -174,6 +169,7 @@ void SendCoinsEntry::setValue(const SendCoinsRecipient &value) ui->payTo_s->setText(recipient.authenticatedMerchant); ui->memoTextLabel_s->setText(QString::fromStdString(details.memo())); ui->payAmount_s->setValue(recipient.amount); + ui->payAmount_s->setReadOnly(true); setCurrentWidget(ui->SendCoinsSecure); } } @@ -203,3 +199,19 @@ void SendCoinsEntry::updateDisplayUnit() ui->payAmount_s->setDisplayUnit(model->getOptionsModel()->getDisplayUnit()); } } + +bool SendCoinsEntry::updateLabel(const QString &address) +{ + if(!model) + return false; + + // Fill in label from address book, if address has an associated label + QString associatedLabel = model->getAddressTableModel()->labelForAddress(address); + if(!associatedLabel.isEmpty()) + { + ui->addAsLabel->setText(associatedLabel); + return true; + } + + return false; +} diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h index 49e622daf1..66d9752909 100644 --- a/src/qt/sendcoinsentry.h +++ b/src/qt/sendcoinsentry.h @@ -58,6 +58,8 @@ private: SendCoinsRecipient recipient; Ui::SendCoinsEntry *ui; WalletModel *model; + + bool updateLabel(const QString &address); }; #endif // SENDCOINSENTRY_H diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 8d6a1b387e..f754bd5e71 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -5,20 +5,21 @@ * The Bitcoin Developers 2011-2013 */ #include "walletframe.h" +#include "walletview.h" #include "bitcoingui.h" -#include "walletstack.h" #include <QHBoxLayout> #include <QMessageBox> +#include <QStackedWidget> WalletFrame::WalletFrame(BitcoinGUI *_gui) : - QFrame(_gui) + QFrame(_gui), + gui(_gui) { // Leave HBox hook for adding a list view later QHBoxLayout *walletFrameLayout = new QHBoxLayout(this); setContentsMargins(0,0,0,0); - walletStack = new WalletStack(this); - walletStack->setBitcoinGUI(_gui); + walletStack = new QStackedWidget(this); walletFrameLayout->setContentsMargins(0,0,0,0); walletFrameLayout->addWidget(walletStack); } @@ -29,95 +30,157 @@ WalletFrame::~WalletFrame() void WalletFrame::setClientModel(ClientModel *clientModel) { - if (clientModel) - walletStack->setClientModel(clientModel); + this->clientModel = clientModel; } bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel) { - return walletStack->addWallet(name, walletModel); + if (!gui || !clientModel || !walletModel || mapWalletViews.count(name) > 0) + return false; + + WalletView *walletView = new WalletView(this); + walletView->setBitcoinGUI(gui); + walletView->setClientModel(clientModel); + walletView->setWalletModel(walletModel); + walletView->showOutOfSyncWarning(bOutOfSync); + + /* TODO we should goto the currently selected page once dynamically adding wallets is supported */ + walletView->gotoOverviewPage(); + walletStack->addWidget(walletView); + mapWalletViews[name] = walletView; + + // Ensure a walletView is able to show the main window + connect(walletView, SIGNAL(showNormalIfMinimized()), gui, SLOT(showNormalIfMinimized())); + + return true; } bool WalletFrame::setCurrentWallet(const QString& name) { - // TODO: Check if valid name - return walletStack->setCurrentWallet(name); + if (mapWalletViews.count(name) == 0) + return false; + + WalletView *walletView = mapWalletViews.value(name); + walletStack->setCurrentWidget(walletView); + walletView->setEncryptionStatus(); + return true; +} + +bool WalletFrame::removeWallet(const QString &name) +{ + if (mapWalletViews.count(name) == 0) + return false; + + WalletView *walletView = mapWalletViews.take(name); + walletStack->removeWidget(walletView); + return true; } void WalletFrame::removeAllWallets() { - walletStack->removeAllWallets(); + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + walletStack->removeWidget(i.value()); + mapWalletViews.clear(); } bool WalletFrame::handlePaymentRequest(const SendCoinsRecipient &recipient) { - return walletStack->handlePaymentRequest(recipient); + WalletView *walletView = (WalletView*)walletStack->currentWidget(); + if (!walletView) + return false; + + return walletView->handlePaymentRequest(recipient); } void WalletFrame::showOutOfSyncWarning(bool fShow) { - if (!walletStack) - return; - - walletStack->showOutOfSyncWarning(fShow); + bOutOfSync = fShow; + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->showOutOfSyncWarning(fShow); } void WalletFrame::gotoOverviewPage() { - walletStack->gotoOverviewPage(); + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoOverviewPage(); } void WalletFrame::gotoHistoryPage() { - walletStack->gotoHistoryPage(); + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoHistoryPage(); } void WalletFrame::gotoAddressBookPage() { - walletStack->gotoAddressBookPage(); + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoAddressBookPage(); } void WalletFrame::gotoReceiveCoinsPage() { - walletStack->gotoReceiveCoinsPage(); + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoReceiveCoinsPage(); } void WalletFrame::gotoSendCoinsPage(QString addr) { - walletStack->gotoSendCoinsPage(addr); + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoSendCoinsPage(addr); } void WalletFrame::gotoSignMessageTab(QString addr) { - walletStack->gotoSignMessageTab(addr); + WalletView *walletView = (WalletView*)walletStack->currentWidget(); + if (walletView) + walletView->gotoSignMessageTab(addr); } void WalletFrame::gotoVerifyMessageTab(QString addr) { - walletStack->gotoSignMessageTab(addr); + WalletView *walletView = (WalletView*)walletStack->currentWidget(); + if (walletView) + walletView->gotoVerifyMessageTab(addr); } void WalletFrame::encryptWallet(bool status) { - walletStack->encryptWallet(status); + WalletView *walletView = (WalletView*)walletStack->currentWidget(); + if (walletView) + walletView->encryptWallet(status); } void WalletFrame::backupWallet() { - walletStack->backupWallet(); + WalletView *walletView = (WalletView*)walletStack->currentWidget(); + if (walletView) + walletView->backupWallet(); } void WalletFrame::changePassphrase() { - walletStack->changePassphrase(); + WalletView *walletView = (WalletView*)walletStack->currentWidget(); + if (walletView) + walletView->changePassphrase(); } void WalletFrame::unlockWallet() { - walletStack->unlockWallet(); + WalletView *walletView = (WalletView*)walletStack->currentWidget(); + if (walletView) + walletView->unlockWallet(); } void WalletFrame::setEncryptionStatus() { - walletStack->setEncryptionStatus(); + WalletView *walletView = (WalletView*)walletStack->currentWidget(); + if (walletView) + walletView->setEncryptionStatus(); } diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index eaae053ccd..5011987963 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -8,12 +8,17 @@ #define WALLETFRAME_H #include <QFrame> +#include <QMap> class BitcoinGUI; class ClientModel; class SendCoinsRecipient; class WalletModel; -class WalletStack; +class WalletView; + +QT_BEGIN_NAMESPACE +class QStackedWidget; +QT_END_NAMESPACE class WalletFrame : public QFrame { @@ -27,7 +32,7 @@ public: bool addWallet(const QString& name, WalletModel *walletModel); bool setCurrentWallet(const QString& name); - + bool removeWallet(const QString &name); void removeAllWallets(); bool handlePaymentRequest(const SendCoinsRecipient& recipient); @@ -35,7 +40,12 @@ public: void showOutOfSyncWarning(bool fShow); private: - WalletStack *walletStack; + QStackedWidget *walletStack; + BitcoinGUI *gui; + ClientModel *clientModel; + QMap<QString, WalletView*> mapWalletViews; + + bool bOutOfSync; public slots: /** Switch to overview (home) page */ diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 099fbe8dc3..417bac9928 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -258,22 +258,26 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran // and emit coinsSent signal for each recipient foreach(const SendCoinsRecipient &rcp, transaction.getRecipients()) { - std::string strAddress = rcp.address.toStdString(); - CTxDestination dest = CBitcoinAddress(strAddress).Get(); - std::string strLabel = rcp.label.toStdString(); + // Don't touch the address book when we have a secure payment-request + if (rcp.authenticatedMerchant.isEmpty()) { - LOCK(wallet->cs_wallet); - - std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(dest); - - // Check if we have a new address or an updated label - if (mi == wallet->mapAddressBook.end()) - { - wallet->SetAddressBook(dest, strLabel, "send"); - } - else if (mi->second.name != strLabel) + std::string strAddress = rcp.address.toStdString(); + CTxDestination dest = CBitcoinAddress(strAddress).Get(); + std::string strLabel = rcp.label.toStdString(); { - wallet->SetAddressBook(dest, strLabel, ""); // "" means don't change purpose + LOCK(wallet->cs_wallet); + + std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(dest); + + // Check if we have a new address or an updated label + if (mi == wallet->mapAddressBook.end()) + { + wallet->SetAddressBook(dest, strLabel, "send"); + } + else if (mi->second.name != strLabel) + { + wallet->SetAddressBook(dest, strLabel, ""); // "" means don't change purpose + } } } emit coinsSent(wallet, rcp, transaction_array); diff --git a/src/qt/walletstack.cpp b/src/qt/walletstack.cpp deleted file mode 100644 index 4ef87aed52..0000000000 --- a/src/qt/walletstack.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Qt4 bitcoin GUI. - * - * W.J. van der Laan 2011-2012 - * The Bitcoin Developers 2011-2013 - */ -#include "walletstack.h" -#include "walletview.h" -#include "bitcoingui.h" - -#include <QMap> -#include <QMessageBox> - -WalletStack::WalletStack(QWidget *parent) : - QStackedWidget(parent), - gui(0), - clientModel(0), - bOutOfSync(true) -{ - setContentsMargins(0,0,0,0); -} - -WalletStack::~WalletStack() -{ -} - -bool WalletStack::addWallet(const QString& name, WalletModel *walletModel) -{ - if (!gui || !clientModel || !walletModel || mapWalletViews.count(name) > 0) - return false; - - WalletView *walletView = new WalletView(this, gui); - walletView->setBitcoinGUI(gui); - walletView->setClientModel(clientModel); - walletView->setWalletModel(walletModel); - walletView->showOutOfSyncWarning(bOutOfSync); - addWidget(walletView); - mapWalletViews[name] = walletView; - - // Ensure a walletView is able to show the main window - connect(walletView, SIGNAL(showNormalIfMinimized()), gui, SLOT(showNormalIfMinimized())); - - return true; -} - -bool WalletStack::removeWallet(const QString& name) -{ - if (mapWalletViews.count(name) == 0) - return false; - - WalletView *walletView = mapWalletViews.take(name); - removeWidget(walletView); - return true; -} - -void WalletStack::removeAllWallets() -{ - QMap<QString, WalletView*>::const_iterator i; - for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) - removeWidget(i.value()); - mapWalletViews.clear(); -} - -bool WalletStack::handlePaymentRequest(const SendCoinsRecipient &recipient) -{ - WalletView *walletView = (WalletView*)currentWidget(); - if (!walletView) - return false; - - return walletView->handlePaymentRequest(recipient); -} - -void WalletStack::showOutOfSyncWarning(bool fShow) -{ - bOutOfSync = fShow; - QMap<QString, WalletView*>::const_iterator i; - for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) - i.value()->showOutOfSyncWarning(fShow); -} - -void WalletStack::gotoOverviewPage() -{ - QMap<QString, WalletView*>::const_iterator i; - for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) - i.value()->gotoOverviewPage(); -} - -void WalletStack::gotoHistoryPage() -{ - QMap<QString, WalletView*>::const_iterator i; - for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) - i.value()->gotoHistoryPage(); -} - -void WalletStack::gotoAddressBookPage() -{ - QMap<QString, WalletView*>::const_iterator i; - for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) - i.value()->gotoAddressBookPage(); -} - -void WalletStack::gotoReceiveCoinsPage() -{ - QMap<QString, WalletView*>::const_iterator i; - for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) - i.value()->gotoReceiveCoinsPage(); -} - -void WalletStack::gotoSendCoinsPage(QString addr) -{ - QMap<QString, WalletView*>::const_iterator i; - for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) - i.value()->gotoSendCoinsPage(addr); -} - -void WalletStack::gotoSignMessageTab(QString addr) -{ - WalletView *walletView = (WalletView*)currentWidget(); - if (walletView) - walletView->gotoSignMessageTab(addr); -} - -void WalletStack::gotoVerifyMessageTab(QString addr) -{ - WalletView *walletView = (WalletView*)currentWidget(); - if (walletView) - walletView->gotoVerifyMessageTab(addr); -} - -void WalletStack::encryptWallet(bool status) -{ - WalletView *walletView = (WalletView*)currentWidget(); - if (walletView) - walletView->encryptWallet(status); -} - -void WalletStack::backupWallet() -{ - WalletView *walletView = (WalletView*)currentWidget(); - if (walletView) - walletView->backupWallet(); -} - -void WalletStack::changePassphrase() -{ - WalletView *walletView = (WalletView*)currentWidget(); - if (walletView) - walletView->changePassphrase(); -} - -void WalletStack::unlockWallet() -{ - WalletView *walletView = (WalletView*)currentWidget(); - if (walletView) - walletView->unlockWallet(); -} - -void WalletStack::setEncryptionStatus() -{ - WalletView *walletView = (WalletView*)currentWidget(); - if (walletView) - walletView->setEncryptionStatus(); -} - -bool WalletStack::setCurrentWallet(const QString& name) -{ - if (mapWalletViews.count(name) == 0) - return false; - - WalletView *walletView = mapWalletViews.value(name); - setCurrentWidget(walletView); - walletView->setEncryptionStatus(); - return true; -} diff --git a/src/qt/walletstack.h b/src/qt/walletstack.h deleted file mode 100644 index 74b9f09081..0000000000 --- a/src/qt/walletstack.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Qt4 bitcoin GUI. - * - * W.J. van der Laan 2011-2012 - * The Bitcoin Developers 2011-2013 - */ -#ifndef WALLETSTACK_H -#define WALLETSTACK_H - -#include <QStackedWidget> -#include <QMap> -#include <boost/shared_ptr.hpp> - -class BitcoinGUI; -class TransactionTableModel; -class ClientModel; -class WalletModel; -class WalletView; -class TransactionView; -class OverviewPage; -class AddressBookPage; -class SendCoinsDialog; -class SendCoinsRecipient; -class SignVerifyMessageDialog; -class Notificator; -class RPCConsole; - -class CWalletManager; - -QT_BEGIN_NAMESPACE -class QLabel; -class QModelIndex; -QT_END_NAMESPACE - -/* - WalletStack class. This class is a container for WalletView instances. It takes the place of centralWidget. - It was added to support multiple wallet functionality. It communicates with both the client and the - wallet models to give the user an up-to-date view of the current core state. It manages all the wallet views - it contains and updates them accordingly. - */ -class WalletStack : public QStackedWidget -{ - Q_OBJECT - -public: - explicit WalletStack(QWidget *parent = 0); - ~WalletStack(); - - void setBitcoinGUI(BitcoinGUI *gui) { this->gui = gui; } - - void setClientModel(ClientModel *clientModel) { this->clientModel = clientModel; } - - bool addWallet(const QString& name, WalletModel *walletModel); - bool removeWallet(const QString& name); - - void removeAllWallets(); - - bool handlePaymentRequest(const SendCoinsRecipient &recipient); - - void showOutOfSyncWarning(bool fShow); - -private: - BitcoinGUI *gui; - ClientModel *clientModel; - QMap<QString, WalletView*> mapWalletViews; - - bool bOutOfSync; - -public slots: - bool setCurrentWallet(const QString& name); - - /** Switch to overview (home) page */ - void gotoOverviewPage(); - /** Switch to history (transactions) page */ - void gotoHistoryPage(); - /** Switch to address book page */ - void gotoAddressBookPage(); - /** Switch to receive coins page */ - void gotoReceiveCoinsPage(); - /** Switch to send coins page */ - void gotoSendCoinsPage(QString addr = ""); - - /** Show Sign/Verify Message dialog and switch to sign message tab */ - void gotoSignMessageTab(QString addr = ""); - /** Show Sign/Verify Message dialog and switch to verify message tab */ - void gotoVerifyMessageTab(QString addr = ""); - - /** Encrypt the wallet */ - void encryptWallet(bool status); - /** Backup the wallet */ - void backupWallet(); - /** Change encrypted wallet passphrase */ - void changePassphrase(); - /** Ask for passphrase to unlock wallet temporarily */ - void unlockWallet(); - - /** Set the encryption status as shown in the UI. - @param[in] status current encryption status - @see WalletModel::EncryptionStatus - */ - void setEncryptionStatus(); -}; - -#endif // WALLETSTACK_H diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index efb74efaa0..d7cef971ed 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -29,9 +29,9 @@ #include <QFileDialog> #include <QPushButton> -WalletView::WalletView(QWidget *parent, BitcoinGUI *_gui): +WalletView::WalletView(QWidget *parent): QStackedWidget(parent), - gui(_gui), + gui(0), clientModel(0), walletModel(0) { @@ -54,12 +54,8 @@ WalletView::WalletView(QWidget *parent, BitcoinGUI *_gui): transactionsPage->setLayout(vbox); addressBookPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab); - receiveCoinsPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab); - - sendCoinsPage = new SendCoinsDialog(gui); - - signVerifyMessageDialog = new SignVerifyMessageDialog(gui); + sendCoinsPage = new SendCoinsDialog(); addWidget(overviewPage); addWidget(transactionsPage); @@ -68,7 +64,6 @@ WalletView::WalletView(QWidget *parent, BitcoinGUI *_gui): addWidget(sendCoinsPage); // Clicking on a transaction on the overview page simply sends you to transaction history page - connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), this, SLOT(gotoHistoryPage())); connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex))); // Double-clicking on a transaction on the transaction history page shows details @@ -82,8 +77,6 @@ WalletView::WalletView(QWidget *parent, BitcoinGUI *_gui): connect(receiveCoinsPage, SIGNAL(signMessage(QString)), this, SLOT(gotoSignMessageTab(QString))); // Clicking on "Export" allows to export the transaction list connect(exportButton, SIGNAL(clicked()), transactionView, SLOT(exportClicked())); - - gotoOverviewPage(); } WalletView::~WalletView() @@ -93,6 +86,10 @@ WalletView::~WalletView() void WalletView::setBitcoinGUI(BitcoinGUI *gui) { this->gui = gui; + if(gui) + { + connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), gui, SLOT(gotoHistoryPage())); + } } void WalletView::setClientModel(ClientModel *clientModel) @@ -109,7 +106,7 @@ void WalletView::setClientModel(ClientModel *clientModel) void WalletView::setWalletModel(WalletModel *walletModel) { this->walletModel = walletModel; - if (walletModel) + if (walletModel && gui) { // Receive and report messages from wallet thread connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), gui, SLOT(message(QString,QString,unsigned int))); @@ -120,7 +117,6 @@ void WalletView::setWalletModel(WalletModel *walletModel) addressBookPage->setModel(walletModel->getAddressTableModel()); receiveCoinsPage->setModel(walletModel->getAddressTableModel()); sendCoinsPage->setModel(walletModel); - signVerifyMessageDialog->setModel(walletModel); setEncryptionStatus(); connect(walletModel, SIGNAL(encryptionStatusChanged(int)), gui, SLOT(setEncryptionStatus(int))); @@ -152,31 +148,26 @@ void WalletView::incomingTransaction(const QModelIndex& parent, int start, int / void WalletView::gotoOverviewPage() { - gui->getOverviewAction()->setChecked(true); setCurrentWidget(overviewPage); } void WalletView::gotoHistoryPage() { - gui->getHistoryAction()->setChecked(true); setCurrentWidget(transactionsPage); } void WalletView::gotoAddressBookPage() { - gui->getAddressBookAction()->setChecked(true); setCurrentWidget(addressBookPage); } void WalletView::gotoReceiveCoinsPage() { - gui->getReceiveCoinsAction()->setChecked(true); setCurrentWidget(receiveCoinsPage); } void WalletView::gotoSendCoinsPage(QString addr) { - gui->getSendCoinsAction()->setChecked(true); setCurrentWidget(sendCoinsPage); if (!addr.isEmpty()) @@ -185,7 +176,10 @@ void WalletView::gotoSendCoinsPage(QString addr) void WalletView::gotoSignMessageTab(QString addr) { - // call show() in showTab_SM() + // calls show() in showTab_SM() + SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(this); + signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose); + signVerifyMessageDialog->setModel(walletModel); signVerifyMessageDialog->showTab_SM(true); if (!addr.isEmpty()) @@ -194,7 +188,10 @@ void WalletView::gotoSignMessageTab(QString addr) void WalletView::gotoVerifyMessageTab(QString addr) { - // call show() in showTab_VM() + // calls show() in showTab_VM() + SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(this); + signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose); + signVerifyMessageDialog->setModel(walletModel); signVerifyMessageDialog->showTab_VM(true); if (!addr.isEmpty()) diff --git a/src/qt/walletview.h b/src/qt/walletview.h index ce4e051098..e3ff253d3c 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -36,7 +36,7 @@ class WalletView : public QStackedWidget Q_OBJECT public: - explicit WalletView(QWidget *parent, BitcoinGUI *_gui); + explicit WalletView(QWidget *parent); ~WalletView(); void setBitcoinGUI(BitcoinGUI *gui); @@ -64,7 +64,6 @@ private: AddressBookPage *addressBookPage; AddressBookPage *receiveCoinsPage; SendCoinsDialog *sendCoinsPage; - SignVerifyMessageDialog *signVerifyMessageDialog; TransactionView *transactionView; diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 957241d6a0..6ea805a7f1 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -1,5 +1,5 @@ // Copyright (c) 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. diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 61cd07d507..3589b45900 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2012 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. diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index f123c3a9e0..77dc13815d 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -1,5 +1,5 @@ // Copyright (c) 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. diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index f78f034e32..7685dec57b 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2012 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. diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 5384b65906..d5bd39cb4d 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -1,5 +1,5 @@ // Copyright (c) 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. diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 433cc8b735..a72c254e76 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1,5 +1,5 @@ // Copyright (c) 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. @@ -1169,7 +1169,9 @@ Value listsinceblock(const Array& params, bool fHelp) uint256 blockId = 0; blockId.SetHex(params[0].get_str()); - pindex = CBlockLocator(blockId).GetBlockIndex(); + std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(blockId); + if (it != mapBlockIndex.end()) + pindex = it->second; } if (params.size() > 1) diff --git a/src/script.cpp b/src/script.cpp index 0fe2953548..4e4e95a678 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1,5 +1,5 @@ // 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. #include "script.h" @@ -971,62 +971,118 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co +namespace { +/** Wrapper that serializes like CTransaction, but with the modifications + * required for the signature hash done in-place + */ +class CTransactionSignatureSerializer { +private: + const CTransaction &txTo; // reference to the spending transaction (the one being serialized) + const CScript &scriptCode; // output script being consumed + const unsigned int nIn; // input index of txTo being signed + const bool fAnyoneCanPay; // whether the hashtype has the SIGHASH_ANYONECANPAY flag set + const bool fHashSingle; // whether the hashtype is SIGHASH_SINGLE + const bool fHashNone; // whether the hashtype is SIGHASH_NONE - -uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) -{ - if (nIn >= txTo.vin.size()) - { - LogPrintf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); - return 1; +public: + CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) : + txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn), + fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)), + fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE), + fHashNone((nHashTypeIn & 0x1f) == SIGHASH_NONE) {} + + /** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */ + template<typename S> + void SerializeScriptCode(S &s, int nType, int nVersion) const { + CScript::const_iterator it = scriptCode.begin(); + CScript::const_iterator itBegin = it; + opcodetype opcode; + unsigned int nCodeSeparators = 0; + while (scriptCode.GetOp(it, opcode)) { + if (opcode == OP_CODESEPARATOR) + nCodeSeparators++; + } + ::WriteCompactSize(s, scriptCode.size() - nCodeSeparators); + it = itBegin; + while (scriptCode.GetOp(it, opcode)) { + if (opcode == OP_CODESEPARATOR) { + s.write((char*)&itBegin[0], it-itBegin-1); + itBegin = it; + } + } + s.write((char*)&itBegin[0], it-itBegin); } - CTransaction txTmp(txTo); - // In case concatenating two scripts ends up with two codeseparators, - // or an extra one at the end, this prevents all those possible incompatibilities. - scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR)); + /** Serialize an input of txTo */ + template<typename S> + void SerializeInput(S &s, unsigned int nInput, int nType, int nVersion) const { + // In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized + if (fAnyoneCanPay) + nInput = nIn; + // Serialize the prevout + ::Serialize(s, txTo.vin[nInput].prevout, nType, nVersion); + // Serialize the script + if (nInput != nIn) + // Blank out other inputs' signatures + ::Serialize(s, CScript(), nType, nVersion); + else + SerializeScriptCode(s, nType, nVersion); + // Serialize the nSequence + if (nInput != nIn && (fHashSingle || fHashNone)) + // let the others update at will + ::Serialize(s, (int)0, nType, nVersion); + else + ::Serialize(s, txTo.vin[nInput].nSequence, nType, nVersion); + } - // Blank out other inputs' signatures - for (unsigned int i = 0; i < txTmp.vin.size(); i++) - txTmp.vin[i].scriptSig = CScript(); - txTmp.vin[nIn].scriptSig = scriptCode; + /** Serialize an output of txTo */ + template<typename S> + void SerializeOutput(S &s, unsigned int nOutput, int nType, int nVersion) const { + if (fHashSingle && nOutput != nIn) + // Do not lock-in the txout payee at other indices as txin + ::Serialize(s, CTxOut(), nType, nVersion); + else + ::Serialize(s, txTo.vout[nOutput], nType, nVersion); + } - // Blank out some of the outputs - if ((nHashType & 0x1f) == SIGHASH_NONE) - { - // Wildcard payee - txTmp.vout.clear(); + /** Serialize txTo */ + template<typename S> + void Serialize(S &s, int nType, int nVersion) const { + // Serialize nVersion + ::Serialize(s, txTo.nVersion, nType, nVersion); + // Serialize vin + unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size(); + ::WriteCompactSize(s, nInputs); + for (unsigned int nInput = 0; nInput < nInputs; nInput++) + SerializeInput(s, nInput, nType, nVersion); + // Serialize vout + unsigned int nOutputs = fHashNone ? 0 : (fHashSingle ? nIn+1 : txTo.vout.size()); + ::WriteCompactSize(s, nOutputs); + for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++) + SerializeOutput(s, nOutput, nType, nVersion); + // Serialie nLockTime + ::Serialize(s, txTo.nLockTime, nType, nVersion); + } +}; +} - // Let the others update at will - for (unsigned int i = 0; i < txTmp.vin.size(); i++) - if (i != nIn) - txTmp.vin[i].nSequence = 0; +uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) +{ + if (nIn >= txTo.vin.size()) { + LogPrintf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); + return 1; } - else if ((nHashType & 0x1f) == SIGHASH_SINGLE) - { - // Only lock-in the txout payee at same index as txin - unsigned int nOut = nIn; - if (nOut >= txTmp.vout.size()) - { - LogPrintf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut); + + // Check for invalid use of SIGHASH_SINGLE + if ((nHashType & 0x1f) == SIGHASH_SINGLE) { + if (nIn >= txTo.vout.size()) { + LogPrintf("ERROR: SignatureHash() : nOut=%d out of range\n", nIn); return 1; } - txTmp.vout.resize(nOut+1); - for (unsigned int i = 0; i < nOut; i++) - txTmp.vout[i].SetNull(); - - // Let the others update at will - for (unsigned int i = 0; i < txTmp.vin.size(); i++) - if (i != nIn) - txTmp.vin[i].nSequence = 0; } - // Blank out other inputs completely, not recommended for open transactions - if (nHashType & SIGHASH_ANYONECANPAY) - { - txTmp.vin[0] = txTmp.vin[nIn]; - txTmp.vin.resize(1); - } + // Wrapper to serialize only the necessary parts of the transaction being signed + CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType); // Serialize and hash CHashWriter ss(SER_GETHASH, 0); diff --git a/src/script.h b/src/script.h index 842b8512eb..d339f7880e 100644 --- a/src/script.h +++ b/src/script.h @@ -1,5 +1,5 @@ // 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 H_BITCOIN_SCRIPT diff --git a/src/serialize.h b/src/serialize.h index e3d9939bcc..4d9aec3426 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1,5 +1,5 @@ // 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_SERIALIZE_H @@ -216,18 +216,24 @@ uint64 ReadCompactSize(Stream& is) unsigned short xSize; READDATA(is, xSize); nSizeRet = xSize; + if (nSizeRet < 253) + throw std::ios_base::failure("non-canonical ReadCompactSize()"); } else if (chSize == 254) { unsigned int xSize; READDATA(is, xSize); nSizeRet = xSize; + if (nSizeRet < 0x10000u) + throw std::ios_base::failure("non-canonical ReadCompactSize()"); } else { uint64 xSize; READDATA(is, xSize); nSizeRet = xSize; + if (nSizeRet < 0x100000000LLu) + throw std::ios_base::failure("non-canonical ReadCompactSize()"); } if (nSizeRet > (uint64)MAX_SIZE) throw std::ios_base::failure("ReadCompactSize() : size too large"); diff --git a/src/sync.cpp b/src/sync.cpp index 29a455f9b2..d6444141dc 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -78,7 +78,7 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) if (lockstack.get() == NULL) lockstack.reset(new LockStack); - if (fDebug) LogPrintf("Locking: %s\n", locklocation.ToString().c_str()); + LogPrint("lock", "Locking: %s\n", locklocation.ToString().c_str()); dd_mutex.lock(); (*lockstack).push_back(std::make_pair(c, locklocation)); @@ -108,7 +108,7 @@ static void pop_lock() if (fDebug) { const CLockLocation& locklocation = (*lockstack).rbegin()->second; - LogPrintf("Unlocked: %s\n", locklocation.ToString().c_str()); + LogPrint("lock", "Unlocked: %s\n", locklocation.ToString().c_str()); } dd_mutex.lock(); (*lockstack).pop_back(); diff --git a/src/sync.h b/src/sync.h index 64de7cc57c..10e0470a20 100644 --- a/src/sync.h +++ b/src/sync.h @@ -1,5 +1,5 @@ // 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_SYNC_H diff --git a/src/test/Makefile.am b/src/test/Makefile.am index a859eb1de8..c3495095d9 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -34,7 +34,7 @@ test_bitcoin_SOURCES = accounting_tests.cpp alert_tests.cpp \ netbase_tests.cpp pmt_tests.cpp rpc_tests.cpp script_P2SH_tests.cpp \ script_tests.cpp serialize_tests.cpp sigopcount_tests.cpp test_bitcoin.cpp \ transaction_tests.cpp uint160_tests.cpp uint256_tests.cpp util_tests.cpp \ - wallet_tests.cpp $(JSON_TEST_FILES) $(RAW_TEST_FILES) + wallet_tests.cpp sighash_tests.cpp $(JSON_TEST_FILES) $(RAW_TEST_FILES) nodist_test_bitcoin_SOURCES = $(BUILT_SOURCES) diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 9ef932b5b4..7f6f141c62 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -19,7 +19,7 @@ using namespace boost::assign; typedef vector<unsigned char> valtype; -extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); +extern uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); BOOST_AUTO_TEST_SUITE(multisig_tests) diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index dfa5529b87..32be914414 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -21,7 +21,7 @@ using namespace std; using namespace json_spirit; using namespace boost::algorithm; -extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); +extern uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index 19ffdcab66..50139df09e 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -39,7 +39,67 @@ BOOST_AUTO_TEST_CASE(varints) ss >> VARINT(j); BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i); } +} + +BOOST_AUTO_TEST_CASE(compactsize) +{ + CDataStream ss(SER_DISK, 0); + vector<char>::size_type i, j; + + for (i = 1; i <= MAX_SIZE; i *= 2) + { + WriteCompactSize(ss, i-1); + WriteCompactSize(ss, i); + } + for (i = 1; i <= MAX_SIZE; i *= 2) + { + j = ReadCompactSize(ss); + BOOST_CHECK_MESSAGE((i-1) == j, "decoded:" << j << " expected:" << (i-1)); + j = ReadCompactSize(ss); + BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i); + } +} + +static bool isCanonicalException(const std::ios_base::failure& ex) +{ + return std::string("non-canonical ReadCompactSize()") == ex.what(); +} + +BOOST_AUTO_TEST_CASE(noncanonical) +{ + // Write some non-canonical CompactSize encodings, and + // make sure an exception is thrown when read back. + CDataStream ss(SER_DISK, 0); + vector<char>::size_type n; + + // zero encoded with three bytes: + ss.write("\xfd\x00\x00", 3); + BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); + + // 0xfc encoded with three bytes: + ss.write("\xfd\xfc\x00", 3); + BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); + + // 0xfd encoded with three bytes is OK: + ss.write("\xfd\xfd\x00", 3); + n = ReadCompactSize(ss); + BOOST_CHECK(n == 0xfd); + + // zero encoded with five bytes: + ss.write("\xfe\x00\x00\x00\x00", 5); + BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); + + // 0xffff encoded with five bytes: + ss.write("\xfe\xff\xff\x00\x00", 5); + BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); + + // zero encoded with nine bytes: + ss.write("\xff\x00\x00\x00\x00\x00\x00\x00\x00", 9); + BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); + // 0x01ffffff encoded with nine bytes: + ss.write("\xff\xff\xff\xff\x01\x00\x00\x00\x00", 9); + BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp new file mode 100644 index 0000000000..f098d46186 --- /dev/null +++ b/src/test/sighash_tests.cpp @@ -0,0 +1,120 @@ +#include <boost/test/unit_test.hpp> + +#include "main.h" +#include "util.h" + +extern uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); + +// Old script.cpp SignatureHash function +uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) +{ + if (nIn >= txTo.vin.size()) + { + printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); + return 1; + } + CTransaction txTmp(txTo); + + // In case concatenating two scripts ends up with two codeseparators, + // or an extra one at the end, this prevents all those possible incompatibilities. + scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR)); + + // Blank out other inputs' signatures + for (unsigned int i = 0; i < txTmp.vin.size(); i++) + txTmp.vin[i].scriptSig = CScript(); + txTmp.vin[nIn].scriptSig = scriptCode; + + // Blank out some of the outputs + if ((nHashType & 0x1f) == SIGHASH_NONE) + { + // Wildcard payee + txTmp.vout.clear(); + + // Let the others update at will + for (unsigned int i = 0; i < txTmp.vin.size(); i++) + if (i != nIn) + txTmp.vin[i].nSequence = 0; + } + else if ((nHashType & 0x1f) == SIGHASH_SINGLE) + { + // Only lock-in the txout payee at same index as txin + unsigned int nOut = nIn; + if (nOut >= txTmp.vout.size()) + { + printf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut); + return 1; + } + txTmp.vout.resize(nOut+1); + for (unsigned int i = 0; i < nOut; i++) + txTmp.vout[i].SetNull(); + + // Let the others update at will + for (unsigned int i = 0; i < txTmp.vin.size(); i++) + if (i != nIn) + txTmp.vin[i].nSequence = 0; + } + + // Blank out other inputs completely, not recommended for open transactions + if (nHashType & SIGHASH_ANYONECANPAY) + { + txTmp.vin[0] = txTmp.vin[nIn]; + txTmp.vin.resize(1); + } + + // Serialize and hash + CHashWriter ss(SER_GETHASH, 0); + ss << txTmp << nHashType; + return ss.GetHash(); +} + +void static RandomScript(CScript &script) { + static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR}; + script = CScript(); + int ops = (insecure_rand() % 10); + for (int i=0; i<ops; i++) + script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))]; +} + +void static RandomTransaction(CTransaction &tx, bool fSingle) { + tx.nVersion = insecure_rand(); + tx.vin.clear(); + tx.vout.clear(); + tx.nLockTime = (insecure_rand() % 2) ? insecure_rand() : 0; + int ins = (insecure_rand() % 4) + 1; + int outs = fSingle ? ins : (insecure_rand() % 4) + 1; + for (int in = 0; in < ins; in++) { + tx.vin.push_back(CTxIn()); + CTxIn &txin = tx.vin.back(); + txin.prevout.hash = GetRandHash(); + txin.prevout.n = insecure_rand() % 4; + RandomScript(txin.scriptSig); + txin.nSequence = (insecure_rand() % 2) ? insecure_rand() : (unsigned int)-1; + } + for (int out = 0; out < outs; out++) { + tx.vout.push_back(CTxOut()); + CTxOut &txout = tx.vout.back(); + txout.nValue = insecure_rand() % 100000000; + RandomScript(txout.scriptPubKey); + } +} + +BOOST_AUTO_TEST_SUITE(sighash_tests) + +BOOST_AUTO_TEST_CASE(sighash_test) +{ + seed_insecure_rand(false); + + for (int i=0; i<50000; i++) { + int nHashType = insecure_rand(); + CTransaction txTo; + RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); + CScript scriptCode; + RandomScript(scriptCode); + int nIn = insecure_rand() % txTo.vin.size(); + BOOST_CHECK(SignatureHash(scriptCode, txTo, nIn, nHashType) == + SignatureHashOld(scriptCode, txTo, nIn, nHashType)); + } +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/src/txdb.cpp b/src/txdb.cpp index 24ee8ec3e8..5e7b78296c 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -1,5 +1,5 @@ // 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. diff --git a/src/txdb.h b/src/txdb.h index f59fc5da86..e3560a9c5c 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -1,5 +1,5 @@ // 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_TXDB_LEVELDB_H diff --git a/src/uint256.h b/src/uint256.h index 45ab8abb5e..79404f1b16 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -1,5 +1,5 @@ // 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_UINT256_H diff --git a/src/util.cpp b/src/util.cpp index cfaf5bdf8c..71994587cf 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,5 +1,5 @@ // 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. @@ -95,8 +95,6 @@ void locking_callback(int mode, int i, const char* file, int line) } } -LockedPageManager LockedPageManager::instance; - // Init class CInit { diff --git a/src/util.h b/src/util.h index c3fb01dbf0..258910e2fb 100644 --- a/src/util.h +++ b/src/util.h @@ -1,5 +1,5 @@ // 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_UTIL_H diff --git a/src/wallet.cpp b/src/wallet.cpp index 0f0ce7e631..5eb2808920 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1,5 +1,5 @@ // 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. @@ -1231,9 +1231,10 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, } int64 nChange = nValueIn - nValue - nFeeRet; - // if sub-cent change is required, the fee must be raised to at least nMinTxFee - // or until nChange becomes zero - // NOTE: this depends on the exact behaviour of GetMinFee + // The following if statement should be removed once enough miners + // have upgraded to the 0.9 GetMinFee() rules. Until then, this avoids + // creating free transactions that have change outputs less than + // CENT bitcoins. if (nFeeRet < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT) { int64 nMoveToFee = min(nChange, CTransaction::nMinTxFee - nFeeRet); @@ -1299,7 +1300,15 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, strFailReason = _("Transaction too large"); return false; } - dPriority /= nBytes; + unsigned int nTxSizeMod = nBytes; + // See miner.c's dPriority logic for the matching network-node side code. + BOOST_FOREACH(const CTxIn& txin, (*(CTransaction*)&wtxNew).vin) + { + unsigned int offset = 41U + min(110U, (unsigned int)txin.scriptSig.size()); + if (nTxSizeMod > offset) + nTxSizeMod -= offset; + } + dPriority /= nTxSizeMod; // Check that enough fee is included int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000); diff --git a/src/wallet.h b/src/wallet.h index 51bc9f67c4..f87e9b08c4 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -1,5 +1,5 @@ // 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_WALLET_H diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 635fda1b42..831ef8b00d 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -1,5 +1,5 @@ // 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. @@ -306,6 +306,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, } CKey key; CPrivKey pkey; + uint256 hash = 0; + if (strType == "key") { wss.nKeys++; @@ -315,14 +317,40 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, ssValue >> wkey; pkey = wkey.vchPrivKey; } - if (!key.SetPrivKey(pkey, vchPubKey.IsCompressed())) + + // Old wallets store keys as "key" [pubkey] => [privkey] + // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key + // using EC operations as a checksum. + // Newer wallets store keys as "key"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while + // remaining backwards-compatible. + try { - strErr = "Error reading wallet database: CPrivKey corrupt"; - return false; + ssValue >> hash; + } + catch(...){} + + bool fSkipCheck = false; + + if (hash != 0) + { + // hash pubkey/privkey to accelerate wallet load + std::vector<unsigned char> vchKey; + vchKey.reserve(vchPubKey.size() + pkey.size()); + vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end()); + vchKey.insert(vchKey.end(), pkey.begin(), pkey.end()); + + if (Hash(vchKey.begin(), vchKey.end()) != hash) + { + strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt"; + return false; + } + + fSkipCheck = true; } - if (key.GetPubKey() != vchPubKey) + + if (!key.Load(pkey, vchPubKey, fSkipCheck)) { - strErr = "Error reading wallet database: CPrivKey pubkey inconsistency"; + strErr = "Error reading wallet database: CPrivKey corrupt"; return false; } if (!pwallet->LoadKey(key, vchPubKey)) diff --git a/src/walletdb.h b/src/walletdb.h index 09ebebe5ac..b6d0d45449 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -1,5 +1,5 @@ // 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_WALLETDB_H @@ -93,8 +93,14 @@ public: if (!Write(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta)) return false; - - return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false); + + // hash pubkey/privkey to accelerate wallet load + std::vector<unsigned char> vchKey; + vchKey.reserve(vchPubKey.size() + vchPrivKey.size()); + vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end()); + vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end()); + + return Write(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false); } bool WriteCryptedKey(const CPubKey& vchPubKey, |