]>
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" | |
67d2b797 S |
33 | #include "zcash/Note.hpp" |
34 | #include "librustzcash.h" | |
2dc35992 SB |
35 | |
36 | using namespace libzcash; | |
2e8aefdc AG |
37 | // This method is based on Shutdown from init.cpp |
38 | void pre_wallet_load() | |
39 | { | |
40 | LogPrintf("%s: In progress...\n", __func__); | |
41 | if (ShutdownRequested()) | |
42 | throw new std::runtime_error("The node is shutting down"); | |
43 | ||
44 | if (pwalletMain) | |
45 | pwalletMain->Flush(false); | |
46 | #ifdef ENABLE_MINING | |
b2993bc5 | 47 | GenerateBitcoins(false, 0, Params()); |
2e8aefdc AG |
48 | #endif |
49 | UnregisterNodeSignals(GetNodeSignals()); | |
50 | if (pwalletMain) | |
51 | pwalletMain->Flush(true); | |
52 | ||
53 | UnregisterValidationInterface(pwalletMain); | |
54 | delete pwalletMain; | |
55 | pwalletMain = NULL; | |
56 | bitdb.Reset(); | |
57 | RegisterNodeSignals(GetNodeSignals()); | |
58 | LogPrintf("%s: done\n", __func__); | |
59 | } | |
60 | ||
61 | void post_wallet_load(){ | |
62 | RegisterValidationInterface(pwalletMain); | |
63 | #ifdef ENABLE_MINING | |
64 | // Generate coins in the background | |
65 | if (pwalletMain || !GetArg("-mineraddress", "").empty()) | |
b2993bc5 | 66 | GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), Params()); |
2e8aefdc AG |
67 | #endif |
68 | } | |
69 | ||
2dc35992 | 70 | |
9e52ca32 | 71 | void timer_start(timeval &tv_start) |
6962bb3d TH |
72 | { |
73 | gettimeofday(&tv_start, 0); | |
74 | } | |
75 | ||
9e52ca32 | 76 | double timer_stop(timeval &tv_start) |
6962bb3d TH |
77 | { |
78 | double elapsed; | |
79 | struct timeval tv_end; | |
80 | gettimeofday(&tv_end, 0); | |
81 | elapsed = double(tv_end.tv_sec-tv_start.tv_sec) + | |
82 | (tv_end.tv_usec-tv_start.tv_usec)/double(1000000); | |
83 | return elapsed; | |
84 | } | |
85 | ||
86 | double benchmark_sleep() | |
87 | { | |
9e52ca32 JG |
88 | struct timeval tv_start; |
89 | timer_start(tv_start); | |
6962bb3d | 90 | sleep(1); |
9e52ca32 | 91 | return timer_stop(tv_start); |
6962bb3d TH |
92 | } |
93 | ||
94 | double benchmark_parameter_loading() | |
95 | { | |
96 | // FIXME: this is duplicated with the actual loading code | |
27e3f362 SB |
97 | boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key"; |
98 | boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key"; | |
6962bb3d | 99 | |
9e52ca32 JG |
100 | struct timeval tv_start; |
101 | timer_start(tv_start); | |
2dc35992 | 102 | |
1a9543d0 | 103 | auto newParams = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string()); |
2dc35992 | 104 | |
9e52ca32 | 105 | double ret = timer_stop(tv_start); |
2dc35992 SB |
106 | |
107 | delete newParams; | |
108 | ||
109 | return ret; | |
6962bb3d TH |
110 | } |
111 | ||
112 | double benchmark_create_joinsplit() | |
113 | { | |
e1a3461c | 114 | uint256 joinSplitPubKey; |
6962bb3d | 115 | |
6962bb3d | 116 | /* Get the anchor of an empty commitment tree. */ |
4fc309f0 | 117 | uint256 anchor = SproutMerkleTree().root(); |
6962bb3d | 118 | |
9e52ca32 JG |
119 | struct timeval tv_start; |
120 | timer_start(tv_start); | |
34f6ea95 | 121 | JSDescription jsdesc(true, |
b7a6c321 | 122 | *pzcashParams, |
e1a3461c | 123 | joinSplitPubKey, |
22de1602 SB |
124 | anchor, |
125 | {JSInput(), JSInput()}, | |
126 | {JSOutput(), JSOutput()}, | |
127 | 0, | |
128 | 0); | |
9e52ca32 | 129 | double ret = timer_stop(tv_start); |
21406393 | 130 | |
bc59f537 | 131 | auto verifier = libzcash::ProofVerifier::Strict(); |
e1a3461c | 132 | assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey)); |
6962bb3d TH |
133 | return ret; |
134 | } | |
bf8def97 | 135 | |
4082dcb1 JG |
136 | std::vector<double> benchmark_create_joinsplit_threaded(int nThreads) |
137 | { | |
138 | std::vector<double> ret; | |
139 | std::vector<std::future<double>> tasks; | |
140 | std::vector<std::thread> threads; | |
141 | for (int i = 0; i < nThreads; i++) { | |
142 | std::packaged_task<double(void)> task(&benchmark_create_joinsplit); | |
143 | tasks.emplace_back(task.get_future()); | |
144 | threads.emplace_back(std::move(task)); | |
145 | } | |
146 | std::future_status status; | |
147 | for (auto it = tasks.begin(); it != tasks.end(); it++) { | |
148 | it->wait(); | |
149 | ret.push_back(it->get()); | |
150 | } | |
151 | for (auto it = threads.begin(); it != threads.end(); it++) { | |
152 | it->join(); | |
153 | } | |
154 | return ret; | |
155 | } | |
156 | ||
a8c68ffe | 157 | double benchmark_verify_joinsplit(const JSDescription &joinsplit) |
a1cd1a27 | 158 | { |
9e52ca32 JG |
159 | struct timeval tv_start; |
160 | timer_start(tv_start); | |
e1a3461c | 161 | uint256 joinSplitPubKey; |
bc59f537 | 162 | auto verifier = libzcash::ProofVerifier::Strict(); |
e1a3461c | 163 | joinsplit.Verify(*pzcashParams, verifier, joinSplitPubKey); |
9e52ca32 | 164 | return timer_stop(tv_start); |
a1cd1a27 TH |
165 | } |
166 | ||
2cc0a252 | 167 | #ifdef ENABLE_MINING |
9e52ca32 | 168 | double benchmark_solve_equihash() |
bf8def97 | 169 | { |
722b0117 TH |
170 | CBlock pblock; |
171 | CEquihashInput I{pblock}; | |
172 | CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | |
173 | ss << I; | |
174 | ||
e9574728 JG |
175 | unsigned int n = Params(CBaseChainParams::MAIN).EquihashN(); |
176 | unsigned int k = Params(CBaseChainParams::MAIN).EquihashK(); | |
bf8def97 | 177 | crypto_generichash_blake2b_state eh_state; |
e9574728 | 178 | EhInitialiseState(n, k, eh_state); |
722b0117 TH |
179 | crypto_generichash_blake2b_update(&eh_state, (unsigned char*)&ss[0], ss.size()); |
180 | ||
181 | uint256 nonce; | |
182 | randombytes_buf(nonce.begin(), 32); | |
183 | crypto_generichash_blake2b_update(&eh_state, | |
184 | nonce.begin(), | |
185 | nonce.size()); | |
186 | ||
9e52ca32 JG |
187 | struct timeval tv_start; |
188 | timer_start(tv_start); | |
e9574728 | 189 | std::set<std::vector<unsigned int>> solns; |
51eb5273 | 190 | EhOptimisedSolveUncancellable(n, k, eh_state, |
5be6abbf | 191 | [](std::vector<unsigned char> soln) { return false; }); |
9e52ca32 | 192 | return timer_stop(tv_start); |
f7478de6 JG |
193 | } |
194 | ||
9e52ca32 | 195 | std::vector<double> benchmark_solve_equihash_threaded(int nThreads) |
f7478de6 | 196 | { |
9e52ca32 JG |
197 | std::vector<double> ret; |
198 | std::vector<std::future<double>> tasks; | |
199 | std::vector<std::thread> threads; | |
200 | for (int i = 0; i < nThreads; i++) { | |
201 | std::packaged_task<double(void)> task(&benchmark_solve_equihash); | |
202 | tasks.emplace_back(task.get_future()); | |
203 | threads.emplace_back(std::move(task)); | |
204 | } | |
205 | std::future_status status; | |
206 | for (auto it = tasks.begin(); it != tasks.end(); it++) { | |
207 | it->wait(); | |
208 | ret.push_back(it->get()); | |
209 | } | |
210 | for (auto it = threads.begin(); it != threads.end(); it++) { | |
211 | it->join(); | |
212 | } | |
213 | return ret; | |
bf8def97 | 214 | } |
2cc0a252 | 215 | #endif // ENABLE_MINING |
d44feea4 | 216 | |
a1cd1a27 | 217 | double benchmark_verify_equihash() |
d44feea4 | 218 | { |
a1cd1a27 TH |
219 | CChainParams params = Params(CBaseChainParams::MAIN); |
220 | CBlock genesis = Params(CBaseChainParams::MAIN).GenesisBlock(); | |
221 | CBlockHeader genesis_header = genesis.GetBlockHeader(); | |
9e52ca32 JG |
222 | struct timeval tv_start; |
223 | timer_start(tv_start); | |
a1cd1a27 | 224 | CheckEquihashSolution(&genesis_header, params); |
9e52ca32 | 225 | return timer_stop(tv_start); |
d44feea4 | 226 | } |
a1cd1a27 | 227 | |
818b94f9 | 228 | double benchmark_large_tx(size_t nInputs) |
f5edc37f | 229 | { |
9c45b501 SB |
230 | // Create priv/pub key |
231 | CKey priv; | |
232 | priv.MakeNewKey(false); | |
233 | auto pub = priv.GetPubKey(); | |
234 | CBasicKeyStore tempKeystore; | |
235 | tempKeystore.AddKey(priv); | |
236 | ||
237 | // The "original" transaction that the spending transaction will spend | |
238 | // from. | |
239 | CMutableTransaction m_orig_tx; | |
240 | m_orig_tx.vout.resize(1); | |
241 | m_orig_tx.vout[0].nValue = 1000000; | |
242 | CScript prevPubKey = GetScriptForDestination(pub.GetID()); | |
243 | m_orig_tx.vout[0].scriptPubKey = prevPubKey; | |
244 | ||
245 | auto orig_tx = CTransaction(m_orig_tx); | |
246 | ||
247 | CMutableTransaction spending_tx; | |
45539018 | 248 | spending_tx.fOverwintered = true; |
ddcee7e1 JG |
249 | spending_tx.nVersionGroupId = SAPLING_VERSION_GROUP_ID; |
250 | spending_tx.nVersion = SAPLING_TX_VERSION; | |
45539018 | 251 | |
805344dc | 252 | auto input_hash = orig_tx.GetHash(); |
818b94f9 JG |
253 | // Add nInputs inputs |
254 | for (size_t i = 0; i < nInputs; i++) { | |
9c45b501 | 255 | spending_tx.vin.emplace_back(input_hash, 0); |
f5edc37f JG |
256 | } |
257 | ||
9c45b501 | 258 | // Sign for all the inputs |
ddcee7e1 | 259 | auto consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId; |
818b94f9 | 260 | for (size_t i = 0; i < nInputs; i++) { |
be126699 | 261 | SignSignature(tempKeystore, prevPubKey, spending_tx, i, 1000000, SIGHASH_ALL, consensusBranchId); |
f5edc37f | 262 | } |
f5edc37f | 263 | |
822b84b6 S |
264 | // Spending tx has all its inputs signed and does not need to be mutated anymore |
265 | CTransaction final_spending_tx(spending_tx); | |
266 | ||
9c45b501 | 267 | // Benchmark signature verification costs: |
9e52ca32 JG |
268 | struct timeval tv_start; |
269 | timer_start(tv_start); | |
45539018 | 270 | PrecomputedTransactionData txdata(final_spending_tx); |
818b94f9 | 271 | for (size_t i = 0; i < nInputs; i++) { |
9c45b501 | 272 | ScriptError serror = SCRIPT_ERR_OK; |
75c2f268 | 273 | assert(VerifyScript(final_spending_tx.vin[i].scriptSig, |
9c45b501 SB |
274 | prevPubKey, |
275 | STANDARD_SCRIPT_VERIFY_FLAGS, | |
45539018 | 276 | TransactionSignatureChecker(&final_spending_tx, i, 1000000, txdata), |
be126699 | 277 | consensusBranchId, |
9c45b501 SB |
278 | &serror)); |
279 | } | |
9e52ca32 | 280 | return timer_stop(tv_start); |
f5edc37f JG |
281 | } |
282 | ||
3e5cc59c | 283 | // The two benchmarks, try_decrypt_sprout_notes and try_decrypt_sapling_notes, |
8a1d1930 | 284 | // are checking worst-case scenarios. In both we add n keys to a wallet, |
3e5cc59c EOW |
285 | // create a transaction using a key not in our original list of n, and then |
286 | // check that the transaction is not associated with any of the keys in our | |
287 | // wallet. We call assert(...) to ensure that this is true. | |
288 | double benchmark_try_decrypt_sprout_notes(size_t nKeys) | |
0fbab55b | 289 | { |
0fbab55b | 290 | CWallet wallet; |
3e5cc59c | 291 | for (int i = 0; i < nKeys; i++) { |
e5eab182 | 292 | auto sk = libzcash::SproutSpendingKey::random(); |
25d5e80c | 293 | wallet.AddSproutSpendingKey(sk); |
0fbab55b JG |
294 | } |
295 | ||
e5eab182 | 296 | auto sk = libzcash::SproutSpendingKey::random(); |
8f410367 | 297 | auto tx = GetValidSproutReceive(*pzcashParams, sk, 10, true); |
0fbab55b JG |
298 | |
299 | struct timeval tv_start; | |
300 | timer_start(tv_start); | |
3e5cc59c EOW |
301 | auto noteDataMap = wallet.FindMySproutNotes(tx); |
302 | ||
303 | assert(noteDataMap.empty()); | |
0fbab55b JG |
304 | return timer_stop(tv_start); |
305 | } | |
306 | ||
3e5cc59c | 307 | double benchmark_try_decrypt_sapling_notes(size_t nKeys) |
89e75c8c EOW |
308 | { |
309 | // Set params | |
a6a17c45 | 310 | auto consensusParams = Params().GetConsensus(); |
89e75c8c | 311 | |
8a1d1930 | 312 | auto masterKey = GetTestMasterSaplingSpendingKey(); |
89e75c8c EOW |
313 | |
314 | CWallet wallet; | |
89e75c8c | 315 | |
8a1d1930 | 316 | for (int i = 0; i < nKeys; i++) { |
89e75c8c EOW |
317 | auto sk = masterKey.Derive(i); |
318 | wallet.AddSaplingSpendingKey(sk, sk.DefaultAddress()); | |
319 | } | |
320 | ||
8a1d1930 EOW |
321 | // Generate a key that has not been added to the wallet |
322 | auto sk = masterKey.Derive(nKeys); | |
3e5cc59c | 323 | auto tx = GetValidSaplingReceive(consensusParams, wallet, sk, 10); |
89e75c8c EOW |
324 | |
325 | struct timeval tv_start; | |
326 | timer_start(tv_start); | |
3e5cc59c EOW |
327 | auto noteDataMapAndAddressesToAdd = wallet.FindMySaplingNotes(tx); |
328 | assert(noteDataMapAndAddressesToAdd.first.empty()); | |
a6a17c45 | 329 | return timer_stop(tv_start); |
89e75c8c EOW |
330 | } |
331 | ||
edac39b8 EOW |
332 | CWalletTx CreateSproutTxWithNoteData(const libzcash::SproutSpendingKey& sk) { |
333 | auto wtx = GetValidSproutReceive(*pzcashParams, sk, 10, true); | |
334 | auto note = GetSproutNote(*pzcashParams, sk, wtx, 0, 1); | |
335 | auto nullifier = note.nullifier(sk); | |
336 | ||
337 | mapSproutNoteData_t noteDataMap; | |
338 | JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; | |
339 | SproutNoteData nd {sk.address(), nullifier}; | |
340 | noteDataMap[jsoutpt] = nd; | |
341 | ||
342 | wtx.SetSproutNoteData(noteDataMap); | |
343 | ||
344 | return wtx; | |
345 | } | |
346 | ||
8a1d1930 | 347 | double benchmark_increment_sprout_note_witnesses(size_t nTxs) |
3e5cc59c EOW |
348 | { |
349 | auto consensusParams = Params().GetConsensus(); | |
350 | ||
351 | CWallet wallet; | |
352 | SproutMerkleTree sproutTree; | |
353 | SaplingMerkleTree saplingTree; | |
354 | ||
355 | auto sproutSpendingKey = libzcash::SproutSpendingKey::random(); | |
356 | wallet.AddSproutSpendingKey(sproutSpendingKey); | |
357 | ||
358 | // First block | |
359 | CBlock block1; | |
360 | for (int i = 0; i < nTxs; ++i) { | |
361 | auto wtx = CreateSproutTxWithNoteData(sproutSpendingKey); | |
362 | wallet.AddToWallet(wtx, true, NULL); | |
363 | block1.vtx.push_back(wtx); | |
364 | } | |
365 | ||
366 | CBlockIndex index1(block1); | |
367 | index1.nHeight = 1; | |
368 | ||
369 | // Increment to get transactions witnessed | |
370 | wallet.ChainTip(&index1, &block1, sproutTree, saplingTree, true); | |
371 | ||
372 | // Second block | |
373 | CBlock block2; | |
374 | block2.hashPrevBlock = block1.GetHash(); | |
375 | { | |
376 | auto sproutTx = CreateSproutTxWithNoteData(sproutSpendingKey); | |
377 | wallet.AddToWallet(sproutTx, true, NULL); | |
378 | block2.vtx.push_back(sproutTx); | |
379 | } | |
380 | ||
381 | CBlockIndex index2(block2); | |
382 | index2.nHeight = 2; | |
383 | ||
384 | struct timeval tv_start; | |
385 | timer_start(tv_start); | |
386 | wallet.ChainTip(&index2, &block2, sproutTree, saplingTree, true); | |
387 | return timer_stop(tv_start); | |
388 | } | |
389 | ||
edac39b8 | 390 | CWalletTx CreateSaplingTxWithNoteData(const Consensus::Params& consensusParams, |
3e5cc59c | 391 | CBasicKeyStore& keyStore, |
edac39b8 | 392 | const libzcash::SaplingExtendedSpendingKey &sk) { |
3e5cc59c | 393 | auto wtx = GetValidSaplingReceive(consensusParams, keyStore, sk, 10); |
edac39b8 EOW |
394 | auto testNote = GetTestSaplingNote(sk.DefaultAddress(), 10); |
395 | auto fvk = sk.expsk.full_viewing_key(); | |
396 | auto nullifier = testNote.note.nullifier(fvk, testNote.tree.witness().position()).get(); | |
397 | ||
398 | mapSaplingNoteData_t noteDataMap; | |
399 | SaplingOutPoint outPoint {wtx.GetHash(), 0}; | |
400 | auto ivk = fvk.in_viewing_key(); | |
401 | SaplingNoteData noteData {ivk, nullifier}; | |
402 | noteDataMap[outPoint] = noteData; | |
403 | ||
404 | wtx.SetSaplingNoteData(noteDataMap); | |
405 | ||
406 | return wtx; | |
407 | } | |
408 | ||
8a1d1930 | 409 | double benchmark_increment_sapling_note_witnesses(size_t nTxs) |
0bb3d40f | 410 | { |
a6a17c45 | 411 | auto consensusParams = Params().GetConsensus(); |
edac39b8 | 412 | |
0bb3d40f | 413 | CWallet wallet; |
4fc309f0 EOW |
414 | SproutMerkleTree sproutTree; |
415 | SaplingMerkleTree saplingTree; | |
0bb3d40f | 416 | |
8a1d1930 | 417 | auto saplingSpendingKey = GetTestMasterSaplingSpendingKey(); |
edac39b8 | 418 | wallet.AddSaplingSpendingKey(saplingSpendingKey, saplingSpendingKey.DefaultAddress()); |
0bb3d40f | 419 | |
edac39b8 EOW |
420 | // First block |
421 | CBlock block1; | |
3e5cc59c EOW |
422 | for (int i = 0; i < nTxs; ++i) { |
423 | auto wtx = CreateSaplingTxWithNoteData(consensusParams, wallet, saplingSpendingKey); | |
0bb3d40f JG |
424 | wallet.AddToWallet(wtx, true, NULL); |
425 | block1.vtx.push_back(wtx); | |
426 | } | |
edac39b8 | 427 | |
0bb3d40f JG |
428 | CBlockIndex index1(block1); |
429 | index1.nHeight = 1; | |
430 | ||
431 | // Increment to get transactions witnessed | |
f86ee1c2 | 432 | wallet.ChainTip(&index1, &block1, sproutTree, saplingTree, true); |
0bb3d40f JG |
433 | |
434 | // Second block | |
435 | CBlock block2; | |
436 | block2.hashPrevBlock = block1.GetHash(); | |
9755eb82 | 437 | { |
3e5cc59c | 438 | auto saplingTx = CreateSaplingTxWithNoteData(consensusParams, wallet, saplingSpendingKey); |
edac39b8 EOW |
439 | wallet.AddToWallet(saplingTx, true, NULL); |
440 | block1.vtx.push_back(saplingTx); | |
9755eb82 | 441 | } |
edac39b8 | 442 | |
0bb3d40f JG |
443 | CBlockIndex index2(block2); |
444 | index2.nHeight = 2; | |
445 | ||
446 | struct timeval tv_start; | |
447 | timer_start(tv_start); | |
f86ee1c2 | 448 | wallet.ChainTip(&index2, &block2, sproutTree, saplingTree, true); |
a6a17c45 | 449 | return timer_stop(tv_start); |
0bb3d40f JG |
450 | } |
451 | ||
c66c731a | 452 | // Fake the input of a given block |
010481c7 EOW |
453 | // This class is based on the class CCoinsViewDB, but with limited functionality. |
454 | // The construtor and the functions `GetCoins` and `HaveCoins` come directly from | |
455 | // CCoinsViewDB, but the rest are either mocks and/or don't really do anything. | |
e1df250a LR |
456 | |
457 | // The following constant is a duplicate of the one found in txdb.cpp | |
458 | static const char DB_COINS = 'c'; | |
459 | ||
010481c7 | 460 | class FakeCoinsViewDB : public CCoinsView { |
010481c7 EOW |
461 | |
462 | CDBWrapper db; | |
463 | ||
c66c731a | 464 | uint256 hash; |
010481c7 EOW |
465 | SproutMerkleTree sproutTree; |
466 | SaplingMerkleTree saplingTree; | |
c66c731a JG |
467 | |
468 | public: | |
010481c7 EOW |
469 | FakeCoinsViewDB(std::string dbName, uint256& hash) : db(GetDataDir() / dbName, 100, false, false), hash(hash) {} |
470 | ||
471 | bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { | |
472 | if (rt == sproutTree.root()) { | |
473 | tree = sproutTree; | |
474 | return true; | |
475 | } | |
476 | return false; | |
477 | } | |
c66c731a | 478 | |
010481c7 EOW |
479 | bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { |
480 | if (rt == saplingTree.root()) { | |
481 | tree = saplingTree; | |
c66c731a JG |
482 | return true; |
483 | } | |
484 | return false; | |
485 | } | |
486 | ||
28d20bdb | 487 | bool GetNullifier(const uint256 &nf, ShieldedType type) const { |
c66c731a JG |
488 | return false; |
489 | } | |
490 | ||
010481c7 EOW |
491 | bool GetCoins(const uint256 &txid, CCoins &coins) const { |
492 | return db.Read(std::make_pair(DB_COINS, txid), coins); | |
493 | } | |
494 | ||
495 | bool HaveCoins(const uint256 &txid) const { | |
496 | return db.Exists(std::make_pair(DB_COINS, txid)); | |
497 | } | |
498 | ||
c66c731a JG |
499 | uint256 GetBestBlock() const { |
500 | return hash; | |
501 | } | |
502 | ||
010481c7 EOW |
503 | uint256 GetBestAnchor(ShieldedType type) const { |
504 | switch (type) { | |
505 | case SPROUT: | |
506 | return sproutTree.root(); | |
507 | case SAPLING: | |
508 | return saplingTree.root(); | |
509 | default: | |
510 | throw new std::runtime_error("Unknown shielded type"); | |
511 | } | |
c66c731a JG |
512 | } |
513 | ||
514 | bool BatchWrite(CCoinsMap &mapCoins, | |
515 | const uint256 &hashBlock, | |
010481c7 EOW |
516 | const uint256 &hashSproutAnchor, |
517 | const uint256 &hashSaplingAnchor, | |
d455828f | 518 | CAnchorsSproutMap &mapSproutAnchors, |
010481c7 | 519 | CAnchorsSaplingMap &mapSaplingAnchors, |
9669920f | 520 | CNullifiersMap &mapSproutNullifiers, |
010481c7 | 521 | CNullifiersMap &mapSaplingNullifiers) { |
c66c731a JG |
522 | return false; |
523 | } | |
524 | ||
525 | bool GetStats(CCoinsStats &stats) const { | |
526 | return false; | |
527 | } | |
528 | }; | |
529 | ||
530 | double benchmark_connectblock_slow() | |
531 | { | |
532 | // Test for issue 2017-05-01.a | |
533 | SelectParams(CBaseChainParams::MAIN); | |
534 | CBlock block; | |
535 | FILE* fp = fopen((GetDataDir() / "benchmark/block-107134.dat").string().c_str(), "rb"); | |
536 | if (!fp) throw new std::runtime_error("Failed to open block data file"); | |
537 | CAutoFile blkFile(fp, SER_DISK, CLIENT_VERSION); | |
538 | blkFile >> block; | |
539 | blkFile.fclose(); | |
540 | ||
541 | // Fake its inputs | |
542 | auto hashPrev = uint256S("00000000159a41f468e22135942a567781c3f3dc7ad62257993eb3c69c3f95ef"); | |
543 | FakeCoinsViewDB fakeDB("benchmark/block-107134-inputs", hashPrev); | |
544 | CCoinsViewCache view(&fakeDB); | |
545 | ||
546 | // Fake the chain | |
547 | CBlockIndex index(block); | |
548 | index.nHeight = 107134; | |
549 | CBlockIndex indexPrev; | |
550 | indexPrev.phashBlock = &hashPrev; | |
551 | indexPrev.nHeight = index.nHeight - 1; | |
552 | index.pprev = &indexPrev; | |
553 | mapBlockIndex.insert(std::make_pair(hashPrev, &indexPrev)); | |
554 | ||
555 | CValidationState state; | |
556 | struct timeval tv_start; | |
557 | timer_start(tv_start); | |
558 | assert(ConnectBlock(block, state, &index, view, true)); | |
559 | auto duration = timer_stop(tv_start); | |
560 | ||
561 | // Undo alterations to global state | |
562 | mapBlockIndex.erase(hashPrev); | |
563 | SelectParamsFromCommandLine(); | |
564 | ||
565 | return duration; | |
566 | } | |
567 | ||
34aca1b0 JS |
568 | extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp |
569 | extern UniValue sendtoaddress(const UniValue& params, bool fHelp); | |
570 | ||
a76174b7 JG |
571 | double benchmark_sendtoaddress(CAmount amount) |
572 | { | |
573 | UniValue params(UniValue::VARR); | |
574 | auto addr = getnewaddress(params, false); | |
575 | ||
576 | params.push_back(addr); | |
577 | params.push_back(ValueFromAmount(amount)); | |
578 | ||
579 | struct timeval tv_start; | |
580 | timer_start(tv_start); | |
581 | auto txid = sendtoaddress(params, false); | |
582 | return timer_stop(tv_start); | |
583 | } | |
584 | ||
2e8aefdc AG |
585 | double benchmark_loadwallet() |
586 | { | |
587 | pre_wallet_load(); | |
588 | struct timeval tv_start; | |
589 | bool fFirstRunRet=true; | |
590 | timer_start(tv_start); | |
591 | pwalletMain = new CWallet("wallet.dat"); | |
592 | DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRunRet); | |
593 | auto res = timer_stop(tv_start); | |
594 | post_wallet_load(); | |
595 | return res; | |
596 | } | |
99dd50c3 | 597 | |
a9496b08 WL |
598 | extern UniValue listunspent(const UniValue& params, bool fHelp); |
599 | ||
99dd50c3 JG |
600 | double benchmark_listunspent() |
601 | { | |
602 | UniValue params(UniValue::VARR); | |
603 | struct timeval tv_start; | |
604 | timer_start(tv_start); | |
605 | auto unspent = listunspent(params, false); | |
606 | return timer_stop(tv_start); | |
607 | } | |
67d2b797 S |
608 | |
609 | double benchmark_create_sapling_spend() | |
610 | { | |
611 | auto sk = libzcash::SaplingSpendingKey::random(); | |
612 | auto expsk = sk.expanded_spending_key(); | |
613 | auto address = sk.default_address(); | |
614 | SaplingNote note(address, GetRand(MAX_MONEY)); | |
615 | SaplingMerkleTree tree; | |
616 | auto maybe_cm = note.cm(); | |
617 | tree.append(maybe_cm.get()); | |
618 | auto anchor = tree.root(); | |
619 | auto witness = tree.witness(); | |
620 | auto maybe_nf = note.nullifier(expsk.full_viewing_key(), witness.position()); | |
621 | if (!(maybe_cm && maybe_nf)) { | |
622 | throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not create note commitment and nullifier"); | |
623 | } | |
624 | ||
625 | CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | |
626 | ss << witness.path(); | |
627 | std::vector<unsigned char> witnessChars(ss.begin(), ss.end()); | |
628 | ||
629 | uint256 alpha; | |
630 | librustzcash_sapling_generate_r(alpha.begin()); | |
631 | ||
632 | auto ctx = librustzcash_sapling_proving_ctx_init(); | |
633 | ||
634 | struct timeval tv_start; | |
635 | timer_start(tv_start); | |
636 | ||
637 | SpendDescription sdesc; | |
638 | bool result = librustzcash_sapling_spend_proof( | |
639 | ctx, | |
640 | expsk.full_viewing_key().ak.begin(), | |
641 | expsk.nsk.begin(), | |
642 | note.d.data(), | |
643 | note.r.begin(), | |
644 | alpha.begin(), | |
645 | note.value(), | |
646 | anchor.begin(), | |
647 | witnessChars.data(), | |
648 | sdesc.cv.begin(), | |
649 | sdesc.rk.begin(), | |
650 | sdesc.zkproof.data()); | |
651 | ||
652 | double t = timer_stop(tv_start); | |
653 | librustzcash_sapling_proving_ctx_free(ctx); | |
654 | if (!result) { | |
655 | throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_spend_proof() should return true"); | |
656 | } | |
657 | return t; | |
658 | } | |
659 | ||
660 | double benchmark_create_sapling_output() | |
661 | { | |
662 | auto sk = libzcash::SaplingSpendingKey::random(); | |
663 | auto address = sk.default_address(); | |
664 | ||
665 | std::array<unsigned char, ZC_MEMO_SIZE> memo; | |
666 | SaplingNote note(address, GetRand(MAX_MONEY)); | |
667 | ||
668 | libzcash::SaplingNotePlaintext notePlaintext(note, memo); | |
669 | auto res = notePlaintext.encrypt(note.pk_d); | |
670 | if (!res) { | |
671 | throw JSONRPCError(RPC_INTERNAL_ERROR, "SaplingNotePlaintext::encrypt() failed"); | |
672 | } | |
673 | ||
674 | auto enc = res.get(); | |
675 | auto encryptor = enc.second; | |
676 | ||
677 | auto ctx = librustzcash_sapling_proving_ctx_init(); | |
678 | ||
679 | struct timeval tv_start; | |
680 | timer_start(tv_start); | |
681 | ||
682 | OutputDescription odesc; | |
683 | bool result = librustzcash_sapling_output_proof( | |
684 | ctx, | |
685 | encryptor.get_esk().begin(), | |
686 | note.d.data(), | |
687 | note.pk_d.begin(), | |
688 | note.r.begin(), | |
689 | note.value(), | |
690 | odesc.cv.begin(), | |
691 | odesc.zkproof.begin()); | |
692 | ||
693 | double t = timer_stop(tv_start); | |
694 | librustzcash_sapling_proving_ctx_free(ctx); | |
695 | if (!result) { | |
696 | throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_output_proof() should return true"); | |
697 | } | |
698 | return t; | |
699 | } | |
700 | ||
701 | // Verify Sapling spend from testnet | |
702 | // txid: abbd823cbd3d4e3b52023599d81a96b74817e95ce5bb58354f979156bd22ecc8 | |
703 | // position: 0 | |
704 | double benchmark_verify_sapling_spend() | |
705 | { | |
706 | SpendDescription spend; | |
707 | CDataStream ss(ParseHex("8c6cf86bbb83bf0d075e5bd9bb4b5cd56141577be69f032880b11e26aa32aa5ef09fd00899e4b469fb11f38e9d09dc0379f0b11c23b5fe541765f76695120a03f0261d32af5d2a2b1e5c9a04200cd87d574dc42349de9790012ce560406a8a876a1e54cfcdc0eb74998abec2a9778330eeb2a0ac0e41d0c9ed5824fbd0dbf7da930ab299966ce333fd7bc1321dada0817aac5444e02c754069e218746bf879d5f2a20a8b028324fb2c73171e63336686aa5ec2e6e9a08eb18b87c14758c572f4531ccf6b55d09f44beb8b47563be4eff7a52598d80959dd9c9fee5ac4783d8370cb7d55d460053d3e067b5f9fe75ff2722623fb1825fcba5e9593d4205b38d1f502ff03035463043bd393a5ee039ce75a5d54f21b395255df6627ef96751566326f7d4a77d828aa21b1827282829fcbc42aad59cdb521e1a3aaa08b99ea8fe7fff0a04da31a52260fc6daeccd79bb877bdd8506614282258e15b3fe74bf71a93f4be3b770119edf99a317b205eea7d5ab800362b97384273888106c77d633600"), SER_NETWORK, PROTOCOL_VERSION); | |
708 | ss >> spend; | |
709 | uint256 dataToBeSigned = uint256S("0x2dbf83fe7b88a7cbd80fac0c719483906bb9a0c4fc69071e4780d5f2c76e592c"); | |
710 | ||
711 | auto ctx = librustzcash_sapling_verification_ctx_init(); | |
712 | ||
713 | struct timeval tv_start; | |
714 | timer_start(tv_start); | |
715 | ||
716 | bool result = librustzcash_sapling_check_spend( | |
717 | ctx, | |
718 | spend.cv.begin(), | |
719 | spend.anchor.begin(), | |
720 | spend.nullifier.begin(), | |
721 | spend.rk.begin(), | |
722 | spend.zkproof.begin(), | |
723 | spend.spendAuthSig.begin(), | |
724 | dataToBeSigned.begin() | |
725 | ); | |
726 | ||
727 | double t = timer_stop(tv_start); | |
728 | librustzcash_sapling_verification_ctx_free(ctx); | |
729 | if (!result) { | |
730 | throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_check_spend() should return true"); | |
731 | } | |
732 | return t; | |
733 | } | |
734 | ||
735 | // Verify Sapling output from testnet | |
736 | // txid: abbd823cbd3d4e3b52023599d81a96b74817e95ce5bb58354f979156bd22ecc8 | |
737 | // position: 0 | |
738 | double benchmark_verify_sapling_output() | |
739 | { | |
740 | OutputDescription output; | |
741 | CDataStream ss(ParseHex("edd742af18857e5ec2d71d346a7fe2ac97c137339bd5268eea86d32e0ff4f38f76213fa8cfed3347ac4e8572dd88aff395c0c10a59f8b3f49d2bc539ed6c726667e29d4763f914ddd0abf1cdfa84e44de87c233434c7e69b8b5b8f4623c8aa444163425bae5cef842972fed66046c1c6ce65c866ad894d02e6e6dcaae7a962d9f2ef95757a09c486928e61f0f7aed90ad0a542b0d3dc5fe140dfa7626b9315c77e03b055f19cbacd21a866e46f06c00e0c7792b2a590a611439b510a9aaffcf1073bad23e712a9268b36888e3727033eee2ab4d869f54a843f93b36ef489fb177bf74b41a9644e5d2a0a417c6ac1c8869bc9b83273d453f878ed6fd96b82a5939903f7b64ecaf68ea16e255a7fb7cc0b6d8b5608a1c6b0ed3024cc62c2f0f9c5cfc7b431ae6e9d40815557aa1d010523f9e1960de77b2274cb6710d229d475c87ae900183206ba90cb5bbc8ec0df98341b82726c705e0308ca5dc08db4db609993a1046dfb43dfd8c760be506c0bed799bb2205fc29dc2e654dce731034a23b0aaf6da0199248702ee0523c159f41f4cbfff6c35ace4dd9ae834e44e09c76a0cbdda1d3f6a2c75ad71212daf9575ab5f09ca148718e667f29ddf18c8a330a86ace18a86e89454653902aa393c84c6b694f27d0d42e24e7ac9fe34733de5ec15f5066081ce912c62c1a804a2bb4dedcef7cc80274f6bb9e89e2fce91dc50d6a73c8aefb9872f1cf3524a92626a0b8f39bbf7bf7d96ca2f770fc04d7f457021c536a506a187a93b2245471ddbfb254a71bc4a0d72c8d639a31c7b1920087ffca05c24214157e2e7b28184e91989ef0b14f9b34c3dc3cc0ac64226b9e337095870cb0885737992e120346e630a416a9b217679ce5a778fb15779c136bcecca5efe79012013d77d90b4e99dd22c8f35bc77121716e160d05bd30d288ee8886390ee436f85bdc9029df888a3a3326d9d4ddba5cb5318b3274928829d662e96fea1d601f7a306251ed8c6cc4e5a3a7a98c35a3650482a0eee08f3b4c2da9b22947c96138f1505c2f081f8972d429f3871f32bef4aaa51aa6945df8e9c9760531ac6f627d17c1518202818a91ca304fb4037875c666060597976144fcbbc48a776a2c61beb9515fa8f3ae6d3a041d320a38a8ac75cb47bb9c866ee497fc3cd13299970c4b369c1c2ceb4220af082fbecdd8114492a8e4d713b5a73396fd224b36c1185bd5e20d683e6c8db35346c47ae7401988255da7cfffdced5801067d4d296688ee8fe424b4a8a69309ce257eefb9345ebfda3f6de46bb11ec94133e1f72cd7ac54934d6cf17b3440800e70b80ebc7c7bfc6fb0fc2c"), SER_NETWORK, PROTOCOL_VERSION); | |
742 | ss >> output; | |
743 | ||
744 | auto ctx = librustzcash_sapling_verification_ctx_init(); | |
745 | ||
746 | struct timeval tv_start; | |
747 | timer_start(tv_start); | |
748 | ||
749 | bool result = librustzcash_sapling_check_output( | |
750 | ctx, | |
751 | output.cv.begin(), | |
752 | output.cm.begin(), | |
753 | output.ephemeralKey.begin(), | |
754 | output.zkproof.begin() | |
755 | ); | |
756 | ||
757 | double t = timer_stop(tv_start); | |
758 | librustzcash_sapling_verification_ctx_free(ctx); | |
759 | if (!result) { | |
760 | throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_check_output() should return true"); | |
761 | } | |
762 | return timer_stop(tv_start); | |
763 | } |