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