Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Zerocoin][Validation] Cache checksum heights #938

Merged
merged 1 commit into from
May 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,6 @@ add_executable(veil
src/versionbits.h
src/walletinitinterface.h
src/warnings.cpp
src/warnings.h src/veil/zerocoin/spendreceipt.h src/veil/ringct/temprecipient.h src/veil/ringct/temprecipient.cpp src/veil/zerocoin/spendreceipt.cpp src/veil/ringct/outputrecord.cpp src/veil/ringct/outputrecord.h src/wallet/walletbalances.h src/veil/ringct/transactionrecord.h src/veil/zerocoin/mintmeta.h src/test/zerocoin_zkp_tests.cpp src/veil/zerocoin/lrucache.h src/veil/zerocoin/lrucache.cpp src/veil/zerocoin/precompute.h src/veil/zerocoin/precompute.cpp src/libzerocoin/PubcoinSignature.h src/libzerocoin/PubcoinSignature.cpp src/test/zerocoin_pubcoinsig_tests.cpp src/veil/invalid_list.h src/veil/invalid_list.cpp)
src/warnings.h src/veil/lru_cache.h src/veil/zerocoin/spendreceipt.h src/veil/ringct/temprecipient.h src/veil/ringct/temprecipient.cpp src/veil/zerocoin/spendreceipt.cpp src/veil/ringct/outputrecord.cpp src/veil/ringct/outputrecord.h src/wallet/walletbalances.h src/veil/ringct/transactionrecord.h src/veil/zerocoin/mintmeta.h src/test/zerocoin_zkp_tests.cpp src/veil/zerocoin/lrucache.h src/veil/zerocoin/lrucache.cpp src/veil/zerocoin/precompute.h src/veil/zerocoin/precompute.cpp src/libzerocoin/PubcoinSignature.h src/libzerocoin/PubcoinSignature.cpp src/test/zerocoin_pubcoinsig_tests.cpp src/veil/invalid_list.h src/veil/invalid_list.cpp)

qt5_use_modules(veil Core Widgets Gui)
1 change: 1 addition & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ BITCOIN_CORE_H = \
veil/dandelioninventory.h \
veil/invalid.h \
veil/invalid_list.h \
veil/lru_cache.h \
veil/proofoffullnode/proofoffullnode.h \
veil/proofofstake/kernel.h \
veil/proofofstake/blockvalidation.h \
Expand Down
82 changes: 82 additions & 0 deletions src/veil/lru_cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright (c) 2021 Veil developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef VEIL_LRU_CACHE_H
#define VEIL_LRU_CACHE_H

#include "sync.h"

#include <list>
#include <unordered_map>
#include <utility>

namespace veil {

/**
* The SimpleLRUCache is a fixed-size key-value map that automatically
* evicts the least-recently-used item when a new item is added while the cache is full.
*
* This is a naive, non-optimized implementation of an LRU cache that uses an
* internal mutex to prevent concurrent access.
*
* K must be a hashable type, but you can define your own Hash for it, or equivalently implement
* std::hash<K> for your type. It must be a default-constructible struct or class
* defining std::size_t operator()(const K&) const, e.g.
*
* namespace std {
* template<> struct hash<MyType>
* {
* std::size_t operator()(const MyType& m) const {
* return std::hash<std::string>()(m.ImportantString()) ^ m.ImportantInteger;
* }
* };
* }
* SimpleLRUCache<MyType, MyValue> cache(100);
*/
template<typename K, typename V = K, class Hash = std::hash<K>>
class SimpleLRUCache
{

private:
std::list<K> items;
std::unordered_map<K, std::pair<V, typename std::list<K>::iterator>, Hash> keyValuesMap;
int csize;
CCriticalSection cs_mycache;

public:
SimpleLRUCache(int s) : csize(s < 1 ? 10 : s), keyValuesMap(csize) {}

void set(const K key, const V value) {
LOCK(cs_mycache);
auto pos = keyValuesMap.find(key);
if (pos == keyValuesMap.end()) {
items.push_front(key);
keyValuesMap[key] = { value, items.begin() };
if (keyValuesMap.size() > csize) {
keyValuesMap.erase(items.back());
items.pop_back();
}
} else {
items.erase(pos->second.second);
items.push_front(key);
keyValuesMap[key] = { value, items.begin() };
}
}

bool get(const K key, V &value) {
LOCK(cs_mycache);
auto pos = keyValuesMap.find(key);
if (pos == keyValuesMap.end())
return false;
items.erase(pos->second.second);
items.push_front(key);
keyValuesMap[key] = { pos->second.first, items.begin() };
value = pos->second.first;
return true;
}
};

} // namespace veil

#endif // VEIL_LRU_CACHE_H
40 changes: 35 additions & 5 deletions src/veil/zerocoin/accumulators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,27 @@
#include "veil/zerocoin/zchain.h"
#include "primitives/zerocoin.h"
#include "shutdown.h"
#include "veil/lru_cache.h"

#include <utility>

using namespace libzerocoin;

// This is only used to store pair<hash, denom> in a map, so the cheap hash is fine.
struct ChecksumHeightHash
{
std::size_t operator()(const std::pair<uint256, CoinDenomination> p) const
{
// convert CoinDenomination to int to use std::hash<int> (for mac compatibility)
return p.first.GetCheapHash() ^ std::hash<int>()(p.second);
}
};

std::map<uint256, CBigNum> mapAccumulatorValues;
std::list<uint256> listAccCheckpointsNoDB;
// This needs to be able to contain a reasonable number of distinct (accumulator hash, denom) pairs
// that could occur in a block or it may not be effective.
static veil::SimpleLRUCache<std::pair<uint256, CoinDenomination>, int, ChecksumHeightHash> cacheChecksumHeights(1024);

uint256 GetChecksum(const CBigNum &bnValue)
{
Expand All @@ -28,20 +44,34 @@ uint256 GetChecksum(const CBigNum &bnValue)
// Find the first occurrence of a certain accumulator checksum. Return 0 if not found.
int GetChecksumHeight(uint256 hashChecksum, CoinDenomination denomination)
{
int height = 0;
std::pair<uint256, CoinDenomination> p(hashChecksum, denomination);
if (cacheChecksumHeights.get(p, height) && height > 0) {
// Verify that the block in question is in the main chain still
CBlockIndex* pindex = chainActive[height];
if (pindex && pindex->GetAccumulatorHash(denomination) == hashChecksum)
return height;

// fall through to search and re-insert if possible
}
CBlockIndex* pindex = chainActive[0];
if (!pindex)
return 0;

//Search through blocks to find the checksum
while (pindex) {
height = pindex->nHeight;
if (pindex->GetAccumulatorHash(denomination) == hashChecksum)
return pindex->nHeight;
{
cacheChecksumHeights.set(p, height);
return height;
}

//Skip forward in groups of 10 blocks since checkpoints only change every 10 blocks
if (pindex->nHeight % 10 == 0) {
if (pindex->nHeight + 10 > chainActive.Height())
return 0;
pindex = chainActive[pindex->nHeight + 10];
if (height % 10 == 0) {
if (height + 10 > chainActive.Height())
break;
pindex = chainActive[height + 10];
continue;
}

Expand Down