]>
Commit | Line | Data |
---|---|---|
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 | ||
34 | using namespace libzcash; | |
2e8aefdc AG |
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()) | |
94f9918f | 64 | GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 0)); |
2e8aefdc AG |
65 | #endif |
66 | } | |
67 | ||
2dc35992 | 68 | |
9e52ca32 | 69 | void timer_start(timeval &tv_start) |
6962bb3d TH |
70 | { |
71 | gettimeofday(&tv_start, 0); | |
72 | } | |
73 | ||
9e52ca32 | 74 | double 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 | ||
84 | double 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 | ||
92 | double 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 | ||
110 | double 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 |
134 | std::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 | 155 | double 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 | 166 | double 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 | 193 | std::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 | 215 | double 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 | 226 | double 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 | 281 | double 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 |
298 | double 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 |
356 | class FakeCoinsViewDB : public CCoinsViewDB { | |
357 | uint256 hash; | |
4fc309f0 | 358 | SproutMerkleTree t; |
c66c731a JG |
359 | |
360 | public: | |
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 | ||
397 | double 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 |
435 | extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp |
436 | extern UniValue sendtoaddress(const UniValue& params, bool fHelp); | |
437 | ||
a76174b7 JG |
438 | double 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 |
452 | double 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 |
465 | extern UniValue listunspent(const UniValue& params, bool fHelp); |
466 | ||
99dd50c3 JG |
467 | double 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 | } |