Page MenuHomePhabricator

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index baca95a0b..acd81a6b2 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -1,366 +1,366 @@
#include <QtGlobal>
// Automatically generated by extract_strings_qt.py
#ifdef __GNUC__
#define UNUSED __attribute__((unused))
#else
#define UNUSED
#endif
static const char UNUSED *bitcoin_strings[] = {
QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin Core"),
QT_TRANSLATE_NOOP("bitcoin-core", "The %s developers"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"(1 = keep tx meta data e.g. account owner and payment request information, 2 "
"= drop tx meta data)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"-maxtxfee is set very high! Fees this large could be paid on a single "
"transaction."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"A fee rate (in %s/kB) that will be used when fee estimation has insufficient "
"data (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Accept connections from outside (default: 1 if no -proxy or -connect/-"
"noconnect)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Accept relayed transactions received from whitelisted peers even when not "
"relaying transactions (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Allow JSON-RPC connections from specified source. Valid for <ip> are a "
"single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or "
"a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Bind to given address and always listen on it. Use [host]:port notation for "
"IPv6"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Bind to given address and whitelist peers connecting to it. Use [host]:port "
"notation for IPv6"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Bind to given address to listen for JSON-RPC connections. Use [host]:port "
"notation for IPv6. This option can be specified multiple times (default: "
"bind to all interfaces)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot obtain a lock on data directory %s. %s is probably already running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Connect only to the specified node(s); -noconnect or -connect=0 alone to "
"disable automatic connections"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Create new files with system default permissions, instead of umask 077 (only "
"effective with disabled wallet functionality)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Delete all wallet transactions and only recover those parts of the "
"blockchain through -rescan on startup"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Discover own IP addresses (default: 1 when listening and no -externalip or -"
"proxy)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Distributed under the MIT software license, see the accompanying file %s or "
"%s"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Do not keep transactions in the mempool longer than <n> hours (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Equivalent bytes per sigop in transactions for relay and mining (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error loading %s: You can't enable HD on a already existing non-HD wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error reading %s! All keys read correctly, but transaction data or address "
"book entries might be missing or incorrect."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error: Listening for incoming connections failed (listen returned error %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Execute command when a relevant alert is received or we see a really long "
"fork (%s in cmd is replaced by message)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Execute command when a wallet transaction changes (%s in cmd is replaced by "
"TxID)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Execute command when the best block changes (%s in cmd is replaced by block "
"hash)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Fees (in %s/kB) smaller than this are considered zero fee for relaying, "
"mining and transaction creation (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Fees (in %s/kB) smaller than this are considered zero fee for transaction "
"creation (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Force relay of transactions from whitelisted peers even if they violate "
"local relay policy (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"How thorough the block verification of -checkblocks is (0-4, default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"If <category> is not supplied or if <category> = 1, output all debugging "
"information."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"If paytxfee is not set, include enough fee so transactions begin "
"confirmation on average within n blocks (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay "
"fee of %s to prevent stuck transactions)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Maintain a full transaction index, used by the getrawtransaction rpc call "
"(default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Maximum allowed median peer time offset adjustment. Local perspective of "
"time may be influenced by peers forward or backward by this amount. "
"(default: %u seconds)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Maximum size of data in data carrier transactions we relay and mine "
"(default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Maximum total fees (in %s) to use in a single wallet transaction or raw "
"transaction; setting this too low may abort large transactions (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Number of seconds to keep misbehaving peers from reconnecting (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Output debugging information (default: %u, supplying <category> is optional)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Please check that your computer's date and time are correct! If your clock "
"is wrong, %s will not work properly."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Please contribute if you find %s useful. Visit %s for further information "
"about the software."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Prune configured below the minimum of %d MiB. Please use a higher number."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Prune: last wallet synchronisation goes beyond pruned data. You need to -"
"reindex (download the whole blockchain again in case of pruned node)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Query for peer addresses via DNS lookup, if low on addresses (default: 1 "
"unless -connect/-noconnect)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Randomize credentials for every proxy connection. This enables Tor stream "
"isolation (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Reduce storage requirements by pruning (deleting) old blocks. This mode is "
"incompatible with -txindex and -rescan. Warning: Reverting this setting "
"requires re-downloading the entire blockchain. (default: 0 = disable pruning "
"blocks, >%u = target size in MiB to use for block files)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Rescans are not possible in pruned mode. You will need to use -reindex which "
"will download the whole blockchain again."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Set the number of script verification threads (%u to %d, 0 = auto, <0 = "
"leave that many cores free, default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Sets the serialization of raw transaction or block hex returned in non-"
"verbose mode, non-segwit(0) or segwit(1) (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Support filtering of blocks and transaction with bloom filters (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"The block database contains a block which appears to be from the future. "
"This may be due to your computer's date and time being set incorrectly. Only "
"rebuild the block database if you are sure that your computer's date and "
"time are correct"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"The transaction amount is too small to send after the fee has been deducted"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"This is the transaction fee you may pay when fee estimates are not available."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"This product includes software developed by the OpenSSL Project for use in "
"the OpenSSL Toolkit %s and cryptographic software written by Eric Young and "
"UPnP software written by Thomas Bernard."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Total length of network version string (%i) exceeds maximum length (%i). "
"Reduce the number or size of uacomments."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = "
"no limit (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unable to rewind the database to a pre-fork state. You will need to "
"redownload the blockchain"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unsupported argument -socks found. Setting SOCKS version isn't possible "
"anymore, only SOCKS5 proxies are supported."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/"
"or -whitelistforcerelay."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Use UPnP to map the listening port (default: 1 when listening and no -proxy)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Use hierarchical deterministic key generation (HD) after BIP32. Only has "
"effect during wallet creation/first start"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: "
"%s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Username and hashed password for JSON-RPC connections. The field <userpw> "
"comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is "
"included in share/rpcuser. This option can be specified multiple times"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Wallet will not create transactions that violate mempool chain limits "
-"(default: %u"),
+"(default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: Unknown block versions being mined! It's possible unknown rules are "
"in effect"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: Wallet file corrupt, data salvaged! Original %s saved as %s in %s; "
"if your balance or transactions are incorrect you should restore from a "
"backup."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR "
"notated network (e.g. 1.2.3.0/24). Can be specified multiple times."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Whitelisted peers cannot be DoS banned and their transactions are always "
"relayed, even if they are already in the mempool, useful e.g. for a gateway"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"You need to rebuild the database using -reindex to go back to unpruned "
"mode. This will redownload the entire blockchain"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"You need to rebuild the database using -reindex-chainstate to change -txindex"),
QT_TRANSLATE_NOOP("bitcoin-core", "%s corrupt, salvage failed"),
QT_TRANSLATE_NOOP("bitcoin-core", "%s is set very high!"),
QT_TRANSLATE_NOOP("bitcoin-core", "(default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "(default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "-maxmempool must be at least %d MB"),
QT_TRANSLATE_NOOP("bitcoin-core", "<category> can be:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Accept command line and JSON-RPC commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Accept public REST requests (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep the connection open"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"),
QT_TRANSLATE_NOOP("bitcoin-core", "Always query for peer addresses via DNS lookup (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Append comment to the user agent string"),
QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to recover private keys from a corrupt wallet on startup"),
QT_TRANSLATE_NOOP("bitcoin-core", "Automatically create Tor hidden service (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Block creation options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -%s address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write default address"),
QT_TRANSLATE_NOOP("bitcoin-core", "Change index out of range"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect through SOCKS5 proxy"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect to a node to retrieve peer addresses, and disconnect"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connection options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Copyright (C) %i-%i"),
QT_TRANSLATE_NOOP("bitcoin-core", "Corrupted block database detected"),
QT_TRANSLATE_NOOP("bitcoin-core", "Debugging/Testing options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Do not load the wallet and disable wallet RPC calls"),
QT_TRANSLATE_NOOP("bitcoin-core", "Do you want to rebuild the block database now?"),
QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"),
QT_TRANSLATE_NOOP("bitcoin-core", "Enable publish hash block in <address>"),
QT_TRANSLATE_NOOP("bitcoin-core", "Enable publish hash transaction in <address>"),
QT_TRANSLATE_NOOP("bitcoin-core", "Enable publish raw block in <address>"),
QT_TRANSLATE_NOOP("bitcoin-core", "Enable publish raw transaction in <address>"),
QT_TRANSLATE_NOOP("bitcoin-core", "Enable transaction replacement in the memory pool (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing wallet database environment %s!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Wallet corrupted"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Wallet requires newer version of %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: You can't disable HD on a already existing HD wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error reading from database, shutting down."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: A fatal internal error occurred, see debug.log for details"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."),
QT_TRANSLATE_NOOP("bitcoin-core", "Fee (in %s/kB) to add to transactions you send (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: %u, 0 = all)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Importing..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000??.dat file on startup"),
QT_TRANSLATE_NOOP("bitcoin-core", "Include IP addresses in debug output (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"),
QT_TRANSLATE_NOOP("bitcoin-core", "Information"),
QT_TRANSLATE_NOOP("bitcoin-core", "Initialization sanity check failed. %s is shutting down."),
QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -%s=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -fallbackfee=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Keep at most <n> unconnectable transactions in memory (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Keep the transaction memory pool below <n> megabytes (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Keypool ran out, please call keypoolrefill first"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on <port> (default: %u or testnet: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading banlist..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Location of the auth cookie (default: data dir)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maintain at most <n> connections to peers (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Make the wallet broadcast transactions"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Need to specify a port with -whitebind: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Node relay options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."),
QT_TRANSLATE_NOOP("bitcoin-core", "Only connect to nodes in network <net> (ipv4, ipv6 or onion)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Password for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Print this help message and exit"),
QT_TRANSLATE_NOOP("bitcoin-core", "Print version and exit"),
QT_TRANSLATE_NOOP("bitcoin-core", "Prune cannot be configured with a negative value."),
QT_TRANSLATE_NOOP("bitcoin-core", "Prune mode is incompatible with -txindex."),
QT_TRANSLATE_NOOP("bitcoin-core", "Pruning blockstore..."),
QT_TRANSLATE_NOOP("bitcoin-core", "RPC server options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rebuild chain state and block index from the blk*.dat files on disk"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rebuild chain state from the currently indexed blocks"),
QT_TRANSLATE_NOOP("bitcoin-core", "Reducing -maxconnections from %d to %d, because of system limitations."),
QT_TRANSLATE_NOOP("bitcoin-core", "Relay and mine data carrier transactions (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Relay non-P2SH multisig (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions on startup"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Rewinding blocks..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to console instead of debug.log file"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send transactions as zero-fee transactions if possible (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send transactions with full-RBF opt-in enabled (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set database cache size in megabytes (%d to %d, default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to <n> (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum BIP141 block weight (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum block size in bytes (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set the number of threads to service RPC calls (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Show all debugging options (usage: --help -help-debug)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Shrink debug.log file on client startup (default: 1 when no -debug)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Signing transaction failed"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify configuration file (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout in milliseconds (minimum: 1, default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify data directory"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify wallet file (within data directory)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify your own public address"),
QT_TRANSLATE_NOOP("bitcoin-core", "Spend unconfirmed change when sending transactions (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Starting network threads..."),
QT_TRANSLATE_NOOP("bitcoin-core", "The source code is available from %s."),
QT_TRANSLATE_NOOP("bitcoin-core", "The transaction amount is too small to pay the fee"),
QT_TRANSLATE_NOOP("bitcoin-core", "The wallet will avoid paying less than the minimum relay fee."),
QT_TRANSLATE_NOOP("bitcoin-core", "This is experimental software."),
QT_TRANSLATE_NOOP("bitcoin-core", "This is the minimum transaction fee you pay on every transaction."),
QT_TRANSLATE_NOOP("bitcoin-core", "This is the transaction fee you will pay if you send a transaction."),
QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Tor control port password (default: empty)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Tor control port to use if onion listening enabled (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amount too small"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amounts must not be negative"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction has too long of a mempool chain"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction must have at least one recipient"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large for fee policy"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer. %s is probably already running."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to start HTTP server. See debug log for details."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -benchmark ignored, use -debug=bench."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -debugnet ignored, use -debug=net."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -tor found, use -onion."),
QT_TRANSLATE_NOOP("bitcoin-core", "Upgrade wallet to latest format on startup"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "User Agent comment (%s) contains unsafe characters."),
QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Verifying blocks..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet %s resides outside data directory %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet debugging/testing options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart %s to complete"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Warning"),
QT_TRANSLATE_NOOP("bitcoin-core", "Warning: unknown new rules activated (versionbit %i)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Whether to operate in a blocks only mode (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Zapping all transactions from wallet..."),
QT_TRANSLATE_NOOP("bitcoin-core", "ZeroMQ notification options:"),
};
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 8132e4fe0..94b1b8abe 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -1,1001 +1,1001 @@
// Copyright (c) 2011-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "guiutil.h"
#include "bitcoinaddressvalidator.h"
#include "bitcoinunits.h"
#include "qvalidatedlineedit.h"
#include "walletmodel.h"
#include "primitives/transaction.h"
#include "init.h"
#include "validation.h" // For minRelayTxFee
#include "protocol.h"
#include "script/script.h"
#include "script/standard.h"
#include "util.h"
#ifdef WIN32
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#ifdef _WIN32_IE
#undef _WIN32_IE
#endif
#define _WIN32_IE 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "shellapi.h"
#include "shlobj.h"
#include "shlwapi.h"
#endif
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#if BOOST_FILESYSTEM_VERSION >= 3
#include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
#endif
#include <boost/scoped_array.hpp>
#include <QAbstractItemView>
#include <QApplication>
#include <QClipboard>
#include <QDateTime>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QDoubleValidator>
#include <QFileDialog>
#include <QFont>
#include <QLineEdit>
#include <QSettings>
#include <QTextDocument> // for Qt::mightBeRichText
#include <QThread>
#include <QMouseEvent>
#if QT_VERSION < 0x050000
#include <QUrl>
#else
#include <QUrlQuery>
#endif
#if QT_VERSION >= 0x50200
#include <QFontDatabase>
#endif
#if BOOST_FILESYSTEM_VERSION >= 3
static boost::filesystem::detail::utf8_codecvt_facet utf8;
#endif
#if defined(Q_OS_MAC)
extern double NSAppKitVersionNumber;
#if !defined(NSAppKitVersionNumber10_8)
#define NSAppKitVersionNumber10_8 1187
#endif
#if !defined(NSAppKitVersionNumber10_9)
#define NSAppKitVersionNumber10_9 1265
#endif
#endif
namespace GUIUtil {
QString dateTimeStr(const QDateTime &date)
{
return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm");
}
QString dateTimeStr(qint64 nTime)
{
return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
}
QFont fixedPitchFont()
{
#if QT_VERSION >= 0x50200
return QFontDatabase::systemFont(QFontDatabase::FixedFont);
#else
QFont font("Monospace");
#if QT_VERSION >= 0x040800
font.setStyleHint(QFont::Monospace);
#else
font.setStyleHint(QFont::TypeWriter);
#endif
return font;
#endif
}
// Just some dummy data to generate an convincing random-looking (but consistent) address
static const uint8_t dummydata[] = {0xeb,0x15,0x23,0x1d,0xfc,0xeb,0x60,0x92,0x58,0x86,0xb6,0x7d,0x06,0x52,0x99,0x92,0x59,0x15,0xae,0xb1,0x72,0xc0,0x66,0x47};
// Generate a dummy address with invalid CRC, starting with the network prefix.
static std::string DummyAddress(const CChainParams &params)
{
std::vector<unsigned char> sourcedata = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
sourcedata.insert(sourcedata.end(), dummydata, dummydata + sizeof(dummydata));
for(int i=0; i<256; ++i) { // Try every trailing byte
std::string s = EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size());
if (!CBitcoinAddress(s).IsValid())
return s;
sourcedata[sourcedata.size()-1] += 1;
}
return "";
}
void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
{
parent->setFocusProxy(widget);
widget->setFont(fixedPitchFont());
#if QT_VERSION >= 0x040700
// We don't want translators to use own addresses in translations
// and this is the only place, where this address is supplied.
widget->setPlaceholderText(QObject::tr("Enter a Bitcoin address (e.g. %1)").arg(
QString::fromStdString(DummyAddress(Params()))));
#endif
widget->setValidator(new BitcoinAddressEntryValidator(parent));
widget->setCheckValidator(new BitcoinAddressCheckValidator(parent));
}
void setupAmountWidget(QLineEdit *widget, QWidget *parent)
{
QDoubleValidator *amountValidator = new QDoubleValidator(parent);
amountValidator->setDecimals(8);
amountValidator->setBottom(0.0);
widget->setValidator(amountValidator);
widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
}
bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
{
// return if URI is not valid or is no bitcoin: URI
if(!uri.isValid() || uri.scheme() != QString("bitcoin"))
return false;
SendCoinsRecipient rv;
rv.address = uri.path();
// Trim any following forward slash which may have been added by the OS
if (rv.address.endsWith("/")) {
rv.address.truncate(rv.address.length() - 1);
}
rv.amount = 0;
#if QT_VERSION < 0x050000
QList<QPair<QString, QString> > items = uri.queryItems();
#else
QUrlQuery uriQuery(uri);
QList<QPair<QString, QString> > items = uriQuery.queryItems();
#endif
for (QList<QPair<QString, QString> >::iterator i = items.begin(); i != items.end(); i++)
{
bool fShouldReturnFalse = false;
if (i->first.startsWith("req-"))
{
i->first.remove(0, 4);
fShouldReturnFalse = true;
}
if (i->first == "label")
{
rv.label = i->second;
fShouldReturnFalse = false;
}
if (i->first == "message")
{
rv.message = i->second;
fShouldReturnFalse = false;
}
else if (i->first == "amount")
{
if(!i->second.isEmpty())
{
if(!BitcoinUnits::parse(BitcoinUnits::BTC, i->second, &rv.amount))
{
return false;
}
}
fShouldReturnFalse = false;
}
if (fShouldReturnFalse)
return false;
}
if(out)
{
*out = rv;
}
return true;
}
bool parseBitcoinURI(QString uri, SendCoinsRecipient *out)
{
// Convert bitcoin:// to bitcoin:
//
// Cannot handle this later, because bitcoin:// will cause Qt to see the part after // as host,
// which will lower-case it (and thus invalidate the address).
if(uri.startsWith("bitcoin://", Qt::CaseInsensitive))
{
uri.replace(0, 10, "bitcoin:");
}
QUrl uriInstance(uri);
return parseBitcoinURI(uriInstance, out);
}
QString formatBitcoinURI(const SendCoinsRecipient &info)
{
QString ret = QString("bitcoin:%1").arg(info.address);
int paramCount = 0;
if (info.amount)
{
ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnits::BTC, info.amount, false, BitcoinUnits::separatorNever));
paramCount++;
}
if (!info.label.isEmpty())
{
QString lbl(QUrl::toPercentEncoding(info.label));
ret += QString("%1label=%2").arg(paramCount == 0 ? "?" : "&").arg(lbl);
paramCount++;
}
if (!info.message.isEmpty())
{
QString msg(QUrl::toPercentEncoding(info.message));
ret += QString("%1message=%2").arg(paramCount == 0 ? "?" : "&").arg(msg);
paramCount++;
}
return ret;
}
bool isDust(const QString& address, const CAmount& amount)
{
CTxDestination dest = CBitcoinAddress(address.toStdString()).Get();
CScript script = GetScriptForDestination(dest);
CTxOut txOut(amount, script);
return txOut.IsDust(::minRelayTxFee);
}
QString HtmlEscape(const QString& str, bool fMultiLine)
{
#if QT_VERSION < 0x050000
QString escaped = Qt::escape(str);
#else
QString escaped = str.toHtmlEscaped();
#endif
if(fMultiLine)
{
escaped = escaped.replace("\n", "<br>\n");
}
return escaped;
}
QString HtmlEscape(const std::string& str, bool fMultiLine)
{
return HtmlEscape(QString::fromStdString(str), fMultiLine);
}
void copyEntryData(QAbstractItemView *view, int column, int role)
{
if(!view || !view->selectionModel())
return;
QModelIndexList selection = view->selectionModel()->selectedRows(column);
if(!selection.isEmpty())
{
// Copy first item
setClipboard(selection.at(0).data(role).toString());
}
}
QList<QModelIndex> getEntryData(QAbstractItemView *view, int column)
{
if(!view || !view->selectionModel())
return QList<QModelIndex>();
return view->selectionModel()->selectedRows(column);
}
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
const QString &filter,
QString *selectedSuffixOut)
{
QString selectedFilter;
QString myDir;
if(dir.isEmpty()) // Default to user documents location
{
#if QT_VERSION < 0x050000
myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
#else
myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
#endif
}
else
{
myDir = dir;
}
/* Directly convert path to native OS path separators */
QString result = QDir::toNativeSeparators(QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter));
/* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
QString selectedSuffix;
if(filter_re.exactMatch(selectedFilter))
{
selectedSuffix = filter_re.cap(1);
}
/* Add suffix if needed */
QFileInfo info(result);
if(!result.isEmpty())
{
if(info.suffix().isEmpty() && !selectedSuffix.isEmpty())
{
/* No suffix specified, add selected suffix */
if(!result.endsWith("."))
result.append(".");
result.append(selectedSuffix);
}
}
/* Return selected suffix if asked to */
if(selectedSuffixOut)
{
*selectedSuffixOut = selectedSuffix;
}
return result;
}
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir,
const QString &filter,
QString *selectedSuffixOut)
{
QString selectedFilter;
QString myDir;
if(dir.isEmpty()) // Default to user documents location
{
#if QT_VERSION < 0x050000
myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
#else
myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
#endif
}
else
{
myDir = dir;
}
/* Directly convert path to native OS path separators */
QString result = QDir::toNativeSeparators(QFileDialog::getOpenFileName(parent, caption, myDir, filter, &selectedFilter));
if(selectedSuffixOut)
{
/* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
QString selectedSuffix;
if(filter_re.exactMatch(selectedFilter))
{
selectedSuffix = filter_re.cap(1);
}
*selectedSuffixOut = selectedSuffix;
}
return result;
}
Qt::ConnectionType blockingGUIThreadConnection()
{
if(QThread::currentThread() != qApp->thread())
{
return Qt::BlockingQueuedConnection;
}
else
{
return Qt::DirectConnection;
}
}
bool checkPoint(const QPoint &p, const QWidget *w)
{
QWidget *atW = QApplication::widgetAt(w->mapToGlobal(p));
if (!atW) return false;
return atW->topLevelWidget() == w;
}
bool isObscured(QWidget *w)
{
return !(checkPoint(QPoint(0, 0), w)
&& checkPoint(QPoint(w->width() - 1, 0), w)
&& checkPoint(QPoint(0, w->height() - 1), w)
&& checkPoint(QPoint(w->width() - 1, w->height() - 1), w)
&& checkPoint(QPoint(w->width() / 2, w->height() / 2), w));
}
void openDebugLogfile()
{
boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
/* Open debug.log with the associated application */
if (boost::filesystem::exists(pathDebug))
QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathDebug)));
}
void SubstituteFonts(const QString& language)
{
#if defined(Q_OS_MAC)
// Background:
// OSX's default font changed in 10.9 and Qt is unable to find it with its
// usual fallback methods when building against the 10.7 sdk or lower.
// The 10.8 SDK added a function to let it find the correct fallback font.
// If this fallback is not properly loaded, some characters may fail to
// render correctly.
//
// The same thing happened with 10.10. .Helvetica Neue DeskInterface is now default.
//
// Solution: If building with the 10.7 SDK or lower and the user's platform
// is 10.9 or higher at runtime, substitute the correct font. This needs to
// happen before the QApplication is created.
#if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_8)
{
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_9)
/* On a 10.9 - 10.9.x system */
QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande");
else
{
/* 10.10 or later system */
if (language == "zh_CN" || language == "zh_TW" || language == "zh_HK") // traditional or simplified Chinese
QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Heiti SC");
else if (language == "ja") // Japanesee
QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Songti SC");
else
QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Lucida Grande");
}
}
#endif
#endif
}
ToolTipToRichTextFilter::ToolTipToRichTextFilter(int _size_threshold, QObject *parent) :
QObject(parent),
size_threshold(_size_threshold)
{
}
bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt)
{
if(evt->type() == QEvent::ToolTipChange)
{
QWidget *widget = static_cast<QWidget*>(obj);
QString tooltip = widget->toolTip();
if(tooltip.size() > size_threshold && !tooltip.startsWith("<qt") && !Qt::mightBeRichText(tooltip))
{
// Envelop with <qt></qt> to make sure Qt detects this as rich text
// Escape the current message as HTML and replace \n by <br>
tooltip = "<qt>" + HtmlEscape(tooltip, true) + "</qt>";
widget->setToolTip(tooltip);
return true;
}
}
return QObject::eventFilter(obj, evt);
}
void TableViewLastColumnResizingFixer::connectViewHeadersSignals()
{
connect(tableView->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(on_sectionResized(int,int,int)));
connect(tableView->horizontalHeader(), SIGNAL(geometriesChanged()), this, SLOT(on_geometriesChanged()));
}
// We need to disconnect these while handling the resize events, otherwise we can enter infinite loops.
void TableViewLastColumnResizingFixer::disconnectViewHeadersSignals()
{
disconnect(tableView->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(on_sectionResized(int,int,int)));
disconnect(tableView->horizontalHeader(), SIGNAL(geometriesChanged()), this, SLOT(on_geometriesChanged()));
}
// Setup the resize mode, handles compatibility for Qt5 and below as the method signatures changed.
// Refactored here for readability.
void TableViewLastColumnResizingFixer::setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode)
{
#if QT_VERSION < 0x050000
tableView->horizontalHeader()->setResizeMode(logicalIndex, resizeMode);
#else
tableView->horizontalHeader()->setSectionResizeMode(logicalIndex, resizeMode);
#endif
}
void TableViewLastColumnResizingFixer::resizeColumn(int nColumnIndex, int width)
{
tableView->setColumnWidth(nColumnIndex, width);
tableView->horizontalHeader()->resizeSection(nColumnIndex, width);
}
int TableViewLastColumnResizingFixer::getColumnsWidth()
{
int nColumnsWidthSum = 0;
for (int i = 0; i < columnCount; i++)
{
nColumnsWidthSum += tableView->horizontalHeader()->sectionSize(i);
}
return nColumnsWidthSum;
}
int TableViewLastColumnResizingFixer::getAvailableWidthForColumn(int column)
{
int nResult = lastColumnMinimumWidth;
int nTableWidth = tableView->horizontalHeader()->width();
if (nTableWidth > 0)
{
int nOtherColsWidth = getColumnsWidth() - tableView->horizontalHeader()->sectionSize(column);
nResult = std::max(nResult, nTableWidth - nOtherColsWidth);
}
return nResult;
}
// Make sure we don't make the columns wider than the tables viewport width.
void TableViewLastColumnResizingFixer::adjustTableColumnsWidth()
{
disconnectViewHeadersSignals();
resizeColumn(lastColumnIndex, getAvailableWidthForColumn(lastColumnIndex));
connectViewHeadersSignals();
int nTableWidth = tableView->horizontalHeader()->width();
int nColsWidth = getColumnsWidth();
if (nColsWidth > nTableWidth)
{
resizeColumn(secondToLastColumnIndex,getAvailableWidthForColumn(secondToLastColumnIndex));
}
}
// Make column use all the space available, useful during window resizing.
void TableViewLastColumnResizingFixer::stretchColumnWidth(int column)
{
disconnectViewHeadersSignals();
resizeColumn(column, getAvailableWidthForColumn(column));
connectViewHeadersSignals();
}
// When a section is resized this is a slot-proxy for ajustAmountColumnWidth().
void TableViewLastColumnResizingFixer::on_sectionResized(int logicalIndex, int oldSize, int newSize)
{
adjustTableColumnsWidth();
int remainingWidth = getAvailableWidthForColumn(logicalIndex);
if (newSize > remainingWidth)
{
resizeColumn(logicalIndex, remainingWidth);
}
}
// When the tabless geometry is ready, we manually perform the stretch of the "Message" column,
// as the "Stretch" resize mode does not allow for interactive resizing.
void TableViewLastColumnResizingFixer::on_geometriesChanged()
{
if ((getColumnsWidth() - this->tableView->horizontalHeader()->width()) != 0)
{
disconnectViewHeadersSignals();
resizeColumn(secondToLastColumnIndex, getAvailableWidthForColumn(secondToLastColumnIndex));
connectViewHeadersSignals();
}
}
/**
* Initializes all internal variables and prepares the
* the resize modes of the last 2 columns of the table and
*/
TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth, QObject *parent) :
QObject(parent),
tableView(table),
lastColumnMinimumWidth(lastColMinimumWidth),
allColumnsMinimumWidth(allColsMinimumWidth)
{
columnCount = tableView->horizontalHeader()->count();
lastColumnIndex = columnCount - 1;
secondToLastColumnIndex = columnCount - 2;
tableView->horizontalHeader()->setMinimumSectionSize(allColumnsMinimumWidth);
setViewHeaderResizeMode(secondToLastColumnIndex, QHeaderView::Interactive);
setViewHeaderResizeMode(lastColumnIndex, QHeaderView::Interactive);
}
#ifdef WIN32
boost::filesystem::path static StartupShortcutPath()
{
std::string chain = ChainNameFromCommandLine();
if (chain == CBaseChainParams::MAIN)
return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin.lnk";
if (chain == CBaseChainParams::TESTNET) // Remove this special case when CBaseChainParams::TESTNET = "testnet4"
return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin (testnet).lnk";
return GetSpecialFolderPath(CSIDL_STARTUP) / strprintf("Bitcoin (%s).lnk", chain);
}
bool GetStartOnSystemStartup()
{
// check for Bitcoin*.lnk
return boost::filesystem::exists(StartupShortcutPath());
}
bool SetStartOnSystemStartup(bool fAutoStart)
{
// If the shortcut exists already, remove it for updating
boost::filesystem::remove(StartupShortcutPath());
if (fAutoStart)
{
CoInitialize(NULL);
// Get a pointer to the IShellLink interface.
IShellLink* psl = NULL;
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER, IID_IShellLink,
reinterpret_cast<void**>(&psl));
if (SUCCEEDED(hres))
{
// Get the current executable path
TCHAR pszExePath[MAX_PATH];
GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
// Start client minimized
QString strArgs = "-min";
// Set -testnet /-regtest options
strArgs += QString::fromStdString(strprintf(" -testnet=%d -regtest=%d", GetBoolArg("-testnet", false), GetBoolArg("-regtest", false)));
#ifdef UNICODE
boost::scoped_array<TCHAR> args(new TCHAR[strArgs.length() + 1]);
// Convert the QString to TCHAR*
strArgs.toWCharArray(args.get());
// Add missing '\0'-termination to string
args[strArgs.length()] = '\0';
#endif
// Set the path to the shortcut target
psl->SetPath(pszExePath);
PathRemoveFileSpec(pszExePath);
psl->SetWorkingDirectory(pszExePath);
psl->SetShowCmd(SW_SHOWMINNOACTIVE);
#ifndef UNICODE
psl->SetArguments(strArgs.toStdString().c_str());
#else
psl->SetArguments(args.get());
#endif
// Query IShellLink for the IPersistFile interface for
// saving the shortcut in persistent storage.
IPersistFile* ppf = NULL;
hres = psl->QueryInterface(IID_IPersistFile, reinterpret_cast<void**>(&ppf));
if (SUCCEEDED(hres))
{
WCHAR pwsz[MAX_PATH];
// Ensure that the string is ANSI.
MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH);
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(pwsz, TRUE);
ppf->Release();
psl->Release();
CoUninitialize();
return true;
}
psl->Release();
}
CoUninitialize();
return false;
}
return true;
}
#elif defined(Q_OS_LINUX)
// Follow the Desktop Application Autostart Spec:
// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
boost::filesystem::path static GetAutostartDir()
{
namespace fs = boost::filesystem;
char* pszConfigHome = getenv("XDG_CONFIG_HOME");
if (pszConfigHome) return fs::path(pszConfigHome) / "autostart";
char* pszHome = getenv("HOME");
if (pszHome) return fs::path(pszHome) / ".config" / "autostart";
return fs::path();
}
boost::filesystem::path static GetAutostartFilePath()
{
std::string chain = ChainNameFromCommandLine();
if (chain == CBaseChainParams::MAIN)
return GetAutostartDir() / "bitcoin.desktop";
return GetAutostartDir() / strprintf("bitcoin-%s.lnk", chain);
}
bool GetStartOnSystemStartup()
{
boost::filesystem::ifstream optionFile(GetAutostartFilePath());
if (!optionFile.good())
return false;
// Scan through file for "Hidden=true":
std::string line;
while (!optionFile.eof())
{
getline(optionFile, line);
if (line.find("Hidden") != std::string::npos &&
line.find("true") != std::string::npos)
return false;
}
optionFile.close();
return true;
}
bool SetStartOnSystemStartup(bool fAutoStart)
{
if (!fAutoStart)
boost::filesystem::remove(GetAutostartFilePath());
else
{
char pszExePath[MAX_PATH+1];
memset(pszExePath, 0, sizeof(pszExePath));
if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
return false;
boost::filesystem::create_directories(GetAutostartDir());
boost::filesystem::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc);
if (!optionFile.good())
return false;
std::string chain = ChainNameFromCommandLine();
// Write a bitcoin.desktop file to the autostart directory:
optionFile << "[Desktop Entry]\n";
optionFile << "Type=Application\n";
if (chain == CBaseChainParams::MAIN)
optionFile << "Name=Bitcoin\n";
else
optionFile << strprintf("Name=Bitcoin (%s)\n", chain);
optionFile << "Exec=" << pszExePath << strprintf(" -min -testnet=%d -regtest=%d\n", GetBoolArg("-testnet", false), GetBoolArg("-regtest", false));
optionFile << "Terminal=false\n";
optionFile << "Hidden=false\n";
optionFile.close();
}
return true;
}
#elif defined(Q_OS_MAC)
// based on: https://github.com/Mozketo/LaunchAtLoginController/blob/master/LaunchAtLoginController.m
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl);
LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl)
{
// loop through the list of startup items and try to find the bitcoin app
CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(list, NULL);
for(int i = 0; i < CFArrayGetCount(listSnapshot); i++) {
LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(listSnapshot, i);
UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
CFURLRef currentItemURL = NULL;
#if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED >= 10100
if(&LSSharedFileListItemCopyResolvedURL)
currentItemURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, NULL);
#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED < 10100
else
LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, NULL);
#endif
#else
LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, NULL);
#endif
if(currentItemURL && CFEqual(currentItemURL, findUrl)) {
// found
CFRelease(currentItemURL);
return item;
}
if(currentItemURL) {
CFRelease(currentItemURL);
}
}
return NULL;
}
bool GetStartOnSystemStartup()
{
CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
return !!foundItem; // return boolified object
}
bool SetStartOnSystemStartup(bool fAutoStart)
{
CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
if(fAutoStart && !foundItem) {
// add bitcoin app to startup item list
LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, NULL, NULL, bitcoinAppUrl, NULL, NULL);
}
else if(!fAutoStart && foundItem) {
// remove item
LSSharedFileListItemRemove(loginItems, foundItem);
}
return true;
}
#else
bool GetStartOnSystemStartup() { return false; }
bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
#endif
void saveWindowGeometry(const QString& strSetting, QWidget *parent)
{
QSettings settings;
settings.setValue(strSetting + "Pos", parent->pos());
settings.setValue(strSetting + "Size", parent->size());
}
void restoreWindowGeometry(const QString& strSetting, const QSize& defaultSize, QWidget *parent)
{
QSettings settings;
QPoint pos = settings.value(strSetting + "Pos").toPoint();
QSize size = settings.value(strSetting + "Size", defaultSize).toSize();
if (!pos.x() && !pos.y()) {
QRect screen = QApplication::desktop()->screenGeometry();
pos.setX((screen.width() - size.width()) / 2);
pos.setY((screen.height() - size.height()) / 2);
}
parent->resize(size);
parent->move(pos);
}
void setClipboard(const QString& str)
{
QApplication::clipboard()->setText(str, QClipboard::Clipboard);
QApplication::clipboard()->setText(str, QClipboard::Selection);
}
#if BOOST_FILESYSTEM_VERSION >= 3
boost::filesystem::path qstringToBoostPath(const QString &path)
{
return boost::filesystem::path(path.toStdString(), utf8);
}
QString boostPathToQString(const boost::filesystem::path &path)
{
return QString::fromStdString(path.string(utf8));
}
#else
#warning Conversion between boost path and QString can use invalid character encoding with boost_filesystem v2 and older
boost::filesystem::path qstringToBoostPath(const QString &path)
{
return boost::filesystem::path(path.toStdString());
}
QString boostPathToQString(const boost::filesystem::path &path)
{
return QString::fromStdString(path.string());
}
#endif
QString formatDurationStr(int secs)
{
QStringList strList;
int days = secs / 86400;
int hours = (secs % 86400) / 3600;
int mins = (secs % 3600) / 60;
int seconds = secs % 60;
if (days)
strList.append(QString(QObject::tr("%1 d")).arg(days));
if (hours)
strList.append(QString(QObject::tr("%1 h")).arg(hours));
if (mins)
strList.append(QString(QObject::tr("%1 m")).arg(mins));
if (seconds || (!days && !hours && !mins))
strList.append(QString(QObject::tr("%1 s")).arg(seconds));
return strList.join(" ");
}
QString formatServicesStr(quint64 mask)
{
QStringList strList;
// Just scan the last 8 bits for now.
for (int i = 0; i < 8; i++) {
uint64_t check = 1 << i;
if (mask & check)
{
switch (check)
{
case NODE_NETWORK:
strList.append("NETWORK");
break;
case NODE_GETUTXO:
strList.append("GETUTXO");
break;
case NODE_BLOOM:
strList.append("BLOOM");
break;
case NODE_WITNESS:
strList.append("WITNESS");
break;
case NODE_XTHIN:
strList.append("XTHIN");
break;
default:
strList.append(QString("%1[%2]").arg("UNKNOWN").arg(check));
}
}
}
if (strList.size())
return strList.join(" & ");
else
return QObject::tr("None");
}
QString formatPingTime(double dPingTime)
{
return (dPingTime == std::numeric_limits<int64_t>::max()/1e6 || dPingTime == 0) ? QObject::tr("N/A") : QString(QObject::tr("%1 ms")).arg(QString::number((int)(dPingTime * 1000), 10));
}
QString formatTimeOffset(int64_t nTimeOffset)
{
return QString(QObject::tr("%1 s")).arg(QString::number((int)nTimeOffset, 10));
}
QString formateNiceTimeOffset(qint64 secs)
{
// Represent time from last generated block in human readable text
QString timeBehindText;
const int HOUR_IN_SECONDS = 60*60;
const int DAY_IN_SECONDS = 24*60*60;
const int WEEK_IN_SECONDS = 7*24*60*60;
const int YEAR_IN_SECONDS = 31556952; // Average length of year in Gregorian calendar
if(secs < 60)
{
- timeBehindText = QObject::tr("%n seconds(s)","",secs);
+ timeBehindText = QObject::tr("%n second(s)","",secs);
}
else if(secs < 2*HOUR_IN_SECONDS)
{
- timeBehindText = QObject::tr("%n minutes(s)","",secs/60);
+ timeBehindText = QObject::tr("%n minute(s)","",secs/60);
}
else if(secs < 2*DAY_IN_SECONDS)
{
timeBehindText = QObject::tr("%n hour(s)","",secs/HOUR_IN_SECONDS);
}
else if(secs < 2*WEEK_IN_SECONDS)
{
timeBehindText = QObject::tr("%n day(s)","",secs/DAY_IN_SECONDS);
}
else if(secs < YEAR_IN_SECONDS)
{
timeBehindText = QObject::tr("%n week(s)","",secs/WEEK_IN_SECONDS);
}
else
{
qint64 years = secs / YEAR_IN_SECONDS;
qint64 remainder = secs % YEAR_IN_SECONDS;
timeBehindText = QObject::tr("%1 and %2").arg(QObject::tr("%n year(s)", "", years)).arg(QObject::tr("%n week(s)","", remainder/WEEK_IN_SECONDS));
}
return timeBehindText;
}
void ClickableLabel::mouseReleaseEvent(QMouseEvent *event)
{
Q_EMIT clicked(event->pos());
}
void ClickableProgressBar::mouseReleaseEvent(QMouseEvent *event)
{
Q_EMIT clicked(event->pos());
}
} // namespace GUIUtil
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 2d0cccb89..83dbeffd4 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -1,4952 +1,4952 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en">
<context>
<name>AddressBookPage</name>
<message>
<location filename="../forms/addressbookpage.ui" line="+30"/>
<source>Right-click to edit address or label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+27"/>
<source>Create a new address</source>
<translation>Create a new address</translation>
</message>
<message>
<location line="+3"/>
<source>&amp;New</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+14"/>
<source>Copy the currently selected address to the system clipboard</source>
<translation>Copy the currently selected address to the system clipboard</translation>
</message>
<message>
<location line="+3"/>
<source>&amp;Copy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+67"/>
<source>C&amp;lose</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-53"/>
<source>Delete the currently selected address from the list</source>
<translation>Delete the currently selected address from the list</translation>
</message>
<message>
<location line="+30"/>
<source>Export the data in the current tab to a file</source>
<translation>Export the data in the current tab to a file</translation>
</message>
<message>
<location line="+3"/>
<source>&amp;Export</source>
<translation>&amp;Export</translation>
</message>
<message>
<location line="-30"/>
<source>&amp;Delete</source>
<translation>&amp;Delete</translation>
</message>
<message>
<location filename="../addressbookpage.cpp" line="+50"/>
<source>Choose the address to send coins to</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Choose the address to receive coins with</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>C&amp;hoose</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Sending addresses</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Receiving addresses</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>&amp;Copy Address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy &amp;Label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>&amp;Edit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+193"/>
<source>Export Address List</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Comma separated file (*.csv)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+13"/>
<source>Exporting Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>There was an error trying to save the address list to %1. Please try again.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>AddressTableModel</name>
<message>
<location filename="../addresstablemodel.cpp" line="+170"/>
<source>Label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+36"/>
<source>(no label)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>AskPassphraseDialog</name>
<message>
<location filename="../forms/askpassphrasedialog.ui" line="+26"/>
<source>Passphrase Dialog</source>
<translation>Passphrase Dialog</translation>
</message>
<message>
<location line="+30"/>
<source>Enter passphrase</source>
<translation>Enter passphrase</translation>
</message>
<message>
<location line="+14"/>
<source>New passphrase</source>
<translation>New passphrase</translation>
</message>
<message>
<location line="+14"/>
<source>Repeat new passphrase</source>
<translation>Repeat new passphrase</translation>
</message>
<message>
<location filename="../askpassphrasedialog.cpp" line="+46"/>
<source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Encrypt wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>Unlock wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>This operation needs your wallet passphrase to decrypt the wallet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>Decrypt wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Change passphrase</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Enter the old passphrase and new passphrase to the wallet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+44"/>
<source>Confirm wallet encryption</source>
<translation type="unfinished"></translation>
</message>
<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>
</message>
<message>
<location line="+0"/>
<source>Are you sure you wish to encrypt your wallet?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<location line="+58"/>
<source>Wallet encrypted</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-56"/>
<source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<location line="+7"/>
<location line="+42"/>
<location line="+6"/>
<source>Wallet encryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-54"/>
<source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<location line="+48"/>
<source>The supplied passphrases do not match.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-37"/>
<source>Wallet unlock failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<location line="+11"/>
<location line="+19"/>
<source>The passphrase entered for the wallet decryption was incorrect.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-20"/>
<source>Wallet decryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+14"/>
<source>Wallet passphrase was successfully changed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+47"/>
<location line="+24"/>
<source>Warning: The Caps Lock key is on!</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>BanTableModel</name>
<message>
<location filename="../bantablemodel.cpp" line="+89"/>
<source>IP/Netmask</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Banned Until</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>BitcoinGUI</name>
<message>
<location filename="../bitcoingui.cpp" line="+356"/>
<source>Sign &amp;message...</source>
<translation>Sign &amp;message...</translation>
</message>
<message>
<location line="+417"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
<location line="-495"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
<message>
<location line="-143"/>
<source>Node</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+144"/>
<source>Show general overview of wallet</source>
<translation>Show general overview of wallet</translation>
</message>
<message>
<location line="+28"/>
<source>&amp;Transactions</source>
<translation>&amp;Transactions</translation>
</message>
<message>
<location line="+1"/>
<source>Browse transaction history</source>
<translation>Browse transaction history</translation>
</message>
<message>
<location line="+23"/>
<source>E&amp;xit</source>
<translation>E&amp;xit</translation>
</message>
<message>
<location line="+1"/>
<source>Quit application</source>
<translation>Quit application</translation>
</message>
<message>
<location line="+3"/>
<source>&amp;About %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Show information about %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>About &amp;Qt</source>
<translation>About &amp;Qt</translation>
</message>
<message>
<location line="+1"/>
<source>Show information about Qt</source>
<translation>Show information about Qt</translation>
</message>
<message>
<location line="+2"/>
<source>&amp;Options...</source>
<translation>&amp;Options...</translation>
</message>
<message>
<location line="+1"/>
<source>Modify configuration options for %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Encrypt Wallet...</translation>
</message>
<message>
<location line="+3"/>
<source>&amp;Backup Wallet...</source>
<translation>&amp;Backup Wallet...</translation>
</message>
<message>
<location line="+2"/>
<source>&amp;Change Passphrase...</source>
<translation>&amp;Change Passphrase...</translation>
</message>
<message>
<location line="+12"/>
<source>&amp;Sending addresses...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>&amp;Receiving addresses...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Open &amp;URI...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+357"/>
<source>Click to disable network activity.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Network activity disabled.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Click to enable network activity again.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+53"/>
<source>Reindexing blocks on disk...</source>
<translation>Reindexing blocks on disk...</translation>
</message>
<message>
<location line="-497"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
<message>
<location line="+67"/>
<source>Backup wallet to another location</source>
<translation>Backup wallet to another location</translation>
</message>
<message>
<location line="+2"/>
<source>Change the passphrase used for wallet encryption</source>
<translation>Change the passphrase used for wallet encryption</translation>
</message>
<message>
<location line="+6"/>
<source>&amp;Debug window</source>
<translation>&amp;Debug window</translation>
</message>
<message>
<location line="+1"/>
<source>Open debugging and diagnostic console</source>
<translation>Open debugging and diagnostic console</translation>
</message>
<message>
<location line="-4"/>
<source>&amp;Verify message...</source>
<translation>&amp;Verify message...</translation>
</message>
<message>
<location line="+504"/>
<source>Bitcoin</source>
<translation>Bitcoin</translation>
</message>
<message>
<location line="-729"/>
<source>Wallet</source>
<translation>Wallet</translation>
</message>
<message>
<location line="+152"/>
<source>&amp;Send</source>
<translation>&amp;Send</translation>
</message>
<message>
<location line="+11"/>
<source>&amp;Receive</source>
<translation>&amp;Receive</translation>
</message>
<message>
<location line="+50"/>
<source>&amp;Show / Hide</source>
<translation>&amp;Show / Hide</translation>
</message>
<message>
<location line="+1"/>
<source>Show or hide the main Window</source>
<translation>Show or hide the main Window</translation>
</message>
<message>
<location line="+3"/>
<source>Encrypt the private keys that belong to your wallet</source>
<translation>Encrypt the private keys that belong to your wallet</translation>
</message>
<message>
<location line="+7"/>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
<translation>Sign messages with your Bitcoin addresses to prove you own them</translation>
</message>
<message>
<location line="+2"/>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
<translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation>
</message>
<message>
<location line="+58"/>
<source>&amp;File</source>
<translation>&amp;File</translation>
</message>
<message>
<location line="+14"/>
<source>&amp;Settings</source>
<translation>&amp;Settings</translation>
</message>
<message>
<location line="+9"/>
<source>&amp;Help</source>
<translation>&amp;Help</translation>
</message>
<message>
<location line="+15"/>
<source>Tabs toolbar</source>
<translation>Tabs toolbar</translation>
</message>
<message>
<location line="-158"/>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+70"/>
<source>Show the list of used sending addresses and labels</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Show the list of used receiving addresses and labels</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Open a bitcoin: URI or payment request</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>&amp;Command-line options</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location line="+354"/>
<source>%n active connection(s) to Bitcoin network</source>
<translation>
<numerusform>%n active connection to Bitcoin network</numerusform>
<numerusform>%n active connections to Bitcoin network</numerusform>
</translation>
</message>
<message>
<location line="+49"/>
<source>Indexing blocks on disk...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Processing blocks on disk...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+11"/>
<source>No block source available...</source>
<translation>No block source available...</translation>
</message>
<message numerus="yes">
<location line="+9"/>
<source>Processed %n block(s) of transaction history.</source>
<translation>
<numerusform>Processed %n block of transaction history.</numerusform>
<numerusform>Processed %n blocks of transaction history.</numerusform>
</translation>
</message>
<message>
<location line="+24"/>
<source>%1 behind</source>
<translation>%1 behind</translation>
</message>
<message>
<location line="+24"/>
<source>Last received block was generated %1 ago.</source>
<translation>Last received block was generated %1 ago.</translation>
</message>
<message>
<location line="+2"/>
<source>Transactions after this will not yet be visible.</source>
<translation>Transactions after this will not yet be visible.</translation>
</message>
<message>
<location line="+27"/>
<source>Error</source>
<translation>Error</translation>
</message>
<message>
<location line="+3"/>
<source>Warning</source>
<translation>Warning</translation>
</message>
<message>
<location line="+3"/>
<source>Information</source>
<translation>Information</translation>
</message>
<message>
<location line="-78"/>
<source>Up to date</source>
<translation>Up to date</translation>
</message>
<message>
<location line="-428"/>
<source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+197"/>
<source>%1 client</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+255"/>
<source>Catching up...</source>
<translation>Catching up...</translation>
</message>
<message>
<location line="+145"/>
<source>Date: %1
</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Amount: %1
</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Type: %1
</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Label: %1
</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Address: %1
</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Sent transaction</source>
<translation>Sent transaction</translation>
</message>
<message>
<location line="+0"/>
<source>Incoming transaction</source>
<translation>Incoming transaction</translation>
</message>
<message>
<location line="+52"/>
<source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+19"/>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</translation>
</message>
<message>
<location line="+8"/>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</translation>
</message>
</context>
<context>
<name>CoinControlDialog</name>
<message>
<location filename="../forms/coincontroldialog.ui" line="+14"/>
<source>Coin Selection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+34"/>
<source>Quantity:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+29"/>
<source>Bytes:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+45"/>
<source>Amount:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+80"/>
<source>Fee:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-48"/>
<source>Dust:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+93"/>
<source>After Fee:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+32"/>
<source>Change:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+56"/>
<source>(un)select all</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+16"/>
<source>Tree mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+13"/>
<source>List mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+56"/>
<source>Amount</source>
<translation type="unfinished">Amount</translation>
</message>
<message>
<location line="+5"/>
<source>Received with label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>Received with address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
<message>
<location line="+5"/>
<source>Confirmations</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Confirmed</source>
<translation type="unfinished">Confirmed</translation>
</message>
<message>
<location filename="../coincontroldialog.cpp" line="+54"/>
<source>Copy address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<location line="+26"/>
<source>Copy amount</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-25"/>
<source>Copy transaction ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Lock unspent</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Unlock unspent</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+22"/>
<source>Copy quantity</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Copy fee</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy after fee</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy bytes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy dust</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy change</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+325"/>
<source>(%1 locked)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+183"/>
<source>yes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>no</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+14"/>
<source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>Can vary +/- %1 satoshi(s) per input.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+42"/>
<location line="+52"/>
<source>(no label)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-7"/>
<source>change from %1 (%2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>(change)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EditAddressDialog</name>
<message>
<location filename="../forms/editaddressdialog.ui" line="+14"/>
<source>Edit Address</source>
<translation>Edit Address</translation>
</message>
<message>
<location line="+11"/>
<source>&amp;Label</source>
<translation>&amp;Label</translation>
</message>
<message>
<location line="+10"/>
<source>The label associated with this address list entry</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+17"/>
<source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-10"/>
<source>&amp;Address</source>
<translation>&amp;Address</translation>
</message>
<message>
<location filename="../editaddressdialog.cpp" line="+28"/>
<source>New receiving address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>New sending address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Edit receiving address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Edit sending address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+71"/>
<source>The entered address &quot;%1&quot; is not a valid Bitcoin address.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>The entered address &quot;%1&quot; is already in the address book.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>Could not unlock wallet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>New key generation failed.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>FreespaceChecker</name>
<message>
<location filename="../intro.cpp" line="+78"/>
<source>A new data directory will be created.</source>
<translation>A new data directory will be created.</translation>
</message>
<message>
<location line="+22"/>
<source>name</source>
<translation>name</translation>
</message>
<message>
<location line="+2"/>
<source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
<translation>Directory already exists. Add %1 if you intend to create a new directory here.</translation>
</message>
<message>
<location line="+3"/>
<source>Path already exists, and is not a directory.</source>
<translation>Path already exists, and is not a directory.</translation>
</message>
<message>
<location line="+7"/>
<source>Cannot create data directory here.</source>
<translation>Cannot create data directory here.</translation>
</message>
</context>
<context>
<name>HelpMessageDialog</name>
<message>
<location filename="../utilitydialog.cpp" line="+40"/>
<source>version</source>
<translation type="unfinished">version</translation>
</message>
<message>
<location line="+5"/>
<location line="+2"/>
<source>(%1-bit)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>About %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+19"/>
<source>Command-line options</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Usage:</source>
<translation type="unfinished">Usage:</translation>
</message>
<message>
<location line="+1"/>
<source>command-line options</source>
<translation type="unfinished">command-line options</translation>
</message>
<message>
<location line="+9"/>
<source>UI Options:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Choose data directory on startup (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Set language, for example &quot;de_DE&quot; (default: system locale)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Start minimized</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Set SSL root certificates for payment request (default: -system-)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Show splash screen on startup (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Reset all settings changed in the GUI</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Intro</name>
<message>
<location filename="../forms/intro.ui" line="+14"/>
<source>Welcome</source>
<translation>Welcome</translation>
</message>
<message>
<location line="+9"/>
<source>Welcome to %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+26"/>
<source>As this is the first time the program is launched, you can choose where %1 will store its data.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>%1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>Use the default data directory</source>
<translation>Use the default data directory</translation>
</message>
<message>
<location line="+7"/>
<source>Use a custom data directory:</source>
<translation>Use a custom data directory:</translation>
</message>
<message>
<location filename="../intro.cpp" line="+89"/>
<source>Error: Specified data directory &quot;%1&quot; cannot be created.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+26"/>
<source>Error</source>
<translation>Error</translation>
</message>
<message numerus="yes">
<location line="+9"/>
<source>%n GB of free space available</source>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <translation>
+ <numerusform>%n GB of free space available</numerusform>
+ <numerusform>%n GB of free space available</numerusform>
</translation>
</message>
<message numerus="yes">
<location line="+3"/>
<source>(of %n GB needed)</source>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <translation>
+ <numerusform>(of %n GB needed)</numerusform>
+ <numerusform>(of %n GB needed)</numerusform>
</translation>
</message>
</context>
<context>
<name>ModalOverlay</name>
<message>
<location filename="../forms/modaloverlay.ui" line="+14"/>
<source>Form</source>
<translation type="unfinished">Form</translation>
</message>
<message>
<location line="+119"/>
<source>Recent transactions may not yet be visible, and therefore your wallet&apos;s balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+19"/>
<source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+63"/>
<source>Number of blocks left</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<location line="+26"/>
<location filename="../modaloverlay.cpp" line="+136"/>
<source>Unknown...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-13"/>
<source>Last block time</source>
<translation type="unfinished">Last block time</translation>
</message>
<message>
<location line="+26"/>
<source>Progress</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>~</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+25"/>
<source>Progress increase per hour</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<location line="+20"/>
<source>calculating...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-7"/>
<source>Estimated time left until synced</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+37"/>
<source>Hide</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../modaloverlay.cpp" line="-1"/>
<source>Unknown. Syncing Headers (%1)...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OpenURIDialog</name>
<message>
<location filename="../forms/openuridialog.ui" line="+14"/>
<source>Open URI</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Open payment request from URI or file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>URI:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>Select payment request file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../openuridialog.cpp" line="+47"/>
<source>Select payment request file to open</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OptionsDialog</name>
<message>
<location filename="../forms/optionsdialog.ui" line="+14"/>
<source>Options</source>
<translation>Options</translation>
</message>
<message>
<location line="+13"/>
<source>&amp;Main</source>
<translation>&amp;Main</translation>
</message>
<message>
<location line="+6"/>
<source>Automatically start %1 after logging in to the system.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>&amp;Start %1 on system login</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>Size of &amp;database cache</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+16"/>
<source>MB</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+27"/>
<source>Number of script &amp;verification threads</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+114"/>
<source>Accept connections from outside</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Allow incoming connections</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+44"/>
<location line="+187"/>
<source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+94"/>
<source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+80"/>
<location line="+13"/>
<source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-10"/>
<source>Third party transaction URLs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+41"/>
<source>Active command-line options that override above options:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+43"/>
<source>Reset all client options to default.</source>
<translation>Reset all client options to default.</translation>
</message>
<message>
<location line="+3"/>
<source>&amp;Reset Options</source>
<translation>&amp;Reset Options</translation>
</message>
<message>
<location line="-514"/>
<source>&amp;Network</source>
<translation>&amp;Network</translation>
</message>
<message>
<location line="-85"/>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+36"/>
<source>W&amp;allet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Expert</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>Enable coin &amp;control features</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>&amp;Spend unconfirmed change</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+30"/>
<source>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
<translation>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</translation>
</message>
<message>
<location line="+3"/>
<source>Map port using &amp;UPnP</source>
<translation>Map port using &amp;UPnP</translation>
</message>
<message>
<location line="+17"/>
<source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<location line="+187"/>
<source>Proxy &amp;IP:</source>
<translation>Proxy &amp;IP:</translation>
</message>
<message>
<location line="-155"/>
<location line="+187"/>
<source>&amp;Port:</source>
<translation>&amp;Port:</translation>
</message>
<message>
<location line="-162"/>
<location line="+187"/>
<source>Port of the proxy (e.g. 9050)</source>
<translation>Port of the proxy (e.g. 9050)</translation>
</message>
<message>
<location line="-163"/>
<source>Used for reaching peers via:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+13"/>
<location line="+23"/>
<location line="+23"/>
<source>Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-36"/>
<source>IPv4</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>IPv6</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Tor</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+25"/>
<source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Use separate SOCKS5 proxy to reach peers via Tor hidden services:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+102"/>
<source>&amp;Window</source>
<translation>&amp;Window</translation>
</message>
<message>
<location line="+6"/>
<source>&amp;Hide the icon from the system tray.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Hide tray icon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Show only a tray icon after minimizing the window.</source>
<translation>Show only a tray icon after minimizing the window.</translation>
</message>
<message>
<location line="+3"/>
<source>&amp;Minimize to the tray instead of the taskbar</source>
<translation>&amp;Minimize to the tray instead of the taskbar</translation>
</message>
<message>
<location line="+10"/>
<source>M&amp;inimize on close</source>
<translation>M&amp;inimize on close</translation>
</message>
<message>
<location line="+21"/>
<source>&amp;Display</source>
<translation>&amp;Display</translation>
</message>
<message>
<location line="+8"/>
<source>User Interface &amp;language:</source>
<translation>User Interface &amp;language:</translation>
</message>
<message>
<location line="+13"/>
<source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+11"/>
<source>&amp;Unit to show amounts in:</source>
<translation>&amp;Unit to show amounts in:</translation>
</message>
<message>
<location line="+13"/>
<source>Choose the default subdivision unit to show in the interface and when sending coins.</source>
<translation>Choose the default subdivision unit to show in the interface and when sending coins.</translation>
</message>
<message>
<location line="-450"/>
<source>Whether to show coin control features or not.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+612"/>
<source>&amp;OK</source>
<translation>&amp;OK</translation>
</message>
<message>
<location line="+13"/>
<source>&amp;Cancel</source>
<translation>&amp;Cancel</translation>
</message>
<message>
<location filename="../optionsdialog.cpp" line="+86"/>
<source>default</source>
<translation>default</translation>
</message>
<message>
<location line="+64"/>
<source>none</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+72"/>
<source>Confirm options reset</source>
<translation>Confirm options reset</translation>
</message>
<message>
<location line="+1"/>
<location line="+43"/>
<source>Client restart required to activate changes.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-43"/>
<source>Client will be shut down. Do you want to proceed?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+47"/>
<source>This change would require a client restart.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+25"/>
<source>The supplied proxy address is invalid.</source>
<translation>The supplied proxy address is invalid.</translation>
</message>
</context>
<context>
<name>OverviewPage</name>
<message>
<location filename="../forms/overviewpage.ui" line="+14"/>
<source>Form</source>
<translation>Form</translation>
</message>
<message>
<location line="+62"/>
<location line="+386"/>
<source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source>
<translation>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</translation>
</message>
<message>
<location line="-139"/>
<source>Watch-only:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>Available:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+16"/>
<source>Your current spendable balance</source>
<translation>Your current spendable balance</translation>
</message>
<message>
<location line="+41"/>
<source>Pending:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-236"/>
<source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
<translation>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</translation>
</message>
<message>
<location line="+112"/>
<source>Immature:</source>
<translation>Immature:</translation>
</message>
<message>
<location line="-29"/>
<source>Mined balance that has not yet matured</source>
<translation>Mined balance that has not yet matured</translation>
</message>
<message>
<location line="-177"/>
<source>Balances</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+161"/>
<source>Total:</source>
<translation>Total:</translation>
</message>
<message>
<location line="+61"/>
<source>Your current total balance</source>
<translation>Your current total balance</translation>
</message>
<message>
<location line="+92"/>
<source>Your current balance in watch-only addresses</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Spendable:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+49"/>
<source>Recent transactions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-317"/>
<source>Unconfirmed transactions to watch-only addresses</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+50"/>
<source>Mined balance in watch-only addresses that has not yet matured</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+128"/>
<source>Current total balance in watch-only addresses</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PaymentServer</name>
<message>
<location filename="../paymentserver.cpp" line="+328"/>
<location line="+216"/>
<location line="+42"/>
<location line="+113"/>
<location line="+14"/>
<location line="+18"/>
<source>Payment request error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-402"/>
<source>Cannot start bitcoin: click-to-pay handler</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+103"/>
<location line="+14"/>
<location line="+7"/>
<source>URI handling</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-20"/>
<source>Payment request fetch URL is invalid: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+13"/>
<source>Invalid payment address %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+13"/>
<source>Payment request file handling</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+61"/>
<location line="+9"/>
<location line="+31"/>
<location line="+10"/>
<location line="+17"/>
<location line="+88"/>
<source>Payment request rejected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-155"/>
<source>Payment request network doesn&apos;t match client network.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>Payment request expired.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Payment request is not initialized.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+26"/>
<source>Unverified payment requests to custom payment scripts are unsupported.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<location line="+17"/>
<source>Invalid payment request.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-10"/>
<source>Requested payment amount of %1 is too small (considered dust).</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+55"/>
<source>Refund from %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+44"/>
<source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>Error communicating with %1: %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+20"/>
<source>Payment request cannot be parsed!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+13"/>
<source>Bad response from server %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+22"/>
<source>Network request error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+11"/>
<source>Payment acknowledged</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PeerTableModel</name>
<message>
<location filename="../peertablemodel.cpp" line="+117"/>
<source>User Agent</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Node/Service</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>NodeId</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Ping</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../bitcoinunits.cpp" line="+176"/>
<source>Amount</source>
<translation type="unfinished">Amount</translation>
</message>
<message>
<location filename="../guiutil.cpp" line="+136"/>
<source>Enter a Bitcoin address (e.g. %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+759"/>
<source>%1 d</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>%1 h</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>%1 m</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<location line="+50"/>
<source>%1 s</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-10"/>
<source>None</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>N/A</source>
<translation type="unfinished">N/A</translation>
</message>
<message>
<location line="+0"/>
<source>%1 ms</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location line="+18"/>
- <source>%n seconds(s)</source>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <source>%n second(s)</source>
+ <translation>
+ <numerusform>%n second</numerusform>
+ <numerusform>%n seconds</numerusform>
</translation>
</message>
<message numerus="yes">
<location line="+4"/>
- <source>%n minutes(s)</source>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <source>%n minute(s)</source>
+ <translation>
+ <numerusform>%n minute</numerusform>
+ <numerusform>%n minutes</numerusform>
</translation>
</message>
<message numerus="yes">
<location line="+4"/>
<source>%n hour(s)</source>
<translation type="unfinished">
<numerusform>%n hour</numerusform>
<numerusform>%n hours</numerusform>
</translation>
</message>
<message numerus="yes">
<location line="+4"/>
<source>%n day(s)</source>
<translation type="unfinished">
<numerusform>%n day</numerusform>
<numerusform>%n days</numerusform>
</translation>
</message>
<message numerus="yes">
<location line="+4"/>
<location line="+6"/>
<source>%n week(s)</source>
<translation type="unfinished">
<numerusform>%n week</numerusform>
<numerusform>%n weeks</numerusform>
</translation>
</message>
<message>
<location line="+0"/>
<source>%1 and %2</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location line="+0"/>
<source>%n year(s)</source>
<translation type="unfinished">
<numerusform>%n year</numerusform>
<numerusform>%n years</numerusform>
</translation>
</message>
</context>
<context>
<name>QRImageWidget</name>
<message>
<location filename="../receiverequestdialog.cpp" line="+36"/>
<source>&amp;Save Image...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>&amp;Copy Image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+32"/>
<source>Save QR Code</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>PNG Image (*.png)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RPCConsole</name>
<message>
<location filename="../forms/debugwindow.ui" line="+56"/>
<location line="+26"/>
<location line="+26"/>
<location line="+23"/>
<location line="+26"/>
<location line="+36"/>
<location line="+23"/>
<location line="+36"/>
<location line="+23"/>
<location line="+36"/>
<location line="+23"/>
<location line="+663"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
<location line="+26"/>
<location line="+23"/>
<location line="+23"/>
<source>N/A</source>
<translation>N/A</translation>
</message>
<message>
<location line="-1345"/>
<source>Client version</source>
<translation>Client version</translation>
</message>
<message>
<location line="-22"/>
<source>&amp;Information</source>
<translation>&amp;Information</translation>
</message>
<message>
<location line="-10"/>
<source>Debug window</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+25"/>
<source>General</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+56"/>
<source>Using BerkeleyDB version</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+26"/>
<source>Datadir</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+26"/>
<source>Startup time</source>
<translation>Startup time</translation>
</message>
<message>
<location line="+29"/>
<source>Network</source>
<translation>Network</translation>
</message>
<message>
<location line="+7"/>
<source>Name</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Number of connections</source>
<translation>Number of connections</translation>
</message>
<message>
<location line="+29"/>
<source>Block chain</source>
<translation>Block chain</translation>
</message>
<message>
<location line="+7"/>
<source>Current number of blocks</source>
<translation>Current number of blocks</translation>
</message>
<message>
<location line="+52"/>
<source>Memory Pool</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Current number of transactions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Memory usage</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+404"/>
<location line="+558"/>
<source>Received</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-478"/>
<location line="+455"/>
<source>Sent</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-414"/>
<source>&amp;Peers</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+53"/>
<source>Banned peers</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+60"/>
<location filename="../rpcconsole.cpp" line="+400"/>
<location line="+692"/>
<source>Select a peer to view detailed information.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+25"/>
<source>Whitelisted</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Direction</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Version</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+69"/>
<source>Starting Block</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Synced Headers</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Synced Blocks</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-1079"/>
<location line="+987"/>
<source>User Agent</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-684"/>
<source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+68"/>
<source>Decrease font size</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+29"/>
<source>Increase font size</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+610"/>
<source>Services</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+92"/>
<source>Ban Score</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Connection Time</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Last Send</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Last Receive</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+69"/>
<source>Ping Time</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>The duration of a currently outstanding ping.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Ping Wait</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Min Ping</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Time Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-1116"/>
<source>Last block time</source>
<translation>Last block time</translation>
</message>
<message>
<location line="+110"/>
<source>&amp;Open</source>
<translation>&amp;Open</translation>
</message>
<message>
<location line="+26"/>
<source>&amp;Console</source>
<translation>&amp;Console</translation>
</message>
<message>
<location line="+195"/>
<source>&amp;Network Traffic</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+52"/>
<source>&amp;Clear</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+16"/>
<source>Totals</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../rpcconsole.cpp" line="-386"/>
<source>In:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Out:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../forms/debugwindow.ui" line="-299"/>
<source>Debug log file</source>
<translation>Debug log file</translation>
</message>
<message>
<location line="+136"/>
<source>Clear console</source>
<translation>Clear console</translation>
</message>
<message>
<location filename="../rpcconsole.cpp" line="-214"/>
<source>1 &amp;hour</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>1 &amp;day</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>1 &amp;week</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>1 &amp;year</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-4"/>
<source>&amp;Disconnect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<location line="+1"/>
<location line="+1"/>
<location line="+1"/>
<source>Ban for</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+48"/>
<source>&amp;Unban</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+126"/>
<source>Welcome to the %1 RPC console.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</source>
<translation>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</translation>
</message>
<message>
<location line="+1"/>
<source>Type &lt;b&gt;help&lt;/b&gt; for an overview of available commands.</source>
<translation>Type &lt;b&gt;help&lt;/b&gt; for an overview of available commands.</translation>
</message>
<message>
<location line="+2"/>
<source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+36"/>
<source>Network activity disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+123"/>
<source>%1 B</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>%1 KB</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>%1 MB</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>%1 GB</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+99"/>
<source>(node id: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>via %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<location line="+1"/>
<source>never</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>Inbound</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Outbound</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Yes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>No</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+12"/>
<location line="+6"/>
<source>Unknown</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ReceiveCoinsDialog</name>
<message>
<location filename="../forms/receivecoinsdialog.ui" line="+107"/>
<source>&amp;Amount:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-16"/>
<source>&amp;Label:</source>
<translation type="unfinished">&amp;Label:</translation>
</message>
<message>
<location line="-37"/>
<source>&amp;Message:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-20"/>
<source>Reuse one of the previously used receiving addresses. Reusing addresses has security and privacy issues. Do not use this unless re-generating a payment request made before.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>R&amp;euse an existing receiving address (not recommended)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+14"/>
<location line="+23"/>
<source>An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-7"/>
<location line="+21"/>
<source>An optional label to associate with the new receiving address.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-7"/>
<source>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<location line="+22"/>
<source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+32"/>
<source>Clear all fields of the form.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Clear</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+75"/>
<source>Requested payments history</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-95"/>
<source>&amp;Request payment</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+120"/>
<source>Show the selected request (does the same as double clicking an entry)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Show</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+17"/>
<source>Remove the selected entries from the list</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Remove</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../receivecoinsdialog.cpp" line="+47"/>
<source>Copy URI</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy message</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy amount</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
<location filename="../forms/receiverequestdialog.ui" line="+29"/>
<source>QR Code</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+46"/>
<source>Copy &amp;URI</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>Copy &amp;Address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>&amp;Save Image...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../receiverequestdialog.cpp" line="+65"/>
<source>Request payment to %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Payment information</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>URI</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Amount</source>
<translation type="unfinished">Amount</translation>
</message>
<message>
<location line="+2"/>
<source>Label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>Resulting URI too long, try to reduce the text for label / message.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>Error encoding URI into QR Code.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RecentRequestsTableModel</name>
<message>
<location filename="../recentrequeststablemodel.cpp" line="+29"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
<message>
<location line="+0"/>
<source>Label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+40"/>
<source>(no label)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>(no message)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>(no amount requested)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+42"/>
<source>Requested</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SendCoinsDialog</name>
<message>
<location filename="../forms/sendcoinsdialog.ui" line="+14"/>
<location filename="../sendcoinsdialog.cpp" line="+553"/>
<source>Send Coins</source>
<translation>Send Coins</translation>
</message>
<message>
<location line="+76"/>
<source>Coin Control Features</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+20"/>
<source>Inputs...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>automatically selected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+19"/>
<source>Insufficient funds!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+89"/>
<source>Quantity:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+35"/>
<source>Bytes:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+48"/>
<source>Amount:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+80"/>
<source>Fee:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+51"/>
<source>After Fee:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+32"/>
<source>Change:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+44"/>
<source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Custom change address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+206"/>
<source>Transaction Fee:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+14"/>
<source>Choose...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+37"/>
<source>collapse fee-settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+54"/>
<source>per kilobyte</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-3"/>
<location line="+16"/>
<source>If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then &quot;per kilobyte&quot; only pays 250 satoshis in fee, while &quot;total at least&quot; pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-64"/>
<source>Hide</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+67"/>
<source>total at least</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+30"/>
<location line="+13"/>
<source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>(read the tooltip)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+29"/>
<source>Recommended:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+30"/>
<source>Custom:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+52"/>
<source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+89"/>
<source>normal</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+40"/>
<source>fast</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+102"/>
<source>Send to multiple recipients at once</source>
<translation>Send to multiple recipients at once</translation>
</message>
<message>
<location line="+3"/>
<source>Add &amp;Recipient</source>
<translation>Add &amp;Recipient</translation>
</message>
<message>
<location line="-20"/>
<source>Clear all fields of the form.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-876"/>
<source>Dust:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+691"/>
<source>Confirmation time target:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+80"/>
<source>(count)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+108"/>
<source>Clear &amp;All</source>
<translation>Clear &amp;All</translation>
</message>
<message>
<location line="+55"/>
<source>Balance:</source>
<translation>Balance:</translation>
</message>
<message>
<location line="-84"/>
<source>Confirm the send action</source>
<translation>Confirm the send action</translation>
</message>
<message>
<location line="+3"/>
<source>S&amp;end</source>
<translation>S&amp;end</translation>
</message>
<message>
<location filename="../sendcoinsdialog.cpp" line="-486"/>
<source>Copy quantity</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy amount</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy fee</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy after fee</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy bytes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy dust</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy change</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+205"/>
<location line="+5"/>
<location line="+5"/>
<location line="+4"/>
<source>%1 to %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Are you sure you want to send?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>added as transaction fee</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+15"/>
<source>Total Amount %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>or</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Confirm send coins</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+191"/>
<source>The recipient address is not valid. Please recheck.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>The amount to pay must be larger than 0.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>The amount exceeds your balance.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>The total exceeds your balance when the %1 transaction fee is included.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Duplicate address found: addresses should only be used once each.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Transaction creation failed!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>The transaction was rejected with the following reason: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Payment request expired.</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location line="+67"/>
<source>%n block(s)</source>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <translation>
+ <numerusform>%n block</numerusform>
+ <numerusform>%n blocks</numerusform>
</translation>
</message>
<message>
<location line="+28"/>
<source>Pay only the required fee of %1</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location line="+25"/>
<source>Estimated to begin confirmation within %n block(s).</source>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <translation>
+ <numerusform>Estimated to begin confirmation within %n block.</numerusform>
+ <numerusform>Estimated to begin confirmation within %n blocks.</numerusform>
</translation>
</message>
<message>
<location line="+102"/>
<source>Warning: Invalid Bitcoin address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>Warning: Unknown change address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+11"/>
<source>(no label)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SendCoinsEntry</name>
<message>
<location filename="../forms/sendcoinsentry.ui" line="+155"/>
<location line="+539"/>
<location line="+533"/>
<source>A&amp;mount:</source>
<translation>A&amp;mount:</translation>
</message>
<message>
<location line="-1185"/>
<source>Pay &amp;To:</source>
<translation>Pay &amp;To:</translation>
</message>
<message>
<location line="+93"/>
<source>&amp;Label:</source>
<translation>&amp;Label:</translation>
</message>
<message>
<location line="-68"/>
<source>Choose previously used address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-46"/>
<source>This is a normal payment.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+39"/>
<source>The Bitcoin address to send the payment to</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Alt+A</source>
<translation>Alt+A</translation>
</message>
<message>
<location line="+7"/>
<source>Paste address from clipboard</source>
<translation>Paste address from clipboard</translation>
</message>
<message>
<location line="+16"/>
<source>Alt+P</source>
<translation>Alt+P</translation>
</message>
<message>
<location line="+7"/>
<location line="+548"/>
<location line="+533"/>
<source>Remove this entry</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-1021"/>
<source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>S&amp;ubtract fee from amount</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>Message:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+443"/>
<source>This is an unauthenticated payment request.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+529"/>
<source>This is an authenticated payment request.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-1009"/>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+47"/>
<source>A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+448"/>
<location line="+529"/>
<source>Pay To:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-495"/>
<location line="+533"/>
<source>Memo:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../sendcoinsentry.cpp" line="+37"/>
<source>Enter a label for this address to add it to your address book</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SendConfirmationDialog</name>
<message>
<location filename="../sendcoinsdialog.cpp" line="+95"/>
<location line="+5"/>
<source>Yes</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ShutdownWindow</name>
<message>
<location filename="../utilitydialog.cpp" line="+78"/>
<source>%1 is shutting down...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Do not shut down the computer until this window disappears.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SignVerifyMessageDialog</name>
<message>
<location filename="../forms/signverifymessagedialog.ui" line="+14"/>
<source>Signatures - Sign / Verify a Message</source>
<translation>Signatures - Sign / Verify a Message</translation>
</message>
<message>
<location line="+13"/>
<source>&amp;Sign Message</source>
<translation>&amp;Sign Message</translation>
</message>
<message>
<location line="+6"/>
<source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+18"/>
<source>The Bitcoin address to sign the message with</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<location line="+210"/>
<source>Choose previously used address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-200"/>
<location line="+210"/>
<source>Alt+A</source>
<translation>Alt+A</translation>
</message>
<message>
<location line="-200"/>
<source>Paste address from clipboard</source>
<translation>Paste address from clipboard</translation>
</message>
<message>
<location line="+10"/>
<source>Alt+P</source>
<translation>Alt+P</translation>
</message>
<message>
<location line="+12"/>
<source>Enter the message you want to sign here</source>
<translation>Enter the message you want to sign here</translation>
</message>
<message>
<location line="+7"/>
<source>Signature</source>
<translation>Signature</translation>
</message>
<message>
<location line="+27"/>
<source>Copy the current signature to the system clipboard</source>
<translation>Copy the current signature to the system clipboard</translation>
</message>
<message>
<location line="+21"/>
<source>Sign the message to prove you own this Bitcoin address</source>
<translation>Sign the message to prove you own this Bitcoin address</translation>
</message>
<message>
<location line="+3"/>
<source>Sign &amp;Message</source>
<translation>Sign &amp;Message</translation>
</message>
<message>
<location line="+14"/>
<source>Reset all sign message fields</source>
<translation>Reset all sign message fields</translation>
</message>
<message>
<location line="+3"/>
<location line="+143"/>
<source>Clear &amp;All</source>
<translation>Clear &amp;All</translation>
</message>
<message>
<location line="-84"/>
<source>&amp;Verify Message</source>
<translation>&amp;Verify Message</translation>
</message>
<message>
<location line="+6"/>
<source>Enter the receiver&apos;s 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. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+21"/>
<source>The Bitcoin address the message was signed with</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+37"/>
<source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
<translation>Verify the message to ensure it was signed with the specified Bitcoin address</translation>
</message>
<message>
<location line="+3"/>
<source>Verify &amp;Message</source>
<translation>Verify &amp;Message</translation>
</message>
<message>
<location line="+14"/>
<source>Reset all verify message fields</source>
<translation>Reset all verify message fields</translation>
</message>
<message>
<location filename="../signverifymessagedialog.cpp" line="+41"/>
<source>Click &quot;Sign Message&quot; to generate signature</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+83"/>
<location line="+80"/>
<source>The entered address is invalid.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-80"/>
<location line="+8"/>
<location line="+72"/>
<location line="+8"/>
<source>Please check the address and try again.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-80"/>
<location line="+80"/>
<source>The entered address does not refer to a key.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-72"/>
<source>Wallet unlock was cancelled.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>Private key for the entered address is not available.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+12"/>
<source>Message signing failed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>Message signed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+58"/>
<source>The signature could not be decoded.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<location line="+13"/>
<source>Please check the signature and try again.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>The signature did not match the message digest.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Message verification failed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>Message verified.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SplashScreen</name>
<message>
<location filename="../networkstyle.cpp" line="+19"/>
<source>[testnet]</source>
<translation>[testnet]</translation>
</message>
</context>
<context>
<name>TrafficGraphWidget</name>
<message>
<location filename="../trafficgraphwidget.cpp" line="+79"/>
<source>KB/s</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TransactionDesc</name>
<message numerus="yes">
<location filename="../transactiondesc.cpp" line="+30"/>
<source>Open for %n more block(s)</source>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <translation>
+ <numerusform>Open for %n more block</numerusform>
+ <numerusform>Open for %n more blocks</numerusform>
</translation>
</message>
<message>
<location line="+2"/>
<source>Open until %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>conflicted with a transaction with %1 confirmations</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>%1/offline</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>0/unconfirmed, %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>in memory pool</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>not in memory pool</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>abandoned</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>%1/unconfirmed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>%1 confirmations</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+17"/>
<source>Status</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>, has not been successfully broadcast yet</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location line="+2"/>
<source>, broadcast through %n node(s)</source>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <translation>
+ <numerusform>, broadcast through %n node</numerusform>
+ <numerusform>, broadcast through %n nodes</numerusform>
</translation>
</message>
<message>
<location line="+4"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
<message>
<location line="+7"/>
<source>Source</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Generated</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<location line="+13"/>
<location line="+72"/>
<source>From</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-72"/>
<source>unknown</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<location line="+20"/>
<location line="+69"/>
<source>To</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-87"/>
<source>own address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<location line="+69"/>
<source>watch-only</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-67"/>
<source>label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+34"/>
<location line="+12"/>
<location line="+53"/>
<location line="+26"/>
<location line="+55"/>
<source>Credit</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location line="-144"/>
<source>matures in %n more block(s)</source>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <translation>
+ <numerusform>matures in %n more block</numerusform>
+ <numerusform>matures in %n more blocks</numerusform>
</translation>
</message>
<message>
<location line="+2"/>
<source>not accepted</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+59"/>
<location line="+25"/>
<location line="+55"/>
<source>Debit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-70"/>
<source>Total debit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Total credit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>Transaction fee</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+16"/>
<source>Net amount</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<location line="+11"/>
<source>Message</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-9"/>
<source>Comment</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Transaction ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Transaction total size</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Output index</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+18"/>
<source>Merchant</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Generated coins must mature %1 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>
</message>
<message>
<location line="+8"/>
<source>Debug information</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>Transaction</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Inputs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+21"/>
<source>Amount</source>
<translation type="unfinished">Amount</translation>
</message>
<message>
<location line="+1"/>
<location line="+1"/>
<source>true</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-1"/>
<location line="+1"/>
<source>false</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TransactionDescDialog</name>
<message>
<location filename="../forms/transactiondescdialog.ui" line="+20"/>
<source>This pane shows a detailed description of the transaction</source>
<translation>This pane shows a detailed description of the transaction</translation>
</message>
<message>
<location filename="../transactiondescdialog.cpp" line="+17"/>
<source>Details for %1</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TransactionTableModel</name>
<message>
<location filename="../transactiontablemodel.cpp" line="+246"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
<message>
<location line="+0"/>
<source>Type</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Label</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location line="+58"/>
<source>Open for %n more block(s)</source>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <translation>
+ <numerusform>Open for %n more block</numerusform>
+ <numerusform>Open for %n more blocks</numerusform>
</translation>
</message>
<message>
<location line="+3"/>
<source>Open until %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Offline</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Unconfirmed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Abandoned</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Confirming (%1 of %2 recommended confirmations)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Confirmed (%1 confirmations)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Conflicted</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Immature (%1 confirmations, will be available after %2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>This block was not received by any other nodes and will probably not be accepted!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Generated but not accepted</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+39"/>
<source>Received with</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Received from</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Sent to</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Payment to yourself</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Mined</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+28"/>
<source>watch-only</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+15"/>
<source>(n/a)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+213"/>
<source>(no label)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+39"/>
<source>Transaction status. Hover over this field to show number of confirmations.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Date and time that the transaction was received.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Type of transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Whether or not a watch-only address is involved in this transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>User-defined intent/purpose of the transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Amount removed from or added to balance.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TransactionView</name>
<message>
<location filename="../transactionview.cpp" line="+69"/>
<location line="+16"/>
<source>All</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-15"/>
<source>Today</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>This week</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>This month</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Last month</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>This year</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Range...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+11"/>
<source>Received with</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Sent to</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>To yourself</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Mined</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Other</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Enter address or label to search</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Min amount</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+36"/>
<source>Abandon transaction</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy amount</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy transaction ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy raw transaction</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy full transaction details</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Edit label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Show transaction details</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+186"/>
<source>Export Transaction History</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Comma separated file (*.csv)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>Confirmed</source>
<translation type="unfinished">Confirmed</translation>
</message>
<message>
<location line="+2"/>
<source>Watch-only</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
<message>
<location line="+1"/>
<source>Type</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Exporting Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>There was an error trying to save the transaction history to %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Exporting Successful</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>The transaction history was successfully saved to %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+147"/>
<source>Range:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>to</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
<location filename="../bitcoingui.cpp" line="+129"/>
<source>Unit to show amounts in. Click to select another unit.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>WalletFrame</name>
<message>
<location filename="../walletframe.cpp" line="+27"/>
<source>No wallet has been loaded.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>WalletModel</name>
<message>
<location filename="../walletmodel.cpp" line="+291"/>
<source>Send Coins</source>
<translation type="unfinished">Send Coins</translation>
</message>
</context>
<context>
<name>WalletView</name>
<message>
<location filename="../walletview.cpp" line="+46"/>
<source>&amp;Export</source>
<translation type="unfinished">&amp;Export</translation>
</message>
<message>
<location line="+1"/>
<source>Export the data in the current tab to a file</source>
<translation type="unfinished">Export the data in the current tab to a file</translation>
</message>
<message>
<location line="+201"/>
<source>Backup Wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Wallet Data (*.dat)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Backup Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>There was an error trying to save the wallet data to %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Backup Successful</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>The wallet data was successfully saved to %1.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>bitcoin-core</name>
<message>
<location filename="../bitcoinstrings.cpp" line="+292"/>
<source>Options:</source>
<translation>Options:</translation>
</message>
<message>
<location line="+31"/>
<source>Specify data directory</source>
<translation>Specify data directory</translation>
</message>
<message>
<location line="-90"/>
<source>Connect to a node to retrieve peer addresses, and disconnect</source>
<translation>Connect to a node to retrieve peer addresses, and disconnect</translation>
</message>
<message>
<location line="+93"/>
<source>Specify your own public address</source>
<translation>Specify your own public address</translation>
</message>
<message>
<location line="-107"/>
<source>Accept command line and JSON-RPC commands</source>
<translation>Accept command line and JSON-RPC commands</translation>
</message>
<message>
<location line="-196"/>
<source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+22"/>
<source>Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+12"/>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+34"/>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+32"/>
<source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+117"/>
<source>Error: A fatal internal error occurred, see debug.log for details</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Fee (in %s/kB) to add to transactions you send (default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+40"/>
<source>Pruning blockstore...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>Run in the background as a daemon and accept commands</source>
<translation>Run in the background as a daemon and accept commands</translation>
</message>
<message>
<location line="+37"/>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-334"/>
<source>Bitcoin Core</source>
<translation type="unfinished">Bitcoin Core</translation>
</message>
<message>
<location line="+1"/>
<source>The %s developers</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
<translation>Bind to given address and always listen on it. Use [host]:port notation for IPv6</translation>
</message>
<message>
<location line="+10"/>
<source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+13"/>
<source>Error loading %s: You can&apos;t enable HD on a already existing non-HD wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</translation>
</message>
<message>
<location line="+29"/>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Please check that your computer&apos;s date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+24"/>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>The block database contains a block which appears to be from the future. This may be due to your computer&apos;s date and time being set incorrectly. Only rebuild the block database if you are sure that your computer&apos;s date and time are correct</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+19"/>
<source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+31"/>
+ <location line="+12"/>
+ <source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+19"/>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>%s corrupt, salvage failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>-maxmempool must be at least %d MB</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>&lt;category&gt; can be:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Append comment to the user agent string</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Attempt to recover private keys from a corrupt wallet on startup</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Block creation options:</source>
<translation>Block creation options:</translation>
</message>
<message>
<location line="+2"/>
<source>Cannot resolve -%s address: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Change index out of range</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Connection options:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copyright (C) %i-%i</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Corrupted block database detected</source>
<translation>Corrupted block database detected</translation>
</message>
<message>
<location line="+1"/>
<source>Debugging/Testing options:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Do not load the wallet and disable wallet RPC calls</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Do you want to rebuild the block database now?</source>
<translation>Do you want to rebuild the block database now?</translation>
</message>
<message>
<location line="+2"/>
<source>Enable publish hash block in &lt;address&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Enable publish hash transaction in &lt;address&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Enable publish raw block in &lt;address&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Enable publish raw transaction in &lt;address&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Enable transaction replacement in the memory pool (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Error initializing block database</source>
<translation>Error initializing block database</translation>
</message>
<message>
<location line="+1"/>
<source>Error initializing wallet database environment %s!</source>
<translation>Error initializing wallet database environment %s!</translation>
</message>
<message>
<location line="+1"/>
<source>Error loading %s</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Error loading %s: Wallet corrupted</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Error loading %s: Wallet requires newer version of %s</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Error loading %s: You can&apos;t disable HD on a already existing HD wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Error loading block database</source>
<translation>Error loading block database</translation>
</message>
<message>
<location line="+1"/>
<source>Error opening block database</source>
<translation>Error opening block database</translation>
</message>
<message>
<location line="+4"/>
<source>Error: Disk space is low!</source>
<translation>Error: Disk space is low!</translation>
</message>
<message>
<location line="+1"/>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation>Failed to listen on any port. Use -listen=0 if you want this.</translation>
</message>
<message>
<location line="+3"/>
<source>Importing...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Incorrect or no genesis block found. Wrong datadir for network?</source>
<translation>Incorrect or no genesis block found. Wrong datadir for network?</translation>
</message>
<message>
<location line="+2"/>
<source>Initialization sanity check failed. %s is shutting down.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Invalid -onion address: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Invalid amount for -fallbackfee=&lt;amount&gt;: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Keep the transaction memory pool below &lt;n&gt; megabytes (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>Loading banlist...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Location of the auth cookie (default: data dir)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Not enough file descriptors available.</source>
<translation>Not enough file descriptors available.</translation>
</message>
<message>
<location line="+1"/>
<source>Only connect to nodes in network &lt;net&gt; (ipv4, ipv6 or onion)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Print this help message and exit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Print version and exit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Prune cannot be configured with a negative value.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Rebuild chain state and block index from the blk*.dat files on disk</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Rebuild chain state from the currently indexed blocks</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Rewinding blocks...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Set maximum block size in bytes (default: %d)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>Specify wallet file (within data directory)</source>
<translation>Specify wallet file (within data directory)</translation>
</message>
<message>
<location line="+4"/>
<source>The source code is available from %s.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+16"/>
<source>Unable to bind to %s on this computer. %s is probably already running.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Unsupported argument -debugnet ignored, use -debug=net.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Unsupported argument -tor found, use -onion.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Use UPnP to map the listening port (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Verifying blocks...</source>
<translation>Verifying blocks...</translation>
</message>
<message>
<location line="+1"/>
<source>Verifying wallet...</source>
<translation>Verifying wallet...</translation>
</message>
<message>
<location line="+1"/>
<source>Wallet %s resides outside data directory %s</source>
<translation>Wallet %s resides outside data directory %s</translation>
</message>
<message>
<location line="+1"/>
<source>Wallet debugging/testing options:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Wallet needed to be rewritten: restart %s to complete</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Wallet options:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-331"/>
<source>Allow JSON-RPC connections from specified source. Valid for &lt;ip&gt; are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+15"/>
<source>Error: Listening for incoming connections failed (listen returned error %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</source>
<translation>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</translation>
</message>
<message>
<location line="+9"/>
<source>Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+14"/>
<source>If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Invalid amount for -maxtxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>Maximum size of data in data carrier transactions we relay and mine (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+24"/>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+11"/>
<source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+15"/>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+25"/>
<source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>(default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Accept public REST requests (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Automatically create Tor hidden service (default: %d)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Connect through SOCKS5 proxy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+22"/>
<source>Error reading from database, shutting down.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>Imports blocks from external blk000??.dat file on startup</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Information</source>
<translation>Information</translation>
</message>
<message>
<location line="+7"/>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Invalid netmask specified in -whitelist: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Keep at most &lt;n&gt; unconnectable transactions in memory (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+14"/>
<source>Need to specify a port with -whitebind: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Node relay options:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+11"/>
<source>RPC server options:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Reducing -maxconnections from %d to %d, because of system limitations.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Rescan the block chain for missing wallet transactions on startup</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>Send trace/debug info to console instead of debug.log file</translation>
</message>
<message>
<location line="+1"/>
<source>Send transactions as zero-fee transactions if possible (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Show all debugging options (usage: --help -help-debug)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Shrink debug.log file on client startup (default: 1 when no -debug)</source>
<translation>Shrink debug.log file on client startup (default: 1 when no -debug)</translation>
</message>
<message>
<location line="+1"/>
<source>Signing transaction failed</source>
<translation>Signing transaction failed</translation>
</message>
<message>
<location line="+10"/>
<source>The transaction amount is too small to pay the fee</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>This is experimental software.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Tor control port password (default: empty)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Tor control port to use if onion listening enabled (default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Transaction amount too small</source>
<translation>Transaction amount too small</translation>
</message>
<message>
<location line="+4"/>
<source>Transaction too large for fee policy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Transaction too large</source>
<translation>Transaction too large</translation>
</message>
<message>
<location line="+1"/>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Upgrade wallet to latest format on startup</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Username for JSON-RPC connections</source>
<translation>Username for JSON-RPC connections</translation>
</message>
<message>
<location line="+7"/>
<source>Warning</source>
<translation>Warning</translation>
</message>
<message>
<location line="+1"/>
<source>Warning: unknown new rules activated (versionbit %i)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Whether to operate in a blocks only mode (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Zapping all transactions from wallet...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>ZeroMQ notification options:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-72"/>
<source>Password for JSON-RPC connections</source>
<translation>Password for JSON-RPC connections</translation>
</message>
<message>
<location line="-216"/>
<source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source>
<translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation>
</message>
<message>
<location line="+145"/>
<source>Allow DNS lookups for -addnode, -seednode and -connect</source>
<translation>Allow DNS lookups for -addnode, -seednode and -connect</translation>
</message>
<message>
<location line="+57"/>
<source>Loading addresses...</source>
<translation>Loading addresses...</translation>
</message>
<message>
<location line="-265"/>
<source>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+43"/>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+21"/>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+11"/>
<source>Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+13"/>
<source>Number of seconds to keep misbehaving peers from reconnecting (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Output debugging information (default: %u, supplying &lt;category&gt; is optional)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+13"/>
<source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+19"/>
<source>Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>This is the transaction fee you may pay when fee estimates are not available.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Unsupported argument -socks found. Setting SOCKS version isn&apos;t possible anymore, only SOCKS5 proxies are supported.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. This option can be specified multiple times</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
- <source>Wallet will not create transactions that violate mempool chain limits (default: %u</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="+7"/>
<source>Warning: Unknown block versions being mined! It&apos;s possible unknown rules are in effect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Warning: Wallet file corrupt, data salvaged! Original %s saved as %s in %s; if your balance or transactions are incorrect you should restore from a backup.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+12"/>
<source>%s is set very high!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>(default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>Always query for peer addresses via DNS lookup (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+37"/>
<source>How many blocks to check at startup (default: %u, 0 = all)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Include IP addresses in debug output (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Invalid -proxy address: &apos;%s&apos;</source>
<translation>Invalid -proxy address: &apos;%s&apos;</translation>
</message>
<message>
<location line="+7"/>
<source>Keypool ran out, please call keypoolrefill first</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Listen for connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Maintain at most &lt;n&gt; connections to peers (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Make the wallet broadcast transactions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Maximum per-connection send buffer, &lt;n&gt;*1000 bytes (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Prepend debug output with timestamp (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>Relay and mine data carrier transactions (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Relay non-P2SH multisig (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Set maximum BIP141 block weight (default: %d)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Specify configuration file (default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Specify connection timeout in milliseconds (minimum: 1, default: %d)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Specify pid file (default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Spend unconfirmed change when sending transactions (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Starting network threads...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>The wallet will avoid paying less than the minimum relay fee.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>This is the minimum transaction fee you pay on every transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>This is the transaction fee you will pay if you send a transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Transaction amounts must not be negative</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Transaction has too long of a mempool chain</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Transaction must have at least one recipient</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Unknown network specified in -onlynet: &apos;%s&apos;</source>
<translation>Unknown network specified in -onlynet: &apos;%s&apos;</translation>
</message>
<message>
<location line="-80"/>
<source>Insufficient funds</source>
<translation>Insufficient funds</translation>
</message>
<message>
<location line="+14"/>
<source>Loading block index...</source>
<translation>Loading block index...</translation>
</message>
<message>
<location line="-60"/>
<source>Add a node to connect to and attempt to keep the connection open</source>
<translation>Add a node to connect to and attempt to keep the connection open</translation>
</message>
<message>
<location line="+61"/>
<source>Loading wallet...</source>
<translation>Loading wallet...</translation>
</message>
<message>
<location line="-54"/>
<source>Cannot downgrade wallet</source>
<translation>Cannot downgrade wallet</translation>
</message>
<message>
<location line="+2"/>
<source>Cannot write default address</source>
<translation>Cannot write default address</translation>
</message>
<message>
<location line="+77"/>
<source>Rescanning...</source>
<translation>Rescanning...</translation>
</message>
<message>
<location line="-67"/>
<source>Done loading</source>
<translation>Done loading</translation>
</message>
<message>
<location line="+15"/>
<source>Error</source>
<translation>Error</translation>
</message>
</context>
</TS>
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index e1c409097..fef0f9e58 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1,3778 +1,3778 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "wallet/wallet.h"
#include "base58.h"
#include "checkpoints.h"
#include "chain.h"
#include "wallet/coincontrol.h"
#include "consensus/consensus.h"
#include "consensus/validation.h"
#include "key.h"
#include "keystore.h"
#include "validation.h"
#include "net.h"
#include "policy/policy.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "script/script.h"
#include "script/sign.h"
#include "timedata.h"
#include "txmempool.h"
#include "util.h"
#include "ui_interface.h"
#include "utilmoneystr.h"
#include <assert.h>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
using namespace std;
CWallet* pwalletMain = NULL;
/** Transaction fee set by the user */
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
bool fWalletRbf = DEFAULT_WALLET_RBF;
const char * DEFAULT_WALLET_DAT = "wallet.dat";
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
/**
* Fees smaller than this (in satoshi) are considered zero fee (for transaction creation)
* Override with -mintxfee
*/
CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE);
/**
* If fee estimation does not have enough data to provide estimates, use this fee instead.
* Has no effect if not using fee estimation
* Override with -fallbackfee
*/
CFeeRate CWallet::fallbackFee = CFeeRate(DEFAULT_FALLBACK_FEE);
const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
/** @defgroup mapWallet
*
* @{
*/
struct CompareValueOnly
{
bool operator()(const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t1,
const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t2) const
{
return t1.first < t2.first;
}
};
std::string COutput::ToString() const
{
return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue));
}
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
{
LOCK(cs_wallet);
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash);
if (it == mapWallet.end())
return NULL;
return &(it->second);
}
CPubKey CWallet::GenerateNewKey()
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
CKey secret;
// Create new metadata
int64_t nCreationTime = GetTime();
CKeyMetadata metadata(nCreationTime);
// use HD key derivation if HD was enabled during wallet creation
if (IsHDEnabled()) {
DeriveNewChildKey(metadata, secret);
} else {
secret.MakeNewKey(fCompressed);
}
// Compressed public keys were introduced in version 0.6.0
if (fCompressed)
SetMinVersion(FEATURE_COMPRPUBKEY);
CPubKey pubkey = secret.GetPubKey();
assert(secret.VerifyPubKey(pubkey));
mapKeyMetadata[pubkey.GetID()] = metadata;
if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
nTimeFirstKey = nCreationTime;
if (!AddKeyPubKey(secret, pubkey))
throw std::runtime_error(std::string(__func__) + ": AddKey failed");
return pubkey;
}
void CWallet::DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret)
{
// for now we use a fixed keypath scheme of m/0'/0'/k
CKey key; //master key seed (256bit)
CExtKey masterKey; //hd master key
CExtKey accountKey; //key at m/0'
CExtKey externalChainChildKey; //key at m/0'/0'
CExtKey childKey; //key at m/0'/0'/<n>'
// try to get the master key
if (!GetKey(hdChain.masterKeyID, key))
throw std::runtime_error(std::string(__func__) + ": Master key not found");
masterKey.SetMaster(key.begin(), key.size());
// derive m/0'
// use hardened derivation (child keys >= 0x80000000 are hardened after bip32)
masterKey.Derive(accountKey, BIP32_HARDENED_KEY_LIMIT);
// derive m/0'/0'
accountKey.Derive(externalChainChildKey, BIP32_HARDENED_KEY_LIMIT);
// derive child key at next index, skip keys already known to the wallet
do {
// always derive hardened keys
// childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened child-index-range
// example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649
externalChainChildKey.Derive(childKey, hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
metadata.hdKeypath = "m/0'/0'/" + std::to_string(hdChain.nExternalChainCounter) + "'";
metadata.hdMasterKeyID = hdChain.masterKeyID;
// increment childkey index
hdChain.nExternalChainCounter++;
} while (HaveKey(childKey.key.GetPubKey().GetID()));
secret = childKey.key;
// update the chain model in the database
if (!CWalletDB(strWalletFile).WriteHDChain(hdChain))
throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");
}
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
return false;
// check if we need to remove from watch-only
CScript script;
script = GetScriptForDestination(pubkey.GetID());
if (HaveWatchOnly(script))
RemoveWatchOnly(script);
script = GetScriptForRawPubKey(pubkey);
if (HaveWatchOnly(script))
RemoveWatchOnly(script);
if (!fFileBacked)
return true;
if (!IsCrypted()) {
return CWalletDB(strWalletFile).WriteKey(pubkey,
secret.GetPrivKey(),
mapKeyMetadata[pubkey.GetID()]);
}
return true;
}
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
const vector<unsigned char> &vchCryptedSecret)
{
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
if (!fFileBacked)
return true;
{
LOCK(cs_wallet);
if (pwalletdbEncryption)
return pwalletdbEncryption->WriteCryptedKey(vchPubKey,
vchCryptedSecret,
mapKeyMetadata[vchPubKey.GetID()]);
else
return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey,
vchCryptedSecret,
mapKeyMetadata[vchPubKey.GetID()]);
}
return false;
}
bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
nTimeFirstKey = meta.nCreateTime;
mapKeyMetadata[pubkey.GetID()] = meta;
return true;
}
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
}
bool CWallet::AddCScript(const CScript& redeemScript)
{
if (!CCryptoKeyStore::AddCScript(redeemScript))
return false;
if (!fFileBacked)
return true;
return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
}
bool CWallet::LoadCScript(const CScript& redeemScript)
{
/* A sanity check was added in pull #3843 to avoid adding redeemScripts
* that never can be redeemed. However, old wallets may still contain
* these. Do not add them to the wallet and warn. */
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
{
std::string strAddr = CBitcoinAddress(CScriptID(redeemScript)).ToString();
LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
__func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
return true;
}
return CCryptoKeyStore::AddCScript(redeemScript);
}
bool CWallet::AddWatchOnly(const CScript &dest)
{
if (!CCryptoKeyStore::AddWatchOnly(dest))
return false;
nTimeFirstKey = 1; // No birthday information for watch-only keys.
NotifyWatchonlyChanged(true);
if (!fFileBacked)
return true;
return CWalletDB(strWalletFile).WriteWatchOnly(dest);
}
bool CWallet::RemoveWatchOnly(const CScript &dest)
{
AssertLockHeld(cs_wallet);
if (!CCryptoKeyStore::RemoveWatchOnly(dest))
return false;
if (!HaveWatchOnly())
NotifyWatchonlyChanged(false);
if (fFileBacked)
if (!CWalletDB(strWalletFile).EraseWatchOnly(dest))
return false;
return true;
}
bool CWallet::LoadWatchOnly(const CScript &dest)
{
return CCryptoKeyStore::AddWatchOnly(dest);
}
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
CCrypter crypter;
CKeyingMaterial vMasterKey;
{
LOCK(cs_wallet);
BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
continue; // try another master key
if (CCryptoKeyStore::Unlock(vMasterKey))
return true;
}
}
return false;
}
bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
{
bool fWasLocked = IsLocked();
{
LOCK(cs_wallet);
Lock();
CCrypter crypter;
CKeyingMaterial vMasterKey;
BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
return false;
if (CCryptoKeyStore::Unlock(vMasterKey))
{
int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
if (pMasterKey.second.nDeriveIterations < 25000)
pMasterKey.second.nDeriveIterations = 25000;
LogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
return false;
CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
if (fWasLocked)
Lock();
return true;
}
}
}
return false;
}
void CWallet::SetBestChain(const CBlockLocator& loc)
{
CWalletDB walletdb(strWalletFile);
walletdb.WriteBestBlock(loc);
}
bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
{
LOCK(cs_wallet); // nWalletVersion
if (nWalletVersion >= nVersion)
return true;
// when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way
if (fExplicit && nVersion > nWalletMaxVersion)
nVersion = FEATURE_LATEST;
nWalletVersion = nVersion;
if (nVersion > nWalletMaxVersion)
nWalletMaxVersion = nVersion;
if (fFileBacked)
{
CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);
if (nWalletVersion > 40000)
pwalletdb->WriteMinVersion(nWalletVersion);
if (!pwalletdbIn)
delete pwalletdb;
}
return true;
}
bool CWallet::SetMaxVersion(int nVersion)
{
LOCK(cs_wallet); // nWalletVersion, nWalletMaxVersion
// cannot downgrade below current version
if (nWalletVersion > nVersion)
return false;
nWalletMaxVersion = nVersion;
return true;
}
set<uint256> CWallet::GetConflicts(const uint256& txid) const
{
set<uint256> result;
AssertLockHeld(cs_wallet);
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid);
if (it == mapWallet.end())
return result;
const CWalletTx& wtx = it->second;
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
if (mapTxSpends.count(txin.prevout) <= 1)
continue; // No conflict if zero or one spends
range = mapTxSpends.equal_range(txin.prevout);
for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)
result.insert(_it->second);
}
return result;
}
void CWallet::Flush(bool shutdown)
{
bitdb.Flush(shutdown);
}
bool CWallet::Verify()
{
if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
return true;
LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
LogPrintf("Using wallet %s\n", walletFile);
uiInterface.InitMessage(_("Verifying wallet..."));
// Wallet file must be a plain filename without a directory
if (walletFile != boost::filesystem::basename(walletFile) + boost::filesystem::extension(walletFile))
return InitError(strprintf(_("Wallet %s resides outside data directory %s"), walletFile, GetDataDir().string()));
if (!bitdb.Open(GetDataDir()))
{
// try moving the database env out of the way
boost::filesystem::path pathDatabase = GetDataDir() / "database";
boost::filesystem::path pathDatabaseBak = GetDataDir() / strprintf("database.%d.bak", GetTime());
try {
boost::filesystem::rename(pathDatabase, pathDatabaseBak);
LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string());
} catch (const boost::filesystem::filesystem_error&) {
// failure is ok (well, not really, but it's not worse than what we started with)
}
// try again
if (!bitdb.Open(GetDataDir())) {
// if it still fails, it probably means we can't even create the database env
return InitError(strprintf(_("Error initializing wallet database environment %s!"), GetDataDir()));
}
}
if (GetBoolArg("-salvagewallet", false))
{
// Recover readable keypairs:
if (!CWalletDB::Recover(bitdb, walletFile, true))
return false;
}
if (boost::filesystem::exists(GetDataDir() / walletFile))
{
CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover);
if (r == CDBEnv::RECOVER_OK)
{
InitWarning(strprintf(_("Warning: Wallet file corrupt, data salvaged!"
" Original %s saved as %s in %s; if"
" your balance or transactions are incorrect you should"
" restore from a backup."),
walletFile, "wallet.{timestamp}.bak", GetDataDir()));
}
if (r == CDBEnv::RECOVER_FAIL)
return InitError(strprintf(_("%s corrupt, salvage failed"), walletFile));
}
return true;
}
void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range)
{
// We want all the wallet transactions in range to have the same metadata as
// the oldest (smallest nOrderPos).
// So: find smallest nOrderPos:
int nMinOrderPos = std::numeric_limits<int>::max();
const CWalletTx* copyFrom = NULL;
for (TxSpends::iterator it = range.first; it != range.second; ++it)
{
const uint256& hash = it->second;
int n = mapWallet[hash].nOrderPos;
if (n < nMinOrderPos)
{
nMinOrderPos = n;
copyFrom = &mapWallet[hash];
}
}
// Now copy data from copyFrom to rest:
for (TxSpends::iterator it = range.first; it != range.second; ++it)
{
const uint256& hash = it->second;
CWalletTx* copyTo = &mapWallet[hash];
if (copyFrom == copyTo) continue;
if (!copyFrom->IsEquivalentTo(*copyTo)) continue;
copyTo->mapValue = copyFrom->mapValue;
copyTo->vOrderForm = copyFrom->vOrderForm;
// fTimeReceivedIsTxTime not copied on purpose
// nTimeReceived not copied on purpose
copyTo->nTimeSmart = copyFrom->nTimeSmart;
copyTo->fFromMe = copyFrom->fFromMe;
copyTo->strFromAccount = copyFrom->strFromAccount;
// nOrderPos not copied on purpose
// cached members not copied on purpose
}
}
/**
* Outpoint is spent if any non-conflicted transaction
* spends it:
*/
bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
{
const COutPoint outpoint(hash, n);
pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
range = mapTxSpends.equal_range(outpoint);
for (TxSpends::const_iterator it = range.first; it != range.second; ++it)
{
const uint256& wtxid = it->second;
std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
if (mit != mapWallet.end()) {
int depth = mit->second.GetDepthInMainChain();
if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
return true; // Spent
}
}
return false;
}
void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid)
{
mapTxSpends.insert(make_pair(outpoint, wtxid));
pair<TxSpends::iterator, TxSpends::iterator> range;
range = mapTxSpends.equal_range(outpoint);
SyncMetaData(range);
}
void CWallet::AddToSpends(const uint256& wtxid)
{
assert(mapWallet.count(wtxid));
CWalletTx& thisTx = mapWallet[wtxid];
if (thisTx.IsCoinBase()) // Coinbases don't spend anything!
return;
BOOST_FOREACH(const CTxIn& txin, thisTx.tx->vin)
AddToSpends(txin.prevout, wtxid);
}
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
{
if (IsCrypted())
return false;
CKeyingMaterial vMasterKey;
vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
GetStrongRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
CMasterKey kMasterKey;
kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
GetStrongRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
CCrypter crypter;
int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
if (kMasterKey.nDeriveIterations < 25000)
kMasterKey.nDeriveIterations = 25000;
LogPrintf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
return false;
if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
return false;
{
LOCK(cs_wallet);
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
if (fFileBacked)
{
assert(!pwalletdbEncryption);
pwalletdbEncryption = new CWalletDB(strWalletFile);
if (!pwalletdbEncryption->TxnBegin()) {
delete pwalletdbEncryption;
pwalletdbEncryption = NULL;
return false;
}
pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
}
if (!EncryptKeys(vMasterKey))
{
if (fFileBacked) {
pwalletdbEncryption->TxnAbort();
delete pwalletdbEncryption;
}
// We now probably have half of our keys encrypted in memory, and half not...
// die and let the user reload the unencrypted wallet.
assert(false);
}
// Encryption was introduced in version 0.4.0
SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);
if (fFileBacked)
{
if (!pwalletdbEncryption->TxnCommit()) {
delete pwalletdbEncryption;
// We now have keys encrypted in memory, but not on disk...
// die to avoid confusion and let the user reload the unencrypted wallet.
assert(false);
}
delete pwalletdbEncryption;
pwalletdbEncryption = NULL;
}
Lock();
Unlock(strWalletPassphrase);
// if we are using HD, replace the HD master key (seed) with a new one
if (IsHDEnabled()) {
CKey key;
CPubKey masterPubKey = GenerateNewHDMasterKey();
if (!SetHDMasterKey(masterPubKey))
return false;
}
NewKeyPool();
Lock();
// Need to completely rewrite the wallet file; if we don't, bdb might keep
// bits of the unencrypted private key in slack space in the database file.
CDB::Rewrite(strWalletFile);
}
NotifyStatusChanged(this);
return true;
}
DBErrors CWallet::ReorderTransactions()
{
LOCK(cs_wallet);
CWalletDB walletdb(strWalletFile);
// Old wallets didn't have any defined order for transactions
// Probably a bad idea to change the output of this
// First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
typedef multimap<int64_t, TxPair > TxItems;
TxItems txByTime;
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
CWalletTx* wtx = &((*it).second);
txByTime.insert(make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0)));
}
list<CAccountingEntry> acentries;
walletdb.ListAccountCreditDebit("", acentries);
BOOST_FOREACH(CAccountingEntry& entry, acentries)
{
txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
}
nOrderPosNext = 0;
std::vector<int64_t> nOrderPosOffsets;
for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
{
CWalletTx *const pwtx = (*it).second.first;
CAccountingEntry *const pacentry = (*it).second.second;
int64_t& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos;
if (nOrderPos == -1)
{
nOrderPos = nOrderPosNext++;
nOrderPosOffsets.push_back(nOrderPos);
if (pwtx)
{
if (!walletdb.WriteTx(*pwtx))
return DB_LOAD_FAIL;
}
else
if (!walletdb.WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
return DB_LOAD_FAIL;
}
else
{
int64_t nOrderPosOff = 0;
BOOST_FOREACH(const int64_t& nOffsetStart, nOrderPosOffsets)
{
if (nOrderPos >= nOffsetStart)
++nOrderPosOff;
}
nOrderPos += nOrderPosOff;
nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
if (!nOrderPosOff)
continue;
// Since we're changing the order, write it back
if (pwtx)
{
if (!walletdb.WriteTx(*pwtx))
return DB_LOAD_FAIL;
}
else
if (!walletdb.WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
return DB_LOAD_FAIL;
}
}
walletdb.WriteOrderPosNext(nOrderPosNext);
return DB_LOAD_OK;
}
int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
{
AssertLockHeld(cs_wallet); // nOrderPosNext
int64_t nRet = nOrderPosNext++;
if (pwalletdb) {
pwalletdb->WriteOrderPosNext(nOrderPosNext);
} else {
CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext);
}
return nRet;
}
bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment)
{
CWalletDB walletdb(strWalletFile);
if (!walletdb.TxnBegin())
return false;
int64_t nNow = GetAdjustedTime();
// Debit
CAccountingEntry debit;
debit.nOrderPos = IncOrderPosNext(&walletdb);
debit.strAccount = strFrom;
debit.nCreditDebit = -nAmount;
debit.nTime = nNow;
debit.strOtherAccount = strTo;
debit.strComment = strComment;
AddAccountingEntry(debit, &walletdb);
// Credit
CAccountingEntry credit;
credit.nOrderPos = IncOrderPosNext(&walletdb);
credit.strAccount = strTo;
credit.nCreditDebit = nAmount;
credit.nTime = nNow;
credit.strOtherAccount = strFrom;
credit.strComment = strComment;
AddAccountingEntry(credit, &walletdb);
if (!walletdb.TxnCommit())
return false;
return true;
}
bool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bForceNew)
{
CWalletDB walletdb(strWalletFile);
CAccount account;
walletdb.ReadAccount(strAccount, account);
if (!bForceNew) {
if (!account.vchPubKey.IsValid())
bForceNew = true;
else {
// Check if the current key has been used
CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin();
it != mapWallet.end() && account.vchPubKey.IsValid();
++it)
BOOST_FOREACH(const CTxOut& txout, (*it).second.tx->vout)
if (txout.scriptPubKey == scriptPubKey) {
bForceNew = true;
break;
}
}
}
// Generate a new key
if (bForceNew) {
if (!GetKeyFromPool(account.vchPubKey))
return false;
SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
walletdb.WriteAccount(strAccount, account);
}
pubKey = account.vchPubKey;
return true;
}
void CWallet::MarkDirty()
{
{
LOCK(cs_wallet);
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
item.second.MarkDirty();
}
}
bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
{
LOCK(cs_wallet);
CWalletDB walletdb(strWalletFile, "r+", fFlushOnClose);
uint256 hash = wtxIn.GetHash();
// Inserts only if not already there, returns tx inserted or tx found
pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
CWalletTx& wtx = (*ret.first).second;
wtx.BindWallet(this);
bool fInsertedNew = ret.second;
if (fInsertedNew)
{
wtx.nTimeReceived = GetAdjustedTime();
wtx.nOrderPos = IncOrderPosNext(&walletdb);
wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
wtx.nTimeSmart = wtx.nTimeReceived;
if (!wtxIn.hashUnset())
{
if (mapBlockIndex.count(wtxIn.hashBlock))
{
int64_t latestNow = wtx.nTimeReceived;
int64_t latestEntry = 0;
{
// Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
int64_t latestTolerated = latestNow + 300;
const TxItems & txOrdered = wtxOrdered;
for (TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
{
CWalletTx *const pwtx = (*it).second.first;
if (pwtx == &wtx)
continue;
CAccountingEntry *const pacentry = (*it).second.second;
int64_t nSmartTime;
if (pwtx)
{
nSmartTime = pwtx->nTimeSmart;
if (!nSmartTime)
nSmartTime = pwtx->nTimeReceived;
}
else
nSmartTime = pacentry->nTime;
if (nSmartTime <= latestTolerated)
{
latestEntry = nSmartTime;
if (nSmartTime > latestNow)
latestNow = nSmartTime;
break;
}
}
}
int64_t blocktime = mapBlockIndex[wtxIn.hashBlock]->GetBlockTime();
wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
}
else
LogPrintf("AddToWallet(): found %s in block %s not in index\n",
wtxIn.GetHash().ToString(),
wtxIn.hashBlock.ToString());
}
AddToSpends(hash);
}
bool fUpdated = false;
if (!fInsertedNew)
{
// Merge
if (!wtxIn.hashUnset() && wtxIn.hashBlock != wtx.hashBlock)
{
wtx.hashBlock = wtxIn.hashBlock;
fUpdated = true;
}
// If no longer abandoned, update
if (wtxIn.hashBlock.IsNull() && wtx.isAbandoned())
{
wtx.hashBlock = wtxIn.hashBlock;
fUpdated = true;
}
if (wtxIn.nIndex != -1 && (wtxIn.nIndex != wtx.nIndex))
{
wtx.nIndex = wtxIn.nIndex;
fUpdated = true;
}
if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
{
wtx.fFromMe = wtxIn.fFromMe;
fUpdated = true;
}
}
//// debug print
LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
// Write to disk
if (fInsertedNew || fUpdated)
if (!walletdb.WriteTx(wtx))
return false;
// Break debit/credit balance caches:
wtx.MarkDirty();
// Notify UI of new or updated transaction
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
// notify an external script when a wallet transaction comes in or is updated
std::string strCmd = GetArg("-walletnotify", "");
if ( !strCmd.empty())
{
boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
boost::thread t(runCommand, strCmd); // thread runs free
}
return true;
}
bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
{
uint256 hash = wtxIn.GetHash();
mapWallet[hash] = wtxIn;
CWalletTx& wtx = mapWallet[hash];
wtx.BindWallet(this);
wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
AddToSpends(hash);
BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) {
if (mapWallet.count(txin.prevout.hash)) {
CWalletTx& prevtx = mapWallet[txin.prevout.hash];
if (prevtx.nIndex == -1 && !prevtx.hashUnset()) {
MarkConflicted(prevtx.hashBlock, wtx.GetHash());
}
}
}
return true;
}
/**
* Add a transaction to the wallet, or update it.
* pblock is optional, but should be provided if the transaction is known to be in a block.
* If fUpdate is true, existing transactions will be updated.
*/
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate)
{
{
AssertLockHeld(cs_wallet);
if (posInBlock != -1) {
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
while (range.first != range.second) {
if (range.first->second != tx.GetHash()) {
LogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), pIndex->GetBlockHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
MarkConflicted(pIndex->GetBlockHash(), range.first->second);
}
range.first++;
}
}
}
bool fExisted = mapWallet.count(tx.GetHash()) != 0;
if (fExisted && !fUpdate) return false;
if (fExisted || IsMine(tx) || IsFromMe(tx))
{
CWalletTx wtx(this, MakeTransactionRef(tx));
// Get merkle branch if transaction was found in a block
if (posInBlock != -1)
wtx.SetMerkleBranch(pIndex, posInBlock);
return AddToWallet(wtx, false);
}
}
return false;
}
bool CWallet::AbandonTransaction(const uint256& hashTx)
{
LOCK2(cs_main, cs_wallet);
CWalletDB walletdb(strWalletFile, "r+");
std::set<uint256> todo;
std::set<uint256> done;
// Can't mark abandoned if confirmed or in mempool
assert(mapWallet.count(hashTx));
CWalletTx& origtx = mapWallet[hashTx];
if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) {
return false;
}
todo.insert(hashTx);
while (!todo.empty()) {
uint256 now = *todo.begin();
todo.erase(now);
done.insert(now);
assert(mapWallet.count(now));
CWalletTx& wtx = mapWallet[now];
int currentconfirm = wtx.GetDepthInMainChain();
// If the orig tx was not in block, none of its spends can be
assert(currentconfirm <= 0);
// if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
if (currentconfirm == 0 && !wtx.isAbandoned()) {
// If the orig tx was not in block/mempool, none of its spends can be in mempool
assert(!wtx.InMempool());
wtx.nIndex = -1;
wtx.setAbandoned();
wtx.MarkDirty();
walletdb.WriteTx(wtx);
NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED);
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(hashTx, 0));
while (iter != mapTxSpends.end() && iter->first.hash == now) {
if (!done.count(iter->second)) {
todo.insert(iter->second);
}
iter++;
}
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be recomputed
BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
if (mapWallet.count(txin.prevout.hash))
mapWallet[txin.prevout.hash].MarkDirty();
}
}
}
return true;
}
void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
{
LOCK2(cs_main, cs_wallet);
int conflictconfirms = 0;
if (mapBlockIndex.count(hashBlock)) {
CBlockIndex* pindex = mapBlockIndex[hashBlock];
if (chainActive.Contains(pindex)) {
conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1);
}
}
// If number of conflict confirms cannot be determined, this means
// that the block is still unknown or not yet part of the main chain,
// for example when loading the wallet during a reindex. Do nothing in that
// case.
if (conflictconfirms >= 0)
return;
// Do not flush the wallet here for performance reasons
CWalletDB walletdb(strWalletFile, "r+", false);
std::set<uint256> todo;
std::set<uint256> done;
todo.insert(hashTx);
while (!todo.empty()) {
uint256 now = *todo.begin();
todo.erase(now);
done.insert(now);
assert(mapWallet.count(now));
CWalletTx& wtx = mapWallet[now];
int currentconfirm = wtx.GetDepthInMainChain();
if (conflictconfirms < currentconfirm) {
// Block is 'more conflicted' than current confirm; update.
// Mark transaction as conflicted with this block.
wtx.nIndex = -1;
wtx.hashBlock = hashBlock;
wtx.MarkDirty();
walletdb.WriteTx(wtx);
// Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
while (iter != mapTxSpends.end() && iter->first.hash == now) {
if (!done.count(iter->second)) {
todo.insert(iter->second);
}
iter++;
}
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be recomputed
BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
if (mapWallet.count(txin.prevout.hash))
mapWallet[txin.prevout.hash].MarkDirty();
}
}
}
}
void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock)
{
LOCK2(cs_main, cs_wallet);
if (!AddToWalletIfInvolvingMe(tx, pindex, posInBlock, true))
return; // Not one of ours
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be
// recomputed, also:
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
if (mapWallet.count(txin.prevout.hash))
mapWallet[txin.prevout.hash].MarkDirty();
}
}
isminetype CWallet::IsMine(const CTxIn &txin) const
{
{
LOCK(cs_wallet);
map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
if (txin.prevout.n < prev.tx->vout.size())
return IsMine(prev.tx->vout[txin.prevout.n]);
}
}
return ISMINE_NO;
}
CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
{
{
LOCK(cs_wallet);
map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
if (txin.prevout.n < prev.tx->vout.size())
if (IsMine(prev.tx->vout[txin.prevout.n]) & filter)
return prev.tx->vout[txin.prevout.n].nValue;
}
}
return 0;
}
isminetype CWallet::IsMine(const CTxOut& txout) const
{
return ::IsMine(*this, txout.scriptPubKey);
}
CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const
{
if (!MoneyRange(txout.nValue))
throw std::runtime_error(std::string(__func__) + ": value out of range");
return ((IsMine(txout) & filter) ? txout.nValue : 0);
}
bool CWallet::IsChange(const CTxOut& txout) const
{
// TODO: fix handling of 'change' outputs. The assumption is that any
// payment to a script that is ours, but is not in the address book
// is change. That assumption is likely to break when we implement multisignature
// wallets that return change back into a multi-signature-protected address;
// a better way of identifying which outputs are 'the send' and which are
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
// which output, if any, was change).
if (::IsMine(*this, txout.scriptPubKey))
{
CTxDestination address;
if (!ExtractDestination(txout.scriptPubKey, address))
return true;
LOCK(cs_wallet);
if (!mapAddressBook.count(address))
return true;
}
return false;
}
CAmount CWallet::GetChange(const CTxOut& txout) const
{
if (!MoneyRange(txout.nValue))
throw std::runtime_error(std::string(__func__) + ": value out of range");
return (IsChange(txout) ? txout.nValue : 0);
}
bool CWallet::IsMine(const CTransaction& tx) const
{
BOOST_FOREACH(const CTxOut& txout, tx.vout)
if (IsMine(txout))
return true;
return false;
}
bool CWallet::IsFromMe(const CTransaction& tx) const
{
return (GetDebit(tx, ISMINE_ALL) > 0);
}
CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) const
{
CAmount nDebit = 0;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
nDebit += GetDebit(txin, filter);
if (!MoneyRange(nDebit))
throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nDebit;
}
CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const
{
CAmount nCredit = 0;
BOOST_FOREACH(const CTxOut& txout, tx.vout)
{
nCredit += GetCredit(txout, filter);
if (!MoneyRange(nCredit))
throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nCredit;
}
CAmount CWallet::GetChange(const CTransaction& tx) const
{
CAmount nChange = 0;
BOOST_FOREACH(const CTxOut& txout, tx.vout)
{
nChange += GetChange(txout);
if (!MoneyRange(nChange))
throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nChange;
}
CPubKey CWallet::GenerateNewHDMasterKey()
{
CKey key;
key.MakeNewKey(true);
int64_t nCreationTime = GetTime();
CKeyMetadata metadata(nCreationTime);
// calculate the pubkey
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey));
// set the hd keypath to "m" -> Master, refers the masterkeyid to itself
metadata.hdKeypath = "m";
metadata.hdMasterKeyID = pubkey.GetID();
{
LOCK(cs_wallet);
// mem store the metadata
mapKeyMetadata[pubkey.GetID()] = metadata;
// write the key&metadata to the database
if (!AddKeyPubKey(key, pubkey))
throw std::runtime_error(std::string(__func__) + ": AddKeyPubKey failed");
}
return pubkey;
}
bool CWallet::SetHDMasterKey(const CPubKey& pubkey)
{
LOCK(cs_wallet);
// ensure this wallet.dat can only be opened by clients supporting HD
SetMinVersion(FEATURE_HD);
// store the keyid (hash160) together with
// the child index counter in the database
// as a hdchain object
CHDChain newHdChain;
newHdChain.masterKeyID = pubkey.GetID();
SetHDChain(newHdChain, false);
return true;
}
bool CWallet::SetHDChain(const CHDChain& chain, bool memonly)
{
LOCK(cs_wallet);
if (!memonly && !CWalletDB(strWalletFile).WriteHDChain(chain))
throw runtime_error(std::string(__func__) + ": writing chain failed");
hdChain = chain;
return true;
}
bool CWallet::IsHDEnabled()
{
return !hdChain.masterKeyID.IsNull();
}
int64_t CWalletTx::GetTxTime() const
{
int64_t n = nTimeSmart;
return n ? n : nTimeReceived;
}
int CWalletTx::GetRequestCount() const
{
// Returns -1 if it wasn't being tracked
int nRequests = -1;
{
LOCK(pwallet->cs_wallet);
if (IsCoinBase())
{
// Generated block
if (!hashUnset())
{
map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
if (mi != pwallet->mapRequestCount.end())
nRequests = (*mi).second;
}
}
else
{
// Did anyone request this transaction?
map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
if (mi != pwallet->mapRequestCount.end())
{
nRequests = (*mi).second;
// How about the block it's in?
if (nRequests == 0 && !hashUnset())
{
map<uint256, int>::const_iterator _mi = pwallet->mapRequestCount.find(hashBlock);
if (_mi != pwallet->mapRequestCount.end())
nRequests = (*_mi).second;
else
nRequests = 1; // If it's in someone else's block it must have got out
}
}
}
}
return nRequests;
}
void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
list<COutputEntry>& listSent, CAmount& nFee, string& strSentAccount, const isminefilter& filter) const
{
nFee = 0;
listReceived.clear();
listSent.clear();
strSentAccount = strFromAccount;
// Compute fee:
CAmount nDebit = GetDebit(filter);
if (nDebit > 0) // debit>0 means we signed/sent this transaction
{
CAmount nValueOut = tx->GetValueOut();
nFee = nDebit - nValueOut;
}
// Sent/received.
for (unsigned int i = 0; i < tx->vout.size(); ++i)
{
const CTxOut& txout = tx->vout[i];
isminetype fIsMine = pwallet->IsMine(txout);
// Only need to handle txouts if AT LEAST one of these is true:
// 1) they debit from us (sent)
// 2) the output is to us (received)
if (nDebit > 0)
{
// Don't report 'change' txouts
if (pwallet->IsChange(txout))
continue;
}
else if (!(fIsMine & filter))
continue;
// In either case, we need to get the destination address
CTxDestination address;
if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
{
LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
this->GetHash().ToString());
address = CNoDestination();
}
COutputEntry output = {address, txout.nValue, (int)i};
// If we are debited by the transaction, add the output as a "sent" entry
if (nDebit > 0)
listSent.push_back(output);
// If we are receiving the output, add it as a "received" entry
if (fIsMine & filter)
listReceived.push_back(output);
}
}
void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived,
CAmount& nSent, CAmount& nFee, const isminefilter& filter) const
{
nReceived = nSent = nFee = 0;
CAmount allFee;
string strSentAccount;
list<COutputEntry> listReceived;
list<COutputEntry> listSent;
GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
if (strAccount == strSentAccount)
{
BOOST_FOREACH(const COutputEntry& s, listSent)
nSent += s.amount;
nFee = allFee;
}
{
LOCK(pwallet->cs_wallet);
BOOST_FOREACH(const COutputEntry& r, listReceived)
{
if (pwallet->mapAddressBook.count(r.destination))
{
map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(r.destination);
if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount)
nReceived += r.amount;
}
else if (strAccount.empty())
{
nReceived += r.amount;
}
}
}
}
/**
* Scan the block chain (starting in pindexStart) for transactions
* from or to us. If fUpdate is true, found transactions that already
* exist in the wallet will be updated.
*/
int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
{
int ret = 0;
int64_t nNow = GetTime();
const CChainParams& chainParams = Params();
CBlockIndex* pindex = pindexStart;
{
LOCK2(cs_main, cs_wallet);
// no need to read and scan block, if block was created before
// our wallet birthday (as adjusted for block time variability)
while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200)))
pindex = chainActive.Next(pindex);
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
double dProgressStart = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false);
double dProgressTip = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip(), false);
while (pindex)
{
if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0)
ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100))));
CBlock block;
ReadBlockFromDisk(block, pindex, Params().GetConsensus());
int posInBlock;
for (posInBlock = 0; posInBlock < (int)block.vtx.size(); posInBlock++)
{
if (AddToWalletIfInvolvingMe(*block.vtx[posInBlock], pindex, posInBlock, fUpdate))
ret++;
}
pindex = chainActive.Next(pindex);
if (GetTime() >= nNow + 60) {
nNow = GetTime();
LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex));
}
}
ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI
}
return ret;
}
void CWallet::ReacceptWalletTransactions()
{
// If transactions aren't being broadcasted, don't let them into local mempool either
if (!fBroadcastTransactions)
return;
LOCK2(cs_main, cs_wallet);
std::map<int64_t, CWalletTx*> mapSorted;
// Sort pending wallet transactions based on their initial wallet insertion order
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
{
const uint256& wtxid = item.first;
CWalletTx& wtx = item.second;
assert(wtx.GetHash() == wtxid);
int nDepth = wtx.GetDepthInMainChain();
if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) {
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
}
}
// Try to add wallet transactions to memory pool
BOOST_FOREACH(PAIRTYPE(const int64_t, CWalletTx*)& item, mapSorted)
{
CWalletTx& wtx = *(item.second);
LOCK(mempool.cs);
CValidationState state;
wtx.AcceptToMemoryPool(maxTxFee, state);
}
}
bool CWalletTx::RelayWalletTransaction(CConnman* connman)
{
assert(pwallet->GetBroadcastTransactions());
if (!IsCoinBase() && !isAbandoned() && GetDepthInMainChain() == 0)
{
CValidationState state;
/* GetDepthInMainChain already catches known conflicts. */
if (InMempool() || AcceptToMemoryPool(maxTxFee, state)) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
if (connman) {
CInv inv(MSG_TX, GetHash());
connman->ForEachNode([&inv](CNode* pnode)
{
pnode->PushInventory(inv);
});
return true;
}
}
}
return false;
}
set<uint256> CWalletTx::GetConflicts() const
{
set<uint256> result;
if (pwallet != NULL)
{
uint256 myHash = GetHash();
result = pwallet->GetConflicts(myHash);
result.erase(myHash);
}
return result;
}
CAmount CWalletTx::GetDebit(const isminefilter& filter) const
{
if (tx->vin.empty())
return 0;
CAmount debit = 0;
if(filter & ISMINE_SPENDABLE)
{
if (fDebitCached)
debit += nDebitCached;
else
{
nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE);
fDebitCached = true;
debit += nDebitCached;
}
}
if(filter & ISMINE_WATCH_ONLY)
{
if(fWatchDebitCached)
debit += nWatchDebitCached;
else
{
nWatchDebitCached = pwallet->GetDebit(*this, ISMINE_WATCH_ONLY);
fWatchDebitCached = true;
debit += nWatchDebitCached;
}
}
return debit;
}
CAmount CWalletTx::GetCredit(const isminefilter& filter) const
{
// Must wait until coinbase is safely deep enough in the chain before valuing it
if (IsCoinBase() && GetBlocksToMaturity() > 0)
return 0;
CAmount credit = 0;
if (filter & ISMINE_SPENDABLE)
{
// GetBalance can assume transactions in mapWallet won't change
if (fCreditCached)
credit += nCreditCached;
else
{
nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
fCreditCached = true;
credit += nCreditCached;
}
}
if (filter & ISMINE_WATCH_ONLY)
{
if (fWatchCreditCached)
credit += nWatchCreditCached;
else
{
nWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
fWatchCreditCached = true;
credit += nWatchCreditCached;
}
}
return credit;
}
CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
{
if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
{
if (fUseCache && fImmatureCreditCached)
return nImmatureCreditCached;
nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
fImmatureCreditCached = true;
return nImmatureCreditCached;
}
return 0;
}
CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
{
if (pwallet == 0)
return 0;
// Must wait until coinbase is safely deep enough in the chain before valuing it
if (IsCoinBase() && GetBlocksToMaturity() > 0)
return 0;
if (fUseCache && fAvailableCreditCached)
return nAvailableCreditCached;
CAmount nCredit = 0;
uint256 hashTx = GetHash();
for (unsigned int i = 0; i < tx->vout.size(); i++)
{
if (!pwallet->IsSpent(hashTx, i))
{
const CTxOut &txout = tx->vout[i];
nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);
if (!MoneyRange(nCredit))
throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
}
}
nAvailableCreditCached = nCredit;
fAvailableCreditCached = true;
return nCredit;
}
CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const
{
if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
{
if (fUseCache && fImmatureWatchCreditCached)
return nImmatureWatchCreditCached;
nImmatureWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
fImmatureWatchCreditCached = true;
return nImmatureWatchCreditCached;
}
return 0;
}
CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const
{
if (pwallet == 0)
return 0;
// Must wait until coinbase is safely deep enough in the chain before valuing it
if (IsCoinBase() && GetBlocksToMaturity() > 0)
return 0;
if (fUseCache && fAvailableWatchCreditCached)
return nAvailableWatchCreditCached;
CAmount nCredit = 0;
for (unsigned int i = 0; i < tx->vout.size(); i++)
{
if (!pwallet->IsSpent(GetHash(), i))
{
const CTxOut &txout = tx->vout[i];
nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY);
if (!MoneyRange(nCredit))
throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
}
}
nAvailableWatchCreditCached = nCredit;
fAvailableWatchCreditCached = true;
return nCredit;
}
CAmount CWalletTx::GetChange() const
{
if (fChangeCached)
return nChangeCached;
nChangeCached = pwallet->GetChange(*this);
fChangeCached = true;
return nChangeCached;
}
bool CWalletTx::InMempool() const
{
LOCK(mempool.cs);
if (mempool.exists(GetHash())) {
return true;
}
return false;
}
bool CWalletTx::IsTrusted() const
{
// Quick answer in most cases
if (!CheckFinalTx(*this))
return false;
int nDepth = GetDepthInMainChain();
if (nDepth >= 1)
return true;
if (nDepth < 0)
return false;
if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit
return false;
// Don't trust unconfirmed transactions from us unless they are in the mempool.
if (!InMempool())
return false;
// Trusted if all inputs are from us and are in the mempool:
BOOST_FOREACH(const CTxIn& txin, tx->vin)
{
// Transactions not sent by us: not trusted
const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash);
if (parent == NULL)
return false;
const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE)
return false;
}
return true;
}
bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const
{
CMutableTransaction tx1 = *this->tx;
CMutableTransaction tx2 = *_tx.tx;
for (unsigned int i = 0; i < tx1.vin.size(); i++) tx1.vin[i].scriptSig = CScript();
for (unsigned int i = 0; i < tx2.vin.size(); i++) tx2.vin[i].scriptSig = CScript();
return CTransaction(tx1) == CTransaction(tx2);
}
std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman)
{
std::vector<uint256> result;
LOCK(cs_wallet);
// Sort them in chronological order
multimap<unsigned int, CWalletTx*> mapSorted;
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
{
CWalletTx& wtx = item.second;
// Don't rebroadcast if newer than nTime:
if (wtx.nTimeReceived > nTime)
continue;
mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
}
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
{
CWalletTx& wtx = *item.second;
if (wtx.RelayWalletTransaction(connman))
result.push_back(wtx.GetHash());
}
return result;
}
void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman)
{
// Do this infrequently and randomly to avoid giving away
// that these are our transactions.
if (GetTime() < nNextResend || !fBroadcastTransactions)
return;
bool fFirst = (nNextResend == 0);
nNextResend = GetTime() + GetRand(30 * 60);
if (fFirst)
return;
// Only do it if there's been a new block since last time
if (nBestBlockTime < nLastResend)
return;
nLastResend = GetTime();
// Rebroadcast unconfirmed txes older than 5 minutes before the last
// block was found:
std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60, connman);
if (!relayed.empty())
LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
}
/** @} */ // end of mapWallet
/** @defgroup Actions
*
* @{
*/
CAmount CWallet::GetBalance() const
{
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (pcoin->IsTrusted())
nTotal += pcoin->GetAvailableCredit();
}
}
return nTotal;
}
CAmount CWallet::GetUnconfirmedBalance() const
{
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
nTotal += pcoin->GetAvailableCredit();
}
}
return nTotal;
}
CAmount CWallet::GetImmatureBalance() const
{
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
nTotal += pcoin->GetImmatureCredit();
}
}
return nTotal;
}
CAmount CWallet::GetWatchOnlyBalance() const
{
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (pcoin->IsTrusted())
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
}
return nTotal;
}
CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
{
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
}
return nTotal;
}
CAmount CWallet::GetImmatureWatchOnlyBalance() const
{
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
nTotal += pcoin->GetImmatureWatchOnlyCredit();
}
}
return nTotal;
}
void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue) const
{
vCoins.clear();
{
LOCK2(cs_main, cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const uint256& wtxid = it->first;
const CWalletTx* pcoin = &(*it).second;
if (!CheckFinalTx(*pcoin))
continue;
if (fOnlyConfirmed && !pcoin->IsTrusted())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
continue;
int nDepth = pcoin->GetDepthInMainChain();
if (nDepth < 0)
continue;
// We should not consider coins which aren't at least in our mempool
// It's possible for these to be conflicted via ancestors which we may never be able to detect
if (nDepth == 0 && !pcoin->InMempool())
continue;
for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) {
isminetype mine = IsMine(pcoin->tx->vout[i]);
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
!IsLockedCoin((*it).first, i) && (pcoin->tx->vout[i].nValue > 0 || fIncludeZeroValue) &&
(!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected(COutPoint((*it).first, i))))
vCoins.push_back(COutput(pcoin, i, nDepth,
((mine & ISMINE_SPENDABLE) != ISMINE_NO) ||
(coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO),
(mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO));
}
}
}
}
static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > >vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,
vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
{
vector<char> vfIncluded;
vfBest.assign(vValue.size(), true);
nBest = nTotalLower;
FastRandomContext insecure_rand;
for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
{
vfIncluded.assign(vValue.size(), false);
CAmount nTotal = 0;
bool fReachedTarget = false;
for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
{
for (unsigned int i = 0; i < vValue.size(); i++)
{
//The solver here uses a randomized algorithm,
//the randomness serves no real security purpose but is just
//needed to prevent degenerate behavior and it is important
//that the rng is fast. We do not use a constant random sequence,
//because there may be some privacy improvement by making
//the selection random.
if (nPass == 0 ? insecure_rand.rand32()&1 : !vfIncluded[i])
{
nTotal += vValue[i].first;
vfIncluded[i] = true;
if (nTotal >= nTargetValue)
{
fReachedTarget = true;
if (nTotal < nBest)
{
nBest = nTotal;
vfBest = vfIncluded;
}
nTotal -= vValue[i].first;
vfIncluded[i] = false;
}
}
}
}
}
}
bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, vector<COutput> vCoins,
set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const
{
setCoinsRet.clear();
nValueRet = 0;
// List of values less than target
pair<CAmount, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
coinLowestLarger.first = std::numeric_limits<CAmount>::max();
coinLowestLarger.second.first = NULL;
vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > > vValue;
CAmount nTotalLower = 0;
random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
BOOST_FOREACH(const COutput &output, vCoins)
{
if (!output.fSpendable)
continue;
const CWalletTx *pcoin = output.tx;
if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs))
continue;
if (!mempool.TransactionWithinChainLimit(pcoin->GetHash(), nMaxAncestors))
continue;
int i = output.i;
CAmount n = pcoin->tx->vout[i].nValue;
pair<CAmount,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i));
if (n == nTargetValue)
{
setCoinsRet.insert(coin.second);
nValueRet += coin.first;
return true;
}
else if (n < nTargetValue + MIN_CHANGE)
{
vValue.push_back(coin);
nTotalLower += n;
}
else if (n < coinLowestLarger.first)
{
coinLowestLarger = coin;
}
}
if (nTotalLower == nTargetValue)
{
for (unsigned int i = 0; i < vValue.size(); ++i)
{
setCoinsRet.insert(vValue[i].second);
nValueRet += vValue[i].first;
}
return true;
}
if (nTotalLower < nTargetValue)
{
if (coinLowestLarger.second.first == NULL)
return false;
setCoinsRet.insert(coinLowestLarger.second);
nValueRet += coinLowestLarger.first;
return true;
}
// Solve subset sum by stochastic approximation
std::sort(vValue.begin(), vValue.end(), CompareValueOnly());
std::reverse(vValue.begin(), vValue.end());
vector<char> vfBest;
CAmount nBest;
ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest);
if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE)
ApproximateBestSubset(vValue, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest);
// If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
// or the next bigger coin is closer), return the bigger coin
if (coinLowestLarger.second.first &&
((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || coinLowestLarger.first <= nBest))
{
setCoinsRet.insert(coinLowestLarger.second);
nValueRet += coinLowestLarger.first;
}
else {
for (unsigned int i = 0; i < vValue.size(); i++)
if (vfBest[i])
{
setCoinsRet.insert(vValue[i].second);
nValueRet += vValue[i].first;
}
LogPrint("selectcoins", "SelectCoins() best subset: ");
for (unsigned int i = 0; i < vValue.size(); i++)
if (vfBest[i])
LogPrint("selectcoins", "%s ", FormatMoney(vValue[i].first));
LogPrint("selectcoins", "total %s\n", FormatMoney(nBest));
}
return true;
}
bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const
{
vector<COutput> vCoins(vAvailableCoins);
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs)
{
BOOST_FOREACH(const COutput& out, vCoins)
{
if (!out.fSpendable)
continue;
nValueRet += out.tx->tx->vout[out.i].nValue;
setCoinsRet.insert(make_pair(out.tx, out.i));
}
return (nValueRet >= nTargetValue);
}
// calculate value from preset inputs and store them
set<pair<const CWalletTx*, uint32_t> > setPresetCoins;
CAmount nValueFromPresetInputs = 0;
std::vector<COutPoint> vPresetInputs;
if (coinControl)
coinControl->ListSelected(vPresetInputs);
BOOST_FOREACH(const COutPoint& outpoint, vPresetInputs)
{
map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash);
if (it != mapWallet.end())
{
const CWalletTx* pcoin = &it->second;
// Clearly invalid input, fail
if (pcoin->tx->vout.size() <= outpoint.n)
return false;
nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue;
setPresetCoins.insert(make_pair(pcoin, outpoint.n));
} else
return false; // TODO: Allow non-wallet inputs
}
// remove preset inputs from vCoins
for (vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();)
{
if (setPresetCoins.count(make_pair(it->tx, it->i)))
it = vCoins.erase(it);
else
++it;
}
size_t nMaxChainLength = std::min(GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT), GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT));
bool fRejectLongChains = GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS);
bool res = nTargetValue <= nValueFromPresetInputs ||
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, 0, vCoins, setCoinsRet, nValueRet) ||
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, 0, vCoins, setCoinsRet, nValueRet) ||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, 2, vCoins, setCoinsRet, nValueRet)) ||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::min((size_t)4, nMaxChainLength/3), vCoins, setCoinsRet, nValueRet)) ||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength/2, vCoins, setCoinsRet, nValueRet)) ||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength, vCoins, setCoinsRet, nValueRet)) ||
(bSpendZeroConfChange && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::numeric_limits<uint64_t>::max(), vCoins, setCoinsRet, nValueRet));
// because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());
// add preset inputs to the total value selected
nValueRet += nValueFromPresetInputs;
return res;
}
bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const CTxDestination& destChange)
{
vector<CRecipient> vecSend;
// Turn the txout set into a CRecipient vector
BOOST_FOREACH(const CTxOut& txOut, tx.vout)
{
CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, false};
vecSend.push_back(recipient);
}
CCoinControl coinControl;
coinControl.destChange = destChange;
coinControl.fAllowOtherInputs = true;
coinControl.fAllowWatchOnly = includeWatching;
coinControl.fOverrideFeeRate = overrideEstimatedFeeRate;
coinControl.nFeeRate = specificFeeRate;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
coinControl.Select(txin.prevout);
CReserveKey reservekey(this);
CWalletTx wtx;
if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, &coinControl, false))
return false;
if (nChangePosInOut != -1)
tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.tx->vout[nChangePosInOut]);
// Add new txins (keeping original txin scriptSig/order)
BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
if (!coinControl.IsSelected(txin.prevout))
{
tx.vin.push_back(txin);
if (lockUnspents)
{
LOCK2(cs_main, cs_wallet);
LockCoin(txin.prevout);
}
}
}
return true;
}
bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign)
{
CAmount nValue = 0;
int nChangePosRequest = nChangePosInOut;
unsigned int nSubtractFeeFromAmount = 0;
BOOST_FOREACH (const CRecipient& recipient, vecSend)
{
if (nValue < 0 || recipient.nAmount < 0)
{
strFailReason = _("Transaction amounts must not be negative");
return false;
}
nValue += recipient.nAmount;
if (recipient.fSubtractFeeFromAmount)
nSubtractFeeFromAmount++;
}
if (vecSend.empty())
{
strFailReason = _("Transaction must have at least one recipient");
return false;
}
wtxNew.fTimeReceivedIsTxTime = true;
wtxNew.BindWallet(this);
CMutableTransaction txNew;
// Discourage fee sniping.
//
// For a large miner the value of the transactions in the best block and
// the mempool can exceed the cost of deliberately attempting to mine two
// blocks to orphan the current best block. By setting nLockTime such that
// only the next block can include the transaction, we discourage this
// practice as the height restricted and limited blocksize gives miners
// considering fee sniping fewer options for pulling off this attack.
//
// A simple way to think about this is from the wallet's point of view we
// always want the blockchain to move forward. By setting nLockTime this
// way we're basically making the statement that we only want this
// transaction to appear in the next block; we don't want to potentially
// encourage reorgs by allowing transactions to appear at lower heights
// than the next block in forks of the best chain.
//
// Of course, the subsidy is high enough, and transaction volume low
// enough, that fee sniping isn't a problem yet, but by implementing a fix
// now we ensure code won't be written that makes assumptions about
// nLockTime that preclude a fix later.
txNew.nLockTime = chainActive.Height();
// Secondly occasionally randomly pick a nLockTime even further back, so
// that transactions that are delayed after signing for whatever reason,
// e.g. high-latency mix networks and some CoinJoin implementations, have
// better privacy.
if (GetRandInt(10) == 0)
txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100));
assert(txNew.nLockTime <= (unsigned int)chainActive.Height());
assert(txNew.nLockTime < LOCKTIME_THRESHOLD);
{
LOCK2(cs_main, cs_wallet);
{
std::vector<COutput> vAvailableCoins;
AvailableCoins(vAvailableCoins, true, coinControl);
nFeeRet = 0;
// Start with no fee and loop until there is enough fee
while (true)
{
nChangePosInOut = nChangePosRequest;
txNew.vin.clear();
txNew.vout.clear();
wtxNew.fFromMe = true;
bool fFirst = true;
CAmount nValueToSelect = nValue;
if (nSubtractFeeFromAmount == 0)
nValueToSelect += nFeeRet;
double dPriority = 0;
// vouts to the payees
BOOST_FOREACH (const CRecipient& recipient, vecSend)
{
CTxOut txout(recipient.nAmount, recipient.scriptPubKey);
if (recipient.fSubtractFeeFromAmount)
{
txout.nValue -= nFeeRet / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient
if (fFirst) // first receiver pays the remainder not divisible by output count
{
fFirst = false;
txout.nValue -= nFeeRet % nSubtractFeeFromAmount;
}
}
if (txout.IsDust(::minRelayTxFee))
{
if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
{
if (txout.nValue < 0)
strFailReason = _("The transaction amount is too small to pay the fee");
else
strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
}
else
strFailReason = _("Transaction amount too small");
return false;
}
txNew.vout.push_back(txout);
}
// Choose coins to use
set<pair<const CWalletTx*,unsigned int> > setCoins;
CAmount nValueIn = 0;
if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl))
{
strFailReason = _("Insufficient funds");
return false;
}
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
{
CAmount nCredit = pcoin.first->tx->vout[pcoin.second].nValue;
//The coin age after the next block (depth+1) is used instead of the current,
//reflecting an assumption the user would accept a bit more delay for
//a chance at a free transaction.
//But mempool inputs might still be in the mempool, so their age stays 0
int age = pcoin.first->GetDepthInMainChain();
assert(age >= 0);
if (age != 0)
age += 1;
dPriority += (double)nCredit * age;
}
const CAmount nChange = nValueIn - nValueToSelect;
if (nChange > 0)
{
// Fill a vout to ourself
// TODO: pass in scriptChange instead of reservekey so
// change transaction isn't always pay-to-bitcoin-address
CScript scriptChange;
// coin control: send change to custom address
if (coinControl && !boost::get<CNoDestination>(&coinControl->destChange))
scriptChange = GetScriptForDestination(coinControl->destChange);
// no coin control: send change to newly generated address
else
{
// Note: We use a new key here to keep it from being obvious which side is the change.
// The drawback is that by not reusing a previous key, the change may be lost if a
// backup is restored, if the backup doesn't have the new private key for the change.
// If we reused the old key, it would be possible to add code to look for and
// rediscover unknown transactions that were written with keys of ours to recover
// post-backup change.
// Reserve a new key pair from key pool
CPubKey vchPubKey;
bool ret;
ret = reservekey.GetReservedKey(vchPubKey);
if (!ret)
{
strFailReason = _("Keypool ran out, please call keypoolrefill first");
return false;
}
scriptChange = GetScriptForDestination(vchPubKey.GetID());
}
CTxOut newTxOut(nChange, scriptChange);
// We do not move dust-change to fees, because the sender would end up paying more than requested.
// This would be against the purpose of the all-inclusive feature.
// So instead we raise the change and deduct from the recipient.
if (nSubtractFeeFromAmount > 0 && newTxOut.IsDust(::minRelayTxFee))
{
CAmount nDust = newTxOut.GetDustThreshold(::minRelayTxFee) - newTxOut.nValue;
newTxOut.nValue += nDust; // raise change until no more dust
for (unsigned int i = 0; i < vecSend.size(); i++) // subtract from first recipient
{
if (vecSend[i].fSubtractFeeFromAmount)
{
txNew.vout[i].nValue -= nDust;
if (txNew.vout[i].IsDust(::minRelayTxFee))
{
strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
return false;
}
break;
}
}
}
// Never create dust outputs; if we would, just
// add the dust to the fee.
if (newTxOut.IsDust(::minRelayTxFee))
{
nChangePosInOut = -1;
nFeeRet += nChange;
reservekey.ReturnKey();
}
else
{
if (nChangePosInOut == -1)
{
// Insert change txn at random position:
nChangePosInOut = GetRandInt(txNew.vout.size()+1);
}
else if ((unsigned int)nChangePosInOut > txNew.vout.size())
{
strFailReason = _("Change index out of range");
return false;
}
vector<CTxOut>::iterator position = txNew.vout.begin()+nChangePosInOut;
txNew.vout.insert(position, newTxOut);
}
}
else
reservekey.ReturnKey();
// Fill vin
//
// Note how the sequence number is set to non-maxint so that
// the nLockTime set above actually works.
//
// BIP125 defines opt-in RBF as any nSequence < maxint-1, so
// we use the highest possible value in that range (maxint-2)
// to avoid conflicting with other possible uses of nSequence,
// and in the spirit of "smallest posible change from prior
// behavior."
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second,CScript(),
std::numeric_limits<unsigned int>::max() - (fWalletRbf ? 2 : 1)));
// Sign
int nIn = 0;
CTransaction txNewConst(txNew);
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
{
bool signSuccess;
const CScript& scriptPubKey = coin.first->tx->vout[coin.second].scriptPubKey;
SignatureData sigdata;
if (sign)
signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->tx->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata);
else
signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata);
if (!signSuccess)
{
strFailReason = _("Signing transaction failed");
return false;
} else {
UpdateTransaction(txNew, nIn, sigdata);
}
nIn++;
}
unsigned int nBytes = GetVirtualTransactionSize(txNew);
// Remove scriptSigs if we used dummy signatures for fee calculation
if (!sign) {
BOOST_FOREACH (CTxIn& vin, txNew.vin) {
vin.scriptSig = CScript();
vin.scriptWitness.SetNull();
}
}
// Embed the constructed transaction data in wtxNew.
wtxNew.SetTx(MakeTransactionRef(std::move(txNew)));
// Limit size
if (GetTransactionWeight(wtxNew) >= MAX_STANDARD_TX_WEIGHT)
{
strFailReason = _("Transaction too large");
return false;
}
dPriority = wtxNew.tx->ComputePriority(dPriority, nBytes);
// Allow to override the default confirmation target over the CoinControl instance
int currentConfirmationTarget = nTxConfirmTarget;
if (coinControl && coinControl->nConfirmTarget > 0)
currentConfirmationTarget = coinControl->nConfirmTarget;
// Can we complete this as a free transaction?
if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
{
// Not enough fee: enough priority?
double dPriorityNeeded = mempool.estimateSmartPriority(currentConfirmationTarget);
// Require at least hard-coded AllowFree.
if (dPriority >= dPriorityNeeded && AllowFree(dPriority))
break;
}
CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, mempool);
if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) {
nFeeNeeded = coinControl->nMinimumTotalFee;
}
if (coinControl && coinControl->fOverrideFeeRate)
nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes);
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// because we must be at the maximum allowed fee.
if (nFeeNeeded < ::minRelayTxFee.GetFee(nBytes))
{
strFailReason = _("Transaction too large for fee policy");
return false;
}
if (nFeeRet >= nFeeNeeded)
break; // Done, enough fee included.
// Include more fee and try again.
nFeeRet = nFeeNeeded;
continue;
}
}
}
if (GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
// Lastly, ensure this tx will pass the mempool's chain limits
LockPoints lp;
CTxMemPoolEntry entry(txNew, 0, 0, 0, 0, false, 0, false, 0, lp);
CTxMemPool::setEntries setAncestors;
size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;
size_t nLimitDescendants = GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
size_t nLimitDescendantSize = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000;
std::string errString;
if (!mempool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {
strFailReason = _("Transaction has too long of a mempool chain");
return false;
}
}
return true;
}
/**
* Call after CreateTransaction unless you want to abort
*/
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state)
{
{
LOCK2(cs_main, cs_wallet);
LogPrintf("CommitTransaction:\n%s", wtxNew.tx->ToString());
{
// Take key pair from key pool so it won't be used again
reservekey.KeepKey();
// Add tx to wallet, because if it has change it's also ours,
// otherwise just for transaction history.
AddToWallet(wtxNew);
// Notify that old coins are spent
BOOST_FOREACH(const CTxIn& txin, wtxNew.tx->vin)
{
CWalletTx &coin = mapWallet[txin.prevout.hash];
coin.BindWallet(this);
NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
}
}
// Track how many getdata requests our transaction gets
mapRequestCount[wtxNew.GetHash()] = 0;
if (fBroadcastTransactions)
{
// Broadcast
if (!wtxNew.AcceptToMemoryPool(maxTxFee, state)) {
LogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", state.GetRejectReason());
// TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
} else {
wtxNew.RelayWalletTransaction(connman);
}
}
}
return true;
}
void CWallet::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) {
CWalletDB walletdb(strWalletFile);
return walletdb.ListAccountCreditDebit(strAccount, entries);
}
bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry)
{
CWalletDB walletdb(strWalletFile);
return AddAccountingEntry(acentry, &walletdb);
}
bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB *pwalletdb)
{
if (!pwalletdb->WriteAccountingEntry_Backend(acentry))
return false;
laccentries.push_back(acentry);
CAccountingEntry & entry = laccentries.back();
wtxOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
return true;
}
CAmount CWallet::GetRequiredFee(unsigned int nTxBytes)
{
return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
}
CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool)
{
// payTxFee is user-set "I want to pay this much"
CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
// User didn't set: use -txconfirmtarget to estimate...
if (nFeeNeeded == 0) {
int estimateFoundTarget = nConfirmTarget;
nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes);
// ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
if (nFeeNeeded == 0)
nFeeNeeded = fallbackFee.GetFee(nTxBytes);
}
// prevent user from paying a fee below minRelayTxFee or minTxFee
nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes));
// But always obey the maximum
if (nFeeNeeded > maxTxFee)
nFeeNeeded = maxTxFee;
return nFeeNeeded;
}
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
{
if (!fFileBacked)
return DB_LOAD_OK;
fFirstRunRet = false;
DBErrors nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
if (nLoadWalletRet == DB_NEED_REWRITE)
{
if (CDB::Rewrite(strWalletFile, "\x04pool"))
{
LOCK(cs_wallet);
setKeyPool.clear();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
}
}
if (nLoadWalletRet != DB_LOAD_OK)
return nLoadWalletRet;
fFirstRunRet = !vchDefaultKey.IsValid();
uiInterface.LoadWallet(this);
return DB_LOAD_OK;
}
DBErrors CWallet::ZapSelectTx(vector<uint256>& vHashIn, vector<uint256>& vHashOut)
{
if (!fFileBacked)
return DB_LOAD_OK;
DBErrors nZapSelectTxRet = CWalletDB(strWalletFile,"cr+").ZapSelectTx(this, vHashIn, vHashOut);
if (nZapSelectTxRet == DB_NEED_REWRITE)
{
if (CDB::Rewrite(strWalletFile, "\x04pool"))
{
LOCK(cs_wallet);
setKeyPool.clear();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
}
}
if (nZapSelectTxRet != DB_LOAD_OK)
return nZapSelectTxRet;
MarkDirty();
return DB_LOAD_OK;
}
DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{
if (!fFileBacked)
return DB_LOAD_OK;
DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this, vWtx);
if (nZapWalletTxRet == DB_NEED_REWRITE)
{
if (CDB::Rewrite(strWalletFile, "\x04pool"))
{
LOCK(cs_wallet);
setKeyPool.clear();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
}
}
if (nZapWalletTxRet != DB_LOAD_OK)
return nZapWalletTxRet;
return DB_LOAD_OK;
}
bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose)
{
bool fUpdated = false;
{
LOCK(cs_wallet); // mapAddressBook
std::map<CTxDestination, CAddressBookData>::iterator mi = mapAddressBook.find(address);
fUpdated = mi != mapAddressBook.end();
mapAddressBook[address].name = strName;
if (!strPurpose.empty()) /* update purpose only if requested */
mapAddressBook[address].purpose = strPurpose;
}
NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO,
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
if (!fFileBacked)
return false;
if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose))
return false;
return CWalletDB(strWalletFile).WriteName(CBitcoinAddress(address).ToString(), strName);
}
bool CWallet::DelAddressBook(const CTxDestination& address)
{
{
LOCK(cs_wallet); // mapAddressBook
if(fFileBacked)
{
// Delete destdata tuples associated with address
std::string strAddress = CBitcoinAddress(address).ToString();
BOOST_FOREACH(const PAIRTYPE(string, string) &item, mapAddressBook[address].destdata)
{
CWalletDB(strWalletFile).EraseDestData(strAddress, item.first);
}
}
mapAddressBook.erase(address);
}
NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, "", CT_DELETED);
if (!fFileBacked)
return false;
CWalletDB(strWalletFile).ErasePurpose(CBitcoinAddress(address).ToString());
return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString());
}
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
{
if (fFileBacked)
{
if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
return false;
}
vchDefaultKey = vchPubKey;
return true;
}
/**
* Mark old keypool keys as used,
* and generate all new keys
*/
bool CWallet::NewKeyPool()
{
{
LOCK(cs_wallet);
CWalletDB walletdb(strWalletFile);
BOOST_FOREACH(int64_t nIndex, setKeyPool)
walletdb.ErasePool(nIndex);
setKeyPool.clear();
if (IsLocked())
return false;
int64_t nKeys = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t)0);
for (int i = 0; i < nKeys; i++)
{
int64_t nIndex = i+1;
walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
setKeyPool.insert(nIndex);
}
LogPrintf("CWallet::NewKeyPool wrote %d new keys\n", nKeys);
}
return true;
}
bool CWallet::TopUpKeyPool(unsigned int kpSize)
{
{
LOCK(cs_wallet);
if (IsLocked())
return false;
CWalletDB walletdb(strWalletFile);
// Top up key pool
unsigned int nTargetSize;
if (kpSize > 0)
nTargetSize = kpSize;
else
nTargetSize = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0);
while (setKeyPool.size() < (nTargetSize + 1))
{
int64_t nEnd = 1;
if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1;
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
throw runtime_error(std::string(__func__) + ": writing generated key failed");
setKeyPool.insert(nEnd);
LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size());
}
}
return true;
}
void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
{
nIndex = -1;
keypool.vchPubKey = CPubKey();
{
LOCK(cs_wallet);
if (!IsLocked())
TopUpKeyPool();
// Get the oldest key
if(setKeyPool.empty())
return;
CWalletDB walletdb(strWalletFile);
nIndex = *(setKeyPool.begin());
setKeyPool.erase(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
throw runtime_error(std::string(__func__) + ": read failed");
if (!HaveKey(keypool.vchPubKey.GetID()))
throw runtime_error(std::string(__func__) + ": unknown key in key pool");
assert(keypool.vchPubKey.IsValid());
LogPrintf("keypool reserve %d\n", nIndex);
}
}
void CWallet::KeepKey(int64_t nIndex)
{
// Remove from key pool
if (fFileBacked)
{
CWalletDB walletdb(strWalletFile);
walletdb.ErasePool(nIndex);
}
LogPrintf("keypool keep %d\n", nIndex);
}
void CWallet::ReturnKey(int64_t nIndex)
{
// Return to key pool
{
LOCK(cs_wallet);
setKeyPool.insert(nIndex);
}
LogPrintf("keypool return %d\n", nIndex);
}
bool CWallet::GetKeyFromPool(CPubKey& result)
{
int64_t nIndex = 0;
CKeyPool keypool;
{
LOCK(cs_wallet);
ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex == -1)
{
if (IsLocked()) return false;
result = GenerateNewKey();
return true;
}
KeepKey(nIndex);
result = keypool.vchPubKey;
}
return true;
}
int64_t CWallet::GetOldestKeyPoolTime()
{
LOCK(cs_wallet);
// if the keypool is empty, return <NOW>
if (setKeyPool.empty())
return GetTime();
// load oldest key from keypool, get time and return
CKeyPool keypool;
CWalletDB walletdb(strWalletFile);
int64_t nIndex = *(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
throw runtime_error(std::string(__func__) + ": read oldest key in keypool failed");
assert(keypool.vchPubKey.IsValid());
return keypool.nTime;
}
std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{
map<CTxDestination, CAmount> balances;
{
LOCK(cs_wallet);
BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
{
CWalletTx *pcoin = &walletEntry.second;
if (!pcoin->IsTrusted())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
continue;
int nDepth = pcoin->GetDepthInMainChain();
if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1))
continue;
for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++)
{
CTxDestination addr;
if (!IsMine(pcoin->tx->vout[i]))
continue;
if(!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr))
continue;
CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->tx->vout[i].nValue;
if (!balances.count(addr))
balances[addr] = 0;
balances[addr] += n;
}
}
}
return balances;
}
set< set<CTxDestination> > CWallet::GetAddressGroupings()
{
AssertLockHeld(cs_wallet); // mapWallet
set< set<CTxDestination> > groupings;
set<CTxDestination> grouping;
BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
{
CWalletTx *pcoin = &walletEntry.second;
if (pcoin->tx->vin.size() > 0)
{
bool any_mine = false;
// group all input addresses with each other
BOOST_FOREACH(CTxIn txin, pcoin->tx->vin)
{
CTxDestination address;
if(!IsMine(txin)) /* If this input isn't mine, ignore it */
continue;
if(!ExtractDestination(mapWallet[txin.prevout.hash].tx->vout[txin.prevout.n].scriptPubKey, address))
continue;
grouping.insert(address);
any_mine = true;
}
// group change with input addresses
if (any_mine)
{
BOOST_FOREACH(CTxOut txout, pcoin->tx->vout)
if (IsChange(txout))
{
CTxDestination txoutAddr;
if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
continue;
grouping.insert(txoutAddr);
}
}
if (grouping.size() > 0)
{
groupings.insert(grouping);
grouping.clear();
}
}
// group lone addrs by themselves
for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++)
if (IsMine(pcoin->tx->vout[i]))
{
CTxDestination address;
if(!ExtractDestination(pcoin->tx->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;
}
CAmount CWallet::GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter)
{
CWalletDB walletdb(strWalletFile);
return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
}
CAmount CWallet::GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter)
{
CAmount nBalance = 0;
// Tally wallet transactions
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
continue;
CAmount nReceived, nSent, nFee;
wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
nBalance += nReceived;
nBalance -= nSent + nFee;
}
// Tally internal accounting entries
nBalance += walletdb.GetAccountCreditDebit(strAccount);
return nBalance;
}
std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
{
LOCK(cs_wallet);
set<CTxDestination> result;
BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook)
{
const CTxDestination& address = item.first;
const string& strName = item.second.name;
if (strName == strAccount)
result.insert(address);
}
return result;
}
bool CReserveKey::GetReservedKey(CPubKey& pubkey)
{
if (nIndex == -1)
{
CKeyPool keypool;
pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex != -1)
vchPubKey = keypool.vchPubKey;
else {
return false;
}
}
assert(vchPubKey.IsValid());
pubkey = vchPubKey;
return true;
}
void CReserveKey::KeepKey()
{
if (nIndex != -1)
pwallet->KeepKey(nIndex);
nIndex = -1;
vchPubKey = CPubKey();
}
void CReserveKey::ReturnKey()
{
if (nIndex != -1)
pwallet->ReturnKey(nIndex);
nIndex = -1;
vchPubKey = CPubKey();
}
void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
{
setAddress.clear();
CWalletDB walletdb(strWalletFile);
LOCK2(cs_main, cs_wallet);
BOOST_FOREACH(const int64_t& id, setKeyPool)
{
CKeyPool keypool;
if (!walletdb.ReadPool(id, keypool))
throw runtime_error(std::string(__func__) + ": read failed");
assert(keypool.vchPubKey.IsValid());
CKeyID keyID = keypool.vchPubKey.GetID();
if (!HaveKey(keyID))
throw runtime_error(std::string(__func__) + ": unknown key in key pool");
setAddress.insert(keyID);
}
}
void CWallet::UpdatedTransaction(const uint256 &hashTx)
{
{
LOCK(cs_wallet);
// Only notify UI if this transaction is in this wallet
map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx);
if (mi != mapWallet.end())
NotifyTransactionChanged(this, hashTx, CT_UPDATED);
}
}
void CWallet::GetScriptForMining(boost::shared_ptr<CReserveScript> &script)
{
boost::shared_ptr<CReserveKey> rKey(new CReserveKey(this));
CPubKey pubkey;
if (!rKey->GetReservedKey(pubkey))
return;
script = rKey;
script->reserveScript = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
}
void CWallet::LockCoin(const COutPoint& output)
{
AssertLockHeld(cs_wallet); // setLockedCoins
setLockedCoins.insert(output);
}
void CWallet::UnlockCoin(const COutPoint& output)
{
AssertLockHeld(cs_wallet); // setLockedCoins
setLockedCoins.erase(output);
}
void CWallet::UnlockAllCoins()
{
AssertLockHeld(cs_wallet); // setLockedCoins
setLockedCoins.clear();
}
bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const
{
AssertLockHeld(cs_wallet); // setLockedCoins
COutPoint outpt(hash, n);
return (setLockedCoins.count(outpt) > 0);
}
void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
{
AssertLockHeld(cs_wallet); // setLockedCoins
for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
it != setLockedCoins.end(); it++) {
COutPoint outpt = (*it);
vOutpts.push_back(outpt);
}
}
/** @} */ // end of Actions
class CAffectedKeysVisitor : public boost::static_visitor<void> {
private:
const CKeyStore &keystore;
std::vector<CKeyID> &vKeys;
public:
CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}
void Process(const CScript &script) {
txnouttype type;
std::vector<CTxDestination> vDest;
int nRequired;
if (ExtractDestinations(script, type, vDest, nRequired)) {
BOOST_FOREACH(const CTxDestination &dest, vDest)
boost::apply_visitor(*this, dest);
}
}
void operator()(const CKeyID &keyId) {
if (keystore.HaveKey(keyId))
vKeys.push_back(keyId);
}
void operator()(const CScriptID &scriptId) {
CScript script;
if (keystore.GetCScript(scriptId, script))
Process(script);
}
void operator()(const CNoDestination &none) {}
};
void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
AssertLockHeld(cs_wallet); // mapKeyMetadata
mapKeyBirth.clear();
// get birth times for keys with metadata
for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)
if (it->second.nCreateTime)
mapKeyBirth[it->first] = it->second.nCreateTime;
// map in which we'll infer heights of other keys
CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin
std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
std::set<CKeyID> setKeys;
GetKeys(setKeys);
BOOST_FOREACH(const CKeyID &keyid, setKeys) {
if (mapKeyBirth.count(keyid) == 0)
mapKeyFirstBlock[keyid] = pindexMax;
}
setKeys.clear();
// if there are no such keys, we're done
if (mapKeyFirstBlock.empty())
return;
// find first block that affects those keys, if there are any left
std::vector<CKeyID> vAffected;
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) {
// iterate over all wallet transactions...
const CWalletTx &wtx = (*it).second;
BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) {
// ... which are already in a block
int nHeight = blit->second->nHeight;
BOOST_FOREACH(const CTxOut &txout, wtx.tx->vout) {
// iterate over all their outputs
CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey);
BOOST_FOREACH(const CKeyID &keyid, vAffected) {
// ... and all their affected keys
std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
rit->second = blit->second;
}
vAffected.clear();
}
}
}
// Extract block timestamps for those keys
for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
mapKeyBirth[it->first] = it->second->GetBlockTime() - 7200; // block times can be 2h off
}
bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
{
if (boost::get<CNoDestination>(&dest))
return false;
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
if (!fFileBacked)
return true;
return CWalletDB(strWalletFile).WriteDestData(CBitcoinAddress(dest).ToString(), key, value);
}
bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key)
{
if (!mapAddressBook[dest].destdata.erase(key))
return false;
if (!fFileBacked)
return true;
return CWalletDB(strWalletFile).EraseDestData(CBitcoinAddress(dest).ToString(), key);
}
bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
{
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
return true;
}
bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const
{
std::map<CTxDestination, CAddressBookData>::const_iterator i = mapAddressBook.find(dest);
if(i != mapAddressBook.end())
{
CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key);
if(j != i->second.destdata.end())
{
if(value)
*value = j->second;
return true;
}
}
return false;
}
std::string CWallet::GetWalletHelpString(bool showDebug)
{
std::string strUsage = HelpMessageGroup(_("Wallet options:"));
strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE));
strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"),
CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)));
strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup"));
strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup"));
if (showDebug)
strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS));
strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
strUsage += HelpMessageOpt("-usehd", _("Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET));
strUsage += HelpMessageOpt("-walletrbf", strprintf(_("Send transactions with full-RBF opt-in enabled (default: %u)"), DEFAULT_WALLET_RBF));
strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
" " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
if (showDebug)
{
strUsage += HelpMessageGroup(_("Wallet debugging/testing options:"));
strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE));
strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET));
strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB));
- strUsage += HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u"), DEFAULT_WALLET_REJECT_LONG_CHAINS));
+ strUsage += HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u)"), DEFAULT_WALLET_REJECT_LONG_CHAINS));
}
return strUsage;
}
bool CWallet::InitLoadWallet()
{
if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
pwalletMain = NULL;
LogPrintf("Wallet disabled!\n");
return true;
}
std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
// needed to restore wallet transaction meta data after -zapwallettxes
std::vector<CWalletTx> vWtx;
if (GetBoolArg("-zapwallettxes", false)) {
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
CWallet *tempWallet = new CWallet(walletFile);
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) {
return InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
}
delete tempWallet;
tempWallet = NULL;
}
uiInterface.InitMessage(_("Loading wallet..."));
int64_t nStart = GetTimeMillis();
bool fFirstRun = true;
CWallet *walletInstance = new CWallet(walletFile);
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DB_LOAD_OK)
{
if (nLoadWalletRet == DB_CORRUPT)
return InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
{
InitWarning(strprintf(_("Error reading %s! All keys read correctly, but transaction data"
" or address book entries might be missing or incorrect."),
walletFile));
}
else if (nLoadWalletRet == DB_TOO_NEW)
return InitError(strprintf(_("Error loading %s: Wallet requires newer version of %s"),
walletFile, _(PACKAGE_NAME)));
else if (nLoadWalletRet == DB_NEED_REWRITE)
{
return InitError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME)));
}
else
return InitError(strprintf(_("Error loading %s"), walletFile));
}
if (GetBoolArg("-upgradewallet", fFirstRun))
{
int nMaxVersion = GetArg("-upgradewallet", 0);
if (nMaxVersion == 0) // the -upgradewallet without argument case
{
LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
nMaxVersion = CLIENT_VERSION;
walletInstance->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
}
else
LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
if (nMaxVersion < walletInstance->GetVersion())
{
return InitError(_("Cannot downgrade wallet"));
}
walletInstance->SetMaxVersion(nMaxVersion);
}
if (fFirstRun)
{
// Create new keyUser and set as default key
if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && !walletInstance->IsHDEnabled()) {
// generate a new master key
CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey();
if (!walletInstance->SetHDMasterKey(masterPubKey))
throw std::runtime_error(std::string(__func__) + ": Storing master key failed");
}
CPubKey newDefaultKey;
if (walletInstance->GetKeyFromPool(newDefaultKey)) {
walletInstance->SetDefaultKey(newDefaultKey);
if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive"))
return InitError(_("Cannot write default address") += "\n");
}
walletInstance->SetBestChain(chainActive.GetLocator());
}
else if (IsArgSet("-usehd")) {
bool useHD = GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET);
if (walletInstance->IsHDEnabled() && !useHD)
return InitError(strprintf(_("Error loading %s: You can't disable HD on a already existing HD wallet"), walletFile));
if (!walletInstance->IsHDEnabled() && useHD)
return InitError(strprintf(_("Error loading %s: You can't enable HD on a already existing non-HD wallet"), walletFile));
}
LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart);
RegisterValidationInterface(walletInstance);
CBlockIndex *pindexRescan = chainActive.Tip();
if (GetBoolArg("-rescan", false))
pindexRescan = chainActive.Genesis();
else
{
CWalletDB walletdb(walletFile);
CBlockLocator locator;
if (walletdb.ReadBestBlock(locator))
pindexRescan = FindForkInGlobalIndex(chainActive, locator);
else
pindexRescan = chainActive.Genesis();
}
if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
{
//We can't rescan beyond non-pruned blocks, stop and throw an error
//this might happen if a user uses a old wallet within a pruned node
// or if he ran -disablewallet for a longer time, then decided to re-enable
if (fPruneMode)
{
CBlockIndex *block = chainActive.Tip();
while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)
block = block->pprev;
if (pindexRescan != block)
return InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
}
uiInterface.InitMessage(_("Rescanning..."));
LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
walletInstance->ScanForWalletTransactions(pindexRescan, true);
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
walletInstance->SetBestChain(chainActive.GetLocator());
nWalletDBUpdated++;
// Restore wallet transaction metadata after -zapwallettxes=1
if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2")
{
CWalletDB walletdb(walletFile);
BOOST_FOREACH(const CWalletTx& wtxOld, vWtx)
{
uint256 hash = wtxOld.GetHash();
std::map<uint256, CWalletTx>::iterator mi = walletInstance->mapWallet.find(hash);
if (mi != walletInstance->mapWallet.end())
{
const CWalletTx* copyFrom = &wtxOld;
CWalletTx* copyTo = &mi->second;
copyTo->mapValue = copyFrom->mapValue;
copyTo->vOrderForm = copyFrom->vOrderForm;
copyTo->nTimeReceived = copyFrom->nTimeReceived;
copyTo->nTimeSmart = copyFrom->nTimeSmart;
copyTo->fFromMe = copyFrom->fFromMe;
copyTo->strFromAccount = copyFrom->strFromAccount;
copyTo->nOrderPos = copyFrom->nOrderPos;
walletdb.WriteTx(*copyTo);
}
}
}
}
walletInstance->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
{
LOCK(walletInstance->cs_wallet);
LogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
LogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size());
LogPrintf("mapAddressBook.size() = %u\n", walletInstance->mapAddressBook.size());
}
pwalletMain = walletInstance;
return true;
}
void CWallet::postInitProcess(boost::thread_group& threadGroup)
{
// Add wallet transactions that aren't already in a block to mempool
// Do this here as mempool requires genesis block to be loaded
ReacceptWalletTransactions();
// Run a thread to flush wallet periodically
threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(this->strWalletFile)));
}
bool CWallet::ParameterInteraction()
{
if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
return true;
if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && SoftSetBoolArg("-walletbroadcast", false)) {
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
}
if (GetBoolArg("-salvagewallet", false) && SoftSetBoolArg("-rescan", true)) {
// Rewrite just private keys: rescan to find transactions
LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
}
// -zapwallettx implies a rescan
if (GetBoolArg("-zapwallettxes", false) && SoftSetBoolArg("-rescan", true)) {
LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
}
if (GetBoolArg("-sysperms", false))
return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
if (GetArg("-prune", 0) && GetBoolArg("-rescan", false))
return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB)
InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
_("The wallet will avoid paying less than the minimum relay fee."));
if (IsArgSet("-mintxfee"))
{
CAmount n = 0;
if (!ParseMoney(GetArg("-mintxfee", ""), n) || 0 == n)
return InitError(AmountErrMsg("mintxfee", GetArg("-mintxfee", "")));
if (n > HIGH_TX_FEE_PER_KB)
InitWarning(AmountHighWarn("-mintxfee") + " " +
_("This is the minimum transaction fee you pay on every transaction."));
CWallet::minTxFee = CFeeRate(n);
}
if (IsArgSet("-fallbackfee"))
{
CAmount nFeePerK = 0;
if (!ParseMoney(GetArg("-fallbackfee", ""), nFeePerK))
return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), GetArg("-fallbackfee", "")));
if (nFeePerK > HIGH_TX_FEE_PER_KB)
InitWarning(AmountHighWarn("-fallbackfee") + " " +
_("This is the transaction fee you may pay when fee estimates are not available."));
CWallet::fallbackFee = CFeeRate(nFeePerK);
}
if (IsArgSet("-paytxfee"))
{
CAmount nFeePerK = 0;
if (!ParseMoney(GetArg("-paytxfee", ""), nFeePerK))
return InitError(AmountErrMsg("paytxfee", GetArg("-paytxfee", "")));
if (nFeePerK > HIGH_TX_FEE_PER_KB)
InitWarning(AmountHighWarn("-paytxfee") + " " +
_("This is the transaction fee you will pay if you send a transaction."));
payTxFee = CFeeRate(nFeePerK, 1000);
if (payTxFee < ::minRelayTxFee)
{
return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
}
}
if (IsArgSet("-maxtxfee"))
{
CAmount nMaxFee = 0;
if (!ParseMoney(GetArg("-maxtxfee", ""), nMaxFee))
return InitError(AmountErrMsg("maxtxfee", GetArg("-maxtxfee", "")));
if (nMaxFee > HIGH_MAX_TX_FEE)
InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
maxTxFee = nMaxFee;
if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
{
return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
}
}
nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS);
fWalletRbf = GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
if (fSendFreeTransactions && GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) <= 0)
return InitError("Creation of free transactions with their relay disabled is not supported.");
return true;
}
bool CWallet::BackupWallet(const std::string& strDest)
{
if (!fFileBacked)
return false;
while (true)
{
{
LOCK(bitdb.cs_db);
if (!bitdb.mapFileUseCount.count(strWalletFile) || bitdb.mapFileUseCount[strWalletFile] == 0)
{
// Flush log data to the dat file
bitdb.CloseDb(strWalletFile);
bitdb.CheckpointLSN(strWalletFile);
bitdb.mapFileUseCount.erase(strWalletFile);
// Copy wallet file
boost::filesystem::path pathSrc = GetDataDir() / strWalletFile;
boost::filesystem::path pathDest(strDest);
if (boost::filesystem::is_directory(pathDest))
pathDest /= strWalletFile;
try {
#if BOOST_VERSION >= 104000
boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
#else
boost::filesystem::copy_file(pathSrc, pathDest);
#endif
LogPrintf("copied %s to %s\n", strWalletFile, pathDest.string());
return true;
} catch (const boost::filesystem::filesystem_error& e) {
LogPrintf("error copying %s to %s - %s\n", strWalletFile, pathDest.string(), e.what());
return false;
}
}
}
MilliSleep(100);
}
return false;
}
CKeyPool::CKeyPool()
{
nTime = GetTime();
}
CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn)
{
nTime = GetTime();
vchPubKey = vchPubKeyIn;
}
CWalletKey::CWalletKey(int64_t nExpires)
{
nTimeCreated = (nExpires ? GetTime() : 0);
nTimeExpires = nExpires;
}
void CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock)
{
// Update the tx's hashBlock
hashBlock = pindex->GetBlockHash();
// set the position of the transaction in the block
nIndex = posInBlock;
}
int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
{
if (hashUnset())
return 0;
AssertLockHeld(cs_main);
// Find the block it claims to be in
BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
if (mi == mapBlockIndex.end())
return 0;
CBlockIndex* pindex = (*mi).second;
if (!pindex || !chainActive.Contains(pindex))
return 0;
pindexRet = pindex;
return ((nIndex == -1) ? (-1) : 1) * (chainActive.Height() - pindex->nHeight + 1);
}
int CMerkleTx::GetBlocksToMaturity() const
{
if (!IsCoinBase())
return 0;
return max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain());
}
bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state)
{
return ::AcceptToMemoryPool(mempool, state, *this, true, NULL, false, nAbsurdFee);
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Mar 2, 10:52 (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187411
Default Alt Text
(372 KB)

Event Timeline