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