aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/allocators.h165
-rw-r--r--src/bitcoinrpc.cpp5
-rw-r--r--src/bitcoinrpc.h1
-rw-r--r--src/checkpoints.cpp2
-rw-r--r--src/crypter.cpp12
-rw-r--r--src/crypter.h11
-rw-r--r--src/main.cpp8
-rw-r--r--src/qt/bitcoingui.cpp10
-rw-r--r--src/qt/locale/bitcoin_cs.ts186
-rw-r--r--src/rpcrawtransaction.cpp42
-rw-r--r--src/rpcwallet.cpp37
-rw-r--r--src/script.cpp3
-rw-r--r--src/test/allocator_tests.cpp115
-rw-r--r--src/util.cpp2
-rw-r--r--src/wallet.cpp123
-rw-r--r--src/wallet.h11
16 files changed, 587 insertions, 146 deletions
diff --git a/src/allocators.h b/src/allocators.h
index ddeabc48c5..99afa10c25 100644
--- a/src/allocators.h
+++ b/src/allocators.h
@@ -7,6 +7,8 @@
#include <string.h>
#include <string>
+#include <boost/thread/mutex.hpp>
+#include <map>
#ifdef WIN32
#ifdef _WIN32_WINNT
@@ -22,23 +24,156 @@
// Note that VirtualLock does not provide this as a guarantee on Windows,
// but, in practice, memory that has been VirtualLock'd almost never gets written to
// the pagefile except in rare circumstances where memory is extremely low.
-#define mlock(p, n) VirtualLock((p), (n));
-#define munlock(p, n) VirtualUnlock((p), (n));
#else
#include <sys/mman.h>
-#include <limits.h>
-/* This comes from limits.h if it's not defined there set a sane default */
-#ifndef PAGESIZE
-#include <unistd.h>
-#define PAGESIZE sysconf(_SC_PAGESIZE)
+#include <limits.h> // for PAGESIZE
+#include <unistd.h> // for sysconf
#endif
-#define mlock(a,b) \
- mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
- (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
-#define munlock(a,b) \
- munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
- (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
+
+/**
+ * Thread-safe class to keep track of locked (ie, non-swappable) memory pages.
+ *
+ * Memory locks do not stack, that is, pages which have been locked several times by calls to mlock()
+ * will be unlocked by a single call to munlock(). This can result in keying material ending up in swap when
+ * those functions are used naively. This class simulates stacking memory locks by keeping a counter per page.
+ *
+ * @note By using a map from each page base address to lock count, this class is optimized for
+ * small objects that span up to a few pages, mostly smaller than a page. To support large allocations,
+ * something like an interval tree would be the preferred data structure.
+ */
+template <class Locker> class LockedPageManagerBase
+{
+public:
+ LockedPageManagerBase(size_t page_size):
+ page_size(page_size)
+ {
+ // Determine bitmask for extracting page from address
+ assert(!(page_size & (page_size-1))); // size must be power of two
+ page_mask = ~(page_size - 1);
+ }
+
+ // For all pages in affected range, increase lock count
+ void LockRange(void *p, size_t size)
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ if(!size) return;
+ const size_t base_addr = reinterpret_cast<size_t>(p);
+ const size_t start_page = base_addr & page_mask;
+ const size_t end_page = (base_addr + size - 1) & page_mask;
+ for(size_t page = start_page; page <= end_page; page += page_size)
+ {
+ Histogram::iterator it = histogram.find(page);
+ if(it == histogram.end()) // Newly locked page
+ {
+ locker.Lock(reinterpret_cast<void*>(page), page_size);
+ histogram.insert(std::make_pair(page, 1));
+ }
+ else // Page was already locked; increase counter
+ {
+ it->second += 1;
+ }
+ }
+ }
+
+ // For all pages in affected range, decrease lock count
+ void UnlockRange(void *p, size_t size)
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ if(!size) return;
+ const size_t base_addr = reinterpret_cast<size_t>(p);
+ const size_t start_page = base_addr & page_mask;
+ const size_t end_page = (base_addr + size - 1) & page_mask;
+ for(size_t page = start_page; page <= end_page; page += page_size)
+ {
+ Histogram::iterator it = histogram.find(page);
+ assert(it != histogram.end()); // Cannot unlock an area that was not locked
+ // Decrease counter for page, when it is zero, the page will be unlocked
+ it->second -= 1;
+ if(it->second == 0) // Nothing on the page anymore that keeps it locked
+ {
+ // Unlock page and remove the count from histogram
+ locker.Unlock(reinterpret_cast<void*>(page), page_size);
+ histogram.erase(it);
+ }
+ }
+ }
+
+ // Get number of locked pages for diagnostics
+ int GetLockedPageCount()
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ return histogram.size();
+ }
+
+private:
+ Locker locker;
+ boost::mutex mutex;
+ size_t page_size, page_mask;
+ // map of page base address to lock count
+ typedef std::map<size_t,int> Histogram;
+ Histogram histogram;
+};
+
+/** Determine system page size in bytes */
+static inline size_t GetSystemPageSize()
+{
+ size_t page_size;
+#if defined(WIN32)
+ SYSTEM_INFO sSysInfo;
+ GetSystemInfo(&sSysInfo);
+ page_size = sSysInfo.dwPageSize;
+#elif defined(PAGESIZE) // defined in limits.h
+ page_size = PAGESIZE;
+#else // assume some POSIX OS
+ page_size = sysconf(_SC_PAGESIZE);
+#endif
+ return page_size;
+}
+
+/**
+ * OS-dependent memory page locking/unlocking.
+ * Defined as policy class to make stubbing for test possible.
+ */
+class MemoryPageLocker
+{
+public:
+ /** Lock memory pages.
+ * addr and len must be a multiple of the system page size
+ */
+ bool Lock(const void *addr, size_t len)
+ {
+#ifdef WIN32
+ return VirtualLock(const_cast<void*>(addr), len);
+#else
+ return mlock(addr, len) == 0;
+#endif
+ }
+ /** Unlock memory pages.
+ * addr and len must be a multiple of the system page size
+ */
+ bool Unlock(const void *addr, size_t len)
+ {
+#ifdef WIN32
+ return VirtualUnlock(const_cast<void*>(addr), len);
+#else
+ return munlock(addr, len) == 0;
#endif
+ }
+};
+
+/**
+ * Singleton class to keep track of locked (ie, non-swappable) memory pages, for use in
+ * std::allocator templates.
+ */
+class LockedPageManager: public LockedPageManagerBase<MemoryPageLocker>
+{
+public:
+ static LockedPageManager instance; // instantiated in util.cpp
+private:
+ LockedPageManager():
+ LockedPageManagerBase<MemoryPageLocker>(GetSystemPageSize())
+ {}
+};
//
// Allocator that locks its contents from being paged
@@ -69,7 +204,7 @@ struct secure_allocator : public std::allocator<T>
T *p;
p = std::allocator<T>::allocate(n, hint);
if (p != NULL)
- mlock(p, sizeof(T) * n);
+ LockedPageManager::instance.LockRange(p, sizeof(T) * n);
return p;
}
@@ -78,7 +213,7 @@ struct secure_allocator : public std::allocator<T>
if (p != NULL)
{
memset(p, 0, sizeof(T) * n);
- munlock(p, sizeof(T) * n);
+ LockedPageManager::instance.UnlockRange(p, sizeof(T) * n);
}
std::allocator<T>::deallocate(p, n);
}
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 5537eb4815..2271ff07c4 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -104,8 +104,7 @@ Value ValueFromAmount(int64 amount)
return (double)amount / (double)COIN;
}
-std::string
-HexBits(unsigned int nBits)
+std::string HexBits(unsigned int nBits)
{
union {
int32_t nBits;
@@ -231,6 +230,7 @@ static const CRPCCommand vRPCCommands[] =
{ "getblockhash", &getblockhash, false, false },
{ "gettransaction", &gettransaction, false, false },
{ "listtransactions", &listtransactions, false, false },
+ { "listaddressgroupings", &listaddressgroupings, false, false },
{ "signmessage", &signmessage, false, false },
{ "verifymessage", &verifymessage, false, false },
{ "getwork", &getwork, true, false },
@@ -1139,6 +1139,7 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "addmultisigaddress" && n > 1) ConvertTo<Array>(params[1]);
if (strMethod == "listunspent" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listunspent" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "listunspent" && n > 2) ConvertTo<Array>(params[2]);
if (strMethod == "getrawtransaction" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "createrawtransaction" && n > 0) ConvertTo<Array>(params[0]);
if (strMethod == "createrawtransaction" && n > 1) ConvertTo<Object>(params[1]);
diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h
index 6a1857cb44..94446c36bb 100644
--- a/src/bitcoinrpc.h
+++ b/src/bitcoinrpc.h
@@ -114,6 +114,7 @@ extern json_spirit::Value addmultisigaddress(const json_spirit::Array& params, b
extern json_spirit::Value listreceivedbyaddress(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value listreceivedbyaccount(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value listtransactions(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value listaddressgroupings(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value listaccounts(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value listsinceblock(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value gettransaction(const json_spirit::Array& params, bool fHelp);
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 2df647e83d..8208854962 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -29,7 +29,7 @@ namespace Checkpoints
(105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
(134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
(168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
- (185333, uint256("0x00000000000002334c71b8706940c20348af897a9cfc0f1a6dab0d14d4ceb815"))
+ (193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"))
;
static MapCheckpoints mapCheckpointsTestnet =
diff --git a/src/crypter.cpp b/src/crypter.cpp
index 411a1ee4c1..181b8fa00a 100644
--- a/src/crypter.cpp
+++ b/src/crypter.cpp
@@ -17,12 +17,6 @@ bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::v
if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
return false;
- // 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.
- mlock(&chKey[0], sizeof chKey);
- mlock(&chIV[0], sizeof chIV);
-
int i = 0;
if (nDerivationMethod == 0)
i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
@@ -44,12 +38,6 @@ bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigne
if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE)
return false;
- // Try to keep the key data 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.
- mlock(&chKey[0], sizeof chKey);
- mlock(&chIV[0], sizeof chIV);
-
memcpy(&chKey[0], &chNewKey[0], sizeof chKey);
memcpy(&chIV[0], &chNewIV[0], sizeof chIV);
diff --git a/src/crypter.h b/src/crypter.h
index d1bdb92c91..04538a3fa5 100644
--- a/src/crypter.h
+++ b/src/crypter.h
@@ -78,19 +78,26 @@ public:
{
memset(&chKey, 0, sizeof chKey);
memset(&chIV, 0, sizeof chIV);
- munlock(&chKey, sizeof chKey);
- munlock(&chIV, sizeof chIV);
fKeySet = false;
}
CCrypter()
{
fKeySet = false;
+
+ // 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);
}
~CCrypter()
{
CleanKey();
+
+ LockedPageManager::instance.UnlockRange(&chKey[0], sizeof chKey);
+ LockedPageManager::instance.UnlockRange(&chIV[0], sizeof chIV);
}
};
diff --git a/src/main.cpp b/src/main.cpp
index 91aba149bc..f71cfe7caa 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -281,9 +281,12 @@ bool CTransaction::IsStandard() const
if (!txin.scriptSig.IsPushOnly())
return false;
}
- BOOST_FOREACH(const CTxOut& txout, vout)
+ BOOST_FOREACH(const CTxOut& txout, vout) {
if (!::IsStandard(txout.scriptPubKey))
return false;
+ if (txout.nValue == 0)
+ return false;
+ }
return true;
}
@@ -653,8 +656,7 @@ bool CTxMemPool::remove(CTransaction &tx)
return true;
}
-void
-CTxMemPool::clear()
+void CTxMemPool::clear()
{
LOCK(cs);
mapTx.clear();
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index b81b832a87..1bdc313da8 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -53,6 +53,7 @@
#include <QTimer>
#include <QDragEnterEvent>
#include <QUrl>
+#include <QStyle>
#include <iostream>
@@ -148,6 +149,15 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
progressBar->setAlignment(Qt::AlignCenter);
progressBar->setVisible(false);
+ // Override style sheet for progress bar for styles that have a segmented progress bar,
+ // as they make the text unreadable (workaround for issue #1071)
+ // See https://qt-project.org/doc/qt-4.8/gallery.html
+ QString curStyle = qApp->style()->metaObject()->className();
+ if(curStyle == "QWindowsStyle" || curStyle == "QWindowsXPStyle")
+ {
+ progressBar->setStyleSheet("QProgressBar { background-color: #e8e8e8; border: 1px solid grey; border-radius: 7px; padding: 1px; text-align: center; } QProgressBar::chunk { background: QLinearGradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #FF8000, stop: 1 orange); border-radius: 7px; margin: 0px; }");
+ }
+
statusBar()->addWidget(progressBarLabel);
statusBar()->addWidget(progressBar);
statusBar()->addPermanentWidget(frameBlocks);
diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts
index 81f94e388e..edc7e52aa4 100644
--- a/src/qt/locale/bitcoin_cs.ts
+++ b/src/qt/locale/bitcoin_cs.ts
@@ -21,7 +21,13 @@ This is experimental software.
Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php.
This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard.</source>
- <translation type="unfinished"/>
+ <translation>Copyright © 2009-2012 Vývojáři Bitcoinu
+
+Tohle je experimentální program.
+
+Šířen pod licencí MIT/X11, viz přiložený soubor COPYING nebo http://www.opensource.org/licenses/mit-license.php.
+
+Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v OpenSSL Toolkitu (http://www.openssl.org/) a kryptografický program od Erika Younga (eay@cryptsoft.com) a program UPnP od Thomase Bernarda.</translation>
</message>
</context>
<context>
@@ -215,18 +221,18 @@ This product includes software developed by the OpenSSL Project for use in the O
<message>
<location line="+1"/>
<source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
- <translation type="unfinished"/>
+ <translation>Varování: Pokud si zašifruješ peněženku a ztratíš či zapomeneš heslo, &lt;b&gt;PŘIJDEŠ O VŠECHNY BITCOINY&lt;/b&gt;!</translation>
</message>
<message>
<location line="+0"/>
<source>Are you sure you wish to encrypt your wallet?</source>
- <translation type="unfinished"/>
+ <translation>Jsi si jistý, že chceš peněženku zašifrovat?</translation>
</message>
<message>
<location line="+106"/>
<location line="+24"/>
<source>Warning: The Caps Lock key is on!</source>
- <translation type="unfinished"/>
+ <translation>Upozornění: Caps Lock je zapnutý!</translation>
</message>
<message>
<location line="-121"/>
@@ -278,7 +284,7 @@ This product includes software developed by the OpenSSL Project for use in the O
<message>
<location line="+14"/>
<source>Wallet passphrase was successfully changed.</source>
- <translation type="unfinished"/>
+ <translation>Heslo k peněžence bylo v pořádku změněno.</translation>
</message>
</context>
<context>
@@ -456,12 +462,12 @@ This product includes software developed by the OpenSSL Project for use in the O
<message>
<location line="+1"/>
<source>&amp;Debug window</source>
- <translation>&amp;Ladící okno</translation>
+ <translation>&amp;Ladicí okno</translation>
</message>
<message>
<location line="+1"/>
<source>Open debugging and diagnostic console</source>
- <translation>Otevři ladící a diagnostickou konzoli</translation>
+ <translation>Otevři ladicí a diagnostickou konzoli</translation>
</message>
<message>
<location line="-56"/>
@@ -481,7 +487,7 @@ This product includes software developed by the OpenSSL Project for use in the O
<message>
<location line="+186"/>
<source>&amp;About Bitcoin</source>
- <translation type="unfinished"/>
+ <translation>O &amp;Bitcoinu</translation>
</message>
<message>
<location line="+44"/>
@@ -643,7 +649,7 @@ Adresa: %4
<message>
<location filename="../bitcoin.cpp" line="+112"/>
<source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
- <translation type="unfinished"/>
+ <translation>Stala se fatální chyba. Bitcoin nemůže bezpečně pokračovat v činnosti, a proto skončí.</translation>
</message>
</context>
<context>
@@ -728,7 +734,7 @@ Adresa: %4
<location filename="../guiutil.cpp" line="+425"/>
<location line="+12"/>
<source>Bitcoin-Qt</source>
- <translation type="unfinished"/>
+ <translation>Bitcoin-Qt</translation>
</message>
<message>
<location line="-12"/>
@@ -997,12 +1003,12 @@ Adresa: %4
<message>
<location line="+124"/>
<source>Immature:</source>
- <translation type="unfinished"/>
+ <translation>Nedozráno:</translation>
</message>
<message>
<location line="+13"/>
<source>Mined balance that has not yet matured</source>
- <translation type="unfinished"/>
+ <translation>Vytěžené mince, které ještě nejsou zralé</translation>
</message>
<message>
<location line="+46"/>
@@ -1178,7 +1184,7 @@ Adresa: %4
<message>
<location line="+7"/>
<source>Show the Bitcoin-Qt help message to get a list with possible Bitcoin command-line options.</source>
- <translation type="unfinished"/>
+ <translation>Seznam parametrů Bitcoinu pro příkazovou řádku získáš v nápovědě Bitcoinu Qt.</translation>
</message>
<message>
<location line="+3"/>
@@ -1198,22 +1204,22 @@ Adresa: %4
<message>
<location line="-104"/>
<source>Bitcoin - Debug window</source>
- <translation type="unfinished"/>
+ <translation>Bitcoin - ladicí okno</translation>
</message>
<message>
<location line="+25"/>
<source>Bitcoin Core</source>
- <translation type="unfinished"/>
+ <translation>Jádro Bitcoinu</translation>
</message>
<message>
<location line="+279"/>
<source>Debug log file</source>
- <translation type="unfinished"/>
+ <translation>Soubor s ladicími záznamy</translation>
</message>
<message>
<location line="+7"/>
<source>Open the Bitcoin debug log file from the current data directory. This can take a few seconds for large log files.</source>
- <translation type="unfinished"/>
+ <translation>Otevři soubor s ladicími záznamy Bitcoinu z aktuálního datového adresáře. U velkých logů to může pár vteřin zabrat.</translation>
</message>
<message>
<location line="+102"/>
@@ -1313,7 +1319,7 @@ Adresa: %4
<message>
<location line="+23"/>
<source>The recipient address is not valid, please recheck.</source>
- <translation type="unfinished"/>
+ <translation>Adresa příjemce je neplatná, překontroluj ji prosím.</translation>
</message>
<message>
<location line="+5"/>
@@ -1415,7 +1421,7 @@ Adresa: %4
<message>
<location filename="../forms/signverifymessagedialog.ui" line="+14"/>
<source>Signatures - Sign / Verify a Message</source>
- <translation type="unfinished"/>
+ <translation>Podpisy - podepsat/ověřit zprávu</translation>
</message>
<message>
<location line="+13"/>
@@ -1443,7 +1449,7 @@ Adresa: %4
<location line="-193"/>
<location line="+203"/>
<source>Alt+A</source>
- <translation type="unfinished"/>
+ <translation>Alt+A</translation>
</message>
<message>
<location line="-193"/>
@@ -1453,7 +1459,7 @@ Adresa: %4
<message>
<location line="+10"/>
<source>Alt+P</source>
- <translation type="unfinished"/>
+ <translation>Alt+P</translation>
</message>
<message>
<location line="+12"/>
@@ -1490,17 +1496,17 @@ Adresa: %4
<message>
<location line="-64"/>
<source>Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack.</source>
- <translation type="unfinished"/>
+ <translation>K ověření podpisu zprávy zadej podepisující adresu, zprávu (ověř si, že správně kopíruješ zalomení řádků, mezery, tabulátory apod.) a podpis. Dávej pozor na to, abys nezkopíroval do podpisu víc, než co je v samotné podepsané zprávě, abys nebyl napálen man-in-the-middle útokem.</translation>
</message>
<message>
<location line="+21"/>
<source>The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source>
- <translation type="unfinished"/>
+ <translation>Adresa, kterou je zpráva podepsána (např. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation>
</message>
<message>
<location line="+40"/>
<source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
- <translation type="unfinished"/>
+ <translation>Ověř zprávu, aby ses ujistil, že byla podepsána danou Bitcoinovou adresou</translation>
</message>
<message>
<location line="+17"/>
@@ -1535,18 +1541,18 @@ Adresa: %4
<location line="+73"/>
<location line="+8"/>
<source>Please check the address and try again.</source>
- <translation type="unfinished"/>
+ <translation>Zkontroluj ji prosím a zkus to pak znovu.</translation>
</message>
<message>
<location line="-81"/>
<location line="+81"/>
<source>The entered address does not refer to a key.</source>
- <translation type="unfinished"/>
+ <translation>Zadaná adresa nepasuje ke klíči.</translation>
</message>
<message>
<location line="-73"/>
<source>Wallet unlock was cancelled.</source>
- <translation type="unfinished"/>
+ <translation>Odemčení peněženky bylo zrušeno.</translation>
</message>
<message>
<location line="+8"/>
@@ -1556,23 +1562,23 @@ Adresa: %4
<message>
<location line="+12"/>
<source>Message signing failed.</source>
- <translation type="unfinished"/>
+ <translation>Podepisování zprávy selhalo.</translation>
</message>
<message>
<location line="+5"/>
<source>Message signed.</source>
- <translation type="unfinished"/>
+ <translation>Zpráv podepsána.</translation>
</message>
<message>
<location line="+59"/>
<source>The signature could not be decoded.</source>
- <translation type="unfinished"/>
+ <translation>Podpis nejde dekódovat.</translation>
</message>
<message>
<location line="+0"/>
<location line="+13"/>
<source>Please check the signature and try again.</source>
- <translation type="unfinished"/>
+ <translation>Zkontroluj ho prosím a zkus to pak znovu.</translation>
</message>
<message>
<location line="+0"/>
@@ -1582,12 +1588,12 @@ Adresa: %4
<message>
<location line="+7"/>
<source>Message verification failed.</source>
- <translation type="unfinished"/>
+ <translation>Ověřování zprávy selhalo.</translation>
</message>
<message>
<location line="+5"/>
<source>Message verified.</source>
- <translation type="unfinished"/>
+ <translation>Zpráva ověřena.</translation>
</message>
</context>
<context>
@@ -1600,12 +1606,12 @@ Adresa: %4
<message numerus="yes">
<location line="-2"/>
<source>Open for %n block(s)</source>
- <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation>
+ <translation><numerusform>Otevřeno pro 1 blok</numerusform><numerusform>Otevřeno pro %n bloky</numerusform><numerusform>Otevřeno pro %n bloků</numerusform></translation>
</message>
<message>
<location line="+8"/>
<source>%1/offline</source>
- <translation type="unfinished"/>
+ <translation>%1/offline</translation>
</message>
<message>
<location line="+2"/>
@@ -1620,12 +1626,12 @@ Adresa: %4
<message>
<location line="+18"/>
<source>Status</source>
- <translation type="unfinished"/>
+ <translation>Stav</translation>
</message>
<message numerus="yes">
<location line="+7"/>
<source>, broadcast through %n node(s)</source>
- <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation>
+ <translation><numerusform>, rozesláno přes 1 uzel</numerusform><numerusform>, rozesláno přes %n uzly</numerusform><numerusform>, rozesláno přes %n uzlů</numerusform></translation>
</message>
<message>
<location line="+4"/>
@@ -1635,36 +1641,36 @@ Adresa: %4
<message>
<location line="+7"/>
<source>Source</source>
- <translation type="unfinished"/>
+ <translation>Zdroj</translation>
</message>
<message>
<location line="+0"/>
<source>Generated</source>
- <translation type="unfinished"/>
+ <translation>Vygenerováno</translation>
</message>
<message>
<location line="+6"/>
<location line="+17"/>
<source>From</source>
- <translation type="unfinished"/>
+ <translation>Od</translation>
</message>
<message>
<location line="+1"/>
<location line="+22"/>
<location line="+58"/>
<source>To</source>
- <translation type="unfinished"/>
+ <translation>Pro</translation>
</message>
<message>
<location line="-77"/>
<location line="+2"/>
<source>own address</source>
- <translation type="unfinished"/>
+ <translation>vlastní adresa</translation>
</message>
<message>
<location line="-2"/>
<source>label</source>
- <translation type="unfinished"/>
+ <translation>označení</translation>
</message>
<message>
<location line="+37"/>
@@ -1673,17 +1679,17 @@ Adresa: %4
<location line="+17"/>
<location line="+30"/>
<source>Credit</source>
- <translation type="unfinished"/>
+ <translation>Příjem</translation>
</message>
<message numerus="yes">
<location line="-102"/>
<source>matures in %n more block(s)</source>
- <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation>
+ <translation><numerusform>dozraje po jednom bloku</numerusform><numerusform>dozraje po %n blocích</numerusform><numerusform>dozraje po %n blocích</numerusform></translation>
</message>
<message>
<location line="+2"/>
<source>not accepted</source>
- <translation type="unfinished"/>
+ <translation>neakceptováno</translation>
</message>
<message>
<location line="+44"/>
@@ -1691,67 +1697,67 @@ Adresa: %4
<location line="+15"/>
<location line="+30"/>
<source>Debit</source>
- <translation type="unfinished"/>
+ <translation>Výdaj</translation>
</message>
<message>
<location line="-39"/>
<source>Transaction fee</source>
- <translation type="unfinished"/>
+ <translation>Transakční poplatek</translation>
</message>
<message>
<location line="+16"/>
<source>Net amount</source>
- <translation type="unfinished"/>
+ <translation>Čistá částka</translation>
</message>
<message>
<location line="+6"/>
<source>Message</source>
- <translation type="unfinished"/>
+ <translation>Zpráva</translation>
</message>
<message>
<location line="+2"/>
<source>Comment</source>
- <translation type="unfinished"/>
+ <translation>Komentář</translation>
</message>
<message>
<location line="+2"/>
<source>Transaction ID</source>
- <translation type="unfinished"/>
+ <translation>ID transakce</translation>
</message>
<message>
<location line="+3"/>
<source>Generated coins must mature 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to &quot;not accepted&quot; and it won&apos;t be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
- <translation type="unfinished"/>
+ <translation>Vygenerované mince musí čekat 120 bloků, než mohou být utraceny. Když jsi vygeneroval tenhle blok, tak byl rozposlán do sítě, aby byl přidán do řetězce bloků. Pokud se mu nepodaří dostat se do řetězce, změní se na &quot;neakceptovaný&quot; a nepůjde utratit. To se občas může stát, pokud jiný uzel vygeneruje blok zhruba ve stejném okamžiku jako ty.</translation>
</message>
<message>
<location line="+7"/>
<source>Debug information</source>
- <translation type="unfinished"/>
+ <translation>Ladicí informace</translation>
</message>
<message>
<location line="+8"/>
<source>Transaction</source>
- <translation type="unfinished"/>
+ <translation>Transakce</translation>
</message>
<message>
<location line="+5"/>
<source>Inputs</source>
- <translation type="unfinished"/>
+ <translation>Vstupy</translation>
</message>
<message>
<location line="+23"/>
<source>Amount</source>
- <translation>Množství</translation>
+ <translation>Částka</translation>
</message>
<message>
<location line="+1"/>
<source>true</source>
- <translation type="unfinished"/>
+ <translation>true</translation>
</message>
<message>
<location line="+0"/>
<source>false</source>
- <translation type="unfinished"/>
+ <translation>false</translation>
</message>
<message>
<location line="-212"/>
@@ -2197,142 +2203,142 @@ Adresa: %4
<message>
<location line="-92"/>
<source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation type="unfinished"/>
+ <translation>Přijímat spojení zvenčí (výchozí: 1, pokud není zadáno -proxy nebo -connect)</translation>
</message>
<message>
<location line="-20"/>
<source>Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)</source>
- <translation type="unfinished"/>
+ <translation>Nastavit maximální velikost prioritních/nízkopoplatkových transakcí v bajtech (výchozí: 27000)</translation>
</message>
<message>
<location line="+5"/>
<source>Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation type="unfinished"/>
+ <translation>Upozornění: -paytxfee je nastaveno velmi vysoko! Toto je transakční poplatek, který zaplatíš za každou poslanou transakci.</translation>
</message>
<message>
<location line="+3"/>
<source>Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.</source>
- <translation type="unfinished"/>
+ <translation>Upozornění: Zobrazené transakce nemusí být správné! Možná potřebuješ aktualizovat nebo ostatní uzly potřebují aktualizovat.</translation>
</message>
<message>
<location line="+3"/>
<source>Warning: Please check that your computer&apos;s date and time are correct! If your clock is wrong Bitcoin will not work properly.</source>
- <translation type="unfinished"/>
+ <translation>Upozornění: Zkontroluj, že máš v počítači správně nastavený datum a čas! Pokud jsou nastaveny špatně, Bitcoin nebude fungovat správně.</translation>
</message>
<message>
<location line="+13"/>
<source>An error occurred while setting up the RPC port %i for listening: %s</source>
- <translation type="unfinished"/>
+ <translation>Při nastavování naslouchacího RPC portu %i nastala chyba: %s</translation>
</message>
<message>
<location line="+4"/>
<source>Block creation options:</source>
- <translation type="unfinished"/>
+ <translation>Možnosti vytvoření bloku:</translation>
</message>
<message>
<location line="+6"/>
<source>Connect only to the specified node(s)</source>
- <translation type="unfinished"/>
+ <translation>Připojovat se pouze k zadaným uzlům</translation>
</message>
<message>
<location line="+3"/>
<source>Discover own IP address (default: 1 when listening and no -externalip)</source>
- <translation type="unfinished"/>
+ <translation>Zjistit vlastní IP adresu (výchozí: 1, pokud naslouchá a není zadáno -externalip)</translation>
</message>
<message>
<location line="+11"/>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
- <translation type="unfinished"/>
+ <translation>Nepodařilo se naslouchat na žádném portu. Použij -listen=0, pokud to byl tvůj záměr.</translation>
</message>
<message>
<location line="+2"/>
<source>Find peers using DNS lookup (default: 1 unless -connect)</source>
- <translation type="unfinished"/>
+ <translation>Hledat uzly přes DNS (výchozí: 1, pokud není zadáno -connect)</translation>
</message>
<message>
<location line="+9"/>
<source>Invalid -tor address: &apos;%s&apos;</source>
- <translation type="unfinished"/>
+ <translation>Neplatná -tor adresa: &apos;%s&apos;</translation>
</message>
<message>
<location line="+10"/>
<source>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: 5000)</source>
- <translation type="unfinished"/>
+ <translation>Maximální velikost přijímacího bufferu pro každé spojení, &lt;n&gt;*1000 bajtů (výchozí: 5000)</translation>
</message>
<message>
<location line="+1"/>
<source>Maximum per-connection send buffer, &lt;n&gt;*1000 bytes (default: 1000)</source>
- <translation type="unfinished"/>
+ <translation>Maximální velikost odesílacího bufferu pro každé spojení, &lt;n&gt;*1000 bajtů (výchozí: 1000)</translation>
</message>
<message>
<location line="+1"/>
<source>Only connect to nodes in network &lt;net&gt; (IPv4, IPv6 or Tor)</source>
- <translation type="unfinished"/>
+ <translation>Připojovat se pouze k uzlům v &lt;net&gt; síti (IPv4, IPv6 nebo Tor)</translation>
</message>
<message>
<location line="+2"/>
<source>Output extra debugging information. Implies all other -debug* options</source>
- <translation type="unfinished"/>
+ <translation>Tisknout speciální ladicí informace. Implikuje použití všechny -debug* voleb</translation>
</message>
<message>
<location line="+1"/>
<source>Output extra network debugging information</source>
- <translation type="unfinished"/>
+ <translation>Tisknout speciální ladicí informace o síti</translation>
</message>
<message>
<location line="+2"/>
<source>Prepend debug output with timestamp</source>
- <translation>Připojit před ladící výstup časové razítko</translation>
+ <translation>Připojit před ladicí výstup časové razítko</translation>
</message>
<message>
<location line="+4"/>
<source>SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source>
- <translation type="unfinished"/>
+ <translation>Možnosti SSL: (viz instrukce nastavení SSL v Bitcoin Wiki)</translation>
</message>
<message>
<location line="+1"/>
<source>Select the version of socks proxy to use (4-5, default: 5)</source>
- <translation type="unfinished"/>
+ <translation>Zvol verzi socks proxy (4-5, výchozí: 5)</translation>
</message>
<message>
<location line="+3"/>
<source>Send trace/debug info to console instead of debug.log file</source>
- <translation>Posílat stopovací/ladící informace do konzole místo do souboru debug.log</translation>
+ <translation>Posílat stopovací/ladicí informace do konzole místo do souboru debug.log</translation>
</message>
<message>
<location line="+1"/>
<source>Send trace/debug info to debugger</source>
- <translation>Posílat stopovací/ladící informace do debuggeru</translation>
+ <translation>Posílat stopovací/ladicí informace do debuggeru</translation>
</message>
<message>
<location line="+7"/>
<source>Set maximum block size in bytes (default: 250000)</source>
- <translation type="unfinished"/>
+ <translation>Nastavit maximální velikost bloku v bajtech (výchozí: 250000)</translation>
</message>
<message>
<location line="+1"/>
<source>Set minimum block size in bytes (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>Nastavit minimální velikost bloku v bajtech (výchozí: 0)</translation>
</message>
<message>
<location line="+1"/>
<source>Shrink debug.log file on client startup (default: 1 when no -debug)</source>
- <translation type="unfinished"/>
+ <translation>Při spuštění klienta zmenšit soubor debug.log (výchozí: 1, pokud není zadáno -debug)</translation>
</message>
<message>
<location line="+15"/>
<source>Use UPnP to map the listening port (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>Použít UPnP k namapování naslouchacího portu (výchozí: 0)</translation>
</message>
<message>
<location line="+1"/>
<source>Use UPnP to map the listening port (default: 1 when listening)</source>
- <translation type="unfinished"/>
+ <translation>Použít UPnP k namapování naslouchacího portu (výchozí: 1, pokud naslouchá)</translation>
</message>
<message>
<location line="+1"/>
<source>Use proxy to reach tor hidden services (default: same as -proxy)</source>
- <translation type="unfinished"/>
+ <translation>Použít proxy k připojení ke skryté služby (výchozí: stejné jako -proxy)</translation>
</message>
<message>
<location line="+2"/>
@@ -2342,12 +2348,12 @@ Adresa: %4
<message>
<location line="+2"/>
<source>Warning: Disk space is low!</source>
- <translation type="unfinished"/>
+ <translation>Upozornění: Na disku je málo místa!</translation>
</message>
<message>
<location line="+1"/>
<source>Warning: This version is obsolete, upgrade required!</source>
- <translation type="unfinished"/>
+ <translation>Upozornění: tahle verze je zastaralá, měl bys ji aktualizovat!</translation>
</message>
<message>
<location line="-41"/>
@@ -2567,7 +2573,7 @@ Adresa: %4
<message>
<location line="-18"/>
<source>Unable to bind to %s on this computer. Bitcoin is probably already running.</source>
- <translation type="unfinished"/>
+ <translation>Nedaří se mi připojit na %s na tomhle počítači. Bitcoin už pravděpodobně jednou běží.</translation>
</message>
<message>
<location line="+48"/>
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index fefefc7d62..08b0049b08 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -18,8 +18,7 @@ using namespace boost;
using namespace boost::assign;
using namespace json_spirit;
-void
-ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
+void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
{
txnouttype type;
vector<CTxDestination> addresses;
@@ -43,8 +42,7 @@ ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
out.push_back(Pair("addresses", a));
}
-void
-TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
+void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
{
entry.push_back(Pair("txid", tx.GetHash().GetHex()));
entry.push_back(Pair("version", tx.nVersion));
@@ -138,24 +136,40 @@ Value getrawtransaction(const Array& params, bool fHelp)
Value listunspent(const Array& params, bool fHelp)
{
- if (fHelp || params.size() > 2)
+ if (fHelp || params.size() > 3)
throw runtime_error(
- "listunspent [minconf=1] [maxconf=999999]\n"
+ "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n"
"Returns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n"
+ "Optionally filtered to only include txouts paid to specified addresses.\n"
"Results are an array of Objects, each of which has:\n"
"{txid, vout, scriptPubKey, amount, confirmations}");
- RPCTypeCheck(params, list_of(int_type)(int_type));
+ RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
int nMinDepth = 1;
if (params.size() > 0)
nMinDepth = params[0].get_int();
- int nMaxDepth = 999999;
+ int nMaxDepth = 9999999;
if (params.size() > 1)
nMaxDepth = params[1].get_int();
+ set<CBitcoinAddress> setAddress;
+ if (params.size() > 2)
+ {
+ Array inputs = params[2].get_array();
+ BOOST_FOREACH(Value& input, inputs)
+ {
+ CBitcoinAddress address(input.get_str());
+ if (!address.IsValid())
+ throw JSONRPCError(-5, string("Invalid Bitcoin address: ")+input.get_str());
+ if (setAddress.count(address))
+ throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+input.get_str());
+ setAddress.insert(address);
+ }
+ }
+
Array results;
vector<COutput> vecOutputs;
pwalletMain->AvailableCoins(vecOutputs, false);
@@ -164,6 +178,16 @@ Value listunspent(const Array& params, bool fHelp)
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
continue;
+ if(setAddress.size())
+ {
+ CTxDestination address;
+ if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
+ continue;
+
+ if (!setAddress.count(address))
+ continue;
+ }
+
int64 nValue = out.tx->vout[out.i].nValue;
const CScript& pk = out.tx->vout[out.i].scriptPubKey;
Object entry;
@@ -224,7 +248,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
{
CBitcoinAddress address(s.name_);
if (!address.IsValid())
- throw JSONRPCError(-5, string("Invalid Bitcoin address:")+s.name_);
+ throw JSONRPCError(-5, string("Invalid Bitcoin address: ")+s.name_);
if (setAddress.count(address))
throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 95fa6718d9..be83b85c15 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -15,16 +15,14 @@ using namespace std;
int64 nWalletUnlockTime;
static CCriticalSection cs_nWalletUnlockTime;
-std::string
-HelpRequiringPassphrase()
+std::string HelpRequiringPassphrase()
{
return pwalletMain->IsCrypted()
? "\nrequires wallet passphrase to be set with walletpassphrase first"
: "";
}
-void
-EnsureWalletIsUnlocked()
+void EnsureWalletIsUnlocked()
{
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
@@ -276,6 +274,37 @@ Value sendtoaddress(const Array& params, bool fHelp)
return wtx.GetHash().GetHex();
}
+Value listaddressgroupings(const Array& params, bool fHelp)
+{
+ if (fHelp)
+ throw runtime_error(
+ "listaddressgroupings\n"
+ "Lists groups of addresses which have had their common ownership\n"
+ "made public by common use as inputs or as the resulting change\n"
+ "in past transactions");
+
+ Array jsonGroupings;
+ map<CTxDestination, int64> balances = pwalletMain->GetAddressBalances();
+ BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
+ {
+ Array jsonGrouping;
+ BOOST_FOREACH(CTxDestination address, grouping)
+ {
+ Array addressInfo;
+ addressInfo.push_back(CBitcoinAddress(address).ToString());
+ addressInfo.push_back(ValueFromAmount(balances[address]));
+ {
+ LOCK(pwalletMain->cs_wallet);
+ if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
+ addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second);
+ }
+ jsonGrouping.push_back(addressInfo);
+ }
+ jsonGroupings.push_back(jsonGrouping);
+ }
+ return jsonGroupings;
+}
+
Value signmessage(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 2)
diff --git a/src/script.cpp b/src/script.cpp
index 8c35f0eed5..c34fbec82d 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -1127,8 +1127,7 @@ public:
return false;
}
- void
- Set(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)
+ void Set(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)
{
// DoS prevention: limit cache size to less than 10MB
// (~200 bytes per cache entry times 50,000 entries)
diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp
new file mode 100644
index 0000000000..d5cb8e8101
--- /dev/null
+++ b/src/test/allocator_tests.cpp
@@ -0,0 +1,115 @@
+#include <boost/test/unit_test.hpp>
+
+#include "init.h"
+#include "main.h"
+#include "util.h"
+
+BOOST_AUTO_TEST_SUITE(allocator_tests)
+
+// Dummy memory page locker for platform independent tests
+static const void *last_lock_addr, *last_unlock_addr;
+static size_t last_lock_len, last_unlock_len;
+class TestLocker
+{
+public:
+ bool Lock(const void *addr, size_t len)
+ {
+ last_lock_addr = addr;
+ last_lock_len = len;
+ return true;
+ }
+ bool Unlock(const void *addr, size_t len)
+ {
+ last_unlock_addr = addr;
+ last_unlock_len = len;
+ return true;
+ }
+};
+
+BOOST_AUTO_TEST_CASE(test_LockedPageManagerBase)
+{
+ const size_t test_page_size = 4096;
+ LockedPageManagerBase<TestLocker> lpm(test_page_size);
+ size_t addr;
+ last_lock_addr = last_unlock_addr = 0;
+ last_lock_len = last_unlock_len = 0;
+
+ /* Try large number of small objects */
+ addr = 0;
+ for(int i=0; i<1000; ++i)
+ {
+ lpm.LockRange(reinterpret_cast<void*>(addr), 33);
+ addr += 33;
+ }
+ /* Try small number of page-sized objects, straddling two pages */
+ addr = test_page_size*100 + 53;
+ for(int i=0; i<100; ++i)
+ {
+ lpm.LockRange(reinterpret_cast<void*>(addr), test_page_size);
+ addr += test_page_size;
+ }
+ /* Try small number of page-sized objects aligned to exactly one page */
+ addr = test_page_size*300;
+ for(int i=0; i<100; ++i)
+ {
+ lpm.LockRange(reinterpret_cast<void*>(addr), test_page_size);
+ addr += test_page_size;
+ }
+ /* one very large object, straddling pages */
+ lpm.LockRange(reinterpret_cast<void*>(test_page_size*600+1), test_page_size*500);
+ BOOST_CHECK(last_lock_addr == reinterpret_cast<void*>(test_page_size*(600+500)));
+ /* one very large object, page aligned */
+ lpm.LockRange(reinterpret_cast<void*>(test_page_size*1200), test_page_size*500-1);
+ BOOST_CHECK(last_lock_addr == reinterpret_cast<void*>(test_page_size*(1200+500-1)));
+
+ BOOST_CHECK(lpm.GetLockedPageCount() == (
+ (1000*33+test_page_size-1)/test_page_size + // small objects
+ 101 + 100 + // page-sized objects
+ 501 + 500)); // large objects
+ BOOST_CHECK((last_lock_len & (test_page_size-1)) == 0); // always lock entire pages
+ BOOST_CHECK(last_unlock_len == 0); // nothing unlocked yet
+
+ /* And unlock again */
+ addr = 0;
+ for(int i=0; i<1000; ++i)
+ {
+ lpm.UnlockRange(reinterpret_cast<void*>(addr), 33);
+ addr += 33;
+ }
+ addr = test_page_size*100 + 53;
+ for(int i=0; i<100; ++i)
+ {
+ lpm.UnlockRange(reinterpret_cast<void*>(addr), test_page_size);
+ addr += test_page_size;
+ }
+ addr = test_page_size*300;
+ for(int i=0; i<100; ++i)
+ {
+ lpm.UnlockRange(reinterpret_cast<void*>(addr), test_page_size);
+ addr += test_page_size;
+ }
+ lpm.UnlockRange(reinterpret_cast<void*>(test_page_size*600+1), test_page_size*500);
+ lpm.UnlockRange(reinterpret_cast<void*>(test_page_size*1200), test_page_size*500-1);
+
+ /* Check that everything is released */
+ BOOST_CHECK(lpm.GetLockedPageCount() == 0);
+
+ /* A few and unlocks of size zero (should have no effect) */
+ addr = 0;
+ for(int i=0; i<1000; ++i)
+ {
+ lpm.LockRange(reinterpret_cast<void*>(addr), 0);
+ addr += 1;
+ }
+ BOOST_CHECK(lpm.GetLockedPageCount() == 0);
+ addr = 0;
+ for(int i=0; i<1000; ++i)
+ {
+ lpm.UnlockRange(reinterpret_cast<void*>(addr), 0);
+ addr += 1;
+ }
+ BOOST_CHECK(lpm.GetLockedPageCount() == 0);
+ BOOST_CHECK((last_unlock_len & (test_page_size-1)) == 0); // always unlock entire pages
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/util.cpp b/src/util.cpp
index d6d9a368f0..461f42d177 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -86,6 +86,8 @@ void locking_callback(int mode, int i, const char* file, int line)
}
}
+LockedPageManager LockedPageManager::instance;
+
// Init
class CInit
{
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 5ca501b1af..dc019d4924 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -1608,6 +1608,129 @@ int64 CWallet::GetOldestKeyPoolTime()
return keypool.nTime;
}
+std::map<CTxDestination, int64> CWallet::GetAddressBalances()
+{
+ map<CTxDestination, int64> balances;
+
+ {
+ LOCK(cs_wallet);
+ BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
+ {
+ CWalletTx *pcoin = &walletEntry.second;
+
+ if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
+ continue;
+
+ if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
+ continue;
+
+ int nDepth = pcoin->GetDepthInMainChain();
+ if (nDepth < (pcoin->IsFromMe() ? 0 : 1))
+ continue;
+
+ for (unsigned int i = 0; i < pcoin->vout.size(); i++)
+ {
+ CTxDestination addr;
+ if (!IsMine(pcoin->vout[i]))
+ continue;
+ if(!ExtractDestination(pcoin->vout[i].scriptPubKey, addr))
+ continue;
+
+ int64 n = pcoin->IsSpent(i) ? 0 : pcoin->vout[i].nValue;
+
+ if (!balances.count(addr))
+ balances[addr] = 0;
+ balances[addr] += n;
+ }
+ }
+ }
+
+ return balances;
+}
+
+set< set<CTxDestination> > CWallet::GetAddressGroupings()
+{
+ set< set<CTxDestination> > groupings;
+ set<CTxDestination> grouping;
+
+ BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
+ {
+ CWalletTx *pcoin = &walletEntry.second;
+
+ if (pcoin->vin.size() > 0 && IsMine(pcoin->vin[0]))
+ {
+ // group all input addresses with each other
+ BOOST_FOREACH(CTxIn txin, pcoin->vin)
+ {
+ CTxDestination address;
+ if(!ExtractDestination(mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address))
+ continue;
+ grouping.insert(address);
+ }
+
+ // group change with input addresses
+ BOOST_FOREACH(CTxOut txout, pcoin->vout)
+ if (IsChange(txout))
+ {
+ CWalletTx tx = mapWallet[pcoin->vin[0].prevout.hash];
+ CTxDestination txoutAddr;
+ if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
+ continue;
+ grouping.insert(txoutAddr);
+ }
+ groupings.insert(grouping);
+ grouping.clear();
+ }
+
+ // group lone addrs by themselves
+ for (unsigned int i = 0; i < pcoin->vout.size(); i++)
+ if (IsMine(pcoin->vout[i]))
+ {
+ CTxDestination address;
+ if(!ExtractDestination(pcoin->vout[i].scriptPubKey, address))
+ continue;
+ grouping.insert(address);
+ groupings.insert(grouping);
+ grouping.clear();
+ }
+ }
+
+ set< set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
+ map< CTxDestination, set<CTxDestination>* > setmap; // map addresses to the unique group containing it
+ BOOST_FOREACH(set<CTxDestination> grouping, groupings)
+ {
+ // make a set of all the groups hit by this new group
+ set< set<CTxDestination>* > hits;
+ map< CTxDestination, set<CTxDestination>* >::iterator it;
+ BOOST_FOREACH(CTxDestination address, grouping)
+ if ((it = setmap.find(address)) != setmap.end())
+ hits.insert((*it).second);
+
+ // merge all hit groups into a new single group and delete old groups
+ set<CTxDestination>* merged = new set<CTxDestination>(grouping);
+ BOOST_FOREACH(set<CTxDestination>* hit, hits)
+ {
+ merged->insert(hit->begin(), hit->end());
+ uniqueGroupings.erase(hit);
+ delete hit;
+ }
+ uniqueGroupings.insert(merged);
+
+ // update setmap
+ BOOST_FOREACH(CTxDestination element, *merged)
+ setmap[element] = merged;
+ }
+
+ set< set<CTxDestination> > ret;
+ BOOST_FOREACH(set<CTxDestination>* uniqueGrouping, uniqueGroupings)
+ {
+ ret.insert(*uniqueGrouping);
+ delete uniqueGrouping;
+ }
+
+ return ret;
+}
+
CPubKey CReserveKey::GetReservedKey()
{
if (nIndex == -1)
diff --git a/src/wallet.h b/src/wallet.h
index 69badaf10d..44f8a17d37 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -176,6 +176,9 @@ public:
int64 GetOldestKeyPoolTime();
void GetAllReserveKeys(std::set<CKeyID>& setAddress);
+ std::set< std::set<CTxDestination> > GetAddressGroupings();
+ std::map<CTxDestination, int64> GetAddressBalances();
+
bool IsMine(const CTxIn& txin) const;
int64 GetDebit(const CTxIn& txin) const;
bool IsMine(const CTxOut& txout) const
@@ -319,9 +322,7 @@ public:
typedef std::map<std::string, std::string> mapValue_t;
-static
-void
-ReadOrderPos(int64& nOrderPos, mapValue_t& mapValue)
+static void ReadOrderPos(int64& nOrderPos, mapValue_t& mapValue)
{
if (!mapValue.count("n"))
{
@@ -332,9 +333,7 @@ ReadOrderPos(int64& nOrderPos, mapValue_t& mapValue)
}
-static
-void
-WriteOrderPos(const int64& nOrderPos, mapValue_t& mapValue)
+static void WriteOrderPos(const int64& nOrderPos, mapValue_t& mapValue)
{
if (nOrderPos == -1)
return;