Organize unit tests by type

Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>

moved a few more tests out
This commit is contained in:
Brannon King 2019-09-11 09:19:43 -06:00
parent 476eae3e93
commit 8b98a9a4e9
10 changed files with 2805 additions and 2684 deletions

View file

@ -66,6 +66,11 @@ BITCOIN_TESTS =\
test/net_tests.cpp \ test/net_tests.cpp \
test/claimtriecache_tests.cpp \ test/claimtriecache_tests.cpp \
test/claimtriebranching_tests.cpp \ test/claimtriebranching_tests.cpp \
test/claimtrieexpirationfork_tests.cpp \
test/claimtriefixture.cpp \
test/claimtriehashfork_tests.cpp \
test/claimtrienormalization_tests.cpp \
test/claimtrierpc_tests.cpp \
test/nameclaim_tests.cpp \ test/nameclaim_tests.cpp \
test/netbase_tests.cpp \ test/netbase_tests.cpp \
test/pmt_tests.cpp \ test/pmt_tests.cpp \

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,7 @@
#include <uint256.h> #include <uint256.h>
#include <validation.h> #include <validation.h>
#include <test/claimtriefixture.h>
#include <test/test_bitcoin.h> #include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <boost/scope_exit.hpp> #include <boost/scope_exit.hpp>
@ -42,23 +43,6 @@ public:
} }
}; };
CMutableTransaction BuildTransaction(const uint256& prevhash)
{
CMutableTransaction tx;
tx.nVersion = 1;
tx.nLockTime = 0;
tx.vin.resize(1);
tx.vout.resize(1);
tx.vin[0].prevout.hash = prevhash;
tx.vin[0].prevout.n = 0;
tx.vin[0].scriptSig = CScript();
tx.vin[0].nSequence = std::numeric_limits<unsigned int>::max();
tx.vout[0].scriptPubKey = CScript();
tx.vout[0].nValue = 0;
return tx;
}
BOOST_FIXTURE_TEST_SUITE(claimtriecache_tests, RegTestingSetup) BOOST_FIXTURE_TEST_SUITE(claimtriecache_tests, RegTestingSetup)
BOOST_AUTO_TEST_CASE(merkle_hash_single_test) BOOST_AUTO_TEST_CASE(merkle_hash_single_test)
@ -403,4 +387,67 @@ BOOST_AUTO_TEST_CASE(verify_basic_serialization)
BOOST_CHECK_EQUAL(cv.nEffectiveAmount, cv2.nEffectiveAmount); BOOST_CHECK_EQUAL(cv.nEffectiveAmount, cv2.nEffectiveAmount);
} }
BOOST_AUTO_TEST_CASE(claimtrienode_serialize_unserialize)
{
CDataStream ss(SER_DISK, 0);
uint160 hash160;
CClaimTrieData n1;
CClaimTrieData n2;
CClaimValue throwaway;
ss << n1;
ss >> n2;
BOOST_CHECK_EQUAL(n1, n2);
CClaimValue v1(COutPoint(uint256S("0000000000000000000000000000000000000000000000000000000000000001"), 0), hash160, 50, 0, 100);
CClaimValue v2(COutPoint(uint256S("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), 1), hash160, 100, 1, 101);
n1.insertClaim(v1);
BOOST_CHECK(n1 != n2);
ss << n1;
ss >> n2;
BOOST_CHECK_EQUAL(n1, n2);
n1.insertClaim(v2);
BOOST_CHECK(n1 != n2);
ss << n1;
ss >> n2;
BOOST_CHECK_EQUAL(n1, n2);
n1.removeClaim(v1.outPoint, throwaway);
BOOST_CHECK(n1 != n2);
ss << n1;
ss >> n2;
BOOST_CHECK_EQUAL(n1, n2);
n1.removeClaim(v2.outPoint, throwaway);
BOOST_CHECK(n1 != n2);
ss << n1;
ss >> n2;
BOOST_CHECK_EQUAL(n1, n2);
}
BOOST_AUTO_TEST_CASE(claimtrienode_remove_invalid_claim)
{
uint160 hash160;
CClaimTrieData n1;
CClaimTrieData n2;
CClaimValue throwaway;
CClaimValue v1(COutPoint(uint256S("0000000000000000000000000000000000000000000000000000000000000001"), 0), hash160, 50, 0, 100);
CClaimValue v2(COutPoint(uint256S("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), 1), hash160, 100, 1, 101);
n1.insertClaim(v1);
n2.insertClaim(v2);
bool invalidClaim = n2.removeClaim(v1.outPoint, throwaway);
BOOST_CHECK_EQUAL(invalidClaim, false);
invalidClaim = n1.removeClaim(v2.outPoint, throwaway);
BOOST_CHECK_EQUAL(invalidClaim, false);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

View file

@ -0,0 +1,803 @@
// Copyright (c) 2015-2019 The LBRY Foundation
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#include <test/claimtriefixture.h>
using namespace std;
BOOST_FIXTURE_TEST_SUITE(claimtrieexpirationfork_tests, RegTestingSetup)
/*
expiration
check claims expire and loses claim
check claims expire and is not updateable (may be changed in future soft fork)
check supports expire and can cause supported bid to lose claim
*/
BOOST_AUTO_TEST_CASE(claimtrie_expire_test)
{
ClaimTrieChainFixture fixture;
fixture.setExpirationForkHeight(1000000, 5, 1000000);
// check claims expire and loses claim
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test", "one", 2);
fixture.IncrementBlocks(fixture.expirationTime());
BOOST_CHECK(fixture.is_best_claim("test", tx1));
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test", "one", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test", tx2));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test", tx1));
fixture.DecrementBlocks(fixture.expirationTime());
// check claims expire and is not updateable (may be changed in future soft fork)
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(),"test", "one", 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test", tx3));
fixture.IncrementBlocks(fixture.expirationTime());
CMutableTransaction u1 = fixture.MakeUpdate(tx3, "test", "two", ClaimIdHash(tx3.GetHash(), 0), 2);
BOOST_CHECK(!fixture.is_best_claim("test",u1));
fixture.DecrementBlocks(fixture.expirationTime());
BOOST_CHECK(fixture.is_best_claim("test", tx3));
fixture.DecrementBlocks(1);
// check supports expire and can cause supported bid to lose claim
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1);
CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 2);
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx4, "test", 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test",tx4));
CMutableTransaction u2 = fixture.MakeUpdate(tx4, "test", "two", ClaimIdHash(tx4.GetHash(),0), 1);
CMutableTransaction u3 = fixture.MakeUpdate(tx5, "test", "two", ClaimIdHash(tx5.GetHash(),0), 2);
fixture.IncrementBlocks(fixture.expirationTime());
BOOST_CHECK(fixture.is_best_claim("test", u3));
fixture.DecrementBlocks(fixture.expirationTime());
BOOST_CHECK(fixture.is_best_claim("test", tx4));
fixture.DecrementBlocks(1);
// check updated claims will extend expiration
CMutableTransaction tx6 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test", tx6));
CMutableTransaction u4 = fixture.MakeUpdate(tx6, "test", "two", ClaimIdHash(tx6.GetHash(), 0), 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test", u4));
fixture.IncrementBlocks(fixture.expirationTime()-1);
BOOST_CHECK(fixture.is_best_claim("test", u4));
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.is_best_claim("test", u4));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test", u4));
fixture.DecrementBlocks(fixture.expirationTime());
BOOST_CHECK(fixture.is_best_claim("test", tx6));
}
/*
claim expiration for hard fork
check claims do not expire post ExpirationForkHeight
check supports work post ExpirationForkHeight
*/
BOOST_AUTO_TEST_CASE(hardfork_claim_test)
{
ClaimTrieChainFixture fixture;
fixture.setExpirationForkHeight(7, 3, 6);
// First create a claim and make sure it expires pre-fork
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",3);
fixture.IncrementBlocks(4);
BOOST_CHECK(!fixture.is_best_claim("test",tx1));
fixture.DecrementBlocks(3);
BOOST_CHECK(fixture.is_best_claim("test",tx1));
fixture.IncrementBlocks(3);
BOOST_CHECK(!fixture.is_best_claim("test",tx1));
// Create a claim 1 block before the fork height that will expire after the fork height
fixture.IncrementBlocks(1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test2","one",3);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 3);
// Disable future expirations and fast-forward past the fork height
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
// 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(fixture.expirationTime(), 3);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
// make sure that claim created 1 block before the fork expires as expected
// at the extended expiration times
BOOST_CHECK(fixture.is_best_claim("test2", tx2));
fixture.IncrementBlocks(5);
BOOST_CHECK(!fixture.is_best_claim("test2", tx2));
fixture.DecrementBlocks(5);
BOOST_CHECK(fixture.is_best_claim("test2", tx2));
// This first claim is still expired since it's pre-fork, even
// after fork activation
BOOST_CHECK(!fixture.is_best_claim("test", tx1));
// This new claim created at the fork height cannot expire at original expiration
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",1);
fixture.IncrementBlocks(1);
fixture.IncrementBlocks(3);
BOOST_CHECK(fixture.is_best_claim("test",tx3));
BOOST_CHECK(!fixture.is_best_claim("test",tx1));
fixture.DecrementBlocks(3);
// but it expires at the extended expiration, and not a single block below
fixture.IncrementBlocks(6);
BOOST_CHECK(!fixture.is_best_claim("test",tx3));
fixture.DecrementBlocks(6);
fixture.IncrementBlocks(5);
BOOST_CHECK(fixture.is_best_claim("test",tx3));
fixture.DecrementBlocks(5);
// 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(!fixture.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(!fixture.is_best_claim("test",u1));
// Ensure that we can update the new post-fork claim
CMutableTransaction u2 = fixture.MakeUpdate(tx3,"test","two",ClaimIdHash(tx3.GetHash(),0), 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.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(fixture.is_best_claim("test",u2));
}
/*
support expiration for hard fork
*/
BOOST_AUTO_TEST_CASE(hardfork_support_test)
{
ClaimTrieChainFixture fixture;
fixture.setExpirationForkHeight(2, 2, 4);
// 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(2);
// check that the claim expires as expected at the extended time, as does the support
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim("test",tx1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3));
fixture.DecrementBlocks(2);
fixture.IncrementBlocks(3);
BOOST_CHECK(!fixture.is_best_claim("test",tx1));
fixture.DecrementBlocks(3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test",tx1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3));
fixture.DecrementBlocks(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(Params().GetConsensus().nExtendedClaimExpirationForkHeight, chainActive.Height());
BOOST_CHECK(fixture.is_best_claim("test", u1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3));
BOOST_CHECK(!fixture.is_claim_in_queue("test", tx1));
BOOST_CHECK(!fixture.is_claim_in_queue("test", tx2));
// check that the support expires as expected
fixture.IncrementBlocks(3);
BOOST_CHECK(fixture.is_best_claim("test", u2));
fixture.DecrementBlocks(3);
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim("test",u1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3));
}
/*
activation_fall_through and supports_fall_through
Tests for where claims/supports in queues would be undone properly in a decrement.
See https://github.com/lbryio/lbrycrd/issues/243 for more details
*/
BOOST_AUTO_TEST_CASE(activations_fall_through)
{
ClaimTrieChainFixture fixture;
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
fixture.IncrementBlocks(3);
BOOST_CHECK_EQUAL(fixture.proportionalDelayFactor(), 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx1));
fixture.IncrementBlocks(3);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
fixture.DecrementBlocks(3);
fixture.Spend(tx1); // this will trigger early activation on tx2 claim
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
fixture.DecrementBlocks(1); //reorg the early activation
BOOST_CHECK(fixture.is_best_claim("A", tx1));
fixture.Spend(tx1);
fixture.IncrementBlocks(1); // this should not cause tx2 to activate again and crash
BOOST_CHECK(fixture.is_best_claim("A", tx2));
}
BOOST_AUTO_TEST_CASE(supports_fall_through)
{
ClaimTrieChainFixture fixture;
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 3);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 1);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "3", 2);
fixture.IncrementBlocks(3);
BOOST_CHECK_EQUAL(fixture.proportionalDelayFactor(), 1);
CMutableTransaction sx2 = fixture.MakeSupport(fixture.GetCoinbase(), tx2, "A", 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx1));
fixture.IncrementBlocks(3);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
fixture.DecrementBlocks(3);
fixture.Spend(tx1); // this will trigger early activation
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
fixture.DecrementBlocks(1); // reorg the early activation
BOOST_CHECK(fixture.is_best_claim("A", tx1));
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx1)); //tx2 support should not be active
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx1)); //tx2 support should not be active
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx2)); //tx2 support should be active now
}
/*
claim/support expiration for hard fork, but with checks for disk procedures
*/
BOOST_AUTO_TEST_CASE(hardfork_disk_test)
{
ClaimTrieChainFixture fixture;
fixture.setExpirationForkHeight(7, 3, 6);
// Check that incrementing to fork height, reseting to disk will get proper expiration time
BOOST_CHECK_EQUAL(fixture.expirationTime(), 3);
fixture.IncrementBlocks(7, true);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
fixture.ReadFromDisk(chainActive.Tip());
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
// 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);
fixture.ReadFromDisk(chainActive.Tip());
BOOST_CHECK_EQUAL(fixture.expirationTime(), 3);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
BOOST_CHECK(fixture.is_best_claim("test", tx1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",2));
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim("test", tx1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",2));
fixture.DecrementBlocks(2);
fixture.IncrementBlocks(5);
BOOST_CHECK(!fixture.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
fixture.DecrementBlocks();
fixture.setExpirationForkHeight(3, 5, 6);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test2","one",1);
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(),tx2,"test2",1);
fixture.IncrementBlocks(1);
fixture.ReadFromDisk(chainActive.Tip());
CMutableTransaction u2 = fixture.MakeUpdate(tx2, "test2", "two", ClaimIdHash(tx2.GetHash(), 0), 1);
// increment to fork
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim("test2", u2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test2",2));
// increment to original expiration, should not be expired
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim("test2", u2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test2", 2));
fixture.DecrementBlocks(2);
// increment to extended expiration, should be expired and not one block before
fixture.IncrementBlocks(5);
BOOST_CHECK(!fixture.is_best_claim("test2", u2));
fixture.DecrementBlocks(5);
fixture.IncrementBlocks(4);
BOOST_CHECK(fixture.is_best_claim("test2", u2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test2", 1)); // the support expires one block before
}
BOOST_AUTO_TEST_CASE(claim_expiration_test)
{
ClaimTrieChainFixture fixture;
std::string sName("atest");
std::string sValue("testa");
int nThrowaway;
// set expiration time to 80 blocks after the block is created
fixture.setExpirationForkHeight(1000000, 80, 1000000);
// create a claim. verify the expiration event has been scheduled.
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue, 10);
COutPoint tx1OutPoint(tx1.GetHash(), 0);
fixture.IncrementBlocks(1, true);
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// advance until the expiration event occurs. verify the expiration event occurs on time.
fixture.IncrementBlocks(79); // 80
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
fixture.IncrementBlocks(1); // 81
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.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.
fixture.IncrementBlocks(20); // 101
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
fixture.DecrementBlocks(21); // 80
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// advance until the expiration event occurs. verify the expiration event occurs on time.
fixture.IncrementBlocks(1); // 81
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again.
fixture.DecrementBlocks(2); // 79
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// roll back some more.
fixture.DecrementBlocks(39); // 40
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// spend the claim. verify the expiration event is removed.
CMutableTransaction tx2 = fixture.Spend(tx1);
fixture.IncrementBlocks(1); // 41
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// roll back the spend. verify the expiration event is returned.
fixture.DecrementBlocks(1); // 40
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// advance until the expiration event occurs. verify the event occurs on time.
fixture.IncrementBlocks(40); // 80
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
fixture.IncrementBlocks(1); // 81
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// spend the expired claim
fixture.CommitTx(tx2);
fixture.IncrementBlocks(1); // 82
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// undo the spend. verify everything remains empty.
fixture.DecrementBlocks(1); // 81
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again.
fixture.DecrementBlocks(1); // 80
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// verify the expiration event happens at the right time again
fixture.IncrementBlocks(1); // 81
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// roll back to before the expiration event. verify it gets reinserted and expiration gets scheduled.
fixture.DecrementBlocks(1); // 80
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// roll all the way back. verify the claim is removed and the expiration event is removed.
fixture.DecrementBlocks(); // 0
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// Make sure that when a claim expires, a lesser claim for the same name takes over
CClaimValue val;
// create one claim for the name
fixture.CommitTx(tx1);
fixture.IncrementBlocks(1, true); // 1
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// advance a little while and insert the second claim
fixture.IncrementBlocks(4); // 5
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue, 5);
COutPoint tx3OutPoint(tx3.GetHash(), 0);
fixture.IncrementBlocks(1); // 6
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(!fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// advance until tx3 is valid, ensure tx1 is winning
fixture.IncrementBlocks(4); // 10
BOOST_CHECK(!fixture.queueEmpty());
BOOST_CHECK(fixture.haveClaimInQueue(sName, tx3OutPoint, nThrowaway));
fixture.IncrementBlocks(1); // 11
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint);
uint256 tx1MerkleHash = fixture.getMerkleHash();
// roll back to before tx3 is valid
fixture.DecrementBlocks(1); // 10
// advance again until tx is valid
fixture.IncrementBlocks(1); // 11
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint);
BOOST_CHECK_EQUAL(tx1MerkleHash, fixture.getMerkleHash());
// advance until the expiration event occurs. verify the expiration event occurs on time.
fixture.IncrementBlocks(69, true); // 80
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
fixture.IncrementBlocks(1); // 81
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint, tx3OutPoint);
BOOST_CHECK(tx1MerkleHash != fixture.getMerkleHash());
// spend tx1
fixture.CommitTx(tx2);
fixture.IncrementBlocks(1); // 82
// roll back to when tx1 and tx3 are in the trie and tx1 is winning
fixture.DecrementBlocks(); // 11
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint);
BOOST_CHECK_EQUAL(tx1MerkleHash, fixture.getMerkleHash());
// roll all the way back
fixture.DecrementBlocks();
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
}
BOOST_AUTO_TEST_CASE(expiring_supports_test)
{
ClaimTrieChainFixture fixture;
std::string sName("atest");
std::string sValue1("testa");
std::string sValue2("testb");
CClaimValue val;
std::vector<uint256> blocks_to_invalidate;
fixture.setExpirationForkHeight(1000000, 80, 1000000);
// to be active bid must have: a higher block number and current block >= (current height - block number) / 32
// Verify that supports expire
// Create a 1 LBC claim (tx1)
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue1, 1);
fixture.IncrementBlocks(1); // 1, expires at 81
BOOST_CHECK(pcoinsTip->HaveCoin(COutPoint(tx1.GetHash(), 0)));
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
// Create a 5 LBC support (tx3)
CMutableTransaction tx3 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName, 5);
fixture.IncrementBlocks(1); // 2, expires at 82
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
// Advance some, then insert 5 LBC claim (tx2)
fixture.IncrementBlocks(19); // 21
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue2, 5);
fixture.IncrementBlocks(1); // 22, activating in (22 - 2) / 1 = 20block (but not then active because support still holds tx1 up)
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(!fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
uint256 rootMerkleHash = fixture.getMerkleHash();
// Advance until tx2 is valid
fixture.IncrementBlocks(20); // 42
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(!fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK_EQUAL(rootMerkleHash, fixture.getMerkleHash());
fixture.IncrementBlocks(1); // 43
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx1.GetHash());
rootMerkleHash = fixture.getMerkleHash();
// Update tx1 so that it expires after tx3 expires
uint160 claimId = ClaimIdHash(tx1.GetHash(), 0);
CMutableTransaction tx4 = fixture.MakeUpdate(tx1, sName, sValue1, claimId, tx1.vout[0].nValue);
fixture.IncrementBlocks(1); // 104
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash());
BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash());
// Advance until the support expires
fixture.IncrementBlocks(37); // 81
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
rootMerkleHash = fixture.getMerkleHash();
fixture.IncrementBlocks(1); // 82
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash());
BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash());
rootMerkleHash = fixture.getMerkleHash();
// undo the block, make sure control goes back
fixture.DecrementBlocks(1); // 81
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash());
BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash());
// redo the block, make sure it expires again
fixture.IncrementBlocks(1); // 82
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash());
rootMerkleHash = fixture.getMerkleHash();
// roll back some, spend the support, and make sure nothing unexpected
// happens at the time the support should have expired
fixture.DecrementBlocks(19); // 63
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash());
BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash());
fixture.Spend(tx3);
fixture.IncrementBlocks(1); // 64
blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash());
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash());
fixture.IncrementBlocks(20); // 84
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash());
//undo the spend, and make sure it still expires on time
fixture.DecrementBlocks(21); // 63
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash());
fixture.IncrementBlocks(18); // 81
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash());
fixture.IncrementBlocks(1); // 82
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash());
// roll all the way back
fixture.DecrementBlocks(82);
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
}
BOOST_AUTO_TEST_CASE(get_claim_by_id_test_3)
{
ClaimTrieChainFixture fixture;
fixture.setExpirationForkHeight(1000000, 5, 1000000);
const std::string name = "test";
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, "one", 1);
uint160 claimId = ClaimIdHash(tx1.GetHash(), 0);
fixture.IncrementBlocks(1);
CClaimValue claimValue;
std::string claimName;
BOOST_CHECK(getClaimById(claimId, claimName, &claimValue));
BOOST_CHECK_EQUAL(claimName, name);
BOOST_CHECK_EQUAL(claimValue.claimId, claimId);
// make second claim with activation delay 1
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), name, "one", 2);
uint160 claimId2 = ClaimIdHash(tx2.GetHash(), 0);
fixture.IncrementBlocks(1);
// second claim is not activated yet, but can still access by claim id
BOOST_CHECK(fixture.is_best_claim(name, tx1));
BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue));
BOOST_CHECK_EQUAL(claimName, name);
BOOST_CHECK_EQUAL(claimValue.claimId, claimId2);
fixture.IncrementBlocks(1);
// second claim has activated
BOOST_CHECK(fixture.is_best_claim(name, tx2));
BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue));
BOOST_CHECK_EQUAL(claimName, name);
BOOST_CHECK_EQUAL(claimValue.claimId, claimId2);
fixture.DecrementBlocks(1);
// second claim has been deactivated via decrement
// should still be accesible via claim id
BOOST_CHECK(fixture.is_best_claim(name, tx1));
BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue));
BOOST_CHECK_EQUAL(claimName, name);
BOOST_CHECK_EQUAL(claimValue.claimId, claimId2);
fixture.IncrementBlocks(1);
// second claim should have been re activated via increment
BOOST_CHECK(fixture.is_best_claim(name, tx2));
BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue));
BOOST_CHECK_EQUAL(claimName, name);
BOOST_CHECK_EQUAL(claimValue.claimId, claimId2);
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -0,0 +1,409 @@
// Copyright (c) 2015-2019 The LBRY Foundation
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#include <functional>
#include <test/claimtriefixture.h>
using namespace std;
CMutableTransaction BuildTransaction(const CTransaction& prev, uint32_t prevout, unsigned int numOutputs, int locktime)
{
CMutableTransaction tx;
tx.nVersion = CTransaction::CURRENT_VERSION;
tx.vin.resize(1);
tx.vout.resize(numOutputs);
tx.vin[0].prevout.hash = prev.GetHash();
tx.vin[0].prevout.n = prevout;
tx.vin[0].scriptSig = CScript();
if (locktime != 0) {
// Use a relative locktime for validity X blocks in the future
tx.nLockTime = chainActive.Height() + locktime;
tx.vin[0].nSequence = 0xffffffff - 1;
} else {
tx.nLockTime = 1 << 31; // Disable BIP68
tx.vin[0].nSequence = std::numeric_limits<unsigned int>::max();
}
CAmount valuePerOutput = prev.vout[prevout].nValue;
unsigned int numOutputsCopy = numOutputs;
while ((numOutputsCopy = numOutputsCopy >> 1) > 0)
valuePerOutput = valuePerOutput >> 1;
for (unsigned int i = 0; i < numOutputs; ++i) {
tx.vout[i].scriptPubKey = CScript();
tx.vout[i].nValue = valuePerOutput;
}
return tx;
}
CMutableTransaction BuildTransaction(const uint256& prevhash)
{
CMutableTransaction tx;
tx.nVersion = 1;
tx.nLockTime = 0;
tx.vin.resize(1);
tx.vout.resize(1);
tx.vin[0].prevout.hash = prevhash;
tx.vin[0].prevout.n = 0;
tx.vin[0].scriptSig = CScript();
tx.vin[0].nSequence = std::numeric_limits<unsigned int>::max();
tx.vout[0].scriptPubKey = CScript();
tx.vout[0].nValue = 0;
return tx;
}
BlockAssembler AssemblerForTest()
{
BlockAssembler::Options options;
options.nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
options.blockMinFeeRate = CFeeRate(0);
return BlockAssembler(Params(), options);
}
ClaimTrieChainFixture::ClaimTrieChainFixture() : CClaimTrieCache(pclaimTrie),
unique_block_counter(0), normalization_original(-1), expirationForkHeight(-1), forkhash_original(-1)
{
fRequireStandard = false;
BOOST_CHECK_EQUAL(nNextHeight, chainActive.Height() + 1);
setNormalizationForkHeight(1000000);
gArgs.ForceSetArg("-limitancestorcount", "1000000");
gArgs.ForceSetArg("-limitancestorsize", "1000000");
gArgs.ForceSetArg("-limitdescendantcount", "1000000");
gArgs.ForceSetArg("-limitdescendantsize", "1000000");
num_txs_for_next_block = 0;
coinbase_txs_used = 0;
unique_block_counter = 0;
added_unchecked = false;
// generate coinbases to spend
CreateCoinbases(40, coinbase_txs);
}
ClaimTrieChainFixture::~ClaimTrieChainFixture()
{
added_unchecked = false;
DecrementBlocks(chainActive.Height());
auto& consensus = const_cast<Consensus::Params&>(Params().GetConsensus());
if (normalization_original >= 0)
consensus.nNormalizedNameForkHeight = normalization_original;
if (expirationForkHeight >= 0) {
consensus.nExtendedClaimExpirationForkHeight = expirationForkHeight;
consensus.nExtendedClaimExpirationTime = extendedExpiration;
consensus.nOriginalClaimExpirationTime = originalExpiration;
}
if (forkhash_original >= 0)
consensus.nAllClaimsInMerkleForkHeight = forkhash_original;
}
void ClaimTrieChainFixture::setExpirationForkHeight(int targetMinusCurrent, int64_t preForkExpirationTime, int64_t postForkExpirationTime)
{
int target = chainActive.Height() + targetMinusCurrent;
auto& consensus = const_cast<Consensus::Params&>(Params().GetConsensus());
if (expirationForkHeight < 0) {
expirationForkHeight = consensus.nExtendedClaimExpirationForkHeight;
originalExpiration = consensus.nOriginalClaimExpirationTime;
extendedExpiration = consensus.nExtendedClaimExpirationTime;
}
consensus.nExtendedClaimExpirationForkHeight = target;
consensus.nExtendedClaimExpirationTime = postForkExpirationTime;
consensus.nOriginalClaimExpirationTime = preForkExpirationTime;
setExpirationTime(targetMinusCurrent >= 0 ? preForkExpirationTime : postForkExpirationTime);
}
void ClaimTrieChainFixture::setNormalizationForkHeight(int targetMinusCurrent)
{
int target = chainActive.Height() + targetMinusCurrent;
auto& consensus = const_cast<Consensus::Params&>(Params().GetConsensus());
if (normalization_original < 0)
normalization_original = consensus.nNormalizedNameForkHeight;
consensus.nNormalizedNameForkHeight = target;
}
void ClaimTrieChainFixture::setHashForkHeight(int targetMinusCurrent)
{
int target = chainActive.Height() + targetMinusCurrent;
auto& consensus = const_cast<Consensus::Params&>(Params().GetConsensus());
if (forkhash_original < 0)
forkhash_original = consensus.nAllClaimsInMerkleForkHeight;
consensus.nAllClaimsInMerkleForkHeight = target;
}
bool ClaimTrieChainFixture::CreateBlock(const std::unique_ptr<CBlockTemplate>& pblocktemplate)
{
CBlock* pblock = &pblocktemplate->block;
{
LOCK(cs_main);
pblock->nVersion = 5;
pblock->hashPrevBlock = chainActive.Tip()->GetBlockHash();
pblock->nTime = chainActive.Tip()->GetBlockTime() + Params().GetConsensus().nPowTargetSpacing;
CMutableTransaction txCoinbase(*pblock->vtx[0]);
txCoinbase.vin[0].scriptSig = CScript() << int(chainActive.Height() + 1) << int(++unique_block_counter);
txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height() + 1, Params().GetConsensus());
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
for (uint32_t i = 0;; ++i) {
pblock->nNonce = i;
if (CheckProofOfWork(pblock->GetPoWHash(), pblock->nBits, Params().GetConsensus()))
break;
}
}
auto success = ProcessNewBlock(Params(), std::make_shared<const CBlock>(*pblock), true, nullptr);
return success && pblock->GetHash() == chainActive.Tip()->GetBlockHash();
}
bool ClaimTrieChainFixture::CreateCoinbases(unsigned int num_coinbases, std::vector<CTransaction>& coinbases)
{
std::unique_ptr<CBlockTemplate> pblocktemplate;
coinbases.clear();
BOOST_CHECK(pblocktemplate = AssemblerForTest().CreateNewBlock(CScript() << OP_TRUE));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1);
for (unsigned int i = 0; i < 100 + num_coinbases; ++i) {
BOOST_CHECK(CreateBlock(pblocktemplate));
if (coinbases.size() < num_coinbases)
coinbases.push_back(std::move(*pblocktemplate->block.vtx[0]));
}
return true;
}
void ClaimTrieChainFixture::CommitTx(const CMutableTransaction &tx, bool has_locktime)
{
num_txs_for_next_block++;
if (has_locktime) {
added_unchecked = true;
TestMemPoolEntryHelper entry;
LOCK(mempool.cs);
mempool.addUnchecked(tx.GetHash(), entry.Fee(0).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
} else {
CValidationState state;
CAmount txFeeRate = CAmount(0);
LOCK(cs_main);
BOOST_CHECK_EQUAL(AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), nullptr, nullptr, false, txFeeRate, false), true);
}
}
// spend a bid into some non claimtrie related unspent
CMutableTransaction ClaimTrieChainFixture::Spend(const CTransaction &prev)
{
CMutableTransaction tx = BuildTransaction(prev, 0);
tx.vout[0].scriptPubKey = CScript() << OP_TRUE;
tx.vout[0].nValue = prev.vout[0].nValue;
CommitTx(tx);
return tx;
}
// make claim at the current block
CMutableTransaction ClaimTrieChainFixture::MakeClaim(const CTransaction& prev, const std::string& name, const std::string& value, CAmount quantity, int locktime)
{
uint32_t prevout = prev.vout.size() - 1;
while (prevout > 0 && prev.vout[prevout].nValue < quantity)
--prevout;
CMutableTransaction tx = BuildTransaction(prev, prevout, prev.vout[prevout].nValue > quantity ? 2 : 1, locktime);
tx.vout[0].scriptPubKey = ClaimNameScript(name, value);
tx.vout[0].nValue = quantity;
if (tx.vout.size() > 1) {
tx.vout[1].scriptPubKey = CScript() << OP_TRUE;
tx.vout[1].nValue = prev.vout[prevout].nValue - quantity;
}
CommitTx(tx, locktime != 0);
return tx;
}
CMutableTransaction ClaimTrieChainFixture::MakeClaim(const CTransaction& prev, const std::string& name, const std::string& value)
{
return MakeClaim(prev, name, value, prev.vout[0].nValue, 0);
}
// make support at the current block
CMutableTransaction ClaimTrieChainFixture::MakeSupport(const CTransaction &prev, const CTransaction &claimtx, const std::string& name, CAmount quantity)
{
uint32_t prevout = prev.vout.size() - 1;
while (prevout > 0 && prev.vout[prevout].nValue < quantity)
--prevout;
CMutableTransaction tx = BuildTransaction(prev, prevout, prev.vout[prevout].nValue > quantity ? 2 : 1);
tx.vout[0].scriptPubKey = SupportClaimScript(name, ClaimIdHash(claimtx.GetHash(), 0));
tx.vout[0].nValue = quantity;
if (tx.vout.size() > 1) {
tx.vout[1].scriptPubKey = CScript() << OP_TRUE;
tx.vout[1].nValue = prev.vout[prevout].nValue - quantity;
}
CommitTx(tx);
return tx;
}
// make update at the current block
CMutableTransaction ClaimTrieChainFixture::MakeUpdate(const CTransaction &prev, const std::string& name, const std::string& value, const uint160& claimId, CAmount quantity)
{
CMutableTransaction tx = BuildTransaction(prev, 0);
tx.vout[0].scriptPubKey = UpdateClaimScript(name, claimId, value);
tx.vout[0].nValue = quantity;
CommitTx(tx);
return tx;
}
CTransaction ClaimTrieChainFixture::GetCoinbase()
{
return coinbase_txs.at(coinbase_txs_used++);
}
// create i blocks
void ClaimTrieChainFixture::IncrementBlocks(int num_blocks, bool mark)
{
if (mark)
marks.push_back(chainActive.Height());
clear(); // clears the internal cache
for (int i = 0; i < num_blocks; ++i) {
CScript coinbase_scriptpubkey;
coinbase_scriptpubkey << CScriptNum(chainActive.Height());
std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest().CreateNewBlock(coinbase_scriptpubkey);
BOOST_CHECK(pblocktemplate != nullptr);
if (!added_unchecked)
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), num_txs_for_next_block + 1);
BOOST_CHECK_EQUAL(CreateBlock(pblocktemplate), true);
num_txs_for_next_block = 0;
nNextHeight = chainActive.Height() + 1;
}
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight - 1));
}
// disconnect i blocks from tip
void ClaimTrieChainFixture::DecrementBlocks(int num_blocks)
{
clear(); // clears the internal cache
CValidationState state;
{
LOCK(cs_main);
CBlockIndex* pblockindex = chainActive[chainActive.Height() - num_blocks + 1];
BOOST_CHECK_EQUAL(InvalidateBlock(state, Params(), pblockindex), true);
}
BOOST_CHECK_EQUAL(state.IsValid(), true);
BOOST_CHECK_EQUAL(ActivateBestChain(state, Params()), true);
mempool.clear();
num_txs_for_next_block = 0;
nNextHeight = chainActive.Height() + 1;
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight - 1));
}
// decrement back to last mark
void ClaimTrieChainFixture::DecrementBlocks()
{
int mark = marks.back();
marks.pop_back();
DecrementBlocks(chainActive.Height() - mark);
}
template <typename K>
bool ClaimTrieChainFixture::keyTypeEmpty(uint8_t keyType)
{
boost::scoped_ptr<CDBIterator> pcursor(base->db->NewIterator());
pcursor->SeekToFirst();
while (pcursor->Valid()) {
std::pair<uint8_t, K> key;
if (pcursor->GetKey(key))
if (key.first == keyType)
return false;
pcursor->Next();
}
return true;
}
bool ClaimTrieChainFixture::queueEmpty()
{
for (const auto& claimQueue: claimQueueCache)
if (!claimQueue.second.empty())
return false;
return keyTypeEmpty<int>(CLAIM_QUEUE_ROW);
}
bool ClaimTrieChainFixture::expirationQueueEmpty()
{
for (const auto& expirationQueue: expirationQueueCache)
if (!expirationQueue.second.empty())
return false;
return keyTypeEmpty<int>(CLAIM_EXP_QUEUE_ROW);
}
bool ClaimTrieChainFixture::supportEmpty()
{
for (const auto& entry: supportCache)
if (!entry.second.empty())
return false;
return supportCache.empty() && keyTypeEmpty<std::string>(SUPPORT);
}
bool ClaimTrieChainFixture::supportQueueEmpty()
{
for (const auto& support: supportQueueCache)
if (!support.second.empty())
return false;
return keyTypeEmpty<int>(SUPPORT_QUEUE_ROW);
}
int ClaimTrieChainFixture::proportionalDelayFactor()
{
return base->nProportionalDelayFactor;
}
boost::test_tools::predicate_result negativeResult(const std::function<void(boost::wrap_stringstream&)>& callback)
{
boost::test_tools::predicate_result res(false);
callback(res.message());
return res;
}
boost::test_tools::predicate_result negativeResult(const std::string& message)
{
return negativeResult([&message](boost::wrap_stringstream& stream) {
stream << message;
});
}
// is a claim in queue
boost::test_tools::predicate_result ClaimTrieChainFixture::is_claim_in_queue(const std::string& name, const CTransaction &tx)
{
COutPoint outPoint(tx.GetHash(), 0);
int validAtHeight;
if (haveClaimInQueue(name, outPoint, validAtHeight))
return true;
return negativeResult("Is not a claim in queue");
}
// check if tx is best claim based on outpoint
boost::test_tools::predicate_result ClaimTrieChainFixture::is_best_claim(const std::string& name, const CTransaction &tx)
{
CClaimValue val;
COutPoint outPoint(tx.GetHash(), 0);
bool have_claim = haveClaim(name, outPoint);
bool have_info = getInfoForName(name, val);
if (have_claim && have_info && val.outPoint == outPoint)
return true;
return negativeResult("Is not best claim");
}
// check effective quantity of best claim
boost::test_tools::predicate_result ClaimTrieChainFixture::best_claim_effective_amount_equals(const std::string& name, CAmount amount)
{
CClaimValue val;
bool have_info = getInfoForName(name, val);
if (!have_info)
return negativeResult("No claim found");
CAmount effective_amount = getClaimsForName(name).find(val.claimId).effectiveAmount;
if (effective_amount != amount)
return negativeResult([amount, effective_amount](boost::wrap_stringstream& stream) {
stream << amount << " != " << effective_amount;
});
return true;
}
std::size_t ClaimTrieChainFixture::getTotalNamesInTrie() const
{
return base->getTotalNamesInTrie();
}

124
src/test/claimtriefixture.h Normal file
View file

@ -0,0 +1,124 @@
// Copyright (c) 2015-2019 The LBRY Foundation
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#ifndef _CLAIMTRIEFIXTURE_H_
#define _CLAIMTRIEFIXTURE_H_
#include <chainparams.h>
#include <claimtrie.h>
#include <coins.h>
#include <consensus/merkle.h>
#include <consensus/validation.h>
#include <miner.h>
#include <nameclaim.h>
#include <policy/policy.h>
#include <pow.h>
#include <primitives/transaction.h>
#include <random.h>
#include <rpc/claimrpchelp.h>
#include <rpc/server.h>
#include <streams.h>
#include <test/test_bitcoin.h>
#include <txmempool.h>
#include <validation.h>
#include <boost/test/unit_test.hpp>
#include <iostream>
extern ::CChainState g_chainstate;
extern ::ArgsManager gArgs;
extern std::vector<std::string> random_strings(std::size_t count);
extern bool getClaimById(const uint160&, std::string&, CClaimValue*);
CMutableTransaction BuildTransaction(const uint256& prevhash);
CMutableTransaction BuildTransaction(const CTransaction& prev, uint32_t prevout=0, unsigned int numOutputs=1, int locktime=0);
BlockAssembler AssemblerForTest();
// Test Fixtures
struct ClaimTrieChainFixture: public CClaimTrieCache
{
std::vector<CTransaction> coinbase_txs;
std::vector<int> marks;
int coinbase_txs_used;
int unique_block_counter;
int normalization_original;
unsigned int num_txs_for_next_block;
bool added_unchecked;
int64_t expirationForkHeight;
int64_t originalExpiration;
int64_t extendedExpiration;
int64_t forkhash_original;
using CClaimTrieCache::getSupportsForName;
ClaimTrieChainFixture();
~ClaimTrieChainFixture();
void setExpirationForkHeight(int targetMinusCurrent, int64_t preForkExpirationTime, int64_t postForkExpirationTime);
void setNormalizationForkHeight(int targetMinusCurrent);
void setHashForkHeight(int targetMinusCurrent);
bool CreateBlock(const std::unique_ptr<CBlockTemplate>& pblocktemplate);
bool CreateCoinbases(unsigned int num_coinbases, std::vector<CTransaction>& coinbases);
void CommitTx(const CMutableTransaction &tx, bool has_locktime=false);
// spend a bid into some non claimtrie related unspent
CMutableTransaction Spend(const CTransaction &prev);
// make claim at the current block
CMutableTransaction MakeClaim(const CTransaction& prev, const std::string& name, const std::string& value, CAmount quantity, int locktime=0);
CMutableTransaction MakeClaim(const CTransaction& prev, const std::string& name, const std::string& value);
// make support at the current block
CMutableTransaction MakeSupport(const CTransaction &prev, const CTransaction &claimtx, const std::string& name, CAmount quantity);
// make update at the current block
CMutableTransaction MakeUpdate(const CTransaction &prev, const std::string& name, const std::string& value, const uint160& claimId, CAmount quantity);
CTransaction GetCoinbase();
// create i blocks
void IncrementBlocks(int num_blocks, bool mark = false);
// disconnect i blocks from tip
void DecrementBlocks(int num_blocks);
// decrement back to last mark
void DecrementBlocks();
bool queueEmpty();
bool expirationQueueEmpty();
bool supportEmpty();
bool supportQueueEmpty();
int proportionalDelayFactor();
// is a claim in queue
boost::test_tools::predicate_result is_claim_in_queue(const std::string& name, const CTransaction &tx);
// check if tx is best claim based on outpoint
boost::test_tools::predicate_result is_best_claim(const std::string& name, const CTransaction &tx);
// check effective quantity of best claim
boost::test_tools::predicate_result best_claim_effective_amount_equals(const std::string& name, CAmount amount);
std::size_t getTotalNamesInTrie() const;
private:
template <typename K>
bool keyTypeEmpty(uint8_t keyType);
};
#endif // _CLAIMTRIEFIXTURE_H_

View file

@ -0,0 +1,390 @@
// Copyright (c) 2015-2019 The LBRY Foundation
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#include <test/claimtriefixture.h>
using namespace std;
void ValidatePairs(CClaimTrieCache& cache, const std::vector<std::pair<bool, uint256>>& pairs, uint256 claimHash)
{
for (auto& pair : pairs)
if (pair.first) // we're on the right because we were an odd index number
claimHash = Hash(pair.second.begin(), pair.second.end(), claimHash.begin(), claimHash.end());
else
claimHash = Hash(claimHash.begin(), claimHash.end(), pair.second.begin(), pair.second.end());
BOOST_CHECK_EQUAL(cache.getMerkleHash(), claimHash);
}
BOOST_FIXTURE_TEST_SUITE(claimtriehashfork_tests, RegTestingSetup)
BOOST_AUTO_TEST_CASE(hash_includes_all_claims_rollback_test)
{
ClaimTrieChainFixture fixture;
fixture.setHashForkHeight(5);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1);
fixture.IncrementBlocks(1);
uint256 currentRoot = fixture.getMerkleHash();
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(currentRoot, fixture.getMerkleHash());
fixture.IncrementBlocks(3);
BOOST_CHECK_NE(currentRoot, fixture.getMerkleHash());
fixture.DecrementBlocks(3);
BOOST_CHECK_EQUAL(currentRoot, fixture.getMerkleHash());
}
BOOST_AUTO_TEST_CASE(hash_includes_all_claims_single_test)
{
ClaimTrieChainFixture fixture;
fixture.setHashForkHeight(2);
fixture.IncrementBlocks(4);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1);
fixture.IncrementBlocks(1);
COutPoint outPoint(tx1.GetHash(), 0);
uint160 claimId = ClaimIdHash(tx1.GetHash(), 0);
CClaimTrieProof proof;
BOOST_CHECK(fixture.getProofForName("test", proof, [&claimId](const CClaimValue& claim) {
return claim.claimId == claimId;
}));
BOOST_CHECK(proof.hasValue);
BOOST_CHECK_EQUAL(proof.outPoint, outPoint);
auto claimHash = getValueHash(outPoint, proof.nHeightOfLastTakeover);
ValidatePairs(fixture, proof.pairs, claimHash);
}
BOOST_AUTO_TEST_CASE(hash_includes_all_claims_triple_test)
{
ClaimTrieChainFixture fixture;
fixture.setHashForkHeight(2);
fixture.IncrementBlocks(4);
std::string names[] = {"test", "tester", "tester2"};
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "one", 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "two", 2);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "thr", 3);
CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "for", 4);
CMutableTransaction tx8 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "fiv", 5);
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), names[1], "two", 2);
CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), names[1], "thr", 3);
CMutableTransaction tx6 = fixture.MakeClaim(fixture.GetCoinbase(), names[2], "one", 1);
fixture.IncrementBlocks(1);
for (const auto& name : names) {
for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) {
CClaimTrieProof proof;
auto& claim = claimSupports.claim;
BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) {
return claim.claimId == value.claimId;
}));
BOOST_CHECK(proof.hasValue);
BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint);
uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover);
ValidatePairs(fixture, proof.pairs, claimHash);
}
}
}
BOOST_AUTO_TEST_CASE(hash_includes_all_claims_branched_test)
{
ClaimTrieChainFixture fixture;
fixture.setHashForkHeight(2);
fixture.IncrementBlocks(4);
std::string names[] = {"test", "toast", "tot", "top", "toa", "toad"};
for (const auto& name : names)
fixture.MakeClaim(fixture.GetCoinbase(), name, "one", 1);
fixture.MakeClaim(fixture.GetCoinbase(), "toa", "two", 2);
fixture.MakeClaim(fixture.GetCoinbase(), "toa", "tre", 3);
fixture.MakeClaim(fixture.GetCoinbase(), "toa", "qua", 4);
fixture.MakeClaim(fixture.GetCoinbase(), "toa", "cin", 5);
fixture.IncrementBlocks(1);
for (const auto& name : names) {
for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) {
CClaimTrieProof proof;
auto& claim = claimSupports.claim;
BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) {
return claim.claimId == value.claimId;
}));
BOOST_CHECK(proof.hasValue);
BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint);
uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover);
ValidatePairs(fixture, proof.pairs, claimHash);
}
}
}
BOOST_AUTO_TEST_CASE(hash_claims_children_fuzzer_test)
{
ClaimTrieChainFixture fixture;
fixture.setHashForkHeight(2);
fixture.IncrementBlocks(4);
std::size_t i = 0;
auto names = random_strings(300);
auto lastTx = MakeTransactionRef(fixture.GetCoinbase());
for (const auto& name : names) {
auto tx = fixture.MakeClaim(*lastTx, name, "one", 1);
lastTx = MakeTransactionRef(std::move(tx));
if (++i % 5 == 0)
for (std::size_t j = 0; j < (i / 5); ++j) {
auto tx = fixture.MakeClaim(*lastTx, name, "one", 1);
lastTx = MakeTransactionRef(std::move(tx));
}
fixture.IncrementBlocks(1);
}
for (const auto& name : names) {
for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) {
CClaimTrieProof proof;
auto& claim = claimSupports.claim;
BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) {
return claim.claimId == value.claimId;
}));
BOOST_CHECK(proof.hasValue);
BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint);
uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover);
ValidatePairs(fixture, proof.pairs, claimHash);
}
}
}
bool verify_proof(const CClaimTrieProof proof, uint256 rootHash, const std::string& name)
{
uint256 previousComputedHash;
std::string computedReverseName;
bool verifiedValue = false;
for (auto itNodes = proof.nodes.rbegin(); itNodes != proof.nodes.rend(); ++itNodes) {
bool foundChildInChain = false;
std::vector<unsigned char> vchToHash;
for (auto itChildren = itNodes->children.begin(); itChildren != itNodes->children.end(); ++itChildren) {
vchToHash.push_back(itChildren->first);
uint256 childHash;
if (itChildren->second.IsNull()) {
if (previousComputedHash.IsNull()) {
return false;
}
if (foundChildInChain) {
return false;
}
foundChildInChain = true;
computedReverseName += itChildren->first;
childHash = previousComputedHash;
} else {
childHash = itChildren->second;
}
vchToHash.insert(vchToHash.end(), childHash.begin(), childHash.end());
}
if (itNodes != proof.nodes.rbegin() && !foundChildInChain) {
return false;
}
if (itNodes->hasValue) {
uint256 valHash;
if (itNodes->valHash.IsNull()) {
if (itNodes != proof.nodes.rbegin()) {
return false;
}
if (!proof.hasValue) {
return false;
}
valHash = getValueHash(proof.outPoint,
proof.nHeightOfLastTakeover);
verifiedValue = true;
} else {
valHash = itNodes->valHash;
}
vchToHash.insert(vchToHash.end(), valHash.begin(), valHash.end());
} else if (proof.hasValue && itNodes == proof.nodes.rbegin()) {
return false;
}
CHash256 hasher;
std::vector<unsigned char> vchHash(hasher.OUTPUT_SIZE);
hasher.Write(vchToHash.data(), vchToHash.size());
hasher.Finalize(&(vchHash[0]));
uint256 calculatedHash(vchHash);
previousComputedHash = calculatedHash;
}
if (previousComputedHash != rootHash) {
return false;
}
if (proof.hasValue && !verifiedValue) {
return false;
}
std::string::reverse_iterator itComputedName = computedReverseName.rbegin();
std::string::const_iterator itName = name.begin();
for (; itName != name.end() && itComputedName != computedReverseName.rend(); ++itName, ++itComputedName) {
if (*itName != *itComputedName) {
return false;
}
}
return (!proof.hasValue || itName == name.end());
}
BOOST_AUTO_TEST_CASE(value_proof_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("a");
std::string sValue1("testa");
std::string sName2("abc");
std::string sValue2("testabc");
std::string sName3("abd");
std::string sValue3("testabd");
std::string sName4("zyx");
std::string sValue4("testzyx");
std::string sName5("zyxa");
std::string sName6("omg");
std::string sName7("");
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1);
COutPoint tx1OutPoint(tx1.GetHash(), 0);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName2, sValue2);
COutPoint tx2OutPoint(tx2.GetHash(), 0);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), sName3, sValue3);
COutPoint tx3OutPoint(tx3.GetHash(), 0);
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), sName4, sValue4);
COutPoint tx4OutPoint(tx4.GetHash(), 0);
CClaimValue val;
// create a claim. verify the expiration event has been scheduled.
fixture.IncrementBlocks(5, true);
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName1, val));
BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint);
BOOST_CHECK(fixture.getInfoForName(sName2, val));
BOOST_CHECK_EQUAL(val.outPoint, tx2OutPoint);
BOOST_CHECK(fixture.getInfoForName(sName3, val));
BOOST_CHECK_EQUAL(val.outPoint, tx3OutPoint);
BOOST_CHECK(fixture.getInfoForName(sName4, val));
BOOST_CHECK_EQUAL(val.outPoint, tx4OutPoint);
CClaimTrieProof proof;
BOOST_CHECK(fixture.getProofForName(sName1, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName1));
BOOST_CHECK_EQUAL(proof.outPoint, tx1OutPoint);
BOOST_CHECK(fixture.getProofForName(sName2, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName2));
BOOST_CHECK_EQUAL(proof.outPoint, tx2OutPoint);
BOOST_CHECK(fixture.getProofForName(sName3, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName3));
BOOST_CHECK_EQUAL(proof.outPoint, tx3OutPoint);
BOOST_CHECK(fixture.getProofForName(sName4, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName4));
BOOST_CHECK_EQUAL(proof.outPoint, tx4OutPoint);
BOOST_CHECK(fixture.getProofForName(sName5, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName5));
BOOST_CHECK_EQUAL(proof.hasValue, false);
BOOST_CHECK(fixture.getProofForName(sName6, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName6));
BOOST_CHECK_EQUAL(proof.hasValue, false);
BOOST_CHECK(fixture.getProofForName(sName7, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName7));
BOOST_CHECK_EQUAL(proof.hasValue, false);
CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), sName7, sValue4);
COutPoint tx5OutPoint(tx5.GetHash(), 0);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.getInfoForName(sName7, val));
BOOST_CHECK_EQUAL(val.outPoint, tx5OutPoint);
BOOST_CHECK(fixture.getProofForName(sName1, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName1));
BOOST_CHECK_EQUAL(proof.outPoint, tx1OutPoint);
BOOST_CHECK(fixture.getProofForName(sName2, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName2));
BOOST_CHECK_EQUAL(proof.outPoint, tx2OutPoint);
BOOST_CHECK(fixture.getProofForName(sName3, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName3));
BOOST_CHECK_EQUAL(proof.outPoint, tx3OutPoint);
BOOST_CHECK(fixture.getProofForName(sName4, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName4));
BOOST_CHECK_EQUAL(proof.outPoint, tx4OutPoint);
BOOST_CHECK(fixture.getProofForName(sName5, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName5));
BOOST_CHECK_EQUAL(proof.hasValue, false);
BOOST_CHECK(fixture.getProofForName(sName6, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName6));
BOOST_CHECK_EQUAL(proof.hasValue, false);
BOOST_CHECK(fixture.getProofForName(sName7, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName7));
BOOST_CHECK_EQUAL(proof.outPoint, tx5OutPoint);
fixture.DecrementBlocks();
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
}
// Check that blocks with bogus calimtrie hash is rejected
BOOST_AUTO_TEST_CASE(bogus_claimtrie_hash_test)
{
ClaimTrieChainFixture fixture;
std::string sName("test");
std::string sValue1("test");
int orig_chain_height = chainActive.Height();
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue1, 1);
std::unique_ptr<CBlockTemplate> pblockTemp;
BOOST_CHECK(pblockTemp = AssemblerForTest().CreateNewBlock(tx1.vout[0].scriptPubKey));
pblockTemp->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
pblockTemp->block.nVersion = 5;
pblockTemp->block.nTime = chainActive.Tip()->GetBlockTime() + Params().GetConsensus().nPowTargetSpacing;
CMutableTransaction txCoinbase(*pblockTemp->block.vtx[0]);
txCoinbase.vin[0].scriptSig = CScript() << int(chainActive.Height() + 1) << 1;
txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height() + 1, Params().GetConsensus());
pblockTemp->block.vtx[0] = MakeTransactionRef(std::move(txCoinbase));
pblockTemp->block.hashMerkleRoot = BlockMerkleRoot(pblockTemp->block);
//create bogus hash
uint256 bogusHashClaimTrie;
bogusHashClaimTrie.SetHex("aaa");
pblockTemp->block.hashClaimTrie = bogusHashClaimTrie;
for (uint32_t i = 0;; ++i) {
pblockTemp->block.nNonce = i;
if (CheckProofOfWork(pblockTemp->block.GetPoWHash(), pblockTemp->block.nBits, Params().GetConsensus())) {
break;
}
}
bool success = ProcessNewBlock(Params(), std::make_shared<const CBlock>(pblockTemp->block), true, nullptr);
// will process , but will not be connected
BOOST_CHECK(success);
BOOST_CHECK(pblockTemp->block.GetHash() != chainActive.Tip()->GetBlockHash());
BOOST_CHECK_EQUAL(orig_chain_height, chainActive.Height());
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -0,0 +1,495 @@
// Copyright (c) 2015-2019 The LBRY Foundation
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#include <test/claimtriefixture.h>
using namespace std;
BOOST_FIXTURE_TEST_SUITE(claimtrienormalization_tests, RegTestingSetup)
/*
normalization
test normalization function indpendent from rest of the code
*/
BOOST_AUTO_TEST_CASE(normalization_only)
{
CClaimTrieCache ccache(pclaimTrie);
// basic ASCII casing tests
BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("TESt", true));
BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("tesT", true));
BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("TesT", true));
BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("test", true));
BOOST_CHECK_EQUAL("test this", ccache.normalizeClaimName("Test This", true));
// test invalid utf8 bytes are returned as is
BOOST_CHECK_EQUAL("\xFF", ccache.normalizeClaimName("\xFF", true));
BOOST_CHECK_EQUAL("\xC3\x28", ccache.normalizeClaimName("\xC3\x28", true));
// ohm sign unicode code point \x2126 should be transformed to equivalent
// unicode code point \x03C9 , greek small letter omega
BOOST_CHECK_EQUAL("\xCF\x89", ccache.normalizeClaimName("\xE2\x84\xA6", true));
// cyrillic capital ef code point \x0424 should be transformed to lower case
// \x0444
BOOST_CHECK_EQUAL("\xD1\x84", ccache.normalizeClaimName("\xD0\xA4", true));
// armenian capital ben code point \x0532 should be transformed to lower case
// \x0562
BOOST_CHECK_EQUAL("\xD5\xA2", ccache.normalizeClaimName("\xD4\xB2", true));
// japanese pbu code point \x3076 should be transformed by NFD decomposition
// into \x3075 and \x3099
BOOST_CHECK_EQUAL("\xE3\x81\xB5\xE3\x82\x99",
ccache.normalizeClaimName("\xE3\x81\xB6", true));
// hangul ggwalg unicode code point \xAF51 should be transformed by NFD
// decomposition into unicode code points \x1101 \x116A \x11B0
// source: http://unicode.org/L2/L2009/09052-tr47.html
BOOST_CHECK_EQUAL("\xE1\x84\x81\xE1\x85\xAA\xE1\x86\xB0",
ccache.normalizeClaimName("\xEA\xBD\x91", true));
}
/*
normalization
check claim name normalization before the fork
check claim name normalization after the fork
*/
BOOST_AUTO_TEST_CASE(claimtriebranching_normalization)
{
ClaimTrieChainFixture fixture;
// check claim names are not normalized
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "normalizeTest", "one", 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.getTotalNamesInTrie() == 0);
fixture.CommitTx(tx1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1));
CMutableTransaction tx2a = fixture.MakeClaim(fixture.GetCoinbase(), "Normalizetest", "one_a", 2);
CMutableTransaction tx2 = fixture.MakeUpdate(tx2a, "Normalizetest", "one", ClaimIdHash(tx2a.GetHash(), 0), 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1));
BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2));
// Activate the fork (which rebuilds the existing claimtrie and
// cache), flattening all previously existing name clashes due to
// the normalization
fixture.setNormalizationForkHeight(2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1));
BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2));
fixture.IncrementBlocks(1, true);
// Post-fork, tx1 (the previous winning claim) assumes all name
// variants of what it originally was ...
BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("normalizetest", 3));
CClaimTrieData data;
BOOST_CHECK(!pclaimTrie->find("normalizeTest", data));
// Check equivalence of normalized claim names
BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // collapsed tx2
fixture.IncrementBlocks(1);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "NORMALIZETEST", "one", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.is_best_claim("normalizetest", tx3));
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "NoRmAlIzEtEsT", 2);
fixture.IncrementBlocks(1);
// Ensure that supports work for normalized claim names
BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // effective amount is 5
BOOST_CHECK(fixture.best_claim_effective_amount_equals("normalizetest", 5));
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "foo", "bar", 1);
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(), tx4, "Foo", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("foo", tx4));
CMutableTransaction u1 = fixture.MakeUpdate(tx4, "foo", "baz", ClaimIdHash(tx4.GetHash(), 0), 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("foo", u1));
CMutableTransaction u2 = fixture.MakeUpdate(tx1, "nOrmalIzEtEst", "two", ClaimIdHash(tx1.GetHash(), 0), 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("normalizetest", u2));
// Add another set of unicode claims that will collapse after the fork
CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "Ame\u0301lie", "amelie", 2);
fixture.IncrementBlocks(1);
CClaimValue nval1;
fixture.getInfoForName("amélie", nval1);
BOOST_CHECK(nval1.claimId == ClaimIdHash(tx5.GetHash(), 0));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("amélie", 2));
// Check equivalence of normalized claim names
BOOST_CHECK(fixture.is_best_claim("amélie", tx5));
CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), "あてはまる", "jn1", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("あてはまる", tx7));
CMutableTransaction tx8 = fixture.MakeClaim(fixture.GetCoinbase(), "AÑEJO", "es1", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("añejo", tx8));
// Rewind to 1 block before the fork and be sure that the fork is no longer active
fixture.DecrementBlocks();
// Now check that our old (non-normalized) claims are 'alive' again
BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1));
BOOST_CHECK(!fixture.is_best_claim("Normalizetest", tx1)); // no longer equivalent
BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2));
// Create new claim
CMutableTransaction tx9 = fixture.MakeClaim(fixture.GetCoinbase(), "blah", "blah", 1);
std::string invalidUtf8("\xFF\xFF");
CMutableTransaction tx10 = fixture.MakeClaim(fixture.GetCoinbase(), invalidUtf8, "blah", 1); // invalid UTF8
// Roll forward to fork height again and check again that we're normalized
fixture.IncrementBlocks(1);
BOOST_CHECK(chainActive.Height() == Params().GetConsensus().nNormalizedNameForkHeight);
BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // collapsed tx2
BOOST_CHECK(fixture.is_best_claim(invalidUtf8, tx10));
// Rewind to 1 block before the fork and be sure that the fork is
// no longer active
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2));
// Roll forward to fork height again and check again that we're normalized
fixture.IncrementBlocks(1);
BOOST_CHECK(chainActive.Height() == Params().GetConsensus().nNormalizedNameForkHeight);
BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // collapsed tx2
}
BOOST_AUTO_TEST_CASE(claimtriecache_normalization)
{
ClaimTrieChainFixture fixture;
std::string name = "Ame\u0301lie";
std::string name_upper = "Amélie";
std::string name_normd = "amélie"; // this accented e is not actually the same as the one above; this has been "normalized"
BOOST_CHECK(name != name_upper);
// Add another set of unicode claims that will collapse after the fork
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, "amilie", 2);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), name_upper, "amelie", 2);
fixture.MakeClaim(fixture.GetCoinbase(), "amelie1", "amelie", 2);
fixture.IncrementBlocks(1);
CClaimValue lookupClaim;
std::string lookupName;
BOOST_CHECK(getClaimById(ClaimIdHash(tx2.GetHash(), 0), lookupName, &lookupClaim));
CClaimValue nval1;
BOOST_CHECK(fixture.getInfoForName("amelie1", nval1));
// amélie is not found cause normalization still not appear
BOOST_CHECK(!fixture.getInfoForName(name_normd, nval1));
// Activate the fork (which rebuilds the existing claimtrie and
// cache), flattening all previously existing name clashes due to
// the normalization
fixture.setNormalizationForkHeight(1);
int currentHeight = chainActive.Height();
fixture.IncrementBlocks(1);
// Ok normalization fix the name problem
BOOST_CHECK(fixture.getInfoForName(name_normd, nval1));
BOOST_CHECK(nval1.nHeight == currentHeight);
BOOST_CHECK(lookupClaim == nval1);
CCoinsViewCache coins(pcoinsTip.get());
CClaimTrieCache trieCache(pclaimTrie);
CBlockIndex* pindex = chainActive.Tip();
CBlock block;
int amelieValidHeight;
BOOST_CHECK(trieCache.shouldNormalize());
BOOST_CHECK(ReadBlockFromDisk(block, pindex, Params().GetConsensus()));
BOOST_CHECK(g_chainstate.DisconnectBlock(block, pindex, coins, trieCache) == DisconnectResult::DISCONNECT_OK);
BOOST_CHECK(!trieCache.shouldNormalize());
BOOST_CHECK(!trieCache.spendClaim(name_normd, COutPoint(tx2.GetHash(), 0), currentHeight, amelieValidHeight));
BOOST_CHECK(trieCache.spendClaim(name_upper, COutPoint(tx2.GetHash(), 0), currentHeight, amelieValidHeight));
CClaimTrieData data;
BOOST_CHECK(!pclaimTrie->find(name, data));
BOOST_CHECK(trieCache.getInfoForName(name, nval1));
BOOST_CHECK(trieCache.addClaim(name, COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), CAmount(2), currentHeight + 1));
BOOST_CHECK(trieCache.getInfoForName(name, nval1));
insertUndoType insertUndo;
claimQueueRowType expireUndo;
insertUndoType insertSupportUndo;
supportQueueRowType expireSupportUndo;
std::vector<std::pair<std::string, int> > takeoverHeightUndo;
BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo));
BOOST_CHECK(trieCache.shouldNormalize());
CClaimTrieDataNode node;
BOOST_CHECK(!pclaimTrie->find(name, node));
}
BOOST_AUTO_TEST_CASE(undo_normalization_does_not_kill_claim_order)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(5);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "a", "3", 3);
fixture.IncrementBlocks(1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 2);
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
fixture.IncrementBlocks(3, true);
BOOST_CHECK(fixture.is_best_claim("a", tx3));
fixture.DecrementBlocks();
BOOST_CHECK(fixture.is_best_claim("A", tx2));
}
BOOST_AUTO_TEST_CASE(normalized_activations_fall_through)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(5);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "AB", "1", 1);
fixture.IncrementBlocks(3);
BOOST_CHECK(fixture.proportionalDelayFactor() == 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "Ab", "2", 4);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "aB", "2", 3);
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "ab", "2", 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("AB", tx1));
fixture.IncrementBlocks(3);
BOOST_CHECK(fixture.is_best_claim("ab", tx2));
BOOST_CHECK(fixture.getClaimsForName("ab").claimsNsupports.size() == 4U);
fixture.DecrementBlocks(3);
fixture.Spend(tx1);
fixture.Spend(tx2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("ab", tx3));
BOOST_CHECK(fixture.getClaimsForName("ab").claimsNsupports.size() == 2U);
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("AB", tx1));
fixture.Spend(tx1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("ab", tx2));
for (int i = 0; i < 7; ++i) {
fixture.IncrementBlocks(i, true); // well into normalized teritory
CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "CD", "a", 1 + i);
fixture.IncrementBlocks(3);
CMutableTransaction tx6 = fixture.MakeClaim(fixture.GetCoinbase(), "Cd", "b", 2 + i);
CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), "cD", "c", 3 + i);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("cd", tx5));
fixture.Spend(tx5);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("cd", tx7));
fixture.DecrementBlocks();
}
}
BOOST_AUTO_TEST_CASE(normalization_removal_test)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(2);
fixture.IncrementBlocks(3);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "AB", "1", 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "Ab", "2", 2);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "aB", "3", 3);
CMutableTransaction sx1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "AB", 1);
CMutableTransaction sx2 = fixture.MakeSupport(fixture.GetCoinbase(), tx2, "Ab", 1);
CClaimTrieCache cache(pclaimTrie);
int height = chainActive.Height() + 1;
cache.addClaim("AB", COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), 1, height);
cache.addClaim("Ab", COutPoint(tx2.GetHash(), 0), ClaimIdHash(tx2.GetHash(), 0), 2, height);
cache.addClaim("aB", COutPoint(tx3.GetHash(), 0), ClaimIdHash(tx3.GetHash(), 0), 3, height);
cache.addSupport("AB", COutPoint(sx1.GetHash(), 0), 1, ClaimIdHash(tx1.GetHash(), 0), height);
cache.addSupport("Ab", COutPoint(sx2.GetHash(), 0), 1, ClaimIdHash(tx2.GetHash(), 0), height);
insertUndoType insertUndo;
claimQueueRowType expireUndo;
insertUndoType insertSupportUndo;
supportQueueRowType expireSupportUndo;
std::vector<std::pair<std::string, int> > takeoverHeightUndo;
BOOST_CHECK(cache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo));
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports.size() == 3U);
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[0].supports.size() == 1U);
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[1].supports.size() == 0U);
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[2].supports.size() == 1U);
BOOST_CHECK(cache.decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo));
BOOST_CHECK(cache.finalizeDecrement(takeoverHeightUndo));
BOOST_CHECK(cache.undoAddSupport("AB", COutPoint(sx1.GetHash(), 0), height));
BOOST_CHECK(cache.undoAddSupport("Ab", COutPoint(sx2.GetHash(), 0), height));
BOOST_CHECK(cache.undoAddClaim("AB", COutPoint(tx1.GetHash(), 0), height));
BOOST_CHECK(cache.undoAddClaim("Ab", COutPoint(tx2.GetHash(), 0), height));
BOOST_CHECK(cache.undoAddClaim("aB", COutPoint(tx3.GetHash(), 0), height));
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports.size() == 0U);
}
BOOST_AUTO_TEST_CASE(normalization_does_not_kill_supports)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(3);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2));
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 3));
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 4));
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 5));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 4));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 3));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2));
fixture.IncrementBlocks(5);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 3));
}
BOOST_AUTO_TEST_CASE(normalization_does_not_fail_on_spend)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(2);
std::string sName1("testN");
std::string sName2("testn");
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, "1", 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim(sName1, tx1));
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, "2", 2);
CMutableTransaction tx1s = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName1, 2);
fixture.IncrementBlocks(2, true);
BOOST_CHECK(fixture.is_best_claim(sName2, tx1));
CMutableTransaction tx3 = fixture.Spend(tx1); // abandon the claim
CMutableTransaction tx3s = fixture.Spend(tx1s);
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim(sName2, tx2));
fixture.DecrementBlocks();
BOOST_CHECK(fixture.is_best_claim(sName1, tx1));
}
BOOST_AUTO_TEST_CASE(normalization_does_not_kill_sort_order)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(2);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 2);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "a", "3", 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
BOOST_CHECK(fixture.is_best_claim("a", tx3));
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.is_best_claim("A", tx2));
BOOST_CHECK(fixture.is_best_claim("a", tx3));
BOOST_CHECK(fixture.getClaimsForName("a").claimsNsupports.size() == 3U);
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
BOOST_CHECK(fixture.is_best_claim("a", tx3));
}
BOOST_AUTO_TEST_CASE(normalization_does_not_kill_expirations)
{
ClaimTrieChainFixture fixture;
auto& consensus = Params().GetConsensus();
fixture.setExpirationForkHeight(consensus.nExtendedClaimExpirationForkHeight, 3, consensus.nExtendedClaimExpirationTime);
fixture.setNormalizationForkHeight(4);
// need to see that claims expiring on the frame when we normalize aren't kept
// need to see that supports expiring on the frame when we normalize aren't kept
// need to see that claims & supports carried through the normalization fork do expire
// and that they come back correctly when we roll backwards
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2));
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "B", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx2, "B", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("B", 2));
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "C", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx3, "C", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("B", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("C", 2));
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "D", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx4, "D", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2));
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2));
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2));
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("d", 2));
fixture.DecrementBlocks(2);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2));
fixture.DecrementBlocks(1);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("B", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("C", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("d", 2));
fixture.IncrementBlocks(3);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("d", 2)); // (not re-added)
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -0,0 +1,407 @@
// Copyright (c) 2015-2019 The LBRY Foundation
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#include <test/claimtriefixture.h>
using namespace std;
extern void ValidatePairs(CClaimTrieCache& cache, const std::vector<std::pair<bool, uint256>>& pairs, uint256 claimHash);
BOOST_FIXTURE_TEST_SUITE(claimtrierpc_tests, RegTestingSetup)
BOOST_AUTO_TEST_CASE(getnamesintrie_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("test");
std::string sValue1("test");
uint256 blockHash = chainActive.Tip()->GetBlockHash();
fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 42);
fixture.IncrementBlocks(1);
rpcfn_type getnamesintrie = tableRPC["getnamesintrie"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
UniValue results = getnamesintrie(req);
BOOST_CHECK_EQUAL(results.size(), 1U);
req.params.push_back(blockHash.GetHex());
results = getnamesintrie(req);
BOOST_CHECK_EQUAL(results.size(), 0U);
}
BOOST_AUTO_TEST_CASE(getvalueforname_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("testN");
std::string sValue1("testV");
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 2);
fixture.IncrementBlocks(1);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName1, 3);
fixture.IncrementBlocks(10);
rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(sName1));
UniValue results = getvalueforname(req);
BOOST_CHECK_EQUAL(results[T_VALUE].get_str(), HexStr(sValue1));
BOOST_CHECK_EQUAL(results[T_AMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(results[T_EFFECTIVEAMOUNT].get_int(), 5);
req.params.push_back(blockHash.GetHex());
results = getvalueforname(req);
BOOST_CHECK_EQUAL(results[T_AMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(results[T_EFFECTIVEAMOUNT].get_int(), 2);
}
BOOST_AUTO_TEST_CASE(getclaimsforname_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("testN");
std::string sValue1("test1");
std::string sValue2("test2");
int height = chainActive.Height();
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 2);
fixture.IncrementBlocks(1);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 3);
fixture.IncrementBlocks(1);
rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(sName1));
UniValue results = getclaimsforname(req);
UniValue claims = results[T_CLAIMS];
BOOST_CHECK_EQUAL(claims.size(), 2U);
BOOST_CHECK_EQUAL(results[T_LASTTAKEOVERHEIGHT].get_int(), height + 1);
BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(claims[0][T_SUPPORTS].size(), 0U);
fixture.IncrementBlocks(1);
results = getclaimsforname(req);
claims = results[T_CLAIMS];
BOOST_CHECK_EQUAL(claims.size(), 2U);
BOOST_CHECK_EQUAL(results[T_LASTTAKEOVERHEIGHT].get_int(), height + 3);
BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 3);
BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(claims[0][T_SUPPORTS].size(), 0U);
BOOST_CHECK_EQUAL(claims[1][T_SUPPORTS].size(), 0U);
req.params.push_back(blockHash.GetHex());
results = getclaimsforname(req);
claims = results[T_CLAIMS];
BOOST_CHECK_EQUAL(claims.size(), 1U);
BOOST_CHECK_EQUAL(results[T_LASTTAKEOVERHEIGHT].get_int(), height + 1);
BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(claims[0][T_SUPPORTS].size(), 0U);
}
BOOST_AUTO_TEST_CASE(claim_rpcs_rollback2_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("testN");
std::string sValue1("test1");
std::string sValue2("test2");
int height = chainActive.Height();
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 1);
fixture.IncrementBlocks(2);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2);
fixture.IncrementBlocks(3);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
CMutableTransaction tx3 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sValue1, 3);
fixture.IncrementBlocks(1);
rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor;
rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(sName1));
req.params.push_back(blockHash.GetHex());
UniValue claimsResults = getclaimsforname(req);
BOOST_CHECK_EQUAL(claimsResults[T_LASTTAKEOVERHEIGHT].get_int(), height + 5);
BOOST_CHECK_EQUAL(claimsResults[T_CLAIMS][0][T_SUPPORTS].size(), 0U);
BOOST_CHECK_EQUAL(claimsResults[T_CLAIMS][1][T_SUPPORTS].size(), 0U);
UniValue valueResults = getvalueforname(req);
BOOST_CHECK_EQUAL(valueResults[T_VALUE].get_str(), HexStr(sValue2));
BOOST_CHECK_EQUAL(valueResults[T_AMOUNT].get_int(), 2);
}
BOOST_AUTO_TEST_CASE(claim_rpcs_rollback3_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("testN");
std::string sValue1("test1");
std::string sValue2("test2");
int height = chainActive.Height();
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 3);
fixture.IncrementBlocks(1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2);
fixture.IncrementBlocks(2);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
CMutableTransaction tx3 = fixture.Spend(tx1); // abandon the claim
fixture.IncrementBlocks(1);
rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor;
rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor;
rpcfn_type getblocktemplate = tableRPC["getblocktemplate"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
UniValue templateResults = getblocktemplate(req);
BOOST_CHECK_EQUAL(templateResults["claimtrie"].get_str(), chainActive.Tip()->hashClaimTrie.GetHex());
req.params.push_back(UniValue(sName1));
req.params.push_back(blockHash.GetHex());
UniValue claimsResults = getclaimsforname(req);
BOOST_CHECK_EQUAL(claimsResults[T_LASTTAKEOVERHEIGHT].get_int(), height + 1);
UniValue valueResults = getvalueforname(req);
BOOST_CHECK_EQUAL(valueResults[T_VALUE].get_str(), HexStr(sValue1));
BOOST_CHECK_EQUAL(valueResults[T_AMOUNT].get_int(), 3);
}
std::vector<std::pair<bool, uint256>> jsonToPairs(const UniValue& jsonPair)
{
std::vector<std::pair<bool, uint256>> pairs;
for (std::size_t i = 0; i < jsonPair.size(); ++i) {
auto& jpair = jsonPair[i];
pairs.emplace_back(jpair[T_ODD].get_bool(), uint256S(jpair[T_HASH].get_str()));
}
return pairs;
}
BOOST_AUTO_TEST_CASE(hash_bid_seq_claim_changes_test)
{
ClaimTrieChainFixture fixture;
fixture.setHashForkHeight(2);
fixture.IncrementBlocks(4);
std::string name = "toa";
std::string value1 = "one", value2 = "two", value3 = "tre", value4 = "for";
auto tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, value1, 1);
fixture.IncrementBlocks(1);
CMutableTransaction tx2 = BuildTransaction(fixture.GetCoinbase(), 0, 2);
tx2.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME
<< std::vector<unsigned char>(name.begin(), name.end())
<< std::vector<unsigned char>(value2.begin(), value2.end()) << OP_2DROP << OP_DROP << OP_TRUE;
tx2.vout[0].nValue = 3;
tx2.vout[1].scriptPubKey = CScript() << OP_CLAIM_NAME
<< std::vector<unsigned char>(name.begin(), name.end())
<< std::vector<unsigned char>(value3.begin(), value3.end()) << OP_2DROP << OP_DROP << OP_TRUE;
tx2.vout[1].nValue = 2;
fixture.CommitTx(tx2);
fixture.IncrementBlocks(1);
auto tx3 = fixture.MakeClaim(fixture.GetCoinbase(), name, value4, 4);
fixture.IncrementBlocks(1);
int height = chainActive.Height();
auto claimId1 = ClaimIdHash(tx1.GetHash(), 0);
auto claimId2 = ClaimIdHash(tx2.GetHash(), 0);
auto claimId3 = ClaimIdHash(tx2.GetHash(), 1);
auto claimId4 = ClaimIdHash(tx3.GetHash(), 0);
int claim1bid = 3, claim1seq = 0;
int claim2bid = 1, claim2seq = 1;
int claim3bid = 2, claim3seq = 2;
int claim4bid = 0, claim4seq = 3;
auto getclaimsforname = tableRPC["getclaimsforname"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
auto result = getclaimsforname(req);
auto claims = result[T_CLAIMS];
BOOST_CHECK_EQUAL(claims.size(), 4U);
BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height);
BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 4);
BOOST_CHECK_EQUAL(claims[0][T_BID].get_int(), claim4bid);
BOOST_CHECK_EQUAL(claims[0][T_SEQUENCE].get_int(), claim4seq);
BOOST_CHECK_EQUAL(claims[0][T_CLAIMID].get_str(), claimId4.GetHex());
BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 3);
BOOST_CHECK_EQUAL(claims[1][T_BID].get_int(), claim2bid);
BOOST_CHECK_EQUAL(claims[1][T_SEQUENCE].get_int(), claim2seq);
BOOST_CHECK_EQUAL(claims[1][T_CLAIMID].get_str(), claimId2.GetHex());
BOOST_CHECK_EQUAL(claims[2][T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(claims[2][T_BID].get_int(), claim3bid);
BOOST_CHECK_EQUAL(claims[2][T_SEQUENCE].get_int(), claim3seq);
BOOST_CHECK_EQUAL(claims[2][T_CLAIMID].get_str(), claimId3.GetHex());
BOOST_CHECK_EQUAL(claims[3][T_EFFECTIVEAMOUNT].get_int(), 1);
BOOST_CHECK_EQUAL(claims[3][T_BID].get_int(), claim1bid);
BOOST_CHECK_EQUAL(claims[3][T_SEQUENCE].get_int(), claim1seq);
BOOST_CHECK_EQUAL(claims[3][T_CLAIMID].get_str(), claimId1.GetHex());
auto getclaimbybid = tableRPC["getclaimbybid"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
req.params.push_back(UniValue(claim3bid));
result = getclaimbybid(req);
BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height);
BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim3bid);
BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim3seq);
BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId3.GetHex());
auto getclaimbyseq = tableRPC["getclaimbyseq"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
req.params.push_back(UniValue(claim2seq));
result = getclaimbyseq(req);
BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height);
BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 3);
BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim2bid);
BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim2seq);
BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId2.GetHex());
auto getclaimbyid = tableRPC["getclaimbyid"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(claimId1.GetHex()));
result = getclaimbyid(req);
BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height);
BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 1);
BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim1bid);
BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim1seq);
BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId1.GetHex());
// check by partial id (at least 3 chars)
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(claimId3.GetHex().substr(0, 3)));
result = getclaimbyid(req);
BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height);
BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim3bid);
BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim3seq);
BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId3.GetHex());
auto blockhash = chainActive.Tip()->GetBlockHash();
auto getnameproof = tableRPC["getnameproof"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
req.params.push_back(UniValue(blockhash.GetHex()));
req.params.push_back(UniValue(claimId3.GetHex()));
result = getnameproof(req);
auto claimHash = getValueHash(COutPoint(tx2.GetHash(), 1), result[T_LASTTAKEOVERHEIGHT].get_int());
ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash);
// check by partial id (can be even 1 char)
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
req.params.push_back(UniValue(blockhash.GetHex()));
req.params.push_back(UniValue(claimId2.GetHex().substr(0, 2)));
result = getnameproof(req);
claimHash = getValueHash(COutPoint(tx2.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int());
ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash);
auto getclaimproofbybid = tableRPC["getclaimproofbybid"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
req.params.push_back(UniValue(claim1bid));
result = getclaimproofbybid(req);
claimHash = getValueHash(COutPoint(tx1.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int());
ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash);
auto getclaimproofbyseq = tableRPC["getclaimproofbyseq"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
req.params.push_back(UniValue(claim4seq));
result = getclaimproofbyseq(req);
claimHash = getValueHash(COutPoint(tx3.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int());
ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash);
auto getchangesinblock = tableRPC["getchangesinblock"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(blockhash.GetHex()));
result = getchangesinblock(req);
BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED].size(), 3);
BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][0].get_str(), claimId2.GetHex());
BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][1].get_str(), claimId3.GetHex());
BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][2].get_str(), claimId4.GetHex());
BOOST_CHECK_EQUAL(result[T_CLAIMSREMOVED].size(), 0);
BOOST_CHECK_EQUAL(result[T_SUPPORTSADDEDORUPDATED].size(), 0);
BOOST_CHECK_EQUAL(result[T_SUPPORTSREMOVED].size(), 0);
}
BOOST_AUTO_TEST_CASE(claim_rpc_pending_amount_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("test");
std::string sValue1("test1");
std::string sValue2("test2");
rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(sName1));
fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 1);
fixture.IncrementBlocks(1);
fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2);
fixture.IncrementBlocks(1);
auto claims = getclaimsforname(req)[T_CLAIMS];
BOOST_CHECK_EQUAL(claims.size(), 2U);
BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 1);
BOOST_CHECK(!claims[0].exists(T_PENDINGAMOUNT));
BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 0);
BOOST_CHECK(claims[1].exists(T_PENDINGAMOUNT));
BOOST_CHECK_EQUAL(claims[1][T_PENDINGAMOUNT].get_int(), 2);
fixture.IncrementBlocks(1);
claims = getclaimsforname(req)[T_CLAIMS];
BOOST_CHECK_EQUAL(claims.size(), 2U);
BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK(!claims[0].exists(T_PENDINGAMOUNT));
BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 1);
BOOST_CHECK(!claims[1].exists(T_PENDINGAMOUNT));
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -3,6 +3,7 @@
#include <random.h> #include <random.h>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <test/claimtriefixture.h>
#include <test/test_bitcoin.h> #include <test/test_bitcoin.h>
#include <chrono> #include <chrono>
@ -37,7 +38,79 @@ std::vector<std::string> random_strings(std::size_t count)
using namespace std; using namespace std;
BOOST_FIXTURE_TEST_SUITE(prefixtrie_tests, BasicTestingSetup) BOOST_FIXTURE_TEST_SUITE(prefixtrie_tests, RegTestingSetup)
#ifndef MAC_OSX // can't find a random number generator that produces the same sequence on OSX
BOOST_AUTO_TEST_CASE(triehash_fuzzer_test)
{
ClaimTrieChainFixture fixture;
auto envClaims = std::getenv("TRIEHASH_FUZZER_CLAIMS");
auto envBlocks = std::getenv("TRIEHASH_FUZZER_BLOCKS");
const int claimsPerBlock = envClaims ? std::atoi(envClaims) : 100;
const int blocks = envBlocks ? std::atoi(envBlocks) : 13;
auto names = random_strings(blocks * claimsPerBlock);
FastRandomContext frc(true);
std::unordered_map<std::string, std::vector<CMutableTransaction>> existingClaims;
std::vector<CMutableTransaction> existingSupports;
std::string value(1024, 'c');
std::vector<CTransaction> cb {fixture.GetCoinbase()};
for (int i = 0; i < blocks; ++i) {
for (int j = 0; j < claimsPerBlock; ++j) {
auto name = names[i * claimsPerBlock + j];
auto supportFront = frc.randrange(4) == 0;
auto supportBack = frc.randrange(4) == 0;
auto removeClaim = frc.randrange(4) == 0;
auto removeSupport = frc.randrange(4) == 0;
auto hit = existingClaims.find(name);
if (supportFront && hit != existingClaims.end() && hit->second.size()) {
auto tx = fixture.MakeSupport(cb.back(), hit->second[frc.rand64() % hit->second.size()], name, 2);
existingSupports.push_back(tx);
cb.emplace_back(std::move(tx));
}
if (removeClaim && hit != existingClaims.end() && hit->second.size()) {
auto idx = frc.rand64() % hit->second.size();
fixture.Spend(hit->second[idx]);
hit->second.erase(hit->second.begin() + idx);
} else {
auto tx = fixture.MakeClaim(cb.back(), name, value, 2);
existingClaims[name].push_back(tx);
hit = existingClaims.find(name);
cb.emplace_back(std::move(tx));
}
if (supportBack && hit != existingClaims.end() && hit->second.size()) {
auto tx = fixture.MakeSupport(cb.back(), hit->second[frc.rand64() % hit->second.size()], name, 2);
existingSupports.push_back(tx);
cb.emplace_back(std::move(tx));
}
if (removeSupport && (i & 7) == 7 && !existingSupports.empty()) {
const auto tidx = frc.rand64() % existingSupports.size();
const auto tx = existingSupports[tidx];
fixture.Spend(tx);
existingSupports.erase(existingSupports.begin() + tidx);
}
if (cb.back().GetValueOut() < 10 || cb.size() > 40000) {
cb.clear();
cb.push_back(fixture.GetCoinbase());
}
}
fixture.IncrementBlocks(1);
if (blocks > 13 && i % 50 == 0) // travisCI needs some periodic output
std::cerr << "In triehash_fuzzer_test with " << fixture.getTotalNamesInTrie() << " names at block " << i << std::endl;
}
if (blocks == 1000 && claimsPerBlock == 100)
BOOST_CHECK_EQUAL(fixture.getMerkleHash().GetHex(), "28825257a129eef69cab87d6255c8359fc6dc083ca7f09222526e3a7971f382d");
else if (blocks == 13 && claimsPerBlock == 100)
BOOST_CHECK_EQUAL(fixture.getMerkleHash().GetHex(), "4e5984d6984f5f05d50e821e6228d56bcfbd16ca2093cd0308f6ff1c2bc8689a");
else
std::cerr << "Hash: " << fixture.getMerkleHash().GetHex() << std::endl;
}
#endif
BOOST_AUTO_TEST_CASE(insert_erase_test) BOOST_AUTO_TEST_CASE(insert_erase_test)
{ {