WIP: namespace/key

This commit is contained in:
Jianping Wu 2018-10-24 12:10:29 -07:00
parent b112e0c795
commit c56fb50b55
12 changed files with 257 additions and 62 deletions

View File

@ -10,6 +10,8 @@
bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; } bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); } uint256 CCoinsView::GetBestBlock() const { return uint256(); }
std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint256>(); } std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint256>(); }
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::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; } bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
CCoinsViewCursor *CCoinsView::Cursor() const { return nullptr; } CCoinsViewCursor *CCoinsView::Cursor() const { return nullptr; }
@ -24,6 +26,8 @@ bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { re
bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->HaveCoin(outpoint); } bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->HaveCoin(outpoint); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); } uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); } std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); }
bool CCoinsViewBacked::GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const { return false; }
bool CCoinsViewBacked::GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const { return false; }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); } CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
@ -142,6 +146,96 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
hashBlock = hashBlockIn; hashBlock = hashBlockIn;
} }
bool CCoinsViewCache::GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const {
if (cacheNames.isDeleted(nameSpace, key))
return false;
if (cacheNames.get(nameSpace, key, data))
return true;
/* Note: This does not attempt to cache name queries. The cache
only keeps track of changes! */
return base->GetName(nameSpace, key, data);
}
bool CCoinsViewCache::GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const {
/* Query the base view first, and then apply the cached changes (if
there are any). */
if (!base->GetNamesForHeight(nHeight, names))
return false;
cacheNames.updateNamesForHeight(nHeight, names);
return true;
}
/* 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
name history. */
void CCoinsViewCache::SetName(const valtype &nameSpace, const valtype &key, const CKevaData& data, bool undo) {
CKevaData oldData;
if (GetName(nameSpace, key, oldData))
{
#if 0
cacheNames.removeExpireIndex(name, oldData.getHeight());
/* Update the name history. If we are undoing, we expect that
the top history item matches the data being set now. If we
are not undoing, push the overwritten data onto the history stack.
Note that we only have to do this if the name already existed
in the database. Otherwise, no special action is required
for the name history. */
if (fNameHistory)
{
CNameHistory history;
if (!GetNameHistory(name, history))
{
/* Ensure that the history stack is indeed (still) empty
and was not modified by the failing GetNameHistory call. */
assert(history.empty());
}
if (undo)
history.pop(data);
else
history.push(oldData);
cacheNames.setHistory(name, history);
}
#endif
} else
assert (!undo);
cacheNames.set(nameSpace, key, data);
#if 0
cacheNames.addExpireIndex(name, data.getHeight());
#endif
}
void CCoinsViewCache::DeleteName(const valtype &nameSpace, const valtype &key) {
CKevaData oldData;
if (GetName(nameSpace, key, oldData)) {
#if 0
cacheNames.removeExpireIndex(name, oldData.getHeight());
#endif
}
else
assert(false);
#if 0
if (fNameHistory)
{
/* When deleting a name, the history should already be clean. */
CNameHistory history;
assert (!GetNameHistory(name, history) || history.empty());
}
#endif
cacheNames.remove(nameSpace, key);
}
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) { bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) { for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) {
// Ignore non-dirty entries (optimization). // Ignore non-dirty entries (optimization).

View File

@ -11,6 +11,7 @@
#include <core_memusage.h> #include <core_memusage.h>
#include <hash.h> #include <hash.h>
#include <memusage.h> #include <memusage.h>
#include <keva/common.h>
#include <serialize.h> #include <serialize.h>
#include <uint256.h> #include <uint256.h>
@ -163,6 +164,12 @@ public:
//! the old block hash, in that order. //! the old block hash, in that order.
virtual std::vector<uint256> GetHeadBlocks() const; virtual std::vector<uint256> GetHeadBlocks() const;
// Get a name (if it exists)
virtual bool GetName(const valtype& nameSpace, const valtype& key, CKevaData& data) const;
// Query for names that were updated at the given height
virtual bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) 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.
virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
@ -190,6 +197,8 @@ public:
bool HaveCoin(const COutPoint &outpoint) const override; bool HaveCoin(const COutPoint &outpoint) const override;
uint256 GetBestBlock() const override; uint256 GetBestBlock() const override;
std::vector<uint256> GetHeadBlocks() const override; std::vector<uint256> GetHeadBlocks() const override;
bool GetName(const valtype& nameSpace, const valtype& key, CKevaData& data) const override;
bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override;
void SetBackend(CCoinsView &viewIn); void SetBackend(CCoinsView &viewIn);
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override; bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
CCoinsViewCursor *Cursor() const override; CCoinsViewCursor *Cursor() const override;
@ -211,6 +220,9 @@ protected:
/* Cached dynamic memory usage for the inner Coin objects. */ /* Cached dynamic memory usage for the inner Coin objects. */
mutable size_t cachedCoinsUsage; mutable size_t cachedCoinsUsage;
/** Name changes cache. */
CKevaCache cacheNames;
public: public:
CCoinsViewCache(CCoinsView *baseIn); CCoinsViewCache(CCoinsView *baseIn);
@ -224,11 +236,17 @@ public:
bool HaveCoin(const COutPoint &outpoint) const override; bool HaveCoin(const COutPoint &outpoint) const override;
uint256 GetBestBlock() const override; uint256 GetBestBlock() const override;
void SetBestBlock(const uint256 &hashBlock); void SetBestBlock(const uint256 &hashBlock);
bool GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const override;
bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override;
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override; bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) 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.");
} }
/* Changes to the name database. */
void SetName(const valtype &nameSpace, const valtype &key, const CKevaData &data, bool undo);
void DeleteName(const valtype &nameSpace, const valtype &key);
/** /**
* Check if we have the given utxo already loaded in this cache. * Check if we have the given utxo already loaded in this cache.
* The semantics are the same as HaveCoin(), but no calls to * The semantics are the same as HaveCoin(), but no calls to

View File

@ -38,7 +38,7 @@ CNameIterator::~CNameIterator ()
} }
/* ************************************************************************** */ /* ************************************************************************** */
/* CNameCacheNameIterator. */ /* CKevaCacheNameIterator. */
class CCacheNameIterator : public CNameIterator class CCacheNameIterator : public CNameIterator
{ {
@ -46,7 +46,7 @@ class CCacheNameIterator : public CNameIterator
private: private:
/** Reference to cache object that is used. */ /** Reference to cache object that is used. */
const CNameCache& cache; const CKevaCache& cache;
/** Base iterator to combine with the cache. */ /** Base iterator to combine with the cache. */
CNameIterator* base; CNameIterator* base;
@ -59,7 +59,7 @@ private:
CKevaData baseData; CKevaData baseData;
/** Iterator of the cache's entries. */ /** Iterator of the cache's entries. */
CNameCache::EntryMap::const_iterator cacheIter; CKevaCache::EntryMap::const_iterator cacheIter;
/* 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
@ -73,7 +73,7 @@ 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 CNameCache& c, CNameIterator* b); CCacheNameIterator (const CKevaCache& c, CNameIterator* b);
/* Destruct, this deletes also the base iterator. */ /* Destruct, this deletes also the base iterator. */
~CCacheNameIterator (); ~CCacheNameIterator ();
@ -84,7 +84,7 @@ public:
}; };
CCacheNameIterator::CCacheNameIterator (const CNameCache& c, CNameIterator* b) CCacheNameIterator::CCacheNameIterator (const CKevaCache& c, CNameIterator* b)
: cache(c), base(b) : cache(c), base(b)
{ {
/* 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
@ -147,7 +147,7 @@ CCacheNameIterator::next (valtype& name, CKevaData& data)
{ {
assert (baseName != cacheIter->first); assert (baseName != cacheIter->first);
CNameCache::NameComparator cmp; CKevaCache::NameComparator cmp;
useBase = cmp (baseName, cacheIter->first); useBase = cmp (baseName, cacheIter->first);
} }
} }
@ -170,11 +170,12 @@ CCacheNameIterator::next (valtype& name, CKevaData& data)
} }
/* ************************************************************************** */ /* ************************************************************************** */
/* CNameCache. */ /* CKevaCache. */
bool bool
CNameCache::get (const valtype& name, CKevaData& data) const CKevaCache::get (const valtype& nameSpace, const valtype& key, CKevaData& data) const
{ {
valtype name = nameSpace + key;
const EntryMap::const_iterator i = entries.find (name); const EntryMap::const_iterator i = entries.find (name);
if (i == entries.end ()) if (i == entries.end ())
return false; return false;
@ -184,8 +185,9 @@ CNameCache::get (const valtype& name, CKevaData& data) const
} }
void void
CNameCache::set (const valtype& name, const CKevaData& data) CKevaCache::set (const valtype& nameSpace, const valtype& key, const CKevaData& data)
{ {
valtype name = nameSpace + key;
const std::set<valtype>::iterator di = deleted.find (name); const std::set<valtype>::iterator di = deleted.find (name);
if (di != deleted.end ()) if (di != deleted.end ())
deleted.erase (di); deleted.erase (di);
@ -198,8 +200,9 @@ CNameCache::set (const valtype& name, const CKevaData& data)
} }
void void
CNameCache::remove (const valtype& name) CKevaCache::remove (const valtype& nameSpace, const valtype& key)
{ {
valtype name = nameSpace + key;
const EntryMap::iterator ei = entries.find (name); const EntryMap::iterator ei = entries.find (name);
if (ei != entries.end ()) if (ei != entries.end ())
entries.erase (ei); entries.erase (ei);
@ -208,13 +211,14 @@ CNameCache::remove (const valtype& name)
} }
CNameIterator* CNameIterator*
CNameCache::iterateNames (CNameIterator* base) const CKevaCache::iterateNames (CNameIterator* base) const
{ {
return new CCacheNameIterator (*this, base); return new CCacheNameIterator (*this, base);
} }
#if 0
bool bool
CNameCache::getHistory (const valtype& name, CNameHistory& res) const CKevaCache::getHistory (const valtype& name, CNameHistory& res) const
{ {
assert (fNameHistory); assert (fNameHistory);
@ -227,7 +231,7 @@ CNameCache::getHistory (const valtype& name, CNameHistory& res) const
} }
void void
CNameCache::setHistory (const valtype& name, const CNameHistory& data) CKevaCache::setHistory (const valtype& name, const CNameHistory& data)
{ {
assert (fNameHistory); assert (fNameHistory);
@ -237,9 +241,10 @@ CNameCache::setHistory (const valtype& name, const CNameHistory& data)
else else
history.insert (std::make_pair (name, data)); history.insert (std::make_pair (name, data));
} }
#endif
void void
CNameCache::updateNamesForHeight (unsigned nHeight, CKevaCache::updateNamesForHeight (unsigned nHeight,
std::set<valtype>& names) const std::set<valtype>& names) const
{ {
/* Seek in the map of cached entries to the first one corresponding /* Seek in the map of cached entries to the first one corresponding
@ -263,21 +268,21 @@ CNameCache::updateNamesForHeight (unsigned nHeight,
} }
void void
CNameCache::addExpireIndex (const valtype& name, unsigned height) CKevaCache::addExpireIndex (const valtype& name, unsigned height)
{ {
const ExpireEntry entry(height, name); const ExpireEntry entry(height, name);
expireIndex[entry] = true; expireIndex[entry] = true;
} }
void void
CNameCache::removeExpireIndex (const valtype& name, unsigned height) CKevaCache::removeExpireIndex (const valtype& name, unsigned height)
{ {
const ExpireEntry entry(height, name); const ExpireEntry entry(height, name);
expireIndex[entry] = false; expireIndex[entry] = false;
} }
void void
CNameCache::apply (const CNameCache& cache) CKevaCache::apply (const CKevaCache& cache)
{ {
for (EntryMap::const_iterator i = cache.entries.begin (); for (EntryMap::const_iterator i = cache.entries.begin ();
i != cache.entries.end (); ++i) i != cache.entries.end (); ++i)

View File

@ -274,7 +274,7 @@ public:
* new names (or updates to them), this also keeps track of deleted names * new names (or updates to them), this also keeps track of deleted names
* (when rolling back changes). * (when rolling back changes).
*/ */
class CNameCache class CKevaCache
{ {
private: private:
@ -306,6 +306,7 @@ public:
* the height is serialised as byte-array with little-endian order, * the height is serialised as byte-array with little-endian order,
* which does not correspond to the ordering by actual value. * which does not correspond to the ordering by actual value.
*/ */
#if 0
class ExpireEntry class ExpireEntry
{ {
public: public:
@ -369,6 +370,7 @@ public:
} }
}; };
#endif
/** /**
* 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
@ -383,17 +385,21 @@ private:
/** Deleted names. */ /** Deleted names. */
std::set<valtype> deleted; std::set<valtype> deleted;
#if 0
/** /**
* New or updated history stacks. If they are empty, the corresponding * New or updated history stacks. If they are empty, the corresponding
* database entry is deleted instead. * database entry is deleted instead.
*/ */
std::map<valtype, CNameHistory> history; std::map<valtype, CNameHistory> history;
#endif
#if 0
/** /**
* Changes to be performed to the expire index. The entry is mapped * Changes to be performed to the expire index. The entry is mapped
* to either "true" (meaning to add it) or "false" (delete). * to either "true" (meaning to add it) or "false" (delete).
*/ */
std::map<ExpireEntry, bool> expireIndex; std::map<ExpireEntry, bool> expireIndex;
#endif
friend class CCacheNameIterator; friend class CCacheNameIterator;
@ -404,8 +410,10 @@ public:
{ {
entries.clear (); entries.clear ();
deleted.clear (); deleted.clear ();
#if 0
history.clear (); history.clear ();
expireIndex.clear (); expireIndex.clear ();
#endif
} }
/** /**
@ -417,38 +425,40 @@ public:
inline bool inline bool
empty () const empty () const
{ {
if (entries.empty () && deleted.empty ()) if (entries.empty () && deleted.empty ()) {
{ #if 0
assert (history.empty () && expireIndex.empty ()); assert (history.empty () && expireIndex.empty ());
return true; #endif
} return true;
}
return false; return false;
} }
/* See if the given name is marked as deleted. */ /* See if the given name is marked as deleted. */
inline bool inline bool
isDeleted (const valtype& name) const isDeleted (const valtype& nameSpace, const valtype& key) const
{ {
return (deleted.count (name) > 0); return (deleted.count (name) > 0);
} }
/* Try to get a name's associated data. This looks only /* Try to get a name's associated data. This looks only
in entries, and doesn't care about deleted data. */ in entries, and doesn't care about deleted data. */
bool get (const valtype& name, CKevaData& data) const; bool get (const valtype& nameSpace, const valtype& key, CKevaData& data) const;
/* Insert (or update) a name. If it is marked as "deleted", this also /* Insert (or update) a name. If it is marked as "deleted", this also
removes the "deleted" mark. */ removes the "deleted" mark. */
void set (const valtype& name, const CKevaData& data); void set (const valtype& nameSpace, const valtype& key, const CKevaData& data);
/* Delete a name. If it is in the "entries" set also, remove it there. */ /* Delete a name. If it is in the "entries" set also, remove it there. */
void remove (const valtype& name); void remove (const valtype& nameSpace, const valtype& key);
/* 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; CNameIterator* iterateNames (CNameIterator* base) const;
#if 0
/** /**
* Query for an history entry. * Query for an history entry.
* @param name The name to look up. * @param name The name to look up.
@ -463,6 +473,7 @@ public:
* @param data The new history entry. * @param data The new history entry.
*/ */
void setHistory (const valtype& name, const CNameHistory& data); void setHistory (const valtype& name, const CNameHistory& data);
#endif
/* 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
@ -470,14 +481,16 @@ public:
are represented by the cached expire index changes. */ are represented by the cached expire index changes. */
void updateNamesForHeight (unsigned nHeight, std::set<valtype>& names) const; void updateNamesForHeight (unsigned nHeight, std::set<valtype>& names) const;
#if 0
/* Add an expire-index entry. */ /* Add an expire-index entry. */
void addExpireIndex (const valtype& name, unsigned height); void addExpireIndex (const valtype& name, unsigned height);
/* Remove an expire-index entry. */ /* Remove an expire-index entry. */
void removeExpireIndex (const valtype& name, unsigned height); void removeExpireIndex (const valtype& name, unsigned height);
#endif
/* Apply all the changes in the passed-in record on top of this one. */ /* Apply all the changes in the passed-in record on top of this one. */
void apply (const CNameCache& cache); void apply (const CKevaCache& cache);
/* Write all cached changes to a database batch update object. */ /* Write all cached changes to a database batch update object. */
void writeBatch (CDBBatch& batch) const; void writeBatch (CDBBatch& batch) const;

View File

@ -26,19 +26,20 @@
/* CKevaTxUndo. */ /* CKevaTxUndo. */
void void
CKevaTxUndo::fromOldState(const valtype& nm, const CCoinsView& view) CKevaTxUndo::fromOldState(const valtype& nameSpace, const valtype& key, const CCoinsView& view)
{ {
name = nm; this->nameSpace = nameSpace;
isNew = !view.GetName(name, oldData); this->key = key;
isNew = !view.GetName(nameSpace, key, oldData);
} }
void void
CKevaTxUndo::apply (CCoinsViewCache& view) const CKevaTxUndo::apply(CCoinsViewCache& view) const
{ {
if (isNew) if (isNew)
view.DeleteName(name); view.DeleteName(nameSpace, key);
else else
view.SetName(name, oldData, true); view.SetName(nameSpace, key, oldData, true);
} }
/* ************************************************************************** */ /* ************************************************************************** */
@ -504,6 +505,7 @@ ApplyNameTransaction (const CTransaction& tx, unsigned nHeight,
{ {
assert (nHeight != MEMPOOL_HEIGHT); assert (nHeight != MEMPOOL_HEIGHT);
#if 0
/* Handle historic bugs that should *not* be applied. Names that are /* Handle historic bugs that should *not* be applied. Names that are
outputs should be marked as unspendable in this case. Otherwise, outputs should be marked as unspendable in this case. Otherwise,
we get an inconsistency between the UTXO set and the name database. */ we get an inconsistency between the UTXO set and the name database. */
@ -521,34 +523,34 @@ ApplyNameTransaction (const CTransaction& tx, unsigned nHeight,
} }
return; return;
} }
#endif
/* This check must be done *after* the historic bug fixing above! Some /* This check must be done *after* the historic bug fixing above! Some
of the names that must be handled above are actually produced by of the names that must be handled above are actually produced by
transactions *not* marked as Namecoin tx. */ transactions *not* marked as Namecoin tx. */
if (!tx.IsNamecoin ()) if (!tx.IsKevacoin ())
return; return;
/* Changes are encoded in the outputs. We don't have to do any checks, /* Changes are encoded in the outputs. We don't have to do any checks,
so simply apply all these. */ so simply apply all these. */
for (unsigned i = 0; i < tx.vout.size (); ++i) for (unsigned i = 0; i < tx.vout.size (); ++i) {
{ const CKevaScript op(tx.vout[i].scriptPubKey);
const CNameScript op(tx.vout[i].scriptPubKey); if (op.isKevaOp () && op.isAnyUpdate ()) {
if (op.isNameOp () && op.isAnyUpdate ()) const valtype& nameSpace = op.getOpNamespace();
{ const valtype& key = op.getOpKey();
const valtype& name = op.getOpName (); LogPrint (BCLog::KEVA, "Updating name at height %d: %s\n",
LogPrint (BCLog::NAMES, "Updating name at height %d: %s\n", nHeight, ValtypeToString (nameSpace).c_str ());
nHeight, ValtypeToString (name).c_str ());
CKevaTxUndo opUndo; CKevaTxUndo opUndo;
opUndo.fromOldState (name, view); opUndo.fromOldState(nameSpace, key, view);
undo.vnameundo.push_back (opUndo); undo.vkevaundo.push_back(opUndo);
CNameData data; CKevaData data;
data.fromScript (nHeight, COutPoint (tx.GetHash (), i), op); data.fromScript (nHeight, COutPoint (tx.GetHash (), i), op);
view.SetName (name, data, false); view.SetName (nameSpace, key, data, false);
}
} }
}
} }
bool bool

View File

@ -51,8 +51,11 @@ class CKevaTxUndo
private: private:
/** The name this concerns. */ /** The namespace this concerns. */
valtype name; valtype nameSpace;
/** The key this concerns. */
valtype key;
/** Whether this was an entirely new name (no update). */ /** Whether this was an entirely new name (no update). */
bool isNew; bool isNew;
@ -79,7 +82,7 @@ public:
* @param nm The name that is being updated. * @param nm The name that is being updated.
* @param view The (old!) chain state. * @param view The (old!) chain state.
*/ */
void fromOldState (const valtype& nm, const CCoinsView& view); void fromOldState (const valtype& nameSpace, const valtype& key, const CCoinsView& view);
/** /**
* Apply the undo to the chain state given. * Apply the undo to the chain state given.

View File

@ -62,6 +62,12 @@ uint256 CMutableTransaction::GetHash() const
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS); return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
} }
void CMutableTransaction::SetKevacoin()
{
assert (nVersion == CTransaction::CURRENT_VERSION);
nVersion = CTransaction::KEVACOIN_VERSION;
}
uint256 CTransaction::ComputeHash() const uint256 CTransaction::ComputeHash() const
{ {
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS); return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);

View File

@ -266,6 +266,7 @@ class CTransaction
public: public:
// Default transaction version. // Default transaction version.
static const int32_t CURRENT_VERSION=2; static const int32_t CURRENT_VERSION=2;
static const int32_t KEVACOIN_VERSION=0x7100;
// Changing the default transaction version requires a two step process: first // Changing the default transaction version requires a two step process: first
// adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date // adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date
@ -335,6 +336,11 @@ public:
return (vin.size() == 1 && vin[0].prevout.IsNull()); return (vin.size() == 1 && vin[0].prevout.IsNull());
} }
bool IsKevacoin() const
{
return nVersion == KEVACOIN_VERSION;
}
friend bool operator==(const CTransaction& a, const CTransaction& b) friend bool operator==(const CTransaction& a, const CTransaction& b)
{ {
return a.hash == b.hash; return a.hash == b.hash;
@ -404,6 +410,12 @@ struct CMutableTransaction
} }
return false; return false;
} }
/**
* Turn this into a Kevacoin version transaction. It is assumed
* that it isn't already.
*/
void SetKevacoin();
}; };
typedef std::shared_ptr<const CTransaction> CTransactionRef; typedef std::shared_ptr<const CTransaction> CTransactionRef;

View File

@ -52,7 +52,7 @@ public:
* @return True iff this is a name operation. * @return True iff this is a name operation.
*/ */
inline bool inline bool
isNameOp () const isKevaOp () const
{ {
switch (op) { switch (op) {
case OP_KEVA_PUT: case OP_KEVA_PUT:
@ -80,10 +80,10 @@ public:
/** /**
* Return the name operation. This returns OP_NAME_NEW, OP_NAME_FIRSTUPDATE * Return the name operation. This returns OP_NAME_NEW, OP_NAME_FIRSTUPDATE
* or OP_NAME_UPDATE. Do not call if this is not a name script. * or OP_NAME_UPDATE. Do not call if this is not a keva script.
* @return The name operation opcode. * @return The name operation opcode.
*/ */
inline opcodetype getNameOp() const inline opcodetype getKevaOp() const
{ {
switch (op) { switch (op) {
case OP_KEVA_PUT: case OP_KEVA_PUT:
@ -119,9 +119,9 @@ public:
/** /**
* Return the name operation name. This call is only valid for * Return the name operation name. This call is only valid for
* OP_KEVA_NAMESPACE or OP_KEVA_PUT. * OP_KEVA_NAMESPACE or OP_KEVA_PUT.
* @return The name operation's name. * @return The keva operation's namespace.
*/ */
inline const valtype& getOpName () const inline const valtype& getOpNamespace() const
{ {
switch (op) { switch (op) {
case OP_KEVA_PUT: case OP_KEVA_PUT:
@ -140,7 +140,7 @@ public:
* OP_KEVA_PUT. * OP_KEVA_PUT.
* @return The name operation's value. * @return The name operation's value.
*/ */
inline const valtype& getOpValue () const inline const valtype& getOpNamespaceValue() const
{ {
switch (op) { switch (op) {
case OP_KEVA_PUT: case OP_KEVA_PUT:
@ -153,15 +153,51 @@ public:
} }
/** /**
* Check if the given script is a name script. This is a utility method. * Return the keva operation key. This call is only valid for
* OP_KEVA_PUT.
* @return The keva operation's value.
*/
inline const valtype& getOpKey() const
{
switch (op) {
case OP_KEVA_PUT:
return args[0];
case OP_KEVA_NAMESPACE:
return args[0];
default:
assert(false);
}
}
/**
* Return the keva operation value. This call is only valid for
* OP_KEVA_PUT.
* @return The keva operation's value.
*/
inline const valtype& getOpValue() const
{
switch (op) {
case OP_KEVA_PUT:
// args[1] is namespace
return args[2];
default:
assert (false);
}
}
/**
* Check if the given script is a keva script. This is a utility method.
* @param script The script to parse. * @param script The script to parse.
* @return True iff it is a name script. * @return True iff it is a name script.
*/ */
static inline bool static inline bool
isNameScript (const CScript& script) isKevaScript (const CScript& script)
{ {
const CKevaScript op(script); const CKevaScript op(script);
return op.isNameOp (); return op.isKevaOp ();
} }
/** /**

View File

@ -38,6 +38,8 @@ static const int MAX_STACK_SIZE = 1000;
// otherwise as UNIX timestamp. // otherwise as UNIX timestamp.
static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
typedef std::vector<unsigned char> valtype;
template <typename T> template <typename T>
std::vector<unsigned char> ToByteVector(const T& in) std::vector<unsigned char> ToByteVector(const T& in)
{ {

View File

@ -101,6 +101,9 @@ class CBlockUndo
public: public:
std::vector<CTxUndo> vtxundo; // for all but the coinbase std::vector<CTxUndo> vtxundo; // for all but the coinbase
/** Stack of operations done to the keva database. */
std::vector<CKevaTxUndo> vkevaundo;
ADD_SERIALIZE_METHODS; ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation> template <typename Stream, typename Operation>

View File

@ -104,6 +104,7 @@ namespace BCLog {
COINDB = (1 << 18), COINDB = (1 << 18),
QT = (1 << 19), QT = (1 << 19),
LEVELDB = (1 << 20), LEVELDB = (1 << 20),
KEVA = (1 << 21),
ALL = ~(uint32_t)0, ALL = ~(uint32_t)0,
}; };
} }