Merge pull request #4877 from Munkybooty/backports-0.20-pr5

Backports 0.20 pr5
This commit is contained in:
PastaPastaPasta 2022-10-17 15:42:57 -05:00 committed by GitHub
commit ba7d5dc6c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 350 additions and 65 deletions

View File

@ -6,6 +6,12 @@
export LC_ALL=C.UTF-8
# The root dir.
# The ci system copies this folder.
# This is where the build is done (depends and dist).
BASE_ROOT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../../ >/dev/null 2>&1 && pwd )
export BASE_ROOT_DIR
echo "Setting specific values in env"
if [ -n "${FILE_ENV}" ]; then
set -o errexit;
@ -17,9 +23,6 @@ export BUILD_TARGET=${BUILD_TARGET:-linux64}
export PULL_REQUEST=${PULL_REQUEST:-false}
export JOB_NUMBER=${JOB_NUMBER:-1}
BASE_ROOT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../../ >/dev/null 2>&1 && pwd )
export BASE_ROOT_DIR
echo "Fallback to default values in env (if not yet set)"
# The number of parallel jobs to pass down to make and test_runner.py
MAKEJOBS="-j$(nproc)"

View File

@ -14,3 +14,7 @@ export GOAL="install"
export BITCOIN_CONFIG="--enable-zmq --enable-reduce-exports --enable-crash-hooks --with-sanitizers=thread"
export CPPFLAGS="-DDEBUG_LOCKORDER -DENABLE_DASH_DEBUG -DARENA_DEBUG"
export PYZMQ=true
# xenial comes with old clang versions that can not parse the sanitizer suppressions files
# Remove unparseable lines as a hacky workaround
sed -i '/^implicit-/d' "${BASE_ROOT_DIR}/test/sanitizer_suppressions/ubsan"

View File

@ -43,7 +43,7 @@ mkdir -p "${CCACHE_DIR}"
export ASAN_OPTIONS="detect_stack_use_after_return=1"
export LSAN_OPTIONS="suppressions=${BASE_BUILD_DIR}/test/sanitizer_suppressions/lsan"
export TSAN_OPTIONS="suppressions=${BASE_BUILD_DIR}/test/sanitizer_suppressions/tsan"
export UBSAN_OPTIONS="suppressions=${BASE_BUILD_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1"
export UBSAN_OPTIONS="suppressions=${BASE_BUILD_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1"
env | grep -E '^(CCACHE_|WINEDEBUG|LC_ALL|BOOST_TEST_RANDOM|CONFIG_SHELL|(ASAN|LSAN|TSAN|UBSAN)_OPTIONS)' | tee /tmp/env
if [[ $HOST = *-mingw32 ]]; then
DOCKER_ADMIN="--cap-add SYS_ADMIN"

View File

@ -19,8 +19,9 @@ MAX_SEEDS_PER_ASN=4
# These are hosts that have been observed to be behaving strangely (e.g.
# aggressively connecting to every node).
SUSPICIOUS_HOSTS = {
}
with open("suspicious_hosts.txt", mode="r", encoding="utf-8") as f:
SUSPICIOUS_HOSTS = {s.strip() for s in f if s.strip()}
PATTERN_IPV4 = re.compile(r"^((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})):(\d+)$")
PATTERN_IPV6 = re.compile(r"^\[([0-9a-z:]+)\]:(\d+)$")

View File

View File

@ -7,8 +7,8 @@ A new wallet flag `avoid_reuse` has been added (default off). When enabled,
a wallet will distinguish between used and unused addresses, and default to not
use the former in coin selection.
(Note: rescanning the blockchain is required, to correctly mark previously
used destinations.)
Rescanning the blockchain is required, to correctly mark previously
used destinations.
Together with "avoid partial spends" (present as of Bitcoin v0.17), this
addresses a serious privacy issue where a malicious user can track spends by
@ -30,10 +30,12 @@ These include:
- createwallet
- getbalance
- getbalances
- sendtoaddress
In addition, `sendtoaddress` has been changed to enable `-avoidpartialspends` when
`avoid_reuse` is enabled.
In addition, `sendtoaddress` has been changed to avoid partial spends when `avoid_reuse`
is enabled (if not already enabled via the `-avoidpartialspends` command line flag),
as it would otherwise risk using up the "wrong" UTXO for an address reuse case.
The listunspent RPC has also been updated to now include a "reused" bool, for nodes
with "avoid_reuse" enabled.

View File

@ -750,12 +750,9 @@ if TARGET_WINDOWS
dashd_SOURCES += dashd-res.rc
endif
# Libraries below may be listed more than once to resolve circular dependencies (see
# https://eli.thegreenplace.net/2013/07/09/library-order-in-static-linking#circular-dependency)
dashd_LDADD = \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_WALLET) \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_COMMON) \
$(LIBUNIVALUE) \
$(LIBBITCOIN_UTIL) \

View File

@ -80,6 +80,8 @@ static const unsigned int MAX_GETDATA_SZ = 1000;
static constexpr int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60;
/** Minimum time between orphan transactions expire time checks in seconds */
static constexpr int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60;
/** How long to cache transactions in mapRelay for normal relay */
static constexpr std::chrono::seconds RELAY_TX_CACHE_TIME{15 * 60};
/** Headers download timeout expressed in microseconds
* Timeout = base + per_header * (expected number of headers) */
static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; // 15 minutes
@ -1179,7 +1181,7 @@ static bool TxRelayMayResultInDisconnect(const CValidationState& state)
/**
* Potentially mark a node discouraged based on the contents of a CValidationState object
*
* @param[in] via_compact_block: this bool is passed in because net_processing should
* @param[in] via_compact_block this bool is passed in because net_processing should
* punish peers differently depending on whether the data was provided in a compact
* block message or not. If the compact block had a valid header, but contained invalid
* txs, the peer should not be punished. See BIP 152.
@ -1814,6 +1816,10 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm
const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
{
// mempool entries added before this time have likely expired from mapRelay
const std::chrono::seconds longlived_mempool_time = GetTime<std::chrono::seconds>() - RELAY_TX_CACHE_TIME;
const std::chrono::seconds mempool_req = pfrom->m_tx_relay->m_last_mempool_req.load();
LOCK(cs_main);
while (it != pfrom->vRecvGetData.end() && it->IsKnownType()) {
@ -1851,11 +1857,15 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::TX, *mi->second));
}
push = true;
} else if (pfrom->m_tx_relay->m_last_mempool_req.load().count()) {
} else {
auto txinfo = mempool.info(inv.hash);
// To protect privacy, do not answer getdata using the mempool when
// that TX couldn't have been INVed in reply to a MEMPOOL request.
if (txinfo.tx && txinfo.m_time <= pfrom->m_tx_relay->m_last_mempool_req.load()) {
// that TX couldn't have been INVed in reply to a MEMPOOL request,
// or when it's too recent to have expired from mapRelay.
if (txinfo.tx && (
(mempool_req.count() && txinfo.m_time <= mempool_req)
|| (txinfo.m_time <= longlived_mempool_time)))
{
if (dstx) {
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::DSTX, dstx));
} else {
@ -4897,7 +4907,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
auto ret = mapRelay.insert(std::make_pair(hash, std::move(txinfo.tx)));
if (ret.second) {
vRelayExpiration.push_back(std::make_pair(nNow + 15 * 60 * 1000000, ret.first));
vRelayExpiration.push_back(std::make_pair(nNow + std::chrono::microseconds{RELAY_TX_CACHE_TIME}.count(), ret.first));
}
}
int nInvType = CCoinJoin::GetDSTX(hash) ? MSG_DSTX : MSG_TX;

View File

@ -782,7 +782,7 @@ bool IsProxy(const CNetAddr &addr) {
* @param hSocket The socket on which to connect to the SOCKS5 proxy.
* @param nTimeout Wait this many milliseconds for the connection to the SOCKS5
* proxy to be established.
* @param outProxyConnectionFailed[out] Whether or not the connection to the
* @param[out] outProxyConnectionFailed Whether or not the connection to the
* SOCKS5 proxy failed.
*
* @returns Whether or not the operation succeeded.

View File

@ -22,10 +22,10 @@ struct NodeContext;
*
* @param[in] node reference to node context
* @param[in] tx the transaction to broadcast
* @param[out] &err_string reference to std::string to fill with error string if available
* @param[out] err_string reference to std::string to fill with error string if available
* @param[in] max_tx_fee reject txs with fees higher than this (if 0, accept any fee)
* @param[in] relay flag if both mempool insertion and p2p relay are requested
* @param[in] wait_callback, wait until callbacks have been processed to avoid stale result due to a sequentially RPC.
* @param[in] wait_callback wait until callbacks have been processed to avoid stale result due to a sequentially RPC.
* return error
*/
[[nodiscard]] TransactionError BroadcastTransaction(NodeContext& node, CTransactionRef tx, std::string& err_string, const CAmount& highfee, bool relay, bool wait_callback, bool bypass_limits = false);

View File

@ -533,7 +533,7 @@ void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransactio
/**
* Finalizes a PSBT if possible, combining partial signatures.
*
* @param[in,out] &psbtx reference to PartiallySignedTransaction to finalize
* @param[in,out] psbtx PartiallySignedTransaction to finalize
* return True if the PSBT is now complete, false otherwise
*/
bool FinalizePSBT(PartiallySignedTransaction& psbtx);
@ -541,7 +541,7 @@ bool FinalizePSBT(PartiallySignedTransaction& psbtx);
/**
* Finalizes a PSBT if possible, and extracts it to a CMutableTransaction if it could be finalized.
*
* @param[in] &psbtx reference to PartiallySignedTransaction
* @param[in] psbtx PartiallySignedTransaction
* @param[out] result CMutableTransaction representing the complete transaction, if successful
* @return True if we successfully extracted the transaction, false otherwise
*/
@ -550,7 +550,7 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
/**
* Combines PSBTs with the same underlying transaction, resulting in a single PSBT with all partial signatures from each input.
*
* @param[out] &out the combined PSBT, if successful
* @param[out] out the combined PSBT, if successful
* @param[in] psbtxs the PSBTs to combine
* @return error (OK if we successfully combined the transactions, other error if they were not compatible)
*/

View File

@ -19,6 +19,7 @@ class SigningProvider;
* Sign a transaction with the given keystore and previous transactions
*
* @param mtx The transaction to-be-signed
* @param prevTxsUnival Array of previous txns outputs that tx depends on but may not yet be in the block chain
* @param keystore Temporary keystore containing signing keys
* @param coins Map of unspent outputs
* @param hashType The signature hash type

View File

@ -90,20 +90,20 @@ struct Descriptor {
/** Expand a descriptor at a specified position.
*
* @param[in] pos: The position at which to expand the descriptor. If IsRange() is false, this is ignored.
* @param[in] provider: The provider to query for private keys in case of hardened derivation.
* @param[out] output_scripts: The expanded scriptPubKeys.
* @param[out] out: Scripts and public keys necessary for solving the expanded scriptPubKeys (may be equal to `provider`).
* @param[out] write_cache: Cache data necessary to evaluate the descriptor at this point without access to private keys.
* @param[in] pos The position at which to expand the descriptor. If IsRange() is false, this is ignored.
* @param[in] provider The provider to query for private keys in case of hardened derivation.
* @param[out] output_scripts The expanded scriptPubKeys.
* @param[out] out Scripts and public keys necessary for solving the expanded scriptPubKeys (may be equal to `provider`).
* @param[out] write_cache Cache data necessary to evaluate the descriptor at this point without access to private keys.
*/
virtual bool Expand(int pos, const SigningProvider& provider, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache = nullptr) const = 0;
/** Expand a descriptor at a specified position using cached expansion data.
*
* @param[in] pos: The position at which to expand the descriptor. If IsRange() is false, this is ignored.
* @param[in] read_cache: Cached expansion data.
* @param[out] output_scripts: The expanded scriptPubKeys.
* @param[out] out: Scripts and public keys necessary for solving the expanded scriptPubKeys (may be equal to `provider`).
* @param[in] pos The position at which to expand the descriptor. If IsRange() is false, this is ignored.
* @param[in] read_cache Cached expansion data.
* @param[out] output_scripts The expanded scriptPubKeys.
* @param[out] out Scripts and public keys necessary for solving the expanded scriptPubKeys (may be equal to `provider`).
*/
virtual bool ExpandFromCache(int pos, const DescriptorCache& read_cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const = 0;

View File

@ -190,14 +190,15 @@ static void TestHKDF_SHA256_32(const std::string &ikm_hex, const std::string &sa
BOOST_CHECK(HexStr(out) == okm_check_hex);
}
static std::string LongTestString() {
static std::string LongTestString()
{
std::string ret;
for (int i=0; i<200000; i++) {
ret += (unsigned char)(i);
ret += (unsigned char)(i >> 4);
ret += (unsigned char)(i >> 8);
ret += (unsigned char)(i >> 12);
ret += (unsigned char)(i >> 16);
for (int i = 0; i < 200000; i++) {
ret += (char)(i);
ret += (char)(i >> 4);
ret += (char)(i >> 8);
ret += (char)(i >> 12);
ret += (char)(i >> 16);
}
return ret;
}

View File

@ -451,6 +451,30 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "multi-op-return");
// Check large scriptSig (non-standard if size is >1650 bytes)
t.vout.resize(1);
t.vout[0].nValue = MAX_MONEY;
t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
// OP_PUSHDATA2 with len (3 bytes) + data (1647 bytes) = 1650 bytes
t.vin[0].scriptSig = CScript() << std::vector<unsigned char>(1647, 0); // 1650
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
t.vin[0].scriptSig = CScript() << std::vector<unsigned char>(1648, 0); // 1651
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "scriptsig-size");
// Check bare multisig (standard if policy flag fIsBareMultisigStd is set)
fIsBareMultisigStd = true;
t.vout[0].scriptPubKey = GetScriptForMultisig(1, {key.GetPubKey()}); // simple 1-of-1
t.vin[0].scriptSig = CScript() << std::vector<unsigned char>(65, 0);
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
fIsBareMultisigStd = false;
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "bare-multisig");
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -15,8 +15,8 @@
* finalize.) Sets `error` and returns false if something goes wrong.
*
* @param[in] pwallet pointer to a wallet
* @param[in] &psbtx reference to PartiallySignedTransaction to fill in
* @param[out] &complete indicates whether the PSBT is now complete
* @param[in] psbtx PartiallySignedTransaction to fill in
* @param[out] complete indicates whether the PSBT is now complete
* @param[in] sighash_type the sighash type to use when signing (if PSBT does not specify)
* @param[in] sign whether to sign or not
* @param[in] bip32derivs whether to fill in bip32 derivation information if available

View File

@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Copyright (c) 2014-2022 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -20,10 +20,10 @@
#include <util/bip32.h>
#include <util/fees.h>
#include <util/message.h> // For MessageSign()
#include <util/system.h>
#include <util/moneystr.h>
#include <util/ref.h>
#include <util/string.h>
#include <util/system.h>
#include <util/translation.h>
#include <util/url.h>
#include <util/vector.h>
@ -123,7 +123,7 @@ std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& reques
"Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
}
void EnsureWalletIsUnlocked(CWallet * const pwallet)
void EnsureWalletIsUnlocked(const CWallet* pwallet)
{
if (pwallet->IsLocked()) {
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
@ -366,7 +366,7 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
" \"UNSET\"\n"
" \"ECONOMICAL\"\n"
" \"CONSERVATIVE\""},
{"avoid_reuse", RPCArg::Type::BOOL, /* default */ pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE) ? "true" : "unavailable", "Avoid spending from dirty addresses; addresses are considered\n"
{"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n"
" dirty if they have previously been used in a transaction."},
},
RPCResult{
@ -753,7 +753,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
{"minconf", RPCArg::Type::NUM, /* default */ "0", "Only include transactions confirmed at least this many times."},
{"addlocked", RPCArg::Type::BOOL, /* default */ "false", "Whether to include transactions locked via InstantSend in the wallet's balance."},
{"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also include balance in watch-only addresses (see 'importaddress')"},
{"avoid_reuse", RPCArg::Type::BOOL, /* default */ pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE) ? "true" : "unavailable", "Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction."},
{"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction."},
},
RPCResult{
RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this wallet."
@ -801,7 +801,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
{
RPCHelpMan{"getunconfirmedbalance",
"Returns the server's total unconfirmed balance\n",
"DEPRECATED\nIdentical to getbalances().mine.untrusted_pending\n",
{},
RPCResult{RPCResult::Type::NUM, "", "The balance"},
RPCExamples{""},
@ -2381,6 +2381,75 @@ static UniValue setcoinjoinamount(const JSONRPCRequest& request)
return NullUniValue;
}
static UniValue getbalances(const JSONRPCRequest& request)
{
RPCHelpMan{"getbalances",
"Returns an object with all balances in " + CURRENCY_UNIT + ".\n",
{},
RPCResult{
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::OBJ, "mine", "balances from outputs that the wallet can sign",
{
{RPCResult::Type::STR_AMOUNT, "trusted", " trusted balance (outputs created by the wallet or confirmed outputs)"},
{RPCResult::Type::STR_AMOUNT, "untrusted_pending", " untrusted pending balance (outputs created by others that are in the mempool)"},
{RPCResult::Type::STR_AMOUNT, "immature", " balance from immature coinbase outputs"},
{RPCResult::Type::STR_AMOUNT, "used", "(only present if avoid_reuse is set) balance from coins sent to addresses that were previously spent from (potentially privacy violating)"},
{RPCResult::Type::STR_AMOUNT, "coinjoin", " CoinJoin balance (outputs with enough rounds created by the wallet via mixing)"},
}},
{RPCResult::Type::OBJ, "watchonly", "watchonly balances (not present if wallet does not watch anything)",
{
{RPCResult::Type::STR_AMOUNT, "trusted", " trusted balance (outputs created by the wallet or confirmed outputs)"},
{RPCResult::Type::STR_AMOUNT, "untrusted_pending", " untrusted pending balance (outputs created by others that are in the mempool)"},
{RPCResult::Type::STR_AMOUNT, "immature", " balance from immature coinbase outputs"},
}},
},
},
RPCExamples{
HelpExampleCli("getbalances", "") +
HelpExampleRpc("getbalances", "")
},
}.Check(request);
std::shared_ptr<CWallet> const rpc_wallet = GetWalletForJSONRPCRequest(request);
if (!rpc_wallet) return NullUniValue;
CWallet& wallet = *rpc_wallet;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
wallet.BlockUntilSyncedToCurrentChain();
LOCK(wallet.cs_wallet);
UniValue obj(UniValue::VOBJ);
const auto bal = wallet.GetBalance();
UniValue balances{UniValue::VOBJ};
{
UniValue balances_mine{UniValue::VOBJ};
balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted));
balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending));
balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature));
if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
// If the AVOID_REUSE flag is set, bal has been set to just the un-reused address balance. Get
// the total balance, and then subtract bal to get the reused address balance.
const auto full_bal = wallet.GetBalance(0, false);
balances_mine.pushKV("used", ValueFromAmount(full_bal.m_mine_trusted + full_bal.m_mine_untrusted_pending - bal.m_mine_trusted - bal.m_mine_untrusted_pending));
}
balances_mine.pushKV("coinjoin", ValueFromAmount(bal.m_anonymized));
balances.pushKV("mine", balances_mine);
}
auto spk_man = wallet.GetLegacyScriptPubKeyMan();
if (spk_man && spk_man->HaveWatchOnly()) {
UniValue balances_watchonly{UniValue::VOBJ};
balances_watchonly.pushKV("trusted", ValueFromAmount(bal.m_watchonly_trusted));
balances_watchonly.pushKV("untrusted_pending", ValueFromAmount(bal.m_watchonly_untrusted_pending));
balances_watchonly.pushKV("immature", ValueFromAmount(bal.m_watchonly_immature));
balances.pushKV("watchonly", balances_watchonly);
}
return balances;
}
static UniValue getwalletinfo(const JSONRPCRequest& request)
{
RPCHelpMan{"getwalletinfo",
@ -2391,10 +2460,10 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
{
{RPCResult::Type::STR, "walletname", "the wallet name"},
{RPCResult::Type::NUM, "walletversion", "the wallet version"},
{RPCResult::Type::NUM, "balance", "the total confirmed balance of the wallet in " + CURRENCY_UNIT},
{RPCResult::Type::NUM, "coinjoin_balance", "the CoinJoin balance in " + CURRENCY_UNIT},
{RPCResult::Type::NUM, "unconfirmed_balance", "the total unconfirmed balance of the wallet in " + CURRENCY_UNIT},
{RPCResult::Type::NUM, "immature_balance", "the total immature balance of the wallet in " + CURRENCY_UNIT},
{RPCResult::Type::NUM, "balance", "DEPRECATED. Identical to getbalances().mine.trusted"},
{RPCResult::Type::NUM, "coinjoin_balance", "DEPRECATED. Identical to getbalances().mine.coinjoin"},
{RPCResult::Type::NUM, "unconfirmed_balance", "DEPRECATED. Identical to getbalances().mine.untrusted_pending"},
{RPCResult::Type::NUM, "immature_balance", "DEPRECATED. Identical to getbalances().mine.immature"},
{RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},
{RPCResult::Type::NUM_TIME, "timefirstkey", "the " + UNIX_EPOCH_TIME + " of the oldest known key in the wallet"},
{RPCResult::Type::NUM_TIME, "keypoololdest", "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool"},
@ -2903,7 +2972,6 @@ static UniValue listunspent(const JSONRPCRequest& request)
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
bool avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
RPCHelpMan{"listunspent",
"\nReturns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n"
@ -2946,7 +3014,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
{RPCResult::Type::BOOL, "spendable", "Whether we have the private keys to spend this output"},
{RPCResult::Type::BOOL, "solvable", "Whether we know how to spend this output, ignoring the lack of keys"},
{RPCResult::Type::STR, "desc", "(only when solvable) A descriptor for spending this output"},
{RPCResult::Type::BOOL, "reused", /* optional*/ true, "Whether this output is reused/dirty (sent to an address that was previously spent from)"},
{RPCResult::Type::BOOL, "reused", /* optional*/ true, "(only present if avoid_reuse is set) Whether this output is reused/dirty (sent to an address that was previously spent from)"},
{RPCResult::Type::BOOL, "safe", "Whether this output is considered safe to spend. Unconfirmed transactions"
" from outside keys and unconfirmed replacement transactions are considered unsafe\n"
"and are not eligible for spending by fundrawtransaction and sendtoaddress."},
@ -3059,6 +3127,8 @@ static UniValue listunspent(const JSONRPCRequest& request)
LOCK(pwallet->cs_wallet);
const bool avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
for (const COutput& out : vecOutputs) {
CTxDestination address;
const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
@ -3985,6 +4055,7 @@ static const CRPCCommand commands[] =
{ "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf","addlocked"} },
{ "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} },
{ "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
{ "wallet", "getbalances", &getbalances, {} },
{ "wallet", "getwalletinfo", &getwalletinfo, {} },
{ "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
{ "wallet", "importelectrumwallet", &importelectrumwallet, {"filename", "index"} },

View File

@ -35,7 +35,7 @@ Span<const CRPCCommand> GetWalletRPCCommands();
*/
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
void EnsureWalletIsUnlocked(CWallet *);
void EnsureWalletIsUnlocked(const CWallet*);
WalletContext& EnsureWalletContext(const util::Ref& context);
UniValue getaddressinfo(const JSONRPCRequest& request);

View File

@ -73,6 +73,7 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa
if (fIsFromMe)
{
wtx->m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1);
wtx->m_is_cache_empty = false;
}
COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
vCoins.push_back(output);

View File

@ -777,7 +777,7 @@ void CWallet::MarkDirty()
fAnonymizableTallyCachedNonDenom = false;
}
void CWallet::SetUsedDestinationState(const uint256& hash, unsigned int n, bool used)
void CWallet::SetUsedDestinationState(const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations)
{
const CWalletTx* srctx = GetWalletTx(hash);
if (!srctx) return;
@ -787,7 +787,9 @@ void CWallet::SetUsedDestinationState(const uint256& hash, unsigned int n, bool
if (IsMine(dst)) {
LOCK(cs_wallet);
if (used && !GetDestData(dst, "used", nullptr)) {
AddDestData(dst, "used", "p"); // p for "present", opposite of absent (null)
if (AddDestData(dst, "used", "p")) { // p for "present", opposite of absent (null)
tx_destinations.insert(dst);
}
} else if (!used && GetDestData(dst, "used", nullptr)) {
EraseDestData(dst, "used");
}
@ -818,10 +820,14 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
if (IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
// Mark used destinations
std::set<CTxDestination> tx_destinations;
for (const CTxIn& txin : wtxIn.tx->vin) {
const COutPoint& op = txin.prevout;
SetUsedDestinationState(op.hash, op.n, true);
SetUsedDestinationState(op.hash, op.n, true, tx_destinations);
}
MarkDestinationsDirty(tx_destinations);
}
// Inserts only if not already there, returns tx inserted or tx found
@ -2029,6 +2035,7 @@ CAmount CWalletTx::GetCachableAmount(AmountType type, const isminefilter& filter
auto& amount = m_amounts[type];
if (recalculate || !amount.m_cached[filter]) {
amount.Set(filter, type == DEBIT ? pwallet->GetDebit(*tx, filter) : pwallet->GetCredit(*tx, filter));
m_is_cache_empty = false;
}
return amount.m_value[filter];
}
@ -2106,6 +2113,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter
if (allow_cache) {
m_amounts[AVAILABLE_CREDIT].Set(filter, nCredit);
m_is_cache_empty = false;
}
return nCredit;
@ -3785,6 +3793,20 @@ bool CWallet::GetNewChangeDestination(CTxDestination& dest, std::string& error)
return true;
}
void CWallet::MarkDestinationsDirty(const std::set<CTxDestination>& destinations) {
for (auto& entry : mapWallet) {
CWalletTx& wtx = entry.second;
if (wtx.m_is_cache_empty) continue;
for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
CTxDestination dst;
if (ExtractDestination(wtx.tx->vout[i].scriptPubKey, dst) && destinations.count(dst)) {
wtx.MarkDirty();
break;
}
}
}
}
std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{
std::map<CTxDestination, CAmount> balances;

View File

@ -327,6 +327,13 @@ public:
enum AmountType { DEBIT, CREDIT, IMMATURE_CREDIT, AVAILABLE_CREDIT, ANON_CREDIT, DENOM_UCREDIT, DENOM_CREDIT, AMOUNTTYPE_ENUM_ELEMENTS };
CAmount GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate = false) const;
mutable CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS];
/**
* This flag is true if all m_amounts caches are empty. This is particularly
* useful in places where MarkDirty is conditionally called and the
* condition can be expensive and thus can be skipped if the flag is true.
* See MarkDestinationsDirty.
*/
mutable bool m_is_cache_empty{true};
mutable bool fChangeCached;
mutable bool fInMempool;
mutable CAmount nChangeCached;
@ -456,6 +463,7 @@ public:
m_amounts[IMMATURE_CREDIT].Reset();
m_amounts[AVAILABLE_CREDIT].Reset();
fChangeCached = false;
m_is_cache_empty = true;
}
void BindWallet(CWallet *pwalletIn)
@ -901,7 +909,7 @@ public:
// Whether this or any UTXO with the same CTxDestination has been spent.
bool IsUsedDestination(const CTxDestination& dst) const;
bool IsUsedDestination(const uint256& hash, unsigned int n) const;
void SetUsedDestinationState(const uint256& hash, unsigned int n, bool used);
void SetUsedDestinationState(const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations);
std::vector<OutputGroup> GroupOutputs(const std::vector<COutput>& outputs, bool single_coin) const;
@ -1020,9 +1028,9 @@ public:
* Should be called after CreateTransaction unless you want to abort
* broadcasting the transaction.
*
* @param tx[in] The transaction to be broadcast.
* @param mapValue[in] key-values to be set on the transaction.
* @param orderForm[in] BIP 70 / BIP 21 order form details to be set on the transaction.
* @param[in] tx The transaction to be broadcast.
* @param[in] mapValue key-values to be set on the transaction.
* @param[in] orderForm BIP 70 / BIP 21 order form details to be set on the transaction.
*/
void CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm);
@ -1066,6 +1074,12 @@ public:
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const;
/**
* Marks all outputs in each one of the destinations dirty, so their cache is
* reset and does not return outdated information.
*/
void MarkDestinationsDirty(const std::set<CTxDestination>& destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool GetNewDestination(const std::string label, CTxDestination& dest, std::string& error);
bool GetNewChangeDestination(CTxDestination& dest, std::string& error);

View File

@ -92,7 +92,7 @@ public:
int nVersion;
int64_t nCreateTime; // 0 means unknown
KeyOriginInfo key_origin; // Key origin info with path and fingerprint
bool has_key_origin = false; //< Whether the key_origin is useful
bool has_key_origin = false; //!< Whether the key_origin is useful
CKeyMetadata()
{

View File

@ -8,6 +8,7 @@ from io import BytesIO
import math
from test_framework.test_framework import BitcoinTestFramework
from test_framework.key import ECKey
from test_framework.messages import (
BIP125_SEQUENCE_NUMBER,
COIN,
@ -21,6 +22,9 @@ from test_framework.script import (
hash160,
CScript,
OP_0,
OP_2,
OP_3,
OP_CHECKMULTISIG,
OP_EQUAL,
OP_HASH160,
OP_RETURN,
@ -36,7 +40,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.extra_args = [[
'-txindex',
'-txindex','-permitbaremultisig=0',
]] * self.num_nodes
self.supports_cli = False
@ -263,6 +267,15 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
rawtxs=[tx.serialize().hex()],
)
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
key = ECKey()
key.generate()
pubkey = key.get_pubkey().get_bytes()
tx.vout[0].scriptPubKey = CScript([OP_2, pubkey, pubkey, pubkey, OP_3, OP_CHECKMULTISIG]) # Some bare multisig script (2-of-3)
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: bare-multisig'}],
rawtxs=[tx.serialize().hex()],
)
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vin[0].scriptSig = CScript([OP_HASH160]) # Some not-pushonly scriptSig
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-not-pushonly'}],
@ -275,6 +288,12 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
rawtxs=[tx.serialize().hex()],
)
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-size'}],
rawtxs=[tx.serialize().hex()],
)
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
output_p2sh_burn = CTxOut(nValue=540, scriptPubKey=CScript([OP_HASH160, hash160(b'burn'), OP_EQUAL]))
num_scripts = 100000 // len(output_p2sh_burn.serialize()) # Use enough outputs to make the tx too large for our policy
tx.vout = [output_p2sh_burn] * num_scripts

View File

@ -14,6 +14,7 @@ import os
import pdb
import random
import shutil
import subprocess
import sys
import tempfile
import time
@ -152,6 +153,9 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
except KeyError:
self.log.exception("Key error")
self.success = TestStatus.FAILED
except subprocess.CalledProcessError as e:
self.log.exception("Called Process failed with '{}'".format(e.output))
self.success = TestStatus.FAILED
except Exception:
self.log.exception("Unexpected exception caught during testing")
self.success = TestStatus.FAILED

View File

@ -62,6 +62,12 @@ def assert_unspent(node, total_count=None, total_sum=None, reused_supported=None
if reused_sum is not None:
assert_approx(stats["reused"]["sum"], reused_sum, 0.001)
def assert_balances(node, mine):
'''Make assertions about a node's getbalances output'''
got = node.getbalances()["mine"]
for k,v in mine.items():
assert_approx(got[k], v, 0.001)
class AvoidReuseTest(BitcoinTestFramework):
def set_test_params(self):
@ -86,6 +92,8 @@ class AvoidReuseTest(BitcoinTestFramework):
self.test_fund_send_fund_senddirty()
reset_balance(self.nodes[1], self.nodes[0].getnewaddress())
self.test_fund_send_fund_send()
reset_balance(self.nodes[1], self.nodes[0].getnewaddress())
self.test_getbalances_used()
def test_persistence(self):
'''Test that wallet files persist the avoid_reuse flag.'''
@ -147,6 +155,10 @@ class AvoidReuseTest(BitcoinTestFramework):
# listunspent should show 1 single, unused 10 btc output
assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0)
# getbalances should show no used, 10 btc trusted
assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})
# node 0 should not show a used entry, as it does not enable avoid_reuse
assert("used" not in self.nodes[0].getbalances()["mine"])
self.nodes[1].sendtoaddress(retaddr, 5)
self.nodes[0].generate(1)
@ -154,6 +166,8 @@ class AvoidReuseTest(BitcoinTestFramework):
# listunspent should show 1 single, unused 5 btc output
assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0)
# getbalances should show no used, 5 btc trusted
assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})
self.nodes[0].sendtoaddress(fundaddr, 10)
self.nodes[0].generate(1)
@ -161,11 +175,15 @@ class AvoidReuseTest(BitcoinTestFramework):
# listunspent should show 2 total outputs (5, 10 btc), one unused (5), one reused (10)
assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
# getbalances should show 10 used, 5 btc trusted
assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5})
self.nodes[1].sendtoaddress(address=retaddr, amount=10, avoid_reuse=False)
# listunspent should show 1 total outputs (5 btc), unused
assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_count=0)
# getbalances should show no used, 5 btc trusted
assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})
# node 1 should now have about 5 btc left (for both cases)
assert_approx(self.nodes[1].getbalance(), 5, 0.001)
@ -191,6 +209,8 @@ class AvoidReuseTest(BitcoinTestFramework):
# listunspent should show 1 single, unused 10 btc output
assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0)
# getbalances should show no used, 10 btc trusted
assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})
self.nodes[1].sendtoaddress(retaddr, 5)
self.nodes[0].generate(1)
@ -198,6 +218,8 @@ class AvoidReuseTest(BitcoinTestFramework):
# listunspent should show 1 single, unused 5 btc output
assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0)
# getbalances should show no used, 5 btc trusted
assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})
self.nodes[0].sendtoaddress(fundaddr, 10)
self.nodes[0].generate(1)
@ -205,6 +227,8 @@ class AvoidReuseTest(BitcoinTestFramework):
# listunspent should show 2 total outputs (5, 10 btc), one unused (5), one reused (10)
assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
# getbalances should show 10 used, 5 btc trusted
assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5})
# node 1 should now have a balance of 5 (no dirty) or 15 (including dirty)
assert_approx(self.nodes[1].getbalance(), 5, 0.001)
@ -216,10 +240,42 @@ class AvoidReuseTest(BitcoinTestFramework):
# listunspent should show 2 total outputs (1, 10 btc), one unused (1), one reused (10)
assert_unspent(self.nodes[1], total_count=2, total_sum=11, reused_count=1, reused_sum=10)
# getbalances should show 10 used, 1 btc trusted
assert_balances(self.nodes[1], mine={"used": 10, "trusted": 1})
# node 1 should now have about 1 btc left (no dirty) and 11 (including dirty)
assert_approx(self.nodes[1].getbalance(), 1, 0.001)
assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 11, 0.001)
def test_getbalances_used(self):
'''
getbalances and listunspent should pick up on reused addresses
immediately, even for address reusing outputs created before the first
transaction was spending from that address
'''
self.log.info("Test getbalances used category")
# node under test should be completely empty
assert_equal(self.nodes[1].getbalance(avoid_reuse=False), 0)
new_addr = self.nodes[1].getnewaddress()
ret_addr = self.nodes[0].getnewaddress()
# send multiple transactions, reusing one address
for _ in range(11):
self.nodes[0].sendtoaddress(new_addr, 1)
self.nodes[0].generate(1)
self.sync_all()
# send transaction that should not use all the available outputs
# per the current coin selection algorithm
self.nodes[1].sendtoaddress(ret_addr, 5)
# getbalances and listunspent should show the remaining outputs
# in the reused address as used/reused
assert_unspent(self.nodes[1], total_count=2, total_sum=6, reused_count=1, reused_sum=1)
assert_balances(self.nodes[1], mine={"used": 1, "trusted": 5})
if __name__ == '__main__':
AvoidReuseTest().main()

View File

@ -62,14 +62,24 @@ class WalletTest(BitcoinTestFramework):
assert_equal(len(self.nodes[0].listunspent()), 0)
assert_equal(len(self.nodes[1].listunspent()), 0)
self.log.info("Mining blocks ...")
self.log.info("Check that only node 0 is watching an address")
assert 'watchonly' in self.nodes[0].getbalances()
assert 'watchonly' not in self.nodes[1].getbalances()
self.log.info("Mining blocks ...")
self.nodes[0].generate(1)
self.sync_all()
self.nodes[1].generate(1)
self.nodes[1].generatetoaddress(101, ADDRESS_WATCHONLY)
self.sync_all()
assert_equal(self.nodes[0].getbalances()['mine']['trusted'], 500)
assert_equal(self.nodes[0].getwalletinfo()['balance'], 500)
assert_equal(self.nodes[1].getbalances()['mine']['trusted'], 500)
assert_equal(self.nodes[0].getbalances()['watchonly']['immature'], 50000)
assert 'watchonly' not in self.nodes[1].getbalances()
assert_equal(self.nodes[0].getbalance(), 500)
assert_equal(self.nodes[1].getbalance(), 500)
@ -113,8 +123,11 @@ class WalletTest(BitcoinTestFramework):
assert_equal(self.nodes[1].getbalance(minconf=1), Decimal('0'))
# getunconfirmedbalance
assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('960')) # output of node 1's spend
assert_equal(self.nodes[0].getbalances()['mine']['untrusted_pending'], Decimal('960'))
assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], Decimal('960'))
assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0')) # Doesn't include output of node 0's send since it was spent
assert_equal(self.nodes[1].getbalances()['mine']['untrusted_pending'], Decimal('0'))
assert_equal(self.nodes[1].getwalletinfo()["unconfirmed_balance"], Decimal('0'))
test_balances(fee_node_1=Decimal('0.01'))

View File

@ -41,3 +41,45 @@ unsigned-integer-overflow:txmempool.cpp
unsigned-integer-overflow:util/strencodings.cpp
unsigned-integer-overflow:validation.cpp
vptr:bls/bls.h
implicit-integer-sign-change:*/include/c++/*/bits/*.h
implicit-integer-sign-change:*/new_allocator.h
implicit-integer-sign-change:/usr/include/boost/date_time/format_date_parser.hpp
implicit-integer-sign-change:arith_uint256.cpp
implicit-integer-sign-change:bech32.cpp
implicit-integer-sign-change:bloom.cpp
implicit-integer-sign-change:chain.*
implicit-integer-sign-change:coins.h
implicit-integer-sign-change:compat/stdin.cpp
implicit-integer-sign-change:compressor.h
implicit-integer-sign-change:crypto/*
implicit-integer-sign-change:key.cpp
implicit-integer-sign-change:noui.cpp
implicit-integer-sign-change:prevector.h
implicit-integer-sign-change:protocol.cpp
implicit-integer-sign-change:script/bitcoinconsensus.cpp
implicit-integer-sign-change:script/interpreter.cpp
implicit-integer-sign-change:serialize.h
implicit-integer-sign-change:test/arith_uint256_tests.cpp
implicit-integer-sign-change:test/coins_tests.cpp
implicit-integer-sign-change:test/pow_tests.cpp
implicit-integer-sign-change:test/prevector_tests.cpp
implicit-integer-sign-change:test/sighash_tests.cpp
implicit-integer-sign-change:test/streams_tests.cpp
implicit-integer-sign-change:test/transaction_tests.cpp
implicit-integer-sign-change:txmempool.cpp
implicit-integer-sign-change:util/strencodings.*
implicit-integer-sign-change:validation.cpp
implicit-integer-sign-change:zmq/zmqpublishnotifier.cpp
implicit-signed-integer-truncation,implicit-integer-sign-change:chain.h
implicit-signed-integer-truncation,implicit-integer-sign-change:test/skiplist_tests.cpp
implicit-signed-integer-truncation:chain.h
implicit-signed-integer-truncation:crypto/*
implicit-signed-integer-truncation:cuckoocache.h
implicit-signed-integer-truncation:leveldb/*
implicit-signed-integer-truncation:streams.h
implicit-signed-integer-truncation:test/arith_uint256_tests.cpp
implicit-signed-integer-truncation:test/skiplist_tests.cpp
implicit-signed-integer-truncation:torcontrol.cpp
implicit-unsigned-integer-truncation:crypto/*
implicit-unsigned-integer-truncation:leveldb/*