From b93984437c05cb6499c7b40034c4569db3978f7f Mon Sep 17 00:00:00 2001 From: pasta Date: Sat, 1 Mar 2025 21:26:10 -0600 Subject: [PATCH] test: introduce basic unit tests for instantsend --- src/Makefile.test.include | 1 + src/chainparams.cpp | 10 ++++ src/chainparams.h | 1 + src/test/evo_islock_tests.cpp | 102 ++++++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 src/test/evo_islock_tests.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 999a06b7b1aa8f..08045018caf857 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -111,6 +111,7 @@ BITCOIN_TESTS =\ test/dynamic_activation_thresholds_tests.cpp \ test/evo_assetlocks_tests.cpp \ test/evo_deterministicmns_tests.cpp \ + test/evo_islock_tests.cpp \ test/evo_mnhf_tests.cpp \ test/evo_simplifiedmns_tests.cpp \ test/evo_trivialvalidation.cpp \ diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 66ead16b301125..6379d20ef2e10f 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -152,6 +152,16 @@ std::optional CChainParams::GetLLMQ(Consensus::LLMQType l return std::nullopt; } +std::optional CChainParams::GetLLMQByName(std::string_view llmqName) const +{ + for (const auto& llmq_param : consensus.llmqs) { + if (llmq_param.name == llmqName) { + return std::make_optional(llmq_param); + } + } + return std::nullopt; +} + /** * Main network on which people trade goods and services. */ diff --git a/src/chainparams.h b/src/chainparams.h index a63eb668ed7c59..759bc39539f3af 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -152,6 +152,7 @@ class CChainParams int MinSporkKeys() const { return nMinSporkKeys; } int CreditPoolPeriodBlocks() const { return nCreditPoolPeriodBlocks; } [[nodiscard]] std::optional GetLLMQ(Consensus::LLMQType llmqType) const; + [[nodiscard]] std::optional GetLLMQByName(std::string_view llmqName) const; protected: CChainParams() {} diff --git a/src/test/evo_islock_tests.cpp b/src/test/evo_islock_tests.cpp new file mode 100644 index 00000000000000..85d9f95bcf2937 --- /dev/null +++ b/src/test/evo_islock_tests.cpp @@ -0,0 +1,102 @@ +// instantsend_tests.cpp +#include +#include +#include +#include +#include +#include +#include + +// For constructing dummy outpoints using uint256S. +#include + +BOOST_AUTO_TEST_SUITE(instantsend_tests) + +BOOST_AUTO_TEST_CASE(getrequestid) +{ + // Create an empty InstantSendLock + llmq::CInstantSendLock islock; + + // Compute expected hash for an empty inputs vector. + // Note: CInstantSendLock::GetRequestId() serializes the prefix "islock" + // followed by the 'inputs' vector. + { + CHashWriter hw(SER_GETHASH, 0); + hw << std::string_view("islock"); + hw << islock.inputs; // empty vector + const uint256 expected = hw.GetHash(); + + BOOST_CHECK(islock.GetRequestId() == expected); + } + + // Now add two dummy inputs to the lock + islock.inputs.clear(); + // Construct two dummy outpoints (using uint256S for a dummy hash) + COutPoint op1(uint256S("0x0000000000000000000000000000000000000000000000000000000000000001"), 0); + COutPoint op2(uint256S("0x0000000000000000000000000000000000000000000000000000000000000002"), 1); + islock.inputs.push_back(op1); + islock.inputs.push_back(op2); + + { + CHashWriter hw(SER_GETHASH, 0); + hw << std::string_view("islock"); + hw << islock.inputs; + const uint256 expected = hw.GetHash(); + + BOOST_CHECK(islock.GetRequestId() == expected); + } +} + +BOOST_AUTO_TEST_CASE(deserialize_instantlock_from_realdata2) +{ + // Expected values from the provided getislocks output: + const std::string_view expectedTxidStr = "7b33968effa613e8ea9c1b5734c9bbbe467ff4650f8060caf8a5c213c6059d5b"; + const std::string_view expectedCycleHashStr = "000000000000000bbd0b1bb95540351e7ee99c5b08efde076b3d712a57ea74d6"; + const std::string_view expectedSignature = "997d0b36738a9eef46ceeb4405998ff7235317708f277402799ffe05258015cae9b6bae43683f992b2f50f70f8f0cb9c0f26af340b00903e93995c1345d1b2c5b697ebecdbe5811dd112e11889101dcb4553b2bc206ab304026b96c07dec4f24"; + const std::string_view cycleHash = "000000000000000bbd0b1bb95540351e7ee99c5b08efde076b3d712a57ea74d6"; + const std::string quorumHash = "0000000000000019756ecc9c9c5f476d3f66876b1dcfa5dde1ea82f0d99334a2"; + const std::string_view expectedSignHash = "6a3c37bc610c4efd5babd8941068a8eca9e7bec942fe175b8ca9cae31b67e838"; + // The serialized InstantSend lock from the "hex" field of getislocks: + const std::string_view islockHex = + "0101497915895c30eebfad0c5fcfb9e0e72308c7e92cd3749be2fd49c8320c4c58b6010000005b9d05c613c2a5f8ca60800f65f47f46bebbc934571b9ceae813a6ff8e96337bd674ea572a713d6b07deef085b9ce97e1e354055b91b0bbd0b00000000000000997d0b36738a9eef46ceeb4405998ff7235317708f277402799ffe05258015cae9b6bae43683f992b2f50f70f8f0cb9c0f26af340b00903e93995c1345d1b2c5b697ebecdbe5811dd112e11889101dcb4553b2bc206ab304026b96c07dec4f24"; + + // This islock was created with non-legacy. Using legacy will result in the signature being all zeros. + bls::bls_legacy_scheme.store(false); + + // Convert hex string to a byte vector and deserialize. + std::vector islockData = ParseHex(islockHex); + CDataStream ss(islockData, SER_NETWORK, PROTOCOL_VERSION); + llmq::CInstantSendLock islock; + ss >> islock; + + // Verify the calculated signHash + auto signHash = llmq::BuildSignHash(Consensus::LLMQType::LLMQ_60_75, uint256S(quorumHash), islock.GetRequestId(), islock.txid); + BOOST_CHECK_EQUAL(signHash.ToString(), + expectedSignHash); + + // Verify the txid field. + BOOST_CHECK_EQUAL(islock.txid.ToString(), expectedTxidStr); + + // Verify the cycleHash field. + BOOST_CHECK_EQUAL(islock.cycleHash.ToString(), expectedCycleHashStr); + + // Verify the inputs vector has exactly one element. + BOOST_REQUIRE_EQUAL(islock.inputs.size(), 1U); + const COutPoint& input = islock.inputs.front(); + const std::string expectedInputTxid = "b6584c0c32c849fde29b74d32ce9c70823e7e0b9cf5f0cadbfee305c89157949"; + const unsigned int expectedInputN = 1; + BOOST_CHECK_EQUAL(input.hash.ToString(), expectedInputTxid); + BOOST_CHECK_EQUAL(input.n, expectedInputN); + + // Compute the expected request ID: it is the hash of the constant prefix "islock" followed by the inputs. + CHashWriter hw(SER_GETHASH, 0); + hw << std::string_view("islock"); + hw << islock.inputs; + uint256 expectedRequestId = hw.GetHash(); + BOOST_CHECK_EQUAL(islock.GetRequestId().ToString(), expectedRequestId.ToString()); + + // Verify the signature field. + BOOST_CHECK_EQUAL(islock.sig.Get().ToString(), expectedSignature); +} + +BOOST_AUTO_TEST_SUITE_END()