Merge pull request #4432 from PastaPastaPasta/backport-trivial-pr18

Backport trivial pr18
This commit is contained in:
UdjinM6 2021-09-19 00:33:21 +03:00 committed by GitHub
commit 8491e925d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 341 additions and 145 deletions

View File

@ -732,8 +732,6 @@ if test x$ac_cv_sys_large_files != x &&
CPPFLAGS="$CPPFLAGS -D_LARGE_FILES=$ac_cv_sys_large_files"
fi
AX_CHECK_LINK_FLAG([[-Wl,--large-address-aware]], [LDFLAGS="$LDFLAGS -Wl,--large-address-aware"])
AX_GCC_FUNC_ATTRIBUTE([visibility])
AX_GCC_FUNC_ATTRIBUTE([dllexport])
AX_GCC_FUNC_ATTRIBUTE([dllimport])
@ -814,10 +812,13 @@ if test x$use_hardening != xno; then
esac
fi
dnl this flag screws up non-darwin gcc even when the check fails. special-case it.
dnl These flags are specific to ld64, and may cause issues with other linkers.
dnl For example: GNU ld will intepret -dead_strip as -de and then try and use
dnl "ad_strip" as the symbol for the entry point.
if test x$TARGET_OS = xdarwin; then
AX_CHECK_LINK_FLAG([[-Wl,-dead_strip]], [LDFLAGS="$LDFLAGS -Wl,-dead_strip"])
AX_CHECK_LINK_FLAG([[-Wl,-dead_strip_dylibs]], [LDFLAGS="$LDFLAGS -Wl,-dead_strip_dylibs"])
AX_CHECK_LINK_FLAG([[-Wl,-bind_at_load]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-bind_at_load"])
fi
AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h sys/prctl.h])

View File

@ -47,7 +47,8 @@ MAX_VERSIONS = {
# Ignore symbols that are exported as part of every executable
IGNORE_EXPORTS = {
'_edata', '_end', '__end__', '_init', '__bss_start', '__bss_start__', '_bss_end__', '__bss_end__', '_fini', '_IO_stdin_used', 'stdin', 'stdout', 'stderr'
'_edata', '_end', '__end__', '_init', '__bss_start', '__bss_start__', '_bss_end__', '__bss_end__', '_fini', '_IO_stdin_used', 'stdin', 'stdout', 'stderr',
'environ', '_environ', '__environ',
}
READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt')

View File

@ -43,7 +43,7 @@ script: |
FAKETIME_PROGS="date ar ranlib nm"
HOST_CFLAGS="-O2 -g"
HOST_CXXFLAGS="-O2 -g"
HOST_LDFLAGS=-static-libstdc++
HOST_LDFLAGS_BASE="-static-libstdc++"
export QT_RCC_TEST=1
export QT_RCC_SOURCE_DATE_OVERRIDE=1
@ -182,6 +182,13 @@ script: |
# Extract the release tarball into a dir for each host and build
for i in ${HOSTS}; do
export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH}
if [ "${i}" = "riscv64-linux-gnu" ]; then
# Workaround for https://bugs.launchpad.net/ubuntu/+source/gcc-8-cross-ports/+bug/1853740
# TODO: remove this when no longer needed
HOST_LDFLAGS="${HOST_LDFLAGS_BASE} -Wl,-z,noexecstack"
else
HOST_LDFLAGS="${HOST_LDFLAGS_BASE}"
fi
mkdir -p distsrc-${i}
cd distsrc-${i}
INSTALLPATH="${PWD}/installed/${DISTNAME}"

View File

@ -36,6 +36,6 @@ script: |
make
find ${UNSIGNED_DIR} -name "*-unsigned.exe" | while read i; do
INFILE="$(basename "${i}")"
OUTFILE="${INFILE/%-unsigned}"
OUTFILE="${INFILE/-unsigned}"
./osslsigncode attach-signature -in "${i}" -out "${OUTDIR}/${OUTFILE}" -sigin "${SIGDIR}/${INFILE}.pem"
done

View File

@ -40,7 +40,7 @@ Import trusted keys
In order to check the commit signatures, you must add the trusted PGP keys to your machine. [GnuPG](https://gnupg.org/) may be used to import the trusted keys by running the following command:
```sh
gpg --recv-keys $(<contrib/verify-commits/trusted-keys)
gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys $(<contrib/verify-commits/trusted-keys)
```
Key expiry/revocation

View File

@ -42,7 +42,9 @@ FUZZ_TARGETS = \
test/fuzz/service_deserialize \
test/fuzz/sub_net_deserialize \
test/fuzz/transaction \
test/fuzz/tx_in \
test/fuzz/tx_in_deserialize \
test/fuzz/tx_out \
test/fuzz/txoutcompressor_deserialize \
test/fuzz/txundo_deserialize
@ -466,6 +468,18 @@ test_fuzz_tx_in_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_tx_in_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(LDFLAGS_WRAP_EXCEPTIONS)
test_fuzz_tx_in_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_tx_in_SOURCES = $(FUZZ_SUITE) test/fuzz/tx_in.cpp
test_fuzz_tx_in_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_tx_in_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_tx_in_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_tx_in_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_tx_out_SOURCES = $(FUZZ_SUITE) test/fuzz/tx_out.cpp
test_fuzz_tx_out_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_tx_out_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_tx_out_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_tx_out_LDADD = $(FUZZ_SUITE_LD_COMMON)
endif # ENABLE_FUZZ
nodist_test_test_dash_SOURCES = $(GENERATED_TEST_FILES)

View File

@ -92,7 +92,6 @@ private:
nTotal--;
bool fRet = fAllOk;
// reset the status for new work later
if (fMaster)
fAllOk = true;
// return the current status
return fRet;

View File

@ -76,8 +76,21 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
}
if (!possible_overwrite) {
if (!it->second.coin.IsSpent()) {
throw std::logic_error("Adding new coin that replaces non-pruned entry");
throw std::logic_error("Attempted to overwrite an unspent coin (when possible_overwrite is false)");
}
// If the coin exists in this cache as a spent coin and is DIRTY, then
// its spentness hasn't been flushed to the parent cache. We're
// re-adding the coin to this cache now but we can't mark it as FRESH.
// If we mark it FRESH and then spend it before the cache is flushed
// we would remove it from this cache and would never flush spentness
// to the parent cache.
//
// Re-adding a spent coin can happen in the case of a re-org (the coin
// is 'spent' when the block adding it is disconnected and then
// re-added when it is also added in a newly connected block).
//
// If the coin doesn't exist in the current cache, or is spent but not
// DIRTY, then it can be marked FRESH.
fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
}
it->second.coin = std::move(coin);
@ -85,12 +98,12 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
}
void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight, bool check) {
void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight, bool check_for_overwrite) {
bool fCoinbase = tx.IsCoinBase();
const uint256& txid = tx.GetHash();
for (size_t i = 0; i < tx.vout.size(); ++i) {
bool overwrite = check ? cache.HaveCoin(COutPoint(txid, i)) : fCoinbase;
// Always set the possible_overwrite flag to AddCoin for coinbase txn, in order to correctly
bool overwrite = check_for_overwrite ? cache.HaveCoin(COutPoint(txid, i)) : fCoinbase;
// Coinbase transactions can always be overwritten, in order to correctly
// deal with the pre-BIP30 occurrences of duplicate coinbase transactions.
cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), overwrite);
}
@ -151,11 +164,11 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
}
CCoinsMap::iterator itUs = cacheCoins.find(it->first);
if (itUs == cacheCoins.end()) {
// The parent cache does not have an entry, while the child does
// We can ignore it if it's both FRESH and pruned in the child
// The parent cache does not have an entry, while the child cache does.
// We can ignore it if it's both spent and FRESH in the child
if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
// Otherwise we will need to create it in the parent
// and move the data up and mark it as dirty
// Create the coin in the parent cache, move the data up
// and mark it as dirty.
CCoinsCacheEntry& entry = cacheCoins[it->first];
entry.coin = std::move(it->second.coin);
cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
@ -168,19 +181,18 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
}
}
} else {
// Assert that the child cache entry was not marked FRESH if the
// parent cache entry has unspent outputs. If this ever happens,
// it means the FRESH flag was misapplied and there is a logic
// error in the calling code.
// Found the entry in the parent cache
if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent()) {
throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");
// The coin was marked FRESH in the child cache, but the coin
// exists in the parent cache. If this ever happens, it means
// the FRESH flag was misapplied and there is a logic error in
// the calling code.
throw std::logic_error("FRESH flag misapplied to coin that exists in parent cache");
}
// Found the entry in the parent cache
if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
// The grandparent does not have an entry, and the child is
// modified and being pruned. This means we can just delete
// it from the parent.
// The grandparent cache does not have an entry, and the coin
// has been spent. We can just delete it from the parent cache.
cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
cacheCoins.erase(itUs);
} else {
@ -189,11 +201,10 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
itUs->second.coin = std::move(it->second.coin);
cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
itUs->second.flags |= CCoinsCacheEntry::DIRTY;
// NOTE: It is possible the child has a FRESH flag here in
// the event the entry we found in the parent is pruned. But
// we must not copy that FRESH flag to the parent as that
// pruned state likely still needs to be communicated to the
// grandparent.
// NOTE: It isn't safe to mark the coin as FRESH in the parent
// cache. If it already existed and was spent in the parent
// cache then marking it FRESH would prevent that spentness
// from being flushed to the grandparent.
}
}
}

View File

@ -111,19 +111,45 @@ public:
}
};
/**
* A Coin in one level of the coins database caching hierarchy.
*
* A coin can either be:
* - unspent or spent (in which case the Coin object will be nulled out - see Coin.Clear())
* - DIRTY or not DIRTY
* - FRESH or not FRESH
*
* Out of these 2^3 = 8 states, only some combinations are valid:
* - unspent, FRESH, DIRTY (e.g. a new coin created in the cache)
* - unspent, not FRESH, DIRTY (e.g. a coin changed in the cache during a reorg)
* - unspent, not FRESH, not DIRTY (e.g. an unspent coin fetched from the parent cache)
* - spent, FRESH, not DIRTY (e.g. a spent coin fetched from the parent cache)
* - spent, not FRESH, DIRTY (e.g. a coin is spent and spentness needs to be flushed to the parent)
*/
struct CCoinsCacheEntry
{
Coin coin; // The actual cached data.
unsigned char flags;
enum Flags {
DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
FRESH = (1 << 1), // The parent view does not have this entry (or it is pruned).
/* Note that FRESH is a performance optimization with which we can
* erase coins that are fully spent if we know we do not need to
* flush the changes to the parent cache. It is always safe to
* not mark FRESH if that condition is not guaranteed.
/**
* DIRTY means the CCoinsCacheEntry is potentially different from the
* version in the parent cache. Failure to mark a coin as DIRTY when
* it is potentially different from the parent cache will cause a
* consensus failure, since the coin's state won't get written to the
* parent when the cache is flushed.
*/
DIRTY = (1 << 0),
/**
* FRESH means the parent cache does not have this coin or that it is a
* spent coin in the parent cache. If a FRESH coin in the cache is
* later spent, it can be deleted entirely and doesn't ever need to be
* flushed to the parent. This is a performance optimization. Marking a
* coin as FRESH when it exists unspent in the parent cache will cause a
* consensus failure, since it might not be deleted from the parent
* when this cache is flushed.
*/
FRESH = (1 << 1),
};
CCoinsCacheEntry() : flags(0) {}
@ -248,7 +274,7 @@ public:
bool HaveCoinInCache(const COutPoint &outpoint) const;
/**
* Return a reference to Coin in the cache, or a pruned one if not found. This is
* Return a reference to Coin in the cache, or coinEmpty if not found. This is
* more efficient than GetCoin.
*
* Generally, do not hold the reference returned for more than a short scope.
@ -260,10 +286,10 @@ public:
const Coin& AccessCoin(const COutPoint &output) const;
/**
* Add a coin. Set potential_overwrite to true if a non-pruned version may
* already exist.
* Add a coin. Set possible_overwrite to true if an unspent version may
* already exist in the cache.
*/
void AddCoin(const COutPoint& outpoint, Coin&& coin, bool potential_overwrite);
void AddCoin(const COutPoint& outpoint, Coin&& coin, bool possible_overwrite);
/**
* Spend a coin. Pass moveto in order to get the deleted data.

View File

@ -520,7 +520,7 @@ void BitcoinGUI::createMenuBar()
QAction* minimize_action = window_menu->addAction(tr("Minimize"));
minimize_action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M));
connect(minimize_action, &QAction::triggered, [] {
qApp->focusWindow()->showMinimized();
QApplication::activeWindow()->showMinimized();
});
connect(qApp, &QApplication::focusWindowChanged, [minimize_action] (QWindow* window) {
minimize_action->setEnabled(window != nullptr && (window->flags() & Qt::Dialog) != Qt::Dialog && window->windowState() != Qt::WindowMinimized);

View File

@ -263,8 +263,9 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int heig
clientmodel->cachedBestHeaderHeight = height;
clientmodel->cachedBestHeaderTime = blockTime;
}
// if we are in-sync or if we notify a header update, update the UI regardless of last update time
if (fHeader || !initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
// During initial sync, block notifications, and header notifications from reindexing are both throttled.
if (!initialSync || (fHeader && !clientmodel->node().getReindex()) || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
//pass an async signal to the UI thread
QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
Q_ARG(int, height),

View File

@ -1059,12 +1059,8 @@ void RPCConsole::on_lineEdit_returnPressed()
cmdBeforeBrowsing = QString();
WalletModel* wallet_model{nullptr};
#ifdef ENABLE_WALLET
const int wallet_index = ui->WalletSelector->currentIndex();
if (wallet_index > 0) {
wallet_model = ui->WalletSelector->itemData(wallet_index).value<WalletModel*>();
}
WalletModel* wallet_model = ui->WalletSelector->currentData().value<WalletModel*>();
if (m_last_wallet_model != wallet_model) {
if (wallet_model) {

View File

@ -23,6 +23,17 @@ BOOST_AUTO_TEST_CASE(base32_testvectors)
std::string strDec = DecodeBase32(vstrOut[i]);
BOOST_CHECK_EQUAL(strDec, vstrIn[i]);
}
// Decoding strings with embedded NUL characters should fail
bool failure;
(void)DecodeBase32(std::string("invalid", 7), &failure);
BOOST_CHECK_EQUAL(failure, true);
(void)DecodeBase32(std::string("AWSX3VPP", 8), &failure);
BOOST_CHECK_EQUAL(failure, false);
(void)DecodeBase32(std::string("AWSX3VPP\0invalid", 16), &failure);
BOOST_CHECK_EQUAL(failure, true);
(void)DecodeBase32(std::string("AWSX3VPPinvalid", 15), &failure);
BOOST_CHECK_EQUAL(failure, true);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -20,6 +20,17 @@ BOOST_AUTO_TEST_CASE(base64_testvectors)
std::string strDec = DecodeBase64(strEnc);
BOOST_CHECK_EQUAL(strDec, vstrIn[i]);
}
// Decoding strings with embedded NUL characters should fail
bool failure;
(void)DecodeBase64(std::string("invalid", 7), &failure);
BOOST_CHECK_EQUAL(failure, true);
(void)DecodeBase64(std::string("nQB/pZw=", 8), &failure);
BOOST_CHECK_EQUAL(failure, false);
(void)DecodeBase64(std::string("nQB/pZw=\0invalid", 16), &failure);
BOOST_CHECK_EQUAL(failure, true);
(void)DecodeBase64(std::string("nQB/pZw=invalid", 15), &failure);
BOOST_CHECK_EQUAL(failure, true);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -532,7 +532,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
}
const static COutPoint OUTPOINT;
const static CAmount PRUNED = -1;
const static CAmount SPENT = -1;
const static CAmount ABSENT = -2;
const static CAmount FAIL = -3;
const static CAmount VALUE1 = 100;
@ -551,7 +551,7 @@ static void SetCoinsValue(CAmount value, Coin& coin)
assert(value != ABSENT);
coin.Clear();
assert(coin.IsSpent());
if (value != PRUNED) {
if (value != SPENT) {
coin.out.nValue = value;
coin.nHeight = 1;
assert(!coin.IsSpent());
@ -581,7 +581,7 @@ void GetCoinsMapEntry(const CCoinsMap& map, CAmount& value, char& flags)
flags = NO_ENTRY;
} else {
if (it->second.coin.IsSpent()) {
value = PRUNED;
value = SPENT;
} else {
value = it->second.coin.out.nValue;
}
@ -634,28 +634,28 @@ BOOST_AUTO_TEST_CASE(ccoins_access)
* Value Value Value Flags Flags
*/
CheckAccessCoin(ABSENT, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
CheckAccessCoin(ABSENT, PRUNED, PRUNED, 0 , 0 );
CheckAccessCoin(ABSENT, PRUNED, PRUNED, FRESH , FRESH );
CheckAccessCoin(ABSENT, PRUNED, PRUNED, DIRTY , DIRTY );
CheckAccessCoin(ABSENT, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoin(ABSENT, SPENT , SPENT , 0 , 0 );
CheckAccessCoin(ABSENT, SPENT , SPENT , FRESH , FRESH );
CheckAccessCoin(ABSENT, SPENT , SPENT , DIRTY , DIRTY );
CheckAccessCoin(ABSENT, SPENT , SPENT , DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoin(ABSENT, VALUE2, VALUE2, 0 , 0 );
CheckAccessCoin(ABSENT, VALUE2, VALUE2, FRESH , FRESH );
CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY , DIRTY );
CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoin(PRUNED, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
CheckAccessCoin(PRUNED, PRUNED, PRUNED, 0 , 0 );
CheckAccessCoin(PRUNED, PRUNED, PRUNED, FRESH , FRESH );
CheckAccessCoin(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY );
CheckAccessCoin(PRUNED, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoin(PRUNED, VALUE2, VALUE2, 0 , 0 );
CheckAccessCoin(PRUNED, VALUE2, VALUE2, FRESH , FRESH );
CheckAccessCoin(PRUNED, VALUE2, VALUE2, DIRTY , DIRTY );
CheckAccessCoin(PRUNED, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoin(SPENT , ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
CheckAccessCoin(SPENT , SPENT , SPENT , 0 , 0 );
CheckAccessCoin(SPENT , SPENT , SPENT , FRESH , FRESH );
CheckAccessCoin(SPENT , SPENT , SPENT , DIRTY , DIRTY );
CheckAccessCoin(SPENT , SPENT , SPENT , DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoin(SPENT , VALUE2, VALUE2, 0 , 0 );
CheckAccessCoin(SPENT , VALUE2, VALUE2, FRESH , FRESH );
CheckAccessCoin(SPENT , VALUE2, VALUE2, DIRTY , DIRTY );
CheckAccessCoin(SPENT , VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoin(VALUE1, ABSENT, VALUE1, NO_ENTRY , 0 );
CheckAccessCoin(VALUE1, PRUNED, PRUNED, 0 , 0 );
CheckAccessCoin(VALUE1, PRUNED, PRUNED, FRESH , FRESH );
CheckAccessCoin(VALUE1, PRUNED, PRUNED, DIRTY , DIRTY );
CheckAccessCoin(VALUE1, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoin(VALUE1, SPENT , SPENT , 0 , 0 );
CheckAccessCoin(VALUE1, SPENT , SPENT , FRESH , FRESH );
CheckAccessCoin(VALUE1, SPENT , SPENT , DIRTY , DIRTY );
CheckAccessCoin(VALUE1, SPENT , SPENT , DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoin(VALUE1, VALUE2, VALUE2, 0 , 0 );
CheckAccessCoin(VALUE1, VALUE2, VALUE2, FRESH , FRESH );
CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY , DIRTY );
@ -685,31 +685,31 @@ BOOST_AUTO_TEST_CASE(ccoins_spend)
* Value Value Value Flags Flags
*/
CheckSpendCoins(ABSENT, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
CheckSpendCoins(ABSENT, PRUNED, PRUNED, 0 , DIRTY );
CheckSpendCoins(ABSENT, PRUNED, ABSENT, FRESH , NO_ENTRY );
CheckSpendCoins(ABSENT, PRUNED, PRUNED, DIRTY , DIRTY );
CheckSpendCoins(ABSENT, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckSpendCoins(ABSENT, VALUE2, PRUNED, 0 , DIRTY );
CheckSpendCoins(ABSENT, SPENT , SPENT , 0 , DIRTY );
CheckSpendCoins(ABSENT, SPENT , ABSENT, FRESH , NO_ENTRY );
CheckSpendCoins(ABSENT, SPENT , SPENT , DIRTY , DIRTY );
CheckSpendCoins(ABSENT, SPENT , ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckSpendCoins(ABSENT, VALUE2, SPENT , 0 , DIRTY );
CheckSpendCoins(ABSENT, VALUE2, ABSENT, FRESH , NO_ENTRY );
CheckSpendCoins(ABSENT, VALUE2, PRUNED, DIRTY , DIRTY );
CheckSpendCoins(ABSENT, VALUE2, SPENT , DIRTY , DIRTY );
CheckSpendCoins(ABSENT, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckSpendCoins(PRUNED, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
CheckSpendCoins(PRUNED, PRUNED, PRUNED, 0 , DIRTY );
CheckSpendCoins(PRUNED, PRUNED, ABSENT, FRESH , NO_ENTRY );
CheckSpendCoins(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY );
CheckSpendCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckSpendCoins(PRUNED, VALUE2, PRUNED, 0 , DIRTY );
CheckSpendCoins(PRUNED, VALUE2, ABSENT, FRESH , NO_ENTRY );
CheckSpendCoins(PRUNED, VALUE2, PRUNED, DIRTY , DIRTY );
CheckSpendCoins(PRUNED, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckSpendCoins(VALUE1, ABSENT, PRUNED, NO_ENTRY , DIRTY );
CheckSpendCoins(VALUE1, PRUNED, PRUNED, 0 , DIRTY );
CheckSpendCoins(VALUE1, PRUNED, ABSENT, FRESH , NO_ENTRY );
CheckSpendCoins(VALUE1, PRUNED, PRUNED, DIRTY , DIRTY );
CheckSpendCoins(VALUE1, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckSpendCoins(VALUE1, VALUE2, PRUNED, 0 , DIRTY );
CheckSpendCoins(SPENT , ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
CheckSpendCoins(SPENT , SPENT , SPENT , 0 , DIRTY );
CheckSpendCoins(SPENT , SPENT , ABSENT, FRESH , NO_ENTRY );
CheckSpendCoins(SPENT , SPENT , SPENT , DIRTY , DIRTY );
CheckSpendCoins(SPENT , SPENT , ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckSpendCoins(SPENT , VALUE2, SPENT , 0 , DIRTY );
CheckSpendCoins(SPENT , VALUE2, ABSENT, FRESH , NO_ENTRY );
CheckSpendCoins(SPENT , VALUE2, SPENT , DIRTY , DIRTY );
CheckSpendCoins(SPENT , VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckSpendCoins(VALUE1, ABSENT, SPENT , NO_ENTRY , DIRTY );
CheckSpendCoins(VALUE1, SPENT , SPENT , 0 , DIRTY );
CheckSpendCoins(VALUE1, SPENT , ABSENT, FRESH , NO_ENTRY );
CheckSpendCoins(VALUE1, SPENT , SPENT , DIRTY , DIRTY );
CheckSpendCoins(VALUE1, SPENT , ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckSpendCoins(VALUE1, VALUE2, SPENT , 0 , DIRTY );
CheckSpendCoins(VALUE1, VALUE2, ABSENT, FRESH , NO_ENTRY );
CheckSpendCoins(VALUE1, VALUE2, PRUNED, DIRTY , DIRTY );
CheckSpendCoins(VALUE1, VALUE2, SPENT , DIRTY , DIRTY );
CheckSpendCoins(VALUE1, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY );
}
@ -742,7 +742,7 @@ static void CheckAddCoinBase(CAmount base_value, CAmount cache_value, CAmount mo
template <typename... Args>
static void CheckAddCoin(Args&&... args)
{
for (const CAmount base_value : {ABSENT, PRUNED, VALUE1})
for (const CAmount base_value : {ABSENT, SPENT, VALUE1})
CheckAddCoinBase(base_value, std::forward<Args>(args)...);
}
@ -751,21 +751,21 @@ BOOST_AUTO_TEST_CASE(ccoins_add)
/* Check AddCoin behavior, requesting a new coin from a cache view,
* writing a modification to the coin, and then checking the resulting
* entry in the cache after the modification. Verify behavior with the
* with the AddCoin potential_overwrite argument set to false, and to true.
* AddCoin possible_overwrite argument set to false, and to true.
*
* Cache Write Result Cache Result potential_overwrite
* Cache Write Result Cache Result possible_overwrite
* Value Value Value Flags Flags
*/
CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY|FRESH, false);
CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY , true );
CheckAddCoin(PRUNED, VALUE3, VALUE3, 0 , DIRTY|FRESH, false);
CheckAddCoin(PRUNED, VALUE3, VALUE3, 0 , DIRTY , true );
CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, false);
CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, true );
CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , false);
CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , true );
CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, false);
CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
CheckAddCoin(SPENT , VALUE3, VALUE3, 0 , DIRTY|FRESH, false);
CheckAddCoin(SPENT , VALUE3, VALUE3, 0 , DIRTY , true );
CheckAddCoin(SPENT , VALUE3, VALUE3, FRESH , DIRTY|FRESH, false);
CheckAddCoin(SPENT , VALUE3, VALUE3, FRESH , DIRTY|FRESH, true );
CheckAddCoin(SPENT , VALUE3, VALUE3, DIRTY , DIRTY , false);
CheckAddCoin(SPENT , VALUE3, VALUE3, DIRTY , DIRTY , true );
CheckAddCoin(SPENT , VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, false);
CheckAddCoin(SPENT , VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
CheckAddCoin(VALUE2, VALUE3, FAIL , 0 , NO_ENTRY , false);
CheckAddCoin(VALUE2, VALUE3, VALUE3, 0 , DIRTY , true );
CheckAddCoin(VALUE2, VALUE3, FAIL , FRESH , NO_ENTRY , false);
@ -805,42 +805,42 @@ BOOST_AUTO_TEST_CASE(ccoins_write)
* Value Value Value Flags Flags Flags
*/
CheckWriteCoins(ABSENT, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY , NO_ENTRY );
CheckWriteCoins(ABSENT, PRUNED, PRUNED, NO_ENTRY , DIRTY , DIRTY );
CheckWriteCoins(ABSENT, PRUNED, ABSENT, NO_ENTRY , DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(ABSENT, SPENT , SPENT , NO_ENTRY , DIRTY , DIRTY );
CheckWriteCoins(ABSENT, SPENT , ABSENT, NO_ENTRY , DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(ABSENT, VALUE2, VALUE2, NO_ENTRY , DIRTY , DIRTY );
CheckWriteCoins(ABSENT, VALUE2, VALUE2, NO_ENTRY , DIRTY|FRESH, DIRTY|FRESH);
CheckWriteCoins(PRUNED, ABSENT, PRUNED, 0 , NO_ENTRY , 0 );
CheckWriteCoins(PRUNED, ABSENT, PRUNED, FRESH , NO_ENTRY , FRESH );
CheckWriteCoins(PRUNED, ABSENT, PRUNED, DIRTY , NO_ENTRY , DIRTY );
CheckWriteCoins(PRUNED, ABSENT, PRUNED, DIRTY|FRESH, NO_ENTRY , DIRTY|FRESH);
CheckWriteCoins(PRUNED, PRUNED, PRUNED, 0 , DIRTY , DIRTY );
CheckWriteCoins(PRUNED, PRUNED, PRUNED, 0 , DIRTY|FRESH, DIRTY );
CheckWriteCoins(PRUNED, PRUNED, ABSENT, FRESH , DIRTY , NO_ENTRY );
CheckWriteCoins(PRUNED, PRUNED, ABSENT, FRESH , DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY , DIRTY );
CheckWriteCoins(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY|FRESH, DIRTY );
CheckWriteCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, DIRTY , NO_ENTRY );
CheckWriteCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(PRUNED, VALUE2, VALUE2, 0 , DIRTY , DIRTY );
CheckWriteCoins(PRUNED, VALUE2, VALUE2, 0 , DIRTY|FRESH, DIRTY );
CheckWriteCoins(PRUNED, VALUE2, VALUE2, FRESH , DIRTY , DIRTY|FRESH);
CheckWriteCoins(PRUNED, VALUE2, VALUE2, FRESH , DIRTY|FRESH, DIRTY|FRESH);
CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY , DIRTY , DIRTY );
CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY , DIRTY|FRESH, DIRTY );
CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY|FRESH, DIRTY , DIRTY|FRESH);
CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH, DIRTY|FRESH);
CheckWriteCoins(SPENT , ABSENT, SPENT , 0 , NO_ENTRY , 0 );
CheckWriteCoins(SPENT , ABSENT, SPENT , FRESH , NO_ENTRY , FRESH );
CheckWriteCoins(SPENT , ABSENT, SPENT , DIRTY , NO_ENTRY , DIRTY );
CheckWriteCoins(SPENT , ABSENT, SPENT , DIRTY|FRESH, NO_ENTRY , DIRTY|FRESH);
CheckWriteCoins(SPENT , SPENT , SPENT , 0 , DIRTY , DIRTY );
CheckWriteCoins(SPENT , SPENT , SPENT , 0 , DIRTY|FRESH, DIRTY );
CheckWriteCoins(SPENT , SPENT , ABSENT, FRESH , DIRTY , NO_ENTRY );
CheckWriteCoins(SPENT , SPENT , ABSENT, FRESH , DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(SPENT , SPENT , SPENT , DIRTY , DIRTY , DIRTY );
CheckWriteCoins(SPENT , SPENT , SPENT , DIRTY , DIRTY|FRESH, DIRTY );
CheckWriteCoins(SPENT , SPENT , ABSENT, DIRTY|FRESH, DIRTY , NO_ENTRY );
CheckWriteCoins(SPENT , SPENT , ABSENT, DIRTY|FRESH, DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(SPENT , VALUE2, VALUE2, 0 , DIRTY , DIRTY );
CheckWriteCoins(SPENT , VALUE2, VALUE2, 0 , DIRTY|FRESH, DIRTY );
CheckWriteCoins(SPENT , VALUE2, VALUE2, FRESH , DIRTY , DIRTY|FRESH);
CheckWriteCoins(SPENT , VALUE2, VALUE2, FRESH , DIRTY|FRESH, DIRTY|FRESH);
CheckWriteCoins(SPENT , VALUE2, VALUE2, DIRTY , DIRTY , DIRTY );
CheckWriteCoins(SPENT , VALUE2, VALUE2, DIRTY , DIRTY|FRESH, DIRTY );
CheckWriteCoins(SPENT , VALUE2, VALUE2, DIRTY|FRESH, DIRTY , DIRTY|FRESH);
CheckWriteCoins(SPENT , VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH, DIRTY|FRESH);
CheckWriteCoins(VALUE1, ABSENT, VALUE1, 0 , NO_ENTRY , 0 );
CheckWriteCoins(VALUE1, ABSENT, VALUE1, FRESH , NO_ENTRY , FRESH );
CheckWriteCoins(VALUE1, ABSENT, VALUE1, DIRTY , NO_ENTRY , DIRTY );
CheckWriteCoins(VALUE1, ABSENT, VALUE1, DIRTY|FRESH, NO_ENTRY , DIRTY|FRESH);
CheckWriteCoins(VALUE1, PRUNED, PRUNED, 0 , DIRTY , DIRTY );
CheckWriteCoins(VALUE1, PRUNED, FAIL , 0 , DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(VALUE1, PRUNED, ABSENT, FRESH , DIRTY , NO_ENTRY );
CheckWriteCoins(VALUE1, PRUNED, FAIL , FRESH , DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(VALUE1, PRUNED, PRUNED, DIRTY , DIRTY , DIRTY );
CheckWriteCoins(VALUE1, PRUNED, FAIL , DIRTY , DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(VALUE1, PRUNED, ABSENT, DIRTY|FRESH, DIRTY , NO_ENTRY );
CheckWriteCoins(VALUE1, PRUNED, FAIL , DIRTY|FRESH, DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(VALUE1, SPENT , SPENT , 0 , DIRTY , DIRTY );
CheckWriteCoins(VALUE1, SPENT , FAIL , 0 , DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(VALUE1, SPENT , ABSENT, FRESH , DIRTY , NO_ENTRY );
CheckWriteCoins(VALUE1, SPENT , FAIL , FRESH , DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(VALUE1, SPENT , SPENT , DIRTY , DIRTY , DIRTY );
CheckWriteCoins(VALUE1, SPENT , FAIL , DIRTY , DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(VALUE1, SPENT , ABSENT, DIRTY|FRESH, DIRTY , NO_ENTRY );
CheckWriteCoins(VALUE1, SPENT , FAIL , DIRTY|FRESH, DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(VALUE1, VALUE2, VALUE2, 0 , DIRTY , DIRTY );
CheckWriteCoins(VALUE1, VALUE2, FAIL , 0 , DIRTY|FRESH, NO_ENTRY );
CheckWriteCoins(VALUE1, VALUE2, VALUE2, FRESH , DIRTY , DIRTY|FRESH);
@ -854,8 +854,8 @@ BOOST_AUTO_TEST_CASE(ccoins_write)
// they would be too repetitive (the parent cache is never updated in these
// cases). The loop below covers these cases and makes sure the parent cache
// is always left unchanged.
for (const CAmount parent_value : {ABSENT, PRUNED, VALUE1})
for (const CAmount child_value : {ABSENT, PRUNED, VALUE2})
for (const CAmount parent_value : {ABSENT, SPENT, VALUE1})
for (const CAmount child_value : {ABSENT, SPENT, VALUE2})
for (const char parent_flags : parent_value == ABSENT ? ABSENT_FLAGS : FLAGS)
for (const char child_flags : child_value == ABSENT ? ABSENT_FLAGS : CLEAN_FLAGS)
CheckWriteCoins(parent_value, child_value, parent_value, parent_flags, child_flags, parent_flags);

33
src/test/fuzz/tx_in.cpp Normal file
View File

@ -0,0 +1,33 @@
// Copyright (c) 2019 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 <consensus/validation.h>
#include <core_memusage.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
#include <streams.h>
#include <test/fuzz/fuzz.h>
#include <version.h>
#include <cassert>
void test_one_input(const std::vector<uint8_t>& buffer)
{
CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
CTxIn tx_in;
try {
int version;
ds >> version;
ds.SetVersion(version);
ds >> tx_in;
} catch (const std::ios_base::failure&) {
return;
}
(void)GetTransactionInputWeight(tx_in);
(void)GetVirtualTransactionInputSize(tx_in);
(void)RecursiveDynamicUsage(tx_in);
(void)tx_in.ToString();
}

35
src/test/fuzz/tx_out.cpp Normal file
View File

@ -0,0 +1,35 @@
// Copyright (c) 2019 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 <consensus/validation.h>
#include <core_memusage.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
#include <streams.h>
#include <test/fuzz/fuzz.h>
#include <version.h>
void test_one_input(const std::vector<uint8_t>& buffer)
{
CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
CTxOut tx_out;
try {
int version;
ds >> version;
ds.SetVersion(version);
ds >> tx_out;
} catch (const std::ios_base::failure&) {
return;
}
const CFeeRate dust_relay_fee{DUST_RELAY_TX_FEE};
(void)GetDustThreshold(tx_out, dust_relay_fee);
(void)IsDust(tx_out, dust_relay_fee);
(void)RecursiveDynamicUsage(tx_out);
(void)tx_out.ToString();
(void)tx_out.IsNull();
tx_out.SetNull();
assert(tx_out.IsNull());
}

View File

@ -640,6 +640,11 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney)
// Parsing negative amounts must fail
BOOST_CHECK(!ParseMoney("-1", ret));
// Parsing strings with embedded NUL characters should fail
BOOST_CHECK(!ParseMoney(std::string("\0-1", 3), ret));
BOOST_CHECK(!ParseMoney(std::string("\01", 2), ret));
BOOST_CHECK(!ParseMoney(std::string("1\0", 2), ret));
}
BOOST_AUTO_TEST_CASE(util_IsHex)

View File

@ -8,6 +8,7 @@
#include <primitives/transaction.h>
#include <tinyformat.h>
#include <util/strencodings.h>
#include <util/string.h>
std::string FormatMoney(const CAmount& n)
{
@ -33,6 +34,9 @@ std::string FormatMoney(const CAmount& n)
bool ParseMoney(const std::string& str, CAmount& nRet)
{
if (!ValidAsCString(str)) {
return false;
}
return ParseMoney(str.c_str(), nRet);
}

View File

@ -191,6 +191,12 @@ std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid)
std::string DecodeBase64(const std::string& str, bool* pf_invalid)
{
if (!ValidAsCString(str)) {
if (pf_invalid) {
*pf_invalid = true;
}
return {};
}
std::vector<unsigned char> vchRet = DecodeBase64(str.c_str(), pf_invalid);
return std::string((const char*)vchRet.data(), vchRet.size());
}
@ -264,6 +270,12 @@ std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid)
std::string DecodeBase32(const std::string& str, bool* pf_invalid)
{
if (!ValidAsCString(str)) {
if (pf_invalid) {
*pf_invalid = true;
}
return {};
}
std::vector<unsigned char> vchRet = DecodeBase32(str.c_str(), pf_invalid);
return std::string((const char*)vchRet.data(), vchRet.size());
}

View File

@ -1159,17 +1159,19 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
SetEndOfFile(hFile);
#elif defined(MAC_OSX)
// OSX specific version
// NOTE: Contrary to other OS versions, the OSX version assumes that
// NOTE: offset is the size of the file.
fstore_t fst;
fst.fst_flags = F_ALLOCATECONTIG;
fst.fst_posmode = F_PEOFPOSMODE;
fst.fst_offset = 0;
fst.fst_length = (off_t)offset + length;
fst.fst_length = length; // mac os fst_length takes the # of free bytes to allocate, not desired file size
fst.fst_bytesalloc = 0;
if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
fst.fst_flags = F_ALLOCATEALL;
fcntl(fileno(file), F_PREALLOCATE, &fst);
}
ftruncate(fileno(file), fst.fst_length);
ftruncate(fileno(file), static_cast<off_t>(offset) + length);
#else
#if defined(__linux__)
// Version using posix_fallocate

View File

@ -1655,10 +1655,11 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
return DISCONNECT_FAILED; // adding output for transaction without known metadata
}
}
// The potential_overwrite parameter to AddCoin is only allowed to be false if we know for
// sure that the coin did not already exist in the cache. As we have queried for that above
// using HaveCoin, we don't need to guess. When fClean is false, a coin already existed and
// it is an overwrite.
// If the coin already exists as an unspent coin in the cache, then the
// possible_overwrite parameter to AddCoin must be set to true. We have
// already checked whether an unspent coin exists above using HaveCoin, so
// we don't need to guess. When fClean is false, an unspent coin already
// existed and it is an overwrite.
view.AddCoin(out, std::move(undo), !fClean);
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;

View File

@ -110,6 +110,9 @@ bool SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& target_v
best_selection = curr_selection;
best_selection.resize(utxo_pool.size());
best_waste = curr_waste;
if (best_waste == 0) {
break;
}
}
curr_waste -= (curr_value - actual_target); // Remove the excess value as we will be selecting different coins now
backtrack = true;

View File

@ -164,8 +164,8 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
selection.clear();
// Select 5 Cent
add_coin(3 * CENT, 3, actual_selection);
add_coin(2 * CENT, 2, actual_selection);
add_coin(4 * CENT, 4, actual_selection);
add_coin(1 * CENT, 1, actual_selection);
BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 5 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees));
BOOST_CHECK(equal_sets(selection, actual_selection));
BOOST_CHECK_EQUAL(value_ret, 5 * CENT);
@ -177,11 +177,23 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
actual_selection.clear();
selection.clear();
// Cost of change is greater than the difference between target value and utxo sum
add_coin(1 * CENT, 1, actual_selection);
BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 0.9 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees));
BOOST_CHECK_EQUAL(value_ret, 1 * CENT);
BOOST_CHECK(equal_sets(selection, actual_selection));
actual_selection.clear();
selection.clear();
// Cost of change is less than the difference between target value and utxo sum
BOOST_CHECK(!SelectCoinsBnB(GroupCoins(utxo_pool), 0.9 * CENT, 0, selection, value_ret, not_input_fees));
actual_selection.clear();
selection.clear();
// Select 10 Cent
add_coin(5 * CENT, 5, utxo_pool);
add_coin(5 * CENT, 5, actual_selection);
add_coin(4 * CENT, 4, actual_selection);
add_coin(3 * CENT, 3, actual_selection);
add_coin(2 * CENT, 2, actual_selection);
add_coin(1 * CENT, 1, actual_selection);
BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 10 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees));
BOOST_CHECK(equal_sets(selection, actual_selection));

View File

@ -21,6 +21,7 @@ FUZZERS_MISSING_CORPORA = [
"fee_rate_deserialize",
"flat_file_pos_deserialize",
"key_origin_info_deserialize",
"locale",
"merkle_block_deserialize",
"out_point_deserialize",
"partial_merkle_tree_deserialize",
@ -32,6 +33,8 @@ FUZZERS_MISSING_CORPORA = [
"script_deserialize",
"sub_net_deserialize",
"tx_in_deserialize",
"tx_in",
"tx_out",
]
def main():
@ -48,6 +51,11 @@ def main():
action='store_true',
help='If true, export coverage information to files in the seed corpus',
)
parser.add_argument(
'--valgrind',
action='store_true',
help='If true, run fuzzing binaries under the valgrind memory error detector. Valgrind 3.14 or later required.',
)
parser.add_argument(
'seed_dir',
help='The seed corpus to run on (must contain subfolders for each fuzz target).',
@ -116,10 +124,11 @@ def main():
test_list=test_list_selection,
build_dir=config["environment"]["BUILDDIR"],
export_coverage=args.export_coverage,
use_valgrind=args.valgrind,
)
def run_once(*, corpus, test_list, build_dir, export_coverage):
def run_once(*, corpus, test_list, build_dir, export_coverage, use_valgrind):
for t in test_list:
corpus_path = os.path.join(corpus, t)
if t in FUZZERS_MISSING_CORPORA:
@ -130,6 +139,8 @@ def run_once(*, corpus, test_list, build_dir, export_coverage):
'-detect_leaks=0',
corpus_path,
]
if use_valgrind:
args = ['valgrind', '--quiet', '--error-exitcode=1', '--exit-on-first-error=yes'] + args
logging.debug('Run {} with args {}'.format(t, args))
result = subprocess.run(args, stderr=subprocess.PIPE, universal_newlines=True)
output = result.stderr