]>
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; | |
805344dc | 245 | auto input_hash = orig_tx.GetHash(); |
818b94f9 JG |
246 | // Add nInputs inputs |
247 | for (size_t i = 0; i < nInputs; i++) { | |
9c45b501 | 248 | spending_tx.vin.emplace_back(input_hash, 0); |
f5edc37f JG |
249 | } |
250 | ||
9c45b501 | 251 | // Sign for all the inputs |
be126699 | 252 | auto consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId; |
818b94f9 | 253 | for (size_t i = 0; i < nInputs; i++) { |
be126699 | 254 | SignSignature(tempKeystore, prevPubKey, spending_tx, i, 1000000, SIGHASH_ALL, consensusBranchId); |
f5edc37f | 255 | } |
f5edc37f | 256 | |
822b84b6 S |
257 | // Spending tx has all its inputs signed and does not need to be mutated anymore |
258 | CTransaction final_spending_tx(spending_tx); | |
259 | ||
9c45b501 | 260 | // Benchmark signature verification costs: |
9e52ca32 JG |
261 | struct timeval tv_start; |
262 | timer_start(tv_start); | |
818b94f9 | 263 | for (size_t i = 0; i < nInputs; i++) { |
9c45b501 | 264 | ScriptError serror = SCRIPT_ERR_OK; |
75c2f268 | 265 | assert(VerifyScript(final_spending_tx.vin[i].scriptSig, |
9c45b501 SB |
266 | prevPubKey, |
267 | STANDARD_SCRIPT_VERIFY_FLAGS, | |
2d42e1a9 | 268 | TransactionSignatureChecker(&final_spending_tx, i, 1000000), |
be126699 | 269 | consensusBranchId, |
9c45b501 SB |
270 | &serror)); |
271 | } | |
9e52ca32 | 272 | return timer_stop(tv_start); |
f5edc37f JG |
273 | } |
274 | ||
88b7f3c2 | 275 | double benchmark_try_decrypt_notes(size_t nAddrs) |
0fbab55b | 276 | { |
0fbab55b | 277 | CWallet wallet; |
88b7f3c2 | 278 | for (int i = 0; i < nAddrs; i++) { |
0fbab55b JG |
279 | auto sk = libzcash::SpendingKey::random(); |
280 | wallet.AddSpendingKey(sk); | |
281 | } | |
282 | ||
88b7f3c2 JG |
283 | auto sk = libzcash::SpendingKey::random(); |
284 | auto tx = GetValidReceive(*pzcashParams, sk, 10, true); | |
0fbab55b JG |
285 | |
286 | struct timeval tv_start; | |
287 | timer_start(tv_start); | |
288 | auto nd = wallet.FindMyNotes(tx); | |
289 | return timer_stop(tv_start); | |
290 | } | |
291 | ||
0bb3d40f JG |
292 | double benchmark_increment_note_witnesses(size_t nTxs) |
293 | { | |
294 | CWallet wallet; | |
295 | ZCIncrementalMerkleTree tree; | |
296 | ||
297 | auto sk = libzcash::SpendingKey::random(); | |
298 | wallet.AddSpendingKey(sk); | |
299 | ||
300 | // First block | |
301 | CBlock block1; | |
302 | for (int i = 0; i < nTxs; i++) { | |
303 | auto wtx = GetValidReceive(*pzcashParams, sk, 10, true); | |
304 | auto note = GetNote(*pzcashParams, sk, wtx, 0, 1); | |
305 | auto nullifier = note.nullifier(sk); | |
306 | ||
307 | mapNoteData_t noteData; | |
308 | JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; | |
309 | CNoteData nd {sk.address(), nullifier}; | |
310 | noteData[jsoutpt] = nd; | |
311 | ||
312 | wtx.SetNoteData(noteData); | |
313 | wallet.AddToWallet(wtx, true, NULL); | |
314 | block1.vtx.push_back(wtx); | |
315 | } | |
316 | CBlockIndex index1(block1); | |
317 | index1.nHeight = 1; | |
318 | ||
319 | // Increment to get transactions witnessed | |
320 | wallet.ChainTip(&index1, &block1, tree, true); | |
321 | ||
322 | // Second block | |
323 | CBlock block2; | |
324 | block2.hashPrevBlock = block1.GetHash(); | |
9755eb82 JG |
325 | { |
326 | auto wtx = GetValidReceive(*pzcashParams, sk, 10, true); | |
327 | auto note = GetNote(*pzcashParams, sk, wtx, 0, 1); | |
328 | auto nullifier = note.nullifier(sk); | |
329 | ||
330 | mapNoteData_t noteData; | |
331 | JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; | |
332 | CNoteData nd {sk.address(), nullifier}; | |
333 | noteData[jsoutpt] = nd; | |
334 | ||
335 | wtx.SetNoteData(noteData); | |
336 | wallet.AddToWallet(wtx, true, NULL); | |
337 | block2.vtx.push_back(wtx); | |
338 | } | |
0bb3d40f JG |
339 | CBlockIndex index2(block2); |
340 | index2.nHeight = 2; | |
341 | ||
342 | struct timeval tv_start; | |
343 | timer_start(tv_start); | |
344 | wallet.ChainTip(&index2, &block2, tree, true); | |
345 | return timer_stop(tv_start); | |
346 | } | |
347 | ||
c66c731a JG |
348 | // Fake the input of a given block |
349 | class FakeCoinsViewDB : public CCoinsViewDB { | |
350 | uint256 hash; | |
351 | ZCIncrementalMerkleTree t; | |
352 | ||
353 | public: | |
354 | FakeCoinsViewDB(std::string dbName, uint256& hash) : CCoinsViewDB(dbName, 100, false, false), hash(hash) {} | |
355 | ||
356 | bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { | |
357 | if (rt == t.root()) { | |
358 | tree = t; | |
359 | return true; | |
360 | } | |
361 | return false; | |
362 | } | |
363 | ||
364 | bool GetNullifier(const uint256 &nf) const { | |
365 | return false; | |
366 | } | |
367 | ||
368 | uint256 GetBestBlock() const { | |
369 | return hash; | |
370 | } | |
371 | ||
372 | uint256 GetBestAnchor() const { | |
373 | return t.root(); | |
374 | } | |
375 | ||
376 | bool BatchWrite(CCoinsMap &mapCoins, | |
377 | const uint256 &hashBlock, | |
378 | const uint256 &hashAnchor, | |
379 | CAnchorsMap &mapAnchors, | |
380 | CNullifiersMap &mapNullifiers) { | |
381 | return false; | |
382 | } | |
383 | ||
384 | bool GetStats(CCoinsStats &stats) const { | |
385 | return false; | |
386 | } | |
387 | }; | |
388 | ||
389 | double benchmark_connectblock_slow() | |
390 | { | |
391 | // Test for issue 2017-05-01.a | |
392 | SelectParams(CBaseChainParams::MAIN); | |
393 | CBlock block; | |
394 | FILE* fp = fopen((GetDataDir() / "benchmark/block-107134.dat").string().c_str(), "rb"); | |
395 | if (!fp) throw new std::runtime_error("Failed to open block data file"); | |
396 | CAutoFile blkFile(fp, SER_DISK, CLIENT_VERSION); | |
397 | blkFile >> block; | |
398 | blkFile.fclose(); | |
399 | ||
400 | // Fake its inputs | |
401 | auto hashPrev = uint256S("00000000159a41f468e22135942a567781c3f3dc7ad62257993eb3c69c3f95ef"); | |
402 | FakeCoinsViewDB fakeDB("benchmark/block-107134-inputs", hashPrev); | |
403 | CCoinsViewCache view(&fakeDB); | |
404 | ||
405 | // Fake the chain | |
406 | CBlockIndex index(block); | |
407 | index.nHeight = 107134; | |
408 | CBlockIndex indexPrev; | |
409 | indexPrev.phashBlock = &hashPrev; | |
410 | indexPrev.nHeight = index.nHeight - 1; | |
411 | index.pprev = &indexPrev; | |
412 | mapBlockIndex.insert(std::make_pair(hashPrev, &indexPrev)); | |
413 | ||
414 | CValidationState state; | |
415 | struct timeval tv_start; | |
416 | timer_start(tv_start); | |
417 | assert(ConnectBlock(block, state, &index, view, true)); | |
418 | auto duration = timer_stop(tv_start); | |
419 | ||
420 | // Undo alterations to global state | |
421 | mapBlockIndex.erase(hashPrev); | |
422 | SelectParamsFromCommandLine(); | |
423 | ||
424 | return duration; | |
425 | } | |
426 | ||
a76174b7 JG |
427 | double benchmark_sendtoaddress(CAmount amount) |
428 | { | |
429 | UniValue params(UniValue::VARR); | |
430 | auto addr = getnewaddress(params, false); | |
431 | ||
432 | params.push_back(addr); | |
433 | params.push_back(ValueFromAmount(amount)); | |
434 | ||
435 | struct timeval tv_start; | |
436 | timer_start(tv_start); | |
437 | auto txid = sendtoaddress(params, false); | |
438 | return timer_stop(tv_start); | |
439 | } | |
440 | ||
2e8aefdc AG |
441 | double benchmark_loadwallet() |
442 | { | |
443 | pre_wallet_load(); | |
444 | struct timeval tv_start; | |
445 | bool fFirstRunRet=true; | |
446 | timer_start(tv_start); | |
447 | pwalletMain = new CWallet("wallet.dat"); | |
448 | DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRunRet); | |
449 | auto res = timer_stop(tv_start); | |
450 | post_wallet_load(); | |
451 | return res; | |
452 | } | |
99dd50c3 JG |
453 | |
454 | double benchmark_listunspent() | |
455 | { | |
456 | UniValue params(UniValue::VARR); | |
457 | struct timeval tv_start; | |
458 | timer_start(tv_start); | |
459 | auto unspent = listunspent(params, false); | |
460 | return timer_stop(tv_start); | |
461 | } |