2015-09-24 07:15:28 +02:00
|
|
|
#include "claimtrie.h"
|
2015-02-05 20:24:09 +01:00
|
|
|
#include "leveldbwrapper.h"
|
|
|
|
|
|
|
|
#include <boost/scoped_ptr.hpp>
|
2015-02-03 02:57:53 +01:00
|
|
|
|
2015-03-26 03:10:05 +01:00
|
|
|
uint256 CNodeValue::GetHash() const
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
2015-03-26 03:10:05 +01:00
|
|
|
CHash256 valTxHasher;
|
|
|
|
valTxHasher.Write(txhash.begin(), txhash.size());
|
|
|
|
std::vector<unsigned char> vchValTxHash(valTxHasher.OUTPUT_SIZE);
|
|
|
|
valTxHasher.Finalize(&(vchValTxHash[0]));
|
|
|
|
|
|
|
|
CHash256 valnOutHasher;
|
2015-02-03 02:57:53 +01:00
|
|
|
std::stringstream ss;
|
|
|
|
ss << nOut;
|
2015-03-26 03:10:05 +01:00
|
|
|
std::string snOut = ss.str();
|
|
|
|
valnOutHasher.Write((unsigned char*) snOut.data(), snOut.size());
|
|
|
|
std::vector<unsigned char> vchValnOutHash(valnOutHasher.OUTPUT_SIZE);
|
|
|
|
valnOutHasher.Finalize(&(vchValnOutHash[0]));
|
|
|
|
|
|
|
|
CHash256 valHasher;
|
|
|
|
valHasher.Write(vchValTxHash.data(), vchValTxHash.size());
|
|
|
|
valHasher.Write(vchValnOutHash.data(), vchValnOutHash.size());
|
|
|
|
std::vector<unsigned char> vchValHash(valHasher.OUTPUT_SIZE);
|
|
|
|
valHasher.Finalize(&(vchValHash[0]));
|
|
|
|
|
|
|
|
uint256 valHash(vchValHash);
|
|
|
|
return valHash;
|
2015-02-03 02:57:53 +01:00
|
|
|
}
|
|
|
|
|
2015-09-25 23:09:21 +02:00
|
|
|
bool CClaimTrieNode::insertValue(CNodeValue val)//, bool * pfChanged)
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
2015-09-24 07:15:28 +02:00
|
|
|
LogPrintf("%s: Inserting %s:%d (amount: %d) into the claim trie\n", __func__, val.txhash.ToString(), val.nOut, val.nAmount);
|
2015-09-25 23:09:21 +02:00
|
|
|
//bool fChanged = false;
|
2015-02-03 02:57:53 +01:00
|
|
|
|
2015-09-25 23:09:21 +02:00
|
|
|
//if (values.empty())
|
|
|
|
//{
|
|
|
|
values.push_back(val);
|
|
|
|
// fChanged = true;
|
|
|
|
//}
|
|
|
|
//else
|
|
|
|
//{
|
|
|
|
// CNodeValue currentTop = values.front();
|
|
|
|
// values.push_back(val);
|
|
|
|
// std::make_heap(values.begin(), values.end());
|
|
|
|
// if (currentTop != values.front())
|
|
|
|
// fChanged = true;
|
|
|
|
//}
|
|
|
|
//if (pfChanged)
|
|
|
|
// *pfChanged = fChanged;
|
2015-02-03 02:57:53 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-25 23:09:21 +02:00
|
|
|
bool CClaimTrieNode::removeValue(uint256& txhash, uint32_t nOut, CNodeValue& val)//, bool * pfChanged)
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
2015-09-24 07:15:28 +02:00
|
|
|
LogPrintf("%s: Removing txid: %s, nOut: %d from the claim trie\n", __func__, txhash.ToString(), nOut);
|
2015-09-25 23:09:21 +02:00
|
|
|
//bool fChanged = false;
|
2015-02-03 02:57:53 +01:00
|
|
|
|
2015-09-25 23:09:21 +02:00
|
|
|
//CNodeValue currentTop = values.front();
|
2015-02-03 02:57:53 +01:00
|
|
|
|
2015-03-17 06:16:37 +01:00
|
|
|
std::vector<CNodeValue>::iterator position;
|
|
|
|
for (position = values.begin(); position != values.end(); ++position)
|
|
|
|
{
|
|
|
|
if (position->txhash == txhash && position->nOut == nOut)
|
|
|
|
{
|
|
|
|
std::swap(val, *position);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-02-03 02:57:53 +01:00
|
|
|
if (position != values.end())
|
|
|
|
values.erase(position);
|
|
|
|
else
|
|
|
|
{
|
2015-09-24 07:15:28 +02:00
|
|
|
LogPrintf("CClaimTrieNode::%s() : asked to remove a value that doesn't exist\n", __func__);
|
|
|
|
LogPrintf("CClaimTrieNode::%s() : values that do exist:\n", __func__);
|
2015-03-09 01:24:13 +01:00
|
|
|
for (unsigned int i = 0; i < values.size(); i++)
|
|
|
|
{
|
2015-03-26 03:10:05 +01:00
|
|
|
LogPrintf("\ttxid: %s, nOut: %d\n", values[i].txhash.ToString(), values[i].nOut);
|
2015-03-09 01:24:13 +01:00
|
|
|
}
|
2015-09-25 23:09:21 +02:00
|
|
|
std::cout << "couldnt find the thing" << std::endl;
|
2015-02-03 02:57:53 +01:00
|
|
|
return false;
|
|
|
|
}
|
2015-09-25 23:09:21 +02:00
|
|
|
//if (!values.empty())
|
|
|
|
//{
|
|
|
|
// std::make_heap(values.begin(), values.end());
|
|
|
|
// if (currentTop != values.front())
|
|
|
|
// fChanged = true;
|
|
|
|
//}
|
|
|
|
//else
|
|
|
|
// fChanged = true;
|
|
|
|
//if (pfChanged)
|
|
|
|
// *pfChanged = fChanged;
|
2015-02-03 02:57:53 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieNode::getBestValue(CNodeValue& value) const
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
|
|
|
if (values.empty())
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value = values.front();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieNode::haveValue(const uint256& txhash, uint32_t nOut) const
|
2015-03-19 22:16:35 +01:00
|
|
|
{
|
|
|
|
for (std::vector<CNodeValue>::const_iterator itval = values.begin(); itval != values.end(); ++itval)
|
|
|
|
if (itval->txhash == txhash && itval->nOut == nOut)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-09-25 23:09:21 +02:00
|
|
|
void CClaimTrieNode::reorderValues()
|
|
|
|
{
|
|
|
|
std::make_heap(values.begin(), values.end());
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
uint256 CClaimTrie::getMerkleHash()
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
|
|
|
return root.hash;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::empty() const
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
|
|
|
return root.empty();
|
|
|
|
}
|
|
|
|
|
2015-09-25 23:09:21 +02:00
|
|
|
bool CClaimTrie::keyTypeEmpty(char key) const
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-05-21 19:50:40 +02:00
|
|
|
boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
|
|
|
|
pcursor->SeekToFirst();
|
|
|
|
|
|
|
|
while (pcursor->Valid())
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
leveldb::Slice slKey = pcursor->key();
|
|
|
|
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
|
|
|
|
char chType;
|
|
|
|
ssKey >> chType;
|
2015-09-25 23:09:21 +02:00
|
|
|
if (chType == key)
|
2015-05-21 19:50:40 +02:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
|
|
|
|
}
|
|
|
|
pcursor->Next();
|
|
|
|
}
|
|
|
|
return true;
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
|
|
|
|
2015-09-25 23:09:21 +02:00
|
|
|
bool CClaimTrie::queueEmpty() const
|
|
|
|
{
|
|
|
|
for (valueQueueType::const_iterator itRow = dirtyQueueRows.begin(); itRow != dirtyQueueRows.end(); ++itRow)
|
|
|
|
{
|
|
|
|
if (!itRow->second.empty())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return keyTypeEmpty(QUEUE_ROW);
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::expirationQueueEmpty() const
|
2015-05-27 23:53:12 +02:00
|
|
|
{
|
|
|
|
for (valueQueueType::const_iterator itRow = dirtyExpirationQueueRows.begin(); itRow != dirtyExpirationQueueRows.end(); ++itRow)
|
|
|
|
{
|
|
|
|
if (!itRow->second.empty())
|
|
|
|
return false;
|
|
|
|
}
|
2015-09-25 23:09:21 +02:00
|
|
|
return keyTypeEmpty(EXP_QUEUE_ROW);
|
|
|
|
}
|
2015-05-27 23:53:12 +02:00
|
|
|
|
2015-09-25 23:09:21 +02:00
|
|
|
bool CClaimTrie::supportEmpty() const
|
|
|
|
{
|
|
|
|
for (supportMapType::const_iterator itNode = dirtySupportNodes.begin(); itNode != dirtySupportNodes.end(); ++itNode)
|
2015-05-27 23:53:12 +02:00
|
|
|
{
|
2015-09-25 23:09:21 +02:00
|
|
|
if (!itNode->second.empty())
|
|
|
|
return false;
|
2015-05-27 23:53:12 +02:00
|
|
|
}
|
2015-09-25 23:09:21 +02:00
|
|
|
return keyTypeEmpty(SUPPORT);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrie::supportQueueEmpty() const
|
|
|
|
{
|
|
|
|
for (supportValueQueueType::const_iterator itRow = dirtySupportQueueRows.begin(); itRow != dirtySupportQueueRows.end(); ++itRow)
|
|
|
|
{
|
|
|
|
if (!itRow->second.empty())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return keyTypeEmpty(SUPPORT_QUEUE);
|
2015-05-27 23:53:12 +02:00
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
void CClaimTrie::setExpirationTime(int t)
|
2015-05-27 23:53:12 +02:00
|
|
|
{
|
|
|
|
nExpirationTime = t;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
void CClaimTrie::clear()
|
2015-03-25 19:06:04 +01:00
|
|
|
{
|
|
|
|
clear(&root);
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
void CClaimTrie::clear(CClaimTrieNode* current)
|
2015-03-25 19:06:04 +01:00
|
|
|
{
|
|
|
|
for (nodeMapType::const_iterator itchildren = current->children.begin(); itchildren != current->children.end(); ++itchildren)
|
|
|
|
{
|
|
|
|
clear(itchildren->second);
|
|
|
|
delete itchildren->second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::haveClaim(const std::string& name, const uint256& txhash, uint32_t nOut) const
|
2015-03-19 22:16:35 +01:00
|
|
|
{
|
2015-09-24 07:15:28 +02:00
|
|
|
const CClaimTrieNode* current = &root;
|
2015-03-19 22:16:35 +01:00
|
|
|
for (std::string::const_iterator itname = name.begin(); itname != name.end(); ++itname)
|
|
|
|
{
|
|
|
|
nodeMapType::const_iterator itchildren = current->children.find(*itname);
|
|
|
|
if (itchildren == current->children.end())
|
|
|
|
return false;
|
|
|
|
current = itchildren->second;
|
|
|
|
}
|
|
|
|
return current->haveValue(txhash, nOut);
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
unsigned int CClaimTrie::getTotalNamesInTrie() const
|
2015-04-10 22:50:50 +02:00
|
|
|
{
|
|
|
|
if (empty())
|
|
|
|
return 0;
|
2015-09-24 07:15:28 +02:00
|
|
|
const CClaimTrieNode* current = &root;
|
2015-04-10 22:50:50 +02:00
|
|
|
return getTotalNamesRecursive(current);
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
unsigned int CClaimTrie::getTotalNamesRecursive(const CClaimTrieNode* current) const
|
2015-04-10 22:50:50 +02:00
|
|
|
{
|
|
|
|
unsigned int names_in_subtrie = 0;
|
|
|
|
if (!(current->values.empty()))
|
|
|
|
names_in_subtrie += 1;
|
|
|
|
for (nodeMapType::const_iterator it = current->children.begin(); it != current->children.end(); ++it)
|
|
|
|
{
|
|
|
|
names_in_subtrie += getTotalNamesRecursive(it->second);
|
|
|
|
}
|
|
|
|
return names_in_subtrie;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
unsigned int CClaimTrie::getTotalClaimsInTrie() const
|
2015-04-10 22:50:50 +02:00
|
|
|
{
|
|
|
|
if (empty())
|
|
|
|
return 0;
|
2015-09-24 07:15:28 +02:00
|
|
|
const CClaimTrieNode* current = &root;
|
2015-04-10 22:50:50 +02:00
|
|
|
return getTotalClaimsRecursive(current);
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
unsigned int CClaimTrie::getTotalClaimsRecursive(const CClaimTrieNode* current) const
|
2015-04-10 22:50:50 +02:00
|
|
|
{
|
|
|
|
unsigned int claims_in_subtrie = current->values.size();
|
|
|
|
for (nodeMapType::const_iterator it = current->children.begin(); it != current->children.end(); ++it)
|
|
|
|
{
|
|
|
|
claims_in_subtrie += getTotalClaimsRecursive(it->second);
|
|
|
|
}
|
|
|
|
return claims_in_subtrie;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
CAmount CClaimTrie::getTotalValueOfClaimsInTrie(bool fControllingOnly) const
|
2015-04-10 22:50:50 +02:00
|
|
|
{
|
|
|
|
if (empty())
|
|
|
|
return 0;
|
2015-09-24 07:15:28 +02:00
|
|
|
const CClaimTrieNode* current = &root;
|
2015-04-10 22:50:50 +02:00
|
|
|
return getTotalValueOfClaimsRecursive(current, fControllingOnly);
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
CAmount CClaimTrie::getTotalValueOfClaimsRecursive(const CClaimTrieNode* current, bool fControllingOnly) const
|
2015-04-10 22:50:50 +02:00
|
|
|
{
|
|
|
|
CAmount value_in_subtrie = 0;
|
|
|
|
for (std::vector<CNodeValue>::const_iterator itval = current->values.begin(); itval != current->values.end(); ++itval)
|
|
|
|
{
|
|
|
|
value_in_subtrie += itval->nAmount;
|
|
|
|
if (fControllingOnly)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (nodeMapType::const_iterator itchild = current->children.begin(); itchild != current->children.end(); ++itchild)
|
|
|
|
{
|
|
|
|
value_in_subtrie += getTotalValueOfClaimsRecursive(itchild->second, fControllingOnly);
|
|
|
|
}
|
|
|
|
return value_in_subtrie;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::recursiveFlattenTrie(const std::string& name, const CClaimTrieNode* current, std::vector<namedNodeType>& nodes) const
|
2015-02-07 18:32:05 +01:00
|
|
|
{
|
2015-06-12 04:55:12 +02:00
|
|
|
namedNodeType node(name, *current);
|
|
|
|
nodes.push_back(node);
|
2015-02-07 18:32:05 +01:00
|
|
|
for (nodeMapType::const_iterator it = current->children.begin(); it != current->children.end(); ++it)
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << name << it->first;
|
2015-06-12 04:55:12 +02:00
|
|
|
if (!recursiveFlattenTrie(ss.str(), it->second, nodes))
|
2015-02-07 18:32:05 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
std::vector<namedNodeType> CClaimTrie::flattenTrie() const
|
2015-02-07 18:32:05 +01:00
|
|
|
{
|
2015-06-12 04:55:12 +02:00
|
|
|
std::vector<namedNodeType> nodes;
|
|
|
|
if (!recursiveFlattenTrie("", &root, nodes))
|
|
|
|
LogPrintf("%s: Something went wrong flattening the trie", __func__);
|
|
|
|
return nodes;
|
2015-02-07 18:32:05 +01:00
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::getInfoForName(const std::string& name, CNodeValue& val) const
|
2015-02-07 18:32:05 +01:00
|
|
|
{
|
2015-09-24 07:15:28 +02:00
|
|
|
const CClaimTrieNode* current = &root;
|
2015-02-07 18:32:05 +01:00
|
|
|
for (std::string::const_iterator itname = name.begin(); itname != name.end(); ++itname)
|
|
|
|
{
|
|
|
|
nodeMapType::const_iterator itchildren = current->children.find(*itname);
|
|
|
|
if (itchildren == current->children.end())
|
2015-02-11 00:44:14 +01:00
|
|
|
return false;
|
2015-02-07 18:32:05 +01:00
|
|
|
current = itchildren->second;
|
|
|
|
}
|
2015-03-17 06:16:37 +01:00
|
|
|
return current->getBestValue(val);
|
2015-02-07 18:32:05 +01:00
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::checkConsistency()
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
2015-02-05 20:24:09 +01:00
|
|
|
if (empty())
|
|
|
|
return true;
|
2015-02-03 02:57:53 +01:00
|
|
|
return recursiveCheckConsistency(&root);
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::recursiveCheckConsistency(CClaimTrieNode* node)
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
2015-03-26 03:10:05 +01:00
|
|
|
std::vector<unsigned char> vchToHash;
|
2015-02-03 02:57:53 +01:00
|
|
|
|
|
|
|
for (nodeMapType::iterator it = node->children.begin(); it != node->children.end(); ++it)
|
|
|
|
{
|
|
|
|
if (recursiveCheckConsistency(it->second))
|
|
|
|
{
|
2015-03-26 03:10:05 +01:00
|
|
|
vchToHash.push_back(it->first);
|
|
|
|
vchToHash.insert(vchToHash.end(), it->second->hash.begin(), it->second->hash.end());
|
2015-02-03 02:57:53 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
2015-03-17 06:16:37 +01:00
|
|
|
|
2015-02-23 23:51:52 +01:00
|
|
|
CNodeValue val;
|
2015-03-17 06:16:37 +01:00
|
|
|
bool hasValue = node->getBestValue(val);
|
2015-02-23 23:51:52 +01:00
|
|
|
|
|
|
|
if (hasValue)
|
|
|
|
{
|
2015-03-26 03:10:05 +01:00
|
|
|
uint256 valHash = val.GetHash();
|
|
|
|
vchToHash.insert(vchToHash.end(), valHash.begin(), valHash.end());
|
2015-02-23 23:51:52 +01:00
|
|
|
}
|
|
|
|
|
2015-02-03 02:57:53 +01:00
|
|
|
CHash256 hasher;
|
|
|
|
std::vector<unsigned char> vchHash(hasher.OUTPUT_SIZE);
|
2015-03-26 03:10:05 +01:00
|
|
|
hasher.Write(vchToHash.data(), vchToHash.size());
|
2015-02-03 02:57:53 +01:00
|
|
|
hasher.Finalize(&(vchHash[0]));
|
|
|
|
uint256 calculatedHash(vchHash);
|
|
|
|
return calculatedHash == node->hash;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::getQueueRow(int nHeight, std::vector<CValueQueueEntry>& row)
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-05-21 19:50:40 +02:00
|
|
|
valueQueueType::iterator itQueueRow = dirtyQueueRows.find(nHeight);
|
|
|
|
if (itQueueRow != dirtyQueueRows.end())
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-05-21 19:50:40 +02:00
|
|
|
row = itQueueRow->second;
|
|
|
|
return true;
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
2015-09-25 23:09:21 +02:00
|
|
|
return db.Read(std::make_pair(QUEUE_ROW, nHeight), row);
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::getExpirationQueueRow(int nHeight, std::vector<CValueQueueEntry>& row)
|
2015-05-27 23:53:12 +02:00
|
|
|
{
|
|
|
|
valueQueueType::iterator itQueueRow = dirtyExpirationQueueRows.find(nHeight);
|
|
|
|
if (itQueueRow != dirtyExpirationQueueRows.end())
|
|
|
|
{
|
|
|
|
row = itQueueRow->second;
|
|
|
|
return true;
|
|
|
|
}
|
2015-09-25 23:09:21 +02:00
|
|
|
return db.Read(std::make_pair(EXP_QUEUE_ROW, nHeight), row);
|
2015-05-27 23:53:12 +02:00
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
void CClaimTrie::updateQueueRow(int nHeight, std::vector<CValueQueueEntry>& row)
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-05-21 19:50:40 +02:00
|
|
|
valueQueueType::iterator itQueueRow = dirtyQueueRows.find(nHeight);
|
|
|
|
if (itQueueRow == dirtyQueueRows.end())
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-05-21 19:50:40 +02:00
|
|
|
std::vector<CValueQueueEntry> newRow;
|
|
|
|
std::pair<valueQueueType::iterator, bool> ret;
|
|
|
|
ret = dirtyQueueRows.insert(std::pair<int, std::vector<CValueQueueEntry> >(nHeight, newRow));
|
|
|
|
assert(ret.second);
|
|
|
|
itQueueRow = ret.first;
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
2015-05-21 19:50:40 +02:00
|
|
|
itQueueRow->second.swap(row);
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
void CClaimTrie::updateExpirationRow(int nHeight, std::vector<CValueQueueEntry>& row)
|
2015-05-27 23:53:12 +02:00
|
|
|
{
|
|
|
|
valueQueueType::iterator itQueueRow = dirtyExpirationQueueRows.find(nHeight);
|
|
|
|
if (itQueueRow == dirtyExpirationQueueRows.end())
|
|
|
|
{
|
|
|
|
std::vector<CValueQueueEntry> newRow;
|
|
|
|
std::pair<valueQueueType::iterator, bool> ret;
|
|
|
|
ret = dirtyExpirationQueueRows.insert(std::pair<int, std::vector<CValueQueueEntry> >(nHeight, newRow));
|
|
|
|
assert(ret.second);
|
|
|
|
itQueueRow = ret.first;
|
|
|
|
}
|
|
|
|
itQueueRow->second.swap(row);
|
|
|
|
}
|
|
|
|
|
2015-09-25 23:09:21 +02:00
|
|
|
void CClaimTrie::updateSupportMap(const std::string& name, supportMapNodeType& node)
|
|
|
|
{
|
|
|
|
supportMapType::iterator itNode = dirtySupportNodes.find(name);
|
|
|
|
if (itNode == dirtySupportNodes.end())
|
|
|
|
{
|
|
|
|
supportMapNodeType newNode;
|
|
|
|
std::pair<supportMapType::iterator, bool> ret;
|
|
|
|
ret = dirtySupportNodes.insert(std::pair<std::string, supportMapNodeType>(name, newNode));
|
|
|
|
assert(ret.second);
|
|
|
|
itNode = ret.first;
|
|
|
|
}
|
|
|
|
itNode->second.swap(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CClaimTrie::updateSupportQueue(int nHeight, std::vector<CSupportValueQueueEntry>& row)
|
|
|
|
{
|
|
|
|
supportValueQueueType::iterator itQueueRow = dirtySupportQueueRows.find(nHeight);
|
|
|
|
if (itQueueRow == dirtySupportQueueRows.end())
|
|
|
|
{
|
|
|
|
std::vector<CSupportValueQueueEntry> newRow;
|
|
|
|
std::pair<supportValueQueueType::iterator, bool> ret;
|
|
|
|
ret = dirtySupportQueueRows.insert(std::pair<int, std::vector<CSupportValueQueueEntry> >(nHeight, newRow));
|
|
|
|
assert(ret.second);
|
|
|
|
itQueueRow = ret.first;
|
|
|
|
}
|
|
|
|
itQueueRow->second.swap(row);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrie::getSupportNode(std::string name, supportMapNodeType& node)
|
|
|
|
{
|
|
|
|
supportMapType::iterator itNode = dirtySupportNodes.find(name);
|
|
|
|
if (itNode != dirtySupportNodes.end())
|
|
|
|
{
|
|
|
|
node = itNode->second;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return db.Read(std::make_pair(SUPPORT, name), node);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrie::getSupportQueueRow(int nHeight, std::vector<CSupportValueQueueEntry>& row)
|
|
|
|
{
|
|
|
|
supportValueQueueType::iterator itQueueRow = dirtySupportQueueRows.find(nHeight);
|
|
|
|
if (itQueueRow != dirtySupportQueueRows.end())
|
|
|
|
{
|
|
|
|
row = itQueueRow->second;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return db.Read(std::make_pair(SUPPORT_QUEUE, nHeight), row);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrie::update(nodeCacheType& cache, hashMapType& hashes, const uint256& hashBlockIn, valueQueueType& queueCache, valueQueueType& expirationQueueCache, int nNewHeight, supportMapType& supportCache, supportValueQueueType& supportQueueCache)
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
|
|
|
// General strategy: the cache is ordered by length, ensuring child
|
|
|
|
// nodes are always inserted after their parents. Insert each node
|
|
|
|
// one at a time. When updating a node, swap its values with those
|
|
|
|
// of the cached node and delete all characters (and their children
|
|
|
|
// and so forth) which don't exist in the updated node. When adding
|
2015-09-24 07:15:28 +02:00
|
|
|
// a new node, make sure that its <character, CClaimTrieNode*> pair
|
2015-02-03 02:57:53 +01:00
|
|
|
// gets into the parent's children.
|
|
|
|
// Then, update all of the given hashes.
|
|
|
|
// This can probably be optimized by checking each substring against
|
|
|
|
// the caches each time, but that will come after this is shown to
|
|
|
|
// work correctly.
|
2015-03-23 19:51:29 +01:00
|
|
|
// Disk strategy: keep a map of <string: dirty node>, where
|
|
|
|
// any nodes that are changed get put into the map, and any nodes
|
|
|
|
// to be deleted will simply be empty (no value, no children). Nodes
|
|
|
|
// whose hashes change will also be inserted into the map.
|
|
|
|
// As far as the queue goes, just keep a list of dirty queue entries.
|
|
|
|
// When the time comes, send all of that to disk in one batch, and
|
|
|
|
// empty the map/list.
|
|
|
|
|
2015-02-03 02:57:53 +01:00
|
|
|
bool success = true;
|
|
|
|
for (nodeCacheType::iterator itcache = cache.begin(); itcache != cache.end(); ++itcache)
|
|
|
|
{
|
2015-03-23 19:51:29 +01:00
|
|
|
success = updateName(itcache->first, itcache->second);
|
2015-02-03 02:57:53 +01:00
|
|
|
if (!success)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for (hashMapType::iterator ithash = hashes.begin(); ithash != hashes.end(); ++ithash)
|
|
|
|
{
|
2015-03-23 19:51:29 +01:00
|
|
|
success = updateHash(ithash->first, ithash->second);
|
2015-02-03 02:57:53 +01:00
|
|
|
if (!success)
|
|
|
|
return false;
|
|
|
|
}
|
2015-03-17 06:16:37 +01:00
|
|
|
for (valueQueueType::iterator itQueueCacheRow = queueCache.begin(); itQueueCacheRow != queueCache.end(); ++itQueueCacheRow)
|
|
|
|
{
|
2015-05-21 19:50:40 +02:00
|
|
|
updateQueueRow(itQueueCacheRow->first, itQueueCacheRow->second);
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
2015-05-27 23:53:12 +02:00
|
|
|
for (valueQueueType::iterator itExpirationRow = expirationQueueCache.begin(); itExpirationRow != expirationQueueCache.end(); ++itExpirationRow)
|
|
|
|
{
|
|
|
|
updateExpirationRow(itExpirationRow->first, itExpirationRow->second);
|
|
|
|
}
|
2015-09-25 23:09:21 +02:00
|
|
|
for (supportMapType::iterator itSupportCache = supportCache.begin(); itSupportCache != supportCache.end(); ++itSupportCache)
|
|
|
|
{
|
|
|
|
updateSupportMap(itSupportCache->first, itSupportCache->second);
|
|
|
|
}
|
|
|
|
for (supportValueQueueType::iterator itSupportQueue = supportQueueCache.begin(); itSupportQueue != supportQueueCache.end(); ++itSupportQueue)
|
|
|
|
{
|
|
|
|
updateSupportQueue(itSupportQueue->first, itSupportQueue->second);
|
|
|
|
}
|
2015-02-10 21:30:40 +01:00
|
|
|
hashBlock = hashBlockIn;
|
2015-03-17 06:16:37 +01:00
|
|
|
nCurrentHeight = nNewHeight;
|
2015-02-03 02:57:53 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
void CClaimTrie::markNodeDirty(const std::string &name, CClaimTrieNode* node)
|
2015-03-23 19:51:29 +01:00
|
|
|
{
|
|
|
|
std::pair<nodeCacheType::iterator, bool> ret;
|
2015-09-24 07:15:28 +02:00
|
|
|
ret = dirtyNodes.insert(std::pair<std::string, CClaimTrieNode*>(name, node));
|
2015-03-23 19:51:29 +01:00
|
|
|
if (ret.second == false)
|
|
|
|
ret.first->second = node;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::updateName(const std::string &name, CClaimTrieNode* updatedNode)
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
2015-09-24 07:15:28 +02:00
|
|
|
CClaimTrieNode* current = &root;
|
2015-02-03 02:57:53 +01:00
|
|
|
for (std::string::const_iterator itname = name.begin(); itname != name.end(); ++itname)
|
|
|
|
{
|
|
|
|
nodeMapType::iterator itchild = current->children.find(*itname);
|
|
|
|
if (itchild == current->children.end())
|
|
|
|
{
|
|
|
|
if (itname + 1 == name.end())
|
|
|
|
{
|
2015-09-24 07:15:28 +02:00
|
|
|
CClaimTrieNode* newNode = new CClaimTrieNode();
|
2015-02-03 02:57:53 +01:00
|
|
|
current->children[*itname] = newNode;
|
|
|
|
current = newNode;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
current = itchild->second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(current != NULL);
|
|
|
|
current->values.swap(updatedNode->values);
|
2015-03-23 19:51:29 +01:00
|
|
|
markNodeDirty(name, current);
|
2015-02-03 02:57:53 +01:00
|
|
|
for (nodeMapType::iterator itchild = current->children.begin(); itchild != current->children.end();)
|
|
|
|
{
|
|
|
|
nodeMapType::iterator itupdatechild = updatedNode->children.find(itchild->first);
|
|
|
|
if (itupdatechild == updatedNode->children.end())
|
|
|
|
{
|
|
|
|
// This character has apparently been deleted, so delete
|
|
|
|
// all descendents from this child.
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << name << itchild->first;
|
|
|
|
std::string newName = ss.str();
|
2015-03-23 19:51:29 +01:00
|
|
|
if (!recursiveNullify(itchild->second, newName))
|
2015-02-03 02:57:53 +01:00
|
|
|
return false;
|
|
|
|
current->children.erase(itchild++);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
++itchild;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::recursiveNullify(CClaimTrieNode* node, std::string& name)
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
|
|
|
assert(node != NULL);
|
|
|
|
for (nodeMapType::iterator itchild = node->children.begin(); itchild != node->children.end(); ++itchild)
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << name << itchild->first;
|
|
|
|
std::string newName = ss.str();
|
2015-03-23 19:51:29 +01:00
|
|
|
if (!recursiveNullify(itchild->second, newName))
|
2015-02-03 02:57:53 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
node->children.clear();
|
2015-03-23 19:51:29 +01:00
|
|
|
markNodeDirty(name, NULL);
|
2015-02-03 02:57:53 +01:00
|
|
|
delete node;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::updateHash(const std::string& name, uint256& hash)
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
2015-09-24 07:15:28 +02:00
|
|
|
CClaimTrieNode* current = &root;
|
2015-02-03 02:57:53 +01:00
|
|
|
for (std::string::const_iterator itname = name.begin(); itname != name.end(); ++itname)
|
|
|
|
{
|
|
|
|
nodeMapType::iterator itchild = current->children.find(*itname);
|
|
|
|
if (itchild == current->children.end())
|
|
|
|
return false;
|
|
|
|
current = itchild->second;
|
|
|
|
}
|
|
|
|
assert(current != NULL);
|
|
|
|
current->hash = hash;
|
2015-03-23 19:51:29 +01:00
|
|
|
markNodeDirty(name, current);
|
2015-02-03 02:57:53 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
void CClaimTrie::BatchWriteNode(CLevelDBBatch& batch, const std::string& name, const CClaimTrieNode* pNode) const
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
2015-03-09 01:24:13 +01:00
|
|
|
LogPrintf("%s: Writing %s to disk with %d values\n", __func__, name, pNode->values.size());
|
2015-03-23 19:51:29 +01:00
|
|
|
if (pNode)
|
2015-09-25 23:09:21 +02:00
|
|
|
batch.Write(std::make_pair(TRIE_NODE, name), *pNode);
|
2015-03-23 19:51:29 +01:00
|
|
|
else
|
2015-09-25 23:09:21 +02:00
|
|
|
batch.Erase(std::make_pair(TRIE_NODE, name));
|
2015-02-03 02:57:53 +01:00
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
void CClaimTrie::BatchWriteQueueRows(CLevelDBBatch& batch)
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-05-21 19:50:40 +02:00
|
|
|
for (valueQueueType::iterator itQueue = dirtyQueueRows.begin(); itQueue != dirtyQueueRows.end(); ++itQueue)
|
|
|
|
{
|
|
|
|
if (itQueue->second.empty())
|
|
|
|
{
|
2015-09-25 23:09:21 +02:00
|
|
|
batch.Erase(std::make_pair(QUEUE_ROW, itQueue->first));
|
2015-05-21 19:50:40 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-25 23:09:21 +02:00
|
|
|
batch.Write(std::make_pair(QUEUE_ROW, itQueue->first), itQueue->second);
|
2015-05-21 19:50:40 +02:00
|
|
|
}
|
|
|
|
}
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
void CClaimTrie::BatchWriteExpirationQueueRows(CLevelDBBatch& batch)
|
2015-05-27 23:53:12 +02:00
|
|
|
{
|
|
|
|
for (valueQueueType::iterator itQueue = dirtyExpirationQueueRows.begin(); itQueue != dirtyExpirationQueueRows.end(); ++itQueue)
|
|
|
|
{
|
|
|
|
if (itQueue->second.empty())
|
|
|
|
{
|
2015-09-25 23:09:21 +02:00
|
|
|
batch.Erase(std::make_pair(EXP_QUEUE_ROW, itQueue->first));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
batch.Write(std::make_pair(EXP_QUEUE_ROW, itQueue->first), itQueue->second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CClaimTrie::BatchWriteSupportNodes(CLevelDBBatch& batch)
|
|
|
|
{
|
|
|
|
for (supportMapType::iterator itSupport = dirtySupportNodes.begin(); itSupport != dirtySupportNodes.end(); ++itSupport)
|
|
|
|
{
|
|
|
|
if (itSupport->second.empty())
|
|
|
|
{
|
|
|
|
batch.Erase(std::make_pair(SUPPORT, itSupport->first));
|
2015-05-27 23:53:12 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-25 23:09:21 +02:00
|
|
|
batch.Write(std::make_pair(SUPPORT, itSupport->first), itSupport->second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CClaimTrie::BatchWriteSupportQueueRows(CLevelDBBatch& batch)
|
|
|
|
{
|
|
|
|
for (supportValueQueueType::iterator itQueue = dirtySupportQueueRows.begin(); itQueue != dirtySupportQueueRows.end(); ++itQueue)
|
|
|
|
{
|
|
|
|
if (itQueue->second.empty())
|
|
|
|
{
|
|
|
|
batch.Erase(std::make_pair(SUPPORT_QUEUE, itQueue->first));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
batch.Write(std::make_pair(SUPPORT_QUEUE, itQueue->first), itQueue->second);
|
2015-05-27 23:53:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::WriteToDisk()
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
|
|
|
CLevelDBBatch batch;
|
2015-03-23 19:51:29 +01:00
|
|
|
for (nodeCacheType::iterator itcache = dirtyNodes.begin(); itcache != dirtyNodes.end(); ++itcache)
|
2015-02-03 02:57:53 +01:00
|
|
|
BatchWriteNode(batch, itcache->first, itcache->second);
|
2015-03-23 19:51:29 +01:00
|
|
|
dirtyNodes.clear();
|
2015-05-21 19:50:40 +02:00
|
|
|
BatchWriteQueueRows(batch);
|
|
|
|
dirtyQueueRows.clear();
|
2015-05-27 23:53:12 +02:00
|
|
|
BatchWriteExpirationQueueRows(batch);
|
|
|
|
dirtyExpirationQueueRows.clear();
|
2015-09-25 23:09:21 +02:00
|
|
|
BatchWriteSupportNodes(batch);
|
|
|
|
dirtySupportNodes.clear();
|
|
|
|
BatchWriteSupportQueueRows(batch);
|
|
|
|
dirtySupportQueueRows.clear();
|
|
|
|
batch.Write(HASH_BLOCK, hashBlock);
|
|
|
|
batch.Write(CURRENT_HEIGHT, nCurrentHeight);
|
2015-02-03 02:57:53 +01:00
|
|
|
return db.WriteBatch(batch);
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::InsertFromDisk(const std::string& name, CClaimTrieNode* node)
|
2015-02-05 20:24:09 +01:00
|
|
|
{
|
|
|
|
if (name.size() == 0)
|
2015-02-10 17:19:41 +01:00
|
|
|
{
|
2015-02-05 20:24:09 +01:00
|
|
|
root = *node;
|
|
|
|
return true;
|
2015-02-10 17:19:41 +01:00
|
|
|
}
|
2015-09-24 07:15:28 +02:00
|
|
|
CClaimTrieNode* current = &root;
|
2015-02-05 20:24:09 +01:00
|
|
|
for (std::string::const_iterator itname = name.begin(); itname + 1 != name.end(); ++itname)
|
|
|
|
{
|
|
|
|
nodeMapType::iterator itchild = current->children.find(*itname);
|
|
|
|
if (itchild == current->children.end())
|
|
|
|
return false;
|
|
|
|
current = itchild->second;
|
|
|
|
}
|
|
|
|
current->children[name[name.size()-1]] = node;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrie::ReadFromDisk(bool check)
|
2015-02-05 20:24:09 +01:00
|
|
|
{
|
2015-09-25 23:09:21 +02:00
|
|
|
if (!db.Read(HASH_BLOCK, hashBlock))
|
2015-02-10 21:30:40 +01:00
|
|
|
LogPrintf("%s: Couldn't read the best block's hash\n", __func__);
|
2015-09-25 23:09:21 +02:00
|
|
|
if (!db.Read(CURRENT_HEIGHT, nCurrentHeight))
|
2015-03-19 17:57:56 +01:00
|
|
|
LogPrintf("%s: Couldn't read the current height\n", __func__);
|
2015-02-05 20:24:09 +01:00
|
|
|
boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
|
|
|
|
pcursor->SeekToFirst();
|
|
|
|
|
|
|
|
while (pcursor->Valid())
|
|
|
|
{
|
2015-02-10 17:19:41 +01:00
|
|
|
try
|
2015-02-05 20:24:09 +01:00
|
|
|
{
|
|
|
|
leveldb::Slice slKey = pcursor->key();
|
|
|
|
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
|
|
|
|
char chType;
|
|
|
|
ssKey >> chType;
|
2015-09-25 23:09:21 +02:00
|
|
|
if (chType == TRIE_NODE)
|
2015-02-05 20:24:09 +01:00
|
|
|
{
|
|
|
|
leveldb::Slice slValue = pcursor->value();
|
|
|
|
std::string name;
|
|
|
|
ssKey >> name;
|
|
|
|
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
|
2015-09-24 07:15:28 +02:00
|
|
|
CClaimTrieNode* node = new CClaimTrieNode();
|
2015-02-05 20:24:09 +01:00
|
|
|
ssValue >> *node;
|
|
|
|
if (!InsertFromDisk(name, node))
|
|
|
|
return false;
|
|
|
|
}
|
2015-02-10 17:19:41 +01:00
|
|
|
pcursor->Next();
|
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
|
2015-02-05 20:24:09 +01:00
|
|
|
}
|
2015-02-10 17:19:41 +01:00
|
|
|
|
2015-02-05 20:24:09 +01:00
|
|
|
}
|
|
|
|
if (check)
|
2015-02-10 17:19:41 +01:00
|
|
|
{
|
2015-09-24 07:15:28 +02:00
|
|
|
LogPrintf("Checking Claim trie consistency...");
|
2015-03-17 06:16:37 +01:00
|
|
|
if (checkConsistency())
|
2015-02-10 17:19:41 +01:00
|
|
|
{
|
|
|
|
LogPrintf("consistent\n");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
LogPrintf("inconsistent!\n");
|
|
|
|
return false;
|
|
|
|
}
|
2015-02-05 20:24:09 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::recursiveComputeMerkleHash(CClaimTrieNode* tnCurrent, std::string sPos) const
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
2015-02-10 17:19:41 +01:00
|
|
|
if (sPos == "" && tnCurrent->empty())
|
|
|
|
{
|
|
|
|
cacheHashes[""] = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
|
|
|
|
return true;
|
|
|
|
}
|
2015-03-26 03:10:05 +01:00
|
|
|
std::vector<unsigned char> vchToHash;
|
2015-02-03 02:57:53 +01:00
|
|
|
nodeCacheType::iterator cachedNode;
|
|
|
|
|
|
|
|
|
|
|
|
for (nodeMapType::iterator it = tnCurrent->children.begin(); it != tnCurrent->children.end(); ++it)
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << it->first;
|
|
|
|
std::string sNextPos = sPos + ss.str();
|
|
|
|
if (dirtyHashes.count(sNextPos) != 0)
|
|
|
|
{
|
|
|
|
// the child might be in the cache, so look for it there
|
|
|
|
cachedNode = cache.find(sNextPos);
|
|
|
|
if (cachedNode != cache.end())
|
|
|
|
recursiveComputeMerkleHash(cachedNode->second, sNextPos);
|
|
|
|
else
|
|
|
|
recursiveComputeMerkleHash(it->second, sNextPos);
|
|
|
|
}
|
2015-03-26 03:10:05 +01:00
|
|
|
vchToHash.push_back(it->first);
|
2015-02-03 02:57:53 +01:00
|
|
|
hashMapType::iterator ithash = cacheHashes.find(sNextPos);
|
|
|
|
if (ithash != cacheHashes.end())
|
2015-03-26 03:10:05 +01:00
|
|
|
{
|
|
|
|
vchToHash.insert(vchToHash.end(), ithash->second.begin(), ithash->second.end());
|
|
|
|
}
|
2015-02-03 02:57:53 +01:00
|
|
|
else
|
2015-03-26 03:10:05 +01:00
|
|
|
{
|
|
|
|
vchToHash.insert(vchToHash.end(), it->second->hash.begin(), it->second->hash.end());
|
|
|
|
}
|
2015-02-03 02:57:53 +01:00
|
|
|
}
|
2015-02-23 23:51:52 +01:00
|
|
|
|
|
|
|
CNodeValue val;
|
2015-03-17 06:16:37 +01:00
|
|
|
bool hasValue = tnCurrent->getBestValue(val);
|
2015-02-23 23:51:52 +01:00
|
|
|
|
|
|
|
if (hasValue)
|
|
|
|
{
|
2015-03-26 03:10:05 +01:00
|
|
|
uint256 valHash = val.GetHash();
|
|
|
|
vchToHash.insert(vchToHash.end(), valHash.begin(), valHash.end());
|
2015-02-23 23:51:52 +01:00
|
|
|
}
|
|
|
|
|
2015-02-03 02:57:53 +01:00
|
|
|
CHash256 hasher;
|
|
|
|
std::vector<unsigned char> vchHash(hasher.OUTPUT_SIZE);
|
2015-03-26 03:10:05 +01:00
|
|
|
hasher.Write(vchToHash.data(), vchToHash.size());
|
2015-02-03 02:57:53 +01:00
|
|
|
hasher.Finalize(&(vchHash[0]));
|
|
|
|
cacheHashes[sPos] = uint256(vchHash);
|
|
|
|
std::set<std::string>::iterator itDirty = dirtyHashes.find(sPos);
|
|
|
|
if (itDirty != dirtyHashes.end())
|
|
|
|
dirtyHashes.erase(itDirty);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
uint256 CClaimTrieCache::getMerkleHash() const
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
|
|
|
if (empty())
|
|
|
|
{
|
|
|
|
uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
|
|
|
return one;
|
|
|
|
}
|
|
|
|
if (dirty())
|
|
|
|
{
|
|
|
|
nodeCacheType::iterator cachedNode = cache.find("");
|
|
|
|
if (cachedNode != cache.end())
|
|
|
|
recursiveComputeMerkleHash(cachedNode->second, "");
|
|
|
|
else
|
|
|
|
recursiveComputeMerkleHash(&(base->root), "");
|
|
|
|
}
|
|
|
|
hashMapType::iterator ithash = cacheHashes.find("");
|
|
|
|
if (ithash != cacheHashes.end())
|
|
|
|
return ithash->second;
|
|
|
|
else
|
|
|
|
return base->root.hash;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::empty() const
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
2015-02-10 21:30:40 +01:00
|
|
|
return base->empty() && cache.empty();
|
2015-02-03 02:57:53 +01:00
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::insertClaimIntoTrie(const std::string name, CNodeValue val) const
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
2015-02-05 20:24:09 +01:00
|
|
|
assert(base);
|
2015-09-24 07:15:28 +02:00
|
|
|
CClaimTrieNode* currentNode = &(base->root);
|
2015-02-03 02:57:53 +01:00
|
|
|
nodeCacheType::iterator cachedNode;
|
|
|
|
cachedNode = cache.find("");
|
|
|
|
if (cachedNode != cache.end())
|
|
|
|
currentNode = cachedNode->second;
|
|
|
|
if (currentNode == NULL)
|
|
|
|
{
|
2015-09-24 07:15:28 +02:00
|
|
|
currentNode = new CClaimTrieNode();
|
2015-02-03 02:57:53 +01:00
|
|
|
cache[""] = currentNode;
|
|
|
|
}
|
|
|
|
for (std::string::const_iterator itCur = name.begin(); itCur != name.end(); ++itCur)
|
|
|
|
{
|
|
|
|
std::string sCurrentSubstring(name.begin(), itCur);
|
|
|
|
std::string sNextSubstring(name.begin(), itCur + 1);
|
|
|
|
|
|
|
|
cachedNode = cache.find(sNextSubstring);
|
|
|
|
if (cachedNode != cache.end())
|
|
|
|
{
|
|
|
|
currentNode = cachedNode->second;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
nodeMapType::iterator childNode = currentNode->children.find(*itCur);
|
|
|
|
if (childNode != currentNode->children.end())
|
|
|
|
{
|
|
|
|
currentNode = childNode->second;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This next substring doesn't exist in the cache and the next
|
|
|
|
// character doesn't exist in current node's children, so check
|
|
|
|
// if the current node is in the cache, and if it's not, copy
|
|
|
|
// it and stick it in the cache, and then create a new node as
|
|
|
|
// its child and stick that in the cache. We have to have both
|
|
|
|
// this node and its child in the cache so that the current
|
|
|
|
// node's child map will contain the next letter, which will be
|
|
|
|
// used to find the child in the cache. This is necessary in
|
|
|
|
// order to calculate the merkle hash.
|
|
|
|
cachedNode = cache.find(sCurrentSubstring);
|
|
|
|
if (cachedNode != cache.end())
|
|
|
|
{
|
|
|
|
assert(cachedNode->second == currentNode);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-24 07:15:28 +02:00
|
|
|
currentNode = new CClaimTrieNode(*currentNode);
|
2015-02-03 02:57:53 +01:00
|
|
|
cache[sCurrentSubstring] = currentNode;
|
|
|
|
}
|
2015-09-24 07:15:28 +02:00
|
|
|
CClaimTrieNode* newNode = new CClaimTrieNode();
|
2015-02-03 02:57:53 +01:00
|
|
|
currentNode->children[*itCur] = newNode;
|
|
|
|
cache[sNextSubstring] = newNode;
|
|
|
|
currentNode = newNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
cachedNode = cache.find(name);
|
|
|
|
if (cachedNode != cache.end())
|
|
|
|
{
|
|
|
|
assert(cachedNode->second == currentNode);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-24 07:15:28 +02:00
|
|
|
currentNode = new CClaimTrieNode(*currentNode);
|
2015-02-03 02:57:53 +01:00
|
|
|
cache[name] = currentNode;
|
|
|
|
}
|
|
|
|
bool fChanged = false;
|
2015-09-25 23:09:21 +02:00
|
|
|
if (currentNode->values.empty())
|
|
|
|
{
|
|
|
|
fChanged = true;
|
|
|
|
currentNode->insertValue(val);//, &fChanged);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CNodeValue currentTop = currentNode->values.front();
|
|
|
|
currentNode->insertValue(val);
|
|
|
|
currentNode->reorderValues();
|
|
|
|
if (currentTop != currentNode->values.front())
|
|
|
|
fChanged = true;
|
|
|
|
}
|
2015-02-03 02:57:53 +01:00
|
|
|
if (fChanged)
|
|
|
|
{
|
|
|
|
for (std::string::const_iterator itCur = name.begin(); itCur != name.end(); ++itCur)
|
|
|
|
{
|
|
|
|
std::string sub(name.begin(), itCur);
|
|
|
|
dirtyHashes.insert(sub);
|
|
|
|
}
|
|
|
|
dirtyHashes.insert(name);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::removeClaimFromTrie(const std::string name, uint256 txhash, uint32_t nOut, int& nValidAtHeight) const
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
2015-02-05 20:24:09 +01:00
|
|
|
assert(base);
|
2015-09-24 07:15:28 +02:00
|
|
|
CClaimTrieNode* currentNode = &(base->root);
|
2015-02-05 20:24:09 +01:00
|
|
|
nodeCacheType::iterator cachedNode;
|
|
|
|
cachedNode = cache.find("");
|
|
|
|
if (cachedNode != cache.end())
|
|
|
|
currentNode = cachedNode->second;
|
|
|
|
assert(currentNode != NULL); // If there is no root in either the trie or the cache, how can there be any names to remove?
|
|
|
|
for (std::string::const_iterator itCur = name.begin(); itCur != name.end(); ++itCur)
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
|
|
|
std::string sCurrentSubstring(name.begin(), itCur);
|
|
|
|
std::string sNextSubstring(name.begin(), itCur + 1);
|
|
|
|
|
|
|
|
cachedNode = cache.find(sNextSubstring);
|
|
|
|
if (cachedNode != cache.end())
|
|
|
|
{
|
|
|
|
currentNode = cachedNode->second;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
nodeMapType::iterator childNode = currentNode->children.find(*itCur);
|
|
|
|
if (childNode != currentNode->children.end())
|
|
|
|
{
|
|
|
|
currentNode = childNode->second;
|
|
|
|
continue;
|
|
|
|
}
|
2015-02-10 17:19:41 +01:00
|
|
|
LogPrintf("%s: The name %s does not exist in the trie\n", __func__, name.c_str());
|
2015-02-03 02:57:53 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
cachedNode = cache.find(name);
|
|
|
|
if (cachedNode != cache.end())
|
|
|
|
assert(cachedNode->second == currentNode);
|
|
|
|
else
|
|
|
|
{
|
2015-09-24 07:15:28 +02:00
|
|
|
currentNode = new CClaimTrieNode(*currentNode);
|
2015-02-03 02:57:53 +01:00
|
|
|
cache[name] = currentNode;
|
|
|
|
}
|
|
|
|
bool fChanged = false;
|
|
|
|
assert(currentNode != NULL);
|
2015-03-17 06:16:37 +01:00
|
|
|
CNodeValue val;
|
2015-09-25 23:09:21 +02:00
|
|
|
bool success = false;
|
|
|
|
|
|
|
|
if (currentNode->values.empty())
|
|
|
|
{
|
|
|
|
LogPrintf("%s: Asked to remove value from node without values\n", __func__);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
CNodeValue currentTop = currentNode->values.front();
|
|
|
|
|
|
|
|
success = currentNode->removeValue(txhash, nOut, val);//, &fChanged);
|
|
|
|
|
|
|
|
if (!currentNode->values.empty())
|
|
|
|
{
|
|
|
|
currentNode->reorderValues();
|
|
|
|
if (currentTop != currentNode->values.front())
|
|
|
|
fChanged = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
fChanged = true;
|
|
|
|
|
2015-03-09 01:24:13 +01:00
|
|
|
if (!success)
|
|
|
|
{
|
|
|
|
LogPrintf("%s: Removing a value was unsuccessful. name = %s, txhash = %s, nOut = %d", __func__, name.c_str(), txhash.GetHex(), nOut);
|
|
|
|
}
|
2015-03-17 06:16:37 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
nValidAtHeight = val.nValidAtHeight;
|
|
|
|
}
|
2015-02-03 02:57:53 +01:00
|
|
|
assert(success);
|
|
|
|
if (fChanged)
|
|
|
|
{
|
|
|
|
for (std::string::const_iterator itCur = name.begin(); itCur != name.end(); ++itCur)
|
|
|
|
{
|
|
|
|
std::string sub(name.begin(), itCur);
|
|
|
|
dirtyHashes.insert(sub);
|
|
|
|
}
|
|
|
|
dirtyHashes.insert(name);
|
|
|
|
}
|
2015-09-24 07:15:28 +02:00
|
|
|
CClaimTrieNode* rootNode = &(base->root);
|
2015-02-03 02:57:53 +01:00
|
|
|
cachedNode = cache.find("");
|
|
|
|
if (cachedNode != cache.end())
|
|
|
|
rootNode = cachedNode->second;
|
|
|
|
return recursivePruneName(rootNode, 0, name);
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::recursivePruneName(CClaimTrieNode* tnCurrent, unsigned int nPos, std::string sName, bool* pfNullified) const
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
|
|
|
bool fNullified = false;
|
|
|
|
std::string sCurrentSubstring = sName.substr(0, nPos);
|
|
|
|
if (nPos < sName.size())
|
|
|
|
{
|
|
|
|
std::string sNextSubstring = sName.substr(0, nPos + 1);
|
|
|
|
unsigned char cNext = sName.at(nPos);
|
2015-09-24 07:15:28 +02:00
|
|
|
CClaimTrieNode* tnNext = NULL;
|
2015-02-03 02:57:53 +01:00
|
|
|
nodeCacheType::iterator cachedNode = cache.find(sNextSubstring);
|
|
|
|
if (cachedNode != cache.end())
|
|
|
|
tnNext = cachedNode->second;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nodeMapType::iterator childNode = tnCurrent->children.find(cNext);
|
|
|
|
if (childNode != tnCurrent->children.end())
|
|
|
|
tnNext = childNode->second;
|
|
|
|
}
|
|
|
|
if (tnNext == NULL)
|
|
|
|
return false;
|
|
|
|
bool fChildNullified = false;
|
|
|
|
if (!recursivePruneName(tnNext, nPos + 1, sName, &fChildNullified))
|
|
|
|
return false;
|
|
|
|
if (fChildNullified)
|
|
|
|
{
|
|
|
|
// If the child nullified itself, the child should already be
|
|
|
|
// out of the cache, and the character must now be removed
|
|
|
|
// from the current node's map of child nodes to ensure that
|
|
|
|
// it isn't found when calculating the merkle hash. But
|
|
|
|
// tnCurrent isn't necessarily in the cache. If it's not, it
|
|
|
|
// has to be added to the cache, so nothing is changed in the
|
|
|
|
// trie. If the current node is added to the cache, however,
|
|
|
|
// that does not imply that the parent node must be altered to
|
|
|
|
// reflect that its child is now in the cache, since it
|
|
|
|
// already has a character in its child map which will be used
|
|
|
|
// when calculating the merkle root.
|
|
|
|
|
|
|
|
// First, find out if this node is in the cache.
|
|
|
|
cachedNode = cache.find(sCurrentSubstring);
|
|
|
|
if (cachedNode == cache.end())
|
|
|
|
{
|
|
|
|
// it isn't, so make a copy, stick it in the cache,
|
|
|
|
// and make it the new current node
|
2015-09-24 07:15:28 +02:00
|
|
|
tnCurrent = new CClaimTrieNode(*tnCurrent);
|
2015-02-03 02:57:53 +01:00
|
|
|
cache[sCurrentSubstring] = tnCurrent;
|
|
|
|
}
|
|
|
|
// erase the character from the current node, which is
|
|
|
|
// now guaranteed to be in the cache
|
|
|
|
nodeMapType::iterator childNode = tnCurrent->children.find(cNext);
|
|
|
|
if (childNode != tnCurrent->children.end())
|
|
|
|
tnCurrent->children.erase(childNode);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sCurrentSubstring.size() != 0 && tnCurrent->empty())
|
|
|
|
{
|
|
|
|
// If the current node is in the cache, remove it from there
|
|
|
|
nodeCacheType::iterator cachedNode = cache.find(sCurrentSubstring);
|
|
|
|
if (cachedNode != cache.end())
|
|
|
|
{
|
|
|
|
assert(tnCurrent == cachedNode->second);
|
|
|
|
delete tnCurrent;
|
|
|
|
cache.erase(cachedNode);
|
|
|
|
}
|
|
|
|
fNullified = true;
|
|
|
|
}
|
|
|
|
if (pfNullified)
|
|
|
|
*pfNullified = fNullified;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
valueQueueType::iterator CClaimTrieCache::getQueueCacheRow(int nHeight, bool createIfNotExists) const
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
|
|
|
valueQueueType::iterator itQueueRow = valueQueueCache.find(nHeight);
|
|
|
|
if (itQueueRow == valueQueueCache.end())
|
|
|
|
{
|
|
|
|
// Have to make a new row it put in the cache, if createIfNotExists is true
|
|
|
|
std::vector<CValueQueueEntry> queueRow;
|
|
|
|
// If the row exists in the base, copy its values into the new row.
|
2015-05-21 19:50:40 +02:00
|
|
|
bool exists = base->getQueueRow(nHeight, queueRow);
|
|
|
|
if (!exists)
|
2015-03-17 06:16:37 +01:00
|
|
|
if (!createIfNotExists)
|
|
|
|
return itQueueRow;
|
|
|
|
// Stick the new row in the cache
|
|
|
|
std::pair<valueQueueType::iterator, bool> ret;
|
|
|
|
ret = valueQueueCache.insert(std::pair<int, std::vector<CValueQueueEntry> >(nHeight, queueRow));
|
|
|
|
assert(ret.second);
|
|
|
|
itQueueRow = ret.first;
|
|
|
|
}
|
|
|
|
return itQueueRow;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::addClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight) const
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-03-19 17:57:56 +01:00
|
|
|
LogPrintf("%s: name: %s, txhash: %s, nOut: %d, nAmount: %d, nHeight: %d, nCurrentHeight: %d\n", __func__, name, txhash.GetHex(), nOut, nAmount, nHeight, nCurrentHeight);
|
2015-03-17 06:16:37 +01:00
|
|
|
assert(nHeight == nCurrentHeight);
|
2015-05-27 23:53:12 +02:00
|
|
|
return addClaimToQueues(name, txhash, nOut, nAmount, nHeight, nHeight + DEFAULT_DELAY);
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::addClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, uint256 prevTxhash, uint32_t nPrevOut) const
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-03-19 17:57:56 +01:00
|
|
|
LogPrintf("%s: name: %s, txhash: %s, nOut: %d, nAmount: %d, nHeight: %d, nCurrentHeight: %d\n", __func__, name, txhash.GetHex(), nOut, nAmount, nHeight, nCurrentHeight);
|
2015-03-17 06:16:37 +01:00
|
|
|
assert(nHeight == nCurrentHeight);
|
|
|
|
CNodeValue val;
|
2015-06-25 20:05:27 +02:00
|
|
|
if (base->getInfoForName(name, val))
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
|
|
|
if (val.txhash == prevTxhash && val.nOut == nPrevOut)
|
2015-03-19 17:57:56 +01:00
|
|
|
{
|
|
|
|
LogPrintf("%s: This is an update to a best claim. Previous claim txhash: %s, nOut: %d\n", __func__, prevTxhash.GetHex(), nPrevOut);
|
2015-05-27 23:53:12 +02:00
|
|
|
return addClaimToQueues(name, txhash, nOut, nAmount, nHeight, nHeight);
|
2015-03-19 17:57:56 +01:00
|
|
|
}
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
|
|
|
return addClaim(name, txhash, nOut, nAmount, nHeight);
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::undoSpendClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-03-19 17:57:56 +01:00
|
|
|
LogPrintf("%s: name: %s, txhash: %s, nOut: %d, nAmount: %d, nHeight: %d, nValidAtHeight: %d, nCurrentHeight: %d\n", __func__, name, txhash.GetHex(), nOut, nAmount, nHeight, nValidAtHeight, nCurrentHeight);
|
2015-03-17 06:16:37 +01:00
|
|
|
if (nValidAtHeight < nCurrentHeight)
|
|
|
|
{
|
|
|
|
CNodeValue val(txhash, nOut, nAmount, nHeight, nValidAtHeight);
|
|
|
|
CValueQueueEntry entry(name, val);
|
2015-05-27 23:53:12 +02:00
|
|
|
addToExpirationQueue(entry);
|
2015-09-25 23:09:21 +02:00
|
|
|
return insertClaimIntoTrie(name, val);
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-25 23:09:21 +02:00
|
|
|
return addClaimToQueues(name, txhash, nOut, nAmount, nHeight, nValidAtHeight);
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::addClaimToQueues(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-03-19 17:57:56 +01:00
|
|
|
LogPrintf("%s: nValidAtHeight: %d\n", __func__, nValidAtHeight);
|
2015-03-17 06:16:37 +01:00
|
|
|
CNodeValue val(txhash, nOut, nAmount, nHeight, nValidAtHeight);
|
|
|
|
CValueQueueEntry entry(name, val);
|
|
|
|
valueQueueType::iterator itQueueRow = getQueueCacheRow(nValidAtHeight, true);
|
|
|
|
itQueueRow->second.push_back(entry);
|
2015-05-27 23:53:12 +02:00
|
|
|
addToExpirationQueue(entry);
|
2015-03-17 06:16:37 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::removeClaimFromQueue(const std::string name, uint256 txhash, uint32_t nOut, int nHeightToCheck, int& nValidAtHeight) const
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
|
|
|
valueQueueType::iterator itQueueRow = getQueueCacheRow(nHeightToCheck, false);
|
|
|
|
if (itQueueRow == valueQueueCache.end())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::vector<CValueQueueEntry>::iterator itQueue;
|
|
|
|
for (itQueue = itQueueRow->second.begin(); itQueue != itQueueRow->second.end(); ++itQueue)
|
|
|
|
{
|
|
|
|
CNodeValue& val = itQueue->val;
|
|
|
|
if (name == itQueue->name && val.txhash == txhash && val.nOut == nOut)
|
|
|
|
{
|
|
|
|
nValidAtHeight = val.nValidAtHeight;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (itQueue != itQueueRow->second.end())
|
|
|
|
{
|
|
|
|
itQueueRow->second.erase(itQueue);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::undoAddClaim(const std::string name, uint256 txhash, uint32_t nOut, int nHeight) const
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
|
|
|
int throwaway;
|
|
|
|
return removeClaim(name, txhash, nOut, nHeight, throwaway);
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::spendClaim(const std::string name, uint256 txhash, uint32_t nOut, int nHeight, int& nValidAtHeight) const
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
|
|
|
return removeClaim(name, txhash, nOut, nHeight, nValidAtHeight);
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::removeClaim(const std::string name, uint256 txhash, uint32_t nOut, int nHeight, int& nValidAtHeight) const
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-03-19 17:57:56 +01:00
|
|
|
LogPrintf("%s: name: %s, txhash: %s, nOut: %s, nHeight: %s, nCurrentHeight: %s\n", __func__, name, txhash.GetHex(), nOut, nHeight, nCurrentHeight);
|
2015-05-27 23:53:12 +02:00
|
|
|
bool removed = false;
|
2015-03-17 06:16:37 +01:00
|
|
|
if (nHeight + DEFAULT_DELAY >= nCurrentHeight)
|
|
|
|
{
|
|
|
|
if (removeClaimFromQueue(name, txhash, nOut, nHeight + DEFAULT_DELAY, nValidAtHeight))
|
2015-05-27 23:53:12 +02:00
|
|
|
removed = true;
|
|
|
|
else if (removeClaimFromQueue(name, txhash, nOut, nHeight, nValidAtHeight))
|
|
|
|
removed = true;
|
|
|
|
}
|
2015-09-25 23:09:21 +02:00
|
|
|
//if (removed == false && removeClaimFromQueue(name, txhash, nOut, nHeight, nCurrentHeight))
|
|
|
|
// removed = true;
|
2015-05-27 23:53:12 +02:00
|
|
|
if (removed == false && removeClaimFromTrie(name, txhash, nOut, nValidAtHeight))
|
|
|
|
removed = true;
|
|
|
|
if (removed == true)
|
|
|
|
removeFromExpirationQueue(name, txhash, nOut, nHeight);
|
|
|
|
return removed;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
void CClaimTrieCache::addToExpirationQueue(CValueQueueEntry& entry) const
|
2015-05-27 23:53:12 +02:00
|
|
|
{
|
|
|
|
int expirationHeight = entry.val.nHeight + base->nExpirationTime;
|
|
|
|
valueQueueType::iterator itQueueRow = getExpirationQueueCacheRow(expirationHeight, true);
|
|
|
|
itQueueRow->second.push_back(entry);
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
void CClaimTrieCache::removeFromExpirationQueue(const std::string name, uint256 txhash, uint32_t nOut, int nHeight) const
|
2015-05-27 23:53:12 +02:00
|
|
|
{
|
|
|
|
int expirationHeight = nHeight + base->nExpirationTime;
|
|
|
|
valueQueueType::iterator itQueueRow = getExpirationQueueCacheRow(expirationHeight, false);
|
|
|
|
std::vector<CValueQueueEntry>::iterator itQueue;
|
|
|
|
if (itQueueRow != valueQueueCache.end())
|
|
|
|
{
|
|
|
|
for (itQueue = itQueueRow->second.begin(); itQueue != itQueueRow->second.end(); ++itQueue)
|
|
|
|
{
|
|
|
|
CNodeValue& val = itQueue->val;
|
|
|
|
if (name == itQueue->name && val.txhash == txhash && val.nOut == nOut)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (itQueue != itQueueRow->second.end())
|
|
|
|
{
|
|
|
|
itQueueRow->second.erase(itQueue);
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
valueQueueType::iterator CClaimTrieCache::getExpirationQueueCacheRow(int nHeight, bool createIfNotExists) const
|
2015-05-27 23:53:12 +02:00
|
|
|
{
|
|
|
|
valueQueueType::iterator itQueueRow = expirationQueueCache.find(nHeight);
|
|
|
|
if (itQueueRow == expirationQueueCache.end())
|
|
|
|
{
|
|
|
|
// Have to make a new row it put in the cache, if createIfNotExists is true
|
|
|
|
std::vector<CValueQueueEntry> queueRow;
|
|
|
|
// If the row exists in the base, copy its values into the new row.
|
|
|
|
bool exists = base->getExpirationQueueRow(nHeight, queueRow);
|
|
|
|
if (!exists)
|
|
|
|
if (!createIfNotExists)
|
|
|
|
return itQueueRow;
|
|
|
|
// Stick the new row in the cache
|
|
|
|
std::pair<valueQueueType::iterator, bool> ret;
|
|
|
|
ret = expirationQueueCache.insert(std::pair<int, std::vector<CValueQueueEntry> >(nHeight, queueRow));
|
|
|
|
assert(ret.second);
|
|
|
|
itQueueRow = ret.first;
|
|
|
|
}
|
|
|
|
return itQueueRow;
|
|
|
|
}
|
|
|
|
|
2015-09-25 23:09:21 +02:00
|
|
|
bool CClaimTrieCache::reorderTrieNode(const std::string name) const
|
|
|
|
{
|
|
|
|
assert(base);
|
|
|
|
nodeCacheType::iterator cachedNode;
|
|
|
|
cachedNode = cache.find("name");
|
|
|
|
if (cachedNode == cache.end())
|
|
|
|
{
|
|
|
|
CClaimTrieNode* currentNode = &(base->root);
|
|
|
|
for (std::string::const_iterator itCur = name.begin(); itCur != name.end(); ++itCur)
|
|
|
|
{
|
|
|
|
std::string sCurrentSubstring(name.begin(), itCur);
|
|
|
|
std::string sNextSubstring(name.begin(), itCur + 1);
|
|
|
|
|
|
|
|
cachedNode = cache.find(sNextSubstring);
|
|
|
|
if (cachedNode != cache.end())
|
|
|
|
{
|
|
|
|
currentNode = cachedNode->second;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
nodeMapType::iterator childNode = currentNode->children.find(*itCur);
|
|
|
|
if (childNode != currentNode->children.end())
|
|
|
|
{
|
|
|
|
currentNode = childNode->second;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// The node doesn't exist, so it can't be reordered.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
currentNode = new CClaimTrieNode(*currentNode);
|
|
|
|
std::pair<nodeCacheType::iterator, bool> ret;
|
|
|
|
ret = cache.insert(std::pair<std::string, CClaimTrieNode*>(name, currentNode));
|
|
|
|
assert(ret.second);
|
|
|
|
cachedNode = ret.first;
|
|
|
|
}
|
|
|
|
bool fChanged = false;
|
|
|
|
if (cachedNode->second->values.empty())
|
|
|
|
{
|
|
|
|
// Nothing in there to reorder
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CNodeValue currentTop = cachedNode->second->values.front();
|
|
|
|
cachedNode->second->reorderValues();
|
|
|
|
if (currentTop != cachedNode->second->values.front())
|
|
|
|
fChanged = true;
|
|
|
|
}
|
|
|
|
if (fChanged)
|
|
|
|
{
|
|
|
|
for (std::string::const_iterator itCur = name.begin(); itCur != name.end(); ++itCur)
|
|
|
|
{
|
|
|
|
std::string sub(name.begin(), itCur);
|
|
|
|
dirtyHashes.insert(sub);
|
|
|
|
}
|
|
|
|
dirtyHashes.insert(name);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrieCache::insertSupportIntoMap(const std::string name, CSupportNodeValue val) const
|
|
|
|
{
|
|
|
|
supportMapType::iterator cachedNode;
|
|
|
|
// If this node is already in the cache, use that
|
|
|
|
cachedNode = supportCache.find(name);
|
|
|
|
// If not, copy the one from base if it exists, and use that
|
|
|
|
if (cachedNode == supportCache.end())
|
|
|
|
{
|
|
|
|
supportMapNodeType node;
|
|
|
|
base->getSupportNode(name, node);
|
|
|
|
std::pair<supportMapType::iterator, bool> ret;
|
|
|
|
ret = supportCache.insert(std::pair<std::string, supportMapNodeType>(name, node));
|
|
|
|
assert(ret.second);
|
|
|
|
cachedNode = ret.first;
|
|
|
|
}
|
|
|
|
cachedNode->second.push_back(val);
|
|
|
|
// See if this changed the biggest bid
|
|
|
|
return reorderTrieNode(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrieCache::removeSupportFromMap(const std::string name, uint256 txhash, uint32_t nOut, uint256 supportedTxhash, int supportednOut, int nHeight, int& nValidAtHeight) const
|
|
|
|
{
|
|
|
|
supportMapType::iterator cachedNode;
|
|
|
|
cachedNode = supportCache.find(name);
|
|
|
|
if (cachedNode == supportCache.end())
|
|
|
|
{
|
|
|
|
supportMapNodeType node;
|
|
|
|
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, supportMapNodeType>(name, node));
|
|
|
|
assert(ret.second);
|
|
|
|
cachedNode = ret.first;
|
|
|
|
}
|
|
|
|
for (supportMapNodeType::iterator itSupport = cachedNode->second.begin(); itSupport != cachedNode->second.end(); ++itSupport)
|
|
|
|
{
|
|
|
|
if (itSupport->txhash == txhash && itSupport->nOut == nOut && itSupport->supportTxhash == supportedTxhash && itSupport->supportnOut == supportednOut && itSupport->nHeight == nHeight)
|
|
|
|
{
|
|
|
|
nValidAtHeight = itSupport->nValidAtHeight;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
supportValueQueueType::iterator CClaimTrieCache::getSupportQueueCacheRow(int nHeight, bool createIfNotExists) const
|
|
|
|
{
|
|
|
|
supportValueQueueType::iterator itQueueRow = supportQueueCache.find(nHeight);
|
|
|
|
if (itQueueRow == supportQueueCache.end())
|
|
|
|
{
|
|
|
|
std::vector<CSupportValueQueueEntry> queueRow;
|
|
|
|
bool exists = base->getSupportQueueRow(nHeight, queueRow);
|
|
|
|
if (!exists)
|
|
|
|
if (!createIfNotExists)
|
|
|
|
return itQueueRow;
|
|
|
|
// Stick the new row in the cache
|
|
|
|
std::pair<supportValueQueueType::iterator, bool> ret;
|
|
|
|
ret = supportQueueCache.insert(std::pair<int, std::vector<CSupportValueQueueEntry> >(nHeight, queueRow));
|
|
|
|
assert(ret.second);
|
|
|
|
itQueueRow = ret.first;
|
|
|
|
}
|
|
|
|
return itQueueRow;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrieCache::addSupportToQueue(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, uint256 supportedTxhash, int supportednOut, int nHeight, int nValidAtHeight) const
|
|
|
|
{
|
|
|
|
LogPrintf("%s: nValidAtHeight: %d\n", __func__, nValidAtHeight);
|
|
|
|
CSupportNodeValue val(txhash, nOut, supportedTxhash, supportednOut, nAmount, nHeight, nValidAtHeight);
|
|
|
|
CSupportValueQueueEntry entry(name, val);
|
|
|
|
supportValueQueueType::iterator itQueueRow = getSupportQueueCacheRow(nValidAtHeight, true);
|
|
|
|
itQueueRow->second.push_back(entry);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrieCache::removeSupportFromQueue(const std::string name, uint256 txhash, uint32_t nOut, uint256 supportedTxhash, int supportednOut, int nHeightToCheck, int& nValidAtHeight) const
|
|
|
|
{
|
|
|
|
supportValueQueueType::iterator itQueueRow = getSupportQueueCacheRow(nHeightToCheck, false);
|
|
|
|
if (itQueueRow == supportQueueCache.end())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::vector<CSupportValueQueueEntry>::iterator itQueue;
|
|
|
|
for (itQueue = itQueueRow->second.begin(); itQueue != itQueueRow->second.end(); ++itQueue)
|
|
|
|
{
|
|
|
|
CSupportNodeValue& val = itQueue->val;
|
|
|
|
if (name == itQueue->name && val.txhash == txhash && val.nOut == nOut && val.supportTxhash == supportedTxhash && val.supportnOut == supportednOut)
|
|
|
|
{
|
|
|
|
nValidAtHeight = val.nValidAtHeight;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (itQueue != itQueueRow->second.end())
|
|
|
|
{
|
|
|
|
itQueueRow->second.erase(itQueue);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrieCache::addSupport(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, uint256 supportedTxhash, int supportednOut, int nHeight) const
|
|
|
|
{
|
|
|
|
std::cout << "just adding some support" << std::endl;
|
|
|
|
LogPrintf("%s: name: %s, txhash: %s, nOut: %d, nAmount: %d, supportedTxhash: %s, supportednOut: %d, nHeight: %d, nCurrentHeight: %d\n", __func__, name, txhash.GetHex(), nOut, nAmount, supportedTxhash.GetHex(), supportednOut, nHeight);
|
|
|
|
assert(nHeight == nCurrentHeight);
|
|
|
|
CNodeValue val;
|
|
|
|
if (base->getInfoForName(name, val))
|
|
|
|
{
|
|
|
|
if (val.txhash == supportedTxhash && val.nOut == supportednOut)
|
|
|
|
{
|
|
|
|
LogPrintf("%s: This is a support to a best claim.\n", __func__);
|
|
|
|
return addSupportToQueue(name, txhash, nOut, nAmount, supportedTxhash, supportednOut, nHeight, nHeight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return addSupportToQueue(name, txhash, nOut, nAmount, supportedTxhash, supportednOut, nHeight, nHeight + DEFAULT_DELAY);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrieCache::undoSpendSupport(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, uint256 supportedTxhash, int supportednOut, int nHeight, int nValidAtHeight) const
|
|
|
|
{
|
|
|
|
LogPrintf("%s: name: %s, txhash: %s, nOut: %d, nAmount: %d, supportedTxhash: %s, supportednOut: %d, nHeight: %d, nCurrentHeight: %d\n", __func__, name, txhash.GetHex(), nOut, nAmount, supportedTxhash.GetHex(), supportednOut, nHeight);
|
|
|
|
if (nValidAtHeight < nCurrentHeight)
|
|
|
|
{
|
|
|
|
CSupportNodeValue val(txhash, nOut, supportedTxhash, supportednOut, nAmount, nHeight, nValidAtHeight);
|
|
|
|
CSupportValueQueueEntry entry(name, val);
|
|
|
|
return insertSupportIntoMap(name, val);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return addSupportToQueue(name, txhash, nOut, nAmount, supportedTxhash, supportednOut, nHeight, nValidAtHeight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrieCache::removeSupport(const std::string name, uint256 txhash, uint32_t nOut, uint256 supportedTxhash, int supportednOut, int nHeight, int& nValidAtHeight) const
|
|
|
|
{
|
|
|
|
bool removed = false;
|
|
|
|
if (nHeight + DEFAULT_DELAY >= nCurrentHeight)
|
|
|
|
{
|
|
|
|
if (removeSupportFromQueue(name, txhash, nOut, supportedTxhash, supportednOut, nHeight + DEFAULT_DELAY, nValidAtHeight))
|
|
|
|
removed = true;
|
|
|
|
else if (removeSupportFromQueue(name, txhash, nOut, supportedTxhash, supportednOut, nHeight, nValidAtHeight))
|
|
|
|
removed = true;
|
|
|
|
}
|
|
|
|
if (removed == false && removeSupportFromMap(name, txhash, nOut, supportedTxhash, supportednOut, nHeight, nValidAtHeight))
|
|
|
|
removed = true;
|
|
|
|
return removed;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrieCache::undoAddSupport(const std::string name, uint256 txhash, uint32_t nOut, uint256 supportedTxhash, int supportednOut, int nHeight) const
|
|
|
|
{
|
|
|
|
LogPrintf("%s: name: %s, txhash: %s, nOut: %d, supportedTxhash: %s, supportednOut: %d, nHeight: %d, nCurrentHeight: %d\n", __func__, name, txhash.GetHex(), nOut, supportedTxhash.GetHex(), supportednOut, nHeight);
|
|
|
|
int throwaway;
|
|
|
|
return removeSupport(name, txhash, nOut, supportedTxhash, supportednOut, nHeight, throwaway);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrieCache::spendSupport(const std::string name, uint256 txhash, uint32_t nOut, uint256 supportedTxhash, int supportednOut, int nHeight, int& nValidAtHeight) const
|
|
|
|
{
|
|
|
|
LogPrintf("%s: name: %s, txhash: %s, nOut: %d, supportedTxhash: %s, supportednOut: %d, nHeight: %d, nCurrentHeight: %d\n", __func__, name, txhash.GetHex(), nOut, supportedTxhash.GetHex(), supportednOut, nHeight);
|
|
|
|
return removeSupport(name, txhash, nOut, supportedTxhash, supportednOut, nHeight, nValidAtHeight);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CClaimTrieCache::incrementBlock(CClaimTrieQueueUndo& insertUndo, CClaimTrieQueueUndo& expireUndo, CSupportValueQueueUndo& insertSupportUndo) const
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-03-19 17:57:56 +01:00
|
|
|
LogPrintf("%s: nCurrentHeight (before increment): %d\n", __func__, nCurrentHeight);
|
2015-03-17 06:16:37 +01:00
|
|
|
valueQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, false);
|
2015-05-27 23:53:12 +02:00
|
|
|
if (itQueueRow != valueQueueCache.end())
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-05-27 23:53:12 +02:00
|
|
|
for (std::vector<CValueQueueEntry>::iterator itEntry = itQueueRow->second.begin(); itEntry != itQueueRow->second.end(); ++itEntry)
|
|
|
|
{
|
|
|
|
insertClaimIntoTrie(itEntry->name, itEntry->val);
|
|
|
|
insertUndo.push_back(*itEntry);
|
|
|
|
}
|
|
|
|
itQueueRow->second.clear();
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
2015-05-27 23:53:12 +02:00
|
|
|
valueQueueType::iterator itExpirationRow = getExpirationQueueCacheRow(nCurrentHeight, false);
|
|
|
|
if (itExpirationRow != expirationQueueCache.end())
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-05-27 23:53:12 +02:00
|
|
|
for (std::vector<CValueQueueEntry>::iterator itEntry = itExpirationRow->second.begin(); itEntry != itExpirationRow->second.end(); ++itEntry)
|
|
|
|
{
|
|
|
|
int nValidAtHeight;
|
|
|
|
assert(base->nExpirationTime > DEFAULT_DELAY);
|
|
|
|
assert(removeClaimFromTrie(itEntry->name, itEntry->val.txhash, itEntry->val.nOut, nValidAtHeight));
|
|
|
|
expireUndo.push_back(*itEntry);
|
|
|
|
}
|
|
|
|
itExpirationRow->second.clear();
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
2015-09-25 23:09:21 +02:00
|
|
|
supportValueQueueType::iterator itSupportRow = getSupportQueueCacheRow(nCurrentHeight, false);
|
|
|
|
if (itSupportRow != supportQueueCache.end())
|
|
|
|
{
|
|
|
|
for (std::vector<CSupportValueQueueEntry>::iterator itSupport = itSupportRow->second.begin(); itSupport != itSupportRow->second.end(); ++itSupport)
|
|
|
|
{
|
|
|
|
insertSupportIntoMap(itSupport->name, itSupport->val);
|
|
|
|
insertSupportUndo.push_back(*itSupport);
|
|
|
|
}
|
|
|
|
itSupportRow->second.clear();
|
|
|
|
}
|
2015-05-27 23:53:12 +02:00
|
|
|
nCurrentHeight++;
|
2015-03-17 06:16:37 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-25 23:09:21 +02:00
|
|
|
bool CClaimTrieCache::decrementBlock(CClaimTrieQueueUndo& insertUndo, CClaimTrieQueueUndo& expireUndo, CSupportValueQueueUndo& insertSupportUndo) const
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-03-19 17:57:56 +01:00
|
|
|
LogPrintf("%s: nCurrentHeight (before decrement): %d\n", __func__, nCurrentHeight);
|
2015-03-17 06:16:37 +01:00
|
|
|
nCurrentHeight--;
|
2015-05-27 23:53:12 +02:00
|
|
|
if (insertUndo.begin() != insertUndo.end())
|
2015-03-17 06:16:37 +01:00
|
|
|
{
|
2015-05-21 19:50:40 +02:00
|
|
|
valueQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, true);
|
2015-09-24 07:15:28 +02:00
|
|
|
for (CClaimTrieQueueUndo::iterator itInsertUndo = insertUndo.begin(); itInsertUndo != insertUndo.end(); ++itInsertUndo)
|
2015-05-21 19:50:40 +02:00
|
|
|
{
|
|
|
|
int nValidHeightInTrie;
|
2015-05-27 23:53:12 +02:00
|
|
|
assert(removeClaimFromTrie(itInsertUndo->name, itInsertUndo->val.txhash, itInsertUndo->val.nOut, nValidHeightInTrie));
|
|
|
|
assert(nValidHeightInTrie == itInsertUndo->val.nValidAtHeight);
|
|
|
|
itQueueRow->second.push_back(*itInsertUndo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (expireUndo.begin() != expireUndo.end())
|
|
|
|
{
|
|
|
|
valueQueueType::iterator itExpireRow = getExpirationQueueCacheRow(nCurrentHeight, true);
|
2015-09-24 07:15:28 +02:00
|
|
|
for (CClaimTrieQueueUndo::iterator itExpireUndo = expireUndo.begin(); itExpireUndo != expireUndo.end(); ++itExpireUndo)
|
2015-05-27 23:53:12 +02:00
|
|
|
{
|
|
|
|
insertClaimIntoTrie(itExpireUndo->name, itExpireUndo->val);
|
|
|
|
itExpireRow->second.push_back(*itExpireUndo);
|
2015-05-21 19:50:40 +02:00
|
|
|
}
|
2015-03-17 06:16:37 +01:00
|
|
|
}
|
2015-09-25 23:09:21 +02:00
|
|
|
if (insertSupportUndo.begin() != insertSupportUndo.end())
|
|
|
|
{
|
|
|
|
supportValueQueueType::iterator itSupportRow = getSupportQueueCacheRow(nCurrentHeight, true);
|
|
|
|
for (CSupportValueQueueUndo::iterator itSupportUndo = insertSupportUndo.begin(); itSupportUndo != insertSupportUndo.end(); ++itSupportUndo)
|
|
|
|
{
|
|
|
|
int nValidHeightInMap;
|
|
|
|
assert(removeSupportFromMap(itSupportUndo->name, itSupportUndo->val.txhash, itSupportUndo->val.nOut, itSupportUndo->val.supportTxhash, itSupportUndo->val.supportnOut, itSupportUndo->val.nHeight, nValidHeightInMap));
|
|
|
|
assert(nValidHeightInMap == itSupportUndo->val.nValidAtHeight);
|
|
|
|
itSupportRow->second.push_back(*itSupportUndo);
|
|
|
|
}
|
|
|
|
}
|
2015-03-17 06:16:37 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
uint256 CClaimTrieCache::getBestBlock()
|
2015-02-10 21:30:40 +01:00
|
|
|
{
|
|
|
|
if (hashBlock.IsNull())
|
|
|
|
if (base != NULL)
|
|
|
|
hashBlock = base->hashBlock;
|
|
|
|
return hashBlock;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
void CClaimTrieCache::setBestBlock(const uint256& hashBlockIn)
|
2015-02-10 21:30:40 +01:00
|
|
|
{
|
|
|
|
hashBlock = hashBlockIn;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::clear() const
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
|
|
|
for (nodeCacheType::iterator itcache = cache.begin(); itcache != cache.end(); ++itcache)
|
|
|
|
{
|
|
|
|
delete itcache->second;
|
|
|
|
}
|
|
|
|
cache.clear();
|
|
|
|
dirtyHashes.clear();
|
|
|
|
cacheHashes.clear();
|
2015-03-17 06:16:37 +01:00
|
|
|
valueQueueCache.clear();
|
2015-09-25 23:09:21 +02:00
|
|
|
expirationQueueCache.clear();
|
|
|
|
supportCache.clear();
|
|
|
|
supportQueueCache.clear();
|
2015-02-03 02:57:53 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-24 07:15:28 +02:00
|
|
|
bool CClaimTrieCache::flush()
|
2015-02-03 02:57:53 +01:00
|
|
|
{
|
|
|
|
if (dirty())
|
|
|
|
getMerkleHash();
|
2015-09-25 23:09:21 +02:00
|
|
|
bool success = base->update(cache, cacheHashes, getBestBlock(), valueQueueCache, expirationQueueCache, nCurrentHeight, supportCache, supportQueueCache);
|
2015-02-03 02:57:53 +01:00
|
|
|
if (success)
|
|
|
|
{
|
|
|
|
success = clear();
|
|
|
|
}
|
|
|
|
return success;
|
|
|
|
}
|