Implement a hard fork for extended/infinite claim expiration times #112

Closed
lbrynaut wants to merge 247 commits from claim-expiration into master
7 changed files with 133 additions and 9 deletions
Showing only changes of commit a4cd484d5a - Show all commits

View file

@ -131,6 +131,9 @@ public:
consensus.powLimit = uint256S("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.powLimit = uint256S("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 150; //retarget every block consensus.nPowTargetTimespan = 150; //retarget every block
consensus.nPowTargetSpacing = 150; consensus.nPowTargetSpacing = 150;
consensus.nOriginalClaimExpirationTime = 262974;
consensus.nExtendedClaimExpirationTime = 2102400;
consensus.nExtendedClaimExpirationForkHeight = 400000; // FIXME: pick a real height
consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowAllowMinDifficultyBlocks = false;
consensus.fPowNoRetargeting = false; consensus.fPowNoRetargeting = false;
consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016
@ -215,6 +218,9 @@ public:
consensus.powLimit = uint256S("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.powLimit = uint256S("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 150; consensus.nPowTargetTimespan = 150;
consensus.nPowTargetSpacing = 150; consensus.nPowTargetSpacing = 150;
consensus.nOriginalClaimExpirationTime = 262974;
consensus.nExtendedClaimExpirationTime = 2102400;
consensus.nExtendedClaimExpirationForkHeight = 400000; // FIXME: pick a real height
consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowAllowMinDifficultyBlocks = true;
consensus.fPowNoRetargeting = false; consensus.fPowNoRetargeting = false;
consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
@ -292,6 +298,9 @@ public:
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 1;//14 * 24 * 60 * 60; // two weeks consensus.nPowTargetTimespan = 1;//14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 1; consensus.nPowTargetSpacing = 1;
consensus.nOriginalClaimExpirationTime = 262974;
consensus.nExtendedClaimExpirationTime = 2102400;
consensus.nExtendedClaimExpirationForkHeight = 450; // FIXME: pick a real height
consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowAllowMinDifficultyBlocks = false;
consensus.fPowNoRetargeting = false; consensus.fPowNoRetargeting = false;
consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains

View file

@ -218,6 +218,7 @@ bool CClaimTrie::supportQueueEmpty() const
void CClaimTrie::setExpirationTime(int t) void CClaimTrie::setExpirationTime(int t)
{ {
nExpirationTime = t; nExpirationTime = t;
LogPrintf("%s: Expiration time is now %d\n", __func__, nExpirationTime);
} }
void CClaimTrie::clear() void CClaimTrie::clear()
@ -1662,10 +1663,16 @@ bool CClaimTrieCache::removeClaim(const std::string& name, const COutPoint& outP
} }
void CClaimTrieCache::addToExpirationQueue(int nExpirationHeight, nameOutPointType& entry) const void CClaimTrieCache::addToExpirationQueue(int nExpirationHeight, nameOutPointType& entry) const
{
const Consensus::Params& consensusParams = Params().GetConsensus();
// NOTE: To allow extended claim expiration times, remove this check
if ((nExpirationHeight < consensusParams.nExtendedClaimExpirationForkHeight) ||
(base->nExpirationTime != consensusParams.nExtendedClaimExpirationTime))
{ {
expirationQueueType::iterator itQueueRow = getExpirationQueueCacheRow(nExpirationHeight, true); expirationQueueType::iterator itQueueRow = getExpirationQueueCacheRow(nExpirationHeight, true);
itQueueRow->second.push_back(entry); 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 nHeight) const
{ {
@ -1679,12 +1686,13 @@ void CClaimTrieCache::removeFromExpirationQueue(const std::string& name, const C
if (name == itQueue->name && outPoint == itQueue->outPoint) if (name == itQueue->name && outPoint == itQueue->outPoint)
break; break;
} }
}
if (itQueue != itQueueRow->second.end()) if (itQueue != itQueueRow->second.end())
{ {
itQueueRow->second.erase(itQueue); itQueueRow->second.erase(itQueue);
} }
} }
}
expirationQueueType::iterator CClaimTrieCache::getExpirationQueueCacheRow(int nHeight, bool createIfNotExists) const expirationQueueType::iterator CClaimTrieCache::getExpirationQueueCacheRow(int nHeight, bool createIfNotExists) const
{ {
@ -2104,6 +2112,7 @@ bool CClaimTrieCache::incrementBlock(insertUndoType& insertUndo, claimQueueRowTy
CClaimValue claim; CClaimValue claim;
assert(removeClaimFromTrie(itEntry->name, itEntry->outPoint, claim, true)); assert(removeClaimFromTrie(itEntry->name, itEntry->outPoint, claim, true));
expireUndo.push_back(std::make_pair(itEntry->name, claim)); expireUndo.push_back(std::make_pair(itEntry->name, claim));
LogPrintf("Expiring claim %s: %s, nHeight: %d, nValidAtHeight: %d\n", claim.claimId.GetHex(), itEntry->name, claim.nHeight, claim.nValidAtHeight);
} }
itExpirationRow->second.clear(); itExpirationRow->second.clear();
} }
@ -2155,6 +2164,7 @@ bool CClaimTrieCache::incrementBlock(insertUndoType& insertUndo, claimQueueRowTy
CSupportValue support; CSupportValue support;
assert(removeSupportFromMap(itEntry->name, itEntry->outPoint, support, true)); assert(removeSupportFromMap(itEntry->name, itEntry->outPoint, support, true));
expireSupportUndo.push_back(std::make_pair(itEntry->name, support)); expireSupportUndo.push_back(std::make_pair(itEntry->name, support));
LogPrintf("Expiring support %s: %s, nHeight: %d, nValidAtHeight: %d\n", support.supportedClaimId.GetHex(), itEntry->name, support.nHeight, support.nValidAtHeight);
} }
itSupportExpirationRow->second.clear(); itSupportExpirationRow->second.clear();
} }

View file

@ -6,6 +6,7 @@
#include "uint256.h" #include "uint256.h"
#include "util.h" #include "util.h"
#include "dbwrapper.h" #include "dbwrapper.h"
#include "chainparams.h"
#include "primitives/transaction.h" #include "primitives/transaction.h"
#include <string> #include <string>

View file

@ -58,6 +58,14 @@ struct Params {
bool fPowNoRetargeting; bool fPowNoRetargeting;
int64_t nPowTargetSpacing; int64_t nPowTargetSpacing;
int64_t nPowTargetTimespan; int64_t nPowTargetTimespan;
int64_t nOriginalClaimExpirationTime;
int64_t nExtendedClaimExpirationTime;
int64_t nExtendedClaimExpirationForkHeight;
int64_t GetExpirationTime(int64_t nHeight) const {
return nHeight < nExtendedClaimExpirationForkHeight ?
nOriginalClaimExpirationTime :
nExtendedClaimExpirationTime;
}
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; } int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
}; };
} // namespace Consensus } // namespace Consensus

View file

@ -1229,6 +1229,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024));
LogPrintf("* Using %.1fMiB for in-memory UTXO set\n", nCoinCacheUsage * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1fMiB for in-memory UTXO set\n", nCoinCacheUsage * (1.0 / 1024 / 1024));
const Consensus::Params& consensusParams = Params().GetConsensus();
bool fLoaded = false; bool fLoaded = false;
while (!fLoaded) { while (!fLoaded) {
bool fReset = fReindex; bool fReset = fReindex;
@ -1266,7 +1268,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// If the loaded chain has a wrong genesis, bail out immediately // If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around). // (we're likely using a testnet datadir, or the other way around).
if (!mapBlockIndex.empty() && mapBlockIndex.count(chainparams.GetConsensus().hashGenesisBlock) == 0) if (!mapBlockIndex.empty() && mapBlockIndex.count(consensusParams.hashGenesisBlock) == 0)
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
// Initialize the block index (no-op if non-empty database was already loaded) // Initialize the block index (no-op if non-empty database was already loaded)
@ -1422,6 +1424,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
RandAddSeedPerfmon(); RandAddSeedPerfmon();
pclaimTrie->setExpirationTime(consensusParams.GetExpirationTime(chainActive.Height()));
//// debug print //// debug print
LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size()); LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
LogPrintf("nBestHeight = %d\n", chainActive.Height()); LogPrintf("nBestHeight = %d\n", chainActive.Height());
@ -1437,7 +1441,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
StartNode(threadGroup, scheduler); StartNode(threadGroup, scheduler);
// Monitor the chain, and alert if we get blocks much quicker or slower than expected // Monitor the chain, and alert if we get blocks much quicker or slower than expected
int64_t nPowTargetSpacing = Params().GetConsensus().nPowTargetSpacing; int64_t nPowTargetSpacing = consensusParams.nPowTargetSpacing;
CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload, CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload,
boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing); boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing);
scheduler.scheduleEvery(f, nPowTargetSpacing); scheduler.scheduleEvery(f, nPowTargetSpacing);

View file

@ -2163,12 +2163,22 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
if (op == OP_CLAIM_NAME) if (op == OP_CLAIM_NAME)
{ {
assert(vvchParams.size() == 2); assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
std::string value(vvchParams[1].begin(), vvchParams[1].end());
claimId = ClaimIdHash(hash, i); claimId = ClaimIdHash(hash, i);
LogPrintf("--- %s[%lu]: OP_CLAIM_NAME \"%s\" = \"%s\" with claimId %s and tx prevout %s at index %d\n",
__func__, view.AccessCoins(hash)->nHeight, name, SanitizeString(value),
claimId.GetHex(), hash.ToString(), i);
} }
else if (op == OP_UPDATE_CLAIM) else if (op == OP_UPDATE_CLAIM)
{ {
assert(vvchParams.size() == 3); assert(vvchParams.size() == 3);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
std::string value(vvchParams[1].begin(), vvchParams[1].end());
claimId = uint160(vvchParams[1]); claimId = uint160(vvchParams[1]);
LogPrintf("--- %s[%lu]: OP_UPDATE_CLAIM \"%s\" = \"%s\" with claimId %s and tx prevout %s at index %d\n",
__func__, view.AccessCoins(hash)->nHeight, name, SanitizeString(value),
claimId.GetHex(), hash.ToString(), i);
} }
std::string name(vvchParams[0].begin(), vvchParams[0].end()); std::string name(vvchParams[0].begin(), vvchParams[0].end());
LogPrintf("%s: (txid: %s, nOut: %d) Trying to remove %s from the claim trie due to its block being disconnected\n", __func__, hash.ToString(), i, name.c_str()); LogPrintf("%s: (txid: %s, nOut: %d) Trying to remove %s from the claim trie due to its block being disconnected\n", __func__, hash.ToString(), i, name.c_str());
@ -2182,6 +2192,8 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
assert(vvchParams.size() == 2); assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end()); std::string name(vvchParams[0].begin(), vvchParams[0].end());
uint160 supportedClaimId(vvchParams[1]); uint160 supportedClaimId(vvchParams[1]);
LogPrintf("--- %s[%lu]: OP_SUPPORT_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n",
__func__, view.AccessCoins(hash)->nHeight, name, supportedClaimId.GetHex(), hash.ToString(), i);
LogPrintf("%s: (txid: %s, nOut: %d) Removing support for claim id %s on %s due to its block being disconnected\n", __func__, hash.ToString(), i, supportedClaimId.ToString(), name.c_str()); LogPrintf("%s: (txid: %s, nOut: %d) Removing support for claim id %s on %s due to its block being disconnected\n", __func__, hash.ToString(), i, supportedClaimId.ToString(), name.c_str());
if (!trieCache.undoAddSupport(name, COutPoint(hash, i), pindex->nHeight)) if (!trieCache.undoAddSupport(name, COutPoint(hash, i), pindex->nHeight))
LogPrintf("%s: Something went wrong removing support for name %s in hash %s\n", __func__, name.c_str(), hash.ToString()); LogPrintf("%s: Something went wrong removing support for name %s in hash %s\n", __func__, name.c_str(), hash.ToString());
@ -2212,6 +2224,8 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
assert(trieCache.finalizeDecrement()); assert(trieCache.finalizeDecrement());
trieCache.setBestBlock(pindex->pprev->GetBlockHash()); trieCache.setBestBlock(pindex->pprev->GetBlockHash());
assert(trieCache.getMerkleHash() == pindex->pprev->hashClaimTrie); assert(trieCache.getMerkleHash() == pindex->pprev->hashClaimTrie);
if (pindex->pprev->nHeight >= Params().GetConsensus().nExtendedClaimExpirationForkHeight)
pclaimTrie->setExpirationTime(Params().GetConsensus().GetExpirationTime(pindex->pprev->nHeight));
if (pfClean) { if (pfClean) {
*pfClean = fClean; *pfClean = fClean;
@ -2565,12 +2579,22 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (op == OP_CLAIM_NAME) if (op == OP_CLAIM_NAME)
{ {
assert(vvchParams.size() == 2); assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
std::string value(vvchParams[1].begin(), vvchParams[1].end());
claimId = ClaimIdHash(txin.prevout.hash, txin.prevout.n); claimId = ClaimIdHash(txin.prevout.hash, txin.prevout.n);
LogPrintf("+++ %s[%lu]: OP_CLAIM_NAME \"%s\" = \"%s\" with claimId %s and tx prevout %s at index %d\n",
__func__, view.AccessCoins(txin.prevout.hash)->nHeight, name, SanitizeString(value),
claimId.GetHex(), txin.prevout.hash.GetHex(), txin.prevout.n);
} }
else if (op == OP_UPDATE_CLAIM) else if (op == OP_UPDATE_CLAIM)
{ {
assert(vvchParams.size() == 3); assert(vvchParams.size() == 3);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
std::string value(vvchParams[1].begin(), vvchParams[1].end());
claimId = uint160(vvchParams[1]); claimId = uint160(vvchParams[1]);
LogPrintf("+++ %s[%lu]: OP_UPDATE_CLAIM \"%s\" = \"%s\" with claimId %s and tx prevout %s at index %d\n",
__func__, view.AccessCoins(txin.prevout.hash)->nHeight, name, SanitizeString(value),
claimId.GetHex(), txin.prevout.hash.GetHex(), txin.prevout.n);
} }
std::string name(vvchParams[0].begin(), vvchParams[0].end()); std::string name(vvchParams[0].begin(), vvchParams[0].end());
int nValidAtHeight; int nValidAtHeight;
@ -2587,6 +2611,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
assert(vvchParams.size() == 2); assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end()); std::string name(vvchParams[0].begin(), vvchParams[0].end());
uint160 supportedClaimId(vvchParams[1]); uint160 supportedClaimId(vvchParams[1]);
LogPrintf("+++ %s[%lu]: OP_SUPPORT_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n",
__func__, view.AccessCoins(txin.prevout.hash)->nHeight, name,
supportedClaimId.GetHex(), txin.prevout.hash.GetHex(), txin.prevout.n);
int nValidAtHeight; int nValidAtHeight;
LogPrintf("%s: Removing support for %s in %s. Tx: %s, nOut: %d, removed txid: %s\n", __func__, supportedClaimId.ToString(), name, txin.prevout.hash.ToString(), txin.prevout.n,tx.GetHash().ToString()); LogPrintf("%s: Removing support for %s in %s. Tx: %s, nOut: %d, removed txid: %s\n", __func__, supportedClaimId.ToString(), name, txin.prevout.hash.ToString(), txin.prevout.n,tx.GetHash().ToString());
if (trieCache.spendSupport(name, COutPoint(txin.prevout.hash, txin.prevout.n), coins->nHeight, nValidAtHeight)) if (trieCache.spendSupport(name, COutPoint(txin.prevout.hash, txin.prevout.n), coins->nHeight, nValidAtHeight))
@ -2736,6 +2763,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// add this block to the view's block chain // add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash()); view.SetBestBlock(pindex->GetBlockHash());
trieCache.setBestBlock(pindex->GetBlockHash()); trieCache.setBestBlock(pindex->GetBlockHash());
if (pindex->nHeight >= Params().GetConsensus().nExtendedClaimExpirationForkHeight)
pclaimTrie->setExpirationTime(chainparams.GetConsensus().GetExpirationTime(pindex->nHeight));
int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4; int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4;
LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001); LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001);

View file

@ -683,6 +683,7 @@ BOOST_AUTO_TEST_CASE(claimtriebranching_update)
fixture.DecrementBlocks(11); fixture.DecrementBlocks(11);
} }
/* /*
expiration expiration
check claims expire and loses claim check claims expire and loses claim
@ -733,5 +734,67 @@ BOOST_AUTO_TEST_CASE(claimtriebranching_expire)
} }
/*
expiration
check claims do not expire post ExpirationForkHeight
check supports work post ExpirationForkHeight
*/
BOOST_AUTO_TEST_CASE(claimtriebranching_no_expire)
{
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.
pclaimTrie->setExpirationTime(5);
const int expirationForkHeight =
Params(CBaseChainParams::REGTEST).GetConsensus().nExtendedClaimExpirationForkHeight;
// First create a claim and make sure it expires pre-fork
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",3);
fixture.IncrementBlocks(6);
BOOST_CHECK(!is_best_claim("test",tx1));
fixture.DecrementBlocks(4);
BOOST_CHECK(is_best_claim("test",tx1));
fixture.IncrementBlocks(4);
BOOST_CHECK(!is_best_claim("test",tx1));
// Disable future expirations and fast-forward past the fork height
fixture.IncrementBlocks(expirationForkHeight);
pclaimTrie->setExpirationTime(2102400);
// 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 cannot expire
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",1);
fixture.IncrementBlocks(6);
BOOST_CHECK(is_best_claim("test",tx2));
BOOST_CHECK(!is_best_claim("test",tx1));
// Ensure that we cannot update the original pre-fork expired claim
CMutableTransaction u1 = fixture.MakeUpdate(tx1,"test","two",ClaimIdHash(tx1.GetHash(),0), 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(!is_best_claim("test",u1));
// Ensure that supports for the expired claim don't support it
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(),u1,"test",10);
BOOST_CHECK(!is_best_claim("test",u1));
// Ensure that we can update the new post-fork claim
CMutableTransaction u2 = fixture.MakeUpdate(tx2,"test","two",ClaimIdHash(tx2.GetHash(),0), 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(is_best_claim("test",u2));
// Ensure that supports for the new post-fork claim
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(),u2,"test",3);
BOOST_CHECK(is_best_claim("test",u2));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()