PIVX Core  5.6.99
P2P Digital Currency
evo_specialtx_tests.cpp
Go to the documentation of this file.
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 
9 
10 #include "consensus/validation.h"
11 #include "core_io.h"
12 #include "evo/providertx.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 static CKey GetRandomKey()
26 {
27  CKey key;
28  key.MakeNewKey(true);
29  return key;
30 }
31 
32 static CKeyID GetRandomKeyID()
33 {
34  return GetRandomKey().GetPubKey().GetID();
35 }
36 
37 static CBLSPublicKey GetRandomBLSKey()
38 {
39  CBLSSecretKey sk;
40  sk.MakeNewKey();
41  return sk.GetPublicKey();
42 }
43 
44 static CScript GetRandomScript()
45 {
46  return GetScriptForDestination(GetRandomKeyID());
47 }
48 
49 static ProRegPL GetRandomProRegPayload()
50 {
51  ProRegPL pl;
53  pl.collateralOutpoint.n = InsecureRandBits(2);
54  BOOST_CHECK(Lookup("57.12.210.11:51472", pl.addr, Params().GetDefaultPort(), false));
55  pl.keyIDOwner = GetRandomKeyID();
56  pl.pubKeyOperator = GetRandomBLSKey();
57  pl.keyIDVoting = GetRandomKeyID();
58  pl.scriptPayout = GetRandomScript();
59  pl.nOperatorReward = InsecureRandRange(10000);
60  pl.scriptOperatorPayout = GetRandomScript();
61  pl.inputsHash = GetRandHash();
62  pl.vchSig = InsecureRandBytes(63);
63  return pl;
64 }
65 
66 static ProUpServPL GetRandomProUpServPayload()
67 {
68  ProUpServPL pl;
69  pl.proTxHash = GetRandHash();
70  BOOST_CHECK(Lookup("127.0.0.1:51472", pl.addr, Params().GetDefaultPort(), false));
71  pl.scriptOperatorPayout = GetRandomScript();
72  pl.inputsHash = GetRandHash();
73  pl.sig.SetByteVector(InsecureRandBytes(BLS_CURVE_SIG_SIZE));
74  return pl;
75 }
76 
77 static ProUpRegPL GetRandomProUpRegPayload()
78 {
79  ProUpRegPL pl;
80  pl.proTxHash = GetRandHash();
81  pl.pubKeyOperator = GetRandomBLSKey();
82  pl.keyIDVoting = GetRandomKeyID();
83  pl.scriptPayout = GetRandomScript();
84  pl.inputsHash = GetRandHash();
85  pl.vchSig = InsecureRandBytes(63);
86  return pl;
87 }
88 
89 static ProUpRevPL GetRandomProUpRevPayload()
90 {
91  ProUpRevPL pl;
92  pl.proTxHash = GetRandHash();
93  pl.nReason = InsecureRand16();
94  pl.inputsHash = GetRandHash();
95  pl.sig.SetByteVector(InsecureRandBytes(BLS_CURVE_SIG_SIZE));
96  return pl;
97 }
98 
100 {
102  fc.nVersion = InsecureRand16();
103  fc.llmqType = InsecureRandBits(8);
104  fc.quorumHash = GetRandHash();
105  int vecsize = InsecureRandRange(500);
106  for (int i = 0; i < vecsize; i++) {
107  fc.signers.emplace_back((bool)InsecureRandBits(1));
108  fc.validMembers.emplace_back((bool)InsecureRandBits(1));
109  }
110  fc.quorumPublicKey.SetByteVector(InsecureRandBytes(BLS_CURVE_PUBKEY_SIZE));
112  fc.quorumSig.SetByteVector(InsecureRandBytes(BLS_CURVE_SIG_SIZE));
113  fc.membersSig.SetByteVector(InsecureRandBytes(BLS_CURVE_SIG_SIZE));
114  return fc;
115 }
116 
117 static llmq::LLMQCommPL GetRandomLLMQCommPayload()
118 {
119  llmq::LLMQCommPL pl;
120  pl.nHeight = InsecureRand32();
122  return pl;
123 }
124 
125 static bool EqualCommitments(const llmq::CFinalCommitment& a, const llmq::CFinalCommitment& b)
126 {
127  return a.nVersion == b.nVersion &&
128  a.llmqType == b.llmqType &&
129  a.quorumHash == b.quorumHash &&
130  a.signers == b.signers &&
133  a.quorumSig == b.quorumSig &&
134  a.membersSig == b.membersSig;
135 }
136 
137 template <typename T>
138 static void TrivialCheckSpecialTx(const CMutableTransaction& mtx, const bool shouldFail, const std::string& rejectReason)
139 {
140  T pl;
141  CValidationState state;
142  GetTxPayload(mtx, pl);
143  BOOST_CHECK(pl.IsTriviallyValid(state) == !shouldFail);
144  if (shouldFail) {
145  BOOST_CHECK(state.GetRejectReason() == rejectReason);
146  }
147 }
148 
149 static void SpecialTxTrivialValidator(const UniValue& tests)
150 {
151  for (size_t i = 1; i < tests.size(); i++) {
152  const auto& test = tests[i];
153 
154  uint256 txHash;
155  std::string txType;
157  std::string rejectReason = "";
158  try {
159  txHash = uint256S(test[0].get_str());
160 
161  txType = test[1].get_str();
162  CDataStream stream(ParseHex(test[2].get_str()), SER_NETWORK, PROTOCOL_VERSION);
163  stream >> mtx;
164 
165  bool shouldFail = test.size() > 3;
166  if (shouldFail) {
167  rejectReason = test[3].get_str();
168  }
169  BOOST_CHECK(mtx.GetHash() == txHash);
170 
171  switch (mtx.nType) {
172  case CTransaction::TxType::PROREG:
173  BOOST_CHECK(txType == "proreg");
174  TrivialCheckSpecialTx<ProRegPL>(mtx, shouldFail, rejectReason);
175  break;
176  case CTransaction::TxType::PROUPSERV:
177  BOOST_CHECK(txType == "proupserv");
178  TrivialCheckSpecialTx<ProUpServPL>(mtx, shouldFail, rejectReason);
179  break;
180  case CTransaction::TxType::PROUPREG:
181  BOOST_CHECK(txType == "proupreg");
182  TrivialCheckSpecialTx<ProUpRegPL>(mtx, shouldFail, rejectReason);
183  break;
184  case CTransaction::TxType::PROUPREV:
185  BOOST_CHECK(txType == "prouprev");
186  TrivialCheckSpecialTx<ProUpRevPL>(mtx, shouldFail, rejectReason);
187  break;
188  default:
189  BOOST_CHECK(false);
190  }
191  } catch (...) {
192  std::string strTest = test.write();
193  BOOST_ERROR("Bad test, couldn't deserialize data: " << strTest);
194  continue;
195  }
196  }
197 }
198 
199 BOOST_AUTO_TEST_CASE(protx_validation_test)
200 {
201  LOCK(cs_main);
202 
204  CValidationState state;
205 
206  // v1 can only be Type=0
207  mtx.nType = CTransaction::TxType::PROREG;
208  mtx.nVersion = CTransaction::TxVersion::LEGACY;
210  BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-type-version");
211 
212  // version >= Sapling, type = 0, payload != null.
213  mtx.nType = CTransaction::TxType::NORMAL;
214  mtx.extraPayload = std::vector<uint8_t>(10, 1);
217  BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-type-payload");
218 
219  // version >= Sapling, type = 0, payload == null --> pass
220  mtx.extraPayload = nullopt;
222 
223  // nVersion>=2 and nType!=0 without extrapayload
224  mtx.nType = CTransaction::TxType::PROREG;
226  BOOST_CHECK(state.GetRejectReason().find("without extra payload"));
227  BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-payload-empty");
228 
229  // Size limits
230  mtx.extraPayload = std::vector<uint8_t>(MAX_SPECIALTX_EXTRAPAYLOAD + 1, 1);
232  BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-payload-oversize");
233 
234  // Remove one element, so now it passes the size check
235  mtx.extraPayload->pop_back();
237  BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-protx-payload");
238 
239  // valid payload but invalid inputs hash
240  mtx.extraPayload->clear();
241  ProRegPL pl = GetRandomProRegPayload();
242  SetTxPayload(mtx, pl);
244  BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-protx-inputs-hash");
245 
246  // all good.
247  mtx.vin.emplace_back(GetRandHash(), 0);
248  mtx.extraPayload->clear();
250  SetTxPayload(mtx, pl);
252 }
253 
254 BOOST_AUTO_TEST_CASE(proreg_setpayload_test)
255 {
256  const ProRegPL& pl = GetRandomProRegPayload();
257 
259  SetTxPayload(mtx, pl);
260  ProRegPL pl2;
261  BOOST_CHECK(GetTxPayload(mtx, pl2));
263  BOOST_CHECK(pl.addr == pl2.addr);
264  BOOST_CHECK(pl.keyIDOwner == pl2.keyIDOwner);
270  BOOST_CHECK(pl.inputsHash == pl2.inputsHash);
271  BOOST_CHECK(pl.vchSig == pl2.vchSig);
272 }
273 
274 BOOST_AUTO_TEST_CASE(proupserv_setpayload_test)
275 {
276  const ProUpServPL& pl = GetRandomProUpServPayload();
277 
279  SetTxPayload(mtx, pl);
280  ProUpServPL pl2;
281  BOOST_CHECK(GetTxPayload(mtx, pl2));
282  BOOST_CHECK(pl.proTxHash == pl2.proTxHash);
283  BOOST_CHECK(pl.addr == pl2.addr);
285  BOOST_CHECK(pl.inputsHash == pl2.inputsHash);
286  BOOST_CHECK(pl.sig == pl2.sig);
287 }
288 
289 BOOST_AUTO_TEST_CASE(proupreg_setpayload_test)
290 {
291  const ProUpRegPL& pl = GetRandomProUpRegPayload();
292 
294  SetTxPayload(mtx, pl);
295  ProUpRegPL pl2;
296  BOOST_CHECK(GetTxPayload(mtx, pl2));
297  BOOST_CHECK(pl.proTxHash == pl2.proTxHash);
301  BOOST_CHECK(pl.inputsHash == pl2.inputsHash);
302  BOOST_CHECK(pl.vchSig == pl2.vchSig);
303 }
304 
305 BOOST_AUTO_TEST_CASE(prouprev_setpayload_test)
306 {
307  const ProUpRevPL& pl = GetRandomProUpRevPayload();
308 
310  SetTxPayload(mtx, pl);
311  ProUpRevPL pl2;
312  BOOST_CHECK(GetTxPayload(mtx, pl2));
313  BOOST_CHECK(pl.proTxHash == pl2.proTxHash);
314  BOOST_CHECK(pl.nReason == pl2.nReason);
315  BOOST_CHECK(pl.inputsHash == pl2.inputsHash);
316  BOOST_CHECK(pl.sig == pl2.sig);
317 }
318 
319 BOOST_AUTO_TEST_CASE(proreg_checkstringsig_test)
320 {
321  ProRegPL pl = GetRandomProRegPayload();
322  pl.vchSig.clear();
323  const CKey& key = GetRandomKey();
325 
326  std::string strError;
327  const CKeyID& keyID = key.GetPubKey().GetID();
329  // Change owner address or script payout
330  pl.keyIDOwner = GetRandomKeyID();
331  BOOST_CHECK(!CMessageSigner::VerifyMessage(keyID, pl.vchSig, pl.MakeSignString(), strError));
332  pl.scriptPayout = GetRandomScript();
333  BOOST_CHECK(!CMessageSigner::VerifyMessage(keyID, pl.vchSig, pl.MakeSignString(), strError));
334 }
335 
336 BOOST_AUTO_TEST_CASE(llmqcomm_setpayload_test)
337 {
338  const llmq::LLMQCommPL& pl = GetRandomLLMQCommPayload();
339 
341  SetTxPayload(mtx, pl);
342  llmq::LLMQCommPL pl2;
343  BOOST_CHECK(GetTxPayload(mtx, pl2));
344  BOOST_CHECK(pl.nHeight == pl2.nHeight);
345  BOOST_CHECK(EqualCommitments(pl.commitment, pl2.commitment));
346 }
347 
348 BOOST_AUTO_TEST_CASE(specialtx_trivial_valid)
349 {
350  UniValue tests = read_json(std::string(json_tests::specialtx_valid, json_tests::specialtx_valid + sizeof(json_tests::specialtx_valid)));
351  SpecialTxTrivialValidator(tests);
352 }
353 
354 BOOST_AUTO_TEST_CASE(specialtx_trivial_invalid)
355 {
356  UniValue tests = read_json(std::string(json_tests::specialtx_invalid, json_tests::specialtx_invalid + sizeof(json_tests::specialtx_invalid)));
357  SpecialTxTrivialValidator(tests);
358 }
359 
#define BLS_CURVE_SIG_SIZE
Definition: bls_wrapper.h:32
#define BLS_CURVE_PUBKEY_SIZE
Definition: bls_wrapper.h:31
const CChainParams & Params()
Return the currently selected parameters.
uint256 hash
Definition: transaction.h:35
uint32_t n
Definition: transaction.h:36
void MakeNewKey()
Definition: bls_wrapper.cpp:54
CBLSPublicKey GetPublicKey() const
Definition: bls_wrapper.cpp:99
void SetByteVector(const std::vector< uint8_t > &vecBytes)
Definition: bls_wrapper.h:97
An encapsulated private key.
Definition: key.h:30
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:158
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:186
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:21
static bool SignMessage(const std::string &strMessage, std::vector< unsigned char > &vchSigRet, const CKey &key)
Sign the message, returns true if successful.
static bool VerifyMessage(const CPubKey &pubkey, const std::vector< unsigned char > &vchSig, const std::string &strMessage, std::string &strErrorRet)
Verify the message signature, returns true if successful.
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:167
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:244
Capture information about block/transaction validation.
Definition: validation.h:24
std::string GetRejectReason() const
Definition: validation.h:94
CScript scriptOperatorPayout
Definition: providertx.h:36
CKeyID keyIDVoting
Definition: providertx.h:33
COutPoint collateralOutpoint
Definition: providertx.h:29
uint16_t nOperatorReward
Definition: providertx.h:35
CScript scriptPayout
Definition: providertx.h:34
CBLSPublicKey pubKeyOperator
Definition: providertx.h:32
uint256 inputsHash
Definition: providertx.h:37
std::vector< unsigned char > vchSig
Definition: providertx.h:38
std::string MakeSignString() const
Definition: providertx.cpp:11
CKeyID keyIDOwner
Definition: providertx.h:31
CService addr
Definition: providertx.h:30
CKeyID keyIDVoting
Definition: providertx.h:113
CScript scriptPayout
Definition: providertx.h:114
uint256 proTxHash
Definition: providertx.h:110
std::vector< unsigned char > vchSig
Definition: providertx.h:116
CBLSPublicKey pubKeyOperator
Definition: providertx.h:112
uint256 inputsHash
Definition: providertx.h:115
uint16_t nReason
Definition: providertx.h:152
uint256 inputsHash
Definition: providertx.h:153
uint256 proTxHash
Definition: providertx.h:151
CBLSSignature sig
Definition: providertx.h:154
uint256 inputsHash
Definition: providertx.h:83
CService addr
Definition: providertx.h:81
uint256 proTxHash
Definition: providertx.h:80
CBLSSignature sig
Definition: providertx.h:84
CScript scriptOperatorPayout
Definition: providertx.h:82
size_t size() const
Definition: univalue.h:68
std::vector< bool > validMembers
std::vector< bool > signers
CFinalCommitment commitment
256-bit opaque blob.
Definition: uint256.h:138
BOOST_AUTO_TEST_SUITE_END()
UniValue read_json(const std::string &jsondata)
llmq::CFinalCommitment GetRandomLLMQCommitment()
BOOST_AUTO_TEST_CASE(protx_validation_test)
#define T(expected, seed, data)
@ LOCK
Definition: lockunlock.h:16
@ SAPLING
Definition: logging.h:63
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:80
bool Lookup(const std::string &name, std::vector< CService > &vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
Definition: netbase.cpp:177
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK(expr)
Definition: object.cpp:17
uint256 GetRandHash() noexcept
Definition: random.cpp:596
@ SER_NETWORK
Definition: serialize.h:174
uint256 CalcTxInputsHash(const CTransaction &tx)
bool CheckSpecialTxNoContext(const CTransaction &tx, CValidationState &state)
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a PIVX scriptPubKey for the given CTxDestination.
Definition: standard.cpp:278
A mutable version of CTransaction.
Definition: transaction.h:409
Optional< std::vector< uint8_t > > extraPayload
Definition: transaction.h:416
std::vector< CTxIn > vin
Definition: transaction.h:410
void SetTxPayload(CMutableTransaction &tx, const T &payload)
Definition: transaction.h:486
bool GetTxPayload(const std::vector< unsigned char > &payload, T &obj)
Definition: transaction.h:464
uint256 uint256S(const char *str)
Definition: uint256.h:157
std::vector< unsigned char > ParseHex(const char *psz)