mirror of
https://github.com/kvazar-network/kevacoin.git
synced 2025-01-13 08:38:15 +00:00
Started implementing namespace association.
This commit is contained in:
parent
5e412845ec
commit
76c50bc850
@ -14,6 +14,7 @@ bool CCoinsView::GetNamespace(const valtype &nameSpace, CKevaData &data) const {
|
||||
bool CCoinsView::GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const { return false; }
|
||||
bool CCoinsView::GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const { return false; }
|
||||
CKevaIterator* CCoinsView::IterateKeys(const valtype& nameSpace) const { assert (false); }
|
||||
CKevaIterator* CCoinsView::IterateAssociatedNamespaces(const valtype& nameSpace) const { assert (false); }
|
||||
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) { return false; }
|
||||
CCoinsViewCursor *CCoinsView::Cursor() const { return nullptr; }
|
||||
bool CCoinsView::ValidateKevaDB() const {
|
||||
@ -43,6 +44,7 @@ bool CCoinsViewBacked::GetNamesForHeight(unsigned nHeight, std::set<valtype>& na
|
||||
return base->GetNamesForHeight(nHeight, names);
|
||||
}
|
||||
CKevaIterator* CCoinsViewBacked::IterateKeys(const valtype& nameSpace) const { return base->IterateKeys(nameSpace); }
|
||||
CKevaIterator* CCoinsViewBacked::IterateAssociatedNamespaces(const valtype& nameSpace) const { return base->IterateAssociatedNamespaces(nameSpace); }
|
||||
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
|
||||
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) {
|
||||
return base->BatchWrite(mapCoins, hashBlock, names);
|
||||
@ -198,6 +200,10 @@ CKevaIterator* CCoinsViewCache::IterateKeys(const valtype& nameSpace) const {
|
||||
return cacheNames.iterateKeys(base->IterateKeys(nameSpace));
|
||||
}
|
||||
|
||||
CKevaIterator* CCoinsViewCache::IterateAssociatedNamespaces(const valtype& nameSpace) const {
|
||||
return cacheNames.IterateAssociatedNamespaces(base->IterateAssociatedNamespaces(nameSpace));
|
||||
}
|
||||
|
||||
/* undo is set if the change is due to disconnecting blocks / going back in
|
||||
time. The ordinary case (!undo) means that we update the name normally,
|
||||
going forward in time. This is important for keeping track of the
|
||||
@ -210,6 +216,18 @@ void CCoinsViewCache::SetName(const valtype &nameSpace, const valtype &key, cons
|
||||
cacheNames.setNamespace(nameSpace, namespaceData);
|
||||
}
|
||||
cacheNames.set(nameSpace, key, data);
|
||||
|
||||
// Handle namespace association.
|
||||
valtype associdateNamespace;
|
||||
if (!cacheNames.getAssociateNamespaces(data.getValue(), associdateNamespace)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CKevaData dummyData;
|
||||
if (!GetNamespace(associdateNamespace, dummyData)) {
|
||||
return;
|
||||
}
|
||||
cacheNames.associateNamespaces(nameSpace, associdateNamespace);
|
||||
}
|
||||
|
||||
void CCoinsViewCache::DeleteName(const valtype &nameSpace, const valtype &key) {
|
||||
@ -218,6 +236,18 @@ void CCoinsViewCache::DeleteName(const valtype &nameSpace, const valtype &key) {
|
||||
assert(false);
|
||||
}
|
||||
cacheNames.remove(nameSpace, key);
|
||||
|
||||
// Handle namespace association.
|
||||
valtype associdateNamespace;
|
||||
if (!cacheNames.getAssociateNamespaces(oldData.getValue(), associdateNamespace)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CKevaData dummyData;
|
||||
if (!GetNamespace(associdateNamespace, dummyData)) {
|
||||
return;
|
||||
}
|
||||
cacheNames.disassociateNamespaces(nameSpace, associdateNamespace);
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn, const CKevaCache &names) {
|
||||
|
@ -176,6 +176,9 @@ public:
|
||||
// Get a key iterator.
|
||||
virtual CKevaIterator* IterateKeys(const valtype& nameSpace) const;
|
||||
|
||||
// Get the associated namespace iterator.
|
||||
virtual CKevaIterator* IterateAssociatedNamespaces(const valtype& nameSpace) const;
|
||||
|
||||
//! Do a bulk modification (multiple Coin changes + BestBlock change).
|
||||
//! The passed mapCoins can be modified.
|
||||
virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names);
|
||||
@ -210,6 +213,7 @@ public:
|
||||
bool GetName(const valtype& nameSpace, const valtype& key, CKevaData& data) const override;
|
||||
bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override;
|
||||
CKevaIterator* IterateKeys(const valtype& nameSpace) const override;
|
||||
virtual CKevaIterator* IterateAssociatedNamespaces(const valtype& nameSpace) const override;
|
||||
void SetBackend(CCoinsView &viewIn);
|
||||
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) override;
|
||||
CCoinsViewCursor *Cursor() const override;
|
||||
@ -252,6 +256,7 @@ public:
|
||||
bool GetName(const valtype &nameSpace, const valtype &key, CKevaData& data) const override;
|
||||
bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override;
|
||||
CKevaIterator* IterateKeys(const valtype& nameSpace) const override;
|
||||
CKevaIterator* IterateAssociatedNamespaces(const valtype& nameSpace) const override;
|
||||
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) override;
|
||||
CCoinsViewCursor* Cursor() const override {
|
||||
throw std::logic_error("CCoinsViewCache cursor iteration not supported.");
|
||||
|
@ -7,7 +7,7 @@
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <keva/common.h>
|
||||
|
||||
#include <base58.h>
|
||||
#include <script/keva.h>
|
||||
|
||||
|
||||
@ -55,6 +55,9 @@ private:
|
||||
/** Base iterator to combine with the cache. */
|
||||
CKevaIterator* base;
|
||||
|
||||
/** Whether or not it is for namespace association. */
|
||||
bool isAssociation;
|
||||
|
||||
/** Whether or not the base iterator has more entries. */
|
||||
bool baseHasMore;
|
||||
|
||||
@ -79,7 +82,7 @@ public:
|
||||
* @param c The cache object to use.
|
||||
* @param b The base iterator.
|
||||
*/
|
||||
CCacheKeyIterator(const CKevaCache& c, CKevaIterator* b);
|
||||
CCacheKeyIterator(const CKevaCache& c, CKevaIterator* b, bool association=false);
|
||||
|
||||
/* Destruct, this deletes also the base iterator. */
|
||||
~CCacheKeyIterator();
|
||||
@ -90,8 +93,8 @@ public:
|
||||
|
||||
};
|
||||
|
||||
CCacheKeyIterator::CCacheKeyIterator(const CKevaCache& c, CKevaIterator* b)
|
||||
: CKevaIterator(b->getNamespace()), cache(c), base(b)
|
||||
CCacheKeyIterator::CCacheKeyIterator(const CKevaCache& c, CKevaIterator* b, bool association)
|
||||
: CKevaIterator(b->getNamespace()), cache(c), base(b), isAssociation(association)
|
||||
{
|
||||
/* Add a seek-to-start to ensure that everything is consistent. This call
|
||||
may be superfluous if we seek to another position afterwards anyway,
|
||||
@ -116,7 +119,8 @@ CCacheKeyIterator::advanceBaseIterator()
|
||||
void
|
||||
CCacheKeyIterator::seek(const valtype& start)
|
||||
{
|
||||
cacheIter = cache.entries.lower_bound(std::make_tuple(nameSpace, start));
|
||||
auto &entries = isAssociation ? cache.associations : cache.entries;
|
||||
cacheIter = entries.lower_bound(std::make_tuple(nameSpace, start));
|
||||
base->seek(start);
|
||||
|
||||
baseHasMore = true;
|
||||
@ -127,15 +131,15 @@ bool CCacheKeyIterator::next(valtype& key, CKevaData& data)
|
||||
{
|
||||
/* Exit early if no more data is available in either the cache
|
||||
nor the base iterator. */
|
||||
|
||||
auto &entries = isAssociation ? cache.associations : cache.entries;
|
||||
bool endOfCacheNamespace = false;
|
||||
if (cacheIter != cache.entries.end()) {
|
||||
if (cacheIter != entries.end()) {
|
||||
valtype curNameSpace = std::get<0>(cacheIter->first);
|
||||
if (curNameSpace != nameSpace) {
|
||||
endOfCacheNamespace = true;
|
||||
}
|
||||
}
|
||||
bool noMoreCache = (cacheIter == cache.entries.end()) || endOfCacheNamespace;
|
||||
bool noMoreCache = (cacheIter == entries.end()) || endOfCacheNamespace;
|
||||
if (!baseHasMore && noMoreCache) {
|
||||
return false;
|
||||
}
|
||||
@ -144,7 +148,7 @@ bool CCacheKeyIterator::next(valtype& key, CKevaData& data)
|
||||
bool useBase = false;
|
||||
if (!baseHasMore) {
|
||||
useBase = false;
|
||||
} else if (cacheIter == cache.entries.end()) {
|
||||
} else if (cacheIter == entries.end()) {
|
||||
useBase = true;
|
||||
} else {
|
||||
if (baseKey == std::get<1>(cacheIter->first)) {
|
||||
@ -182,6 +186,8 @@ bool CCacheKeyIterator::next(valtype& key, CKevaData& data)
|
||||
/* ************************************************************************** */
|
||||
/* CKevaCache. */
|
||||
|
||||
const std::string CKevaCache::associatePrefix = "_A_";
|
||||
|
||||
bool
|
||||
CKevaCache::get(const valtype& nameSpace, const valtype& key, CKevaData& data) const
|
||||
{
|
||||
@ -233,12 +239,55 @@ CKevaCache::remove(const valtype& nameSpace, const valtype& key)
|
||||
deleted.insert(name);
|
||||
}
|
||||
|
||||
/* If the value is an associated namespace (_A_N...), return the namespace */
|
||||
bool
|
||||
CKevaCache::getAssociateNamespaces(const valtype& value, valtype& nameSpace)
|
||||
{
|
||||
std::string valueStr = ValtypeToString(value);
|
||||
if (valueStr.rfind(associatePrefix, 0) != 0) {
|
||||
return false;
|
||||
}
|
||||
valueStr.erase(0, associatePrefix.length());
|
||||
if (!DecodeKevaNamespace(valueStr, Params(), nameSpace)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CKevaCache::associateNamespaces(const valtype& nameSpace, const valtype& nameSpaceOther)
|
||||
{
|
||||
auto name = std::make_tuple(nameSpaceOther, nameSpace);
|
||||
const NamespaceMap::iterator ei = associations.find(name);
|
||||
CKevaData data;
|
||||
if (ei != entries.end())
|
||||
ei->second = data;
|
||||
else
|
||||
associations.insert(std::make_pair(name, data));
|
||||
}
|
||||
|
||||
void
|
||||
CKevaCache::disassociateNamespaces(const valtype& nameSpace, const valtype& nameSpaceOther)
|
||||
{
|
||||
auto name = std::make_tuple(nameSpaceOther, nameSpace);
|
||||
const NamespaceMap::iterator ei = entries.find(name);
|
||||
if (ei != entries.end()) {
|
||||
associations.erase(ei);
|
||||
}
|
||||
}
|
||||
|
||||
CKevaIterator*
|
||||
CKevaCache::iterateKeys(CKevaIterator* base) const
|
||||
{
|
||||
return new CCacheKeyIterator(*this, base);
|
||||
}
|
||||
|
||||
CKevaIterator*
|
||||
CKevaCache::IterateAssociatedNamespaces(CKevaIterator* base) const
|
||||
{
|
||||
return new CCacheKeyIterator(*this, base, true);
|
||||
}
|
||||
|
||||
void
|
||||
CKevaCache::updateNamesForHeight (unsigned nHeight,
|
||||
std::set<valtype>& names) const
|
||||
@ -253,6 +302,10 @@ void CKevaCache::apply(const CKevaCache& cache)
|
||||
set(std::get<0>(i->first), std::get<1>(i->first), i->second);
|
||||
}
|
||||
|
||||
for (NamespaceMap::const_iterator i = associations.begin(); i != associations.end(); ++i) {
|
||||
set(std::get<0>(i->first), std::get<1>(i->first), i->second);
|
||||
}
|
||||
|
||||
for (std::set<NamespaceKeyType>::const_iterator i = cache.deleted.begin(); i != cache.deleted.end(); ++i) {
|
||||
remove(std::get<0>(*i), std::get<1>(*i));
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
// Copyright (c) 2018
|
||||
// Copyright (c) 2018-2020 The Kevacoin Core Developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
@ -298,6 +298,8 @@ class CKevaCache
|
||||
|
||||
private:
|
||||
|
||||
const static std::string associatePrefix;
|
||||
|
||||
/**
|
||||
* Special comparator class for names that compares by length first.
|
||||
* This is used to sort the cache entry map in the same way as the
|
||||
@ -336,6 +338,8 @@ public:
|
||||
|
||||
typedef std::tuple<valtype, valtype> NamespaceKeyType;
|
||||
|
||||
typedef std::map<std::tuple<valtype, valtype>, CKevaData, KeyComparator> NamespaceMap;
|
||||
|
||||
private:
|
||||
|
||||
/** New or updated names. */
|
||||
@ -344,6 +348,9 @@ private:
|
||||
/** Deleted names. */
|
||||
std::set<NamespaceKeyType> deleted;
|
||||
|
||||
/** Namespace association. */
|
||||
NamespaceMap associations;
|
||||
|
||||
friend class CCacheKeyIterator;
|
||||
|
||||
public:
|
||||
@ -353,6 +360,7 @@ public:
|
||||
{
|
||||
entries.clear();
|
||||
deleted.clear();
|
||||
associations.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -364,7 +372,7 @@ public:
|
||||
inline bool
|
||||
empty() const
|
||||
{
|
||||
if (entries.empty() && deleted.empty()) {
|
||||
if (entries.empty() && deleted.empty() && associations.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -394,11 +402,23 @@ public:
|
||||
/* Delete a name. If it is in the "entries" set also, remove it there. */
|
||||
void remove(const valtype& nameSpace, const valtype& key);
|
||||
|
||||
/* If the value is an associated namespace (_A_N...), return the namespace */
|
||||
bool getAssociateNamespaces(const valtype& value, valtype& nameSpace);
|
||||
|
||||
/* Associate nameSpace with nameSpaceOther */
|
||||
void associateNamespaces(const valtype& nameSpace, const valtype& nameSpaceOther);
|
||||
|
||||
/* Disassociate nameSpace with nameSpaceOther */
|
||||
void disassociateNamespaces(const valtype& nameSpace, const valtype& nameSpaceOther);
|
||||
|
||||
/* Return a name iterator that combines a "base" iterator with the changes
|
||||
made to it according to the cache. The base iterator is taken
|
||||
ownership of. */
|
||||
CKevaIterator* iterateKeys(CKevaIterator* base) const;
|
||||
|
||||
// Get the associated namespace iterator.
|
||||
CKevaIterator* IterateAssociatedNamespaces(CKevaIterator* base) const;
|
||||
|
||||
/* Query the cached changes to the expire index. In particular,
|
||||
for a given height and a given set of names that were indexed to
|
||||
this update height, apply possible changes to the set that
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
// Copyright (c) 2018 the Kevacoin Core Developers
|
||||
// Copyright (c) 2018-2020 the Kevacoin Core Developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
25
src/txdb.cpp
25
src/txdb.cpp
@ -26,6 +26,7 @@ static const char DB_TXINDEX = 't';
|
||||
static const char DB_BLOCK_INDEX = 'b';
|
||||
|
||||
static const char DB_NAME = 'n';
|
||||
static const char DB_NS_ASSOC = 'a';
|
||||
|
||||
static const char DB_BEST_BLOCK = 'B';
|
||||
static const char DB_HEAD_BLOCKS = 'H';
|
||||
@ -92,6 +93,9 @@ private:
|
||||
/* The backing LevelDB iterator. */
|
||||
CDBIterator* iter;
|
||||
|
||||
/* This iterator is for namespace association search. */
|
||||
bool isAssociation;
|
||||
|
||||
public:
|
||||
|
||||
~CDbKeyIterator();
|
||||
@ -100,7 +104,7 @@ public:
|
||||
* Construct a new name iterator for the database.
|
||||
* @param db The database to create the iterator for.
|
||||
*/
|
||||
CDbKeyIterator(const CDBWrapper& db, const valtype& nameSpace);
|
||||
CDbKeyIterator(const CDBWrapper& db, const valtype& nameSpace, bool association=false);
|
||||
|
||||
/* Implement iterator methods. */
|
||||
void seek(const valtype& start);
|
||||
@ -112,22 +116,24 @@ CDbKeyIterator::~CDbKeyIterator() {
|
||||
delete iter;
|
||||
}
|
||||
|
||||
CDbKeyIterator::CDbKeyIterator(const CDBWrapper& db, const valtype& ns)
|
||||
: CKevaIterator(ns), iter(const_cast<CDBWrapper*>(&db)->NewIterator())
|
||||
CDbKeyIterator::CDbKeyIterator(const CDBWrapper& db, const valtype& ns, bool association)
|
||||
: CKevaIterator(ns), iter(const_cast<CDBWrapper*>(&db)->NewIterator()), isAssociation(association)
|
||||
{
|
||||
seek(valtype());
|
||||
}
|
||||
|
||||
void CDbKeyIterator::seek(const valtype& start) {
|
||||
iter->Seek(std::make_pair(DB_NAME, std::make_pair(nameSpace, start)));
|
||||
auto &prefix = isAssociation ? DB_NS_ASSOC : DB_NAME;
|
||||
iter->Seek(std::make_pair(prefix, std::make_pair(nameSpace, start)));
|
||||
}
|
||||
|
||||
bool CDbKeyIterator::next(valtype& key, CKevaData& data) {
|
||||
if (!iter->Valid())
|
||||
return false;
|
||||
|
||||
auto &prefix = isAssociation ? DB_NS_ASSOC : DB_NAME;
|
||||
std::pair<char, std::pair<valtype, valtype>> curKey;
|
||||
if (!iter->GetKey(curKey) || curKey.first != DB_NAME)
|
||||
if (!iter->GetKey(curKey) || curKey.first != prefix)
|
||||
return false;
|
||||
|
||||
valtype curNameSpace = std::get<0>(curKey.second);
|
||||
@ -148,6 +154,10 @@ CKevaIterator* CCoinsViewDB::IterateKeys(const valtype& nameSpace) const {
|
||||
return new CDbKeyIterator(db, nameSpace);
|
||||
}
|
||||
|
||||
CKevaIterator* CCoinsViewDB::IterateAssociatedNamespaces(const valtype& nameSpace) const {
|
||||
return new CDbKeyIterator(db, nameSpace, true);
|
||||
}
|
||||
|
||||
bool CCoinsViewDB::GetNamespace(const valtype &nameSpace, CKevaData &data) const {
|
||||
return db.Read(std::make_pair(DB_NAME, std::make_pair(nameSpace, CKevaScript::KEVA_DISPLAY_NAME_KEY)), data);
|
||||
}
|
||||
@ -324,6 +334,11 @@ void CKevaCache::writeBatch (CDBBatch& batch) const
|
||||
batch.Write(std::make_pair(DB_NAME, name), i->second);
|
||||
}
|
||||
|
||||
for (NamespaceMap::const_iterator i = associations.begin(); i != associations.end(); ++i) {
|
||||
std::pair<valtype, valtype> name = std::make_pair(std::get<0>(i->first), std::get<1>(i->first));
|
||||
batch.Write(std::make_pair(DB_NS_ASSOC, name), i->second);
|
||||
}
|
||||
|
||||
for (std::set<NamespaceKeyType>::const_iterator i = deleted.begin(); i != deleted.end(); ++i) {
|
||||
std::pair<valtype, valtype> name = std::make_pair(std::get<0>(*i), std::get<1>(*i));
|
||||
batch.Erase(std::make_pair(DB_NAME, name));
|
||||
|
@ -80,6 +80,7 @@ public:
|
||||
bool GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const override;
|
||||
bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override;
|
||||
CKevaIterator* IterateKeys(const valtype& nameSpace) const override;
|
||||
CKevaIterator* IterateAssociatedNamespaces(const valtype& nameSpace) const override;
|
||||
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) override;
|
||||
CCoinsViewCursor *Cursor() const override;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user