]>
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" |
a76174b7 | 21 | #include "rpcserver.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()) | |
64 | GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 1)); | |
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 | { | |
21406393 | 112 | uint256 pubKeyHash; |
6962bb3d | 113 | |
6962bb3d | 114 | /* Get the anchor of an empty commitment tree. */ |
5961dcb6 | 115 | uint256 anchor = ZCIncrementalMerkleTree().root(); |
6962bb3d | 116 | |
9e52ca32 JG |
117 | struct timeval tv_start; |
118 | timer_start(tv_start); | |
22de1602 SB |
119 | JSDescription jsdesc(*pzcashParams, |
120 | pubKeyHash, | |
121 | anchor, | |
122 | {JSInput(), JSInput()}, | |
123 | {JSOutput(), JSOutput()}, | |
124 | 0, | |
125 | 0); | |
9e52ca32 | 126 | double ret = timer_stop(tv_start); |
21406393 | 127 | |
bc59f537 SB |
128 | auto verifier = libzcash::ProofVerifier::Strict(); |
129 | assert(jsdesc.Verify(*pzcashParams, verifier, pubKeyHash)); | |
6962bb3d TH |
130 | return ret; |
131 | } | |
bf8def97 | 132 | |
4082dcb1 JG |
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 | ||
a8c68ffe | 154 | double benchmark_verify_joinsplit(const JSDescription &joinsplit) |
a1cd1a27 | 155 | { |
9e52ca32 JG |
156 | struct timeval tv_start; |
157 | timer_start(tv_start); | |
21406393 | 158 | uint256 pubKeyHash; |
bc59f537 SB |
159 | auto verifier = libzcash::ProofVerifier::Strict(); |
160 | joinsplit.Verify(*pzcashParams, verifier, pubKeyHash); | |
9e52ca32 | 161 | return timer_stop(tv_start); |
a1cd1a27 TH |
162 | } |
163 | ||
2cc0a252 | 164 | #ifdef ENABLE_MINING |
9e52ca32 | 165 | double benchmark_solve_equihash() |
bf8def97 | 166 | { |
722b0117 TH |
167 | CBlock pblock; |
168 | CEquihashInput I{pblock}; | |
169 | CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | |
170 | ss << I; | |
171 | ||
e9574728 JG |
172 | unsigned int n = Params(CBaseChainParams::MAIN).EquihashN(); |
173 | unsigned int k = Params(CBaseChainParams::MAIN).EquihashK(); | |
bf8def97 | 174 | crypto_generichash_blake2b_state eh_state; |
e9574728 | 175 | EhInitialiseState(n, k, eh_state); |
722b0117 TH |
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 | ||
9e52ca32 JG |
184 | struct timeval tv_start; |
185 | timer_start(tv_start); | |
e9574728 | 186 | std::set<std::vector<unsigned int>> solns; |
51eb5273 | 187 | EhOptimisedSolveUncancellable(n, k, eh_state, |
5be6abbf | 188 | [](std::vector<unsigned char> soln) { return false; }); |
9e52ca32 | 189 | return timer_stop(tv_start); |
f7478de6 JG |
190 | } |
191 | ||
9e52ca32 | 192 | std::vector<double> benchmark_solve_equihash_threaded(int nThreads) |
f7478de6 | 193 | { |
9e52ca32 JG |
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; | |
bf8def97 | 211 | } |
2cc0a252 | 212 | #endif // ENABLE_MINING |
d44feea4 | 213 | |
a1cd1a27 | 214 | double benchmark_verify_equihash() |
d44feea4 | 215 | { |
a1cd1a27 TH |
216 | CChainParams params = Params(CBaseChainParams::MAIN); |
217 | CBlock genesis = Params(CBaseChainParams::MAIN).GenesisBlock(); | |
218 | CBlockHeader genesis_header = genesis.GetBlockHeader(); | |
9e52ca32 JG |
219 | struct timeval tv_start; |
220 | timer_start(tv_start); | |
a1cd1a27 | 221 | CheckEquihashSolution(&genesis_header, params); |
9e52ca32 | 222 | return timer_stop(tv_start); |
d44feea4 | 223 | } |
a1cd1a27 | 224 | |
818b94f9 | 225 | double benchmark_large_tx(size_t nInputs) |
f5edc37f | 226 | { |
9c45b501 SB |
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; | |
45539018 | 245 | spending_tx.fOverwintered = true; |
b1608eed | 246 | spending_tx.nVersion = OVERWINTER_TX_VERSION; |
45539018 JG |
247 | spending_tx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; |
248 | ||
805344dc | 249 | auto input_hash = orig_tx.GetHash(); |
818b94f9 JG |
250 | // Add nInputs inputs |
251 | for (size_t i = 0; i < nInputs; i++) { | |
9c45b501 | 252 | spending_tx.vin.emplace_back(input_hash, 0); |
f5edc37f JG |
253 | } |
254 | ||
9c45b501 | 255 | // Sign for all the inputs |
be126699 | 256 | auto consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId; |
818b94f9 | 257 | for (size_t i = 0; i < nInputs; i++) { |
be126699 | 258 | SignSignature(tempKeystore, prevPubKey, spending_tx, i, 1000000, SIGHASH_ALL, consensusBranchId); |
f5edc37f | 259 | } |
f5edc37f | 260 | |
822b84b6 S |
261 | // Spending tx has all its inputs signed and does not need to be mutated anymore |
262 | CTransaction final_spending_tx(spending_tx); | |
263 | ||
9c45b501 | 264 | // Benchmark signature verification costs: |
9e52ca32 JG |
265 | struct timeval tv_start; |
266 | timer_start(tv_start); | |
45539018 | 267 | PrecomputedTransactionData txdata(final_spending_tx); |
818b94f9 | 268 | for (size_t i = 0; i < nInputs; i++) { |
9c45b501 | 269 | ScriptError serror = SCRIPT_ERR_OK; |
75c2f268 | 270 | assert(VerifyScript(final_spending_tx.vin[i].scriptSig, |
9c45b501 SB |
271 | prevPubKey, |
272 | STANDARD_SCRIPT_VERIFY_FLAGS, | |
45539018 | 273 | TransactionSignatureChecker(&final_spending_tx, i, 1000000, txdata), |
be126699 | 274 | consensusBranchId, |
9c45b501 SB |
275 | &serror)); |
276 | } | |
9e52ca32 | 277 | return timer_stop(tv_start); |
f5edc37f JG |
278 | } |
279 | ||
88b7f3c2 | 280 | double benchmark_try_decrypt_notes(size_t nAddrs) |
0fbab55b | 281 | { |
0fbab55b | 282 | CWallet wallet; |
88b7f3c2 | 283 | for (int i = 0; i < nAddrs; i++) { |
0fbab55b JG |
284 | auto sk = libzcash::SpendingKey::random(); |
285 | wallet.AddSpendingKey(sk); | |
286 | } | |
287 | ||
88b7f3c2 JG |
288 | auto sk = libzcash::SpendingKey::random(); |
289 | auto tx = GetValidReceive(*pzcashParams, sk, 10, true); | |
0fbab55b JG |
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 | ||
0bb3d40f JG |
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(); | |
9755eb82 JG |
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 | } | |
0bb3d40f JG |
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 | ||
c66c731a JG |
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 | ||
708c87f1 | 369 | bool GetNullifier(const uint256 &nf, NullifierType type) const { |
c66c731a JG |
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, | |
685e936c EOW |
385 | CNullifiersMap &mapNullifiers, |
386 | CNullifiersMap& mapSaplingNullifiers) { | |
c66c731a JG |
387 | return false; |
388 | } | |
389 | ||
390 | bool GetStats(CCoinsStats &stats) const { | |
391 | return false; | |
392 | } | |
393 | }; | |
394 | ||
395 | double benchmark_connectblock_slow() | |
396 | { | |
397 | // Test for issue 2017-05-01.a | |
398 | SelectParams(CBaseChainParams::MAIN); | |
399 | CBlock block; | |
400 | FILE* fp = fopen((GetDataDir() / "benchmark/block-107134.dat").string().c_str(), "rb"); | |
401 | if (!fp) throw new std::runtime_error("Failed to open block data file"); | |
402 | CAutoFile blkFile(fp, SER_DISK, CLIENT_VERSION); | |
403 | blkFile >> block; | |
404 | blkFile.fclose(); | |
405 | ||
406 | // Fake its inputs | |
407 | auto hashPrev = uint256S("00000000159a41f468e22135942a567781c3f3dc7ad62257993eb3c69c3f95ef"); | |
408 | FakeCoinsViewDB fakeDB("benchmark/block-107134-inputs", hashPrev); | |
409 | CCoinsViewCache view(&fakeDB); | |
410 | ||
411 | // Fake the chain | |
412 | CBlockIndex index(block); | |
413 | index.nHeight = 107134; | |
414 | CBlockIndex indexPrev; | |
415 | indexPrev.phashBlock = &hashPrev; | |
416 | indexPrev.nHeight = index.nHeight - 1; | |
417 | index.pprev = &indexPrev; | |
418 | mapBlockIndex.insert(std::make_pair(hashPrev, &indexPrev)); | |
419 | ||
420 | CValidationState state; | |
421 | struct timeval tv_start; | |
422 | timer_start(tv_start); | |
423 | assert(ConnectBlock(block, state, &index, view, true)); | |
424 | auto duration = timer_stop(tv_start); | |
425 | ||
426 | // Undo alterations to global state | |
427 | mapBlockIndex.erase(hashPrev); | |
428 | SelectParamsFromCommandLine(); | |
429 | ||
430 | return duration; | |
431 | } | |
432 | ||
a76174b7 JG |
433 | double benchmark_sendtoaddress(CAmount amount) |
434 | { | |
435 | UniValue params(UniValue::VARR); | |
436 | auto addr = getnewaddress(params, false); | |
437 | ||
438 | params.push_back(addr); | |
439 | params.push_back(ValueFromAmount(amount)); | |
440 | ||
441 | struct timeval tv_start; | |
442 | timer_start(tv_start); | |
443 | auto txid = sendtoaddress(params, false); | |
444 | return timer_stop(tv_start); | |
445 | } | |
446 | ||
2e8aefdc AG |
447 | double benchmark_loadwallet() |
448 | { | |
449 | pre_wallet_load(); | |
450 | struct timeval tv_start; | |
451 | bool fFirstRunRet=true; | |
452 | timer_start(tv_start); | |
453 | pwalletMain = new CWallet("wallet.dat"); | |
454 | DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRunRet); | |
455 | auto res = timer_stop(tv_start); | |
456 | post_wallet_load(); | |
457 | return res; | |
458 | } | |
99dd50c3 JG |
459 | |
460 | double benchmark_listunspent() | |
461 | { | |
462 | UniValue params(UniValue::VARR); | |
463 | struct timeval tv_start; | |
464 | timer_start(tv_start); | |
465 | auto unspent = listunspent(params, false); | |
466 | return timer_stop(tv_start); | |
467 | } |