mirror of
https://github.com/kvazar-network/kevacoin.git
synced 2025-01-14 09:08:11 +00:00
Cleaned up code - removed dead code from namecoin.
Removed lots of legacy checks from namecoin.
This commit is contained in:
parent
a875d1ca34
commit
11c740f549
@ -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)));
|
||||||
@ -227,17 +144,14 @@ bool CKevaMemPool::validateNamespace(const CTransaction& tx, const valtype& name
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CKevaMemPool::checkTx (const CTransaction& tx) const
|
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,33 +225,27 @@ 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. */
|
As a first step, try to locate inputs and outputs of the transaction
|
||||||
CChainParams::BugType type;
|
that are keva scripts. At most one input and output should be
|
||||||
if (Params ().IsHistoricBug (tx.GetHash (), nHeight, type))
|
a keva operation.
|
||||||
return true;
|
*/
|
||||||
#endif
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
a keva operation. */
|
|
||||||
|
|
||||||
int nameIn = -1;
|
int nameIn = -1;
|
||||||
CKevaScript nameOpIn;
|
CKevaScript nameOpIn;
|
||||||
Coin coinIn;
|
Coin coinIn;
|
||||||
for (unsigned i = 0; i < tx.vin.size (); ++i) {
|
for (unsigned i = 0; i < tx.vin.size(); ++i) {
|
||||||
const COutPoint& prevout = tx.vin[i].prevout;
|
const COutPoint& prevout = tx.vin[i].prevout;
|
||||||
Coin coin;
|
Coin coin;
|
||||||
if (!view.GetCoin (prevout, coin)) {
|
if (!view.GetCoin(prevout, coin)) {
|
||||||
return error ("%s: failed to fetch input coin for %s", __func__, txid);
|
return error("%s: failed to fetch input coin for %s", __func__, txid);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CKevaScript op(coin.out.scriptPubKey);
|
const CKevaScript op(coin.out.scriptPubKey);
|
||||||
if (op.isKevaOp()) {
|
if (op.isKevaOp()) {
|
||||||
if (nameIn != -1) {
|
if (nameIn != -1) {
|
||||||
return state.Invalid (error ("%s: multiple name inputs into transaction %s", __func__, txid));
|
return state.Invalid(error("%s: multiple name inputs into transaction %s", __func__, txid));
|
||||||
}
|
}
|
||||||
nameIn = i;
|
nameIn = i;
|
||||||
nameOpIn = op;
|
nameOpIn = op;
|
||||||
@ -356,71 +255,43 @@ CheckKevaTransaction (const CTransaction& tx, unsigned nHeight,
|
|||||||
|
|
||||||
int nameOut = -1;
|
int nameOut = -1;
|
||||||
CKevaScript nameOpOut;
|
CKevaScript nameOpOut;
|
||||||
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 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 (nameIn != -1)
|
|
||||||
return state.Invalid (error ("%s: non-Kevacoin tx %s has keva inputs",
|
|
||||||
__func__, txid));
|
|
||||||
if (nameOut != -1)
|
|
||||||
return state.Invalid (error ("%s: non-Kevacoin tx %s at height %u"
|
|
||||||
" has keva outputs",
|
|
||||||
__func__, txid, nHeight));
|
|
||||||
|
|
||||||
|
if (!tx.IsKevacoin()) {
|
||||||
|
if (nameIn != -1) {
|
||||||
|
return state.Invalid(error("%s: non-Kevacoin tx %s has keva inputs", __func__, txid));
|
||||||
|
}
|
||||||
|
if (nameOut != -1) {
|
||||||
|
return state.Invalid (error ("%s: non-Kevacoin tx %s at height %u has keva outputs",
|
||||||
|
__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) {
|
||||||
@ -429,7 +300,8 @@ CheckKevaTransaction (const CTransaction& tx, unsigned nHeight,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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
|
|
||||||
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;
|
|
||||||
{
|
|
||||||
LOCK (cs_main);
|
|
||||||
if (!pcoinsTip->GetNamespace(nameSpace, oldData)) {
|
|
||||||
throw JSONRPCError (RPC_TRANSACTION_ERROR,
|
|
||||||
"this name can not be updated");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const COutPoint outp = oldData.getUpdateOutpoint();
|
|
||||||
const CTxIn txIn(outp);
|
|
||||||
|
|
||||||
/* No more locking required, similarly to name_new. */
|
|
||||||
|
|
||||||
EnsureWalletIsUnlocked(pwallet);
|
EnsureWalletIsUnlocked(pwallet);
|
||||||
|
|
||||||
|
COutput output;
|
||||||
|
std::string kevaNamespce = namespaceStr;
|
||||||
|
if (!pwallet->FindKevaCoin(output, kevaNamespce)) {
|
||||||
|
throw JSONRPCError (RPC_TRANSACTION_ERROR, "this name can not be updated");
|
||||||
|
}
|
||||||
|
const COutPoint outp(output.tx->GetHash(), output.i);
|
||||||
|
const CTxIn txIn(outp);
|
||||||
|
|
||||||
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…
Reference in New Issue
Block a user