Browse Source

Implemented keva_filter.

cn
Jianping Wu 6 years ago
parent
commit
9a025be151
  1. 8
      src/coins.cpp
  2. 8
      src/coins.h
  3. 126
      src/keva/common.cpp
  4. 42
      src/keva/common.h
  5. 23
      src/keva/main.cpp
  6. 2
      src/keva/main.h
  7. 2
      src/script/keva.h
  8. 17
      src/test/keva_tests.cpp
  9. 31
      src/txdb.cpp
  10. 2
      src/txdb.h
  11. 247
      src/wallet/rpckeva.cpp
  12. 4
      src/wallet/rpcwallet.cpp

8
src/coins.cpp

@ -13,7 +13,7 @@ std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint
bool CCoinsView::GetNamespace(const valtype &nameSpace, CKevaData &data) const { return false; } bool CCoinsView::GetNamespace(const valtype &nameSpace, CKevaData &data) const { return false; }
bool CCoinsView::GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const { return false; } 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; } bool CCoinsView::GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const { return false; }
CNameIterator* CCoinsView::IterateNames() const { assert (false); } CKevaIterator* CCoinsView::IterateKeys(const valtype& nameSpace) const { assert (false); }
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) { return false; } bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) { return false; }
CCoinsViewCursor *CCoinsView::Cursor() const { return nullptr; } CCoinsViewCursor *CCoinsView::Cursor() const { return nullptr; }
bool CCoinsView::ValidateNameDB() const { return false; } bool CCoinsView::ValidateNameDB() const { return false; }
@ -38,7 +38,7 @@ bool CCoinsViewBacked::GetName(const valtype &nameSpace, const valtype &key, CKe
bool CCoinsViewBacked::GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const { bool CCoinsViewBacked::GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const {
return base->GetNamesForHeight(nHeight, names); return base->GetNamesForHeight(nHeight, names);
} }
CNameIterator* CCoinsViewBacked::IterateNames() const { return base->IterateNames(); } CKevaIterator* CCoinsViewBacked::IterateKeys(const valtype& nameSpace) const { return base->IterateKeys(nameSpace); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) { bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) {
return base->BatchWrite(mapCoins, hashBlock, names); return base->BatchWrite(mapCoins, hashBlock, names);
@ -190,8 +190,8 @@ bool CCoinsViewCache::GetNamesForHeight(unsigned nHeight, std::set<valtype>& nam
return true; return true;
} }
CNameIterator* CCoinsViewCache::IterateNames() const { CKevaIterator* CCoinsViewCache::IterateKeys(const valtype& nameSpace) const {
return cacheNames.iterateNames(base->IterateNames()); return cacheNames.iterateKeys(base->IterateKeys(nameSpace));
} }
/* undo is set if the change is due to disconnecting blocks / going back in /* undo is set if the change is due to disconnecting blocks / going back in

8
src/coins.h

@ -173,8 +173,8 @@ public:
// Query for names that were updated at the given height // Query for names that were updated at the given height
virtual bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const; virtual bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const;
// Get a name iterator. // Get a key iterator.
virtual CNameIterator* IterateNames() const; virtual CKevaIterator* IterateKeys(const valtype& nameSpace) const;
//! Do a bulk modification (multiple Coin changes + BestBlock change). //! Do a bulk modification (multiple Coin changes + BestBlock change).
//! The passed mapCoins can be modified. //! The passed mapCoins can be modified.
@ -209,7 +209,7 @@ public:
bool GetNamespace(const valtype& nameSpace, CKevaData& data) const override; bool GetNamespace(const valtype& nameSpace, CKevaData& data) const override;
bool GetName(const valtype& nameSpace, const valtype& key, CKevaData& data) const override; bool GetName(const valtype& nameSpace, const valtype& key, CKevaData& data) const override;
bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override; bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override;
CNameIterator* IterateNames() const override; CKevaIterator* IterateKeys(const valtype& nameSpace) const override;
void SetBackend(CCoinsView &viewIn); void SetBackend(CCoinsView &viewIn);
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) override; bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) override;
CCoinsViewCursor *Cursor() const override; CCoinsViewCursor *Cursor() const override;
@ -251,7 +251,7 @@ public:
bool GetNamespace(const valtype &nameSpace, CKevaData& data) const override; bool GetNamespace(const valtype &nameSpace, CKevaData& data) const override;
bool GetName(const valtype &nameSpace, const valtype &key, CKevaData& data) const override; bool GetName(const valtype &nameSpace, const valtype &key, CKevaData& data) const override;
bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override; bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override;
CNameIterator* IterateNames() const override; CKevaIterator* IterateKeys(const valtype& nameSpace) const override;
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) override; bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) override;
CCoinsViewCursor* Cursor() const override { CCoinsViewCursor* Cursor() const override {
throw std::logic_error("CCoinsViewCache cursor iteration not supported."); throw std::logic_error("CCoinsViewCache cursor iteration not supported.");

126
src/keva/common.cpp

@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
// Copyright (c) 2018 Jianping Wu // Copyright (c) 2018 the Kevacoin Core Developers
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -10,9 +10,6 @@
#include <script/keva.h> #include <script/keva.h>
typedef std::vector<unsigned char> valtype;
bool fNameHistory = false;
/* ************************************************************************** */ /* ************************************************************************** */
/* CKevaData. */ /* CKevaData. */
@ -36,9 +33,9 @@ CKevaData::fromScript (unsigned h, const COutPoint& out,
} }
/* ************************************************************************** */ /* ************************************************************************** */
/* CNameIterator. */ /* CKevaIterator. */
CNameIterator::~CNameIterator () CKevaIterator::~CKevaIterator ()
{ {
/* Nothing to be done here. This may be overwritten by /* Nothing to be done here. This may be overwritten by
subclasses if they need a destructor. */ subclasses if they need a destructor. */
@ -47,8 +44,7 @@ CNameIterator::~CNameIterator ()
/* ************************************************************************** */ /* ************************************************************************** */
/* CKevaCacheNameIterator. */ /* CKevaCacheNameIterator. */
// JWU TODO: this doesn't work at all!!!! class CCacheKeyIterator : public CKevaIterator
class CCacheNameIterator : public CNameIterator
{ {
private: private:
@ -57,12 +53,14 @@ private:
const CKevaCache& cache; const CKevaCache& cache;
/** Base iterator to combine with the cache. */ /** Base iterator to combine with the cache. */
CNameIterator* base; CKevaIterator* base;
/** Whether or not the base iterator has more entries. */ /** Whether or not the base iterator has more entries. */
bool baseHasMore; bool baseHasMore;
/** "Next" name of the base iterator. */
valtype baseName; /** "Next" key of the base iterator. */
valtype baseKey;
/** "Next" data of the base iterator. */ /** "Next" data of the base iterator. */
CKevaData baseData; CKevaData baseData;
@ -72,7 +70,7 @@ private:
/* Call the base iterator's next() routine to fill in the internal /* Call the base iterator's next() routine to fill in the internal
"cache" for the next entry. This already skips entries that are "cache" for the next entry. This already skips entries that are
marked as deleted in the cache. */ marked as deleted in the cache. */
void advanceBaseIterator (); void advanceBaseIterator();
public: public:
@ -81,104 +79,92 @@ public:
* @param c The cache object to use. * @param c The cache object to use.
* @param b The base iterator. * @param b The base iterator.
*/ */
CCacheNameIterator (const CKevaCache& c, CNameIterator* b); CCacheKeyIterator(const CKevaCache& c, CKevaIterator* b);
/* Destruct, this deletes also the base iterator. */ /* Destruct, this deletes also the base iterator. */
~CCacheNameIterator (); ~CCacheKeyIterator();
/* Implement iterator methods. */ /* Implement iterator methods. */
void seek (const valtype& name); void seek(const valtype& key);
bool next (valtype& name, CKevaData& data); bool next(valtype& key, CKevaData& data);
}; };
CCacheNameIterator::CCacheNameIterator (const CKevaCache& c, CNameIterator* b) CCacheKeyIterator::CCacheKeyIterator(const CKevaCache& c, CKevaIterator* b)
: cache(c), base(b) : cache(c), base(b), CKevaIterator(b->getNamespace())
{ {
/* Add a seek-to-start to ensure that everything is consistent. This call /* Add a seek-to-start to ensure that everything is consistent. This call
may be superfluous if we seek to another position afterwards anyway, may be superfluous if we seek to another position afterwards anyway,
but it should also not hurt too much. */ but it should also not hurt too much. */
seek (valtype ()); seek(valtype());
} }
CCacheNameIterator::~CCacheNameIterator () CCacheKeyIterator::~CCacheKeyIterator()
{ {
delete base; delete base;
} }
void void
CCacheNameIterator::advanceBaseIterator () CCacheKeyIterator::advanceBaseIterator()
{ {
assert (baseHasMore); assert (baseHasMore);
do do {
baseHasMore = base->next (baseName, baseData); baseHasMore = base->next(baseKey, baseData);
while (baseHasMore && cache.isDeleted(baseName, baseName)); } while (baseHasMore && cache.isDeleted(nameSpace, baseKey));
} }
void void
CCacheNameIterator::seek(const valtype& start) CCacheKeyIterator::seek(const valtype& start)
{ {
// JWU TODO: fix this! cacheIter = cache.entries.lower_bound(std::make_tuple(nameSpace, start));
#if 0
cacheIter = cache.entries.lower_bound(start);
#endif
base->seek(start); base->seek(start);
baseHasMore = true; baseHasMore = true;
advanceBaseIterator(); advanceBaseIterator();
} }
bool CCacheNameIterator::next (valtype& name, CKevaData& data) bool CCacheKeyIterator::next(valtype& key, CKevaData& data)
{ {
#if 0
// JWU TODO: fix this!
/* Exit early if no more data is available in either the cache /* Exit early if no more data is available in either the cache
nor the base iterator. */ nor the base iterator. */
if (!baseHasMore && cacheIter == cache.entries.end ()) if (!baseHasMore && cacheIter == cache.entries.end())
return false; return false;
/* Determine which source to use for the next. */ /* Determine which source to use for the next. */
bool useBase; bool useBase;
if (!baseHasMore) if (!baseHasMore)
useBase = false; useBase = false;
else if (cacheIter == cache.entries.end ()) else if (cacheIter == cache.entries.end())
useBase = true; useBase = true;
else else {
{ /* A special case is when both iterators are equal. In this case,
/* A special case is when both iterators are equal. In this case, we want to use the cached version. We also have to advance
we want to use the cached version. We also have to advance the base iterator. */
the base iterator. */ if (baseKey == std::get<1>(cacheIter->first))
if (baseName == cacheIter->first) advanceBaseIterator ();
advanceBaseIterator ();
/* Due to advancing the base iterator above, it may happen that
/* Due to advancing the base iterator above, it may happen that no more base entries are present. Handle this gracefully. */
no more base entries are present. Handle this gracefully. */ if (!baseHasMore)
if (!baseHasMore) useBase = false;
useBase = false; else {
else assert(baseKey != std::get<1>(cacheIter->first));
{
assert (baseName != cacheIter->first); CKevaCache::KeyComparator cmp;
useBase = cmp(std::make_tuple(nameSpace, baseKey), cacheIter->first);
CKevaCache::NameComparator cmp;
useBase = cmp (baseName, cacheIter->first);
}
} }
}
/* Use the correct source now and advance it. */ /* Use the correct source now and advance it. */
if (useBase) if (useBase) {
{ key = baseKey;
name = baseName; data = baseData;
data = baseData; advanceBaseIterator();
advanceBaseIterator (); } else {
} key = std::get<1>(cacheIter->first);
else data = cacheIter->second;
{ ++cacheIter;
name = cacheIter->first; }
data = cacheIter->second;
++cacheIter;
}
#endif
return true; return true;
} }
@ -235,10 +221,10 @@ CKevaCache::remove(const valtype& nameSpace, const valtype& key)
deleted.insert(name); deleted.insert(name);
} }
CNameIterator* CKevaIterator*
CKevaCache::iterateNames(CNameIterator* base) const CKevaCache::iterateKeys(CKevaIterator* base) const
{ {
return new CCacheNameIterator (*this, base); return new CCacheKeyIterator(*this, base);
} }
void void

42
src/keva/common.h

@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
// Copyright (c) 2018 Jianping Wu // Copyright (c) 2018
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -246,37 +246,47 @@ public:
}; };
/* ************************************************************************** */ /* ************************************************************************** */
/* CNameIterator. */ /* CKevaIterator. */
/** /**
* Interface for iterators over the name database. * Interface for iterators over the name database.
*/ */
class CNameIterator class CKevaIterator
{ {
protected:
const valtype& nameSpace;
public: public:
CKevaIterator(const valtype& ns) :nameSpace(ns)
{}
// Virtual destructor in case subclasses need them. // Virtual destructor in case subclasses need them.
virtual ~CNameIterator (); virtual ~CKevaIterator();
const valtype& getNamespace() {
return nameSpace;
}
/** /**
* Seek to a given lower bound. * Seek to a given lower bound.
* @param start The name to seek to. * @param start The key to seek to.
*/ */
virtual void seek (const valtype& name) = 0; virtual void seek(const valtype& start) = 0;
/** /**
* Get the next name. Returns false if no more names are available. * Get the next key. Returns false if no more keys are available.
* @param name Put the name here. * @param nameSpace Put the namespace here.
* @param data Put the name's data here. * @param key Put the key here.
* @return True if successful, false if no more names. * @param data Put the key's data here.
* @return True if successful, false if no more keys.
*/ */
virtual bool next (valtype& name, CKevaData& data) = 0; virtual bool next(valtype& key, CKevaData& data) = 0;
}; };
/* ************************************************************************** */ /* ************************************************************************** */
/* CNameCache. */ /* CKevaCache. */
/** /**
* Cache / record of updates to the name database. In addition to * Cache / record of updates to the name database. In addition to
@ -293,7 +303,7 @@ private:
* This is used to sort the cache entry map in the same way as the * This is used to sort the cache entry map in the same way as the
* database is sorted. * database is sorted.
*/ */
class NameComparator class KeyComparator
{ {
public: public:
inline bool operator() (const std::tuple<valtype, valtype> a, inline bool operator() (const std::tuple<valtype, valtype> a,
@ -314,7 +324,7 @@ public:
* Type of name entry map. This is public because it is also used * Type of name entry map. This is public because it is also used
* by the unit tests. * by the unit tests.
*/ */
typedef std::map<std::tuple<valtype, valtype>, CKevaData, NameComparator> EntryMap; typedef std::map<std::tuple<valtype, valtype>, CKevaData, KeyComparator> EntryMap;
typedef std::tuple<valtype, valtype> NamespaceKeyType; typedef std::tuple<valtype, valtype> NamespaceKeyType;
@ -326,7 +336,7 @@ private:
/** Deleted names. */ /** Deleted names. */
std::set<NamespaceKeyType> deleted; std::set<NamespaceKeyType> deleted;
friend class CCacheNameIterator; friend class CCacheKeyIterator;
public: public:
@ -379,7 +389,7 @@ public:
/* Return a name iterator that combines a "base" iterator with the changes /* Return a name iterator that combines a "base" iterator with the changes
made to it according to the cache. The base iterator is taken made to it according to the cache. The base iterator is taken
ownership of. */ ownership of. */
CNameIterator* iterateNames (CNameIterator* base) const; CKevaIterator* iterateKeys(CKevaIterator* base) const;
/* Query the cached changes to the expire index. In particular, /* Query the cached changes to the expire index. In particular,
for a given height and a given set of names that were indexed to for a given height and a given set of names that were indexed to

23
src/keva/main.cpp

@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
// Copyright (c) 2018 Jianping Wu // Copyright (c) 2018 the Kevacoin Core Developers
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -133,27 +133,6 @@ void CKevaMemPool::remove(const CTxMemPoolEntry& entry)
void void
CKevaMemPool::removeConflicts(const CTransaction& tx) CKevaMemPool::removeConflicts(const CTransaction& tx)
{ {
// JWU TODO: is this required at all?
#if 0
AssertLockHeld (pool.cs);
if (!tx.IsKevacoin ())
return;
for (const auto& txout : tx.vout) {
const CKevaScript nameOp(txout.scriptPubKey);
if (nameOp.isKevaOp() && nameOp.getKevaOp() == OP_KEVA_PUT) {
const valtype& nameSpace = nameOp.getOpNamespace();
const NamespaceTxMap::const_iterator mit = mapNamespaceRegs.find(nameSpace);
if (mit != mapNamespaceRegs.end()) {
const CTxMemPool::txiter mit2 = pool.mapTx.find(mit->second);
assert(mit2 != pool.mapTx.end());
pool.removeRecursive (mit2->GetTx(),
MemPoolRemovalReason::KEVA_CONFLICT);
}
}
}
#endif
} }
bool CKevaMemPool::validateNamespace(const CTransaction& tx, const valtype& nameSpace) const bool CKevaMemPool::validateNamespace(const CTransaction& tx, const valtype& nameSpace) const

2
src/keva/main.h

@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
// Copyright (c) 2018 Jianping Wu // Copyright (c) 2018 the Kevacoin Core Developers
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.

2
src/script/keva.h

@ -1,4 +1,4 @@
// Copyright (c) 2018 Jianping Wu // Copyright (c) 2018 the Kevacoin Core Developers
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.

17
src/test/keva_tests.cpp

@ -180,7 +180,7 @@ private:
/** /**
* "Fake" name iterator returned. * "Fake" name iterator returned.
*/ */
class Iterator : public CNameIterator class Iterator : public CKevaIterator
{ {
public: public:
@ -198,8 +198,8 @@ private:
public: public:
CNameIterator* CKevaIterator*
IterateNames() const IterateKeys() const
{ {
return new Iterator(); return new Iterator();
} }
@ -271,7 +271,7 @@ private:
* @param iter The iterator to use. * @param iter The iterator to use.
* @return The resulting entry list. * @return The resulting entry list.
*/ */
static EntryList getNamesFromIterator (CNameIterator& iter); static EntryList getNamesFromIterator (CKevaIterator& iter);
public: public:
@ -340,7 +340,7 @@ NameIterationTester::verify (const CCoinsView& view) const
/* Seek the iterator to the end first for "maximum confusion". This ensures /* Seek the iterator to the end first for "maximum confusion". This ensures
that seeking to valtype() works. */ that seeking to valtype() works. */
std::unique_ptr<CNameIterator> iter(view.IterateNames()); std::unique_ptr<CKevaIterator> iter(view.IterateKeys());
const valtype end = ValtypeFromString ("zzzzzzzzzzzzzzzz"); const valtype end = ValtypeFromString ("zzzzzzzzzzzzzzzz");
{ {
valtype name; valtype name;
@ -392,14 +392,14 @@ NameIterationTester::EntryList
NameIterationTester::getNamesFromView (const CCoinsView& view, NameIterationTester::getNamesFromView (const CCoinsView& view,
const valtype& start) const valtype& start)
{ {
std::unique_ptr<CNameIterator> iter(view.IterateNames()); std::unique_ptr<CKevaIterator> iter(view.IterateKeys());
iter->seek (start); iter->seek (start);
return getNamesFromIterator (*iter); return getNamesFromIterator (*iter);
} }
NameIterationTester::EntryList NameIterationTester::EntryList
NameIterationTester::getNamesFromIterator (CNameIterator& iter) NameIterationTester::getNamesFromIterator (CKevaIterator& iter)
{ {
EntryList res; EntryList res;
@ -702,9 +702,6 @@ BOOST_AUTO_TEST_CASE (name_tx_verification)
BOOST_AUTO_TEST_CASE(keva_updates_undo) BOOST_AUTO_TEST_CASE(keva_updates_undo)
{ {
/* Enable name history to test this on the go. */
fNameHistory = true;
const valtype nameSpace = ValtypeFromString ("database-test-namespace"); const valtype nameSpace = ValtypeFromString ("database-test-namespace");
const valtype displayName = ValtypeFromString ("display name"); const valtype displayName = ValtypeFromString ("display name");
const valtype key1 = ValtypeFromString ("key1"); const valtype key1 = ValtypeFromString ("key1");

31
src/txdb.cpp

@ -84,7 +84,7 @@ std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
return vhashHeadBlocks; return vhashHeadBlocks;
} }
class CDbNameIterator : public CNameIterator class CDbKeyIterator : public CKevaIterator
{ {
private: private:
@ -94,42 +94,43 @@ private:
public: public:
~CDbNameIterator(); ~CDbKeyIterator();
/** /**
* Construct a new name iterator for the database. * Construct a new name iterator for the database.
* @param db The database to create the iterator for. * @param db The database to create the iterator for.
*/ */
CDbNameIterator(const CDBWrapper& db); CDbKeyIterator(const CDBWrapper& db, const valtype& nameSpace);
/* Implement iterator methods. */ /* Implement iterator methods. */
void seek(const valtype& start); void seek(const valtype& start);
bool next(valtype& name, CKevaData& data); bool next(valtype& key, CKevaData& data);
}; };
CDbNameIterator::~CDbNameIterator() { CDbKeyIterator::~CDbKeyIterator() {
delete iter; delete iter;
} }
CDbNameIterator::CDbNameIterator(const CDBWrapper& db) CDbKeyIterator::CDbKeyIterator(const CDBWrapper& db, const valtype& ns)
: iter(const_cast<CDBWrapper*>(&db)->NewIterator()) : iter(const_cast<CDBWrapper*>(&db)->NewIterator()), CKevaIterator(ns)
{ {
seek(valtype()); seek(valtype());
} }
void CDbNameIterator::seek(const valtype& start) { void CDbKeyIterator::seek(const valtype& start) {
iter->Seek(std::make_pair(DB_NAME, start)); iter->Seek(std::make_pair(DB_NAME, std::make_pair(nameSpace, start)));
} }
bool CDbNameIterator::next(valtype& name, CKevaData& data) { bool CDbKeyIterator::next(valtype& key, CKevaData& data) {
if (!iter->Valid()) if (!iter->Valid())
return false; return false;
std::pair<char, valtype> key; std::pair<char, std::pair<valtype, valtype>> curKey;
if (!iter->GetKey(key) || key.first != DB_NAME) if (!iter->GetKey(curKey) || curKey.first != DB_NAME)
return false; return false;
name = key.second;
key = std::get<1>(curKey.second);
if (!iter->GetValue(data)) { if (!iter->GetValue(data)) {
return error("%s : failed to read data from iterator", __func__); return error("%s : failed to read data from iterator", __func__);
@ -139,8 +140,8 @@ bool CDbNameIterator::next(valtype& name, CKevaData& data) {
return true; return true;
} }
CNameIterator* CCoinsViewDB::IterateNames() const { CKevaIterator* CCoinsViewDB::IterateKeys(const valtype& nameSpace) const {
return new CDbNameIterator(db); return new CDbKeyIterator(db, nameSpace);
} }
bool CCoinsViewDB::GetNamespace(const valtype &nameSpace, CKevaData &data) const { bool CCoinsViewDB::GetNamespace(const valtype &nameSpace, CKevaData &data) const {

2
src/txdb.h

@ -79,7 +79,7 @@ public:
bool GetNamespace(const valtype &nameSpace, CKevaData &data) const override; bool GetNamespace(const valtype &nameSpace, CKevaData &data) const override;
bool GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const override; bool GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const override;
bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override; bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override;
CNameIterator* IterateNames() const override; CKevaIterator* IterateKeys(const valtype& nameSpace) const override;
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) override; bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) override;
CCoinsViewCursor *Cursor() const override; CCoinsViewCursor *Cursor() const override;

247
src/wallet/rpckeva.cpp

@ -1,4 +1,8 @@
// Copyright (c) 2018 Jianping Wu // Copyright (c) 2014-2017 Daniel Kraft
// 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
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -20,6 +24,7 @@
#include "wallet/wallet.h" #include "wallet/wallet.h"
#include <univalue.h> #include <univalue.h>
#include <boost/xpressive/xpressive_dynamic.hpp>
const int NAMESPACE_LENGTH = 21; const int NAMESPACE_LENGTH = 21;
const std::string DUMMY_NAMESPACE = "___DUMMY_NAMESPACE___"; const std::string DUMMY_NAMESPACE = "___DUMMY_NAMESPACE___";
@ -33,7 +38,7 @@ UniValue keva_namespace(const JSONRPCRequest& request)
if (!EnsureWalletIsAvailable (pwallet, request.fHelp)) if (!EnsureWalletIsAvailable (pwallet, request.fHelp))
return NullUniValue; return NullUniValue;
if (request.fHelp || request.params.size () != 1) if (request.fHelp || request.params.size() != 1)
throw std::runtime_error ( throw std::runtime_error (
"keva_namespace \"display_name\"\n" "keva_namespace \"display_name\"\n"
"\nRegister a namespace with the given display name.\n" "\nRegister a namespace with the given display name.\n"
@ -55,7 +60,7 @@ UniValue keva_namespace(const JSONRPCRequest& request)
const std::string displayNameStr = request.params[0].get_str(); const std::string displayNameStr = request.params[0].get_str();
const valtype displayName = ValtypeFromString (displayNameStr); const valtype displayName = ValtypeFromString (displayNameStr);
if (displayName.size () > MAX_NAMESPACE_LENGTH) { if (displayName.size() > MAX_NAMESPACE_LENGTH) {
throw JSONRPCError (RPC_INVALID_PARAMETER, "the name is too long"); throw JSONRPCError (RPC_INVALID_PARAMETER, "the name is too long");
} }
@ -140,7 +145,7 @@ UniValue keva_list_namespaces(const JSONRPCRequest& request)
CKevaScript kevaOp; CKevaScript kevaOp;
int nOut = -1; int nOut = -1;
for (unsigned i = 0; i < tx.tx->vout.size (); ++i) for (unsigned i = 0; i < tx.tx->vout.size(); ++i)
{ {
const CKevaScript cur(tx.tx->vout[i].scriptPubKey); const CKevaScript cur(tx.tx->vout[i].scriptPubKey);
if (cur.isKevaOp ()) if (cur.isKevaOp ())
@ -236,17 +241,17 @@ UniValue keva_put(const JSONRPCRequest& request)
if (!DecodeKevaNamespace(namespaceStr, Params(), nameSpace)) { if (!DecodeKevaNamespace(namespaceStr, Params(), nameSpace)) {
throw JSONRPCError (RPC_INVALID_PARAMETER, "invalid namespace id"); throw JSONRPCError (RPC_INVALID_PARAMETER, "invalid namespace id");
} }
if (nameSpace.size () > MAX_NAMESPACE_LENGTH) if (nameSpace.size() > MAX_NAMESPACE_LENGTH)
throw JSONRPCError (RPC_INVALID_PARAMETER, "the namespace is too long"); throw JSONRPCError (RPC_INVALID_PARAMETER, "the namespace is too long");
const std::string keyStr = request.params[1].get_str (); const std::string keyStr = request.params[1].get_str ();
const valtype key = ValtypeFromString (keyStr); const valtype key = ValtypeFromString (keyStr);
if (key.size () > MAX_KEY_LENGTH) if (key.size() > MAX_KEY_LENGTH)
throw JSONRPCError (RPC_INVALID_PARAMETER, "the key is too long"); throw JSONRPCError (RPC_INVALID_PARAMETER, "the key is too long");
const std::string valueStr = request.params[2].get_str (); const std::string valueStr = request.params[2].get_str ();
const valtype value = ValtypeFromString (valueStr); const valtype value = ValtypeFromString (valueStr);
if (value.size () > MAX_VALUE_LENGTH) if (value.size() > MAX_VALUE_LENGTH)
throw JSONRPCError (RPC_INVALID_PARAMETER, "the value is too long"); throw JSONRPCError (RPC_INVALID_PARAMETER, "the value is too long");
EnsureWalletIsUnlocked(pwallet); EnsureWalletIsUnlocked(pwallet);
@ -317,13 +322,13 @@ UniValue keva_delete(const JSONRPCRequest& request)
if (!DecodeKevaNamespace(namespaceStr, Params(), nameSpace)) { if (!DecodeKevaNamespace(namespaceStr, Params(), nameSpace)) {
throw JSONRPCError (RPC_INVALID_PARAMETER, "invalid namespace id"); throw JSONRPCError (RPC_INVALID_PARAMETER, "invalid namespace id");
} }
if (nameSpace.size () > MAX_NAMESPACE_LENGTH) { if (nameSpace.size() > MAX_NAMESPACE_LENGTH) {
throw JSONRPCError (RPC_INVALID_PARAMETER, "the namespace is too long"); throw JSONRPCError (RPC_INVALID_PARAMETER, "the namespace is too long");
} }
const std::string keyStr = request.params[1].get_str (); const std::string keyStr = request.params[1].get_str ();
const valtype key = ValtypeFromString (keyStr); const valtype key = ValtypeFromString (keyStr);
if (key.size () > MAX_KEY_LENGTH) { if (key.size() > MAX_KEY_LENGTH) {
throw JSONRPCError (RPC_INVALID_PARAMETER, "the key is too long"); throw JSONRPCError (RPC_INVALID_PARAMETER, "the key is too long");
} }
@ -414,12 +419,12 @@ UniValue keva_get(const JSONRPCRequest& request)
if (!DecodeKevaNamespace(namespaceStr, Params(), nameSpace)) { if (!DecodeKevaNamespace(namespaceStr, Params(), nameSpace)) {
throw JSONRPCError (RPC_INVALID_PARAMETER, "invalid namespace id"); throw JSONRPCError (RPC_INVALID_PARAMETER, "invalid namespace id");
} }
if (nameSpace.size () > MAX_NAMESPACE_LENGTH) if (nameSpace.size() > MAX_NAMESPACE_LENGTH)
throw JSONRPCError (RPC_INVALID_PARAMETER, "the namespace is too long"); throw JSONRPCError (RPC_INVALID_PARAMETER, "the namespace is too long");
const std::string keyStr = request.params[1].get_str (); const std::string keyStr = request.params[1].get_str ();
const valtype key = ValtypeFromString (keyStr); const valtype key = ValtypeFromString (keyStr);
if (key.size () > MAX_KEY_LENGTH) if (key.size() > MAX_KEY_LENGTH)
throw JSONRPCError (RPC_INVALID_PARAMETER, "the key is too long"); throw JSONRPCError (RPC_INVALID_PARAMETER, "the key is too long");
CKevaData data; CKevaData data;
@ -445,7 +450,7 @@ UniValue keva_get(const JSONRPCRequest& request)
UniValue keva_pending(const JSONRPCRequest& request) UniValue keva_pending(const JSONRPCRequest& request)
{ {
if (request.fHelp || request.params.size () > 1) if (request.fHelp || request.params.size() > 1)
throw std::runtime_error ( throw std::runtime_error (
"keva_pending (\"namespace\")\n" "keva_pending (\"namespace\")\n"
"\nList unconfirmed keva operations in the mempool.\n" "\nList unconfirmed keva operations in the mempool.\n"
@ -523,3 +528,221 @@ UniValue keva_pending(const JSONRPCRequest& request)
return arr; return arr;
} }
/**
* Return the help string description to use for keva info objects.
* @param indent Indentation at the line starts.
* @param trailing Trailing string (e. g., comma for an array of these objects).
* @return The description string.
*/
std::string getKevaInfoHelp (const std::string& indent, const std::string& trailing)
{
std::ostringstream res;
res << indent << "{" << std::endl;
res << indent << " \"name\": xxxxx, "
<< "(string) the requested name" << std::endl;
res << indent << " \"value\": xxxxx, "
<< "(string) the name's current value" << std::endl;
res << indent << " \"txid\": xxxxx, "
<< "(string) the name's last update tx" << std::endl;
res << indent << " \"address\": xxxxx, "
<< "(string) the address holding the name" << std::endl;
res << indent << " \"height\": xxxxx, "
<< "(numeric) the name's last update height" << std::endl;
res << indent << "}" << trailing << std::endl;
return res.str ();
}
/**
* Utility routine to construct a "name info" object to return. This is used
* for name_show and also name_list.
* @param name The name.
* @param value The name's value.
* @param outp The last update's outpoint.
* @param addr The name's address script.
* @param height The name's last update height.
* @return A JSON object to return.
*/
UniValue
getKevaInfo (const valtype& name, const valtype& value, const COutPoint& outp,
const CScript& addr, int height)
{
UniValue obj(UniValue::VOBJ);
obj.pushKV("name", ValtypeToString(name));
obj.pushKV("value", ValtypeToString(value));
obj.pushKV("txid", outp.hash.GetHex());
obj.pushKV("vout", static_cast<int>(outp.n));
/* Try to extract the address. May fail if we can't parse the script
as a "standard" script. */
CTxDestination dest;
std::string addrStr;
if (ExtractDestination(addr, dest))
addrStr = EncodeDestination(dest);
else
addrStr = "<nonstandard>";
obj.pushKV("address", addrStr);
/* Calculate expiration data. */
const int curHeight = chainActive.Height ();
const Consensus::Params& params = Params ().GetConsensus ();
obj.pushKV("height", height);
return obj;
}
/**
* Return name info object for a CNameData object.
* @param name The name.
* @param data The name's data.
* @return A JSON object to return.
*/
UniValue
getKevaInfo (const valtype& name, const CKevaData& data)
{
return getKevaInfo(name, data.getValue (), data.getUpdateOutpoint (),
data.getAddress (), data.getHeight ());
}
UniValue keva_filter(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 6 || request.params.size() == 0)
throw std::runtime_error(
"keva_filter (\"namespaceId\" (\"regexp\" (\"from\" (\"nb\" (\"stat\")))))\n"
"\nScan and list keys matching a regular expression.\n"
"\nArguments:\n"
"1. \"namespace\" (string) namespace Id\n"
"2. \"regexp\" (string, optional) filter keys with this regexp\n"
"3. \"maxage\" (numeric, optional, default=36000) only consider names updated in the last \"maxage\" blocks; 0 means all names\n"
"4. \"from\" (numeric, optional, default=0) return from this position onward; index starts at 0\n"
"5. \"nb\" (numeric, optional, default=0) return only \"nb\" entries; 0 means all\n"
"6. \"stat\" (string, optional) if set to the string \"stat\", print statistics instead of returning the names\n"
"\nResult:\n"
"[\n"
+ getKevaInfoHelp (" ", ",") +
" ...\n"
"]\n"
"\nExamples:\n"
+ HelpExampleCli ("keva_filter", "\"\" 5")
+ HelpExampleCli ("keva_filter", "\"^id/\"")
+ HelpExampleCli ("keva_filter", "\"^id/\" 36000 0 0 \"stat\"")
+ HelpExampleRpc ("keva_scan", "\"^d/\"")
);
RPCTypeCheck(request.params, {
UniValue::VSTR, UniValue::VSTR, UniValue::VNUM,
UniValue::VNUM, UniValue::VNUM, UniValue::VSTR
});
if (IsInitialBlockDownload()) {
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD,
"Kevacoin is downloading blocks...");
}
ObserveSafeMode();
/* ********************** */
/* Interpret parameters. */
bool haveRegexp(false);
boost::xpressive::sregex regexp;
valtype nameSpace;
int maxage(36000), from(0), nb(0);
bool stats(false);
if (request.params.size() >= 1) {
const std::string namespaceStr = request.params[0].get_str();
valtype nameSpace;
if (!DecodeKevaNamespace(namespaceStr, Params(), nameSpace)) {
throw JSONRPCError (RPC_INVALID_PARAMETER, "invalid namespace id");
}
}
if (request.params.size() >= 2) {
haveRegexp = true;
regexp = boost::xpressive::sregex::compile (request.params[1].get_str());
}
if (request.params.size() >= 3)
maxage = request.params[2].get_int();
if (maxage < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER,
"'maxage' should be non-negative");
if (request.params.size() >= 4)
from = request.params[3].get_int ();
if (from < 0)
throw JSONRPCError (RPC_INVALID_PARAMETER, "'from' should be non-negative");
if (request.params.size() >= 5)
nb = request.params[4].get_int ();
if (nb < 0)
throw JSONRPCError (RPC_INVALID_PARAMETER, "'nb' should be non-negative");
if (request.params.size() >= 6) {
if (request.params[5].get_str() != "stat")
throw JSONRPCError (RPC_INVALID_PARAMETER,
"fifth argument must be the literal string 'stat'");
stats = true;
}
/* ******************************************* */
/* Iterate over names to build up the result. */
UniValue keys(UniValue::VARR);
unsigned count(0);
LOCK (cs_main);
valtype key;
CKevaData data;
std::unique_ptr<CKevaIterator> iter(pcoinsTip->IterateKeys(nameSpace));
while (iter->next(key, data)) {
const int age = chainActive.Height() - data.getHeight();
assert(age >= 0);
if (maxage != 0 && age >= maxage)
continue;
if (haveRegexp) {
const std::string keyStr = ValtypeToString(key);
boost::xpressive::smatch matches;
if (!boost::xpressive::regex_search(keyStr, matches, regexp))
continue;
}
if (from > 0) {
--from;
continue;
}
assert(from == 0);
if (stats)
++count;
else
keys.push_back(getKevaInfo(key, data));
if (nb > 0) {
--nb;
if (nb == 0)
break;
}
}
/* ********************************************************** */
/* Return the correct result (take stats mode into account). */
if (stats) {
UniValue res(UniValue::VOBJ);
res.pushKV("blocks", chainActive.Height());
res.pushKV("count", static_cast<int>(count));
return res;
}
return keys;
}

4
src/wallet/rpcwallet.cpp

@ -3597,6 +3597,7 @@ extern UniValue keva_delete(const JSONRPCRequest& request);
extern UniValue keva_get(const JSONRPCRequest& request); extern UniValue keva_get(const JSONRPCRequest& request);
extern UniValue keva_list_namespaces(const JSONRPCRequest& request); extern UniValue keva_list_namespaces(const JSONRPCRequest& request);
extern UniValue keva_pending(const JSONRPCRequest& request); extern UniValue keva_pending(const JSONRPCRequest& request);
extern UniValue keva_filter(const JSONRPCRequest& request);
static const CRPCCommand commands[] = static const CRPCCommand commands[] =
{ // category name actor (function) argNames { // category name actor (function) argNames
@ -3661,7 +3662,8 @@ static const CRPCCommand commands[] =
{ "kevacoin", "keva_put", &keva_put, {"namespace", "key", "value"} }, { "kevacoin", "keva_put", &keva_put, {"namespace", "key", "value"} },
{ "kevacoin", "keva_delete", &keva_delete, {"namespace", "key"} }, { "kevacoin", "keva_delete", &keva_delete, {"namespace", "key"} },
{ "kevacoin", "keva_get", &keva_get, {"namespace", "key"} }, { "kevacoin", "keva_get", &keva_get, {"namespace", "key"} },
{ "kevacoin", "keva_pending", &keva_pending, {"namespace"} } { "kevacoin", "keva_pending", &keva_pending, {"namespace"} },
{ "kevacoin", "keva_filter", &keva_filter, {"namespace", "regexp", "from", "nb", "stat"} }
}; };
void RegisterWalletRPCCommands(CRPCTable &t) void RegisterWalletRPCCommands(CRPCTable &t)

Loading…
Cancel
Save