Browse Source

WIP: tried to compile keva/main.cpp.

cn
Jianping Wu 6 years ago
parent
commit
d05ab948e2
  1. 419
      src/keva/main.cpp
  2. 23
      src/keva/main.h
  3. 26
      src/txmempool.h

419
src/keva/main.cpp

@ -46,25 +46,25 @@ CKevaTxUndo::apply(CCoinsViewCache& view) const @@ -46,25 +46,25 @@ CKevaTxUndo::apply(CCoinsViewCache& view) const
/* CKevaMemPool. */
uint256
CKevaMemPool::getTxForName(const valtype& name) const
CKevaMemPool::getTxForNamespace(const valtype& nameSpace) const
{
NameTxMap::const_iterator mi;
mi = mapNameRegs.find (name);
if (mi != mapNameRegs.end ())
{
assert (mapNameUpdates.count (name) == 0);
return mi->second;
}
#if 0
// JWU TODO: implement this!
NamespaceTxMap::const_iterator mi;
mi = mapNameUpdates.find (name);
if (mi != mapNameUpdates.end ())
{
assert (mapNameRegs.count (name) == 0);
return mi->second;
}
mi = mapNamespaceRegs.find(nameSpace);
if (mi != mapNamespaceRegs.end()) {
assert(mapNamespaceKeyUpdates.count(name) == 0);
return mi->second;
}
return uint256 ();
mi = mapNamespaceKeyUpdates.find(name);
if (mi != mapNameUpdates.end ()) {
assert (mapNameRegs.count (name) == 0);
return mi->second;
}
#endif
return uint256();
}
void
@ -72,29 +72,19 @@ CKevaMemPool::addUnchecked (const uint256& hash, const CTxMemPoolEntry& entry) @@ -72,29 +72,19 @@ CKevaMemPool::addUnchecked (const uint256& hash, const CTxMemPoolEntry& entry)
{
AssertLockHeld (pool.cs);
if (entry.isNameNew ())
{
const valtype& newHash = entry.getNameNewHash ();
const NameTxMap::const_iterator mit = mapNameNews.find (newHash);
if (mit != mapNameNews.end ())
assert (mit->second == hash);
else
mapNameNews.insert (std::make_pair (newHash, hash));
}
if (entry.isNameRegistration ())
{
const valtype& name = entry.getName ();
assert (mapNameRegs.count (name) == 0);
mapNameRegs.insert (std::make_pair (name, hash));
}
if (entry.isNamespaceRegistration()) {
const valtype& nameSpace = entry.getNamespace();
assert(mapNamespaceRegs.count(nameSpace) == 0);
mapNamespaceRegs.insert(std::make_pair (nameSpace, hash));
}
if (entry.isNameUpdate ())
{
const valtype& name = entry.getName ();
assert (mapNameUpdates.count (name) == 0);
mapNameUpdates.insert (std::make_pair (name, hash));
}
if (entry.isNamespaceKeyUpdate ()) {
const valtype& nameSpace = entry.getNamespace();
const valtype& key = entry.getKey();
NamespaceKeyTuple tuple(nameSpace, key);
assert(mapNamespaceKeyUpdates.count(tuple) == 0);
mapNamespaceKeyUpdates.insert (std::make_pair (name, hash));
}
}
void
@ -102,18 +92,18 @@ CKevaMemPool::remove (const CTxMemPoolEntry& entry) @@ -102,18 +92,18 @@ CKevaMemPool::remove (const CTxMemPoolEntry& entry)
{
AssertLockHeld (pool.cs);
if (entry.isNameRegistration ())
{
const NameTxMap::iterator mit = mapNameRegs.find (entry.getName ());
assert (mit != mapNameRegs.end ());
mapNameRegs.erase (mit);
}
if (entry.isNameUpdate ())
{
const NameTxMap::iterator mit = mapNameUpdates.find (entry.getName ());
assert (mit != mapNameUpdates.end ());
mapNameUpdates.erase (mit);
}
if (entry.isNamespaceRegistration ()) {
const NamespaceTxMap::iterator mit = mapNamespaceRegs.find (entry.getNamespace());
assert (mit != mapNamespaceRegs.end());
mapNamespaceRegs.erase (mit);
}
if (entry.isNamespaceKeyUpdate ()) {
NamespaceKeyTuple tuple(entry.getNamespace(), entry.getKey());
const NamespaceKeyTxMap::iterator mit = mapNamespaceKeyUpdates.find(tuple);
assert (mit != mapNamespaceKeyUpdates.end());
mapNamespaceKeyUpdates.erase (mit);
}
}
void
@ -121,29 +111,27 @@ CKevaMemPool::removeConflicts (const CTransaction& tx) @@ -121,29 +111,27 @@ CKevaMemPool::removeConflicts (const CTransaction& tx)
{
AssertLockHeld (pool.cs);
if (!tx.IsNamecoin ())
if (!tx.IsKevacoin ())
return;
for (const auto& txout : tx.vout)
{
const CNameScript nameOp(txout.scriptPubKey);
if (nameOp.isNameOp () && nameOp.getNameOp () == OP_NAME_FIRSTUPDATE)
{
const valtype& name = nameOp.getOpName ();
const NameTxMap::const_iterator mit = mapNameRegs.find (name);
if (mit != mapNameRegs.end ())
{
const CTxMemPool::txiter mit2 = pool.mapTx.find (mit->second);
assert (mit2 != pool.mapTx.end ());
pool.removeRecursive (mit2->GetTx (),
MemPoolRemovalReason::NAME_CONFLICT);
}
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);
}
}
}
}
void
CKevaMemPool::check (const CCoinsView& coins) const
CKevaMemPool::check(const CCoinsView& coins) const
{
AssertLockHeld (pool.cs);
@ -156,55 +144,43 @@ CKevaMemPool::check (const CCoinsView& coins) const @@ -156,55 +144,43 @@ CKevaMemPool::check (const CCoinsView& coins) const
std::set<valtype> nameRegs;
std::set<valtype> nameUpdates;
for (const auto& entry : pool.mapTx)
{
const uint256 txHash = entry.GetTx ().GetHash ();
if (entry.isNameNew ())
{
const valtype& newHash = entry.getNameNewHash ();
const NameTxMap::const_iterator mit = mapNameNews.find (newHash);
assert (mit != mapNameNews.end ());
assert (mit->second == txHash);
}
if (entry.isNameRegistration ())
{
const valtype& name = entry.getName ();
for (const auto& entry : pool.mapTx) {
const uint256 txHash = entry.GetTx ().GetHash ();
if (entry.isNamespaceRegistration()) {
const valtype& nameSpace = entry.getNamespace();
const NameTxMap::const_iterator mit = mapNameRegs.find (name);
assert (mit != mapNameRegs.end ());
assert (mit->second == txHash);
const NamespaceTxMap::const_iterator mit = mapNamespaceRegs.find(nameSpace);
assert (mit != mapNamespaceRegs.end());
assert (mit->second == txHash);
assert (nameRegs.count (name) == 0);
nameRegs.insert (name);
assert (nameRegs.count(nameSpace) == 0);
nameRegs.insert(nameSpace);
/* The old name should be expired already. Note that we use
nHeight+1 for the check, because that's the height at which
the mempool tx will actually be mined. */
CNameData data;
if (coins.GetName (name, data))
assert (data.isExpired (nHeight + 1));
}
/* The old name should be expired already. Note that we use
nHeight+1 for the check, because that's the height at which
the mempool tx will actually be mined. */
CKevaData data;
if (coins.GetName(name, data))
assert (data.isExpired (nHeight + 1));
}
if (entry.isNameUpdate ())
{
const valtype& name = entry.getName ();
if (entry.isNamespaceKeyUpdate()) {
const valtype& name = entry.getName ();
const NameTxMap::const_iterator mit = mapNameUpdates.find (name);
assert (mit != mapNameUpdates.end ());
assert (mit->second == txHash);
const NameTxMap::const_iterator mit = mapNameUpdates.find (name);
assert (mit != mapNameUpdates.end ());
assert (mit->second == txHash);
assert (nameUpdates.count (name) == 0);
nameUpdates.insert (name);
assert (nameUpdates.count (name) == 0);
nameUpdates.insert(name);
/* As above, use nHeight+1 for the expiration check. */
CNameData data;
if (!coins.GetName (name, data))
assert (false);
assert (!data.isExpired (nHeight + 1));
}
/* As above, use nHeight+1 for the expiration check. */
CKevaData data;
if (!coins.GetName(name, data))
assert (false);
assert (!data.isExpired (nHeight + 1));
}
}
assert (nameRegs.size () == mapNameRegs.size ());
assert (nameUpdates.size () == mapNameUpdates.size ());
@ -223,7 +199,7 @@ CKevaMemPool::checkTx (const CTransaction& tx) const @@ -223,7 +199,7 @@ CKevaMemPool::checkTx (const CTransaction& tx) const
{
AssertLockHeld (pool.cs);
if (!tx.IsNamecoin ())
if (!tx.IsKevacoin ())
return true;
/* In principle, multiple name_updates could be performed within the
@ -231,44 +207,35 @@ CKevaMemPool::checkTx (const CTransaction& tx) const @@ -231,44 +207,35 @@ CKevaMemPool::checkTx (const CTransaction& tx) const
since the current mempool implementation does not like it. (We keep
track of only a single update tx for each name.) */
for (const auto& txout : tx.vout)
{
const CNameScript nameOp(txout.scriptPubKey);
if (!nameOp.isNameOp ())
continue;
switch (nameOp.getNameOp ())
{
case OP_NAME_NEW:
{
const valtype& newHash = nameOp.getOpHash ();
std::map<valtype, uint256>::const_iterator mi;
mi = mapNameNews.find (newHash);
if (mi != mapNameNews.end () && mi->second != tx.GetHash ())
return false;
break;
}
case OP_NAME_FIRSTUPDATE:
{
const valtype& name = nameOp.getOpName ();
if (registersName (name))
return false;
break;
}
case OP_NAME_UPDATE:
{
const valtype& name = nameOp.getOpName ();
if (updatesName (name))
return false;
break;
}
default:
assert (false);
}
for (const auto& txout : tx.vout) {
const CKevaScript nameOp(txout.scriptPubKey);
if (!nameOp.isKevaOp ())
continue;
switch (nameOp.getKevaOp ()) {
case OP_KEVA_NAMESPACE:
{
const valtype& nameSpace = nameOp.getOpNamespace();
std::map<valtype, uint256>::const_iterator mi;
mi = mapNamespaceRegs.find(nameSpace);
if (mi != mapNamespaceRegs.end ())
return false;
break;
}
case OP_KEVA_PUT:
{
const valtype& nameSpace = nameOp.getOpNamespace();
const valtype& key = nameOp.getOpKey();
if (updatesKey(nameSpace, key))
return false;
break;
}
default:
assert (false);
}
}
return true;
}
@ -284,7 +251,7 @@ ConflictTrackerNotifyEntryRemoved (CNameConflictTracker* tracker, @@ -284,7 +251,7 @@ ConflictTrackerNotifyEntryRemoved (CNameConflictTracker* tracker,
CTransactionRef txRemoved,
MemPoolRemovalReason reason)
{
if (reason == MemPoolRemovalReason::NAME_CONFLICT)
if (reason == MemPoolRemovalReason::KEVA_CONFLICT)
tracker->AddConflictedEntry (txRemoved);
}
@ -320,17 +287,19 @@ CheckNameTransaction (const CTransaction& tx, unsigned nHeight, @@ -320,17 +287,19 @@ CheckNameTransaction (const CTransaction& tx, unsigned nHeight,
const char* txid = strTxid.c_str ();
const bool fMempool = (flags & SCRIPT_VERIFY_NAMES_MEMPOOL);
#if 0
/* Ignore historic bugs. */
CChainParams::BugType type;
if (Params ().IsHistoricBug (tx.GetHash (), nHeight, type))
return true;
#endif
/* As a first step, try to locate inputs and outputs of the transaction
that are name scripts. At most one input and output should be
a name operation. */
int nameIn = -1;
CNameScript nameOpIn;
CKevaScript nameOpIn;
Coin coinIn;
for (unsigned i = 0; i < tx.vin.size (); ++i)
{
@ -339,51 +308,47 @@ CheckNameTransaction (const CTransaction& tx, unsigned nHeight, @@ -339,51 +308,47 @@ CheckNameTransaction (const CTransaction& tx, unsigned nHeight,
if (!view.GetCoin (prevout, coin))
return error ("%s: failed to fetch input coin for %s", __func__, txid);
const CNameScript op(coin.out.scriptPubKey);
if (op.isNameOp ())
{
if (nameIn != -1)
return state.Invalid (error ("%s: multiple name inputs into"
" transaction %s", __func__, txid));
nameIn = i;
nameOpIn = op;
coinIn = coin;
}
const CKevaScript op(coin.out.scriptPubKey);
if (op.isKevaOp()) {
if (nameIn != -1)
return state.Invalid (error ("%s: multiple name inputs into"
" transaction %s", __func__, txid));
nameIn = i;
nameOpIn = op;
coinIn = coin;
}
}
int nameOut = -1;
CNameScript nameOpOut;
for (unsigned i = 0; i < tx.vout.size (); ++i)
{
const CNameScript op(tx.vout[i].scriptPubKey);
if (op.isNameOp ())
{
if (nameOut != -1)
return state.Invalid (error ("%s: multiple name outputs from"
" transaction %s", __func__, txid));
nameOut = i;
nameOpOut = op;
}
CKevaScript nameOpOut;
for (unsigned i = 0; i < tx.vout.size (); ++i) {
const CKevaScript op(tx.vout[i].scriptPubKey);
if (op.isKevaOp()) {
if (nameOut != -1)
return state.Invalid (error ("%s: multiple name outputs from"
" transaction %s", __func__, txid));
nameOut = i;
nameOpOut = op;
}
}
/* Check that no name inputs/outputs are present for a non-Namecoin tx.
If that's the case, all is fine. For a Namecoin tx instead, there
should be at least an output (for NAME_NEW, no inputs are expected). */
if (!tx.IsNamecoin ())
{
if (nameIn != -1)
return state.Invalid (error ("%s: non-Namecoin tx %s has name inputs",
__func__, txid));
if (nameOut != -1)
return state.Invalid (error ("%s: non-Namecoin tx %s at height %u"
" has name outputs",
__func__, txid, nHeight));
if (!tx.IsKevacoin ()) {
if (nameIn != -1)
return state.Invalid (error ("%s: non-Namecoin tx %s has name inputs",
__func__, txid));
if (nameOut != -1)
return state.Invalid (error ("%s: non-Namecoin tx %s at height %u"
" has name outputs",
__func__, txid, nHeight));
return true;
}
return true;
}
assert (tx.IsNamecoin ());
assert(tx.IsKevacoin ());
if (nameOut == -1)
return state.Invalid (error ("%s: Namecoin tx %s has no name outputs",
__func__, txid));
@ -393,6 +358,7 @@ CheckNameTransaction (const CTransaction& tx, unsigned nHeight, @@ -393,6 +358,7 @@ CheckNameTransaction (const CTransaction& tx, unsigned nHeight,
if (tx.vout[nameOut].nValue < params.rules->MinNameCoinAmount(nHeight))
return state.Invalid (error ("%s: greedy name", __func__));
#if 0
/* Handle NAME_NEW now, since this is easy and different from the other
operations. */
@ -411,54 +377,65 @@ CheckNameTransaction (const CTransaction& tx, unsigned nHeight, @@ -411,54 +377,65 @@ CheckNameTransaction (const CTransaction& tx, unsigned nHeight,
/* Now that we have ruled out NAME_NEW, check that we have a previous
name input that is being updated. */
#endif
assert (nameOpOut.isAnyUpdate ());
if (nameIn == -1)
return state.Invalid (error ("CheckNameTransaction: update without"
assert (nameOpOut.isAnyUpdate());
if (nameIn == -1) {
return state.Invalid(error("CheckNameTransaction: update without"
" previous name input"));
const valtype& name = nameOpOut.getOpName ();
if (name.size () > MAX_NAME_LENGTH)
return state.Invalid (error ("CheckNameTransaction: name too long"));
if (nameOpOut.getOpValue ().size () > MAX_VALUE_LENGTH)
return state.Invalid (error ("CheckNameTransaction: value too long"));
/* Process NAME_UPDATE next. */
}
if (nameOpOut.getNameOp () == OP_NAME_UPDATE)
{
if (!nameOpIn.isAnyUpdate ())
return state.Invalid (error ("CheckNameTransaction: NAME_UPDATE with"
" prev input that is no update"));
if (name != nameOpIn.getOpName ())
return state.Invalid (error ("%s: NAME_UPDATE name mismatch to prev tx"
" found in %s", __func__, txid));
/* This is actually redundant, since expired names are removed
from the UTXO set and thus not available to be spent anyway.
But it does not hurt to enforce this here, too. It is also
exercised by the unit tests. */
CNameData oldName;
if (!view.GetName (name, oldName))
return state.Invalid (error ("%s: NAME_UPDATE name does not exist",
__func__));
if (oldName.isExpired (nHeight))
return state.Invalid (error ("%s: trying to update expired name",
__func__));
/* This is an internal consistency check. If everything is fine,
the input coins from the UTXO database should match the
name database. */
assert (static_cast<unsigned> (coinIn.nHeight) == oldName.getHeight ());
assert (tx.vin[nameIn].prevout == oldName.getUpdateOutpoint ());
const valtype& key = nameOpOut.getOpKey();
if (key.size() > MAX_KEY_LENGTH) {
return state.Invalid (error ("CheckNameTransaction: key too long"));
}
return true;
if (nameOpOut.getOpValue().size () > MAX_VALUE_LENGTH) {
return state.Invalid (error ("CheckNameTransaction: value too long"));
}
/* Process KEVA_PUT next. */
const valtype& nameSpace = nameOpOut.getOpNamespace();
if (nameOpOut.getKevaOp() == OP_KEVA_PUT) {
if (!nameOpIn.isAnyUpdate ()) {
return state.Invalid(error("CheckNameTransaction: KEVA_PUT with"
" prev input that is no update"));
}
if (nameSpace != nameOpIn.getOpNamespace()) {
return state.Invalid (error ("%s: KEVA_PUT namespace mismatch to prev tx"
" found in %s", __func__, txid));
}
/* This is actually redundant, since expired names are removed
from the UTXO set and thus not available to be spent anyway.
But it does not hurt to enforce this here, too. It is also
exercised by the unit tests. */
CKevaData oldName;
const valtype& namespaceIn = nameOpIn.getOpNamespace();
const valtype& keyIn = nameOpIn.getOpKey();
if (!view.GetName(namespaceIn, keyIn, oldName)) {
return state.Invalid (error ("%s: KEVA_PUT name does not exist",
__func__));
}
#if 0
if (oldName.isExpired (nHeight))
return state.Invalid (error ("%s: trying to update expired name",
__func__));
#endif
/* This is an internal consistency check. If everything is fine,
the input coins from the UTXO database should match the
name database. */
assert (static_cast<unsigned> (coinIn.nHeight) == oldName.getHeight());
assert (tx.vin[nameIn].prevout == oldName.getUpdateOutpoint());
return true;
}
#if 0
/* Finally, NAME_FIRSTUPDATE. */
assert (nameOpOut.getNameOp () == OP_NAME_FIRSTUPDATE);
assert(nameOpOut.getNameOp () == OP_NAME_FIRSTUPDATE);
if (nameOpIn.getNameOp () != OP_NAME_NEW)
return state.Invalid (error ("CheckNameTransaction: NAME_FIRSTUPDATE"
" with non-NAME_NEW prev tx"));
@ -495,7 +472,7 @@ CheckNameTransaction (const CTransaction& tx, unsigned nHeight, @@ -495,7 +472,7 @@ CheckNameTransaction (const CTransaction& tx, unsigned nHeight,
/* We don't have to specifically check that miners don't create blocks with
conflicting NAME_FIRSTUPDATE's, since the mining's CCoinsViewCache
takes care of this with the check above already. */
#endif
return true;
}
@ -553,6 +530,7 @@ ApplyNameTransaction (const CTransaction& tx, unsigned nHeight, @@ -553,6 +530,7 @@ ApplyNameTransaction (const CTransaction& tx, unsigned nHeight,
}
}
#if 0
bool
ExpireNames (unsigned nHeight, CCoinsViewCache& view, CBlockUndo& undo,
std::set<valtype>& names)
@ -672,6 +650,7 @@ UnexpireNames (unsigned nHeight, CBlockUndo& undo, CCoinsViewCache& view, @@ -672,6 +650,7 @@ UnexpireNames (unsigned nHeight, CBlockUndo& undo, CCoinsViewCache& view,
return true;
}
#endif
void
CheckNameDB (bool disconnect)

23
src/keva/main.h

@ -126,13 +126,13 @@ private: @@ -126,13 +126,13 @@ private:
NamespaceTxMap mapNamespaceRegs;
/** Map pending name updates to transaction IDs. */
NamespaceTxMap mapNamespaceUpdates;
//NamespaceTxMap mapNamespaceUpdates;
/**
* Keep track of key that are registered by transactions in the pool.
* Keep track of key that are updated by transactions in the pool.
* Map key to registering transaction.
*/
NamespaceKeyTxMap mapNamespaceKeyRegs;
NamespaceKeyTxMap mapNamespaceKeyUpdates;
public:
@ -163,10 +163,10 @@ public: @@ -163,10 +163,10 @@ public:
* @return True iff there's a matching name update in the pool.
*/
inline bool
updatesName (const valtype& name) const
updatesKey (const valtype& nameSpace, const valtype& key) const
{
//return mapNameUpdates.count (name) > 0;
return true;
NamespaceKeyTuple tuple(nameSpace, key);
return mapNamespaceKeyUpdates.count(tuple) > 0;
}
/**
@ -175,7 +175,9 @@ public: @@ -175,7 +175,9 @@ public:
* @param name The name to check for.
* @return The txid that registers/updates it. Null if none.
*/
uint256 getTxForName (const valtype& name) const;
uint256 getTxForNamespace(const valtype& nameSpace) const;
uint256 getTxForNamespaceKey(const valtype& nameSpace, const valtype& key) const;
/**
* Clear all data.
@ -183,11 +185,8 @@ public: @@ -183,11 +185,8 @@ public:
inline void
clear ()
{
/*
mapNameRegs.clear ();
mapNameUpdates.clear ();
mapNameNews.clear ();
*/
mapNamespaceRegs.clear();
mapNamespaceKeyUpdates.clear();
}
/**

26
src/txmempool.h

@ -88,6 +88,9 @@ private: @@ -88,6 +88,9 @@ private:
CAmount nModFeesWithAncestors;
int64_t nSigOpCostWithAncestors;
/* Cache keva operation (if any) performed by this tx. */
CKevaScript kevaOp;
public:
CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
int64_t _nTime, unsigned int _entryHeight,
@ -127,6 +130,26 @@ public: @@ -127,6 +130,26 @@ public:
CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
int64_t GetSigOpCostWithAncestors() const { return nSigOpCostWithAncestors; }
inline bool isNamespaceRegistration() const
{
return kevaOp.isKevaOp() && kevaOp.getKevaOp() == OP_KEVA_NAMESPACE;
}
inline bool isNamespaceKeyUpdate() const
{
return kevaOp.isKevaOp() && kevaOp.getKevaOp() == OP_KEVA_PUT;
}
inline const valtype& getNamespace() const
{
return kevaOp.getOpNamespace();
}
inline const valtype& getKey() const
{
return kevaOp.getOpKey();
}
mutable size_t vTxHashesIdx; //!< Index in mempool's vTxHashes
};
@ -345,7 +368,8 @@ enum class MemPoolRemovalReason { @@ -345,7 +368,8 @@ enum class MemPoolRemovalReason {
REORG, //! Removed for reorganization
BLOCK, //! Removed for block
CONFLICT, //! Removed for conflict with in-block transaction
REPLACED //! Removed for replacement
REPLACED, //! Removed for replacement,
KEVA_CONFLICT
};
class SaltedTxidHasher

Loading…
Cancel
Save