repairing unintended hard fork at 745383
This commit is contained in:
parent
fea44d7daf
commit
bab4fd1648
4 changed files with 79 additions and 27 deletions
|
@ -144,7 +144,7 @@ public:
|
|||
consensus.nAllowMinDiffMaxHeight = -1;
|
||||
consensus.nNormalizedNameForkHeight = 539940; // targeting 21 March 2019
|
||||
consensus.nMinRemovalWorkaroundHeight = 297706;
|
||||
consensus.nMaxRemovalWorkaroundHeight = 100000000;
|
||||
consensus.nMaxRemovalWorkaroundHeight = 658300;
|
||||
consensus.nWitnessForkHeight = 680770; // targeting 11 Dec 2019
|
||||
consensus.nAllClaimsInMerkleForkHeight = 658310; // targeting 30 Oct 2019
|
||||
consensus.fPowAllowMinDifficultyBlocks = false;
|
||||
|
@ -371,8 +371,8 @@ public:
|
|||
consensus.nAllowMinDiffMinHeight = -1;
|
||||
consensus.nAllowMinDiffMaxHeight = -1;
|
||||
consensus.nNormalizedNameForkHeight = 250; // SDK depends upon this number
|
||||
consensus.nMinRemovalWorkaroundHeight = -1;
|
||||
consensus.nMaxRemovalWorkaroundHeight = -1;
|
||||
consensus.nMinRemovalWorkaroundHeight = 0;
|
||||
consensus.nMaxRemovalWorkaroundHeight = 1000;
|
||||
consensus.nWitnessForkHeight = 150;
|
||||
consensus.nAllClaimsInMerkleForkHeight = 350;
|
||||
consensus.fPowAllowMinDifficultyBlocks = false;
|
||||
|
|
|
@ -198,6 +198,27 @@ bool CClaimTrieCacheBase::haveSupportInQueue(const std::string& name, const COut
|
|||
return false;
|
||||
}
|
||||
|
||||
bool emptyNodeShouldExistAt(sqlite::database& db, const std::string& name, int nNextHeight) {
|
||||
auto end = name + std::string(256, std::numeric_limits<char>::max()); // 256 == MAX_CLAIM_NAME_SIZE + 1
|
||||
auto query = db << "SELECT DISTINCT nodeName FROM claim "
|
||||
"WHERE nodeName BETWEEN ?1 AND ?2 "
|
||||
"AND activationHeight < ?3 AND expirationHeight >= ?3 "
|
||||
"ORDER BY nodeName"
|
||||
<< name << end << nNextHeight;
|
||||
std::unordered_set<char> ss;
|
||||
for (auto&& row: query) {
|
||||
std::string nn;
|
||||
row >> nn;
|
||||
if (nn == name)
|
||||
return false;
|
||||
assert(nn.size() > name.size());
|
||||
ss.insert(nn[name.size()]);
|
||||
if (ss.size() > 1)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheBase::deleteNodeIfPossible(const std::string& name, std::string& parent, int64_t& claims)
|
||||
{
|
||||
if (name.empty()) return false;
|
||||
|
@ -676,19 +697,10 @@ bool CClaimTrieCacheBase::removeClaim(const uint160& claimId, const COutPoint& o
|
|||
// because it's a parent one and should not be effectively erased
|
||||
// we had a bug in the old code where that situation would force a zero delay on re-add
|
||||
if (nNextHeight >= base->nMinRemovalWorkaroundHeight
|
||||
&& nNextHeight < base->nMaxRemovalWorkaroundHeight) { // TODO: hard fork this out (which we already tried once but failed)
|
||||
// neither LIKE nor SUBSTR will use an index on a blob, but BETWEEN is a good, fast alternative
|
||||
auto end = nodeName + std::string( 256, std::numeric_limits<char>::max()); // 256 == MAX_CLAIM_NAME_SIZE + 1
|
||||
auto innerQuery = db << "SELECT nodeName FROM claim WHERE nodeName BETWEEN ?1 AND ?2 "
|
||||
"AND activationHeight < ?3 AND expirationHeight >= ?3 ORDER BY nodeName LIMIT 1"
|
||||
<< nodeName << end << nNextHeight;
|
||||
for (auto&& row: innerQuery) {
|
||||
std::string shortestMatch;
|
||||
row >> shortestMatch;
|
||||
if (shortestMatch != nodeName)
|
||||
// set this when there are no more claims on that name and that node still has children
|
||||
removalWorkaround.insert(nodeName);
|
||||
}
|
||||
&& nNextHeight < base->nMaxRemovalWorkaroundHeight
|
||||
) {
|
||||
if (emptyNodeShouldExistAt(db, nodeName, nNextHeight))
|
||||
removalWorkaround.insert(nodeName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -845,14 +857,27 @@ int CClaimTrieCacheBase::getDelayForName(const std::string& name, const uint160&
|
|||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: old code had a bug in it where nodes with no claims but with children would get left in the cache after removal.
|
||||
// This would cause the getNumBlocksOfContinuousOwnership to return zero (causing incorrect takeover height calc).
|
||||
auto hit = removalWorkaround.find(name);
|
||||
if (hit != removalWorkaround.end()) {
|
||||
removalWorkaround.erase(hit);
|
||||
if (!hasCurrentWinner)
|
||||
return 0;
|
||||
|
||||
if (nNextHeight > base->nMaxRemovalWorkaroundHeight) {
|
||||
// TODO: hard fork this out! It's wrong but kept for backwards compatibility
|
||||
// Plan: if we have no claims for this node but we do have multiple children
|
||||
// such that we have an implicit node here then return a 0
|
||||
if (emptyNodeShouldExistAt(db, name, nNextHeight))
|
||||
return 0;
|
||||
}
|
||||
return hasCurrentWinner ? std::min((nNextHeight - winningTakeoverHeight) / base->nProportionalDelayFactor, 4032) : 0;
|
||||
else {
|
||||
// NOTE: old code had a bug in it where nodes with no claims but with children would get left in the cache after removal.
|
||||
// This would cause the getNumBlocksOfContinuousOwnership to return zero (causing incorrect takeover height calc).
|
||||
auto hit = removalWorkaround.find(name);
|
||||
if (hit != removalWorkaround.end()) {
|
||||
removalWorkaround.erase(hit);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return std::min((nNextHeight - winningTakeoverHeight) / base->nProportionalDelayFactor, 4032);
|
||||
}
|
||||
|
||||
std::string CClaimTrieCacheBase::adjustNameForValidHeight(const std::string& name, int validHeight) const
|
||||
|
|
|
@ -24,6 +24,32 @@ BOOST_AUTO_TEST_CASE(claim_replace_test) {
|
|||
BOOST_CHECK(fixture.is_best_claim("bassfisher", tx2));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(triple_update_test)
|
||||
{
|
||||
ClaimTrieChainFixture fixture;
|
||||
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 10);
|
||||
fixture.IncrementBlocks(1);
|
||||
CMutableTransaction tx1a = fixture.MakeClaim(fixture.GetCoinbase(), "tester", "one", 3);
|
||||
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 5);
|
||||
auto height = chainActive.Tip()->nHeight;
|
||||
fixture.IncrementBlocks(9);
|
||||
|
||||
CMutableTransaction tx3 = fixture.MakeUpdate(tx1, "test", "two", ClaimIdHash(tx1.GetHash(), 0), 10);
|
||||
CMutableTransaction tx4 = fixture.MakeUpdate(tx2, "test", "two", ClaimIdHash(tx2.GetHash(), 0), 15);
|
||||
CMutableTransaction tx5 = fixture.MakeUpdate(tx4, "test", "two", ClaimIdHash(tx2.GetHash(), 0), 5);
|
||||
|
||||
fixture.IncrementBlocks(1);
|
||||
BOOST_CHECK(fixture.is_best_claim("test", tx3));
|
||||
uint160 id; int takeover;
|
||||
BOOST_REQUIRE(fixture.getLastTakeoverForName("test", id, takeover));
|
||||
BOOST_CHECK_EQUAL(takeover, height);
|
||||
id = ClaimIdHash(tx2.GetHash(), 0);
|
||||
std::string name;
|
||||
CClaimValue value;
|
||||
BOOST_REQUIRE(fixture.getClaimById(id, name, value));
|
||||
BOOST_CHECK_EQUAL(value.nValidAtHeight, height+20);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(takeover_stability_test) {
|
||||
// no competing bids
|
||||
ClaimTrieChainFixture fixture;
|
||||
|
|
|
@ -823,11 +823,12 @@ BOOST_AUTO_TEST_CASE(removal_workaround_functions)
|
|||
fixture.IncrementBlocks(1);
|
||||
BOOST_CHECK(fixture.is_best_claim("a", tx3a));
|
||||
|
||||
fixture.IncrementBlocks(7);
|
||||
CMutableTransaction tx4a = fixture.MakeUpdate(tx2a, "b", "b", ClaimIdHash(tx2a.GetHash(), 0), 4);
|
||||
CMutableTransaction tx4b = fixture.MakeUpdate(tx2b, "b", "b", ClaimIdHash(tx2b.GetHash(), 0), 5); // trigger a takeover
|
||||
fixture.IncrementBlocks(1);
|
||||
BOOST_CHECK(fixture.is_best_claim("b", tx4b));
|
||||
// TODO: bring this back after we hard fork out the removal workaround part 2!
|
||||
// fixture.IncrementBlocks(7);
|
||||
// CMutableTransaction tx4a = fixture.MakeUpdate(tx2a, "b", "b", ClaimIdHash(tx2a.GetHash(), 0), 4);
|
||||
// CMutableTransaction tx4b = fixture.MakeUpdate(tx2b, "b", "b", ClaimIdHash(tx2b.GetHash(), 0), 5); // trigger a takeover
|
||||
// fixture.IncrementBlocks(1);
|
||||
// BOOST_CHECK(fixture.is_best_claim("b", tx4b));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
Loading…
Reference in a new issue