12 #include "validation.h"
23 #include <boost/filesystem.hpp>
25 #include <boost/test/unit_test.hpp>
39 saplingNoteData[saplingOutPoint] = saplingNd;
41 std::vector<SaplingOutPoint> saplingNotes {saplingOutPoint};
56 block.
vtx.emplace_back(wtx.
tx);
59 return saplingNotes[0];
63 const std::vector<SaplingOutPoint>& saplingNotes,
66 saplingWitnesses.clear();
82 auto expsk = sk.expsk;
83 auto fvk = expsk.full_viewing_key();
84 auto ivk = fvk.in_viewing_key();
85 auto pk = sk.DefaultAddress();
88 auto cm = note.
cmu().get();
91 auto anchor = tree.
root();
99 builder.AddSaplingSpend(expsk, note, anchor, witness);
100 builder.AddSaplingOutput(fvk.ovk, pk, 40000000, {});
101 builder.SetFee(10000000);
102 auto tx = builder.Build().GetTxOrThrow();
104 CWalletTx wtx {&wallet, MakeTransactionRef(tx)};
115 noteData.insert(std::make_pair(op, nd));
117 wtx.SetSaplingNoteData(noteData);
121 BOOST_CHECK(wtx.mapSaplingNoteData[op].IsMyNote());
122 BOOST_CHECK(ivk == *(wtx.mapSaplingNoteData[op].ivk));
123 BOOST_CHECK(nullifier == wtx.mapSaplingNoteData[op].nullifier);
125 BOOST_CHECK(witness == wtx.mapSaplingNoteData[op].witnesses.front());
130 CWalletTx wtx(
nullptr , MakeTransactionRef());
136 noteData.insert(std::make_pair(op, nd));
151 auto expsk = sk.expsk;
152 auto extfvk = sk.ToXFVK();
153 auto pa = sk.DefaultAddress();
159 builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness());
160 builder.AddSaplingOutput(extfvk.fvk.ovk, pa, 25000000, {});
161 builder.SetFee(10000000);
162 auto tx = builder.Build().GetTxOrThrow();
165 CWalletTx wtx {&wallet, MakeTransactionRef(tx)};
188 auto expsk = sk.expsk;
189 auto extfvk = sk.ToXFVK();
190 auto ivk = extfvk.fvk.in_viewing_key();
191 auto pk = sk.DefaultAddress();
198 auto cm = note.
cmu().get();
201 auto anchor = saplingTree.
root();
202 auto witness = saplingTree.
witness();
206 builder.AddSaplingSpend(expsk, note, anchor, witness);
207 builder.AddSaplingOutput(extfvk.fvk.ovk, pk, 35000000, {});
208 builder.SetFee(10000000);
209 auto tx = builder.Build().GetTxOrThrow();
210 CWalletTx wtx {&wallet, MakeTransactionRef(tx)};
216 block.
vtx.emplace_back(wtx.tx);
218 const auto& blockHash = block.
GetHash();
220 BlockMap::iterator mi =
mapBlockIndex.emplace(blockHash, &fakeIndex).first;
221 fakeIndex.phashBlock = &((*mi).first);
229 wtx.SetSaplingNoteData(saplingNoteData);
238 const uint256& hash = wtx.GetHash();
243 wtx.tx->sapData->vShieldedOutput[0].encCiphertext,
245 wtx.tx->sapData->vShieldedOutput[0].ephemeralKey,
246 wtx.tx->sapData->vShieldedOutput[0].cmu);
248 auto maybe_note = maybe_pt.get().note(ivk);
249 BOOST_CHECK(
static_cast<bool>(maybe_note) ==
true);
250 auto note2 = maybe_note.get();
253 auto spend_note_witness = wtx.mapSaplingNoteData[sop0].witnesses.front();
254 auto maybe_nf = note2.nullifier(extfvk.fvk, spend_note_witness.position());
257 anchor = saplingTree.
root();
261 builder2.SetFee(10000000);
262 builder2.AddSaplingSpend(expsk, note2, anchor, spend_note_witness);
263 builder2.AddSaplingOutput(extfvk.fvk.ovk, pk, 20000000, {});
264 auto tx2 = builder2.Build().GetTxOrThrow();
268 builder3.SetFee(10000000);
269 builder3.AddSaplingSpend(expsk, note2, anchor, spend_note_witness);
270 builder3.AddSaplingOutput(extfvk.fvk.ovk, pk, 19999000, {});
271 auto tx3 = builder3.Build().GetTxOrThrow();
273 CWalletTx wtx2 {&wallet, MakeTransactionRef(tx2)};
274 CWalletTx wtx3 {&wallet, MakeTransactionRef(tx3)};
276 const auto& hash2 = wtx2.GetHash();
277 const auto& hash3 = wtx3.GetHash();
291 BOOST_CHECK(std::set<uint256>({hash2, hash3}) == c3);
308 auto expsk = sk.expsk;
309 auto extfvk = sk.ToXFVK();
310 auto pa = sk.DefaultAddress();
316 builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness());
317 builder.AddSaplingOutput(extfvk.fvk.ovk, pa, 2500000, {});
318 builder.SetFee(10000000);
319 auto tx = builder.Build().GetTxOrThrow();
321 CWalletTx wtx {&wallet, MakeTransactionRef(tx)};
326 auto nf = testNote.note.nullifier(extfvk.fvk, testNote.tree.witness().position());
337 block.
vtx.emplace_back(wtx.tx);
339 const auto& blockHash = block.
GetHash();
341 BlockMap::iterator mi =
mapBlockIndex.emplace(blockHash, &fakeIndex).first;
342 fakeIndex.phashBlock = &((*mi).first);
347 wallet.
BlockConnected(std::make_shared<CBlock>(block), mi->second);
367 auto expsk = sk.expsk;
368 auto extfvk = sk.ToXFVK();
369 auto pa = sk.DefaultAddress();
375 builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness());
376 builder.AddSaplingOutput(extfvk.fvk.ovk, pa, 25000000, {});
377 builder.SetFee(10000000);
378 auto tx = builder.Build().GetTxOrThrow();
380 CWalletTx wtx {&wallet, MakeTransactionRef(tx)};
385 auto nf = testNote.note.nullifier(extfvk.fvk, testNote.tree.witness().position());
396 block.
vtx.emplace_back(wtx.tx);
398 const auto& blockHash = block.
GetHash();
400 BlockMap::iterator mi =
mapBlockIndex.emplace(blockHash, &fakeIndex).first;
401 fakeIndex.phashBlock = &((*mi).first);
410 wtx.SetSaplingNoteData(saplingNoteData);
419 for (mapSaplingNoteData_t::value_type &item : wtx.mapSaplingNoteData) {
430 const uint256& hash = wtx.GetHash();
435 for (mapSaplingNoteData_t::value_type &item : wtx.mapSaplingNoteData) {
463 auto expsk = sk.expsk;
464 auto extfvk = sk.ToXFVK();
465 auto ivk = extfvk.fvk.in_viewing_key();
466 auto pk = sk.DefaultAddress();
470 auto cm = note.
cmu().get();
473 auto anchor = saplingTree.
root();
474 auto witness = saplingTree.
witness();
478 builder.AddSaplingSpend(expsk, note, anchor, witness);
479 builder.AddSaplingOutput(extfvk.fvk.ovk, pk, 25000000, {});
480 builder.SetFee(10000000);
481 auto tx = builder.Build().GetTxOrThrow();
483 CWalletTx wtx {&wallet, MakeTransactionRef(tx)};
491 block.
vtx.emplace_back(wtx.tx);
493 const auto& blockHash = block.
GetHash();
495 BlockMap::iterator mi =
mapBlockIndex.emplace(blockHash, &fakeIndex).first;
496 fakeIndex.phashBlock = &((*mi).first);
503 wtx.SetSaplingNoteData(saplingNoteData);
515 wtx = wallet.
mapWallet.at(wtx.GetHash());
523 auto nf = note.
nullifier(extfvk.fvk, witness.position());
529 wtx.tx->sapData->vShieldedOutput[0].encCiphertext,
531 wtx.tx->sapData->vShieldedOutput[0].ephemeralKey,
532 wtx.tx->sapData->vShieldedOutput[0].cmu);
534 auto maybe_note = maybe_pt.get().note(ivk);
536 auto note2 = maybe_note.get();
540 auto spend_note_witness = wtx.mapSaplingNoteData[sop0].witnesses.front();
541 auto maybe_nf = note2.nullifier(extfvk.fvk, spend_note_witness.position());
543 auto nullifier2 = maybe_nf.get();
547 anchor = saplingTree.
root();
551 builder2.AddSaplingSpend(expsk, note2, anchor, spend_note_witness);
552 builder2.AddSaplingOutput(extfvk.fvk.ovk, pk, 12500000, {});
553 builder2.SetFee(10000000);
554 auto tx2 = builder2.Build().GetTxOrThrow();
561 CWalletTx wtx2 {&wallet, MakeTransactionRef(tx2)};
566 block2.
vtx.emplace_back(wtx2.tx);
569 auto blockHash2 = block2.
GetHash();
571 BlockMap::iterator mi2 =
mapBlockIndex.emplace(blockHash2, &fakeIndex2).first;
572 fakeIndex2.phashBlock = &((*mi2).first);
573 fakeIndex2.nHeight = 1;
580 wtx2.SetSaplingNoteData(saplingNoteData2);
612 std::vector<Optional<SaplingWitness>> saplingWitnesses;
625 block.
vtx.emplace_back(wtx.
tx);
662 std::vector<SaplingOutPoint> saplingNotes {output};
663 std::vector<Optional<SaplingWitness>> saplingWitnesses;
671 wallet, sk, 50,
true);
676 std::vector<Optional<SaplingWitness>> saplingWitnesses;
684 block2.
vtx.emplace_back(wtx.
tx);
710 std::vector<Optional<SaplingWitness>> saplingWitnesses5;
713 BOOST_CHECK(saplingWitnesses == saplingWitnesses5);
748 std::vector<SaplingOutPoint> saplingNotes {output};
749 std::vector<Optional<SaplingWitness>> saplingWitnesses;
756 wallet, sk, 20,
true);
760 std::vector<Optional<SaplingWitness>> saplingWitnesses;
798 std::vector<CBlock> blocks;
799 std::vector<CBlockIndex> indices;
800 std::vector<SaplingOutPoint> saplingNotes;
801 std::vector<uint256> saplingAnchors;
804 std::vector<Optional<SaplingWitness>> saplingWitnesses;
807 size_t numBlocks = WITNESS_CACHE_SIZE + 10;
808 blocks.resize(numBlocks);
809 indices.resize(numBlocks);
810 for (
size_t i = 0; i < numBlocks; i++) {
811 indices[i].nHeight = i;
812 auto oldSaplingRoot = saplingTree.
root();
813 auto outpts =
CreateValidBlock(wallet, sk, indices[i], blocks[i], saplingTree);
815 saplingNotes.push_back(outpts);
818 for (
size_t j = 0; j <= i; j++) {
821 saplingAnchors.push_back(anchor);
826 for (
size_t i = 0; i < numBlocks; i++) {
831 for (
size_t j = 0; j < numBlocks; j++) {
837 if ((i == 5) || (i == 50)) {
843 for (
size_t j = 0; j < numBlocks; j++) {
853 for (
size_t j = 0; j < numBlocks; j++) {
876 wallet, sk, 10,
true);
891 saplingNotes.emplace_back(wtx.
GetHash(), 1);
894 std::vector<Optional<SaplingWitness>> saplingWitnesses;
924 auto sk = m.Derive(0);
925 auto expsk = sk.expsk;
926 auto extfvk = sk.ToXFVK();
927 auto pa = sk.DefaultAddress();
930 auto sk2 = m.Derive(1);
931 auto extfvk2 = sk2.ToXFVK();
932 auto pa2 = sk2.DefaultAddress();
938 builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness());
939 builder.AddSaplingOutput(extfvk.fvk.ovk, pa2, 25000000, {});
940 builder.SetFee(10000000);
941 auto tx = builder.Build().GetTxOrThrow();
944 CWalletTx wtx {&wallet, MakeTransactionRef(tx)};
952 block.
vtx.emplace_back(wtx.tx);
954 const auto& blockHash = block.
GetHash();
956 BlockMap::iterator mi =
mapBlockIndex.emplace(blockHash, &fakeIndex).first;
957 fakeIndex.phashBlock = &((*mi).first);
965 wtx.SetSaplingNoteData(saplingNoteData);
974 const uint256& hash = wtx.GetHash();
1016 BOOST_CHECK(wtx.mapSaplingNoteData[sop1].witnesses.front() == testNote.tree.witness());
1033 auto expsk = sk.expsk;
1034 auto extfvk = sk.ToXFVK();
1035 auto ivk = extfvk.fvk.in_viewing_key();
1036 auto pk = sk.DefaultAddress();
1049 builder.AddTransparentInput(
COutPoint(), scriptPubKey, 50000000);
1050 builder.AddSaplingOutput(extfvk.fvk.ovk, pk, 40000000, {});
1051 builder.SetFee(10000000);
1052 auto tx1 = builder.Build().GetTxOrThrow();
1060 CWalletTx wtx {&wallet, MakeTransactionRef(tx1)};
1066 block.
vtx.emplace_back(wtx.tx);
1068 const auto& blockHash = block.
GetHash();
1070 BlockMap::iterator mi =
mapBlockIndex.emplace(blockHash, &fakeIndex).first;
1071 fakeIndex.phashBlock = &((*mi).first);
1079 wtx.SetSaplingNoteData(saplingNoteData);
1088 const uint256& hash = wtx.GetHash();
1093 tx1.sapData->vShieldedOutput[0].encCiphertext, ivk, tx1.sapData->vShieldedOutput[0].ephemeralKey, tx1.sapData->vShieldedOutput[0].cmu);
1095 auto maybe_note = maybe_pt.get().note(ivk);
1097 auto note = maybe_note.get();
1098 auto anchor = saplingTree.
root();
1099 auto witness = saplingTree.
witness();
1104 builder2.AddSaplingSpend(expsk, note, anchor, witness);
1105 builder2.AddSaplingOutput(extfvk.fvk.ovk, pk, 25000000, {});
1106 builder2.SetFee(10000000);
1107 auto tx2 = builder2.Build().GetTxOrThrow();
1115 CWalletTx wtx2 {&wallet, MakeTransactionRef(tx2)};
1140 std::vector<SaplingOutPoint> saplingOutpoints;
1147 auto extfvk = sk.ToXFVK();
1148 pk = sk.DefaultAddress();
1160 builder.AddTransparentInput(
COutPoint(), scriptPubKey, 510000000);
1161 for (
int i=0; i<5; i++) builder.AddSaplingOutput(extfvk.fvk.ovk, pk, 100000000, {});
1162 builder.SetFee(10000000);
1163 auto tx1 = builder.Build().GetTxOrThrow();
1165 CWalletTx wtx {&wallet, MakeTransactionRef(tx1)};
1171 block.
vtx.emplace_back(wtx.tx);
1175 BlockMap::iterator mi =
mapBlockIndex.emplace(blockHash, &fakeIndex).first;
1176 fakeIndex.phashBlock = &((*mi).first);
1184 wtx.SetSaplingNoteData(saplingNoteData);
1193 const uint256& txid = wtx.GetHash();
1194 for (
int i=0; i<5; i++) saplingOutpoints.emplace_back(txid, i);
1198 std::vector<SaplingNoteEntry> entries;
1201 for (
int i=0; i<5; i++) {
1202 BOOST_CHECK(entries[i].op == saplingOutpoints[i]);
1208 std::vector<SaplingNoteEntry> entries2;
1210 for (
int i=0; i<5; i++) {
1212 BOOST_CHECK(entries2[i].address == entries[i].address);
1213 BOOST_CHECK(entries2[i].note.d == entries[i].note.d);
const CChainParams & Params()
Return the currently selected parameters.
Basic key store, that keeps keys in an address->secret map.
std::vector< CTransactionRef > vtx
The block chain is a tree shaped structure starting with the genesis block at the root,...
int nHeight
height of the entry in the chain. The genesis block has height 0
int Height() const
Return the maximal height in the chain.
void SetTip(CBlockIndex *pindex)
Set/initialize a chain with a given tip.
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
const Consensus::Params & GetConsensus() const
bool HaveSaplingSpendingKey(const libzcash::SaplingExtendedFullViewingKey &extfvk) const override
An encapsulated private key.
CPubKey GetPubKey() const
Compute the public key from a private key.
An outpoint - a combination of a transaction hash and an index n into its vout.
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,...
std::map< uint256, CWalletTx > mapWallet
void IncrementNoteWitnesses(const CBlockIndex *pindex, const CBlock *pblock, SaplingMerkleTree &saplingTree)
pindex is the new tip being connected.
void DecrementNoteWitnesses(const CBlockIndex *pindex)
pindex is the old tip being disconnected.
bool AddSaplingZKey(const libzcash::SaplingExtendedSpendingKey &key)
Adds Sapling spending key to the store, and saves it to disk.
void SetLastBlockProcessed(const CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Set last block processed height, currently only use in unit test.
bool IsFromMe(const CTransactionRef &tx) const
should probably be renamed to IsRelevantToMe
SaplingScriptPubKeyMan * GetSaplingScriptPubKeyMan() const
A transaction with a bunch of additional info that only the owner cares about.
void SetSaplingNoteData(mapSaplingNoteData_t ¬eData)
mapSaplingNoteData_t mapSaplingNoteData
const uint256 & GetHash() const
Optional< uint256 > nullifier
Cached note nullifier.
std::list< SaplingWitness > witnesses
Optional< libzcash::SaplingIncomingViewingKey > ivk
int witnessHeight
Block height corresponding to the most current witness.
An outpoint - a combination of a transaction hash and an index n into its sapling output description ...
bool UpdatedNoteData(const CWalletTx &wtxIn, CWalletTx &wtx)
Update note data if is needed.
bool IsSaplingSpent(const SaplingOutPoint &op) const
int64_t nWitnessCacheSize
std::map< uint256, SaplingOutPoint > mapSaplingNullifiersToNotes
The reverse mapping of nullifiers to notes.
void GetNotes(const std::vector< SaplingOutPoint > &saplingOutpoints, std::vector< SaplingNoteEntry > &saplingEntriesRet) const
Find notes for the outpoints.
std::pair< mapSaplingNoteData_t, SaplingIncomingViewingKeyMap > FindMySaplingNotes(const CTransaction &tx) const
Finds all output notes in the given tx that have been sent to a SaplingPaymentAddress in this wallet.
void GetSaplingNoteWitnesses(const std::vector< SaplingOutPoint > ¬es, std::vector< Optional< SaplingWitness >> &witnesses, uint256 &final_anchor) const
Return all of the witnesses for the input notes.
void GetFilteredNotes(std::vector< SaplingNoteEntry > &saplingEntries, Optional< libzcash::SaplingPaymentAddress > &address, int minDepth=1, bool ignoreSpent=true, bool requireSpendingKey=true, bool ignoreLocked=true) const
Find notes in the wallet filtered by payment address, min depth and ability to spend and if the notes...
void UpdateSaplingNullifierNoteMapForBlock(const CBlock *pblock)
Iterate over transactions in a block and update the cached Sapling nullifiers for transactions which ...
void ClearNoteWitnessCache()
Clear every notesData from every wallet tx and reset the witness cache size.
IncrementalWitness< Depth, Hash > witness() const
Optional< uint256 > cmu() const
Optional< uint256 > nullifier(const SaplingFullViewingKey &vk, const uint64_t position) const
static Optional< SaplingNotePlaintext > decrypt(const SaplingEncCiphertext &ciphertext, const uint256 &ivk, const uint256 &epk, const uint256 &cmu)
BOOST_AUTO_TEST_SUITE_END()
std::set< uint256 > GetConflicts(const uint256 &txid) const
Get wallet transactions that conflict with given transaction (spend same outputs)
bool SetMinVersion(enum WalletFeature, WalletBatch *batch_in=nullptr, bool fExplicit=false)
signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVe...
bool LoadToWallet(CWalletTx &wtxIn)
bool SetupSPKM(bool newKeypool=true, bool memOnly=false)
Generates hd wallet //.
void BlockConnected(const std::shared_ptr< const CBlock > &pblock, const CBlockIndex *pindex) override
Notifies listeners of a block being connected.
void MarkAffectedTransactionsDirty(const CTransaction &tx)
uint256 BlockMerkleRoot(const CBlock &block, bool *mutated)
RecursiveMutex cs_main
Global state.
#define BOOST_CHECK_THROW(stmt, excMatch)
#define BOOST_FIXTURE_TEST_SUITE(a, b)
#define BOOST_CHECK_EQUAL(v1, v2)
#define BOOST_CHECK(expr)
boost::optional< T > Optional
Substitute for C++17 std::optional.
BOOST_AUTO_TEST_CASE(SetSaplingNoteAddrsInCWalletTx)
void setupWallet(CWallet &wallet)
SaplingOutPoint CreateValidBlock(CWallet &wallet, libzcash::SaplingExtendedSpendingKey &sk, const CBlockIndex &index, CBlock &block, SaplingMerkleTree &saplingTree)
uint256 GetWitnessesAndAnchors(CWallet &wallet, const std::vector< SaplingOutPoint > &saplingNotes, std::vector< Optional< SaplingWitness >> &saplingWitnesses)
std::vector< SaplingOutPoint > SetSaplingNoteData(CWalletTx &wtx)
std::map< SaplingOutPoint, SaplingNoteData > mapSaplingNoteData_t
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a PIVX scriptPubKey for the given CTxDestination.
SaplingExtendedFullViewingKey ToXFVK() const
CKey AddTestCKeyToKeyStore(CBasicKeyStore &keyStore, bool genNewKey)
TestSaplingNote GetTestSaplingNote(const libzcash::SaplingPaymentAddress &pa, CAmount value)
Generate a dummy SaplingNote and a SaplingMerkleTree with that note's commitment.
CWalletTx GetValidSaplingReceive(const Consensus::Params &consensusParams, CBasicKeyStore &keyStoreFrom, std::vector< TransparentInput > vIn, std::vector< ShieldedDestination > vDest, const CWallet *pwalletIn)
One or many inputs from keyStoreFrom, one or many shielded outputs to pwalletIn (if not nullptr).
libzcash::SaplingExtendedSpendingKey GetTestMasterSaplingSpendingKey()
CChain chainActive
The currently-connected chain of blocks (protected by cs_main).