Extend expiration of pre fork claims and supports. Adjust and add unit test for the extended expiration hardfork.

This commit is contained in:
kay kurokawa 2018-05-09 00:33:23 -04:00 committed by Umpei Kay Kurokawa
parent dc34766423
commit 4e147cb380
4 changed files with 283 additions and 51 deletions

View file

@ -1695,29 +1695,20 @@ bool CClaimTrieCache::removeClaim(const std::string& name, const COutPoint& outP
if (removed == true)
{
nValidAtHeight = claim.nValidAtHeight;
removeFromExpirationQueue(name, outPoint, nHeight);
int expirationHeight = nHeight + base->nExpirationTime;
removeFromExpirationQueue(name, outPoint, expirationHeight);
}
return removed;
}
void CClaimTrieCache::addToExpirationQueue(int nExpirationHeight, nameOutPointType& entry) const
{
// NOTE: To disable expiration completely after fork, set this define to enable check
// #define CLAIM_EXPIRATION_DISABLED_AFTER_FORK
#ifdef CLAIM_EXPIRATION_DISABLED_AFTER_FORK
const Consensus::Params& consensusParams = Params().GetConsensus();
if ((nExpirationHeight < consensusParams.nExtendedClaimExpirationForkHeight) ||
(base->nCurrentHeight < consensusParams.nExtendedClaimExpirationForkHeight))
#endif
{
expirationQueueType::iterator itQueueRow = getExpirationQueueCacheRow(nExpirationHeight, true);
itQueueRow->second.push_back(entry);
}
expirationQueueType::iterator itQueueRow = getExpirationQueueCacheRow(nExpirationHeight, true);
itQueueRow->second.push_back(entry);
}
void CClaimTrieCache::removeFromExpirationQueue(const std::string& name, const COutPoint& outPoint, int nHeight) const
void CClaimTrieCache::removeFromExpirationQueue(const std::string& name, const COutPoint& outPoint, int expirationHeight) const
{
int expirationHeight = nHeight + base->nExpirationTime;
expirationQueueType::iterator itQueueRow = getExpirationQueueCacheRow(expirationHeight, false);
expirationQueueRowType::iterator itQueue;
if (itQueueRow != expirationQueueCache.end())
@ -2036,7 +2027,8 @@ bool CClaimTrieCache::removeSupport(const std::string& name, const COutPoint& ou
removed = true;
if (removed)
{
removeSupportFromExpirationQueue(name, outPoint, nHeight);
int expirationHeight = nHeight + base->nExpirationTime;
removeSupportFromExpirationQueue(name, outPoint, expirationHeight);
nValidAtHeight = support.nValidAtHeight;
}
return removed;
@ -2048,9 +2040,8 @@ void CClaimTrieCache::addSupportToExpirationQueue(int nExpirationHeight, nameOut
itQueueRow->second.push_back(entry);
}
void CClaimTrieCache::removeSupportFromExpirationQueue(const std::string& name, const COutPoint& outPoint, int nHeight) const
void CClaimTrieCache::removeSupportFromExpirationQueue(const std::string& name, const COutPoint& outPoint, int expirationHeight) const
{
int expirationHeight = nHeight + base->nExpirationTime;
expirationQueueType::iterator itQueueRow = getSupportExpirationQueueCacheRow(expirationHeight, false);
expirationQueueRowType::iterator itQueue;
if (itQueueRow != supportExpirationQueueCache.end())
@ -2104,6 +2095,7 @@ bool CClaimTrieCache::spendSupport(const std::string& name, const COutPoint& out
bool CClaimTrieCache::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo, std::vector<std::pair<std::string, int> >& takeoverHeightUndo) const
{
LogPrintf("%s: nCurrentHeight (before increment): %d\n", __func__, nCurrentHeight);
claimQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, false);
if (itQueueRow != claimQueueCache.end())
{
@ -2421,6 +2413,7 @@ bool CClaimTrieCache::decrementBlock(insertUndoType& insertUndo, claimQueueRowTy
{
cacheTakeoverHeights[itTakeoverHeightUndo->first] = itTakeoverHeightUndo->second;
}
return true;
}
@ -2609,3 +2602,106 @@ CClaimTrieProof CClaimTrieCache::getProofForName(const std::string& name) const
return CClaimTrieProof(nodes, fNameHasValue, outPoint,
nHeightOfLastTakeover);
}
void CClaimTrieCache::removeAndAddToExpirationQueue(expirationQueueRowType &row, int height, bool increment) const
{
for (expirationQueueRowType::iterator e = row.begin(); e != row.end(); ++e)
{
// remove and insert with new expiration time
removeFromExpirationQueue(e->name, e->outPoint, height);
int extend_expiration = Params().GetConsensus().nExtendedClaimExpirationTime - Params().GetConsensus().nOriginalClaimExpirationTime;
int new_expiration_height = increment ? height + extend_expiration : height - extend_expiration;
nameOutPointType entry(e->name, e->outPoint);
addToExpirationQueue(new_expiration_height, entry);
}
}
void CClaimTrieCache::removeAndAddSupportToExpirationQueue(expirationQueueRowType &row, int height, bool increment) const
{
for (expirationQueueRowType::iterator e = row.begin(); e != row.end(); ++e)
{
// remove and insert with new expiration time
removeSupportFromExpirationQueue(e->name, e->outPoint, height);
int extend_expiration = Params().GetConsensus().nExtendedClaimExpirationTime - Params().GetConsensus().nOriginalClaimExpirationTime;
int new_expiration_height = increment ? height + extend_expiration : height - extend_expiration;
nameOutPointType entry(e->name, e->outPoint);
addSupportToExpirationQueue(new_expiration_height, entry);
}
}
bool CClaimTrieCache::forkForExpirationChange(bool increment) const
{
/*
If increment is True, we have forked to extend the expiration time, thus items in the expiration queue
will have their expiration extended by "new expiration time - original expiration time"
If increment is False, we are decremented a block to reverse the fork. Thus items in the expiration queue
will have their expiration extension removed.
*/
// look through dirty expiration queues
std::set<int> dirtyHeights;
for (expirationQueueType::const_iterator i = base->dirtyExpirationQueueRows.begin(); i != base->dirtyExpirationQueueRows.end(); ++i)
{
int height = i->first;
dirtyHeights.insert(height);
expirationQueueRowType row = i->second;
removeAndAddToExpirationQueue(row, height, increment);
}
std::set<int> dirtySupportHeights;
for (expirationQueueType::const_iterator i = base->dirtySupportExpirationQueueRows.begin(); i != base->dirtySupportExpirationQueueRows.end(); ++i)
{
int height = i->first;
dirtySupportHeights.insert(height);
expirationQueueRowType row = i->second;
removeAndAddSupportToExpirationQueue(row, height, increment);
}
//look through db for expiration queues, if we haven't already found it in dirty expiration queue
boost::scoped_ptr<CDBIterator> pcursor(const_cast<CDBWrapper*>(&base->db)->NewIterator());
pcursor->SeekToFirst();
while (pcursor->Valid())
{
std::pair<char, int> key;
if (pcursor->GetKey(key))
{
int height = key.second;
// if we've looked throught this in dirtyExprirationQueueRows, don't use it
// because its stale
if ((key.first == EXP_QUEUE_ROW) & (dirtyHeights.count(height) == 0))
{
expirationQueueRowType row;
if (pcursor->GetValue(row))
{
removeAndAddToExpirationQueue(row, height, increment);
}
else
{
return error("%s(): error reading expiration queue rows from disk", __func__);
}
}
else if ((key.first == SUPPORT_EXP_QUEUE_ROW) & (dirtySupportHeights.count(height) == 0))
{
expirationQueueRowType row;
if (pcursor->GetValue(row))
{
removeAndAddSupportToExpirationQueue(row, height, increment);
}
else
{
return error("%s(): error reading support expiration queue rows from disk", __func__);
}
}
}
pcursor->Next();
}
return true;
}

View file

@ -517,6 +517,13 @@ public:
CClaimTrieProof getProofForName(const std::string& name) const;
bool finalizeDecrement() const;
void removeAndAddSupportToExpirationQueue(expirationQueueRowType &row, int height, bool increment) const;
void removeAndAddToExpirationQueue(expirationQueueRowType &row, int height, bool increment) const;
bool forkForExpirationChange(bool increment) const;
protected:
CClaimTrie* base;

View file

@ -2236,6 +2236,7 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
{
LogPrintf("Decremented past the extended claim expiration hard fork height");
pclaimTrie->setExpirationTime(Params().GetConsensus().GetExpirationTime(pindex->nHeight-1));
trieCache.forkForExpirationChange(false);
}
@ -2504,6 +2505,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
{
LogPrintf("Incremented past the extended claim expiration hard fork height");
pclaimTrie->setExpirationTime(chainparams.GetConsensus().GetExpirationTime(pindex->nHeight));
trieCache.forkForExpirationChange(true);
}

View file

@ -23,7 +23,6 @@ using namespace std;
BOOST_FIXTURE_TEST_SUITE(claimtriebranching_tests, RegTestingSetup)
//is a claim in queue
boost::test_tools::predicate_result
is_claim_in_queue(std::string name, const CTransaction &tx)
@ -164,7 +163,16 @@ struct ClaimTrieChainFixture{
unsigned int num_txs;
unsigned int num_txs_for_next_block;
ClaimTrieChainFixture()
// these will take on regtest parameters
const int expirationForkHeight;
const int originalExpiration;
const int extendedExpiration;
ClaimTrieChainFixture():
expirationForkHeight(Params(CBaseChainParams::REGTEST).GetConsensus().nExtendedClaimExpirationForkHeight),
originalExpiration(Params(CBaseChainParams::REGTEST).GetConsensus().nOriginalClaimExpirationTime),
extendedExpiration(Params(CBaseChainParams::REGTEST).GetConsensus().nExtendedClaimExpirationTime)
{
fRequireStandard = false;
BOOST_CHECK(pclaimTrie->nCurrentHeight == chainActive.Height() + 1);
@ -300,6 +308,17 @@ struct ClaimTrieChainFixture{
num_txs_for_next_block = 0;
}
void WriteClearReadClaimTrie()
{
// this will simulate restart of lbrycrdd by writing the claimtrie to disk,
// clearing the-in memory claimtrie, and then reading the saved claimtrie
// from disk
pclaimTrie->WriteToDisk();
pclaimTrie->clear();
pclaimTrie->ReadFromDisk(true);
}
};
@ -846,76 +865,68 @@ BOOST_AUTO_TEST_CASE(claimtriebranching_get_claim_by_id)
}
/*
expiration
claim expiration for hard fork
check claims do not expire post ExpirationForkHeight
check supports work post ExpirationForkHeight
*/
BOOST_AUTO_TEST_CASE(claimtriebranching_no_expire)
BOOST_AUTO_TEST_CASE(claimtriebranching_hardfork_claim)
{
ClaimTrieChainFixture fixture;
// To activate the expiration hard fork, the expiration time must
// be set to 10 years of blocks (not used as 10 years, but rather
// a sentinel value for hard fork activation) and we must advance
// past nExtendedClaimExpirationForkHeight. This is purposely set
// low enough for testing in the Regtest chain parameters.
const int expirationForkHeight =
Params(CBaseChainParams::REGTEST).GetConsensus().nExtendedClaimExpirationForkHeight;
const int originalExpiration =
Params(CBaseChainParams::REGTEST).GetConsensus().nOriginalClaimExpirationTime;
const int extendedExpiration =
Params(CBaseChainParams::REGTEST).GetConsensus().nExtendedClaimExpirationTime;
BOOST_CHECK_EQUAL(pclaimTrie->nExpirationTime, originalExpiration);
BOOST_CHECK_EQUAL(pclaimTrie->nExpirationTime, fixture.originalExpiration);
// First create a claim and make sure it expires pre-fork
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",3);
fixture.IncrementBlocks(originalExpiration+1);
fixture.IncrementBlocks(fixture.originalExpiration+1);
BOOST_CHECK(!is_best_claim("test",tx1));
fixture.DecrementBlocks(originalExpiration);
fixture.DecrementBlocks(fixture.originalExpiration);
BOOST_CHECK(is_best_claim("test",tx1));
fixture.IncrementBlocks(originalExpiration);
fixture.IncrementBlocks(fixture.originalExpiration);
BOOST_CHECK(!is_best_claim("test",tx1));
// Create a claim 1 block before the fork height that will expire after the fork height
fixture.IncrementBlocks(expirationForkHeight - chainActive.Height() -2);
fixture.IncrementBlocks(fixture.expirationForkHeight - chainActive.Height() -2);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test2","one",3);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(chainActive.Height(), expirationForkHeight -1);
BOOST_CHECK_EQUAL(chainActive.Height(), fixture.expirationForkHeight -1);
// Disable future expirations and fast-forward past the fork height
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(chainActive.Height(), expirationForkHeight);
BOOST_CHECK_EQUAL(pclaimTrie->nExpirationTime, extendedExpiration);
BOOST_CHECK_EQUAL(chainActive.Height(), fixture.expirationForkHeight);
BOOST_CHECK_EQUAL(pclaimTrie->nExpirationTime, fixture.extendedExpiration);
// make sure decrementing to before the fork height will apppropriately set back the
// expiration time to the original expiraiton time
fixture.DecrementBlocks(1);
BOOST_CHECK_EQUAL(pclaimTrie->nExpirationTime, originalExpiration);
BOOST_CHECK_EQUAL(pclaimTrie->nExpirationTime, fixture.originalExpiration);
fixture.IncrementBlocks(1);
// make sure that claim created 1 block before the fork expires as expected
// at the original expiration times
// at the extended expiration times
BOOST_CHECK(is_best_claim("test2", tx2));
fixture.IncrementBlocks(originalExpiration-1);
fixture.IncrementBlocks(fixture.extendedExpiration-1);
BOOST_CHECK(!is_best_claim("test2", tx2));
fixture.DecrementBlocks(originalExpiration-1);
fixture.DecrementBlocks(fixture.extendedExpiration-1);
// This first claim is still expired since it's pre-fork, even
// after fork activation
BOOST_CHECK(!is_best_claim("test",tx1));
// This new claim created at the fork height cannot expire at original expiration
BOOST_CHECK_EQUAL(chainActive.Height(), expirationForkHeight);
BOOST_CHECK_EQUAL(chainActive.Height(), fixture.expirationForkHeight);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",1);
fixture.IncrementBlocks(1);
fixture.IncrementBlocks(originalExpiration);
fixture.IncrementBlocks(fixture.originalExpiration);
BOOST_CHECK(is_best_claim("test",tx3));
BOOST_CHECK(!is_best_claim("test",tx1));
fixture.DecrementBlocks(originalExpiration);
fixture.DecrementBlocks(fixture.originalExpiration);
// but it expires at the extended expiration
fixture.IncrementBlocks(extendedExpiration);
// but it expires at the extended expiration, and not a single block below
fixture.IncrementBlocks(fixture.extendedExpiration);
BOOST_CHECK(!is_best_claim("test",tx3));
fixture.DecrementBlocks(extendedExpiration);
fixture.DecrementBlocks(fixture.extendedExpiration);
fixture.IncrementBlocks(fixture.extendedExpiration-1);
BOOST_CHECK(is_best_claim("test",tx3));
fixture.DecrementBlocks(fixture.extendedExpiration-1);
// Ensure that we cannot update the original pre-fork expired claim
CMutableTransaction u1 = fixture.MakeUpdate(tx1,"test","two",ClaimIdHash(tx1.GetHash(),0), 3);
@ -936,5 +947,121 @@ BOOST_AUTO_TEST_CASE(claimtriebranching_no_expire)
BOOST_CHECK(is_best_claim("test",u2));
}
/*
support expiration for hard fork
*/
BOOST_AUTO_TEST_CASE(claimtriebranching_hardfork_support)
{
ClaimTrieChainFixture fixture;
int blocks_before_fork = 10;
fixture.IncrementBlocks(fixture.expirationForkHeight - chainActive.Height() - blocks_before_fork-1);
// Create claim and support it before the fork height
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",1);
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(),tx1,"test",2);
// this claim will win without the support
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",2);
fixture.IncrementBlocks(1);
fixture.IncrementBlocks(blocks_before_fork);
// check that the claim expires as expected at the extended time, as does the support
fixture.IncrementBlocks(fixture.originalExpiration - blocks_before_fork);
BOOST_CHECK(is_best_claim("test",tx1));
BOOST_CHECK(best_claim_effective_amount_equals("test",3));
fixture.DecrementBlocks(fixture.originalExpiration - blocks_before_fork);
fixture.IncrementBlocks(fixture.extendedExpiration - blocks_before_fork);
BOOST_CHECK(!is_best_claim("test",tx1));
fixture.DecrementBlocks(fixture.extendedExpiration - blocks_before_fork);
fixture.IncrementBlocks(fixture.extendedExpiration - blocks_before_fork - 1);
BOOST_CHECK(is_best_claim("test",tx1));
BOOST_CHECK(best_claim_effective_amount_equals("test",3));
fixture.DecrementBlocks(fixture.extendedExpiration - blocks_before_fork - 1);
// update the claims at fork
fixture.DecrementBlocks(1);
CMutableTransaction u1 = fixture.MakeUpdate(tx1,"test","two",ClaimIdHash(tx1.GetHash(),0),1);
CMutableTransaction u2 = fixture.MakeUpdate(tx2,"test","two",ClaimIdHash(tx2.GetHash(),0),2);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(fixture.expirationForkHeight, chainActive.Height());
BOOST_CHECK(is_best_claim("test", u1));
BOOST_CHECK(best_claim_effective_amount_equals("test",3));
BOOST_CHECK(!is_claim_in_queue("test",tx1));
BOOST_CHECK(!is_claim_in_queue("test",tx2));
// check that the support expires as expected
fixture.IncrementBlocks(fixture.extendedExpiration - blocks_before_fork);
BOOST_CHECK(is_best_claim("test",u2));
fixture.DecrementBlocks(fixture.extendedExpiration - blocks_before_fork);
fixture.IncrementBlocks(fixture.extendedExpiration - blocks_before_fork - 1);
BOOST_CHECK(is_best_claim("test",u1));
BOOST_CHECK(best_claim_effective_amount_equals("test",3));
}
/*
claim/support expiration for hard fork, but with checks for disk procedures
*/
BOOST_AUTO_TEST_CASE(claimtriebranching_hardfork_disktest)
{
ClaimTrieChainFixture fixture;
// Check that incrementing to fork height, reseting to disk will get proper expiration time
BOOST_CHECK_EQUAL(pclaimTrie->nExpirationTime, fixture.originalExpiration);
fixture.IncrementBlocks(fixture.expirationForkHeight - chainActive.Height());
BOOST_CHECK_EQUAL(chainActive.Height(), fixture.expirationForkHeight);
BOOST_CHECK_EQUAL(pclaimTrie->nExpirationTime, fixture.extendedExpiration);
fixture.WriteClearReadClaimTrie();
BOOST_CHECK_EQUAL(pclaimTrie->nExpirationTime, fixture.extendedExpiration);
// Create a claim and support 1 block before the fork height that will expire after the fork height.
// Reset to disk, increment past the fork height and make sure we get
// proper behavior
fixture.DecrementBlocks(2);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",1);
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(),tx1,"test",1);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(chainActive.Height(), fixture.expirationForkHeight -1);
fixture.WriteClearReadClaimTrie();
BOOST_CHECK_EQUAL(chainActive.Height(), fixture.expirationForkHeight-1);
BOOST_CHECK_EQUAL(pclaimTrie->nExpirationTime, fixture.originalExpiration);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(pclaimTrie->nExpirationTime, fixture.extendedExpiration);
BOOST_CHECK(is_best_claim("test", tx1));
BOOST_CHECK(best_claim_effective_amount_equals("test",2));
fixture.IncrementBlocks(fixture.originalExpiration-1);
BOOST_CHECK(is_best_claim("test", tx1));
BOOST_CHECK(best_claim_effective_amount_equals("test",2));
fixture.DecrementBlocks(fixture.originalExpiration-1);
fixture.IncrementBlocks(fixture.extendedExpiration-1);
BOOST_CHECK(!is_best_claim("test", tx1));
// Create a claim and support before the fork height, reset to disk, update the claim
// increment past the fork height and make sure we get proper behavior
int height_of_update_before_expiration = 50;
fixture.DecrementBlocks(chainActive.Height() - fixture.expirationForkHeight + height_of_update_before_expiration+2);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test2","one",1);
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(),tx2,"test2",1);
fixture.IncrementBlocks(1);
fixture.WriteClearReadClaimTrie();
CMutableTransaction u2 = fixture.MakeUpdate(tx2,"test2","two",ClaimIdHash(tx2.GetHash(),0),1);
// increment to fork
fixture.IncrementBlocks(fixture.expirationForkHeight - chainActive.Height());
BOOST_CHECK(is_best_claim("test2", u2));
BOOST_CHECK(best_claim_effective_amount_equals("test2",2));
// increment to original expiration, should not be expired
fixture.IncrementBlocks(fixture.originalExpiration - height_of_update_before_expiration);
BOOST_CHECK(is_best_claim("test2", u2));
BOOST_CHECK(best_claim_effective_amount_equals("test2",2));
fixture.DecrementBlocks(fixture.originalExpiration - height_of_update_before_expiration);
// increment to extended expiration, should be expired and not one block before
fixture.IncrementBlocks(fixture.extendedExpiration - height_of_update_before_expiration);
BOOST_CHECK(!is_best_claim("test2", u2));
fixture.DecrementBlocks(fixture.extendedExpiration - height_of_update_before_expiration);
fixture.IncrementBlocks(fixture.extendedExpiration - height_of_update_before_expiration-1);
BOOST_CHECK(is_best_claim("test2", u2));
BOOST_CHECK(best_claim_effective_amount_equals("test2",1)); // the support expires one block before
}
BOOST_AUTO_TEST_SUITE_END()