Rudimentary Claimtrie node leak fixes to fix test corruption.

Misc cleanups and code improvements.
Additional updates from Brannon's branch.
This commit is contained in:
lbrynaut 2019-04-22 07:41:08 -05:00
parent 6dd2df3a0c
commit da42a0516c
12 changed files with 1019 additions and 491 deletions

View file

@ -5,7 +5,7 @@ define(_CLIENT_VERSION_MINOR, 17)
define(_CLIENT_VERSION_REVISION, 1)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2018)
define(_COPYRIGHT_YEAR, 2019)
define(_COPYRIGHT_HOLDERS,[The %s developers])
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[LBRYcrd Core]])
AC_INIT([LBRYcrd Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/bitcoin/bitcoin/issues],[bitcoin],[https://bitcoincore.org/])
@ -14,7 +14,7 @@ AC_CONFIG_HEADERS([src/config/bitcoin-config.h])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4])
BITCOIN_DAEMON_NAME=lbrycrd
BITCOIN_DAEMON_NAME=lbrycrdd
BITCOIN_GUI_NAME=lbrycrd-qt
BITCOIN_CLI_NAME=lbrycrd-cli
BITCOIN_TX_NAME=lbrycrd-tx

View file

@ -6,6 +6,9 @@
#include <algorithm>
#include <boost/scoped_ptr.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
boost::ptr_vector<CClaimTrieNode> nodes;
static const std::string rootClaimName = "";
static const std::string rootClaimHash = "0000000000000000000000000000000000000000000000000000000000000001";
@ -94,14 +97,10 @@ bool CClaimTrieNode::removeClaim(const COutPoint& outPoint, CClaimValue& claim)
bool CClaimTrieNode::getBestClaim(CClaimValue& claim) const
{
if (claims.empty())
{
return false;
}
else
{
claim = claims.front();
return true;
}
claim = claims.front();
return true;
}
bool CClaimTrieNode::haveClaim(const COutPoint& outPoint) const
@ -119,9 +118,7 @@ void CClaimTrieNode::reorderClaims(supportMapEntryType& supports)
std::vector<CClaimValue>::iterator itclaim;
for (itclaim = claims.begin(); itclaim != claims.end(); ++itclaim)
{
itclaim->nEffectiveAmount = itclaim->nAmount;
}
for (supportMapEntryType::iterator itsupport = supports.begin(); itsupport != supports.end(); ++itsupport)
{
@ -148,7 +145,7 @@ bool CClaimTrie::empty() const
return root.empty();
}
template<typename K> bool CClaimTrie::keyTypeEmpty(char keyType, K& dummy) const
template<typename K> bool CClaimTrie::keyTypeEmpty(char keyType, K& /* throwaway */) const
{
boost::scoped_ptr<CDBIterator> pcursor(const_cast<CDBWrapper*>(&db)->NewIterator());
pcursor->SeekToFirst();
@ -156,17 +153,12 @@ template<typename K> bool CClaimTrie::keyTypeEmpty(char keyType, K& dummy) const
while (pcursor->Valid())
{
std::pair<char, K> key;
if (pcursor->GetKey(key))
{
if (key.first == keyType)
{
return false;
}
}
else
{
if (!pcursor->GetKey(key))
break;
}
if (key.first == keyType)
return false;
pcursor->Next();
}
return true;
@ -179,8 +171,8 @@ bool CClaimTrie::queueEmpty() const
if (!itRow->second.empty())
return false;
}
int dummy;
return keyTypeEmpty(CLAIM_QUEUE_ROW, dummy);
int throwaway;
return keyTypeEmpty(CLAIM_QUEUE_ROW, throwaway);
}
bool CClaimTrie::expirationQueueEmpty() const
@ -190,8 +182,8 @@ bool CClaimTrie::expirationQueueEmpty() const
if (!itRow->second.empty())
return false;
}
int dummy;
return keyTypeEmpty(EXP_QUEUE_ROW, dummy);
int throwaway;
return keyTypeEmpty(EXP_QUEUE_ROW, throwaway);
}
bool CClaimTrie::supportEmpty() const
@ -201,8 +193,8 @@ bool CClaimTrie::supportEmpty() const
if (!itNode->second.empty())
return false;
}
std::string dummy;
return keyTypeEmpty(SUPPORT, dummy);
std::string throwaway;
return keyTypeEmpty(SUPPORT, throwaway);
}
bool CClaimTrie::supportQueueEmpty() const
@ -212,8 +204,8 @@ bool CClaimTrie::supportQueueEmpty() const
if (!itRow->second.empty())
return false;
}
int dummy;
return keyTypeEmpty(SUPPORT_QUEUE_ROW, dummy);
int throwaway;
return keyTypeEmpty(SUPPORT_QUEUE_ROW, throwaway);
}
void CClaimTrie::setExpirationTime(int t)
@ -232,7 +224,17 @@ void CClaimTrie::clear(CClaimTrieNode* current)
for (nodeMapType::const_iterator itchildren = current->children.begin(); itchildren != current->children.end(); ++itchildren)
{
clear(itchildren->second);
delete itchildren->second;
auto matcher = [&itchildren](const CClaimTrieNode& a)
{
return const_cast<CClaimTrieNode*>(&a) == itchildren->second;
};
auto it = std::find_if(nodes.begin(), nodes.end(), matcher);
if (it != nodes.end())
nodes.erase(it);
else
delete itchildren->second;
}
current->children.clear();
}
@ -254,9 +256,8 @@ bool CClaimTrie::haveSupport(const std::string& name, const COutPoint& outPoint)
{
supportMapEntryType node;
if (!getSupportNode(name, node))
{
return false;
}
for (supportMapEntryType::const_iterator itnode = node.begin(); itnode != node.end(); ++itnode)
{
if (itnode->outPoint == outPoint)
@ -308,9 +309,8 @@ bool CClaimTrie::haveSupportInQueue(const std::string& name, const COutPoint& ou
{
queueNameRowType nameRow;
if (!getSupportQueueNameRow(name, nameRow))
{
return false;
}
queueNameRowType::const_iterator itNameRow;
for (itNameRow = nameRow.begin(); itNameRow != nameRow.end(); ++itNameRow)
{
@ -321,9 +321,8 @@ bool CClaimTrie::haveSupportInQueue(const std::string& name, const COutPoint& ou
}
}
if (itNameRow == nameRow.end())
{
return false;
}
supportQueueRowType row;
if (getSupportQueueRow(nValidAtHeight, row))
{
@ -407,7 +406,7 @@ CAmount CClaimTrie::getTotalValueOfClaimsRecursive(const CClaimTrieNode* current
const CClaimTrieNode* CClaimTrie::getNodeForName(const std::string& name) const
{
const CClaimTrieNode* current = &root;
auto current = const_cast<CClaimTrieNode*>(&root);
for (std::string::const_iterator itname = name.begin(); itname != name.end(); ++itname)
{
nodeMapType::const_iterator itchildren = current->children.find(*itname);
@ -421,11 +420,7 @@ const CClaimTrieNode* CClaimTrie::getNodeForName(const std::string& name) const
bool CClaimTrie::getInfoForName(const std::string& name, CClaimValue& claim) const
{
const CClaimTrieNode* current = getNodeForName(name);
if (current)
{
return current->getBestClaim(claim);
}
return false;
return current ? current->getBestClaim(claim) : false;
}
bool CClaimTrie::getLastTakeoverForName(const std::string& name, int& lastTakeoverHeight) const
@ -448,9 +443,7 @@ std::vector<CClaimValue> CClaimTrie::getClaimsForName(const std::string& name) c
bool CClaimTrie::checkConsistency() const
{
if (empty())
return true;
return recursiveCheckConsistency(&root);
return empty() ? true : recursiveCheckConsistency(&root);
}
bool CClaimTrie::recursiveCheckConsistency(const CClaimTrieNode* node) const
@ -459,13 +452,11 @@ bool CClaimTrie::recursiveCheckConsistency(const CClaimTrieNode* node) const
for (nodeMapType::const_iterator it = node->children.begin(); it != node->children.end(); ++it)
{
if (recursiveCheckConsistency(it->second))
{
vchToHash.push_back(it->first);
vchToHash.insert(vchToHash.end(), it->second->hash.begin(), it->second->hash.end());
}
else
if (!recursiveCheckConsistency(it->second))
return false;
vchToHash.push_back(it->first);
vchToHash.insert(vchToHash.end(), it->second->hash.begin(), it->second->hash.end());
}
CClaimValue claim;
@ -499,14 +490,15 @@ bool CClaimTrie::getClaimById(const uint160 claimId, std::string& name, CClaimVa
CClaimIndexElement element;
if (db.Read(std::make_pair(CLAIM_BY_ID, claimId), element))
{
if (element.claim.claimId == claimId) {
if (element.claim.claimId == claimId)
{
name = element.name;
claim = element.claim;
return true;
} else {
LogPrintf("%s: ClaimIndex[%s] returned unmatched claimId %s when looking for %s\n",
__func__, claimId.GetHex(), element.claim.claimId.GetHex(), name);
}
LogPrintf("%s: ClaimIndex[%s] returned unmatched claimId %s when looking for %s\n",
__func__, claimId.GetHex(), element.claim.claimId.GetHex(), name);
}
return false;
}
@ -761,14 +753,13 @@ bool CClaimTrie::updateName(const std::string &name, CClaimTrieNode* updatedNode
nodeMapType::iterator itchild = current->children.find(*itname);
if (itchild == current->children.end())
{
if (itname + 1 == name.end())
{
CClaimTrieNode* newNode = new CClaimTrieNode();
current->children[*itname] = newNode;
current = newNode;
}
else
if (itname + 1 != name.end())
return false;
nodes.push_back(new CClaimTrieNode());
CClaimTrieNode& newNode = nodes[nodes.size() - 1];
current->children[*itname] = &newNode;
current = &newNode;
}
else
{
@ -792,7 +783,9 @@ bool CClaimTrie::updateName(const std::string &name, CClaimTrieNode* updatedNode
current->children.erase(itchild++);
}
else
{
++itchild;
}
}
return true;
}
@ -809,7 +802,17 @@ bool CClaimTrie::recursiveNullify(CClaimTrieNode* node, const std::string& name)
}
node->children.clear();
markNodeDirty(name, nullptr);
delete node;
auto matcher = [node](const CClaimTrieNode& a)
{
return const_cast<CClaimTrieNode*>(&a) == node;
};
auto it = std::find_if(nodes.begin(), nodes.end(), matcher);
if (it != nodes.end())
nodes.erase(it);
else
delete node;
return true;
}
@ -984,11 +987,11 @@ bool CClaimTrie::WriteToDisk()
return db.WriteBatch(batch);
}
bool CClaimTrie::InsertFromDisk(const std::string& name, CClaimTrieNode* node)
bool CClaimTrie::InsertFromDisk(const std::string& name, const CClaimTrieNode& node)
{
if (name.empty())
{
root = *node;
root = node;
return true;
}
CClaimTrieNode* current = &root;
@ -999,7 +1002,7 @@ bool CClaimTrie::InsertFromDisk(const std::string& name, CClaimTrieNode* node)
return false;
current = itchild->second;
}
current->children[name[name.size()-1]] = node;
current->children[name[name.size() - 1]] = const_cast<CClaimTrieNode*>(&node);
return true;
}
@ -1021,8 +1024,9 @@ bool CClaimTrie::ReadFromDisk(bool check)
{
if (key.first == TRIE_NODE)
{
CClaimTrieNode* node = new CClaimTrieNode();
if (pcursor->GetValue(*node))
nodes.push_back(new CClaimTrieNode());
const CClaimTrieNode& node = nodes[nodes.size() - 1];
if (pcursor->GetValue(const_cast<CClaimTrieNode&>(node)))
{
if (!InsertFromDisk(key.second, node))
{
@ -1054,7 +1058,8 @@ bool CClaimTrie::ReadFromDisk(bool check)
bool CClaimTrieCacheBase::recursiveComputeMerkleHash(CClaimTrieNode* tnCurrent, const std::string& sPos, bool forceCompute) const
{
if ((sPos == rootClaimName) && tnCurrent->empty()) {
if ((sPos == rootClaimName) && tnCurrent->empty())
{
cacheHashes[rootClaimName] = uint256S(rootClaimHash);
return true;
}
@ -1135,16 +1140,21 @@ bool CClaimTrieCacheBase::empty() const
CClaimTrieNode* CClaimTrieCacheBase::addNodeToCache(const std::string& position, CClaimTrieNode* original) const
{
// create a copy of the node in the cache, if new node, create empty node
CClaimTrieNode* cacheCopy = (original ? new CClaimTrieNode(*original) : new CClaimTrieNode());
cache[position] = cacheCopy;
nodes.push_back(original ? new CClaimTrieNode(*original) : new CClaimTrieNode());
CClaimTrieNode& cacheCopy = nodes[nodes.size() - 1];
cache[position] = &cacheCopy;
// check to see if there is the original node in block_originals,
// if not, add it to block_originals cache
nodeCacheType::const_iterator itOriginals = block_originals.find(position);
if (block_originals.end() == itOriginals)
block_originals[position] = (original ? new CClaimTrieNode(*original) : new CClaimTrieNode());
{
nodes.push_back(original ? new CClaimTrieNode(*original) : new CClaimTrieNode());
CClaimTrieNode& block_originalsCopy = nodes[nodes.size() - 1];
block_originals[position] = &block_originalsCopy;
}
return cacheCopy;
return &cacheCopy;
}
bool CClaimTrieCacheBase::getOriginalInfoForName(const std::string& name, CClaimValue& claim) const
@ -1320,7 +1330,9 @@ bool CClaimTrieCacheBase::recursivePruneName(CClaimTrieNode* tnCurrent, unsigned
CClaimTrieNode* tnNext = nullptr;
nodeCacheType::iterator cachedNode = cache.find(sNextSubstring);
if (cachedNode != cache.end())
{
tnNext = cachedNode->second;
}
else
{
nodeMapType::iterator childNode = tnCurrent->children.find(cNext);
@ -1370,7 +1382,17 @@ bool CClaimTrieCacheBase::recursivePruneName(CClaimTrieNode* tnCurrent, unsigned
if (cachedNode != cache.end())
{
assert(tnCurrent == cachedNode->second);
delete tnCurrent;
auto matcher = [tnCurrent](const CClaimTrieNode& a)
{
return const_cast<CClaimTrieNode*>(&a) == tnCurrent;
};
auto it = std::find_if(nodes.begin(), nodes.end(), matcher);
if (it != nodes.end())
nodes.erase(it);
else
delete tnCurrent;
cache.erase(cachedNode);
}
fNullified = true;
@ -1389,9 +1411,8 @@ claimQueueType::iterator CClaimTrieCacheBase::getQueueCacheRow(int nHeight, bool
claimQueueRowType queueRow;
// If the row exists in the base, copy its claims into the new row.
bool exists = base->getQueueRow(nHeight, queueRow);
if (!exists)
if (!createIfNotExists)
return itQueueRow;
if (!exists && !createIfNotExists)
return itQueueRow;
// Stick the new row in the cache
std::pair<claimQueueType::iterator, bool> ret;
ret = claimQueueCache.insert(std::pair<int, claimQueueRowType >(nHeight, queueRow));
@ -1410,9 +1431,8 @@ queueNameType::iterator CClaimTrieCacheBase::getQueueCacheNameRow(const std::str
queueNameRowType queueNameRow;
// If the row exists in the base, copy its claims into the new row.
bool exists = base->getQueueNameRow(name, queueNameRow);
if (!exists)
if (!createIfNotExists)
return itQueueNameRow;
if (!exists && !createIfNotExists)
return itQueueNameRow;
// Stick the new row in the cache
std::pair<queueNameType::iterator, bool> ret;
ret = claimQueueNameCache.insert(std::pair<std::string, queueNameRowType>(name, queueNameRow));
@ -1430,7 +1450,7 @@ bool CClaimTrieCacheBase::addClaim(const std::string& name, const COutPoint& out
int delayForClaim = getDelayForName(name, claimId);
CClaimValue claim(outPoint, claimId, nAmount, nHeight, nHeight + delayForClaim);
addClaimToQueues(name, claim);
CClaimIndexElement element = {name, claim};
CClaimIndexElement element = { name, claim };
claimsToAdd.push_back(element);
return true;
}
@ -1448,7 +1468,7 @@ bool CClaimTrieCacheBase::undoSpendClaim(const std::string& name, const COutPoin
return insertClaimIntoTrie(name, claim, false);
}
addClaimToQueues(name, claim);
CClaimIndexElement element = {name, claim};
CClaimIndexElement element = { name, claim };
claimsToAdd.push_back(element);
return true;
}
@ -1474,21 +1494,17 @@ bool CClaimTrieCacheBase::removeClaimFromQueue(const std::string& name, const CO
{
queueNameType::iterator itQueueNameRow = getQueueCacheNameRow(name, false);
if (itQueueNameRow == claimQueueNameCache.end())
{
return false;
}
queueNameRowType::iterator itQueueName;
for (itQueueName = itQueueNameRow->second.begin(); itQueueName != itQueueNameRow->second.end(); ++itQueueName)
{
if (itQueueName->outPoint == outPoint)
{
break;
}
}
if (itQueueName == itQueueNameRow->second.end())
{
return false;
}
claimQueueType::iterator itQueueRow = getQueueCacheRow(itQueueName->nHeight, false);
if (itQueueRow != claimQueueCache.end())
{
@ -1497,9 +1513,7 @@ bool CClaimTrieCacheBase::removeClaimFromQueue(const std::string& name, const CO
for (itQueue = itQueueRow->second.begin(); itQueue != itQueueRow->second.end(); ++itQueue)
{
if (itQueue->second.outPoint == outPoint && name == itQueue->first)
{
break;
}
}
if (itQueue != itQueueRow->second.end())
{
@ -1532,13 +1546,13 @@ bool CClaimTrieCacheBase::removeClaim(const std::string& name, const COutPoint&
nValidAtHeight = nHeight + getDelayForName(name);
std::string adjusted = adjustNameForValidHeight(name, nValidAtHeight);
if (removeClaimFromQueue(adjusted, outPoint, claim)) {
if (removeClaimFromQueue(adjusted, outPoint, claim))
// assert(claim.nValidAtHeight == nValidAtHeight); probably better to leak than to crash
removed = true;
}
if (removed == false && removeClaimFromTrie(name, outPoint, claim, fCheckTakeover)) {
if (removed == false && removeClaimFromTrie(name, outPoint, claim, fCheckTakeover))
removed = true;
}
if (removed == true)
{
int expirationHeight = claim.nHeight + base->nExpirationTime;
@ -1563,14 +1577,12 @@ void CClaimTrieCacheBase::removeFromExpirationQueue(const std::string& name, con
{
for (itQueue = itQueueRow->second.begin(); itQueue != itQueueRow->second.end(); ++itQueue)
{
if (name == itQueue->name && outPoint == itQueue->outPoint)
if (outPoint == itQueue->outPoint && name == itQueue->name)
break;
}
if (itQueue != itQueueRow->second.end())
{
itQueueRow->second.erase(itQueue);
}
}
}
@ -1583,9 +1595,8 @@ expirationQueueType::iterator CClaimTrieCacheBase::getExpirationQueueCacheRow(in
expirationQueueRowType queueRow;
// If the row exists in the base, copy its claims into the new row.
bool exists = base->getExpirationQueueRow(nHeight, queueRow);
if (!exists)
if (!createIfNotExists)
return itQueueRow;
if (!exists && !createIfNotExists)
return itQueueRow;
// Stick the new row in the cache
std::pair<expirationQueueType::iterator, bool> ret;
ret = expirationQueueCache.insert(std::pair<int, expirationQueueRowType >(nHeight, queueRow));
@ -1625,7 +1636,8 @@ bool CClaimTrieCacheBase::reorderTrieNode(const std::string& name, bool fCheckTa
return true;
}
currentNode = new CClaimTrieNode(*currentNode);
nodes.push_back(new CClaimTrieNode(*currentNode));
currentNode = &nodes[nodes.size() - 1];
std::pair<nodeCacheType::iterator, bool> ret;
ret = cache.insert(std::pair<std::string, CClaimTrieNode*>(name, currentNode));
assert(ret.second);
@ -1700,11 +1712,9 @@ bool CClaimTrieCacheBase::removeSupportFromMap(const std::string& name, const CO
if (cachedNode == supportCache.end())
{
supportMapEntryType node;
if (!base->getSupportNode(name, node))
{
// clearly, this support does not exist
if (!base->getSupportNode(name, node)) // clearly, this support does not exist
return false;
}
std::pair<supportMapType::iterator, bool> ret;
ret = supportCache.insert(std::pair<std::string, supportMapEntryType>(name, node));
assert(ret.second);
@ -1714,9 +1724,7 @@ bool CClaimTrieCacheBase::removeSupportFromMap(const std::string& name, const CO
for (itSupport = cachedNode->second.begin(); itSupport != cachedNode->second.end(); ++itSupport)
{
if (itSupport->outPoint == outPoint)
{
break;
}
}
if (itSupport != cachedNode->second.end())
{
@ -1724,11 +1732,9 @@ bool CClaimTrieCacheBase::removeSupportFromMap(const std::string& name, const CO
cachedNode->second.erase(itSupport);
return reorderTrieNode(name, fCheckTakeover);
}
else
{
LogPrintf("CClaimTrieCacheBase::%s() : asked to remove a support that doesn't exist\n", __func__);
return false;
}
LogPrintf("CClaimTrieCacheBase::%s() : asked to remove a support that doesn't exist\n", __func__);
return false;
}
supportQueueType::iterator CClaimTrieCacheBase::getSupportQueueCacheRow(int nHeight, bool createIfNotExists) const
@ -1757,9 +1763,8 @@ queueNameType::iterator CClaimTrieCacheBase::getSupportQueueCacheNameRow(const s
{
queueNameRowType queueNameRow;
bool exists = base->getSupportQueueNameRow(name, queueNameRow);
if (!exists)
if (!createIfNotExists)
return itQueueNameRow;
if (!exists && !createIfNotExists)
return itQueueNameRow;
// Stick the new row in the name cache
std::pair<queueNameType::iterator, bool> ret;
ret = supportQueueNameCache.insert(std::pair<std::string, queueNameRowType>(name, queueNameRow));
@ -1786,21 +1791,17 @@ bool CClaimTrieCacheBase::removeSupportFromQueue(const std::string& name, const
{
queueNameType::iterator itQueueNameRow = getSupportQueueCacheNameRow(name, false);
if (itQueueNameRow == supportQueueNameCache.end())
{
return false;
}
queueNameRowType::iterator itQueueName;
for (itQueueName = itQueueNameRow->second.begin(); itQueueName != itQueueNameRow->second.end(); ++itQueueName)
{
if (itQueueName->outPoint == outPoint)
{
break;
}
}
if (itQueueName == itQueueNameRow->second.end())
{
return false;
}
supportQueueType::iterator itQueueRow = getSupportQueueCacheRow(itQueueName->nHeight, false);
if (itQueueRow != supportQueueCache.end())
{
@ -1809,9 +1810,7 @@ bool CClaimTrieCacheBase::removeSupportFromQueue(const std::string& name, const
{
CSupportValue& support = itQueue->second;
if (support.outPoint == outPoint && name == itQueue->first)
{
break;
}
}
if (itQueue != itQueueRow->second.end())
{
@ -1845,10 +1844,8 @@ bool CClaimTrieCacheBase::undoSpendSupport(const std::string& name, const COutPo
addSupportToExpirationQueue(support.nHeight + base->nExpirationTime, entry);
return insertSupportIntoMap(name, support, false);
}
else
{
return addSupportToQueues(name, support);
}
return addSupportToQueues(name, support);
}
bool CClaimTrieCacheBase::removeSupport(const std::string& name, const COutPoint& outPoint, int nHeight, int& nValidAtHeight, bool fCheckTakeover) const
@ -1890,9 +1887,7 @@ void CClaimTrieCacheBase::removeSupportFromExpirationQueue(const std::string& na
}
}
if (itQueue != itQueueRow->second.end())
{
itQueueRow->second.erase(itQueue);
}
}
expirationQueueType::iterator CClaimTrieCacheBase::getSupportExpirationQueueCacheRow(int nHeight, bool createIfNotExists) const
@ -1904,9 +1899,8 @@ expirationQueueType::iterator CClaimTrieCacheBase::getSupportExpirationQueueCach
expirationQueueRowType queueRow;
// If the row exists in the base, copy its claims into the new row.
bool exists = base->getSupportExpirationQueueRow(nHeight, queueRow);
if (!exists)
if (!createIfNotExists)
return itQueueRow;
if (!exists && !createIfNotExists)
return itQueueRow;
// Stick the new row in the cache
std::pair<expirationQueueType::iterator, bool> ret;
ret = supportExpirationQueueCache.insert(std::pair<int, expirationQueueRowType >(nHeight, queueRow));
@ -2057,12 +2051,22 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimQueueR
for (nodeCacheType::const_iterator itOriginals = block_originals.begin(); itOriginals != block_originals.end(); ++itOriginals)
{
delete itOriginals->second;
auto matcher = [&itOriginals](const CClaimTrieNode& a)
{
return const_cast<CClaimTrieNode*>(&a) == itOriginals->second;
};
auto it = std::find_if(nodes.begin(), nodes.end(), matcher);
if (it != nodes.end())
nodes.erase(it);
else
delete itOriginals->second;
}
block_originals.clear();
for (nodeCacheType::const_iterator itCache = cache.begin(); itCache != cache.end(); ++itCache)
{
block_originals[itCache->first] = new CClaimTrieNode(*itCache->second);
nodes.push_back(new CClaimTrieNode(*itCache->second));
block_originals[itCache->first] = &nodes[nodes.size() - 1];
}
nCurrentHeight++;
@ -2259,12 +2263,14 @@ bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimQueueR
if (!expireUndo.empty())
{
expirationQueueType::iterator itExpireRow = getExpirationQueueCacheRow(nCurrentHeight, true);
for (claimQueueRowType::iterator itExpireUndo = expireUndo.begin(); itExpireUndo != expireUndo.end(); ++itExpireUndo)
for (claimQueueRowType::reverse_iterator itExpireUndo = expireUndo.rbegin(); itExpireUndo != expireUndo.rend(); ++itExpireUndo)
{
insertClaimIntoTrie(itExpireUndo->first, itExpireUndo->second, false);
CClaimIndexElement element = {itExpireUndo->first, itExpireUndo->second};
CClaimIndexElement element = { itExpireUndo->first, itExpireUndo->second };
claimsToAdd.push_back(element);
itExpireRow->second.push_back(nameOutPointType(itExpireUndo->first, itExpireUndo->second.outPoint));
// Check if it expired at this height rather than being a rename/normalization
if (nCurrentHeight == itExpireUndo->second.nHeight + base->nExpirationTime)
itExpireRow->second.push_back(nameOutPointType(itExpireUndo->first, itExpireUndo->second.outPoint));
}
}
@ -2300,12 +2306,22 @@ bool CClaimTrieCacheBase::finalizeDecrement() const
{
for (nodeCacheType::iterator itOriginals = block_originals.begin(); itOriginals != block_originals.end(); ++itOriginals)
{
delete itOriginals->second;
auto matcher = [&itOriginals](const CClaimTrieNode& a)
{
return const_cast<CClaimTrieNode*>(&a) == itOriginals->second;
};
auto it = std::find_if(nodes.begin(), nodes.end(), matcher);
if (it != nodes.end())
nodes.erase(it);
else
delete itOriginals->second;
}
block_originals.clear();
for (nodeCacheType::const_iterator itCache = cache.begin(); itCache != cache.end(); ++itCache)
{
block_originals[itCache->first] = new CClaimTrieNode(*itCache->second);
nodes.push_back(new CClaimTrieNode(*itCache->second));
block_originals[itCache->first] = &nodes[nodes.size() - 1];
}
return true;
}
@ -2329,7 +2345,8 @@ bool CClaimTrieCacheBase::getLastTakeoverForName(const std::string& name, int& n
int CClaimTrieCacheBase::getNumBlocksOfContinuousOwnership(const std::string& name) const
{
const CClaimTrieNode* node = getNodeForName(name);
if (!node || node->claims.empty()) return 0;
if (!node || node->claims.empty())
return 0;
int nLastTakeoverHeight;
assert(getLastTakeoverForName(name, nLastTakeoverHeight));
return nCurrentHeight - nLastTakeoverHeight;
@ -2337,8 +2354,20 @@ int CClaimTrieCacheBase::getNumBlocksOfContinuousOwnership(const std::string& na
const CClaimTrieNode* CClaimTrieCacheBase::getNodeForName(const std::string& name) const
{
/* CClaimTrieNode* node = nullptr; */
/* nodeCacheType::const_iterator itCache = cache.find(name); */
/* if (itCache != cache.end()) */
/* node = itCache->second; */
/* return (node ? node : base->getNodeForName(name)); */
const CClaimTrieNode* node = nullptr;
nodeCacheType::const_iterator itCache = cache.find(name);
return ((itCache != cache.end()) ? itCache->second : base->getNodeForName(name));
if (itCache != cache.end()) {
node = itCache->second;
}
if (!node) {
node = base->getNodeForName(name);
}
return node;
}
// "name" is already normalized if needed
@ -2364,9 +2393,8 @@ int CClaimTrieCacheBase::getDelayForName(const std::string& name, const uint160&
uint256 CClaimTrieCacheBase::getBestBlock()
{
if (hashBlock.IsNull())
if (base != nullptr)
hashBlock = base->hashBlock;
if (hashBlock.IsNull() && base != nullptr)
hashBlock = base->hashBlock;
return hashBlock;
}
@ -2379,12 +2407,30 @@ bool CClaimTrieCacheBase::clear() const
{
for (nodeCacheType::iterator itcache = cache.begin(); itcache != cache.end(); ++itcache)
{
delete itcache->second;
auto matcher = [&itcache](const CClaimTrieNode& a)
{
return const_cast<CClaimTrieNode*>(&a) == itcache->second;
};
auto it = std::find_if(nodes.begin(), nodes.end(), matcher);
if (it != nodes.end())
nodes.erase(it);
else
delete itcache->second;
}
cache.clear();
for (nodeCacheType::iterator itOriginals = block_originals.begin(); itOriginals != block_originals.end(); ++itOriginals)
{
delete itOriginals->second;
auto matcher = [&itOriginals](const CClaimTrieNode& a)
{
return const_cast<CClaimTrieNode*>(&a) == itOriginals->second;
};
auto it = std::find_if(nodes.begin(), nodes.end(), matcher);
if (it != nodes.end())
nodes.erase(it);
else
delete itOriginals->second;
}
block_originals.clear();
dirtyHashes.clear();
@ -2445,11 +2491,14 @@ void CClaimTrieCacheBase::recursiveIterateTrie(std::string& name, const CClaimTr
bool CClaimTrieCacheBase::iterateTrie(CNodeCallback& callback) const
{
try {
try
{
std::string name;
recursiveIterateTrie(name, getRoot(), callback);
assert(name.empty());
} catch (const CNodeCallback::CRecursionInterruptionException& ex) {
}
catch (const CNodeCallback::CRecursionInterruptionException& ex)
{
return ex.success;
}
return true;
@ -2459,7 +2508,8 @@ claimsForNameType CClaimTrieCacheBase::getClaimsForName(const std::string& name)
{
int nLastTakeoverHeight = 0;
std::vector<CClaimValue> claims;
if (const CClaimTrieNode* node = getNodeForName(name)) {
if (const CClaimTrieNode* node = getNodeForName(name))
{
claims = node->claims;
getLastTakeoverForName(name, nLastTakeoverHeight);
}
@ -2476,13 +2526,18 @@ CAmount CClaimTrieCacheBase::getEffectiveAmountForClaim(const std::string& name,
CAmount CClaimTrieCacheBase::getEffectiveAmountForClaim(const claimsForNameType& claims, const uint160& claimId, std::vector<CSupportValue>* supports) const
{
CAmount effectiveAmount = 0;
for (std::vector<CClaimValue>::const_iterator it = claims.claims.begin(); it != claims.claims.end(); ++it) {
if (it->claimId == claimId && it->nValidAtHeight < nCurrentHeight) {
for (std::vector<CClaimValue>::const_iterator it = claims.claims.begin(); it != claims.claims.end(); ++it)
{
if (it->claimId == claimId && it->nValidAtHeight < nCurrentHeight)
{
effectiveAmount += it->nAmount;
for (std::vector<CSupportValue>::const_iterator it = claims.supports.begin(); it != claims.supports.end(); ++it) {
if (it->supportedClaimId == claimId && it->nValidAtHeight < nCurrentHeight) {
for (std::vector<CSupportValue>::const_iterator it = claims.supports.begin(); it != claims.supports.end(); ++it)
{
if (it->supportedClaimId == claimId && it->nValidAtHeight < nCurrentHeight)
{
effectiveAmount += it->nAmount;
if (supports) supports->push_back(*it);
if (supports)
supports->push_back(*it);
}
}
break;
@ -2499,7 +2554,8 @@ bool CClaimTrieCacheBase::getInfoForName(const std::string& name, CClaimValue& c
CClaimTrieNode* current = getRoot();
nodeCacheType::const_iterator cachedNode;
for (std::string::const_iterator itName = name.begin(); current; ++itName) {
for (std::string::const_iterator itName = name.begin(); current; ++itName)
{
std::string currentPosition(name.begin(), itName);
cachedNode = cache.find(currentPosition);
if (cachedNode != cache.end())
@ -2509,9 +2565,8 @@ bool CClaimTrieCacheBase::getInfoForName(const std::string& name, CClaimValue& c
return current->getBestClaim(claim);
nodeMapType::const_iterator itChildren = current->children.find(*itName);
if (itChildren != current->children.end()) {
if (itChildren != current->children.end())
current = itChildren->second;
}
}
return false;
}

View file

@ -139,7 +139,6 @@ class CClaimTrieNode;
class CClaimTrie;
typedef std::vector<CSupportValue> supportMapEntryType;
typedef std::map<unsigned char, CClaimTrieNode*> nodeMapType;
class CClaimTrieNode
@ -150,16 +149,18 @@ public:
CClaimTrieNode(const CClaimTrieNode&) = default;
CClaimTrieNode(CClaimTrieNode&& other)
{
hash = other.hash;
hash = std::move(other.hash);
claims = std::move(other.claims);
children = std::move(other.children);
nHeightOfLastTakeover = other.nHeightOfLastTakeover;
}
CClaimTrieNode& operator=(const CClaimTrieNode&) = default;
CClaimTrieNode& operator=(CClaimTrieNode&& other)
{
if (this != &other) {
hash = other.hash;
if (this != &other)
{
hash = std::move(other.hash);
claims = std::move(other.claims);
children = std::move(other.children);
nHeightOfLastTakeover = other.nHeightOfLastTakeover;
@ -323,7 +324,7 @@ struct claimsForNameType
claimsForNameType(std::vector<CClaimValue> claims, std::vector<CSupportValue> supports,
int nLastTakeoverHeight, const std::string& name)
: claims(std::move(claims)), supports(std::move(supports)),
: claims(std::move(claims)), supports(std::move(supports)),
nLastTakeoverHeight(nLastTakeoverHeight), name(name) {}
claimsForNameType(const claimsForNameType&) = default;
@ -331,8 +332,8 @@ struct claimsForNameType
{
claims = std::move(other.claims);
supports = std::move(other.supports);
nLastTakeoverHeight = other.nLastTakeoverHeight;
name = std::move(other.name);
nLastTakeoverHeight = other.nLastTakeoverHeight;
}
claimsForNameType& operator=(const claimsForNameType&) = default;
@ -342,8 +343,8 @@ struct claimsForNameType
{
claims = std::move(other.claims);
supports = std::move(other.supports);
nLastTakeoverHeight = other.nLastTakeoverHeight;
name = std::move(other.name);
nLastTakeoverHeight = other.nLastTakeoverHeight;
}
return *this;
}
@ -358,10 +359,10 @@ class CClaimTrie
{
public:
CClaimTrie(bool fMemory = false, bool fWipe = false, int nProportionalDelayFactor = 32)
: db(GetDataDir() / "claimtrie", 100, fMemory, fWipe, false), nCurrentHeight(0),
nExpirationTime(Params().GetConsensus().nOriginalClaimExpirationTime),
nProportionalDelayFactor(nProportionalDelayFactor),
root(uint256S("0000000000000000000000000000000000000000000000000000000000000001"))
: db(GetDataDir() / "claimtrie", 100, fMemory, fWipe, false)
, nCurrentHeight(0), nExpirationTime(Params().GetConsensus().nOriginalClaimExpirationTime)
, nProportionalDelayFactor(nProportionalDelayFactor)
, root(uint256S("0000000000000000000000000000000000000000000000000000000000000001"))
{}
uint256 getMerkleHash();
@ -411,7 +412,7 @@ public:
int nExpirationTime;
int nProportionalDelayFactor;
private:
private:
void clear(CClaimTrieNode* current);
const CClaimTrieNode* getNodeForName(const std::string& name) const;
@ -432,7 +433,7 @@ public:
bool recursiveCheckConsistency(const CClaimTrieNode* node) const;
bool InsertFromDisk(const std::string& name, CClaimTrieNode* node);
bool InsertFromDisk(const std::string& name, const CClaimTrieNode& node);
unsigned int getTotalNamesRecursive(const CClaimTrieNode* current) const;
unsigned int getTotalClaimsRecursive(const CClaimTrieNode* current) const;
@ -490,25 +491,27 @@ public:
CClaimTrieProofNode() {};
CClaimTrieProofNode(std::vector<std::pair<unsigned char, uint256> > children,
bool hasValue, uint256 valHash)
: children(std::move(children)), hasValue(hasValue), valHash(valHash)
: children(std::move(children)), hasValue(hasValue), valHash(std::move(valHash))
{};
CClaimTrieProofNode(const CClaimTrieProofNode&) = default;
CClaimTrieProofNode(CClaimTrieProofNode&& other)
{
hasValue = other.hasValue;
valHash = other.valHash;
valHash = std::move(other.valHash);
children = std::move(other.children);
}
CClaimTrieProofNode& operator=(const CClaimTrieProofNode&) = default;
CClaimTrieProofNode& operator=(CClaimTrieProofNode&& other)
{
if (this != &other) {
if (this != &other)
{
hasValue = other.hasValue;
valHash = other.valHash;
valHash = std::move(other.valHash);
children = std::move(other.children);
}
return *this;
}
std::vector<std::pair<unsigned char, uint256> > children;
bool hasValue;
uint256 valHash;
@ -523,21 +526,24 @@ public:
CClaimTrieProof(CClaimTrieProof&& other)
{
hasValue = other.hasValue;
outPoint = other.outPoint;
outPoint = std::move(other.outPoint);
nodes = std::move(other.nodes);
nHeightOfLastTakeover = other.nHeightOfLastTakeover;
}
CClaimTrieProof& operator=(const CClaimTrieProof&) = default;
CClaimTrieProof& operator=(CClaimTrieProof&& other)
{
if (this != &other) {
if (this != &other)
{
hasValue = other.hasValue;
outPoint = other.outPoint;
outPoint = std::move(other.outPoint);
nodes = std::move(other.nodes);
nHeightOfLastTakeover = other.nHeightOfLastTakeover;
}
return *this;
}
std::vector<CClaimTrieProofNode> nodes;
bool hasValue;
COutPoint outPoint;
@ -569,8 +575,7 @@ class CClaimTrieCacheBase
{
public:
CClaimTrieCacheBase(CClaimTrie* base, bool fRequireTakeoverHeights = true)
: base(base),
fRequireTakeoverHeights(fRequireTakeoverHeights)
: base(base), fRequireTakeoverHeights(fRequireTakeoverHeights)
{
assert(base);
nCurrentHeight = base->nCurrentHeight;
@ -584,7 +589,7 @@ public:
CClaimTrieNode* getRoot() const
{
const nodeCacheType::iterator iter = cache.find("");
const auto iter = cache.find("");
return iter == cache.end() ? &(base->root) : iter->second;
}
@ -611,15 +616,15 @@ public:
void setBestBlock(const uint256& hashBlock);
virtual bool incrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo,
std::vector<std::pair<std::string, int> >& takeoverHeightUndo);
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo,
std::vector<std::pair<std::string, int> >& takeoverHeightUndo);
virtual bool decrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo,
std::vector<std::pair<std::string, int> >& takeoverHeightUndo);
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo,
std::vector<std::pair<std::string, int> >& takeoverHeightUndo);
virtual ~CClaimTrieCacheBase() { clear(); }
@ -632,31 +637,33 @@ public:
virtual claimsForNameType getClaimsForName(const std::string& name) const;
CAmount getEffectiveAmountForClaim(const std::string& name, const uint160& claimId, std::vector<CSupportValue>* supports = NULL) const;
CAmount getEffectiveAmountForClaim(const claimsForNameType& claims, const uint160& claimId, std::vector<CSupportValue>* supports = NULL) const;
CAmount getEffectiveAmountForClaim(const std::string& name, const uint160& claimId,
std::vector<CSupportValue>* supports = nullptr) const;
CAmount getEffectiveAmountForClaim(const claimsForNameType& claims, const uint160& claimId,
std::vector<CSupportValue>* supports = nullptr) const;
protected:
// Should be private: Do not use unless you know what you're doing.
CClaimTrieNode* addNodeToCache(const std::string& position, CClaimTrieNode* original) const;
bool recursiveComputeMerkleHash(CClaimTrieNode* tnCurrent,
const std::string& sPos,
bool forceCompute = false) const;
bool recursivePruneName(CClaimTrieNode* tnCurrent, unsigned int nPos, const std::string& sName, bool* pfNullified = NULL) const;
const std::string& sPos,
bool forceCompute = false) const;
bool recursivePruneName(CClaimTrieNode* tnCurrent, unsigned int nPos, const std::string& sName, bool* pfNullified = nullptr) const;
void checkNamesForTakeover(insertUndoType& insertUndo, insertUndoType& insertSupportUndo,
std::vector<std::pair<std::string, int> >& takeoverHeightUndo) const;
virtual bool insertClaimIntoTrie(const std::string& name, CClaimValue claim,
bool fCheckTakeover = false) const;
bool fCheckTakeover = false) const;
virtual bool removeClaimFromTrie(const std::string& name, const COutPoint& outPoint,
CClaimValue& claim,
bool fCheckTakeover = false) const;
CClaimValue& claim,
bool fCheckTakeover = false) const;
virtual bool insertSupportIntoMap(const std::string& name,
CSupportValue support,
bool fCheckTakeover) const;
CSupportValue support,
bool fCheckTakeover) const;
virtual bool removeSupportFromMap(const std::string& name, const COutPoint& outPoint,
CSupportValue& support,
bool fCheckTakeover) const;
CSupportValue& support,
bool fCheckTakeover) const;
virtual void addClaimToQueues(const std::string& name, CClaimValue& claim) const;
virtual bool addSupportToQueues(const std::string& name, CSupportValue& support) const;
@ -726,9 +733,9 @@ private:
supportQueueType::iterator getSupportQueueCacheRow(int nHeight,
bool createIfNotExists) const;
queueNameType::iterator getSupportQueueCacheNameRow(const std::string& name,
bool createIfNotExists) const;
bool createIfNotExists) const;
expirationQueueType::iterator getSupportExpirationQueueCacheRow(int nHeight,
bool createIfNotExists) const;
bool createIfNotExists) const;
bool removeSupportFromQueue(const std::string& name, const COutPoint& outPoint,
CSupportValue& support) const;
@ -749,9 +756,9 @@ private:
};
class CClaimTrieCacheExpirationFork: public CClaimTrieCacheBase {
public:
public:
CClaimTrieCacheExpirationFork(CClaimTrie* base, bool fRequireTakeoverHeights = true)
: CClaimTrieCacheBase(base, fRequireTakeoverHeights) {}
: CClaimTrieCacheBase(base, fRequireTakeoverHeights) {}
virtual ~CClaimTrieCacheExpirationFork() {}
@ -765,7 +772,7 @@ private:
};
class CClaimTrieCacheNormalizationFork: public CClaimTrieCacheExpirationFork {
public:
public:
CClaimTrieCacheNormalizationFork(CClaimTrie* base, bool fRequireTakeoverHeights = true)
: CClaimTrieCacheExpirationFork(base, fRequireTakeoverHeights),
overrideInsertNormalization(false), overrideRemoveNormalization(false) {}

View file

@ -205,10 +205,9 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(insert
if (nCurrentHeight == Params().GetConsensus().nNormalizedNameForkHeight) {
std::cout << "RUNNING NORMALIZATION NOW" << std::endl;
// run the one-time upgrade of all names that need to change
// it modifies the (cache) trie as it goes, so we need to grab everything to be modified first
// it modifies the (cache) trie as it goes, so we need to grab
// everything to be modified first
CNameChangeDetector detector(this);
iterateTrie(detector);

View file

@ -532,7 +532,7 @@ void SetupServerArgs()
std::string LicenseInfo()
{
const std::string URL_SOURCE_CODE = "<https://github.com/lbryio/lbrycrd>";
const std::string URL_WEBSITE = "<https://lbry.io>";
const std::string URL_WEBSITE = "<https://lbry.com>";
return CopyrightHolders(strprintf(_("Copyright (C) %i-%i"), 2009, COPYRIGHT_YEAR) + " ") + "\n" +
"\n" +
@ -1430,6 +1430,7 @@ bool AppInitMain()
nCoinDBCache = std::min(nCoinDBCache, nMaxCoinsDBCache << 20); // cap total coins db cache
nTotalCache -= nCoinDBCache;
nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
std::cout << "nTotalCache: " << nTotalCache << ", nCoinCacheUsage: " << nCoinCacheUsage << ", nCoinDBCache: " << nCoinDBCache << std::endl;
int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
LogPrintf("Cache configuration:\n");
LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024));

View file

@ -454,6 +454,7 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
if (DecodeClaimScript(scriptPubKey, op, vvchParams))
{
std::string name(vvchParams[0].begin(), vvchParams[0].end());
if (op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM)
{
uint160 claimId;
@ -467,7 +468,6 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
assert(vvchParams.size() == 3);
claimId = uint160(vvchParams[1]);
}
std::string name(vvchParams[0].begin(), vvchParams[0].end());
int throwaway;
if (trieCache.spendClaim(name, COutPoint(txin.prevout.hash, txin.prevout.n), coin.nHeight, throwaway))
{
@ -482,7 +482,6 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
else if (op == OP_SUPPORT_CLAIM)
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
int throwaway;
if (!trieCache.spendSupport(name, COutPoint(txin.prevout.hash, txin.prevout.n), coin.nHeight, throwaway))
{
@ -500,10 +499,10 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
int op;
if (DecodeClaimScript(txout.scriptPubKey, op, vvchParams))
{
std::string name(vvchParams[0].begin(), vvchParams[0].end());
if (op == OP_CLAIM_NAME)
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
if (!trieCache.addClaim(name, COutPoint(tx.GetHash(), i), ClaimIdHash(tx.GetHash(), i), txout.nValue, nHeight))
{
LogPrintf("%s: Something went wrong inserting the name\n", __func__);
@ -512,13 +511,12 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
else if (op == OP_UPDATE_CLAIM)
{
assert(vvchParams.size() == 3);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
uint160 claimId(vvchParams[1]);
spentClaimsType::iterator itSpent;
for (itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent)
{
if ((itSpent->first == name && itSpent->second == claimId) &&
(trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(itSpent->first)))
if (itSpent->second == claimId &&
trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(itSpent->first))
break;
}
if (itSpent != spentClaims.end())
@ -537,7 +535,6 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
else if (op == OP_SUPPORT_CLAIM)
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
uint160 supportedClaimId(vvchParams[1]);
if (!trieCache.addSupport(name, COutPoint(tx.GetHash(), i), txout.nValue, supportedClaimId, nHeight))
{

View file

@ -25,7 +25,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
// Special difficulty rule for testnet:
// If the new block's timestamp is twice the target block time
// then allow mining of a min-difficulty block.
// This is to prevent the testnet from gettig stuck when a large amount
// This is to prevent the testnet from getting stuck when a large amount
// of hashrate drops off the network.
// This rule was not implemented properly until testnet block 277299.
if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2){

View file

@ -275,7 +275,7 @@ static bool getValueForOutPoint(const CCoinsViewCache& coinsCache, const COutPoi
sValue = HexStr(vvchParams[1].begin(), vvchParams[1].end());
return true;
}
else if (op == OP_UPDATE_CLAIM)
else if (vvchParams.size() > 2) // both UPDATE and SUPPORT
{
sValue = HexStr(vvchParams[2].begin(), vvchParams[2].end());
return true;
@ -431,6 +431,7 @@ UniValue getclaimsforname(const JSONRPCRequest& request)
" \"nAmount\" (numeric) the amount of the support\n"
" \"value\" (string) the metadata of the support if any\n"
" ]\n"
" \"name\" (string) the original name of this claim before normalization\n"
" }\n"
" ],\n"
" \"supports without claims\": [ (array of object) supports that did not match a claim for this name\n"

File diff suppressed because it is too large Load diff

View file

@ -2105,10 +2105,10 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
std::vector<std::vector<unsigned char> > vvchParams;
if (DecodeClaimScript(coin.out.scriptPubKey, op, vvchParams))
{
std::string name(vvchParams[0].begin(), vvchParams[0].end());
if (op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM)
{
uint160 claimId;
std::string name(vvchParams[0].begin(), vvchParams[0].end());
std::string value(vvchParams[1].begin(), vvchParams[1].end());
if (op == OP_CLAIM_NAME)
{
@ -2141,7 +2141,6 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
else if (op == OP_SUPPORT_CLAIM)
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
uint160 supportedClaimId(vvchParams[1]);
LogPrintf("+++ %s[%lu]: OP_SUPPORT_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n",
__func__, pindex->nHeight, name,
@ -2166,10 +2165,10 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
std::vector<std::vector<unsigned char> > vvchParams;
if (DecodeClaimScript(txout.scriptPubKey, op, vvchParams))
{
std::string name(vvchParams[0].begin(), vvchParams[0].end());
if (op == OP_CLAIM_NAME)
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
LogPrintf("%s: Inserting %s into the claim trie. Tx: %s, nOut: %d\n",
__func__, name, tx.GetHash().GetHex(), j);
if (!trieCache.addClaim(name, COutPoint(tx.GetHash(), j), ClaimIdHash(tx.GetHash(), j), txout.nValue, pindex->nHeight))
@ -2180,15 +2179,14 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
else if (op == OP_UPDATE_CLAIM)
{
assert(vvchParams.size() == 3);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
uint160 claimId(vvchParams[1]);
LogPrintf("%s: Got a claim update. Name: %s, claimId: %s, new txid: %s, nOut: %d\n",
__func__, name, claimId.GetHex(), tx.GetHash().GetHex(), j);
spentClaimsType::iterator itSpent;
for (itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent)
{
if ((itSpent->first == name && itSpent->second == claimId) &&
(trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(itSpent->first)))
if (itSpent->second == claimId &&
trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(itSpent->first))
break;
}
if (itSpent != spentClaims.end())
@ -2203,7 +2201,6 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
else if (op == OP_SUPPORT_CLAIM)
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
uint160 supportedClaimId(vvchParams[1]);
if (!trieCache.addSupport(name, COutPoint(tx.GetHash(), j), txout.nValue, supportedClaimId, pindex->nHeight))
{

View file

@ -462,8 +462,9 @@ static UniValue getaddressesbyaccount(const JSONRPCRequest& request)
return ret;
}
static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue, std::string fromAccount)
{
static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue,
bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue, std::string fromAccount,
const CScript& prefix = CScript()){
CAmount curBalance = pwallet->GetBalance();
// Check amount
@ -478,7 +479,7 @@ static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &
}
// Parse Bitcoin address
CScript scriptPubKey = GetScriptForDestination(address);
CScript scriptPubKey = prefix + GetScriptForDestination(address);
// Create and send the transaction
CReserveKey reservekey(pwallet);
@ -502,6 +503,468 @@ static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &
return tx;
}
UniValue claimname(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() != 3)
throw std::runtime_error(
"claimname \"name\" \"value\" amount\n"
"\nCreate a transaction which issues a claim assigning a value to a name. The claim will be authoritative if the transaction amount is greater than the transaction amount of all other unspent transactions which issue a claim over the same name, and it will remain au\
thoritative as long as it remains unspent and there are no other greater unspent transactions issuing a claim over the same name. The amount is a real and is rounded to the nearest 0.00000001\n"
+ HelpRequiringPassphrase(pwallet) +
"\nArguments:\n"
"1. \"name\" (string, required) The name to be assigned the value.\n"
"2. \"value\" (string, required) The value to assign to the name encoded in hexadecimal.\n"
"3. \"amount\" (numeric, required) The amount in LBRYcrd to send. eg 0.1\n"
"\nResult:\n"
"\"transactionid\" (string) The transaction id.\n");
auto sName = request.params[0].get_str();
auto sValue = request.params[1].get_str();
if (!IsHex(sValue))
throw JSONRPCError(RPC_INVALID_PARAMETER, "value must be hexadecimal");
std::vector<unsigned char> vchName (sName.begin(), sName.end());
std::vector<unsigned char> vchValue(ParseHex(sValue));
CAmount nAmount = AmountFromValue(request.params[2]);
EnsureWalletIsUnlocked(pwallet);
CScript claimScript = CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP;
//Get new address
CPubKey newKey;
if (!pwallet->GetKeyFromPool(newKey))
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
CCoinControl cc;
cc.m_change_type = DEFAULT_ADDRESS_TYPE;
auto tx = SendMoney(pwallet, CTxDestination(newKey.GetID()), nAmount, false, cc, {}, {}, claimScript);
return tx->GetHash().GetHex();
}
UniValue updateclaim(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() != 3)
throw std::runtime_error(
"updateclaim \"txid\" \"value\" amount\n"
"Create a transaction which issues a claim assigning a value to a name, spending the previous txout which issued a claim over the same name and therefore superseding that claim. The claim will be authoritative if the transaction amount is greater than the transaction amount of all other unspent transactions which issue a claim over the same name, and it will remain authoritative as long as it remains unspent and there are no greater unspent transactions issuing a claim over the same name.\n"
+ HelpRequiringPassphrase(pwallet) + "\n"
"Arguments:\n"
"1. \"txid\" (string, required) The transaction containing the unspent txout which should be spent.\n"
"2. \"value\" (string, required) The value to assign to the name encoded in hexadecimal.\n"
"3. \"amount\" (numeric, required) The amount in LBRYcrd to use to bid for the name. eg 0.1\n"
"\nResult:\n"
"\"transactionid\" (string) The new transaction id.\n");
uint256 hash;
hash.SetHex(request.params[0].get_str());
auto sValue = request.params[1].get_str();
if (!IsHex(sValue))
throw JSONRPCError(RPC_INVALID_PARAMETER, "value must be hexadecimal");
std::vector<unsigned char> vchValue(ParseHex(sValue));
CAmount nAmount = AmountFromValue(request.params[2]);
LOCK2(cs_main, pwallet->cs_wallet);
auto it = pwallet->mapWallet.find(hash);
if (it == pwallet->mapWallet.end()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
}
const auto& wtx = it->second;
CTransactionRef wtxNew = nullptr;
for (uint32_t i = 0; i < wtx.tx->vout.size(); ++i)
{
const auto& out = wtx.tx->vout[i];
if (pwallet->IsMine(out) & isminetype::ISMINE_SPENDABLE)
{
std::vector<std::vector<unsigned char>> vvchParams;
int op;
if (DecodeClaimScript(out.scriptPubKey, op, vvchParams))
{
if (op == OP_SUPPORT_CLAIM)
continue;
const auto& vchName = vvchParams[0];
EnsureWalletIsUnlocked(pwallet);
uint160 claimId;
if (op == OP_CLAIM_NAME) {
claimId = ClaimIdHash(wtx.GetHash(), i);
}
else if (op == OP_UPDATE_CLAIM) {
claimId = uint160(vvchParams[1]);
}
else {
throw std::runtime_error("Error: op not implemented");
}
std::vector<unsigned char> vchClaimId(claimId.begin(), claimId.end());
auto updateScript = CScript() << OP_UPDATE_CLAIM << vchName << vchClaimId << vchValue << OP_2DROP << OP_2DROP;
CPubKey newKey;
if (!pwallet->GetKeyFromPool(newKey))
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
CCoinControl cc;
cc.m_change_type = DEFAULT_ADDRESS_TYPE;
wtxNew = SendMoney(pwallet, CTxDestination(newKey.GetID()), nAmount, false, cc, {}, {}, updateScript);
break;
}
}
}
if (wtxNew == nullptr)
throw std::runtime_error("Error: The given transaction contains no claim scripts owned by this wallet");
return wtxNew->GetHash().GetHex();
}
UniValue abandonclaim(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() != 2)
throw std::runtime_error(
"abandonclaim \"txid\" \"address\"\n"
"Create a transaction which spends a txout which assigned a value to a name, effectively abandoning that claim.\n"
+ HelpRequiringPassphrase(pwallet) +
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction containing the unspent txout which should be spent.\n"
"2. \"address\" (string, required) The lbrycrd address to send to.\n"
"\nResult:\n"
"\"transactionid\" (string) The new transaction id.\n");
uint256 hash;
hash.SetHex(request.params[0].get_str());
CKeyID address;
address.SetHex(request.params[1].get_str());
LOCK2(cs_main, pwallet->cs_wallet);
auto it = pwallet->mapWallet.find(hash);
if (it == pwallet->mapWallet.end()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
}
const auto& wtx = it->second;
std::vector<std::vector<unsigned char> > vvchParams;
CTransactionRef wtxNew = nullptr;
for (uint32_t i = 0; i < wtx.tx->vout.size(); ++i)
{
auto mine = pwallet->IsMine(wtx.tx->vout[i]);
if (mine & isminetype::ISMINE_CLAIM)
{
EnsureWalletIsUnlocked(pwallet);
CCoinControl cc;
cc.m_change_type = DEFAULT_ADDRESS_TYPE;
cc.Select(COutPoint(wtx.tx->GetHash(), i));
wtxNew = SendMoney(pwallet, address, wtx.tx->vout[i].nValue, true, cc, {}, {});
break;
}
}
if (wtxNew == nullptr)
throw std::runtime_error("Error: The given transaction contains no claim scripts owned by this wallet");
return wtxNew->GetHash().GetHex();
}
static void MaybePushAddress(UniValue& entry, const CTxDestination &dest);
void ListNameClaims(const CWalletTx& wtx, CWallet* const pwallet, const std::string& strAccount, int nMinDepth,
UniValue& ret, const bool include_supports, bool list_spent)
{
CAmount nFee;
std::string strSentAccount;
std::list<COutputEntry> listSent;
std::list<COutputEntry> listReceived;
isminefilter filter = isminetype::ISMINE_CLAIM;
if (include_supports)
filter |= isminetype::ISMINE_SUPPORT;
wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
bool fAllAccounts = (strAccount == std::string("*"));
if ((!listReceived.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
{
for (const COutputEntry& s: listReceived)
{
if (!list_spent && pwallet->IsSpent(wtx.GetHash(), s.vout))
continue;
UniValue entry(UniValue::VOBJ);
const CScript& scriptPubKey = wtx.tx->vout[s.vout].scriptPubKey;
int op;
std::vector<std::vector<unsigned char>> vvchParams;
if (!DecodeClaimScript(scriptPubKey, op, vvchParams)) {
continue;
}
std::string sName (vvchParams[0].begin(), vvchParams[0].end());
entry.pushKV("name", sName);
if (op == OP_CLAIM_NAME)
{
uint160 claimId = ClaimIdHash(wtx.GetHash(), s.vout);
entry.pushKV("claimId", claimId.GetHex());
entry.pushKV("value", HexStr(vvchParams[1].begin(), vvchParams[1].end()));
}
else if (op == OP_UPDATE_CLAIM)
{
uint160 claimId(vvchParams[1]);
entry.pushKV("claimId", claimId.GetHex());
entry.pushKV("value", HexStr(vvchParams[2].begin(), vvchParams[2].end()));
}
else if (op == OP_SUPPORT_CLAIM)
{
uint160 claimId(vvchParams[1]);
entry.pushKV("supported_claimid", claimId.GetHex());
if (vvchParams.size() > 2) {
entry.pushKV("value", HexStr(vvchParams[2].begin(), vvchParams[2].end()));
}
}
entry.pushKV("txid", wtx.GetHash().ToString());
entry.pushKV("account", strSentAccount);
MaybePushAddress(entry, s.destination);
entry.pushKV("amount", ValueFromAmount(s.amount));
entry.pushKV("vout", s.vout);
entry.pushKV("fee", ValueFromAmount(nFee));
auto it = mapBlockIndex.find(wtx.hashBlock);
if (it != mapBlockIndex.end())
{
CBlockIndex* pindex = it->second;
if (pindex)
{
entry.pushKV("height", pindex->nHeight);
entry.pushKV("expiration height", pindex->nHeight + pclaimTrie->nExpirationTime);
if (pindex->nHeight + pclaimTrie->nExpirationTime > chainActive.Height())
{
entry.pushKV("expired", false);
entry.pushKV("blocks to expiration", pindex->nHeight + pclaimTrie->nExpirationTime - chainActive.Height());
}
else
{
entry.pushKV("expired", true);
}
}
}
entry.pushKV("confirmations", wtx.GetDepthInMainChain());
entry.pushKV("is spent", pwallet->IsSpent(wtx.GetHash(), s.vout));
if (op == OP_CLAIM_NAME)
{
entry.pushKV("is in name trie", pclaimTrie->haveClaim(sName, COutPoint(wtx.GetHash(), s.vout)));
}
else if (op == OP_SUPPORT_CLAIM)
{
entry.pushKV("is in support map", pclaimTrie->haveSupport(sName, COutPoint(wtx.GetHash(), s.vout)));
}
ret.push_back(entry);
}
}
}
UniValue listnameclaims(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() > 3)
throw std::runtime_error(
"listnameclaims includesuppports activeonly minconf\n"
"Return a list of all transactions claiming names.\n"
"\nArguments\n"
"1. includesupports (bool, optional) Whether to also include claim supports. Default is true.\n"
"2. activeonly (bool, optional, not implemented) Whether to only include transactions which are still active, i.e. have n\
ot been spent. Default is false.\n"
"3. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
"\nResult:\n"
"[\n"
" {\n"
" \"name\":\"claimedname\", (string) The name that is claimed.\n"
" \"claimtype\":\"claimtype\", (string) CLAIM or SUPPORT.\n"
" \"claimId\":\"claimId\", (string) The claimId of the claim.\n"
" \"value\":\"value\" (string) The value assigned to the name, if claimtype is CLAIM.\n"
" \"account\":\"accountname\", (string) The account name associated with the transaction. \n"
" It will be \"\" for the default account.\n"
" \"address\":\"lbrycrdaddress\", (string) The lbrycrd address of the transaction.\n"
" \"category\":\"name\" (string) Always name\n"
" \"amount\": x.xxx, (numeric) The amount in LBC.\n"
" \"vout\": n, (numeric) The vout value\n"
" \"fee\": x.xxx, (numeric) The amount of the fee in LBC.\n"
" \"height\": n (numeric) The height of the block in which this transaction was included.\n"
" \"confirmations\": n, (numeric) The number of confirmations for the transaction\n"
" \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction.\n"
" \"blockindex\": n, (numeric) The block index containing the transaction.\n"
" \"txid\": \"transactionid\", (string) The transaction id.\n"
" \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
" \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT).\n"
" \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
" }\n"
"]\n");
std::string strAccount = "*";
auto include_supports = request.params.size() < 1 || request.params[0].get_bool();
bool fListSpent = request.params.size() > 1 && request.params[1].get_bool();
// Minimum confirmations
int nMinDepth = 1;
if (request.params.size() > 2)
nMinDepth = request.params[2].get_int();
UniValue ret(UniValue::VARR);
LOCK2(cs_main, pwallet->cs_wallet);
const auto& txOrdered = pwallet->wtxOrdered;
for (auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
{
auto *const pwtx = (*it).second.first;
if (pwtx != nullptr && pwtx->GetDepthInMainChain() >= nMinDepth)
ListNameClaims(*pwtx, pwallet, strAccount, 0, ret, include_supports, fListSpent);
}
auto arrTmp = ret.getValues();
std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
ret.clear();
ret.setArray();
ret.push_backV(arrTmp);
return ret;
}
UniValue supportclaim(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || (request.params.size() != 3 && request.params.size() != 4))
throw std::runtime_error(
"supportclaim \"name\" \"claimid\" \"amount\" \"value\"\n"
"Increase the value of a claim. Whichever claim has the greatest value, including all support values, will be the authoritative claim, according to the rest of the rules. The name is the name which is claimed by the claim that will be supported, the txid is the txid\
of the claim that will be supported, nout is the transaction output which contains the claim to be supported, and amount is the amount which will be added to the value of the claim. If the claim is currently the authoritative claim, this support will go into effect immediately \
. Otherwise, it will go into effect after 100 blocks. The support will be in effect until it is spent, and will lose its effect when the claim is spent or expires. The amount is a real and is rounded to the nearest .00000001\n"
+ HelpRequiringPassphrase(pwallet) +
"\nArguments:\n"
"1. \"name\" (string, required) The name claimed by the claim to support.\n"
"2. \"claimid\" (string, required) The claimid of the claim to support. This can be obtained by TODO PUT IN PLACE THAT SHOWS THIS.\n"
"3. \"amount\" (numeric, required) The amount in LBC to use to support the claim.\n"
"4. \"value\" (string, optional) The metadata of the support encoded in hexadecimal.\n"
"\nResult:\n"
"\"transactionid\" (string) The transaction id of the support.\n");
auto sName = request.params[0].get_str();
auto sClaimId = request.params[1].get_str();
const size_t claimLength = 40;
if (!IsHex(sClaimId))
throw JSONRPCError(RPC_INVALID_PARAMETER, "claimid must be a 20-character hexadecimal string (not '" + sClaimId + "')");
if (sClaimId.length() != claimLength)
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("claimid must be of length %d", claimLength));
uint160 claimId;
claimId.SetHex(sClaimId);
std::vector<unsigned char> vchName (sName.begin(), sName.end());
std::vector<unsigned char> vchClaimId (claimId.begin(), claimId.end());
CAmount nAmount = AmountFromValue(request.params[2]);
LOCK2(cs_main, pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
CScript supportScript = CScript() << OP_SUPPORT_CLAIM << vchName << vchClaimId;
auto lastOp = OP_DROP;
if (request.params.size() > 3) {
auto hex = request.params[3].get_str();
if (!IsHex(hex))
throw JSONRPCError(RPC_INVALID_PARAMETER, "value/metadata must be of hexadecimal data");
supportScript = supportScript << ParseHex(hex);
lastOp = OP_2DROP;
}
supportScript = supportScript << OP_2DROP << lastOp;
CPubKey newKey;
if (!pwallet->GetKeyFromPool(newKey))
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
CCoinControl cc;
cc.m_change_type = DEFAULT_ADDRESS_TYPE;
auto tx = SendMoney(pwallet, CTxDestination(newKey.GetID()), nAmount, false, cc, {}, {}, supportScript);
return tx->GetHash().GetHex();
}
UniValue abandonsupport(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() != 2)
throw std::runtime_error(
"abandonsupport \"txid\" \"address\"\n"
"Create a transaction which spends a txout which supported a name claim, effectively abandoning that support.\n"
+ HelpRequiringPassphrase(pwallet) +
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction containing the unspent txout which should be spent.\n"
"2. \"address\" (string, required) The lbrycrd address to send to.\n"
"\nResult:\n"
"\"transactionid\" (string) The new transaction id.\n");
uint256 hash;
hash.SetHex(request.params[0].get_str());
CKeyID address;
address.SetHex(request.params[1].get_str());
LOCK2(cs_main, pwallet->cs_wallet);
auto it = pwallet->mapWallet.find(hash);
if (it == pwallet->mapWallet.end()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
}
const auto& wtx = it->second;
std::vector<std::vector<unsigned char> > vvchParams;
CTransactionRef wtxNew = nullptr;
for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i)
{
auto mine = pwallet->IsMine(wtx.tx->vout[i]);
if (mine & isminetype::ISMINE_SUPPORT)
{
EnsureWalletIsUnlocked(pwallet);
CCoinControl cc;
cc.m_change_type = DEFAULT_ADDRESS_TYPE;
cc.Select(COutPoint(wtx.tx->GetHash(), i));
wtxNew = SendMoney(pwallet, address, wtx.tx->vout[i].nValue, true, cc, {}, {});
break;
}
}
if (wtxNew == nullptr)
throw std::runtime_error("Error: The given transaction contains no support scripts owned by this wallet");
return wtxNew->GetHash().GetHex();
}
static UniValue sendtoaddress(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@ -4830,6 +5293,13 @@ static const CRPCCommand commands[] =
{ "wallet", "setlabel", &setlabel, {"address","label"} },
{ "generating", "generate", &generate, {"nblocks","maxtries"} },
{ "Claimtrie", "claimname", &claimname, {"name","value","amount"} },
{ "Claimtrie", "updateclaim", &updateclaim, {"txid","value","amount"} },
{ "Claimtrie", "abandonclaim", &abandonclaim, {"txid","address"} },
{ "Claimtrie", "listnameclaims", &listnameclaims, {"includesuppports","activeonly","minconf"} },
{ "Claimtrie", "supportclaim", &supportclaim, {"name","claimid","amount","value"} },
{ "Claimtrie", "abandonsupport", &abandonsupport, {"txid","address"} },
};
void RegisterWalletRPCCommands(CRPCTable &t)

View file

@ -15,6 +15,7 @@
#include <key_io.h>
#include <keystore.h>
#include <validation.h>
#include <nameclaim.h>
#include <net.h>
#include <policy/fees.h>
#include <policy/policy.h>
@ -1381,7 +1382,13 @@ CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
isminetype CWallet::IsMine(const CTxOut& txout) const
{
return ::IsMine(*this, txout.scriptPubKey);
int op = 0;
auto script = StripClaimScriptPrefix(txout.scriptPubKey, op);
if (op == OP_CLAIM_NAME)
return isminetype::ISMINE_CLAIM;
if (op == OP_SUPPORT_CLAIM)
return isminetype::ISMINE_SUPPORT;
return ::IsMine(*this, script);
}
CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const
@ -1403,11 +1410,13 @@ bool CWallet::IsChange(const CTxOut& txout) const
if (::IsMine(*this, txout.scriptPubKey))
{
CTxDestination address;
if (!ExtractDestination(txout.scriptPubKey, address))
const CScript& scriptPubKey = StripClaimScriptPrefix(txout.scriptPubKey);
if (!ExtractDestination(scriptPubKey, address))
return true;
LOCK(cs_wallet);
if (!mapAddressBook.count(address))
if (!mapAddressBook.count(address) && (scriptPubKey == txout.scriptPubKey))
return true;
}
return false;
@ -1690,18 +1699,19 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
// In either case, we need to get the destination address
CTxDestination address;
const CScript& scriptPubKey = StripClaimScriptPrefix(txout.scriptPubKey);
if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
if (!ExtractDestination(scriptPubKey, address) && !scriptPubKey.IsUnspendable())
{
pwallet->WalletLogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
this->GetHash().ToString());
LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
this->GetHash().ToString());
address = CNoDestination();
}
COutputEntry output = {address, txout.nValue, (int)i};
// If we are debited by the transaction, add the output as a "sent" entry
if (nDebit > 0)
if (nDebit > 0 || filter & ISMINE_CLAIM || filter & ISMINE_SUPPORT)
listSent.push_back(output);
// If we are receiving the output, add it as a "received" entry
@ -2371,8 +2381,12 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
continue;
}
// spending claims or supports requires specific selection:
auto claimSpendRequested = (mine & ISMINE_CLAIM) || (mine & ISMINE_SUPPORT);
claimSpendRequested &= coinControl && coinControl->IsSelected(COutPoint(entry.first, i));
bool solvable = IsSolvable(*this, pcoin->tx->vout[i].scriptPubKey);
bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable));
bool spendable = claimSpendRequested || ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable));
vCoins.push_back(COutput(pcoin, i, nDepth, spendable, solvable, safeTx, (coinControl && coinControl->fAllowWatchOnly)));
@ -2950,6 +2964,9 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
strFailReason = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.");
return false;
}
// Make sure we meet the minimum claimtrie fee, pick which ever one is largest
CAmount minClaimTrieFee = CalcMinClaimTrieFee(txNew, minFeePerNameClaimChar);
nFeeNeeded = std::max(nFeeNeeded, minClaimTrieFee);
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// because we must be at the maximum allowed fee.