]>
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 | |
47 | GenerateBitcoins(false, NULL, 0); | |
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()) | |
94f9918f | 66 | GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 0)); |
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 | ||
88b7f3c2 | 283 | double benchmark_try_decrypt_notes(size_t nAddrs) |
0fbab55b | 284 | { |
0fbab55b | 285 | CWallet wallet; |
88b7f3c2 | 286 | for (int i = 0; i < nAddrs; i++) { |
e5eab182 | 287 | auto sk = libzcash::SproutSpendingKey::random(); |
25d5e80c | 288 | wallet.AddSproutSpendingKey(sk); |
0fbab55b JG |
289 | } |
290 | ||
e5eab182 | 291 | auto sk = libzcash::SproutSpendingKey::random(); |
88b7f3c2 | 292 | auto tx = GetValidReceive(*pzcashParams, sk, 10, true); |
0fbab55b JG |
293 | |
294 | struct timeval tv_start; | |
295 | timer_start(tv_start); | |
57faf44e | 296 | auto nd = wallet.FindMySproutNotes(tx); |
0fbab55b JG |
297 | return timer_stop(tv_start); |
298 | } | |
299 | ||
0bb3d40f JG |
300 | double benchmark_increment_note_witnesses(size_t nTxs) |
301 | { | |
302 | CWallet wallet; | |
4fc309f0 EOW |
303 | SproutMerkleTree sproutTree; |
304 | SaplingMerkleTree saplingTree; | |
0bb3d40f | 305 | |
e5eab182 | 306 | auto sk = libzcash::SproutSpendingKey::random(); |
25d5e80c | 307 | wallet.AddSproutSpendingKey(sk); |
0bb3d40f JG |
308 | |
309 | // First block | |
310 | CBlock block1; | |
311 | for (int i = 0; i < nTxs; i++) { | |
312 | auto wtx = GetValidReceive(*pzcashParams, sk, 10, true); | |
313 | auto note = GetNote(*pzcashParams, sk, wtx, 0, 1); | |
314 | auto nullifier = note.nullifier(sk); | |
315 | ||
005f3ad1 | 316 | mapSproutNoteData_t noteData; |
0bb3d40f | 317 | JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; |
005f3ad1 | 318 | SproutNoteData nd {sk.address(), nullifier}; |
0bb3d40f JG |
319 | noteData[jsoutpt] = nd; |
320 | ||
8e8279e7 | 321 | wtx.SetSproutNoteData(noteData); |
0bb3d40f JG |
322 | wallet.AddToWallet(wtx, true, NULL); |
323 | block1.vtx.push_back(wtx); | |
324 | } | |
325 | CBlockIndex index1(block1); | |
4b729ec5 | 326 | index1.SetHeight(1); |
0bb3d40f JG |
327 | |
328 | // Increment to get transactions witnessed | |
f86ee1c2 | 329 | wallet.ChainTip(&index1, &block1, sproutTree, saplingTree, true); |
0bb3d40f JG |
330 | |
331 | // Second block | |
332 | CBlock block2; | |
333 | block2.hashPrevBlock = block1.GetHash(); | |
9755eb82 JG |
334 | { |
335 | auto wtx = GetValidReceive(*pzcashParams, sk, 10, true); | |
336 | auto note = GetNote(*pzcashParams, sk, wtx, 0, 1); | |
337 | auto nullifier = note.nullifier(sk); | |
338 | ||
005f3ad1 | 339 | mapSproutNoteData_t noteData; |
9755eb82 | 340 | JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; |
005f3ad1 | 341 | SproutNoteData nd {sk.address(), nullifier}; |
9755eb82 JG |
342 | noteData[jsoutpt] = nd; |
343 | ||
8e8279e7 | 344 | wtx.SetSproutNoteData(noteData); |
9755eb82 JG |
345 | wallet.AddToWallet(wtx, true, NULL); |
346 | block2.vtx.push_back(wtx); | |
347 | } | |
0bb3d40f | 348 | CBlockIndex index2(block2); |
4b729ec5 | 349 | index2.SetHeight(2); |
0bb3d40f JG |
350 | |
351 | struct timeval tv_start; | |
352 | timer_start(tv_start); | |
f86ee1c2 | 353 | wallet.ChainTip(&index2, &block2, sproutTree, saplingTree, true); |
0bb3d40f JG |
354 | return timer_stop(tv_start); |
355 | } | |
356 | ||
c66c731a JG |
357 | // Fake the input of a given block |
358 | class FakeCoinsViewDB : public CCoinsViewDB { | |
359 | uint256 hash; | |
4fc309f0 | 360 | SproutMerkleTree t; |
c66c731a JG |
361 | |
362 | public: | |
363 | FakeCoinsViewDB(std::string dbName, uint256& hash) : CCoinsViewDB(dbName, 100, false, false), hash(hash) {} | |
364 | ||
4fc309f0 | 365 | bool GetAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { |
c66c731a JG |
366 | if (rt == t.root()) { |
367 | tree = t; | |
368 | return true; | |
369 | } | |
370 | return false; | |
371 | } | |
372 | ||
28d20bdb | 373 | bool GetNullifier(const uint256 &nf, ShieldedType type) const { |
c66c731a JG |
374 | return false; |
375 | } | |
376 | ||
377 | uint256 GetBestBlock() const { | |
378 | return hash; | |
379 | } | |
380 | ||
381 | uint256 GetBestAnchor() const { | |
382 | return t.root(); | |
383 | } | |
384 | ||
385 | bool BatchWrite(CCoinsMap &mapCoins, | |
386 | const uint256 &hashBlock, | |
387 | const uint256 &hashAnchor, | |
d455828f | 388 | CAnchorsSproutMap &mapSproutAnchors, |
9669920f | 389 | CNullifiersMap &mapSproutNullifiers, |
685e936c | 390 | CNullifiersMap& mapSaplingNullifiers) { |
c66c731a JG |
391 | return false; |
392 | } | |
393 | ||
394 | bool GetStats(CCoinsStats &stats) const { | |
395 | return false; | |
396 | } | |
397 | }; | |
398 | ||
399 | double benchmark_connectblock_slow() | |
400 | { | |
401 | // Test for issue 2017-05-01.a | |
402 | SelectParams(CBaseChainParams::MAIN); | |
403 | CBlock block; | |
404 | FILE* fp = fopen((GetDataDir() / "benchmark/block-107134.dat").string().c_str(), "rb"); | |
405 | if (!fp) throw new std::runtime_error("Failed to open block data file"); | |
406 | CAutoFile blkFile(fp, SER_DISK, CLIENT_VERSION); | |
407 | blkFile >> block; | |
408 | blkFile.fclose(); | |
409 | ||
410 | // Fake its inputs | |
411 | auto hashPrev = uint256S("00000000159a41f468e22135942a567781c3f3dc7ad62257993eb3c69c3f95ef"); | |
412 | FakeCoinsViewDB fakeDB("benchmark/block-107134-inputs", hashPrev); | |
413 | CCoinsViewCache view(&fakeDB); | |
414 | ||
415 | // Fake the chain | |
416 | CBlockIndex index(block); | |
4b729ec5 | 417 | index.SetHeight(107134); |
c66c731a JG |
418 | CBlockIndex indexPrev; |
419 | indexPrev.phashBlock = &hashPrev; | |
4b729ec5 | 420 | indexPrev.SetHeight(index.GetHeight() - 1); |
c66c731a JG |
421 | index.pprev = &indexPrev; |
422 | mapBlockIndex.insert(std::make_pair(hashPrev, &indexPrev)); | |
423 | ||
424 | CValidationState state; | |
425 | struct timeval tv_start; | |
426 | timer_start(tv_start); | |
427 | assert(ConnectBlock(block, state, &index, view, true)); | |
428 | auto duration = timer_stop(tv_start); | |
429 | ||
430 | // Undo alterations to global state | |
431 | mapBlockIndex.erase(hashPrev); | |
432 | SelectParamsFromCommandLine(); | |
433 | ||
434 | return duration; | |
435 | } | |
436 | ||
34aca1b0 JS |
437 | extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp |
438 | extern UniValue sendtoaddress(const UniValue& params, bool fHelp); | |
439 | ||
a76174b7 JG |
440 | double benchmark_sendtoaddress(CAmount amount) |
441 | { | |
442 | UniValue params(UniValue::VARR); | |
443 | auto addr = getnewaddress(params, false); | |
444 | ||
445 | params.push_back(addr); | |
446 | params.push_back(ValueFromAmount(amount)); | |
447 | ||
448 | struct timeval tv_start; | |
449 | timer_start(tv_start); | |
450 | auto txid = sendtoaddress(params, false); | |
451 | return timer_stop(tv_start); | |
452 | } | |
453 | ||
2e8aefdc AG |
454 | double benchmark_loadwallet() |
455 | { | |
456 | pre_wallet_load(); | |
457 | struct timeval tv_start; | |
458 | bool fFirstRunRet=true; | |
459 | timer_start(tv_start); | |
460 | pwalletMain = new CWallet("wallet.dat"); | |
461 | DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRunRet); | |
462 | auto res = timer_stop(tv_start); | |
463 | post_wallet_load(); | |
464 | return res; | |
465 | } | |
99dd50c3 | 466 | |
a9496b08 WL |
467 | extern UniValue listunspent(const UniValue& params, bool fHelp); |
468 | ||
99dd50c3 JG |
469 | double benchmark_listunspent() |
470 | { | |
471 | UniValue params(UniValue::VARR); | |
472 | struct timeval tv_start; | |
473 | timer_start(tv_start); | |
474 | auto unspent = listunspent(params, false); | |
475 | return timer_stop(tv_start); | |
476 | } | |
67d2b797 S |
477 | |
478 | double benchmark_create_sapling_spend() | |
479 | { | |
480 | auto sk = libzcash::SaplingSpendingKey::random(); | |
481 | auto expsk = sk.expanded_spending_key(); | |
482 | auto address = sk.default_address(); | |
483 | SaplingNote note(address, GetRand(MAX_MONEY)); | |
484 | SaplingMerkleTree tree; | |
485 | auto maybe_cm = note.cm(); | |
486 | tree.append(maybe_cm.get()); | |
487 | auto anchor = tree.root(); | |
488 | auto witness = tree.witness(); | |
489 | auto maybe_nf = note.nullifier(expsk.full_viewing_key(), witness.position()); | |
490 | if (!(maybe_cm && maybe_nf)) { | |
491 | throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not create note commitment and nullifier"); | |
492 | } | |
493 | ||
494 | CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | |
495 | ss << witness.path(); | |
496 | std::vector<unsigned char> witnessChars(ss.begin(), ss.end()); | |
497 | ||
498 | uint256 alpha; | |
499 | librustzcash_sapling_generate_r(alpha.begin()); | |
500 | ||
501 | auto ctx = librustzcash_sapling_proving_ctx_init(); | |
502 | ||
503 | struct timeval tv_start; | |
504 | timer_start(tv_start); | |
505 | ||
506 | SpendDescription sdesc; | |
507 | bool result = librustzcash_sapling_spend_proof( | |
508 | ctx, | |
509 | expsk.full_viewing_key().ak.begin(), | |
510 | expsk.nsk.begin(), | |
511 | note.d.data(), | |
512 | note.r.begin(), | |
513 | alpha.begin(), | |
514 | note.value(), | |
515 | anchor.begin(), | |
516 | witnessChars.data(), | |
517 | sdesc.cv.begin(), | |
518 | sdesc.rk.begin(), | |
519 | sdesc.zkproof.data()); | |
520 | ||
521 | double t = timer_stop(tv_start); | |
522 | librustzcash_sapling_proving_ctx_free(ctx); | |
523 | if (!result) { | |
524 | throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_spend_proof() should return true"); | |
525 | } | |
526 | return t; | |
527 | } | |
528 | ||
529 | double benchmark_create_sapling_output() | |
530 | { | |
531 | auto sk = libzcash::SaplingSpendingKey::random(); | |
532 | auto address = sk.default_address(); | |
533 | ||
534 | std::array<unsigned char, ZC_MEMO_SIZE> memo; | |
535 | SaplingNote note(address, GetRand(MAX_MONEY)); | |
536 | ||
537 | libzcash::SaplingNotePlaintext notePlaintext(note, memo); | |
538 | auto res = notePlaintext.encrypt(note.pk_d); | |
539 | if (!res) { | |
540 | throw JSONRPCError(RPC_INTERNAL_ERROR, "SaplingNotePlaintext::encrypt() failed"); | |
541 | } | |
542 | ||
543 | auto enc = res.get(); | |
544 | auto encryptor = enc.second; | |
545 | ||
546 | auto ctx = librustzcash_sapling_proving_ctx_init(); | |
547 | ||
548 | struct timeval tv_start; | |
549 | timer_start(tv_start); | |
550 | ||
551 | OutputDescription odesc; | |
552 | bool result = librustzcash_sapling_output_proof( | |
553 | ctx, | |
554 | encryptor.get_esk().begin(), | |
555 | note.d.data(), | |
556 | note.pk_d.begin(), | |
557 | note.r.begin(), | |
558 | note.value(), | |
559 | odesc.cv.begin(), | |
560 | odesc.zkproof.begin()); | |
561 | ||
562 | double t = timer_stop(tv_start); | |
563 | librustzcash_sapling_proving_ctx_free(ctx); | |
564 | if (!result) { | |
565 | throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_output_proof() should return true"); | |
566 | } | |
567 | return t; | |
568 | } | |
569 | ||
570 | // Verify Sapling spend from testnet | |
571 | // txid: abbd823cbd3d4e3b52023599d81a96b74817e95ce5bb58354f979156bd22ecc8 | |
572 | // position: 0 | |
573 | double benchmark_verify_sapling_spend() | |
574 | { | |
575 | SpendDescription spend; | |
576 | CDataStream ss(ParseHex("8c6cf86bbb83bf0d075e5bd9bb4b5cd56141577be69f032880b11e26aa32aa5ef09fd00899e4b469fb11f38e9d09dc0379f0b11c23b5fe541765f76695120a03f0261d32af5d2a2b1e5c9a04200cd87d574dc42349de9790012ce560406a8a876a1e54cfcdc0eb74998abec2a9778330eeb2a0ac0e41d0c9ed5824fbd0dbf7da930ab299966ce333fd7bc1321dada0817aac5444e02c754069e218746bf879d5f2a20a8b028324fb2c73171e63336686aa5ec2e6e9a08eb18b87c14758c572f4531ccf6b55d09f44beb8b47563be4eff7a52598d80959dd9c9fee5ac4783d8370cb7d55d460053d3e067b5f9fe75ff2722623fb1825fcba5e9593d4205b38d1f502ff03035463043bd393a5ee039ce75a5d54f21b395255df6627ef96751566326f7d4a77d828aa21b1827282829fcbc42aad59cdb521e1a3aaa08b99ea8fe7fff0a04da31a52260fc6daeccd79bb877bdd8506614282258e15b3fe74bf71a93f4be3b770119edf99a317b205eea7d5ab800362b97384273888106c77d633600"), SER_NETWORK, PROTOCOL_VERSION); | |
577 | ss >> spend; | |
578 | uint256 dataToBeSigned = uint256S("0x2dbf83fe7b88a7cbd80fac0c719483906bb9a0c4fc69071e4780d5f2c76e592c"); | |
579 | ||
580 | auto ctx = librustzcash_sapling_verification_ctx_init(); | |
581 | ||
582 | struct timeval tv_start; | |
583 | timer_start(tv_start); | |
584 | ||
585 | bool result = librustzcash_sapling_check_spend( | |
586 | ctx, | |
587 | spend.cv.begin(), | |
588 | spend.anchor.begin(), | |
589 | spend.nullifier.begin(), | |
590 | spend.rk.begin(), | |
591 | spend.zkproof.begin(), | |
592 | spend.spendAuthSig.begin(), | |
593 | dataToBeSigned.begin() | |
594 | ); | |
595 | ||
596 | double t = timer_stop(tv_start); | |
597 | librustzcash_sapling_verification_ctx_free(ctx); | |
598 | if (!result) { | |
599 | throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_check_spend() should return true"); | |
600 | } | |
601 | return t; | |
602 | } | |
603 | ||
604 | // Verify Sapling output from testnet | |
605 | // txid: abbd823cbd3d4e3b52023599d81a96b74817e95ce5bb58354f979156bd22ecc8 | |
606 | // position: 0 | |
607 | double benchmark_verify_sapling_output() | |
608 | { | |
609 | OutputDescription output; | |
610 | CDataStream ss(ParseHex("edd742af18857e5ec2d71d346a7fe2ac97c137339bd5268eea86d32e0ff4f38f76213fa8cfed3347ac4e8572dd88aff395c0c10a59f8b3f49d2bc539ed6c726667e29d4763f914ddd0abf1cdfa84e44de87c233434c7e69b8b5b8f4623c8aa444163425bae5cef842972fed66046c1c6ce65c866ad894d02e6e6dcaae7a962d9f2ef95757a09c486928e61f0f7aed90ad0a542b0d3dc5fe140dfa7626b9315c77e03b055f19cbacd21a866e46f06c00e0c7792b2a590a611439b510a9aaffcf1073bad23e712a9268b36888e3727033eee2ab4d869f54a843f93b36ef489fb177bf74b41a9644e5d2a0a417c6ac1c8869bc9b83273d453f878ed6fd96b82a5939903f7b64ecaf68ea16e255a7fb7cc0b6d8b5608a1c6b0ed3024cc62c2f0f9c5cfc7b431ae6e9d40815557aa1d010523f9e1960de77b2274cb6710d229d475c87ae900183206ba90cb5bbc8ec0df98341b82726c705e0308ca5dc08db4db609993a1046dfb43dfd8c760be506c0bed799bb2205fc29dc2e654dce731034a23b0aaf6da0199248702ee0523c159f41f4cbfff6c35ace4dd9ae834e44e09c76a0cbdda1d3f6a2c75ad71212daf9575ab5f09ca148718e667f29ddf18c8a330a86ace18a86e89454653902aa393c84c6b694f27d0d42e24e7ac9fe34733de5ec15f5066081ce912c62c1a804a2bb4dedcef7cc80274f6bb9e89e2fce91dc50d6a73c8aefb9872f1cf3524a92626a0b8f39bbf7bf7d96ca2f770fc04d7f457021c536a506a187a93b2245471ddbfb254a71bc4a0d72c8d639a31c7b1920087ffca05c24214157e2e7b28184e91989ef0b14f9b34c3dc3cc0ac64226b9e337095870cb0885737992e120346e630a416a9b217679ce5a778fb15779c136bcecca5efe79012013d77d90b4e99dd22c8f35bc77121716e160d05bd30d288ee8886390ee436f85bdc9029df888a3a3326d9d4ddba5cb5318b3274928829d662e96fea1d601f7a306251ed8c6cc4e5a3a7a98c35a3650482a0eee08f3b4c2da9b22947c96138f1505c2f081f8972d429f3871f32bef4aaa51aa6945df8e9c9760531ac6f627d17c1518202818a91ca304fb4037875c666060597976144fcbbc48a776a2c61beb9515fa8f3ae6d3a041d320a38a8ac75cb47bb9c866ee497fc3cd13299970c4b369c1c2ceb4220af082fbecdd8114492a8e4d713b5a73396fd224b36c1185bd5e20d683e6c8db35346c47ae7401988255da7cfffdced5801067d4d296688ee8fe424b4a8a69309ce257eefb9345ebfda3f6de46bb11ec94133e1f72cd7ac54934d6cf17b3440800e70b80ebc7c7bfc6fb0fc2c"), SER_NETWORK, PROTOCOL_VERSION); | |
611 | ss >> output; | |
612 | ||
613 | auto ctx = librustzcash_sapling_verification_ctx_init(); | |
614 | ||
615 | struct timeval tv_start; | |
616 | timer_start(tv_start); | |
617 | ||
618 | bool result = librustzcash_sapling_check_output( | |
619 | ctx, | |
620 | output.cv.begin(), | |
621 | output.cm.begin(), | |
622 | output.ephemeralKey.begin(), | |
623 | output.zkproof.begin() | |
624 | ); | |
625 | ||
626 | double t = timer_stop(tv_start); | |
627 | librustzcash_sapling_verification_ctx_free(ctx); | |
628 | if (!result) { | |
629 | throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_check_output() should return true"); | |
630 | } | |
631 | return timer_stop(tv_start); | |
632 | } |