LCOV - code coverage report
Current view: top level - src/test - evo_specialtx_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 235 241 97.5 %
Date: 2025-02-23 09:33:43 Functions: 34 34 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2021-2022 The PIVX Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or https://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include "test/test_pivx.h"
       6             : 
       7             : #include "test/data/specialtx_invalid.json.h"
       8             : #include "test/data/specialtx_valid.json.h"
       9             : 
      10             : #include "consensus/validation.h"
      11             : #include "core_io.h"
      12             : #include "evo/providertx.h"
      13             : #include "evo/specialtx_validation.h"
      14             : #include "llmq/quorums_commitment.h"
      15             : #include "messagesigner.h"
      16             : #include "netbase.h"
      17             : #include "primitives/transaction.h"
      18             : 
      19             : #include <boost/test/unit_test.hpp>
      20             : 
      21             : extern UniValue read_json(const std::string& jsondata);
      22             : 
      23             : BOOST_FIXTURE_TEST_SUITE(evo_specialtx_tests, TestingSetup)
      24             : 
      25          18 : static CKey GetRandomKey()
      26             : {
      27          18 :     CKey key;
      28          18 :     key.MakeNewKey(true);
      29          18 :     return key;
      30             : }
      31             : 
      32          17 : static CKeyID GetRandomKeyID()
      33             : {
      34          34 :     return GetRandomKey().GetPubKey().GetID();
      35             : }
      36             : 
      37           4 : static CBLSPublicKey GetRandomBLSKey()
      38             : {
      39           4 :     CBLSSecretKey sk;
      40           4 :     sk.MakeNewKey();
      41           8 :     return sk.GetPublicKey();
      42             : }
      43             : 
      44           9 : static CScript GetRandomScript()
      45             : {
      46          18 :     return GetScriptForDestination(GetRandomKeyID());
      47             : }
      48             : 
      49           3 : static ProRegPL GetRandomProRegPayload()
      50             : {
      51           3 :     ProRegPL pl;
      52           3 :     pl.collateralOutpoint.hash = GetRandHash();
      53           3 :     pl.collateralOutpoint.n = InsecureRandBits(2);
      54           9 :     BOOST_CHECK(Lookup("57.12.210.11:51472", pl.addr, Params().GetDefaultPort(), false));
      55           3 :     pl.keyIDOwner = GetRandomKeyID();
      56           3 :     pl.pubKeyOperator = GetRandomBLSKey();
      57           3 :     pl.keyIDVoting = GetRandomKeyID();
      58           3 :     pl.scriptPayout = GetRandomScript();
      59           3 :     pl.nOperatorReward = InsecureRandRange(10000);
      60           3 :     pl.scriptOperatorPayout = GetRandomScript();
      61           3 :     pl.inputsHash = GetRandHash();
      62           3 :     pl.vchSig = InsecureRandBytes(63);
      63           3 :     return pl;
      64             : }
      65             : 
      66           1 : static ProUpServPL GetRandomProUpServPayload()
      67             : {
      68           1 :     ProUpServPL pl;
      69           1 :     pl.proTxHash = GetRandHash();
      70           2 :     BOOST_CHECK(Lookup("127.0.0.1:51472", pl.addr, Params().GetDefaultPort(), false));
      71           1 :     pl.scriptOperatorPayout = GetRandomScript();
      72           1 :     pl.inputsHash = GetRandHash();
      73           1 :     pl.sig.SetByteVector(InsecureRandBytes(BLS_CURVE_SIG_SIZE));
      74           1 :     return pl;
      75             : }
      76             : 
      77           1 : static ProUpRegPL GetRandomProUpRegPayload()
      78             : {
      79           1 :     ProUpRegPL pl;
      80           1 :     pl.proTxHash = GetRandHash();
      81           1 :     pl.pubKeyOperator = GetRandomBLSKey();
      82           1 :     pl.keyIDVoting = GetRandomKeyID();
      83           1 :     pl.scriptPayout = GetRandomScript();
      84           1 :     pl.inputsHash = GetRandHash();
      85           1 :     pl.vchSig = InsecureRandBytes(63);
      86           1 :     return pl;
      87             : }
      88             : 
      89           1 : static ProUpRevPL GetRandomProUpRevPayload()
      90             : {
      91           1 :     ProUpRevPL pl;
      92           1 :     pl.proTxHash = GetRandHash();
      93           1 :     pl.nReason = InsecureRand16();
      94           1 :     pl.inputsHash = GetRandHash();
      95           1 :     pl.sig.SetByteVector(InsecureRandBytes(BLS_CURVE_SIG_SIZE));
      96           1 :     return pl;
      97             : }
      98             : 
      99           1 : llmq::CFinalCommitment GetRandomLLMQCommitment()
     100             : {
     101           1 :     llmq::CFinalCommitment fc;
     102           1 :     fc.nVersion = InsecureRand16();
     103           1 :     fc.llmqType = InsecureRandBits(8);
     104           1 :     fc.quorumHash = GetRandHash();
     105           1 :     int vecsize = InsecureRandRange(500);
     106          63 :     for (int i = 0; i < vecsize; i++) {
     107          62 :         fc.signers.emplace_back((bool)InsecureRandBits(1));
     108         124 :         fc.validMembers.emplace_back((bool)InsecureRandBits(1));
     109             :     }
     110           1 :     fc.quorumPublicKey.SetByteVector(InsecureRandBytes(BLS_CURVE_PUBKEY_SIZE));
     111           1 :     fc.quorumVvecHash = GetRandHash();
     112           1 :     fc.quorumSig.SetByteVector(InsecureRandBytes(BLS_CURVE_SIG_SIZE));
     113           1 :     fc.membersSig.SetByteVector(InsecureRandBytes(BLS_CURVE_SIG_SIZE));
     114           1 :     return fc;
     115             : }
     116             : 
     117           1 : static llmq::LLMQCommPL GetRandomLLMQCommPayload()
     118             : {
     119           1 :     llmq::LLMQCommPL pl;
     120           1 :     pl.nHeight = InsecureRand32();
     121           1 :     pl.commitment = GetRandomLLMQCommitment();
     122           1 :     return pl;
     123             : }
     124             : 
     125           1 : static bool EqualCommitments(const llmq::CFinalCommitment& a, const llmq::CFinalCommitment& b)
     126             : {
     127           1 :     return a.nVersion == b.nVersion &&
     128           1 :            a.llmqType == b.llmqType &&
     129           2 :            a.quorumHash == b.quorumHash &&
     130           1 :            a.signers == b.signers &&
     131           1 :            a.quorumPublicKey == b.quorumPublicKey &&
     132           1 :            a.quorumVvecHash == b.quorumVvecHash &&
     133           2 :            a.quorumSig == b.quorumSig &&
     134           1 :            a.membersSig == b.membersSig;
     135             : }
     136             : 
     137             : template <typename T>
     138          59 : static void TrivialCheckSpecialTx(const CMutableTransaction& mtx, const bool shouldFail, const std::string& rejectReason)
     139             : {
     140         105 :     T pl;
     141          59 :     CValidationState state;
     142          59 :     GetTxPayload(mtx, pl);
     143         118 :     BOOST_CHECK(pl.IsTriviallyValid(state) == !shouldFail);
     144          59 :     if (shouldFail) {
     145          33 :         BOOST_CHECK(state.GetRejectReason() == rejectReason);
     146             :     }
     147          59 : }
     148             : 
     149           2 : static void SpecialTxTrivialValidator(const UniValue& tests)
     150             : {
     151          61 :     for (size_t i = 1; i < tests.size(); i++) {
     152          59 :         const auto& test = tests[i];
     153             : 
     154          59 :         uint256 txHash;
     155         118 :         std::string txType;
     156         118 :         CMutableTransaction mtx;
     157         118 :         std::string rejectReason = "";
     158          59 :         try {
     159          59 :             txHash = uint256S(test[0].get_str());
     160             : 
     161          59 :             txType = test[1].get_str();
     162         177 :             CDataStream stream(ParseHex(test[2].get_str()), SER_NETWORK, PROTOCOL_VERSION);
     163          59 :             stream >> mtx;
     164             : 
     165          59 :             bool shouldFail = test.size() > 3;
     166          59 :             if (shouldFail) {
     167           9 :                 rejectReason = test[3].get_str();
     168             :             }
     169         118 :             BOOST_CHECK(mtx.GetHash() == txHash);
     170             : 
     171          59 :             switch (mtx.nType) {
     172          18 :             case CTransaction::TxType::PROREG:
     173          36 :                 BOOST_CHECK(txType == "proreg");
     174          18 :                 TrivialCheckSpecialTx<ProRegPL>(mtx, shouldFail, rejectReason);
     175             :                 break;
     176          17 :             case CTransaction::TxType::PROUPSERV:
     177          34 :                 BOOST_CHECK(txType == "proupserv");
     178          17 :                 TrivialCheckSpecialTx<ProUpServPL>(mtx, shouldFail, rejectReason);
     179             :                 break;
     180          11 :             case CTransaction::TxType::PROUPREG:
     181          22 :                 BOOST_CHECK(txType == "proupreg");
     182          11 :                 TrivialCheckSpecialTx<ProUpRegPL>(mtx, shouldFail, rejectReason);
     183             :                 break;
     184          13 :             case CTransaction::TxType::PROUPREV:
     185          26 :                 BOOST_CHECK(txType == "prouprev");
     186          13 :                 TrivialCheckSpecialTx<ProUpRevPL>(mtx, shouldFail, rejectReason);
     187             :                 break;
     188           0 :             default:
     189           0 :                 BOOST_CHECK(false);
     190             :             }
     191           0 :         } catch (...) {
     192           0 :             std::string strTest = test.write();
     193           0 :             BOOST_ERROR("Bad test, couldn't deserialize data: " << strTest);
     194           0 :             continue;
     195             :         }
     196             :     }
     197           2 : }
     198             : 
     199           2 : BOOST_AUTO_TEST_CASE(protx_validation_test)
     200             : {
     201           1 :     LOCK(cs_main);
     202             : 
     203           2 :     CMutableTransaction mtx;
     204           2 :     CValidationState state;
     205             : 
     206             :     // v1 can only be Type=0
     207           1 :     mtx.nType = CTransaction::TxType::PROREG;
     208           1 :     mtx.nVersion = CTransaction::TxVersion::LEGACY;
     209           2 :     BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
     210           3 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-type-version");
     211             : 
     212             :     // version >= Sapling, type = 0, payload != null.
     213           1 :     mtx.nType = CTransaction::TxType::NORMAL;
     214           2 :     mtx.extraPayload = std::vector<uint8_t>(10, 1);
     215           1 :     mtx.nVersion = CTransaction::TxVersion::SAPLING;
     216           2 :     BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
     217           3 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-type-payload");
     218             : 
     219             :     // version >= Sapling, type = 0, payload == null --> pass
     220           1 :     mtx.extraPayload = nullopt;
     221           2 :     BOOST_CHECK(CheckSpecialTxNoContext(CTransaction(mtx), state));
     222             : 
     223             :     // nVersion>=2 and nType!=0 without extrapayload
     224           1 :     mtx.nType = CTransaction::TxType::PROREG;
     225           2 :     BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
     226           4 :     BOOST_CHECK(state.GetRejectReason().find("without extra payload"));
     227           3 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-payload-empty");
     228             : 
     229             :     // Size limits
     230           2 :     mtx.extraPayload = std::vector<uint8_t>(MAX_SPECIALTX_EXTRAPAYLOAD + 1, 1);
     231           2 :     BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
     232           3 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-payload-oversize");
     233             : 
     234             :     // Remove one element, so now it passes the size check
     235           1 :     mtx.extraPayload->pop_back();
     236           2 :     BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
     237           3 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-protx-payload");
     238             : 
     239             :     // valid payload but invalid inputs hash
     240           1 :     mtx.extraPayload->clear();
     241           2 :     ProRegPL pl = GetRandomProRegPayload();
     242           1 :     SetTxPayload(mtx, pl);
     243           2 :     BOOST_CHECK(!CheckSpecialTxNoContext(CTransaction(mtx), state));
     244           3 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-protx-inputs-hash");
     245             : 
     246             :     // all good.
     247           1 :     mtx.vin.emplace_back(GetRandHash(), 0);
     248           1 :     mtx.extraPayload->clear();
     249           1 :     pl.inputsHash = CalcTxInputsHash(CTransaction(mtx));
     250           1 :     SetTxPayload(mtx, pl);
     251           2 :     BOOST_CHECK(CheckSpecialTxNoContext(CTransaction(mtx), state));
     252           1 : }
     253             : 
     254           2 : BOOST_AUTO_TEST_CASE(proreg_setpayload_test)
     255             : {
     256           2 :     const ProRegPL& pl = GetRandomProRegPayload();
     257             : 
     258           2 :     CMutableTransaction mtx;
     259           1 :     SetTxPayload(mtx, pl);
     260           2 :     ProRegPL pl2;
     261           2 :     BOOST_CHECK(GetTxPayload(mtx, pl2));
     262           3 :     BOOST_CHECK(pl.collateralOutpoint == pl2.collateralOutpoint);
     263           2 :     BOOST_CHECK(pl.addr  == pl2.addr);
     264           2 :     BOOST_CHECK(pl.keyIDOwner == pl2.keyIDOwner);
     265           3 :     BOOST_CHECK(pl.pubKeyOperator == pl2.pubKeyOperator);
     266           2 :     BOOST_CHECK(pl.keyIDVoting == pl2.keyIDVoting);
     267           2 :     BOOST_CHECK(pl.scriptPayout == pl2.scriptPayout);
     268           2 :     BOOST_CHECK(pl.nOperatorReward  == pl2.nOperatorReward);
     269           2 :     BOOST_CHECK(pl.scriptOperatorPayout == pl2.scriptOperatorPayout);
     270           2 :     BOOST_CHECK(pl.inputsHash == pl2.inputsHash);
     271           2 :     BOOST_CHECK(pl.vchSig == pl2.vchSig);
     272           1 : }
     273             : 
     274           2 : BOOST_AUTO_TEST_CASE(proupserv_setpayload_test)
     275             : {
     276           2 :     const ProUpServPL& pl = GetRandomProUpServPayload();
     277             : 
     278           2 :     CMutableTransaction mtx;
     279           1 :     SetTxPayload(mtx, pl);
     280           2 :     ProUpServPL pl2;
     281           2 :     BOOST_CHECK(GetTxPayload(mtx, pl2));
     282           2 :     BOOST_CHECK(pl.proTxHash == pl2.proTxHash);
     283           2 :     BOOST_CHECK(pl.addr  == pl2.addr);
     284           2 :     BOOST_CHECK(pl.scriptOperatorPayout == pl2.scriptOperatorPayout);
     285           2 :     BOOST_CHECK(pl.inputsHash == pl2.inputsHash);
     286           3 :     BOOST_CHECK(pl.sig == pl2.sig);
     287           1 : }
     288             : 
     289           2 : BOOST_AUTO_TEST_CASE(proupreg_setpayload_test)
     290             : {
     291           2 :     const ProUpRegPL& pl = GetRandomProUpRegPayload();
     292             : 
     293           2 :     CMutableTransaction mtx;
     294           1 :     SetTxPayload(mtx, pl);
     295           2 :     ProUpRegPL pl2;
     296           2 :     BOOST_CHECK(GetTxPayload(mtx, pl2));
     297           2 :     BOOST_CHECK(pl.proTxHash == pl2.proTxHash);
     298           3 :     BOOST_CHECK(pl.pubKeyOperator == pl2.pubKeyOperator);
     299           2 :     BOOST_CHECK(pl.keyIDVoting == pl2.keyIDVoting);
     300           2 :     BOOST_CHECK(pl.scriptPayout == pl2.scriptPayout);
     301           2 :     BOOST_CHECK(pl.inputsHash == pl2.inputsHash);
     302           2 :     BOOST_CHECK(pl.vchSig == pl2.vchSig);
     303           1 : }
     304             : 
     305           2 : BOOST_AUTO_TEST_CASE(prouprev_setpayload_test)
     306             : {
     307           1 :     const ProUpRevPL& pl = GetRandomProUpRevPayload();
     308             : 
     309           2 :     CMutableTransaction mtx;
     310           1 :     SetTxPayload(mtx, pl);
     311           1 :     ProUpRevPL pl2;
     312           2 :     BOOST_CHECK(GetTxPayload(mtx, pl2));
     313           2 :     BOOST_CHECK(pl.proTxHash == pl2.proTxHash);
     314           2 :     BOOST_CHECK(pl.nReason == pl2.nReason);
     315           2 :     BOOST_CHECK(pl.inputsHash == pl2.inputsHash);
     316           3 :     BOOST_CHECK(pl.sig == pl2.sig);
     317           1 : }
     318             : 
     319           2 : BOOST_AUTO_TEST_CASE(proreg_checkstringsig_test)
     320             : {
     321           1 :     ProRegPL pl = GetRandomProRegPayload();
     322           1 :     pl.vchSig.clear();
     323           2 :     const CKey& key = GetRandomKey();
     324           3 :     BOOST_CHECK(CMessageSigner::SignMessage(pl.MakeSignString(), pl.vchSig, key));
     325             : 
     326           2 :     std::string strError;
     327           1 :     const CKeyID& keyID = key.GetPubKey().GetID();
     328           3 :     BOOST_CHECK(CMessageSigner::VerifyMessage(keyID, pl.vchSig, pl.MakeSignString(), strError));
     329             :     // Change owner address or script payout
     330           1 :     pl.keyIDOwner = GetRandomKeyID();
     331           3 :     BOOST_CHECK(!CMessageSigner::VerifyMessage(keyID, pl.vchSig, pl.MakeSignString(), strError));
     332           1 :     pl.scriptPayout = GetRandomScript();
     333           3 :     BOOST_CHECK(!CMessageSigner::VerifyMessage(keyID, pl.vchSig, pl.MakeSignString(), strError));
     334           1 : }
     335             : 
     336           2 : BOOST_AUTO_TEST_CASE(llmqcomm_setpayload_test)
     337             : {
     338           1 :     const llmq::LLMQCommPL& pl = GetRandomLLMQCommPayload();
     339             : 
     340           2 :     CMutableTransaction mtx;
     341           1 :     SetTxPayload(mtx, pl);
     342           2 :     llmq::LLMQCommPL pl2;
     343           2 :     BOOST_CHECK(GetTxPayload(mtx, pl2));
     344           2 :     BOOST_CHECK(pl.nHeight == pl2.nHeight);
     345           2 :     BOOST_CHECK(EqualCommitments(pl.commitment, pl2.commitment));
     346           1 : }
     347             : 
     348           2 : BOOST_AUTO_TEST_CASE(specialtx_trivial_valid)
     349             : {
     350           3 :     UniValue tests = read_json(std::string(json_tests::specialtx_valid, json_tests::specialtx_valid + sizeof(json_tests::specialtx_valid)));
     351           1 :     SpecialTxTrivialValidator(tests);
     352           1 : }
     353             : 
     354           2 : BOOST_AUTO_TEST_CASE(specialtx_trivial_invalid)
     355             : {
     356           3 :     UniValue tests = read_json(std::string(json_tests::specialtx_invalid, json_tests::specialtx_invalid + sizeof(json_tests::specialtx_invalid)));
     357           1 :     SpecialTxTrivialValidator(tests);
     358           1 : }
     359             : 
     360             : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.14