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

8
src/coins.h

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

96
src/keva/common.cpp

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

42
src/keva/common.h

@ -2,7 +2,7 @@ @@ -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 Jianping Wu
// Copyright (c) 2018
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -246,37 +246,47 @@ public: @@ -246,37 +246,47 @@ public:
};
/* ************************************************************************** */
/* CNameIterator. */
/* CKevaIterator. */
/**
* Interface for iterators over the name database.
*/
class CNameIterator
class CKevaIterator
{
protected:
const valtype& nameSpace;
public:
CKevaIterator(const valtype& ns) :nameSpace(ns)
{}
// Virtual destructor in case subclasses need them.
virtual ~CNameIterator ();
virtual ~CKevaIterator();
const valtype& getNamespace() {
return nameSpace;
}
/**
* 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.
* @param name Put the name here.
* @param data Put the name's data here.
* @return True if successful, false if no more names.
* Get the next key. Returns false if no more keys are available.
* @param nameSpace Put the namespace here.
* @param key Put the key here.
* @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
@ -293,7 +303,7 @@ private: @@ -293,7 +303,7 @@ private:
* This is used to sort the cache entry map in the same way as the
* database is sorted.
*/
class NameComparator
class KeyComparator
{
public:
inline bool operator() (const std::tuple<valtype, valtype> a,
@ -314,7 +324,7 @@ public: @@ -314,7 +324,7 @@ public:
* Type of name entry map. This is public because it is also used
* 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;
@ -326,7 +336,7 @@ private: @@ -326,7 +336,7 @@ private:
/** Deleted names. */
std::set<NamespaceKeyType> deleted;
friend class CCacheNameIterator;
friend class CCacheKeyIterator;
public:
@ -379,7 +389,7 @@ public: @@ -379,7 +389,7 @@ public:
/* 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. */
CNameIterator* iterateNames (CNameIterator* base) const;
CKevaIterator* iterateKeys(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

23
src/keva/main.cpp

@ -2,7 +2,7 @@ @@ -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 Jianping Wu
// Copyright (c) 2018 the Kevacoin Core Developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -133,27 +133,6 @@ void CKevaMemPool::remove(const CTxMemPoolEntry& entry) @@ -133,27 +133,6 @@ void CKevaMemPool::remove(const CTxMemPoolEntry& entry)
void
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

2
src/keva/main.h

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

2
src/script/keva.h

@ -1,4 +1,4 @@ @@ -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
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

17
src/test/keva_tests.cpp

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

31
src/txdb.cpp

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

2
src/txdb.h

@ -79,7 +79,7 @@ public: @@ -79,7 +79,7 @@ public:
bool GetNamespace(const valtype &nameSpace, 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;
CNameIterator* IterateNames() const override;
CKevaIterator* IterateKeys(const valtype& nameSpace) const override;
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) override;
CCoinsViewCursor *Cursor() const override;

247
src/wallet/rpckeva.cpp

@ -1,4 +1,8 @@ @@ -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
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -20,6 +24,7 @@ @@ -20,6 +24,7 @@
#include "wallet/wallet.h"
#include <univalue.h>
#include <boost/xpressive/xpressive_dynamic.hpp>
const int NAMESPACE_LENGTH = 21;
const std::string DUMMY_NAMESPACE = "___DUMMY_NAMESPACE___";
@ -33,7 +38,7 @@ UniValue keva_namespace(const JSONRPCRequest& request) @@ -33,7 +38,7 @@ UniValue keva_namespace(const JSONRPCRequest& request)
if (!EnsureWalletIsAvailable (pwallet, request.fHelp))
return NullUniValue;
if (request.fHelp || request.params.size () != 1)
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error (
"keva_namespace \"display_name\"\n"
"\nRegister a namespace with the given display name.\n"
@ -55,7 +60,7 @@ UniValue keva_namespace(const JSONRPCRequest& request) @@ -55,7 +60,7 @@ UniValue keva_namespace(const JSONRPCRequest& request)
const std::string displayNameStr = request.params[0].get_str();
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");
}
@ -140,7 +145,7 @@ UniValue keva_list_namespaces(const JSONRPCRequest& request) @@ -140,7 +145,7 @@ UniValue keva_list_namespaces(const JSONRPCRequest& request)
CKevaScript kevaOp;
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);
if (cur.isKevaOp ())
@ -236,17 +241,17 @@ UniValue keva_put(const JSONRPCRequest& request) @@ -236,17 +241,17 @@ UniValue keva_put(const JSONRPCRequest& request)
if (!DecodeKevaNamespace(namespaceStr, Params(), nameSpace)) {
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");
const std::string keyStr = request.params[1].get_str ();
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");
const std::string valueStr = request.params[2].get_str ();
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");
EnsureWalletIsUnlocked(pwallet);
@ -317,13 +322,13 @@ UniValue keva_delete(const JSONRPCRequest& request) @@ -317,13 +322,13 @@ UniValue keva_delete(const JSONRPCRequest& request)
if (!DecodeKevaNamespace(namespaceStr, Params(), nameSpace)) {
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");
}
const std::string keyStr = request.params[1].get_str ();
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");
}
@ -414,12 +419,12 @@ UniValue keva_get(const JSONRPCRequest& request) @@ -414,12 +419,12 @@ UniValue keva_get(const JSONRPCRequest& request)
if (!DecodeKevaNamespace(namespaceStr, Params(), nameSpace)) {
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");
const std::string keyStr = request.params[1].get_str ();
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");
CKevaData data;
@ -445,7 +450,7 @@ UniValue keva_get(const JSONRPCRequest& request) @@ -445,7 +450,7 @@ UniValue keva_get(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 (
"keva_pending (\"namespace\")\n"
"\nList unconfirmed keva operations in the mempool.\n"
@ -523,3 +528,221 @@ UniValue keva_pending(const JSONRPCRequest& request) @@ -523,3 +528,221 @@ UniValue keva_pending(const JSONRPCRequest& request)
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); @@ -3597,6 +3597,7 @@ extern UniValue keva_delete(const JSONRPCRequest& request);
extern UniValue keva_get(const JSONRPCRequest& request);
extern UniValue keva_list_namespaces(const JSONRPCRequest& request);
extern UniValue keva_pending(const JSONRPCRequest& request);
extern UniValue keva_filter(const JSONRPCRequest& request);
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
@ -3661,7 +3662,8 @@ static const CRPCCommand commands[] = @@ -3661,7 +3662,8 @@ static const CRPCCommand commands[] =
{ "kevacoin", "keva_put", &keva_put, {"namespace", "key", "value"} },
{ "kevacoin", "keva_delete", &keva_delete, {"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)

Loading…
Cancel
Save