PIVX Core  5.6.99
P2P Digital Currency
test_pivx.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2013 The Bitcoin Core developers
2 // Copyright (c) 2017-2022 The PIVX Core developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #define BOOST_TEST_MODULE Pivx Test Suite
7 
8 #include "test/test_pivx.h"
9 
10 #include "blockassembler.h"
11 #include "consensus/merkle.h"
12 #include "bls/bls_wrapper.h"
13 #include "guiinterface.h"
14 #include "evo/deterministicmns.h"
15 #include "evo/evodb.h"
17 #include "llmq/quorums_init.h"
18 #include "miner.h"
19 #include "net_processing.h"
20 #include "rpc/server.h"
21 #include "rpc/register.h"
22 #include "pow.h"
23 #include "script/sigcache.h"
24 #include "sporkdb.h"
25 #include "streams.h"
26 #include "txmempool.h"
27 #include "validation.h"
28 
29 #include <boost/test/unit_test.hpp>
30 
31 std::unique_ptr<CConnman> g_connman;
32 
33 CClientUIInterface uiInterface; // Declared but not defined in guiinterface.h
34 
37 static FastRandomContext g_insecure_rand_ctx_temp_path;
38 
40 static uint256 GetUintFromEnv(const std::string& env_name)
41 {
42  const char* num = std::getenv(env_name.c_str());
43  if (!num) return {};
44  return uint256S(num);
45 }
46 
48 {
49  // Should be enough to get the seed once for the process
50  static uint256 seed{};
51  static const std::string RANDOM_CTX_SEED{"RANDOM_CTX_SEED"};
52  if (seed.IsNull()) seed = GetUintFromEnv(RANDOM_CTX_SEED);
53  if (seed.IsNull()) seed = GetRandHash();
54  LogPrintf("%s: Setting random seed for current tests to %s=%s\n", __func__, RANDOM_CTX_SEED, seed.GetHex());
55  ctx = FastRandomContext(seed);
56 }
57 
58 extern bool fPrintToConsole;
59 extern void noui_connect();
60 
61 std::ostream& operator<<(std::ostream& os, const uint256& num)
62 {
63  os << num.ToString();
64  return os;
65 }
66 
67 BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
68  : m_path_root{fs::temp_directory_path() / "test_pivx" / std::to_string(g_insecure_rand_ctx_temp_path.rand32())}
69 {
70  ECC_Start();
71  BLSInit();
74  fCheckBlockIndex = true;
75  SelectParams(chainName);
76  SeedInsecureRand();
77  evoDb.reset(new CEvoDB(1 << 20, true, true));
79 }
80 
82 {
83  fs::remove_all(m_path_root);
84  ECC_Stop();
85  deterministicMNManager.reset();
86  evoDb.reset();
87 }
88 
89 fs::path BasicTestingSetup::SetDataDir(const std::string& name)
90 {
91  fs::path ret = m_path_root / name;
92  fs::create_directories(ret);
93  gArgs.ForceSetArg("-datadir", ret.string());
94  return ret;
95 }
96 
97 TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
98 {
99  SetDataDir("tempdir");
101 
102  // Start the lightweight task scheduler thread
103  CScheduler::Function serviceLoop = std::bind(&CScheduler::serviceQueue, &scheduler);
104  threadGroup.create_thread(std::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
105 
106  // Note that because we don't bother running a scheduler thread here,
107  // callbacks via CValidationInterface are unreliable, but that's OK,
108  // our unit tests aren't testing multiple parts of the code at once.
110 
111  g_connman = std::make_unique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
112  connman = g_connman.get();
113 
114  // Register EvoNotificationInterface
117 
118  // Ideally we'd move all the RPC tests to the functional testing framework
119  // instead of unit tests, but for now we need these here.
120  RegisterAllCoreRPCCommands(tableRPC);
121  zerocoinDB.reset(new CZerocoinDB(0, true));
122  pSporkDB.reset(new CSporkDB(0, true));
123  pblocktree.reset(new CBlockTreeDB(1 << 20, true));
124  pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
125  pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
127  if (!LoadGenesisBlock()) {
128  throw std::runtime_error("Error initializing block database");
129  }
130  {
131  CValidationState state;
132  bool ok = ActivateBestChain(state);
133  BOOST_CHECK(ok);
134  }
136  for (int i=0; i < nScriptCheckThreads-1; i++)
137  threadGroup.create_thread(&ThreadScriptCheck);
139 }
140 
142 {
143  scheduler.stop();
145  threadGroup.interrupt_all();
146  threadGroup.join_all();
150  g_connman.reset();
151  peerLogic.reset();
154  pcoinsTip.reset();
155  pcoinsdbview.reset();
156  pblocktree.reset();
157  zerocoinDB.reset();
158  pSporkDB.reset();
160 }
161 
162 // Test chain only available on regtest
164 {
165  // if blockCount is over PoS start, delay it to 100 blocks after.
166  if (blockCount > Params().GetConsensus().vUpgrades[Consensus::UPGRADE_POS].nActivationHeight) {
169  }
170 
171  // Generate a blockCount-block chain:
172  coinbaseKey.MakeNewKey(true);
173  CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
174  for (int i = 0; i < blockCount; i++)
175  {
176  std::vector<CMutableTransaction> noTxns;
177  CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
178  coinbaseTxns.push_back(*b.vtx[0]);
179  }
180 }
181 
182 // Create a new block with coinbase paying to scriptPubKey, and try to add it to the current chain.
183 // Include given transactions, and, if fNoMempoolTx=true, remove transactions coming from the mempool.
184 CBlock TestChainSetup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey, bool fNoMempoolTx)
185 {
186  CBlock block = CreateBlock(txns, scriptPubKey, fNoMempoolTx);
187  ProcessNewBlock(std::make_shared<const CBlock>(block), nullptr);
188  return block;
189 }
190 
191 CBlock TestChainSetup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CKey& scriptKey)
192 {
193  CScript scriptPubKey = CScript() << ToByteVector(scriptKey.GetPubKey()) << OP_CHECKSIG;
194  return CreateAndProcessBlock(txns, scriptPubKey);
195 }
196 
197 CBlock TestChainSetup::CreateBlock(const std::vector<CMutableTransaction>& txns,
198  const CScript& scriptPubKey,
199  bool fNoMempoolTx,
200  bool fTestBlockValidity,
201  bool fIncludeQfc,
202  CBlockIndex* customPrevBlock)
203 {
204  std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(
205  Params(), DEFAULT_PRINTPRIORITY).CreateNewBlock(scriptPubKey,
206  nullptr, // wallet
207  false, // fProofOfStake
208  nullptr, // availableCoins
209  fNoMempoolTx,
210  fTestBlockValidity,
211  customPrevBlock,
212  true,
213  fIncludeQfc);
214  std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(pblocktemplate->block);
215 
216  // Add passed-in txns:
217  for (const CMutableTransaction& tx : txns) {
218  pblock->vtx.push_back(MakeTransactionRef(tx));
219  }
220 
221  const int nHeight = (customPrevBlock != nullptr ? customPrevBlock->nHeight + 1
222  : WITH_LOCK(cs_main, return chainActive.Height()) + 1);
223 
224  // Re-compute sapling root
225  pblock->hashFinalSaplingRoot = CalculateSaplingTreeRoot(pblock.get(), nHeight, Params());
226 
227  // Find valid PoW
228  assert(SolveBlock(pblock, nHeight));
229  return *pblock;
230 }
231 
232 CBlock TestChainSetup::CreateBlock(const std::vector<CMutableTransaction>& txns, const CKey& scriptKey,
233  bool fTestBlockValidity)
234 {
235  CScript scriptPubKey = CScript() << ToByteVector(scriptKey.GetPubKey()) << OP_CHECKSIG;
236  return CreateBlock(txns, scriptPubKey, fTestBlockValidity);
237 }
238 
239 std::shared_ptr<CBlock> FinalizeBlock(std::shared_ptr<CBlock> pblock)
240 {
241  pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
242  while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits)) { ++(pblock->nNonce); }
243  return pblock;
244 }
245 
247 {
248 }
249 
251 {
252  CTransaction txn(tx);
253  return FromTx(txn);
254 }
255 
257 {
258  return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, nHeight,
260 }
261 
262 [[noreturn]] void Shutdown(void* parg)
263 {
264  std::exit(0);
265 }
266 
267 [[noreturn]] void StartShutdown()
268 {
269  std::exit(0);
270 }
271 
273 {
274  return false;
275 }
bool SolveBlock(std::shared_ptr< CBlock > &pblock, int nHeight)
Modify the nonce/extranonce in a block.
uint256 CalculateSaplingTreeRoot(CBlock *pblock, int nHeight, const CChainParams &chainparams)
bool BLSInit()
void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivationHeight)
Allows modifying the network upgrade regtest parameters.
void SelectParams(const std::string &network)
Sets the params returned by Params() to those for the given chain name.
const CChainParams & Params()
Return the currently selected parameters.
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition: system.cpp:489
Generate a new block.
std::unique_ptr< CBlockTemplate > CreateNewBlock(const CScript &scriptPubKeyIn, CWallet *pwallet=nullptr, bool fProofOfStake=false, std::vector< CStakeableOutput > *availableCoins=nullptr, bool fNoMempoolTx=false, bool fTestValidity=true, CBlockIndex *prevBlock=nullptr, bool stopPoSOnNewBlock=true, bool fIncludeQfc=true)
Construct a new block template with coinbase to scriptPubKeyIn.
CBaseChainParams defines the base parameters (shared between pivx-cli and pivxd) of a given instance ...
Definition: block.h:80
std::vector< CTransactionRef > vtx
Definition: block.h:83
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:139
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:151
Access to the block database (blocks/index/)
Definition: txdb.h:128
int Height() const
Return the maximal height in the chain.
Definition: chain.h:450
Signals for UI communication.
Definition: guiinterface.h:32
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:283
CCoinsView backed by the LevelDB coin database (chainstate/)
Definition: txdb.h:71
Definition: evodb.h:32
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
void UnregisterBackgroundSignalScheduler()
Unregister a CScheduler to give callbacks which should run in the background - these callbacks will n...
void RegisterBackgroundSignalScheduler(CScheduler &scheduler)
Register a CScheduler to give callbacks which should run in the background (may only be called once)
void FlushBackgroundCallbacks()
Call any remaining callbacks on the calling thread.
void serviceQueue()
Definition: scheduler.cpp:22
void stop(bool drain=false)
Definition: scheduler.cpp:73
std::function< void(void)> Function
Definition: scheduler.h:45
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
CTxMemPoolEntry stores data about the corresponding transaction, as well as data about all in-mempool...
Definition: txmempool.h:55
Capture information about block/transaction validation.
Definition: validation.h:24
Zerocoin database (zerocoin/)
Definition: txdb.h:152
Fast randomness source.
Definition: random.h:107
std::string ToString() const
Definition: uint256.cpp:65
256-bit opaque blob.
Definition: uint256.h:138
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
std::unique_ptr< CEvoDB > evoDb
Definition: evodb.cpp:10
void ECC_Start()
Initialize the elliptic curve support.
Definition: key.cpp:344
void ECC_Stop()
Deinitialize the elliptic curve support.
Definition: key.cpp:361
uint256 BlockMerkleRoot(const CBlock &block, bool *mutated)
Definition: merkle.cpp:154
@ UPGRADE_V3_4
Definition: params.h:34
@ UPGRADE_POS
Definition: params.h:28
void DestroyLLMQSystem()
void InterruptLLMQSystem()
void InitLLMQSystem(CEvoDB &evoDb, CScheduler *scheduler, bool unitTests)
Definition: uint256.h:212
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:80
#define BOOST_CHECK(expr)
Definition: object.cpp:17
bool CheckProofOfWork(uint256 hash, unsigned int nBits)
Check whether a block hash satisfies the proof-of-work requirement specified by nBits.
Definition: pow.cpp:122
uint256 GetRandHash() noexcept
Definition: random.cpp:596
const char * name
Definition: rest.cpp:37
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:43
@ OP_CHECKSIG
Definition: script.h:166
CRPCTable tableRPC
Definition: server.cpp:565
void InitSignatureCache()
Definition: sigcache.cpp:74
Basic testing setup.
Definition: test_pivx.h:51
BasicTestingSetup(const std::string &chainName=CBaseChainParams::MAIN)
Definition: test_pivx.cpp:67
fs::path SetDataDir(const std::string &name)
Definition: test_pivx.cpp:89
const fs::path m_path_root
Definition: test_pivx.h:60
A mutable version of CTransaction.
Definition: transaction.h:409
TestChainSetup(int blockCount)
Definition: test_pivx.cpp:163
std::vector< CTransaction > coinbaseTxns
Definition: test_pivx.h:117
CBlock CreateBlock(const std::vector< CMutableTransaction > &txns, const CScript &scriptPubKey, bool fNoMempoolTx=true, bool fTestBlockValidity=true, bool fIncludeQfc=true, CBlockIndex *customPrevBlock=nullptr)
Definition: test_pivx.cpp:197
CBlock CreateAndProcessBlock(const std::vector< CMutableTransaction > &txns, const CScript &scriptPubKey, bool fNoMempoolTx=true)
Definition: test_pivx.cpp:184
CKey coinbaseKey
Definition: test_pivx.h:118
CAmount nFee
Definition: test_pivx.h:139
unsigned int sigOpCount
Definition: test_pivx.h:143
bool spendsCoinbaseOrCoinstake
Definition: test_pivx.h:142
int64_t nTime
Definition: test_pivx.h:140
unsigned int nHeight
Definition: test_pivx.h:141
CTxMemPoolEntry FromTx(const CMutableTransaction &tx)
Definition: test_pivx.cpp:250
EvoNotificationInterface * pEvoNotificationInterface
Definition: test_pivx.h:74
CScheduler scheduler
Definition: test_pivx.h:75
CConnman * connman
Definition: test_pivx.h:73
TestingSetup(const std::string &chainName=CBaseChainParams::MAIN)
Definition: test_pivx.cpp:97
boost::thread_group threadGroup
Definition: test_pivx.h:72
std::unique_ptr< PeerLogicValidation > peerLogic
Definition: test_pivx.h:76
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:247
ArgsManager gArgs
Definition: system.cpp:89
void SetupEnvironment()
Definition: system.cpp:1043
void ClearDatadirCache()
Definition: system.cpp:761
std::unique_ptr< CConnman > g_connman
Definition: test_pivx.cpp:31
std::ostream & operator<<(std::ostream &os, const uint256 &num)
Definition: test_pivx.cpp:61
CClientUIInterface uiInterface
Definition: test_pivx.cpp:33
bool ShutdownRequested()
Definition: test_pivx.cpp:272
std::shared_ptr< CBlock > FinalizeBlock(std::shared_ptr< CBlock > pblock)
Definition: test_pivx.cpp:239
bool fPrintToConsole
void Seed(FastRandomContext &ctx)
Seed the given random ctx or use the seed passed in via an environment var.
Definition: test_pivx.cpp:47
void Shutdown(void *parg)
Definition: test_pivx.cpp:262
void StartShutdown()
Definition: test_pivx.cpp:267
void noui_connect()
Definition: noui.cpp:49
FastRandomContext g_insecure_rand_ctx
Definition: test_pivx.cpp:35
uint256 uint256S(const char *str)
Definition: uint256.h:157
bool LoadGenesisBlock()
Ensures we have a genesis block in the block tree, possibly writing one to disk.
std::unique_ptr< CBlockTreeDB > pblocktree
Global variable that points to the active block tree (protected by cs_main)
Definition: validation.cpp:207
bool fCheckBlockIndex
Definition: validation.cpp:98
std::unique_ptr< CZerocoinDB > zerocoinDB
Global variable that points to the zerocoin database (protected by cs_main)
Definition: validation.cpp:208
int nScriptCheckThreads
Definition: validation.cpp:93
std::unique_ptr< CSporkDB > pSporkDB
Global variable that points to the spork database (protected by cs_main)
Definition: validation.cpp:209
bool ProcessNewBlock(const std::shared_ptr< const CBlock > &pblock, const FlatFilePos *dbp)
Process an incoming block.
bool ActivateBestChain(CValidationState &state, std::shared_ptr< const CBlock > pblock)
Make the best chain active, in multiple steps.
std::unique_ptr< CCoinsViewCache > pcoinsTip
Global variable that points to the active CCoinsView (protected by cs_main)
Definition: validation.cpp:206
void ThreadScriptCheck()
Run an instance of the script checking thread.
std::unique_ptr< CCoinsViewDB > pcoinsdbview
Global variable that points to the coins database (protected by cs_main)
Definition: validation.cpp:205
void UnloadBlockIndex()
Unload database information.
CChain chainActive
The currently-connected chain of blocks (protected by cs_main).
Definition: validation.cpp:84
CMainSignals & GetMainSignals()
void UnregisterAllValidationInterfaces()
Unregister all wallets from core.
void RegisterValidationInterface(CValidationInterface *pwalletIn)
Register a wallet to receive updates from core.