mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-17 13:07:54 +02:00
146 lines
6.4 KiB
C++
146 lines
6.4 KiB
C++
// 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 <chainparams.h>
|
|
#include <coins.h>
|
|
#include <consensus/consensus.h>
|
|
#include <consensus/merkle.h>
|
|
#include <consensus/validation.h>
|
|
#include <validation.h>
|
|
#include <node/miner.h>
|
|
#include <pubkey.h>
|
|
#include <random.h>
|
|
#include <txmempool.h>
|
|
#include <uint256.h>
|
|
#include <util/strencodings.h>
|
|
|
|
#include <txdb.h>
|
|
|
|
#include <test/util/setup_common.h>
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(pegin_spent_tests, TestingSetup)
|
|
|
|
class CCoinsViewTester : public CCoinsView {
|
|
public:
|
|
bool IsPeginSpentCalled{false};
|
|
bool IsPeginSpent(const std::pair<uint256, COutPoint> &outpoint) const override {
|
|
const_cast<bool&>(IsPeginSpentCalled) = true;
|
|
return CCoinsView::IsPeginSpent(outpoint);
|
|
}
|
|
|
|
CCoinsMapMemoryResource resource;
|
|
CCoinsMap mapCoinsWritten{0, CCoinsMap::hasher{}, CCoinsMap::key_equal{}, &resource};
|
|
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase) override {
|
|
mapCoinsWritten.clear();
|
|
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) {
|
|
mapCoinsWritten[it->first] = it->second;
|
|
}
|
|
//mapCoinsWritten = mapCoins;
|
|
return CCoinsView::BatchWrite(mapCoins, hashBlock, erase);
|
|
}
|
|
|
|
CCoinsViewTester() {}
|
|
};
|
|
|
|
BOOST_AUTO_TEST_CASE(PeginSpent_validity)
|
|
{
|
|
CCoinsViewTester coins;
|
|
CCoinsViewCache coinsCache(&coins);
|
|
Coin ret;
|
|
|
|
//Basic insert of blank outpoint pair, blank COutPoint allows for checking coinsCache
|
|
|
|
std::pair<uint256, COutPoint> outpoint = std::make_pair(GetRandHash(), COutPoint(Txid::FromUint256(GetRandHash()), 42));
|
|
BOOST_CHECK(!coinsCache.GetCoin(outpoint.second, ret));
|
|
|
|
//Checking for pegin spentness should not create an entry
|
|
BOOST_CHECK(!coinsCache.IsPeginSpent(outpoint));
|
|
BOOST_CHECK(coins.IsPeginSpentCalled);
|
|
coins.IsPeginSpentCalled = false;
|
|
BOOST_CHECK(!coinsCache.IsPeginSpent(outpoint));
|
|
BOOST_CHECK(!coins.IsPeginSpentCalled);
|
|
|
|
coinsCache.SetPeginSpent(outpoint, true);
|
|
BOOST_CHECK(coinsCache.IsPeginSpent(outpoint));
|
|
coinsCache.SetPeginSpent(outpoint, false);
|
|
BOOST_CHECK(!coinsCache.IsPeginSpent(outpoint));
|
|
coinsCache.SetPeginSpent(outpoint, true);
|
|
BOOST_CHECK(coinsCache.IsPeginSpent(outpoint));
|
|
|
|
//Check for slightly similar non-existent entries
|
|
std::pair<uint256, COutPoint> outpoint2(outpoint);
|
|
outpoint2.second.n = 0;
|
|
BOOST_CHECK(!coinsCache.IsPeginSpent(outpoint2));
|
|
|
|
CCoinsMapMemoryResource resource;
|
|
CCoinsMap mapCoins{0, CCoinsMap::hasher{}, CCoinsMap::key_equal{}, &resource};
|
|
CCoinsCacheEntry entry;
|
|
std::pair<uint256, COutPoint> outpoint3(std::make_pair(GetRandHash(), COutPoint(Txid::FromUint256(GetRandHash()), 42)));
|
|
|
|
//Attempt batch write of non-dirty pegin, no effect
|
|
entry.flags = CCoinsCacheEntry::PEGIN;
|
|
entry.peginSpent = true;
|
|
mapCoins.insert(std::make_pair(outpoint3, entry));
|
|
coinsCache.BatchWrite(mapCoins, uint256());
|
|
//Check for effect
|
|
coins.IsPeginSpentCalled = false;
|
|
BOOST_CHECK(!coinsCache.IsPeginSpent(outpoint3));
|
|
BOOST_CHECK(coins.IsPeginSpentCalled);
|
|
BOOST_CHECK(mapCoins.size() == 0);
|
|
|
|
//Write again with pegin, dirty && fresh flags, but unspent. No effect.
|
|
entry.peginSpent = false;
|
|
entry.flags |= CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH;
|
|
mapCoins.insert(std::make_pair(outpoint3, entry));
|
|
coinsCache.BatchWrite(mapCoins, uint256());
|
|
//Check for effect
|
|
coins.IsPeginSpentCalled = false;
|
|
BOOST_CHECK(!coinsCache.IsPeginSpent(outpoint3));
|
|
BOOST_CHECK(coins.IsPeginSpentCalled);
|
|
BOOST_CHECK(mapCoins.size() == 0);
|
|
|
|
//Re-mark as spent. It's super effective.
|
|
entry.peginSpent = true;
|
|
mapCoins.insert(std::make_pair(outpoint3, entry));
|
|
coinsCache.BatchWrite(mapCoins, uint256());
|
|
//Check for effect
|
|
coins.IsPeginSpentCalled = false;
|
|
BOOST_CHECK(coinsCache.IsPeginSpent(outpoint3));
|
|
BOOST_CHECK(!coins.IsPeginSpentCalled);
|
|
BOOST_CHECK(mapCoins.size() == 0);
|
|
|
|
//Add an entry we never IsPeginSpent'd first (ie added to cache via SetPeginSpent)
|
|
std::pair<uint256, COutPoint> outpoint4(std::make_pair(GetRandHash(), COutPoint(Txid::FromUint256(GetRandHash()), 42)));
|
|
coinsCache.SetPeginSpent(outpoint4, true);
|
|
|
|
// Check the final state of coinsCache.mapCoins is sane.
|
|
BOOST_CHECK_EQUAL(coins.mapCoinsWritten.size(), 0U);
|
|
coinsCache.Flush();
|
|
BOOST_CHECK_EQUAL(coins.mapCoinsWritten.size(), 4U);
|
|
BOOST_CHECK_EQUAL(coins.mapCoinsWritten[outpoint].flags, CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH | CCoinsCacheEntry::PEGIN);
|
|
BOOST_CHECK_EQUAL(coins.mapCoinsWritten[outpoint].peginSpent, true);
|
|
BOOST_CHECK_EQUAL(coins.mapCoinsWritten[outpoint2].flags, CCoinsCacheEntry::FRESH | CCoinsCacheEntry::PEGIN);
|
|
BOOST_CHECK_EQUAL(coins.mapCoinsWritten[outpoint2].peginSpent, false);
|
|
BOOST_CHECK_EQUAL(coins.mapCoinsWritten[outpoint3].flags, CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH | CCoinsCacheEntry::PEGIN);
|
|
BOOST_CHECK_EQUAL(coins.mapCoinsWritten[outpoint3].peginSpent, true);
|
|
BOOST_CHECK_EQUAL(coins.mapCoinsWritten[outpoint4].flags, CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH | CCoinsCacheEntry::PEGIN);
|
|
BOOST_CHECK_EQUAL(coins.mapCoinsWritten[outpoint3].peginSpent, true);
|
|
|
|
// CCoinsViewCache should lose outpoint2 in BatchWrite logic
|
|
CCoinsViewTester coins2;
|
|
CCoinsViewCache coinsCache2(&coins2);
|
|
BOOST_CHECK(coinsCache2.BatchWrite(coins.mapCoinsWritten, uint256()));
|
|
coinsCache2.Flush();
|
|
BOOST_CHECK_EQUAL(coins2.mapCoinsWritten.size(), 3U);
|
|
BOOST_CHECK_EQUAL(coins2.mapCoinsWritten[outpoint].flags, CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH | CCoinsCacheEntry::PEGIN);
|
|
BOOST_CHECK_EQUAL(coins2.mapCoinsWritten[outpoint].peginSpent, true);
|
|
BOOST_CHECK_EQUAL(coins2.mapCoinsWritten[outpoint3].flags, CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH | CCoinsCacheEntry::PEGIN);
|
|
BOOST_CHECK_EQUAL(coins2.mapCoinsWritten[outpoint3].peginSpent, true);
|
|
BOOST_CHECK_EQUAL(coins2.mapCoinsWritten[outpoint4].flags, CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH | CCoinsCacheEntry::PEGIN);
|
|
BOOST_CHECK_EQUAL(coins2.mapCoinsWritten[outpoint4].peginSpent, true);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|