Implement a hard fork for extended/infinite claim expiration times #112
7 changed files with 601 additions and 80 deletions
|
@ -1625,7 +1625,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
|||
if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
|
||||
return error("DisconnectBlock(): block and undo data inconsistent");
|
||||
|
||||
assert(trieCache.decrementBlock(blockUndo.queueUndo));
|
||||
assert(trieCache.decrementBlock(blockUndo.insertUndo, blockUndo.expireUndo));
|
||||
|
||||
// undo transactions in reverse order
|
||||
for (int i = block.vtx.size() - 1; i >= 0; i--) {
|
||||
|
@ -1934,7 +1934,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
|
||||
}
|
||||
|
||||
assert(trieCache.incrementBlock(blockundo.queueUndo));
|
||||
assert(trieCache.incrementBlock(blockundo.insertUndo, blockundo.expireUndo));
|
||||
|
||||
if (trieCache.getMerkleHash() != block.hashNCCTrie)
|
||||
return state.DoS(100,
|
||||
|
|
|
@ -394,8 +394,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
|||
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
|
||||
pblock->nNonce = 0;
|
||||
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
|
||||
CNCCTrieQueueUndo dummyundo;
|
||||
trieCache.incrementBlock(dummyundo);
|
||||
CNCCTrieQueueUndo dummyInsertUndo;
|
||||
CNCCTrieQueueUndo dummyExpireUndo;
|
||||
trieCache.incrementBlock(dummyInsertUndo, dummyExpireUndo);
|
||||
pblock->hashNCCTrie = trieCache.getMerkleHash();
|
||||
|
||||
CValidationState state;
|
||||
|
|
216
src/ncctrie.cpp
216
src/ncctrie.cpp
|
@ -153,6 +153,43 @@ bool CNCCTrie::queueEmpty() const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CNCCTrie::expirationQueueEmpty() const
|
||||
{
|
||||
for (valueQueueType::const_iterator itRow = dirtyExpirationQueueRows.begin(); itRow != dirtyExpirationQueueRows.end(); ++itRow)
|
||||
{
|
||||
if (!itRow->second.empty())
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
if (chType == 'e')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
|
||||
}
|
||||
pcursor->Next();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CNCCTrie::setExpirationTime(int t)
|
||||
{
|
||||
nExpirationTime = t;
|
||||
}
|
||||
|
||||
void CNCCTrie::clear()
|
||||
{
|
||||
clear(&root);
|
||||
|
@ -338,6 +375,17 @@ bool CNCCTrie::getQueueRow(int nHeight, std::vector<CValueQueueEntry>& row)
|
|||
return db.Read(std::make_pair('r', nHeight), row);
|
||||
}
|
||||
|
||||
bool CNCCTrie::getExpirationQueueRow(int nHeight, std::vector<CValueQueueEntry>& row)
|
||||
{
|
||||
valueQueueType::iterator itQueueRow = dirtyExpirationQueueRows.find(nHeight);
|
||||
if (itQueueRow != dirtyExpirationQueueRows.end())
|
||||
{
|
||||
row = itQueueRow->second;
|
||||
return true;
|
||||
}
|
||||
return db.Read(std::make_pair('e', nHeight), row);
|
||||
}
|
||||
|
||||
void CNCCTrie::updateQueueRow(int nHeight, std::vector<CValueQueueEntry>& row)
|
||||
{
|
||||
valueQueueType::iterator itQueueRow = dirtyQueueRows.find(nHeight);
|
||||
|
@ -352,7 +400,21 @@ void CNCCTrie::updateQueueRow(int nHeight, std::vector<CValueQueueEntry>& row)
|
|||
itQueueRow->second.swap(row);
|
||||
}
|
||||
|
||||
bool CNCCTrie::update(nodeCacheType& cache, hashMapType& hashes, const uint256& hashBlockIn, valueQueueType& queueCache, int nNewHeight)
|
||||
void CNCCTrie::updateExpirationRow(int nHeight, std::vector<CValueQueueEntry>& row)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
bool CNCCTrie::update(nodeCacheType& cache, hashMapType& hashes, const uint256& hashBlockIn, valueQueueType& queueCache, valueQueueType& expirationQueueCache, int nNewHeight)
|
||||
{
|
||||
// General strategy: the cache is ordered by length, ensuring child
|
||||
// nodes are always inserted after their parents. Insert each node
|
||||
|
@ -390,6 +452,10 @@ bool CNCCTrie::update(nodeCacheType& cache, hashMapType& hashes, const uint256&
|
|||
{
|
||||
updateQueueRow(itQueueCacheRow->first, itQueueCacheRow->second);
|
||||
}
|
||||
for (valueQueueType::iterator itExpirationRow = expirationQueueCache.begin(); itExpirationRow != expirationQueueCache.end(); ++itExpirationRow)
|
||||
{
|
||||
updateExpirationRow(itExpirationRow->first, itExpirationRow->second);
|
||||
}
|
||||
hashBlock = hashBlockIn;
|
||||
nCurrentHeight = nNewHeight;
|
||||
return true;
|
||||
|
@ -505,6 +571,21 @@ void CNCCTrie::BatchWriteQueueRows(CLevelDBBatch& batch)
|
|||
}
|
||||
}
|
||||
|
||||
void CNCCTrie::BatchWriteExpirationQueueRows(CLevelDBBatch& batch)
|
||||
{
|
||||
for (valueQueueType::iterator itQueue = dirtyExpirationQueueRows.begin(); itQueue != dirtyExpirationQueueRows.end(); ++itQueue)
|
||||
{
|
||||
if (itQueue->second.empty())
|
||||
{
|
||||
batch.Erase(std::make_pair('e', itQueue->first));
|
||||
}
|
||||
else
|
||||
{
|
||||
batch.Write(std::make_pair('e', itQueue->first), itQueue->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CNCCTrie::WriteToDisk()
|
||||
{
|
||||
CLevelDBBatch batch;
|
||||
|
@ -513,6 +594,8 @@ bool CNCCTrie::WriteToDisk()
|
|||
dirtyNodes.clear();
|
||||
BatchWriteQueueRows(batch);
|
||||
dirtyQueueRows.clear();
|
||||
BatchWriteExpirationQueueRows(batch);
|
||||
dirtyExpirationQueueRows.clear();
|
||||
batch.Write('h', hashBlock);
|
||||
batch.Write('t', nCurrentHeight);
|
||||
return db.WriteBatch(batch);
|
||||
|
@ -928,7 +1011,7 @@ bool CNCCTrieCache::addClaim(const std::string name, uint256 txhash, uint32_t nO
|
|||
{
|
||||
LogPrintf("%s: name: %s, txhash: %s, nOut: %d, nAmount: %d, nHeight: %d, nCurrentHeight: %d\n", __func__, name, txhash.GetHex(), nOut, nAmount, nHeight, nCurrentHeight);
|
||||
assert(nHeight == nCurrentHeight);
|
||||
return addClaimToQueue(name, txhash, nOut, nAmount, nHeight, nHeight + DEFAULT_DELAY);
|
||||
return addClaimToQueues(name, txhash, nOut, nAmount, nHeight, nHeight + DEFAULT_DELAY);
|
||||
}
|
||||
|
||||
bool CNCCTrieCache::addClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, uint256 prevTxhash, uint32_t nPrevOut) const
|
||||
|
@ -941,7 +1024,7 @@ bool CNCCTrieCache::addClaim(const std::string name, uint256 txhash, uint32_t nO
|
|||
if (val.txhash == prevTxhash && val.nOut == nPrevOut)
|
||||
{
|
||||
LogPrintf("%s: This is an update to a best claim. Previous claim txhash: %s, nOut: %d\n", __func__, prevTxhash.GetHex(), nPrevOut);
|
||||
return addClaimToQueue(name, txhash, nOut, nAmount, nHeight, nHeight);
|
||||
return addClaimToQueues(name, txhash, nOut, nAmount, nHeight, nHeight);
|
||||
}
|
||||
}
|
||||
return addClaim(name, txhash, nOut, nAmount, nHeight);
|
||||
|
@ -955,21 +1038,23 @@ bool CNCCTrieCache::undoSpendClaim(const std::string name, uint256 txhash, uint3
|
|||
CNodeValue val(txhash, nOut, nAmount, nHeight, nValidAtHeight);
|
||||
CValueQueueEntry entry(name, val);
|
||||
insertClaimIntoTrie(name, CNodeValue(txhash, nOut, nAmount, nHeight, nValidAtHeight));
|
||||
addToExpirationQueue(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
addClaimToQueue(name, txhash, nOut, nAmount, nHeight, nValidAtHeight);
|
||||
addClaimToQueues(name, txhash, nOut, nAmount, nHeight, nValidAtHeight);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CNCCTrieCache::addClaimToQueue(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const
|
||||
bool CNCCTrieCache::addClaimToQueues(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const
|
||||
{
|
||||
LogPrintf("%s: nValidAtHeight: %d\n", __func__, nValidAtHeight);
|
||||
CNodeValue val(txhash, nOut, nAmount, nHeight, nValidAtHeight);
|
||||
CValueQueueEntry entry(name, val);
|
||||
valueQueueType::iterator itQueueRow = getQueueCacheRow(nValidAtHeight, true);
|
||||
itQueueRow->second.push_back(entry);
|
||||
addToExpirationQueue(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1012,49 +1097,122 @@ bool CNCCTrieCache::spendClaim(const std::string name, uint256 txhash, uint32_t
|
|||
bool CNCCTrieCache::removeClaim(const std::string name, uint256 txhash, uint32_t nOut, int nHeight, int& nValidAtHeight) const
|
||||
{
|
||||
LogPrintf("%s: name: %s, txhash: %s, nOut: %s, nHeight: %s, nCurrentHeight: %s\n", __func__, name, txhash.GetHex(), nOut, nHeight, nCurrentHeight);
|
||||
bool removed = false;
|
||||
if (nHeight + DEFAULT_DELAY >= nCurrentHeight)
|
||||
{
|
||||
if (removeClaimFromQueue(name, txhash, nOut, nHeight + DEFAULT_DELAY, nValidAtHeight))
|
||||
return true;
|
||||
if (removeClaimFromQueue(name, txhash, nOut, nHeight, nValidAtHeight))
|
||||
return true;
|
||||
removed = true;
|
||||
else if (removeClaimFromQueue(name, txhash, nOut, nHeight, nValidAtHeight))
|
||||
removed = true;
|
||||
}
|
||||
if (removeClaimFromQueue(name, txhash, nOut, nHeight, nCurrentHeight))
|
||||
return true;
|
||||
return removeClaimFromTrie(name, txhash, nOut, nValidAtHeight);
|
||||
if (removed == false && removeClaimFromQueue(name, txhash, nOut, nHeight, nCurrentHeight))
|
||||
removed = true;
|
||||
if (removed == false && removeClaimFromTrie(name, txhash, nOut, nValidAtHeight))
|
||||
removed = true;
|
||||
if (removed == true)
|
||||
removeFromExpirationQueue(name, txhash, nOut, nHeight);
|
||||
return removed;
|
||||
}
|
||||
|
||||
bool CNCCTrieCache::incrementBlock(CNCCTrieQueueUndo& undo) const
|
||||
void CNCCTrieCache::addToExpirationQueue(CValueQueueEntry& entry) const
|
||||
{
|
||||
int expirationHeight = entry.val.nHeight + base->nExpirationTime;
|
||||
valueQueueType::iterator itQueueRow = getExpirationQueueCacheRow(expirationHeight, true);
|
||||
itQueueRow->second.push_back(entry);
|
||||
}
|
||||
|
||||
void CNCCTrieCache::removeFromExpirationQueue(const std::string name, uint256 txhash, uint32_t nOut, int nHeight) const
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
valueQueueType::iterator CNCCTrieCache::getExpirationQueueCacheRow(int nHeight, bool createIfNotExists) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool CNCCTrieCache::incrementBlock(CNCCTrieQueueUndo& insertUndo, CNCCTrieQueueUndo& expireUndo) const
|
||||
{
|
||||
LogPrintf("%s: nCurrentHeight (before increment): %d\n", __func__, nCurrentHeight);
|
||||
valueQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, false);
|
||||
if (itQueueRow != valueQueueCache.end())
|
||||
{
|
||||
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();
|
||||
}
|
||||
valueQueueType::iterator itExpirationRow = getExpirationQueueCacheRow(nCurrentHeight, false);
|
||||
if (itExpirationRow != expirationQueueCache.end())
|
||||
{
|
||||
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();
|
||||
}
|
||||
nCurrentHeight++;
|
||||
if (itQueueRow == valueQueueCache.end())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
for (std::vector<CValueQueueEntry>::iterator itEntry = itQueueRow->second.begin(); itEntry != itQueueRow->second.end(); ++itEntry)
|
||||
{
|
||||
insertClaimIntoTrie(itEntry->name, itEntry->val);
|
||||
undo.push_back(*itEntry);
|
||||
}
|
||||
itQueueRow->second.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CNCCTrieCache::decrementBlock(CNCCTrieQueueUndo& undo) const
|
||||
bool CNCCTrieCache::decrementBlock(CNCCTrieQueueUndo& insertUndo, CNCCTrieQueueUndo& expireUndo) const
|
||||
{
|
||||
LogPrintf("%s: nCurrentHeight (before decrement): %d\n", __func__, nCurrentHeight);
|
||||
nCurrentHeight--;
|
||||
if (undo.begin() != undo.end())
|
||||
if (insertUndo.begin() != insertUndo.end())
|
||||
{
|
||||
valueQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, true);
|
||||
for (CNCCTrieQueueUndo::iterator itUndo = undo.begin(); itUndo != undo.end(); ++itUndo)
|
||||
for (CNCCTrieQueueUndo::iterator itInsertUndo = insertUndo.begin(); itInsertUndo != insertUndo.end(); ++itInsertUndo)
|
||||
{
|
||||
int nValidHeightInTrie;
|
||||
assert(removeClaimFromTrie(itUndo->name, itUndo->val.txhash, itUndo->val.nOut, nValidHeightInTrie));
|
||||
assert(nValidHeightInTrie == itUndo->val.nValidAtHeight);
|
||||
itQueueRow->second.push_back(*itUndo);
|
||||
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);
|
||||
for (CNCCTrieQueueUndo::iterator itExpireUndo = expireUndo.begin(); itExpireUndo != expireUndo.end(); ++itExpireUndo)
|
||||
{
|
||||
insertClaimIntoTrie(itExpireUndo->name, itExpireUndo->val);
|
||||
itExpireRow->second.push_back(*itExpireUndo);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -1090,7 +1248,7 @@ bool CNCCTrieCache::flush()
|
|||
{
|
||||
if (dirty())
|
||||
getMerkleHash();
|
||||
bool success = base->update(cache, cacheHashes, getBestBlock(), valueQueueCache, nCurrentHeight);
|
||||
bool success = base->update(cache, cacheHashes, getBestBlock(), valueQueueCache, expirationQueueCache, nCurrentHeight);
|
||||
if (success)
|
||||
{
|
||||
success = clear();
|
||||
|
|
|
@ -147,7 +147,7 @@ class CNCCTrieCache;
|
|||
class CNCCTrie
|
||||
{
|
||||
public:
|
||||
CNCCTrie(bool fMemory = false, bool fWipe = false) : db(GetDataDir() / "ncctrie", 100, fMemory, fWipe), nCurrentHeight(0), root(uint256S("0000000000000000000000000000000000000000000000000000000000000001")) {}
|
||||
CNCCTrie(bool fMemory = false, bool fWipe = false) : db(GetDataDir() / "ncctrie", 100, fMemory, fWipe), nCurrentHeight(0), nExpirationTime(262974), root(uint256S("0000000000000000000000000000000000000000000000000000000000000001")) {}
|
||||
uint256 getMerkleHash();
|
||||
CLevelDBWrapper db;
|
||||
bool empty() const;
|
||||
|
@ -159,15 +159,19 @@ public:
|
|||
bool getInfoForName(const std::string& name, CNodeValue& val) const;
|
||||
int nCurrentHeight;
|
||||
bool queueEmpty() const;
|
||||
bool expirationQueueEmpty() const;
|
||||
void setExpirationTime(int t);
|
||||
bool getQueueRow(int nHeight, std::vector<CValueQueueEntry>& row);
|
||||
bool getExpirationQueueRow(int nHeight, std::vector<CValueQueueEntry>& row);
|
||||
bool haveClaim(const std::string& name, const uint256& txhash, uint32_t nOut) const;
|
||||
unsigned int getTotalNamesInTrie() const;
|
||||
unsigned int getTotalClaimsInTrie() const;
|
||||
CAmount getTotalValueOfClaimsInTrie(bool fControllingOnly) const;
|
||||
friend class CNCCTrieCache;
|
||||
int nExpirationTime;
|
||||
private:
|
||||
void clear(CNCCTrieNode* current);
|
||||
bool update(nodeCacheType& cache, hashMapType& hashes, const uint256& hashBlock, valueQueueType& queueCache, int nNewHeight);
|
||||
bool update(nodeCacheType& cache, hashMapType& hashes, const uint256& hashBlock, valueQueueType& queueCache, valueQueueType& expirationQueueCache, int nNewHeight);
|
||||
bool updateName(const std::string& name, CNCCTrieNode* updatedNode);
|
||||
bool updateHash(const std::string& name, uint256& hash);
|
||||
bool recursiveNullify(CNCCTrieNode* node, std::string& name);
|
||||
|
@ -180,14 +184,16 @@ private:
|
|||
CNCCTrieNode root;
|
||||
uint256 hashBlock;
|
||||
valueQueueType dirtyQueueRows;
|
||||
valueQueueType dirtyExpirationQueueRows;
|
||||
|
||||
nodeCacheType dirtyNodes;
|
||||
void markNodeDirty(const std::string& name, CNCCTrieNode* node);
|
||||
void deleteQueueRow(int nHeight);
|
||||
void updateQueueRow(int nHeight, std::vector<CValueQueueEntry>& row);
|
||||
void updateExpirationRow(int nHeight, std::vector<CValueQueueEntry>& row);
|
||||
void BatchWriteNode(CLevelDBBatch& batch, const std::string& name, const CNCCTrieNode* pNode) const;
|
||||
void BatchEraseNode(CLevelDBBatch& batch, const std::string& nome) const;
|
||||
void BatchWriteQueueRows(CLevelDBBatch& batch);
|
||||
void BatchWriteExpirationQueueRows(CLevelDBBatch& batch);
|
||||
};
|
||||
|
||||
class CNCCTrieCache
|
||||
|
@ -205,8 +211,8 @@ public:
|
|||
bool undoSpendClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const;
|
||||
uint256 getBestBlock();
|
||||
void setBestBlock(const uint256& hashBlock);
|
||||
bool incrementBlock(CNCCTrieQueueUndo& undo) const;
|
||||
bool decrementBlock(CNCCTrieQueueUndo& undo) const;
|
||||
bool incrementBlock(CNCCTrieQueueUndo& insertUndo, CNCCTrieQueueUndo& expireUndo) const;
|
||||
bool decrementBlock(CNCCTrieQueueUndo& insertUndo, CNCCTrieQueueUndo& expireUndo) const;
|
||||
~CNCCTrieCache() { clear(); }
|
||||
bool insertClaimIntoTrie(const std::string name, CNodeValue val) const;
|
||||
bool removeClaimFromTrie(const std::string name, uint256 txhash, uint32_t nOut, int& nValidAtHeight) const;
|
||||
|
@ -217,6 +223,7 @@ private:
|
|||
mutable std::set<std::string> dirtyHashes;
|
||||
mutable hashMapType cacheHashes;
|
||||
mutable valueQueueType valueQueueCache;
|
||||
mutable valueQueueType expirationQueueCache;
|
||||
mutable int nCurrentHeight; // Height of the block that is being worked on, which is
|
||||
// one greater than the height of the chain's tip
|
||||
uint256 computeHash() const;
|
||||
|
@ -224,9 +231,12 @@ private:
|
|||
bool recursivePruneName(CNCCTrieNode* tnCurrent, unsigned int nPos, std::string sName, bool* pfNullified = NULL) const;
|
||||
bool clear() const;
|
||||
bool removeClaim(const std::string name, uint256 txhash, uint32_t nOut, int nHeight, int& nValidAtHeight) const;
|
||||
bool addClaimToQueue(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const;
|
||||
bool addClaimToQueues(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const;
|
||||
bool removeClaimFromQueue(const std::string name, uint256 txhash, uint32_t nOut, int nHeightToCheck, int& nValidAtHeight) const;
|
||||
void addToExpirationQueue(CValueQueueEntry& entry) const;
|
||||
void removeFromExpirationQueue(const std::string name, uint256 txhash, uint32_t nOut, int nHeight) const;
|
||||
valueQueueType::iterator getQueueCacheRow(int nHeight, bool createIfNotExists) const;
|
||||
valueQueueType::iterator getExpirationQueueCacheRow(int nHeight, bool createIfNotExists) const;
|
||||
uint256 hashBlock;
|
||||
};
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
const unsigned int nonces[] = {
|
||||
const unsigned int insert_nonces[] = {
|
||||
62302, 78404, 42509, 88397, 232147, 34120, 48944, 8449, 3855, 99418,
|
||||
35007, 36992, 18865, 48021, 117592, 61911, 26614, 26267, 171911, 49917,
|
||||
68274, 19360, 48650, 22711, 102612, 73362, 7375, 39379, 413, 123283,
|
||||
|
@ -83,6 +83,64 @@ const unsigned int nonces[] = {
|
|||
102894, 41478, 509, 169951, 5571, 28284, 8138, 53248, 47878, 113791,
|
||||
192277, 73645, 28672, 93670, 30741, 129667};
|
||||
|
||||
const unsigned int expire_nonces[] = {
|
||||
1772, 19895, 52494, 75900, 15954, 92687, 381518, 24750, 131218, 140637,
|
||||
25151, 4751, 117588, 31281, 741, 13006, 56207, 23174, 32024, 23597,
|
||||
17093, 22998, 68975, 84976, 47024, 48818, 29830, 28891, 66091, 6304,
|
||||
117, 253782, 126584, 55982, 43172, 5862, 36712, 289031, 42833, 61902,
|
||||
81993, 26790, 80145, 111102, 27904, 16188, 55120, 7171, 67694, 214899,
|
||||
16360, 133920, 31442, 103537, 266284, 4407, 102008, 1149, 156950, 76029,
|
||||
33751, 20831, 24714, 202595, 9393, 227174, 3357, 70, 45445, 104755,
|
||||
6024, 13512, 163718, 43755, 17582, 17069, 17355, 38898, 101900, 41342,
|
||||
20701, 9827, 11663, 146362, 189082, 279537, 79142, 423101, 11154, 103046,
|
||||
44740, 90350, 41450, 4627, 4685, 14510, 13639, 13705, 2369, 326596,
|
||||
74814, 15068, 7287, 26685, 41834, 5872, 94033, 77510, 21271, 51233,
|
||||
687, 84716, 18945, 139111, 11508, 15009, 103492, 25317, 100121, 29105,
|
||||
26520, 531, 6883, 181308, 161707, 72079, 50032, 65286, 96365, 18280,
|
||||
21015, 56591, 90913, 3280, 74270, 87610, 85124, 58599, 161342, 36017,
|
||||
135104, 19625, 114763, 163177, 31400, 99871, 15939, 6822, 51007, 33240,
|
||||
15449, 28232, 242057, 45744, 253284, 218826, 25843, 118582, 228181, 7592,
|
||||
3398, 23637, 46762, 22853, 7669, 358599, 99238, 32782, 46407, 36545,
|
||||
28976, 34995, 23564, 60624, 45957, 162829, 7055, 184611, 69270, 22560,
|
||||
17314, 24374, 67156, 44705, 9482, 17611, 92669, 22471, 47688, 110960,
|
||||
18595, 46376, 23989, 47847, 41231, 2937, 34056, 61839, 9393, 122723,
|
||||
119967, 41795, 13244, 22081, 41407, 65568, 120355, 228591, 3763, 23561,
|
||||
78832, 20110, 3849, 162319, 9699, 153960, 60013, 22063, 22895, 84997,
|
||||
20008, 6201, 18985, 7065, 63655, 35849, 19788, 69977, 45664, 15647,
|
||||
111735, 1372, 2487, 38856, 39081, 74496, 71062, 20232, 33091, 26777,
|
||||
155180, 149434, 35380, 102844, 46709, 3373, 137389, 33273, 13194, 5106,
|
||||
69109, 21599, 24896, 16688, 101584, 567, 61253, 125648, 30825, 38976,
|
||||
88494, 82214, 84079, 52761, 16392, 206857, 19856, 48376, 11820, 21296,
|
||||
12707, 94783, 31272, 113581, 40682, 143247, 1206, 21720, 40627, 131077,
|
||||
78794, 9026, 38830, 39757, 94577, 20134, 15904, 185817, 35595, 21609,
|
||||
15868, 187480, 62515, 36383, 12797, 101029, 17979, 48892, 59215, 197023,
|
||||
217536, 295885, 5639, 24470, 440, 96896, 3113, 74270, 8773, 89871,
|
||||
41807, 33896, 41053, 87038, 64666, 2642, 39880, 113389, 51922, 64364,
|
||||
46026, 34424, 6856, 51050, 48871, 43033, 95444, 68098, 10463, 27119,
|
||||
101386, 28555, 94429, 38046, 13110, 39449, 976, 12015, 32827, 20156,
|
||||
79086, 90632, 24716, 11632, 27225, 11563, 45437, 41804, 240056, 26298,
|
||||
7089, 119823, 87043, 46315, 108722, 24002, 109328, 32013, 47232, 243845,
|
||||
9604, 158119, 189402, 124127, 89656, 39496, 63807, 83836, 80843, 2261,
|
||||
103229, 24028, 299032, 43513, 8506, 362389, 14113, 47973, 145654, 23170,
|
||||
23272, 35090, 17628, 28197, 96581, 84151, 694, 182728, 86514, 129029,
|
||||
4509, 48647, 63280, 86829, 138046, 8075, 59670, 53232, 37353, 51966,
|
||||
62110, 66890, 75512, 42296, 240099, 64624, 98903, 29189, 2593, 17376,
|
||||
11417, 2982, 3273, 40001, 468410, 29603, 111819, 36878, 6710, 14350,
|
||||
87778, 69800, 18820, 75880, 26049, 36685, 8500, 189289, 186944, 100520,
|
||||
167630, 7170, 115904, 79212, 4792, 82507, 13634, 71118, 27066, 66914,
|
||||
44963, 58999, 153183, 184462, 65596, 102627, 333388, 164930, 6664, 120605,
|
||||
141, 122317, 162948, 93160, 216861, 68595, 67370, 15526, 4320, 45961,
|
||||
86806, 61077, 61730, 117548, 127472, 1191, 15735, 133987, 16288, 4652,
|
||||
83674, 21872, 21351, 35691, 11584, 85669, 196, 75276, 45275, 55828,
|
||||
46586, 153482, 6183, 386, 28729, 111942, 2847, 10584, 207349, 57260,
|
||||
12075, 27552, 129129, 282325, 11954, 28300, 175155, 31256, 12953, 16345,
|
||||
34101, 57962, 16950, 9103, 94414, 1918, 69031, 151629, 41281, 85752,
|
||||
66681, 31646, 12396, 167, 72005, 3936, 27566, 5663, 24098, 73350,
|
||||
19076, 179631, 36500, 152550, 56501, 81202, 77561, 134713, 81130, 22321,
|
||||
112081, 32992, 144573, 21369, 2471, 18371, 63050, 44211, 6147, 206052,
|
||||
34252, 534, 20176, 58035, 24268, 19608, 37770, 57588, 120961, 58415,
|
||||
4780, 4614, 229320, 42279, 41295, 23501, 78183};
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(ncctrie_tests, TestingSetup)
|
||||
|
||||
CMutableTransaction BuildTransaction(const uint256& prevhash)
|
||||
|
@ -129,7 +187,7 @@ void AddToMempool(CMutableTransaction& tx)
|
|||
mempool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(tx, 0, GetTime(), 111.0, chainActive.Height()));
|
||||
}
|
||||
|
||||
bool CreateBlock(CBlockTemplate* pblocktemplate, bool f = false)
|
||||
bool CreateBlock(CBlockTemplate* pblocktemplate, int nonce)
|
||||
{
|
||||
static int unique_block_counter = 0;
|
||||
CBlock* pblock = &pblocktemplate->block;
|
||||
|
@ -140,18 +198,24 @@ bool CreateBlock(CBlockTemplate* pblocktemplate, bool f = false)
|
|||
txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height(), Params().GetConsensus());
|
||||
pblock->vtx[0] = CTransaction(txCoinbase);
|
||||
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
|
||||
pblock->nNonce = nonces[unique_block_counter - 1];
|
||||
/*for (int i = 0; ; ++i)
|
||||
//if (nonce != -1)
|
||||
//{
|
||||
pblock->nNonce = nonce;
|
||||
//}
|
||||
/*else
|
||||
{
|
||||
pblock->nNonce = i;
|
||||
if (CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus()))
|
||||
for (int i = 0; ; ++i)
|
||||
{
|
||||
std::cout << pblock->nNonce << ",";
|
||||
if (unique_block_counter % 10 == 0)
|
||||
std::cout << std::endl;
|
||||
else
|
||||
std::cout << " ";
|
||||
break;
|
||||
pblock->nNonce = i;
|
||||
if (CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus()))
|
||||
{
|
||||
std::cout << pblock->nNonce << ",";
|
||||
if (unique_block_counter % 10 == 0)
|
||||
std::cout << std::endl;
|
||||
else
|
||||
std::cout << " ";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
CValidationState state;
|
||||
|
@ -290,6 +354,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_merkle_hash)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
||||
{
|
||||
int block_counter = 0;
|
||||
BOOST_CHECK(pnccTrie->nCurrentHeight == chainActive.Height() + 1);
|
||||
|
||||
CBlockTemplate *pblocktemplate;
|
||||
|
@ -315,7 +380,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
|
||||
for (unsigned int i = 0; i < 103; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
if (coinbases.size() < 3)
|
||||
coinbases.push_back(CTransaction(pblocktemplate->block.vtx[0]));
|
||||
}
|
||||
|
@ -352,7 +417,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 3);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -363,7 +428,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 1; i < 100; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
}
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -372,7 +437,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
delete pblocktemplate;
|
||||
|
||||
// Verify tx1 and tx2 are in the trie
|
||||
|
@ -389,7 +454,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 4);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -429,7 +494,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, true));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -451,7 +516,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -462,7 +527,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 1; i < 100; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
}
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -471,7 +536,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
|
@ -497,7 +562,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 3);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -519,7 +584,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
|
@ -529,7 +594,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 1; i < 50; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
}
|
||||
delete pblocktemplate;
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
|
@ -542,7 +607,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
|
@ -552,7 +617,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 1; i < 51; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
}
|
||||
delete pblocktemplate;
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
|
@ -571,7 +636,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 0; i < 50; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
}
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -580,7 +645,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
delete pblocktemplate;
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
|
@ -596,7 +661,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -628,7 +693,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, true));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -641,7 +706,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 1; i < 50; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
}
|
||||
delete pblocktemplate;
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
|
@ -654,7 +719,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -668,7 +733,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -689,7 +754,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 1; i < 100; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, true));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
}
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -698,7 +763,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
|
@ -720,7 +785,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 0; i < 50; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
}
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -729,7 +794,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
|
@ -744,7 +809,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
|
@ -759,7 +824,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
|
@ -783,6 +848,279 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
|||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ncctrie_claim_expiration)
|
||||
{
|
||||
int block_counter = 0;
|
||||
BOOST_CHECK(pnccTrie->nCurrentHeight == chainActive.Height() + 1);
|
||||
|
||||
CBlockTemplate *pblocktemplate;
|
||||
LOCK(cs_main);
|
||||
|
||||
CScript scriptPubKey = CScript() << OP_TRUE;
|
||||
|
||||
std::string sName("atest");
|
||||
std::string sValue("testa");
|
||||
|
||||
std::vector<unsigned char> vchName(sName.begin(), sName.end());
|
||||
std::vector<unsigned char> vchValue(sValue.begin(), sValue.end());
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
std::vector<CTransaction> coinbases;
|
||||
for (unsigned int i = 0; i < 102; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
if (coinbases.size() < 2)
|
||||
coinbases.push_back(CTransaction(pblocktemplate->block.vtx[0]));
|
||||
}
|
||||
|
||||
delete pblocktemplate;
|
||||
|
||||
CMutableTransaction tx1 = BuildTransaction(coinbases[0]);
|
||||
tx1.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP << OP_TRUE;
|
||||
CMutableTransaction tx2 = BuildTransaction(tx1);
|
||||
tx2.vout[0].scriptPubKey = CScript() << OP_TRUE;
|
||||
|
||||
std::vector<uint256> blocks_to_invalidate;
|
||||
// set expiration time to 100 blocks after the block becomes valid.
|
||||
|
||||
pnccTrie->setExpirationTime(200);
|
||||
|
||||
// create a claim. verify no expiration event has been scheduled.
|
||||
|
||||
AddToMempool(tx1);
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// advance until the claim is valid. verify the expiration event is scheduled.
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 1; i < 100; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
}
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// advance until the expiration event occurs. verify the expiration event occurs on time.
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 1; i < 100; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
}
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// roll forward a bit and then roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again.
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 0; i < 100; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
}
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
|
||||
|
||||
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||
blocks_to_invalidate.pop_back();
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// advance until the expiration event occurs. verify the expiration event occurs on time.
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again.
|
||||
|
||||
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||
blocks_to_invalidate.pop_back();
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// roll back to before the claim is valid. verify the claim is removed but the expiration event still exists.
|
||||
|
||||
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||
blocks_to_invalidate.pop_back();
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// advance until the claim is valid again. verify the expiration event is scheduled.
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// advance until the expiration event occurs. verify the expiration event occurs on time.
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 1; i < 100; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
if (i == 50)
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
}
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// roll back to before the expiration event. verify the expiration event is scheduled.
|
||||
|
||||
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||
blocks_to_invalidate.pop_back();
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// roll back some.
|
||||
|
||||
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||
blocks_to_invalidate.pop_back();
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// spend the claim. verify the expiration event is removed.
|
||||
|
||||
AddToMempool(tx2);
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// roll back the spend. verify the expiration event is returned.
|
||||
|
||||
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||
blocks_to_invalidate.pop_back();
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// advance until the expiration event occurs. verify the event occurs on time.
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 50; i < 100; ++i)
|
||||
{
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
}
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
|
||||
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again.
|
||||
|
||||
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||
blocks_to_invalidate.pop_back();
|
||||
BOOST_CHECK(!pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// roll back to before the claim is valid. verify the claim is removed but the expiration event is not.
|
||||
|
||||
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||
blocks_to_invalidate.pop_back();
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
|
||||
|
||||
// roll all the way back
|
||||
|
||||
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||
blocks_to_invalidate.pop_back();
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
|
||||
BOOST_CHECK(blocks_to_invalidate.empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ncctrienode_serialize_unserialize)
|
||||
{
|
||||
CDataStream ss(SER_DISK, 0);
|
||||
|
|
|
@ -80,14 +80,16 @@ class CBlockUndo
|
|||
{
|
||||
public:
|
||||
std::vector<CTxUndo> vtxundo; // for all but the coinbase
|
||||
CNCCTrieQueueUndo queueUndo; // any claims that went from the queue to the trie
|
||||
CNCCTrieQueueUndo insertUndo; // any claims that went from the queue to the trie
|
||||
CNCCTrieQueueUndo expireUndo; // any claims that expired
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(vtxundo);
|
||||
READWRITE(queueUndo);
|
||||
READWRITE(insertUndo);
|
||||
READWRITE(expireUndo);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -665,7 +665,19 @@ void ListNameClaims(const CWalletTx& wtx, const string& strAccount, int nMinDept
|
|||
{
|
||||
CBlockIndex* pindex = it->second;
|
||||
if (pindex)
|
||||
{
|
||||
entry.push_back(Pair("height", pindex->nHeight));
|
||||
entry.push_back(Pair("expiration height", pindex->nHeight + pnccTrie->nExpirationTime));
|
||||
if (pindex->nHeight + pnccTrie->nExpirationTime > chainActive.Height())
|
||||
{
|
||||
entry.push_back(Pair("expired", false));
|
||||
entry.push_back(Pair("blocks to expiration", pindex->nHeight + pnccTrie->nExpirationTime - chainActive.Height()));
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.push_back(Pair("expired", true));
|
||||
}
|
||||
}
|
||||
}
|
||||
entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
|
||||
entry.push_back(Pair("is spent", pwalletMain->IsSpent(wtx.GetHash(), s.vout)));
|
||||
|
|
Loading…
Reference in a new issue