]> Git Repo - VerusCoin.git/blob - src/zcbenchmarks.cpp
Merge branch 'dev' into jl777
[VerusCoin.git] / src / zcbenchmarks.cpp
1 #include <cstdio>
2 #include <future>
3 #include <map>
4 #include <thread>
5 #include <unistd.h>
6 #include <boost/filesystem.hpp>
7
8 #include "coins.h"
9 #include "util.h"
10 #include "init.h"
11 #include "primitives/transaction.h"
12 #include "base58.h"
13 #include "crypto/equihash.h"
14 #include "chain.h"
15 #include "chainparams.h"
16 #include "consensus/upgrades.h"
17 #include "consensus/validation.h"
18 #include "main.h"
19 #include "miner.h"
20 #include "pow.h"
21 #include "rpcserver.h"
22 #include "script/sign.h"
23 #include "sodium.h"
24 #include "streams.h"
25 #include "txdb.h"
26 #include "utiltest.h"
27 #include "wallet/wallet.h"
28
29 #include "zcbenchmarks.h"
30
31 #include "zcash/Zcash.h"
32 #include "zcash/IncrementalMerkleTree.hpp"
33
34 using namespace libzcash;
35 // This method is based on Shutdown from init.cpp
36 void pre_wallet_load()
37 {
38     LogPrintf("%s: In progress...\n", __func__);
39     if (ShutdownRequested())
40         throw new std::runtime_error("The node is shutting down");
41
42     if (pwalletMain)
43         pwalletMain->Flush(false);
44 #ifdef ENABLE_MINING
45     GenerateBitcoins(false, NULL, 0);
46 #endif
47     UnregisterNodeSignals(GetNodeSignals());
48     if (pwalletMain)
49         pwalletMain->Flush(true);
50
51     UnregisterValidationInterface(pwalletMain);
52     delete pwalletMain;
53     pwalletMain = NULL;
54     bitdb.Reset();
55     RegisterNodeSignals(GetNodeSignals());
56     LogPrintf("%s: done\n", __func__);
57 }
58
59 void post_wallet_load(){
60     RegisterValidationInterface(pwalletMain);
61 #ifdef ENABLE_MINING
62     // Generate coins in the background
63     if (pwalletMain || !GetArg("-mineraddress", "").empty())
64         GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 1));
65 #endif    
66 }
67
68
69 void timer_start(timeval &tv_start)
70 {
71     gettimeofday(&tv_start, 0);
72 }
73
74 double timer_stop(timeval &tv_start)
75 {
76     double elapsed;
77     struct timeval tv_end;
78     gettimeofday(&tv_end, 0);
79     elapsed = double(tv_end.tv_sec-tv_start.tv_sec) +
80         (tv_end.tv_usec-tv_start.tv_usec)/double(1000000);
81     return elapsed;
82 }
83
84 double benchmark_sleep()
85 {
86     struct timeval tv_start;
87     timer_start(tv_start);
88     sleep(1);
89     return timer_stop(tv_start);
90 }
91
92 double benchmark_parameter_loading()
93 {
94     // FIXME: this is duplicated with the actual loading code
95     boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key";
96     boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key";
97
98     struct timeval tv_start;
99     timer_start(tv_start);
100
101     auto newParams = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string());
102
103     double ret = timer_stop(tv_start);
104
105     delete newParams;
106
107     return ret;
108 }
109
110 double benchmark_create_joinsplit()
111 {
112     uint256 pubKeyHash;
113
114     /* Get the anchor of an empty commitment tree. */
115     uint256 anchor = ZCIncrementalMerkleTree().root();
116
117     struct timeval tv_start;
118     timer_start(tv_start);
119     JSDescription jsdesc(*pzcashParams,
120                          pubKeyHash,
121                          anchor,
122                          {JSInput(), JSInput()},
123                          {JSOutput(), JSOutput()},
124                          0,
125                          0);
126     double ret = timer_stop(tv_start);
127
128     auto verifier = libzcash::ProofVerifier::Strict();
129     assert(jsdesc.Verify(*pzcashParams, verifier, pubKeyHash));
130     return ret;
131 }
132
133 std::vector<double> benchmark_create_joinsplit_threaded(int nThreads)
134 {
135     std::vector<double> ret;
136     std::vector<std::future<double>> tasks;
137     std::vector<std::thread> threads;
138     for (int i = 0; i < nThreads; i++) {
139         std::packaged_task<double(void)> task(&benchmark_create_joinsplit);
140         tasks.emplace_back(task.get_future());
141         threads.emplace_back(std::move(task));
142     }
143     std::future_status status;
144     for (auto it = tasks.begin(); it != tasks.end(); it++) {
145         it->wait();
146         ret.push_back(it->get());
147     }
148     for (auto it = threads.begin(); it != threads.end(); it++) {
149         it->join();
150     }
151     return ret;
152 }
153
154 double benchmark_verify_joinsplit(const JSDescription &joinsplit)
155 {
156     struct timeval tv_start;
157     timer_start(tv_start);
158     uint256 pubKeyHash;
159     auto verifier = libzcash::ProofVerifier::Strict();
160     joinsplit.Verify(*pzcashParams, verifier, pubKeyHash);
161     return timer_stop(tv_start);
162 }
163
164 #ifdef ENABLE_MINING
165 double benchmark_solve_equihash()
166 {
167     CBlock pblock;
168     CEquihashInput I{pblock};
169     CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
170     ss << I;
171
172     unsigned int n = Params(CBaseChainParams::MAIN).EquihashN();
173     unsigned int k = Params(CBaseChainParams::MAIN).EquihashK();
174     crypto_generichash_blake2b_state eh_state;
175     EhInitialiseState(n, k, eh_state);
176     crypto_generichash_blake2b_update(&eh_state, (unsigned char*)&ss[0], ss.size());
177
178     uint256 nonce;
179     randombytes_buf(nonce.begin(), 32);
180     crypto_generichash_blake2b_update(&eh_state,
181                                     nonce.begin(),
182                                     nonce.size());
183
184     struct timeval tv_start;
185     timer_start(tv_start);
186     std::set<std::vector<unsigned int>> solns;
187     EhOptimisedSolveUncancellable(n, k, eh_state,
188                                   [](std::vector<unsigned char> soln) { return false; });
189     return timer_stop(tv_start);
190 }
191
192 std::vector<double> benchmark_solve_equihash_threaded(int nThreads)
193 {
194     std::vector<double> ret;
195     std::vector<std::future<double>> tasks;
196     std::vector<std::thread> threads;
197     for (int i = 0; i < nThreads; i++) {
198         std::packaged_task<double(void)> task(&benchmark_solve_equihash);
199         tasks.emplace_back(task.get_future());
200         threads.emplace_back(std::move(task));
201     }
202     std::future_status status;
203     for (auto it = tasks.begin(); it != tasks.end(); it++) {
204         it->wait();
205         ret.push_back(it->get());
206     }
207     for (auto it = threads.begin(); it != threads.end(); it++) {
208         it->join();
209     }
210     return ret;
211 }
212 #endif // ENABLE_MINING
213
214 double benchmark_verify_equihash()
215 {
216     CChainParams params = Params(CBaseChainParams::MAIN);
217     CBlock genesis = Params(CBaseChainParams::MAIN).GenesisBlock();
218     CBlockHeader genesis_header = genesis.GetBlockHeader();
219     struct timeval tv_start;
220     timer_start(tv_start);
221     CheckEquihashSolution(&genesis_header, params);
222     return timer_stop(tv_start);
223 }
224
225 double benchmark_large_tx(size_t nInputs)
226 {
227     // Create priv/pub key
228     CKey priv;
229     priv.MakeNewKey(false);
230     auto pub = priv.GetPubKey();
231     CBasicKeyStore tempKeystore;
232     tempKeystore.AddKey(priv);
233
234     // The "original" transaction that the spending transaction will spend
235     // from.
236     CMutableTransaction m_orig_tx;
237     m_orig_tx.vout.resize(1);
238     m_orig_tx.vout[0].nValue = 1000000;
239     CScript prevPubKey = GetScriptForDestination(pub.GetID());
240     m_orig_tx.vout[0].scriptPubKey = prevPubKey;
241
242     auto orig_tx = CTransaction(m_orig_tx);
243
244     CMutableTransaction spending_tx;
245     spending_tx.fOverwintered = true;
246     spending_tx.nVersion = 3;
247     spending_tx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
248
249     auto input_hash = orig_tx.GetHash();
250     // Add nInputs inputs
251     for (size_t i = 0; i < nInputs; i++) {
252         spending_tx.vin.emplace_back(input_hash, 0);
253     }
254
255     // Sign for all the inputs
256     auto consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId;
257     for (size_t i = 0; i < nInputs; i++) {
258         SignSignature(tempKeystore, prevPubKey, spending_tx, i, 1000000, SIGHASH_ALL, consensusBranchId);
259     }
260
261     // Spending tx has all its inputs signed and does not need to be mutated anymore
262     CTransaction final_spending_tx(spending_tx);
263
264     // Benchmark signature verification costs:
265     struct timeval tv_start;
266     timer_start(tv_start);
267     PrecomputedTransactionData txdata(final_spending_tx);
268     for (size_t i = 0; i < nInputs; i++) {
269         ScriptError serror = SCRIPT_ERR_OK;
270         assert(VerifyScript(final_spending_tx.vin[i].scriptSig,
271                             prevPubKey,
272                             STANDARD_SCRIPT_VERIFY_FLAGS,
273                             TransactionSignatureChecker(&final_spending_tx, i, 1000000, txdata),
274                             consensusBranchId,
275                             &serror));
276     }
277     return timer_stop(tv_start);
278 }
279
280 double benchmark_try_decrypt_notes(size_t nAddrs)
281 {
282     CWallet wallet;
283     for (int i = 0; i < nAddrs; i++) {
284         auto sk = libzcash::SpendingKey::random();
285         wallet.AddSpendingKey(sk);
286     }
287
288     auto sk = libzcash::SpendingKey::random();
289     auto tx = GetValidReceive(*pzcashParams, sk, 10, true);
290
291     struct timeval tv_start;
292     timer_start(tv_start);
293     auto nd = wallet.FindMyNotes(tx);
294     return timer_stop(tv_start);
295 }
296
297 double benchmark_increment_note_witnesses(size_t nTxs)
298 {
299     CWallet wallet;
300     ZCIncrementalMerkleTree tree;
301
302     auto sk = libzcash::SpendingKey::random();
303     wallet.AddSpendingKey(sk);
304
305     // First block
306     CBlock block1;
307     for (int i = 0; i < nTxs; i++) {
308         auto wtx = GetValidReceive(*pzcashParams, sk, 10, true);
309         auto note = GetNote(*pzcashParams, sk, wtx, 0, 1);
310         auto nullifier = note.nullifier(sk);
311
312         mapNoteData_t noteData;
313         JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
314         CNoteData nd {sk.address(), nullifier};
315         noteData[jsoutpt] = nd;
316
317         wtx.SetNoteData(noteData);
318         wallet.AddToWallet(wtx, true, NULL);
319         block1.vtx.push_back(wtx);
320     }
321     CBlockIndex index1(block1);
322     index1.nHeight = 1;
323
324     // Increment to get transactions witnessed
325     wallet.ChainTip(&index1, &block1, tree, true);
326
327     // Second block
328     CBlock block2;
329     block2.hashPrevBlock = block1.GetHash();
330     {
331         auto wtx = GetValidReceive(*pzcashParams, sk, 10, true);
332         auto note = GetNote(*pzcashParams, sk, wtx, 0, 1);
333         auto nullifier = note.nullifier(sk);
334
335         mapNoteData_t noteData;
336         JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
337         CNoteData nd {sk.address(), nullifier};
338         noteData[jsoutpt] = nd;
339
340         wtx.SetNoteData(noteData);
341         wallet.AddToWallet(wtx, true, NULL);
342         block2.vtx.push_back(wtx);
343     }
344     CBlockIndex index2(block2);
345     index2.nHeight = 2;
346
347     struct timeval tv_start;
348     timer_start(tv_start);
349     wallet.ChainTip(&index2, &block2, tree, true);
350     return timer_stop(tv_start);
351 }
352
353 // Fake the input of a given block
354 class FakeCoinsViewDB : public CCoinsViewDB {
355     uint256 hash;
356     ZCIncrementalMerkleTree t;
357
358 public:
359     FakeCoinsViewDB(std::string dbName, uint256& hash) : CCoinsViewDB(dbName, 100, false, false), hash(hash) {}
360
361     bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
362         if (rt == t.root()) {
363             tree = t;
364             return true;
365         }
366         return false;
367     }
368
369     bool GetNullifier(const uint256 &nf) const {
370         return false;
371     }
372
373     uint256 GetBestBlock() const {
374         return hash;
375     }
376
377     uint256 GetBestAnchor() const {
378         return t.root();
379     }
380
381     bool BatchWrite(CCoinsMap &mapCoins,
382                     const uint256 &hashBlock,
383                     const uint256 &hashAnchor,
384                     CAnchorsMap &mapAnchors,
385                     CNullifiersMap &mapNullifiers) {
386         return false;
387     }
388
389     bool GetStats(CCoinsStats &stats) const {
390         return false;
391     }
392 };
393
394 double benchmark_connectblock_slow()
395 {
396     // Test for issue 2017-05-01.a
397     SelectParams(CBaseChainParams::MAIN);
398     CBlock block;
399     FILE* fp = fopen((GetDataDir() / "benchmark/block-107134.dat").string().c_str(), "rb");
400     if (!fp) throw new std::runtime_error("Failed to open block data file");
401     CAutoFile blkFile(fp, SER_DISK, CLIENT_VERSION);
402     blkFile >> block;
403     blkFile.fclose();
404
405     // Fake its inputs
406     auto hashPrev = uint256S("00000000159a41f468e22135942a567781c3f3dc7ad62257993eb3c69c3f95ef");
407     FakeCoinsViewDB fakeDB("benchmark/block-107134-inputs", hashPrev);
408     CCoinsViewCache view(&fakeDB);
409
410     // Fake the chain
411     CBlockIndex index(block);
412     index.nHeight = 107134;
413     CBlockIndex indexPrev;
414     indexPrev.phashBlock = &hashPrev;
415     indexPrev.nHeight = index.nHeight - 1;
416     index.pprev = &indexPrev;
417     mapBlockIndex.insert(std::make_pair(hashPrev, &indexPrev));
418
419     CValidationState state;
420     struct timeval tv_start;
421     timer_start(tv_start);
422     assert(ConnectBlock(block, state, &index, view, true));
423     auto duration = timer_stop(tv_start);
424
425     // Undo alterations to global state
426     mapBlockIndex.erase(hashPrev);
427     SelectParamsFromCommandLine();
428
429     return duration;
430 }
431
432 double benchmark_sendtoaddress(CAmount amount)
433 {
434     UniValue params(UniValue::VARR);
435     auto addr = getnewaddress(params, false);
436
437     params.push_back(addr);
438     params.push_back(ValueFromAmount(amount));
439
440     struct timeval tv_start;
441     timer_start(tv_start);
442     auto txid = sendtoaddress(params, false);
443     return timer_stop(tv_start);
444 }
445
446 double benchmark_loadwallet()
447 {
448     pre_wallet_load();
449     struct timeval tv_start;
450     bool fFirstRunRet=true;
451     timer_start(tv_start);
452     pwalletMain = new CWallet("wallet.dat");
453     DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRunRet);
454     auto res = timer_stop(tv_start);
455     post_wallet_load();
456     return res;
457 }
458
459 double benchmark_listunspent()
460 {
461     UniValue params(UniValue::VARR);
462     struct timeval tv_start;
463     timer_start(tv_start);
464     auto unspent = listunspent(params, false);
465     return timer_stop(tv_start);
466 }
This page took 0.047594 seconds and 4 git commands to generate.