aboutsummaryrefslogtreecommitdiff
path: root/src/test/txrequest_tests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/txrequest_tests.cpp')
-rw-r--r--src/test/txrequest_tests.cpp120
1 files changed, 68 insertions, 52 deletions
diff --git a/src/test/txrequest_tests.cpp b/src/test/txrequest_tests.cpp
index 0ca70d2c7a..6bb732ba69 100644
--- a/src/test/txrequest_tests.cpp
+++ b/src/test/txrequest_tests.cpp
@@ -15,10 +15,23 @@
#include <boost/test/unit_test.hpp>
-BOOST_FIXTURE_TEST_SUITE(txrequest_tests, BasicTestingSetup)
-
namespace {
+class Scenario;
+
+struct TxRequestTest : BasicTestingSetup {
+ std::chrono::microseconds RandomTime8s();
+ std::chrono::microseconds RandomTime1y();
+ void BuildSingleTest(Scenario& scenario, int config);
+ void BuildPriorityTest(Scenario& scenario, int config);
+ void BuildBigPriorityTest(Scenario& scenario, int peers);
+ void BuildRequestOrderTest(Scenario& scenario, int config);
+ void BuildWtxidTest(Scenario& scenario, int config);
+ void BuildTimeBackwardsTest(Scenario& scenario);
+ void BuildWeirdRequestsTest(Scenario& scenario);
+ void TestInterleavedScenarios();
+};
+
constexpr std::chrono::microseconds MIN_TIME = std::chrono::microseconds::min();
constexpr std::chrono::microseconds MAX_TIME = std::chrono::microseconds::max();
constexpr std::chrono::microseconds MICROSECOND = std::chrono::microseconds{1};
@@ -51,8 +64,8 @@ struct Runner
std::multiset<std::pair<NodeId, GenTxid>> expired;
};
-std::chrono::microseconds RandomTime8s() { return std::chrono::microseconds{1 + InsecureRandBits(23)}; }
-std::chrono::microseconds RandomTime1y() { return std::chrono::microseconds{1 + InsecureRandBits(45)}; }
+std::chrono::microseconds TxRequestTest::RandomTime8s() { return std::chrono::microseconds{1 + m_rng.randbits(23)}; }
+std::chrono::microseconds TxRequestTest::RandomTime1y() { return std::chrono::microseconds{1 + m_rng.randbits(45)}; }
/** A proxy for a Runner that helps build a sequence of consecutive test actions on a TxRequestTracker.
*
@@ -65,12 +78,13 @@ std::chrono::microseconds RandomTime1y() { return std::chrono::microseconds{1 +
*/
class Scenario
{
+ FastRandomContext& m_rng;
Runner& m_runner;
std::chrono::microseconds m_now;
std::string m_testname;
public:
- Scenario(Runner& runner, std::chrono::microseconds starttime) : m_runner(runner), m_now(starttime) {}
+ Scenario(FastRandomContext& rng, Runner& runner, std::chrono::microseconds starttime) : m_rng(rng), m_runner(runner), m_now(starttime) {}
/** Set a name for the current test, to give more clear error messages. */
void SetTestName(std::string testname)
@@ -199,7 +213,7 @@ public:
uint256 ret;
bool ok;
do {
- ret = InsecureRand256();
+ ret = m_rng.rand256();
ok = true;
for (const auto& order : orders) {
for (size_t pos = 1; pos < order.size(); ++pos) {
@@ -222,7 +236,7 @@ public:
/** Generate a random GenTxid; the txhash follows NewTxHash; the is_wtxid flag is random. */
GenTxid NewGTxid(const std::vector<std::vector<NodeId>>& orders = {})
{
- return InsecureRandBool() ? GenTxid::Wtxid(NewTxHash(orders)) : GenTxid::Txid(NewTxHash(orders));
+ return m_rng.randbool() ? GenTxid::Wtxid(NewTxHash(orders)) : GenTxid::Txid(NewTxHash(orders));
}
/** Generate a new random NodeId to use as peer. The same NodeId is never returned twice
@@ -232,7 +246,7 @@ public:
bool ok;
NodeId ret;
do {
- ret = InsecureRandBits(63);
+ ret = m_rng.randbits(63);
ok = m_runner.peerset.insert(ret).second;
} while(!ok);
return ret;
@@ -245,7 +259,7 @@ public:
*
* config is an integer in [0, 32), which controls which variant of the test is used.
*/
-void BuildSingleTest(Scenario& scenario, int config)
+void TxRequestTest::BuildSingleTest(Scenario& scenario, int config)
{
auto peer = scenario.NewPeer();
auto gtxid = scenario.NewGTxid();
@@ -282,7 +296,7 @@ void BuildSingleTest(Scenario& scenario, int config)
scenario.CheckExpired(peer, gtxid);
return;
} else {
- scenario.AdvanceTime(std::chrono::microseconds{InsecureRandRange(expiry.count())});
+ scenario.AdvanceTime(std::chrono::microseconds{m_rng.randrange(expiry.count())});
scenario.Check(peer, {}, 0, 1, 0, "s9");
if ((config >> 3) == 3) { // A response will arrive for the transaction
scenario.ReceivedResponse(peer, gtxid.GetHash());
@@ -305,7 +319,7 @@ void BuildSingleTest(Scenario& scenario, int config)
*
* config is an integer in [0, 32), which controls which variant of the test is used.
*/
-void BuildPriorityTest(Scenario& scenario, int config)
+void TxRequestTest::BuildPriorityTest(Scenario& scenario, int config)
{
scenario.SetTestName(strprintf("Priority(config=%i)", config));
@@ -319,7 +333,7 @@ void BuildPriorityTest(Scenario& scenario, int config)
scenario.ReceivedInv(peer1, gtxid, pref1, MIN_TIME);
scenario.Check(peer1, {gtxid}, 1, 0, 0, "p1");
- if (InsecureRandBool()) {
+ if (m_rng.randbool()) {
scenario.AdvanceTime(RandomTime8s());
scenario.Check(peer1, {gtxid}, 1, 0, 0, "p2");
}
@@ -335,7 +349,7 @@ void BuildPriorityTest(Scenario& scenario, int config)
NodeId priopeer = stage2_prio ? peer2 : peer1, otherpeer = stage2_prio ? peer1 : peer2;
scenario.Check(otherpeer, {}, 1, 0, 0, "p3");
scenario.Check(priopeer, {gtxid}, 1, 0, 0, "p4");
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.Check(otherpeer, {}, 1, 0, 0, "p5");
scenario.Check(priopeer, {gtxid}, 1, 0, 0, "p6");
@@ -344,7 +358,7 @@ void BuildPriorityTest(Scenario& scenario, int config)
scenario.RequestedTx(priopeer, gtxid.GetHash(), MAX_TIME);
scenario.Check(priopeer, {}, 0, 1, 0, "p7");
scenario.Check(otherpeer, {}, 1, 0, 0, "p8");
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
}
// The peer which was selected (or requested from) now goes offline, or a NOTFOUND is received from them.
@@ -353,28 +367,28 @@ void BuildPriorityTest(Scenario& scenario, int config)
} else {
scenario.ReceivedResponse(priopeer, gtxid.GetHash());
}
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.Check(priopeer, {}, 0, 0, !(config & 16), "p8");
scenario.Check(otherpeer, {gtxid}, 1, 0, 0, "p9");
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
// Now the other peer goes offline.
scenario.DisconnectedPeer(otherpeer);
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.Check(peer1, {}, 0, 0, 0, "p10");
scenario.Check(peer2, {}, 0, 0, 0, "p11");
}
/** Add to scenario a randomized test in which N peers announce the same transaction, to verify
* the order in which they are requested. */
-void BuildBigPriorityTest(Scenario& scenario, int peers)
+void TxRequestTest::BuildBigPriorityTest(Scenario& scenario, int peers)
{
scenario.SetTestName(strprintf("BigPriority(peers=%i)", peers));
// We will have N peers announce the same transaction.
std::map<NodeId, bool> preferred;
std::vector<NodeId> pref_peers, npref_peers;
- int num_pref = InsecureRandRange(peers + 1) ; // Some preferred, ...
+ int num_pref = m_rng.randrange(peers + 1) ; // Some preferred, ...
int num_npref = peers - num_pref; // some not preferred.
for (int i = 0; i < num_pref; ++i) {
pref_peers.push_back(scenario.NewPeer());
@@ -392,7 +406,7 @@ void BuildBigPriorityTest(Scenario& scenario, int peers)
// Determine the announcement order randomly.
std::vector<NodeId> announce_order = request_order;
- std::shuffle(announce_order.begin(), announce_order.end(), g_insecure_rand_ctx);
+ std::shuffle(announce_order.begin(), announce_order.end(), m_rng);
// Find a gtxid whose txhash prioritization is consistent with the required ordering within pref_peers and
// within npref_peers.
@@ -427,11 +441,11 @@ void BuildBigPriorityTest(Scenario& scenario, int peers)
// Peers now in random order go offline, or send NOTFOUNDs. At every point in time the new to-be-requested-from
// peer should be the best remaining one, so verify this after every response.
for (int i = 0; i < peers; ++i) {
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
- const int pos = InsecureRandRange(request_order.size());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
+ const int pos = m_rng.randrange(request_order.size());
const auto peer = request_order[pos];
request_order.erase(request_order.begin() + pos);
- if (InsecureRandBool()) {
+ if (m_rng.randbool()) {
scenario.DisconnectedPeer(peer);
scenario.Check(peer, {}, 0, 0, 0, "b4");
} else {
@@ -454,7 +468,7 @@ void BuildBigPriorityTest(Scenario& scenario, int peers)
*
* config is an integer in [0, 4) inclusive, and selects the variant of the test.
*/
-void BuildRequestOrderTest(Scenario& scenario, int config)
+void TxRequestTest::BuildRequestOrderTest(Scenario& scenario, int config)
{
scenario.SetTestName(strprintf("RequestOrder(config=%i)", config));
@@ -489,7 +503,7 @@ void BuildRequestOrderTest(Scenario& scenario, int config)
*
* config is an integer in [0, 4) inclusive, and selects the variant of the test used.
*/
-void BuildWtxidTest(Scenario& scenario, int config)
+void TxRequestTest::BuildWtxidTest(Scenario& scenario, int config)
{
scenario.SetTestName(strprintf("Wtxid(config=%i)", config));
@@ -499,17 +513,17 @@ void BuildWtxidTest(Scenario& scenario, int config)
auto txid{GenTxid::Txid(txhash)};
auto wtxid{GenTxid::Wtxid(txhash)};
- auto reqtimeT = InsecureRandBool() ? MIN_TIME : scenario.Now() + RandomTime8s();
- auto reqtimeW = InsecureRandBool() ? MIN_TIME : scenario.Now() + RandomTime8s();
+ auto reqtimeT = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s();
+ auto reqtimeW = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s();
// Announce txid first or wtxid first.
if (config & 1) {
scenario.ReceivedInv(peerT, txid, config & 2, reqtimeT);
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.ReceivedInv(peerW, wtxid, !(config & 2), reqtimeW);
} else {
scenario.ReceivedInv(peerW, wtxid, !(config & 2), reqtimeW);
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.ReceivedInv(peerT, txid, config & 2, reqtimeT);
}
@@ -552,14 +566,14 @@ void BuildWtxidTest(Scenario& scenario, int config)
// If a good transaction with either that hash as wtxid or txid arrives, both
// announcements are gone.
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.ForgetTxHash(txhash);
scenario.Check(peerT, {}, 0, 0, 0, "w13");
scenario.Check(peerW, {}, 0, 0, 0, "w14");
}
/** Add to scenario a test that exercises clocks that go backwards. */
-void BuildTimeBackwardsTest(Scenario& scenario)
+void TxRequestTest::BuildTimeBackwardsTest(Scenario& scenario)
{
auto peer1 = scenario.NewPeer();
auto peer2 = scenario.NewPeer();
@@ -577,13 +591,13 @@ void BuildTimeBackwardsTest(Scenario& scenario)
scenario.Check(peer2, {gtxid}, 1, 0, 0, "r4");
// Announce from peer1.
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.ReceivedInv(peer1, gtxid, true, MAX_TIME);
scenario.Check(peer2, {gtxid}, 1, 0, 0, "r5");
scenario.Check(peer1, {}, 1, 0, 0, "r6");
// Request from peer1.
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
auto expiry = scenario.Now() + RandomTime8s();
scenario.RequestedTx(peer1, gtxid.GetHash(), expiry);
scenario.Check(peer1, {}, 0, 1, 0, "r7");
@@ -598,14 +612,14 @@ void BuildTimeBackwardsTest(Scenario& scenario)
scenario.Check(peer2, {gtxid}, 1, 0, 0, "r12", -MICROSECOND);
// Peer2 goes offline, meaning no viable announcements remain.
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.DisconnectedPeer(peer2);
scenario.Check(peer1, {}, 0, 0, 0, "r13");
scenario.Check(peer2, {}, 0, 0, 0, "r14");
}
/** Add to scenario a test that involves RequestedTx() calls for txhashes not returned by GetRequestable. */
-void BuildWeirdRequestsTest(Scenario& scenario)
+void TxRequestTest::BuildWeirdRequestsTest(Scenario& scenario)
{
auto peer1 = scenario.NewPeer();
auto peer2 = scenario.NewPeer();
@@ -617,19 +631,19 @@ void BuildWeirdRequestsTest(Scenario& scenario)
scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q1");
// Announce gtxid2 by peer2.
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.ReceivedInv(peer2, gtxid2, true, MIN_TIME);
scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q2");
scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q3");
// We request gtxid2 from *peer1* - no effect.
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME);
scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q4");
scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q5");
// Now request gtxid1 from peer1 - marks it as REQUESTED.
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
auto expiryA = scenario.Now() + RandomTime8s();
scenario.RequestedTx(peer1, gtxid1.GetHash(), expiryA);
scenario.Check(peer1, {}, 0, 1, 0, "q6");
@@ -653,25 +667,25 @@ void BuildWeirdRequestsTest(Scenario& scenario)
scenario.CheckExpired(peer1, gtxid1);
// Requesting it yet again from peer1 doesn't do anything, as it's already COMPLETED.
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.RequestedTx(peer1, gtxid1.GetHash(), MAX_TIME);
scenario.Check(peer1, {}, 0, 0, 1, "q14");
scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q15");
// Now announce gtxid2 from peer1.
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.ReceivedInv(peer1, gtxid2, true, MIN_TIME);
scenario.Check(peer1, {}, 1, 0, 1, "q16");
scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q17");
// And request it from peer1 (weird as peer2 has the preference).
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME);
scenario.Check(peer1, {}, 0, 1, 1, "q18");
scenario.Check(peer2, {gtxid1}, 2, 0, 0, "q19");
// If peer2 now (normally) requests gtxid2, the existing request by peer1 becomes COMPLETED.
- if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s());
+ if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.RequestedTx(peer2, gtxid2.GetHash(), MAX_TIME);
scenario.Check(peer1, {}, 0, 0, 2, "q20");
scenario.Check(peer2, {gtxid1}, 1, 1, 0, "q21");
@@ -682,22 +696,22 @@ void BuildWeirdRequestsTest(Scenario& scenario)
scenario.Check(peer2, {}, 0, 0, 0, "q23");
}
-void TestInterleavedScenarios()
+void TxRequestTest::TestInterleavedScenarios()
{
// Create a list of functions which add tests to scenarios.
std::vector<std::function<void(Scenario&)>> builders;
// Add instances of every test, for every configuration.
for (int n = 0; n < 64; ++n) {
- builders.emplace_back([n](Scenario& scenario){ BuildWtxidTest(scenario, n); });
- builders.emplace_back([n](Scenario& scenario){ BuildRequestOrderTest(scenario, n & 3); });
- builders.emplace_back([n](Scenario& scenario){ BuildSingleTest(scenario, n & 31); });
- builders.emplace_back([n](Scenario& scenario){ BuildPriorityTest(scenario, n & 31); });
- builders.emplace_back([n](Scenario& scenario){ BuildBigPriorityTest(scenario, (n & 7) + 1); });
- builders.emplace_back([](Scenario& scenario){ BuildTimeBackwardsTest(scenario); });
- builders.emplace_back([](Scenario& scenario){ BuildWeirdRequestsTest(scenario); });
+ builders.emplace_back([this, n](Scenario& scenario) { BuildWtxidTest(scenario, n); });
+ builders.emplace_back([this, n](Scenario& scenario) { BuildRequestOrderTest(scenario, n & 3); });
+ builders.emplace_back([this, n](Scenario& scenario) { BuildSingleTest(scenario, n & 31); });
+ builders.emplace_back([this, n](Scenario& scenario) { BuildPriorityTest(scenario, n & 31); });
+ builders.emplace_back([this, n](Scenario& scenario) { BuildBigPriorityTest(scenario, (n & 7) + 1); });
+ builders.emplace_back([this](Scenario& scenario) { BuildTimeBackwardsTest(scenario); });
+ builders.emplace_back([this](Scenario& scenario) { BuildWeirdRequestsTest(scenario); });
}
// Randomly shuffle all those functions.
- std::shuffle(builders.begin(), builders.end(), g_insecure_rand_ctx);
+ std::shuffle(builders.begin(), builders.end(), m_rng);
Runner runner;
auto starttime = RandomTime1y();
@@ -706,7 +720,7 @@ void TestInterleavedScenarios()
// Introduce some variation in the start time of each scenario, so they don't all start off
// concurrently, but get a more random interleaving.
auto scenario_start = starttime + RandomTime8s() + RandomTime8s() + RandomTime8s();
- Scenario scenario(runner, scenario_start);
+ Scenario scenario(m_rng, runner, scenario_start);
for (int j = 0; builders.size() && j < 10; ++j) {
builders.back()(scenario);
builders.pop_back();
@@ -730,6 +744,8 @@ void TestInterleavedScenarios()
} // namespace
+BOOST_FIXTURE_TEST_SUITE(txrequest_tests, TxRequestTest)
+
BOOST_AUTO_TEST_CASE(TxRequestTest)
{
for (int i = 0; i < 5; ++i) {