PIVX Core  5.6.99
P2P Digital Currency
walletprocessblock.cpp
Go to the documentation of this file.
1 // Copyright (c) 2021 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 "bench.h"
6 #include "blockassembler.h"
7 #include "chainparams.h"
8 #include "consensus/merkle.h"
9 #include "evo/deterministicmns.h"
10 #include "evo/evodb.h"
12 
14 #include "scheduler.h"
15 #include "script/sigcache.h"
16 #include "sporkdb.h"
17 #include "txdb.h"
18 #include "validation.h"
19 #include "wallet/wallet.h"
20 
21 #include <boost/thread.hpp>
22 
23 // Number of blocks that will be created to make noise on this benchmark
24 const unsigned int CREATE_BLOCK = 500;
25 // Number of transparent transactions that will be created to make noise on this benchmark.
26 const unsigned int CREATE_TRANSACTIONS_PER_BLOCK = 20;
27 
28 static CMutableTransaction NewCoinbase(const int nHeight, const CScript& scriptPubKey)
29 {
30  CMutableTransaction txCoinbase;
31  txCoinbase.vout.emplace_back();
32  txCoinbase.vout[0].SetEmpty();
33  txCoinbase.vout[0].scriptPubKey = scriptPubKey;
34  txCoinbase.vin.emplace_back();
35  txCoinbase.vin[0].scriptSig = CScript() << nHeight << OP_0;
36  txCoinbase.vout[0].nValue = GetBlockValue(nHeight);
37  return txCoinbase;
38 }
39 
40 std::shared_ptr<CBlock> createAndProcessBlock(
41  const CChainParams& params,
42  const CScript& coinbaseScript,
43  const std::vector<CMutableTransaction>& txns,
44  CBlockIndex* prevpindex)
45 {
46  int nextHeight = prevpindex ? prevpindex->nHeight + 1 : 0;
47  CMutableTransaction coinbaseTx = NewCoinbase(nextHeight, coinbaseScript);
48 
49  CBlock block;
50  block.hashMerkleRoot = BlockMerkleRoot(block);
51  if (prevpindex) block.hashPrevBlock = prevpindex->GetBlockHash();
52  block.vtx.emplace_back(MakeTransactionRef(coinbaseTx));
53  for (const CMutableTransaction& tx : txns) {
54  block.vtx.emplace_back(MakeTransactionRef(tx));
55  }
56  block.hashFinalSaplingRoot = CalculateSaplingTreeRoot(&block, nextHeight, params);
57 
58  const auto& blockHash = block.GetHash();
59  CBlockIndex* fakeIndex = new CBlockIndex{block};
60  fakeIndex->nHeight = nextHeight;
61  BlockMap::iterator mi = mapBlockIndex.emplace(blockHash, fakeIndex).first;
62  fakeIndex->phashBlock = &((*mi).first);
63  chainActive.SetTip(fakeIndex);
64  assert(chainActive.Contains(fakeIndex));
65  assert(nextHeight == chainActive.Height());
66 
67  return std::make_shared<CBlock>(block);
68 }
69 
70 CTransactionRef createNoisyTx(CWallet* pwallet, int numOfOutputs)
71 {
72  CallResult<CTxDestination> ret = pwallet->getNewAddress("");
73  assert(ret);
74  const auto& dest = GetScriptForDestination(*ret.getObjResult());
75  std::vector<CRecipient> vecSend;
76  vecSend.reserve(numOfOutputs);
77  for (int i=0; i<numOfOutputs; i++) {
78  vecSend.emplace_back(dest, 5 * COIN, false);
79  }
80 
81  CTransactionRef txRet;
82  CReserveKey reservedKey(pwallet);
83  CAmount nFeeRequired = 0;
84  int nChangePosInOut = -1;
85  std::string strFailReason;
86  bool fCreated = pwallet->CreateTransaction(vecSend,
87  txRet,
88  reservedKey,
89  nFeeRequired,
90  nChangePosInOut,
91  strFailReason);
92  assert(fCreated);
93  return txRet;
94 }
95 
96 boost::thread_group threadGroup;
99 
100 static void initBasics()
101 {
102  initZKSNARKS();
103  CScheduler::Function serviceLoop = std::bind(&CScheduler::serviceQueue, &scheduler);
104  threadGroup.create_thread(std::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
106 
107  zerocoinDB.reset(new CZerocoinDB(0, true));
108  pSporkDB.reset(new CSporkDB(0, true));
109  pblocktree.reset(new CBlockTreeDB(1 << 20, true));
110  pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
111  pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
112  evoDb.reset(new CEvoDB(1 << 20, true, true));
116 }
117 
118 static void WalletProcessBlockBench(benchmark::State& state)
119 {
120  const static auto verify_handle = std::make_unique<ECCVerifyHandle>();
121 
126  const auto& params = Params();
127  initBasics();
128 
129  std::unique_ptr<CWallet> pwallet = std::make_unique<CWallet>("default", WalletDatabase::CreateMock());
130  bool isInit;
131  pwallet->LoadWallet(isInit);
132  pwallet->SetupSPKM(true, true);
133  auto res = pwallet->getNewAddress("coinbase");
134  if (!res) throw std::runtime_error("Cannot create coinbase address");
135  const CScript& coinbaseScript = GetScriptForDestination(*res.getObjResult());
136 
137  // Let's generate blocks first
138  int gen = CREATE_BLOCK;
139  for (int i=0; i<gen; i++) {
140  std::vector<CMutableTransaction> vtx;
141  if (i > 101) { // Generate extra transaction
142  vtx.emplace_back(*createNoisyTx(pwallet.get(), 15));
143  if (i > 106) {
144  for (int j=0; j < (int)CREATE_TRANSACTIONS_PER_BLOCK; j++) {
145  vtx.emplace_back(*createNoisyTx(pwallet.get(), 1));
146  }
147  }
148  }
149 
150  std::shared_ptr<CBlock> pblock = createAndProcessBlock(params, coinbaseScript, vtx, chainActive.Tip());
151  pwallet->BlockConnected(pblock, mapBlockIndex[pblock->GetHash()]);
152  }
153  assert(WITH_LOCK(cs_main, return chainActive.Height();) == gen -1);
154  int nextBlockHeight = gen + 1;
155 
156  // Now the wallet has balance to shield and the network is mature enough.
157  // let's generate 30 more blocks with 3 shielding transactions each.
158  std::vector<std::shared_ptr<CBlock>> blocks;
159  for (int i=0; i<30; i++) {
160  std::vector<CMutableTransaction> vtx;
161  for (int j=0; j<3; j++) {
162  std::vector<SendManyRecipient> recipients;
163  recipients.emplace_back(pwallet->GenerateNewSaplingZKey(), 2 * COIN, "", false);
164  recipients.emplace_back(pwallet->GenerateNewSaplingZKey(), 100 * COIN, "", false);
165  recipients.emplace_back(pwallet->GenerateNewSaplingZKey(), 240 * COIN, "", false);
166 
167  SaplingOperation operation(params.GetConsensus(), pwallet.get());
168  auto operationResult = operation.setRecipients(recipients)
169  ->setSelectTransparentCoins(true)
170  ->setMinDepth(1)
171  ->build();
172 
173  assert(operationResult);
174  vtx.emplace_back(operation.getFinalTx());
175  }
176 
177  std::shared_ptr<CBlock> pblock = createAndProcessBlock(params,
178  coinbaseScript,
179  vtx,
180  chainActive.Tip());
181  assert(WITH_LOCK(cs_main, return chainActive.Height();) == nextBlockHeight - 1);
182  blocks.emplace_back(pblock);
183  nextBlockHeight++;
184  }
185 
186  // The wallet receiving the blocks..
187  while (state.KeepRunning()) {
188  for (const auto& pblock : blocks) {
189  pwallet->BlockConnected(pblock, mapBlockIndex[pblock->GetHash()]);
190  }
191  }
192 
193  // Cleanup
194  ECC_Stop();
195  deterministicMNManager.reset();
196  evoDb.reset();
197  scheduler.stop();
198  threadGroup.interrupt_all();
199  threadGroup.join_all();
201  chainActive.SetTip(nullptr);
203  pcoinsTip.reset();
204  pcoinsdbview.reset();
205  pblocktree.reset();
206  zerocoinDB.reset();
207  pSporkDB.reset();
208 }
209 
210 BENCHMARK(WalletProcessBlockBench, 0);
int64_t CAmount
Amount in PIV (Can be negative)
Definition: amount.h:13
uint256 CalculateSaplingTreeRoot(CBlock *pblock, int nHeight, const CChainParams &chainparams)
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.
static std::unique_ptr< BerkeleyDatabase > CreateMock()
Return object for accessing temporary in-memory database.
Definition: db.h:138
static const std::string REGTEST
uint256 hashFinalSaplingRoot
Definition: block.h:34
uint256 hashPrevBlock
Definition: block.h:28
uint256 hashMerkleRoot
Definition: block.h:29
uint256 GetHash() const
Definition: block.cpp:15
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
uint256 GetBlockHash() const
Definition: chain.h:215
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:151
const uint256 * phashBlock
pointer to the hash of the block, if any. memory is owned by this CBlockIndex
Definition: chain.h:142
Access to the block database (blocks/index/)
Definition: txdb.h:128
CBlockIndex * Tip(bool fProofOfStake=false) const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:405
int Height() const
Return the maximal height in the chain.
Definition: chain.h:450
void SetTip(CBlockIndex *pindex)
Set/initialize a chain with a given tip.
Definition: chain.cpp:14
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition: chain.h:435
CChainParams defines various tweakable parameters of a given instance of the PIVX system.
Definition: chainparams.h:43
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
void RegisterBackgroundSignalScheduler(CScheduler &scheduler)
Register a CScheduler to give callbacks which should run in the background (may only be called once)
A key allocated from the key pool.
Definition: wallet.h:1256
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
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,...
Definition: wallet.h:577
Zerocoin database (zerocoin/)
Definition: txdb.h:152
const Optional< T > & getObjResult() const
bool KeepRunning()
Definition: bench.h:69
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
std::unique_ptr< CEvoDB > evoDb
Definition: evodb.cpp:10
bool CreateTransaction(const std::vector< CRecipient > &vecSend, CTransactionRef &txRet, CReserveKey &reservekey, CAmount &nFeeRet, int &nChangePosInOut, std::string &strFailReason, const CCoinControl *coinControl=nullptr, bool sign=true, CAmount nFeePay=0, bool fIncludeDelegated=false, bool *fStakeDelegationVoided=nullptr, int nExtraSize=0, int nMinDepth=0)
Create a new transaction paying the recipients with a set of coins selected by SelectCoins(); Also cr...
Definition: wallet.cpp:3040
CallResult< CTxDestination > getNewAddress(const std::string &addressLabel, const std::string purpose, const CChainParams::Base58Type addrType=CChainParams::PUBKEY_ADDRESS)
Definition: wallet.cpp:196
void ECC_Stop()
Deinitialize the elliptic curve support.
Definition: key.cpp:361
uint256 BlockMerkleRoot(const CBlock &block, bool *mutated)
Definition: merkle.cpp:154
@ UPGRADE_POS_V2
Definition: params.h:29
@ UPGRADE_POS
Definition: params.h:28
@ UPGRADE_V5_0
Definition: params.h:36
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:80
@ OP_0
Definition: script.h:52
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
std::vector< CTxOut > vout
Definition: transaction.h:411
std::vector< CTxIn > vin
Definition: transaction.h:410
static constexpr int NO_ACTIVATION_HEIGHT
Special value for nActivationHeight indicating that the upgrade will never activate.
Definition: params.h:74
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:247
void initZKSNARKS()
Definition: system.cpp:624
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:456
std::unique_ptr< CBlockTreeDB > pblocktree
Global variable that points to the active block tree (protected by cs_main)
Definition: validation.cpp:207
std::unique_ptr< CZerocoinDB > zerocoinDB
Global variable that points to the zerocoin database (protected by cs_main)
Definition: validation.cpp:208
std::unique_ptr< CSporkDB > pSporkDB
Global variable that points to the spork database (protected by cs_main)
Definition: validation.cpp:209
std::unique_ptr< CCoinsViewCache > pcoinsTip
Global variable that points to the active CCoinsView (protected by cs_main)
Definition: validation.cpp:206
CAmount GetBlockValue(int nHeight)
Definition: validation.cpp:816
BlockMap mapBlockIndex
Definition: validation.cpp:82
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 RegisterValidationInterface(CValidationInterface *pwalletIn)
Register a wallet to receive updates from core.
CTransactionRef createNoisyTx(CWallet *pwallet, int numOfOutputs)
BENCHMARK(WalletProcessBlockBench, 0)
const unsigned int CREATE_TRANSACTIONS_PER_BLOCK
std::shared_ptr< CBlock > createAndProcessBlock(const CChainParams &params, const CScript &coinbaseScript, const std::vector< CMutableTransaction > &txns, CBlockIndex *prevpindex)
CScheduler scheduler
boost::thread_group threadGroup
EvoNotificationInterface * pEvoNotificationInterface
const unsigned int CREATE_BLOCK