Browse Source

Cleaned up code - removed dead code from namecoin.

Removed lots of legacy checks from namecoin.
cn
Jianping Wu 6 years ago
parent
commit
11c740f549
  1. 369
      src/keva/main.cpp
  2. 76
      src/keva/main.h
  3. 18
      src/txmempool.h
  4. 29
      src/wallet/rpckeva.cpp

369
src/keva/main.cpp

@ -51,15 +51,11 @@ CKevaMemPool::addUnchecked (const uint256& hash, const CTxMemPoolEntry& entry)
AssertLockHeld (pool.cs); AssertLockHeld (pool.cs);
if (entry.isNamespaceRegistration()) { if (entry.isNamespaceRegistration()) {
const valtype& nameSpace = entry.getNamespace(); const valtype& nameSpace = entry.getNamespace();
assert(mapNamespaceRegs.count(nameSpace) == 0);
mapNamespaceRegs.insert(std::make_pair(nameSpace, hash));
listUnconfirmedNamespaces.push_back(std::make_tuple(hash, nameSpace, entry.getDisplayName())); listUnconfirmedNamespaces.push_back(std::make_tuple(hash, nameSpace, entry.getDisplayName()));
} }
if (entry.isNamespaceKeyUpdate ()) { if (entry.isNamespaceKeyUpdate ()) {
const valtype& nameSpace = entry.getNamespace(); const valtype& nameSpace = entry.getNamespace();
assert(mapNamespaceUpdates.count(nameSpace) == 0);
mapNamespaceUpdates.insert (std::make_pair(nameSpace, hash));
listUnconfirmedKeyValues.push_back(std::make_tuple(hash, nameSpace, entry.getKey(), entry.getValue())); listUnconfirmedKeyValues.push_back(std::make_tuple(hash, nameSpace, entry.getKey(), entry.getValue()));
} }
} }
@ -94,9 +90,6 @@ void CKevaMemPool::remove(const CTxMemPoolEntry& entry)
{ {
AssertLockHeld (pool.cs); AssertLockHeld (pool.cs);
if (entry.isNamespaceRegistration()) { if (entry.isNamespaceRegistration()) {
const NamespaceTxMap::iterator mit = mapNamespaceRegs.find(entry.getNamespace());
assert (mit != mapNamespaceRegs.end());
mapNamespaceRegs.erase(mit);
auto hash = entry.GetTx().GetHash(); auto hash = entry.GetTx().GetHash();
for (auto iter = listUnconfirmedNamespaces.begin(); iter != listUnconfirmedNamespaces.end(); ++iter) { for (auto iter = listUnconfirmedNamespaces.begin(); iter != listUnconfirmedNamespaces.end(); ++iter) {
if (std::get<0>(*iter) == hash) { if (std::get<0>(*iter) == hash) {
@ -107,9 +100,6 @@ void CKevaMemPool::remove(const CTxMemPoolEntry& entry)
} }
if (entry.isNamespaceKeyUpdate()) { if (entry.isNamespaceKeyUpdate()) {
const NamespaceTxMap::iterator mit = mapNamespaceUpdates.find(entry.getNamespace());
assert (mit != mapNamespaceUpdates.end());
mapNamespaceUpdates.erase(mit);
auto hash = entry.GetTx().GetHash(); auto hash = entry.GetTx().GetHash();
for (auto iter = listUnconfirmedKeyValues.begin(); iter != listUnconfirmedKeyValues.end(); ++iter) { for (auto iter = listUnconfirmedKeyValues.begin(); iter != listUnconfirmedKeyValues.end(); ++iter) {
if (std::get<0>(*iter) == hash) { if (std::get<0>(*iter) == hash) {
@ -146,79 +136,6 @@ CKevaMemPool::removeConflicts(const CTransaction& tx)
#endif #endif
} }
void
CKevaMemPool::check(const CCoinsView& coins) const
{
AssertLockHeld (pool.cs);
const uint256 blockHash = coins.GetBestBlock ();
int nHeight;
if (blockHash.IsNull())
nHeight = 0;
else
nHeight = mapBlockIndex.find (blockHash)->second->nHeight;
std::set<valtype> nameRegs;
std::set<valtype> namespaceKeyUpdates;
for (const auto& entry : pool.mapTx) {
const uint256 txHash = entry.GetTx ().GetHash ();
if (entry.isNamespaceRegistration()) {
const valtype& nameSpace = entry.getNamespace();
const NamespaceTxMap::const_iterator mit = mapNamespaceRegs.find(nameSpace);
assert (mit != mapNamespaceRegs.end());
assert (mit->second == txHash);
assert (nameRegs.count(nameSpace) == 0);
nameRegs.insert(nameSpace);
#if 0
/* 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));
#endif
}
if (entry.isNamespaceKeyUpdate()) {
const valtype& nameSpace = entry.getNamespace();
const NamespaceTxMap::const_iterator mit = mapNamespaceUpdates.find(nameSpace);
assert (mit != mapNamespaceUpdates.end ());
assert (mit->second == txHash);
assert (namespaceKeyUpdates.count(nameSpace) == 0);
namespaceKeyUpdates.insert(nameSpace);
#if 0
/* As above, use nHeight+1 for the expiration check. */
CKevaData data;
if (!coins.GetName(name, data)) {
assert (false);
}
assert (!data.isExpired (nHeight + 1));
#endif
}
}
assert(nameRegs.size() == mapNamespaceRegs.size());
assert(namespaceKeyUpdates.size() == mapNamespaceUpdates.size());
/* Check that nameRegs and nameUpdates are disjoint. They must be since
a name can only be in either category, depending on whether it exists
at the moment or not. */
#if 0
// Is this neccesary?
for (const auto& nameSpace : nameRegs) {
assert(namespaceKeyUpdates.count(name) == 0);
}
#endif
for (const auto& nameSpace : namespaceKeyUpdates) {
assert(nameRegs.count(nameSpace) == 0);
}
}
bool CKevaMemPool::validateNamespace(const CTransaction& tx, const valtype& nameSpace) const bool CKevaMemPool::validateNamespace(const CTransaction& tx, const valtype& nameSpace) const
{ {
valtype kevaNamespace = ToByteVector(Hash160(ToByteVector(tx.vin[0].prevout.hash))); valtype kevaNamespace = ToByteVector(Hash160(ToByteVector(tx.vin[0].prevout.hash)));
@ -231,13 +148,10 @@ CKevaMemPool::checkTx (const CTransaction& tx) const
{ {
AssertLockHeld (pool.cs); AssertLockHeld (pool.cs);
if (!tx.IsKevacoin ()) if (!tx.IsKevacoin ()) {
return true; return true;
}
/* In principle, multiple name_updates could be performed within the
mempool at once (building upon each other). This is disallowed, though,
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) { for (const auto& txout : tx.vout) {
const CKevaScript nameOp(txout.scriptPubKey); const CKevaScript nameOp(txout.scriptPubKey);
if (!nameOp.isKevaOp ()) if (!nameOp.isKevaOp ())
@ -247,10 +161,6 @@ CKevaMemPool::checkTx (const CTransaction& tx) const
{ {
const valtype& nameSpace = nameOp.getOpNamespace(); const valtype& nameSpace = nameOp.getOpNamespace();
std::map<valtype, uint256>::const_iterator mi; std::map<valtype, uint256>::const_iterator mi;
mi = mapNamespaceRegs.find(nameSpace);
if (mi != mapNamespaceRegs.end ()) {
return false;
}
if (!validateNamespace(tx, nameSpace)) { if (!validateNamespace(tx, nameSpace)) {
return false; return false;
} }
@ -259,11 +169,6 @@ CKevaMemPool::checkTx (const CTransaction& tx) const
case OP_KEVA_PUT: case OP_KEVA_PUT:
{ {
const valtype& nameSpace = nameOp.getOpNamespace();
const valtype& key = nameOp.getOpKey();
if (updatesNamespace(nameSpace)) {
return false;
}
break; break;
} }
@ -320,18 +225,12 @@ CheckKevaTransaction (const CTransaction& tx, unsigned nHeight,
{ {
const std::string strTxid = tx.GetHash ().GetHex (); const std::string strTxid = tx.GetHash ().GetHex ();
const char* txid = strTxid.c_str (); const char* txid = strTxid.c_str ();
const bool fMempool = (flags & SCRIPT_VERIFY_KEVA_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 /*
As a first step, try to locate inputs and outputs of the transaction
that are keva scripts. At most one input and output should be that are keva scripts. At most one input and output should be
a keva operation. */ a keva operation.
*/
int nameIn = -1; int nameIn = -1;
CKevaScript nameOpIn; CKevaScript nameOpIn;
@ -360,67 +259,39 @@ CheckKevaTransaction (const CTransaction& tx, unsigned nHeight,
const CKevaScript op(tx.vout[i].scriptPubKey); const CKevaScript op(tx.vout[i].scriptPubKey);
if (op.isKevaOp()) { if (op.isKevaOp()) {
if (nameOut != -1) { if (nameOut != -1) {
return state.Invalid (error ("%s: multiple name outputs from" return state.Invalid(error("%s: multiple name outputs from transaction %s", __func__, txid));
" transaction %s", __func__, txid));
} }
nameOut = i; nameOut = i;
nameOpOut = op; 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 Check that no keva inputs/outputs are present for a non-Kevacoin tx.
should be at least an output (for NAME_NEW, no inputs are expected). */ If that's the case, all is fine. For a kevacoin tx instead, there
should be at least an output.
*/
if (!tx.IsKevacoin()) { if (!tx.IsKevacoin()) {
if (nameIn != -1) if (nameIn != -1) {
return state.Invalid (error ("%s: non-Kevacoin tx %s has keva inputs", return state.Invalid(error("%s: non-Kevacoin tx %s has keva inputs", __func__, txid));
__func__, txid)); }
if (nameOut != -1) if (nameOut != -1) {
return state.Invalid (error ("%s: non-Kevacoin tx %s at height %u" return state.Invalid (error ("%s: non-Kevacoin tx %s at height %u has keva outputs",
" has keva outputs",
__func__, txid, nHeight)); __func__, txid, nHeight));
}
return true; return true;
} }
assert(tx.IsKevacoin ()); assert(tx.IsKevacoin ());
if (nameOut == -1) if (nameOut == -1) {
return state.Invalid (error ("%s: Kevacoin tx %s has no keva outputs", return state.Invalid (error ("%s: Kevacoin tx %s has no keva outputs", __func__, txid));
__func__, txid)); }
/* Reject "greedy names". */ /* Reject "greedy names". */
#if 0
const Consensus::Params& params = Params ().GetConsensus ();
if (tx.vout[nameOut].nValue < params.rules->MinNameCoinAmount(nHeight)) {
return state.Invalid (error ("%s: greedy name", __func__));
}
#else
if (tx.vout[nameOut].nValue < KEVA_LOCKED_AMOUNT) { if (tx.vout[nameOut].nValue < KEVA_LOCKED_AMOUNT) {
return state.Invalid (error ("%s: greedy name", __func__)); return state.Invalid (error ("%s: greedy name", __func__));
} }
#endif
#if 0
/* Handle NAME_NEW now, since this is easy and different from the other
operations. */
if (nameOpOut.getNameOp () == OP_NAME_NEW)
{
if (nameIn != -1)
return state.Invalid (error ("CheckKevaTransaction: NAME_NEW with"
" previous name input"));
if (nameOpOut.getOpHash ().size () != 20)
return state.Invalid (error ("CheckKevaTransaction: NAME_NEW's hash"
" has wrong size"));
return true;
}
/* Now that we have ruled out NAME_NEW, check that we have a previous
name input that is being updated. */
#endif
if (nameOpOut.isNamespaceRegistration()) { if (nameOpOut.isNamespaceRegistration()) {
if (nameOpOut.getOpNamespaceDisplayName().size () > MAX_VALUE_LENGTH) { if (nameOpOut.getOpNamespaceDisplayName().size () > MAX_VALUE_LENGTH) {
@ -430,6 +301,7 @@ CheckKevaTransaction (const CTransaction& tx, unsigned nHeight,
} }
assert(nameOpOut.isAnyUpdate()); assert(nameOpOut.isAnyUpdate());
if (nameIn == -1) { if (nameIn == -1) {
return state.Invalid(error("CheckKevaTransaction: update without previous keva input")); return state.Invalid(error("CheckKevaTransaction: update without previous keva input"));
} }
@ -451,82 +323,9 @@ CheckKevaTransaction (const CTransaction& tx, unsigned nHeight,
} }
if (nameSpace != nameOpIn.getOpNamespace()) { if (nameSpace != nameOpIn.getOpNamespace()) {
return state.Invalid (error ("%s: KEVA_PUT namespace mismatch to prev tx" return state.Invalid(error("%s: KEVA_PUT namespace mismatch to prev tx found in %s", __func__, txid));
" found in %s", __func__, txid));
}
CKevaData oldName;
const valtype& namespaceIn = nameOpIn.getOpNamespace();
if (!view.GetNamespace(namespaceIn, oldName)) {
return state.Invalid (error ("%s: Namespace not found", __func__));
}
assert (tx.vin[nameIn].prevout == oldName.getUpdateOutpoint());
#if 0
/* 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 (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());
#endif
return true;
} }
#if 0
/* Finally, NAME_FIRSTUPDATE. */
assert(nameOpOut.getNameOp () == OP_NAME_FIRSTUPDATE);
if (nameOpIn.getNameOp () != OP_NAME_NEW)
return state.Invalid (error ("CheckKevaTransaction: NAME_FIRSTUPDATE"
" with non-NAME_NEW prev tx"));
/* Maturity of NAME_NEW is checked only if we're not adding
to the mempool. */
if (!fMempool)
{
assert (static_cast<unsigned> (coinIn.nHeight) != MEMPOOL_HEIGHT);
if (coinIn.nHeight + MIN_FIRSTUPDATE_DEPTH > nHeight)
return state.Invalid (error ("CheckKevaTransaction: NAME_NEW"
" is not mature for FIRST_UPDATE"));
} }
if (nameOpOut.getOpRand ().size () > 20)
return state.Invalid (error ("CheckKevaTransaction: NAME_FIRSTUPDATE"
" rand too large, %d bytes",
nameOpOut.getOpRand ().size ()));
{
valtype toHash(nameOpOut.getOpRand ());
toHash.insert (toHash.end (), name.begin (), name.end ());
const uint160 hash = Hash160 (toHash);
if (hash != uint160 (nameOpIn.getOpHash ()))
return state.Invalid (error ("CheckKevaTransaction: NAME_FIRSTUPDATE"
" hash mismatch"));
}
CNameData oldName;
if (view.GetName (name, oldName) && !oldName.isExpired (nHeight))
return state.Invalid (error ("CheckKevaTransaction: NAME_FIRSTUPDATE"
" on an unexpired name"));
/* 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; return true;
} }
@ -578,128 +377,6 @@ void ApplyNameTransaction(const CTransaction& tx, unsigned nHeight,
} }
} }
#if 0
bool
ExpireNames (unsigned nHeight, CCoinsViewCache& view, CBlockUndo& undo,
std::set<valtype>& names)
{
names.clear ();
/* The genesis block contains no name expirations. */
if (nHeight == 0)
return true;
/* Otherwise, find out at which update heights names have expired
since the last block. If the expiration depth changes, this could
be multiple heights at once. */
const Consensus::Params& params = Params ().GetConsensus ();
const unsigned expDepthOld = params.rules->NameExpirationDepth (nHeight - 1);
const unsigned expDepthNow = params.rules->NameExpirationDepth (nHeight);
if (expDepthNow > nHeight)
return true;
/* Both are inclusive! The last expireTo was nHeight - 1 - expDepthOld,
now we start at this value + 1. */
const unsigned expireFrom = nHeight - expDepthOld;
const unsigned expireTo = nHeight - expDepthNow;
/* It is possible that expireFrom = expireTo + 1, in case that the
expiration period is raised together with the block height. In this
case, no names expire in the current step. This case means that
the absolute expiration height "n - expirationDepth(n)" is
flat -- which is fine. */
assert (expireFrom <= expireTo + 1);
/* Find all names that expire at those depths. Note that GetNamesForHeight
clears the output set, to we union all sets here. */
for (unsigned h = expireFrom; h <= expireTo; ++h)
{
std::set<valtype> newNames;
view.GetNamesForHeight (h, newNames);
names.insert (newNames.begin (), newNames.end ());
}
/* Expire all those names. */
for (std::set<valtype>::const_iterator i = names.begin ();
i != names.end (); ++i)
{
const std::string nameStr = ValtypeToString (*i);
CNameData data;
if (!view.GetName (*i, data))
return error ("%s : name '%s' not found in the database",
__func__, nameStr.c_str ());
if (!data.isExpired (nHeight))
return error ("%s : name '%s' is not actually expired",
__func__, nameStr.c_str ());
/* Special rule: When d/postmortem expires (the name used by
libcoin in the name-stealing demonstration), it's coin
is already spent. Ignore. */
if (nHeight == 175868 && nameStr == "d/postmortem")
continue;
const COutPoint& out = data.getUpdateOutpoint ();
Coin coin;
if (!view.GetCoin(out, coin))
return error ("%s : name coin for '%s' is not available",
__func__, nameStr.c_str ());
const CNameScript nameOp(coin.out.scriptPubKey);
if (!nameOp.isNameOp () || !nameOp.isAnyUpdate ()
|| nameOp.getOpName () != *i)
return error ("%s : name coin to be expired is wrong script", __func__);
if (!view.SpendCoin (out, &coin))
return error ("%s : spending name coin failed", __func__);
undo.vexpired.push_back (coin);
}
return true;
}
bool
UnexpireNames (unsigned nHeight, CBlockUndo& undo, CCoinsViewCache& view,
std::set<valtype>& names)
{
names.clear ();
/* The genesis block contains no name expirations. */
if (nHeight == 0)
return true;
std::vector<Coin>::reverse_iterator i;
for (i = undo.vexpired.rbegin (); i != undo.vexpired.rend (); ++i)
{
const CNameScript nameOp(i->out.scriptPubKey);
if (!nameOp.isNameOp () || !nameOp.isAnyUpdate ())
return error ("%s : wrong script to be unexpired", __func__);
const valtype& name = nameOp.getOpName ();
if (names.count (name) > 0)
return error ("%s : name '%s' unexpired twice",
__func__, ValtypeToString (name).c_str ());
names.insert (name);
CNameData data;
if (!view.GetName (nameOp.getOpName (), data))
return error ("%s : no data for name '%s' to be unexpired",
__func__, ValtypeToString (name).c_str ());
if (!data.isExpired (nHeight) || data.isExpired (nHeight - 1))
return error ("%s : name '%s' to be unexpired is not expired in the DB"
" or it was already expired before the current height",
__func__, ValtypeToString (name).c_str ());
if (ApplyTxInUndo (std::move(*i), view,
data.getUpdateOutpoint ()) != DISCONNECT_OK)
return error ("%s : failed to undo name coin spending", __func__);
}
return true;
}
#endif
void void
CheckNameDB (bool disconnect) CheckNameDB (bool disconnect)
{ {

76
src/keva/main.h

@ -111,31 +111,6 @@ private:
/** The parent mempool object. Used to, e. g., remove conflicting tx. */ /** The parent mempool object. Used to, e. g., remove conflicting tx. */
CTxMemPool& pool; CTxMemPool& pool;
/** Type used for internal indices. */
typedef std::map<valtype, uint256> NamespaceTxMap;
/** Type used for indexing Tx */
typedef std::tuple<valtype, valtype> NamespaceKeyTuple;
/** Type used for internal indices. */
typedef std::map<NamespaceKeyTuple, uint256> NamespaceKeyTxMap;
/**
* Keep track of namespaces that are registered by transactions in the pool.
* Map name to registering transaction.
*/
NamespaceTxMap mapNamespaceRegs;
/** Map pending name updates to transaction IDs. */
//NamespaceTxMap mapNamespaceUpdates;
/**
* Keep track of key that are updated by transactions in the pool.
* Map key to registering transaction.
*/
NamespaceTxMap mapNamespaceUpdates;
/** /**
* Pending/unconfirmed namespaces. * Pending/unconfirmed namespaces.
* Tuple: txid, namespace, display name * Tuple: txid, namespace, display name
@ -159,52 +134,15 @@ public:
* Construct with reference to parent mempool. * Construct with reference to parent mempool.
* @param p The parent pool. * @param p The parent pool.
*/ */
explicit inline CKevaMemPool (CTxMemPool& p) explicit inline CKevaMemPool (CTxMemPool& p) : pool(p) {}
: pool(p), mapNamespaceRegs()
{}
/**
* Check whether a particular namespace is being registered by
* some transaction in the mempool. Does not lock, this is
* done by the parent mempool (which calls through afterwards).
* @param name The name to check for.
* @return True iff there's a matching namespace registration in the pool.
*/
inline bool
registersNamespace (const valtype& nameSpace) const
{
return mapNamespaceRegs.count(nameSpace) > 0;
}
/**
* Check whether a particular namespace has a pending update. Does not lock.
* @param name The namespace to check for.
* @return True iff there's a matching namespace update in the pool.
*/
inline bool
updatesNamespace(const valtype& nameSpace) const
{
return mapNamespaceUpdates.count(nameSpace) > 0;
}
/**
* Return txid of transaction registering or updating a name. The returned
* txid is null if no such tx exists.
* @param name The name to check for.
* @return The txid that registers/updates it. Null if none.
*/
uint256 getTxForNamespace(const valtype& nameSpace) const;
uint256 getTxForNamespaceKey(const valtype& nameSpace, const valtype& key) const;
/** /**
* Clear all data. * Clear all data.
*/ */
inline void inline void clear ()
clear ()
{ {
mapNamespaceRegs.clear(); listUnconfirmedNamespaces.clear();
mapNamespaceUpdates.clear(); listUnconfirmedKeyValues.clear();
} }
/** /**
@ -230,12 +168,6 @@ public:
*/ */
void removeConflicts (const CTransaction& tx); void removeConflicts (const CTransaction& tx);
/**
* Perform sanity checks. Throws if it fails.
* @param coins The coins view this represents.
*/
void check (const CCoinsView& coins) const;
/** /**
* Check if a tx can be added (based on name criteria) without * Check if a tx can be added (based on name criteria) without
* causing a conflict. * causing a conflict.

18
src/txmempool.h

@ -675,24 +675,6 @@ public:
return (mapTx.count(hash) != 0); return (mapTx.count(hash) != 0);
} }
inline bool registersNamespace(const valtype& nameSpace) const
{
AssertLockHeld(cs);
return kevaMemPool.registersNamespace(nameSpace);
}
inline bool updatesNamespace(const valtype& nameSpace) const
{
AssertLockHeld(cs);
return kevaMemPool.updatesNamespace(nameSpace);
}
inline uint256 getTxForNamespace(const valtype& name) const
{
AssertLockHeld(cs);
return kevaMemPool.getTxForNamespace(name);
}
/** /**
* Check if a tx can be added to it according to name criteria. * Check if a tx can be added to it according to name criteria.
* (The non-name criteria are checked in main.cpp and not here, we * (The non-name criteria are checked in main.cpp and not here, we

29
src/wallet/rpckeva.cpp

@ -244,33 +244,16 @@ UniValue keva_put(const JSONRPCRequest& request)
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");
/* Reject updates to a name for which the mempool already has EnsureWalletIsUnlocked(pwallet);
a pending update. This is not a hard rule enforced by network
rules, but it is necessary with the current mempool implementation. */
{
LOCK (mempool.cs);
if (mempool.updatesNamespace(nameSpace)) {
throw JSONRPCError (RPC_TRANSACTION_ERROR,
"there is already a pending update for this name");
}
}
CKevaData oldData; COutput output;
{ std::string kevaNamespce = namespaceStr;
LOCK (cs_main); if (!pwallet->FindKevaCoin(output, kevaNamespce)) {
if (!pcoinsTip->GetNamespace(nameSpace, oldData)) { throw JSONRPCError (RPC_TRANSACTION_ERROR, "this name can not be updated");
throw JSONRPCError (RPC_TRANSACTION_ERROR,
"this name can not be updated");
}
} }
const COutPoint outp(output.tx->GetHash(), output.i);
const COutPoint outp = oldData.getUpdateOutpoint();
const CTxIn txIn(outp); const CTxIn txIn(outp);
/* No more locking required, similarly to name_new. */
EnsureWalletIsUnlocked(pwallet);
CReserveKey keyName(pwallet); CReserveKey keyName(pwallet);
CPubKey pubKeyReserve; CPubKey pubKeyReserve;
const bool ok = keyName.GetReservedKey(pubKeyReserve, true); const bool ok = keyName.GetReservedKey(pubKeyReserve, true);

Loading…
Cancel
Save