Hush Full Node software. We were censored from Github, this is where all development happens now. https://hush.is
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2163 lines
80 KiB

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <sodium.h>
#include "base58.h"
#include "chainparams.h"
6 years ago
#include "key_io.h"
#include "main.h"
#include "primitives/block.h"
#include "random.h"
6 years ago
#include "transaction_builder.h"
#include "utiltest.h"
#include "wallet/wallet.h"
#include "zcash/JoinSplit.hpp"
#include "zcash/Note.hpp"
#include "zcash/NoteEncryption.hpp"
#include <boost/filesystem.hpp>
using ::testing::Return;
extern ZCJoinSplit* params;
ACTION(ThrowLogicError) {
throw std::logic_error("Boom");
}
6 years ago
static const std::string tSecretRegtest = "cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN";
class MockWalletDB {
public:
MOCK_METHOD0(TxnBegin, bool());
MOCK_METHOD0(TxnCommit, bool());
MOCK_METHOD0(TxnAbort, bool());
MOCK_METHOD2(WriteTx, bool(uint256 hash, const CWalletTx& wtx));
MOCK_METHOD1(WriteWitnessCacheSize, bool(int64_t nWitnessCacheSize));
MOCK_METHOD1(WriteBestBlock, bool(const CBlockLocator& loc));
};
template void CWallet::SetBestChainINTERNAL<MockWalletDB>(
MockWalletDB& walletdb, const CBlockLocator& loc);
class TestWallet : public CWallet {
public:
TestWallet() : CWallet() { }
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn) {
return CCryptoKeyStore::EncryptKeys(vMasterKeyIn);
}
bool Unlock(const CKeyingMaterial& vMasterKeyIn) {
return CCryptoKeyStore::Unlock(vMasterKeyIn);
}
void IncrementNoteWitnesses(const CBlockIndex* pindex,
const CBlock* pblock,
6 years ago
SproutMerkleTree& sproutTree,
SaplingMerkleTree& saplingTree) {
CWallet::IncrementNoteWitnesses(pindex, pblock, sproutTree, saplingTree);
}
void DecrementNoteWitnesses(const CBlockIndex* pindex) {
CWallet::DecrementNoteWitnesses(pindex);
}
void SetBestChain(MockWalletDB& walletdb, const CBlockLocator& loc) {
CWallet::SetBestChainINTERNAL(walletdb, loc);
}
bool UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx) {
return CWallet::UpdatedNoteData(wtxIn, wtx);
}
void MarkAffectedTransactionsDirty(const CTransaction& tx) {
CWallet::MarkAffectedTransactionsDirty(tx);
}
};
6 years ago
CWalletTx GetValidReceive(const libzcash::SproutSpendingKey& sk, CAmount value, bool randomInputs, int32_t version = 2) {
return GetValidReceive(*params, sk, value, randomInputs, version);
}
6 years ago
libzcash::SproutNote GetNote(const libzcash::SproutSpendingKey& sk,
const CTransaction& tx, size_t js, size_t n) {
return GetNote(*params, sk, tx, js, n);
}
6 years ago
CWalletTx GetValidSpend(const libzcash::SproutSpendingKey& sk,
const libzcash::SproutNote& note, CAmount value) {
return GetValidSpend(*params, sk, note, value);
}
6 years ago
std::vector<SaplingOutPoint> SetSaplingNoteData(CWalletTx& wtx) {
mapSaplingNoteData_t saplingNoteData;
SaplingOutPoint saplingOutPoint = {wtx.GetHash(), 0};
SaplingNoteData saplingNd;
saplingNoteData[saplingOutPoint] = saplingNd;
wtx.SetSaplingNoteData(saplingNoteData);
std::vector<SaplingOutPoint> saplingNotes {saplingOutPoint};
return saplingNotes;
}
std::pair<JSOutPoint, SaplingOutPoint> CreateValidBlock(TestWallet& wallet,
const libzcash::SproutSpendingKey& sk,
const CBlockIndex& index,
CBlock& block,
6 years ago
SproutMerkleTree& sproutTree,
SaplingMerkleTree& saplingTree) {
auto wtx = GetValidReceive(sk, 50, true, 4);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
6 years ago
mapSproutNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
6 years ago
wtx.SetSproutNoteData(noteData);
auto saplingNotes = SetSaplingNoteData(wtx);
wallet.AddToWallet(wtx, true, NULL);
block.vtx.push_back(wtx);
6 years ago
wallet.IncrementNoteWitnesses(&index, &block, sproutTree, saplingTree);
return std::make_pair(jsoutpt, saplingNotes[0]);
}
6 years ago
std::pair<uint256, uint256> GetWitnessesAndAnchors(TestWallet& wallet,
std::vector<JSOutPoint>& sproutNotes,
std::vector<SaplingOutPoint>& saplingNotes,
std::vector<boost::optional<SproutWitness>>& sproutWitnesses,
std::vector<boost::optional<SaplingWitness>>& saplingWitnesses) {
sproutWitnesses.clear();
saplingWitnesses.clear();
uint256 sproutAnchor;
uint256 saplingAnchor;
wallet.GetSproutNoteWitnesses(sproutNotes, sproutWitnesses, sproutAnchor);
wallet.GetSaplingNoteWitnesses(saplingNotes, saplingWitnesses, saplingAnchor);
return std::make_pair(sproutAnchor, saplingAnchor);
}
6 years ago
TEST(WalletTests, SetupDatadirLocationRunAsFirstTest) {
// Get temporary and unique path for file.
boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
boost::filesystem::create_directories(pathTemp);
mapArgs["-datadir"] = pathTemp.string();
}
6 years ago
TEST(WalletTests, SproutNoteDataSerialisation) {
auto sk = libzcash::SproutSpendingKey::random();
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
6 years ago
mapSproutNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
SproutMerkleTree tree;
nd.witnesses.push_front(tree.witness());
noteData[jsoutpt] = nd;
CDataStream ss(SER_DISK, CLIENT_VERSION);
ss << noteData;
6 years ago
mapSproutNoteData_t noteData2;
ss >> noteData2;
EXPECT_EQ(noteData, noteData2);
EXPECT_EQ(noteData[jsoutpt].witnesses, noteData2[jsoutpt].witnesses);
}
6 years ago
TEST(WalletTests, FindUnspentSproutNotes) {
SelectParams(CBaseChainParams::TESTNET);
CWallet wallet;
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
6 years ago
mapSproutNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
6 years ago
wtx.SetSproutNoteData(noteData);
wallet.AddToWallet(wtx, true, NULL);
6 years ago
EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
// We currently have an unspent and unconfirmed note in the wallet (depth of -1)
6 years ago
std::vector<CSproutNotePlaintextEntry> sproutEntries;
std::vector<SaplingNoteEntry> saplingEntries;
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0);
EXPECT_EQ(0, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", -1);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Fake-mine the transaction
EXPECT_EQ(-1, chainActive.Height());
CBlock block;
block.vtx.push_back(wtx);
block.hashMerkleRoot = block.BuildMerkleTree();
auto blockHash = block.GetHash();
CBlockIndex fakeIndex {block};
mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
chainActive.SetTip(&fakeIndex);
EXPECT_TRUE(chainActive.Contains(&fakeIndex));
EXPECT_EQ(0, chainActive.Height());
wtx.SetMerkleBranch(block);
wallet.AddToWallet(wtx, true, NULL);
6 years ago
EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
// We now have an unspent and confirmed note in the wallet (depth of 1)
6 years ago
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 1);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2);
EXPECT_EQ(0, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Let's spend the note.
auto wtx2 = GetValidSpend(sk, note, 5);
wallet.AddToWallet(wtx2, true, NULL);
6 years ago
EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
// Fake-mine a spend transaction
EXPECT_EQ(0, chainActive.Height());
CBlock block2;
block2.vtx.push_back(wtx2);
block2.hashMerkleRoot = block2.BuildMerkleTree();
block2.hashPrevBlock = blockHash;
auto blockHash2 = block2.GetHash();
CBlockIndex fakeIndex2 {block2};
mapBlockIndex.insert(std::make_pair(blockHash2, &fakeIndex2));
6 years ago
fakeIndex2.SetHeight(1);
chainActive.SetTip(&fakeIndex2);
EXPECT_TRUE(chainActive.Contains(&fakeIndex2));
EXPECT_EQ(1, chainActive.Height());
wtx2.SetMerkleBranch(block2);
wallet.AddToWallet(wtx2, true, NULL);
6 years ago
EXPECT_TRUE(wallet.IsSproutSpent(nullifier));
// The note has been spent. By default, GetFilteredNotes() ignores spent notes.
6 years ago
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0);
EXPECT_EQ(0, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Let's include spent notes to retrieve it.
6 years ago
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0, false);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// The spent note has two confirmations.
6 years ago
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2, false);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// It does not have 3 confirmations.
6 years ago
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 3, false);
EXPECT_EQ(0, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Let's receive a new note
CWalletTx wtx3;
{
auto wtx = GetValidReceive(sk, 20, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
6 years ago
mapSproutNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
6 years ago
wtx.SetSproutNoteData(noteData);
wallet.AddToWallet(wtx, true, NULL);
6 years ago
EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
wtx3 = wtx;
}
// Fake-mine the new transaction
EXPECT_EQ(1, chainActive.Height());
CBlock block3;
block3.vtx.push_back(wtx3);
block3.hashMerkleRoot = block3.BuildMerkleTree();
block3.hashPrevBlock = blockHash2;
auto blockHash3 = block3.GetHash();
CBlockIndex fakeIndex3 {block3};
mapBlockIndex.insert(std::make_pair(blockHash3, &fakeIndex3));
6 years ago
fakeIndex3.SetHeight(2);
chainActive.SetTip(&fakeIndex3);
EXPECT_TRUE(chainActive.Contains(&fakeIndex3));
EXPECT_EQ(2, chainActive.Height());
wtx3.SetMerkleBranch(block3);
wallet.AddToWallet(wtx3, true, NULL);
// We now have an unspent note which has one confirmation, in addition to our spent note.
6 years ago
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 1);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Let's return the spent note too.
6 years ago
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 1, false);
EXPECT_EQ(2, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Increasing number of confirmations will exclude our new unspent note.
6 years ago
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2, false);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
Squashed commit of the following: commit 5e7222e4bc0401ef8c6d8049b12a62d4854ac85c Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Thu Mar 1 21:20:51 2018 +0200 Cleanup commit 2e1bc7a7cd6c72e7c3d2ff74cb30f7a56515006c Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Thu Mar 1 21:19:53 2018 +0200 Cleanup commit edd7fa87fb2c839c17457ff004d258a049df832f Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Thu Mar 1 21:18:57 2018 +0200 Cleanup commit ee34e1433806655a7123f0617802aa4771507dff Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Thu Mar 1 21:18:10 2018 +0200 Cleanup commit 20779e4021b8ab95a87289d2741ad2f0fbc7fb39 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Thu Mar 1 21:16:52 2018 +0200 Cleanup commit 084e1aa563807f5625ad3aaff376b598e139f2a7 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 18:42:49 2018 +0200 Fix typo commit c61a7c2319d3b9b96d1b5ad52ecf9d4f2fd92658 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 18:37:43 2018 +0200 Cleanup commit e435c0229b0cbe3f4a77f43b01ca87ed0552d405 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 18:17:58 2018 +0200 Fix typos commit e05bff3fea8915e95a473fe3266b2b1f727deca0 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 17:59:32 2018 +0200 Fix typo commit 8c55c7840232cef7fa4389a12f6f220e86f5f581 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 17:46:33 2018 +0200 Fix typos commit a1edfcc5cc29d815ba7e8c4baaf14c23ef93af64 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 17:39:41 2018 +0200 Fix typos commit 2ce2c4d180e936ccc5c10745a6430fda5de38a9b Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 17:14:10 2018 +0200 Fix typo commit 5bdc6cd5bc9cff93aa48fbdeda36d4d9774bfa18 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 17:12:14 2018 +0200 Fix typo commit d08749f549575efc6f44a7f80850bc439c12ad5c Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 16:54:06 2018 +0200 Revert one change commit a734bb1191c692f09f58bcc8e85160ce7c839905 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 16:52:45 2018 +0200 Fix typo commit 95fbc8d94bbefc0db989c83d0f053111bfed45e7 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 16:51:33 2018 +0200 Fix typos commit d17d540a83d035cf9a200f9a8b19f0fab6084728 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 16:49:36 2018 +0200 Fix typo commit c4bf4402210bcb926ccfb3928afeb3a8a7490b42 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 16:48:09 2018 +0200 Fix typo commit 25e7990848a1d723702e2d041c04bc68a6c1275f Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 16:47:01 2018 +0200 Fix typo commit d72ffb5b0253e0d7b992ffe13c40695421378dc3 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 16:45:20 2018 +0200 Fix typo commit 705e6f271192a575cc99d794545b0efe75d964c4 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 16:41:19 2018 +0200 Revert one change commit 4fd26cd29e21c42b027e37da2616761ebc399d16 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 16:39:41 2018 +0200 Revert commit commit 8a5cc627b1048368fe8807973d1f542bab2e045f Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 16:28:56 2018 +0200 Fix typo commit 0a24baa7258c0ae0f244d82af8d0831b148ab012 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 16:15:45 2018 +0200 Fix typo commit 38f93ecd90171fb881243f0de55b3452daccff20 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 15:56:49 2018 +0200 Fix typos commit 15446fd62400c36c2a51f7e6f13725cc8adfd924 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 15:48:00 2018 +0200 Fix typos commit 76533b41986bbc5826070a1e644215a74757c1db Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 15:04:38 2018 +0200 Fix typo commit aea330c2b0bf76975ec69142a732288cc8b192bd Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 14:46:29 2018 +0200 Fix typo commit 8b1b1d0be1dc44f36c22c54d1a3d56d84d456b92 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 14:40:23 2018 +0200 Fix typo commit 46ea76785a26cf20a664ed211c8f3fb9a283e127 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 14:14:17 2018 +0200 Fix typo commit e0d7c5748545dd0975507ad603623072fcc6bdea Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 14:08:24 2018 +0200 Fix typo commit 604d5a244323b17ba596b12d245407e1cf63a375 Merge: 6c081ca 1c65b2b Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 09:03:23 2018 +0200 Merge pull request #36 from rex4539/patch-36 Fix typo commit 6c081caf28b7cef9e62ed523284dff90e4add16d Merge: 899e5d2 88fa2d9 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 09:02:49 2018 +0200 Merge pull request #35 from rex4539/patch-35 Fix typo commit 899e5d2c343ac7ea5069b8548e5df86c8e963e21 Merge: 6380c7f 40e73e2 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 09:02:16 2018 +0200 Merge pull request #34 from rex4539/patch-34 Fix typo commit 6380c7f740246474c69d8145bde61688551efe83 Merge: f592274 4567667 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 09:01:47 2018 +0200 Merge pull request #33 from rex4539/patch-33 Fix typos commit f592274a713162da0083bd6d22fb47cb1afcdba9 Merge: d86ef7e 4aeaa3a Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 09:01:14 2018 +0200 Merge pull request #32 from rex4539/patch-32 Fix typo commit d86ef7e5e4f7e9c2014358ec5b647d1815eb304d Merge: fe0b432 5cdd1b2 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 09:00:41 2018 +0200 Merge pull request #31 from rex4539/patch-31 Fix typo commit fe0b432ee125ae0b876af2c26139dfc979005a3b Merge: 6fd6d0d 70130d0 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 09:00:12 2018 +0200 Merge pull request #30 from rex4539/patch-30 Fix typos commit 6fd6d0dcf3714118a623c0d8d84aabb4578410a8 Merge: 389660f 3377426 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:59:42 2018 +0200 Merge pull request #29 from rex4539/patch-29 Fix typo commit 389660f856cb60ff475a8757aad3873b99213cc0 Merge: a0b85ce 40643eb Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:59:15 2018 +0200 Merge pull request #28 from rex4539/patch-28 Fix typo commit a0b85ce3b4d2e6596da0727e05c1fe15c289b1e7 Merge: 6f9a1c7 23ead80 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:58:42 2018 +0200 Merge pull request #27 from rex4539/patch-27 Fix typo commit 6f9a1c71a680bb3ed1c249dd42bf0a54663d0af3 Merge: b880547 3612eab Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:58:06 2018 +0200 Merge pull request #26 from rex4539/patch-26 Patch 26 commit b880547415afeae36bd19867388e60a3040a15ca Merge: a3b7da2 5c3177f Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:57:24 2018 +0200 Merge pull request #25 from rex4539/patch-25 Fix typo commit a3b7da2c6d6691f38751292e1aea63498a325788 Merge: edd8586 60026ef Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:56:52 2018 +0200 Merge pull request #24 from rex4539/patch-24 Fix typo commit edd8586fdf8c112f4c513804610c237d7e2e80ef Merge: 0c28eb7 f979c00 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:56:12 2018 +0200 Merge pull request #23 from rex4539/patch-23 Fix typo commit 0c28eb7717821b1d68016f40911d07f2a7231b4f Merge: 775beb6 c900722 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:55:42 2018 +0200 Merge pull request #22 from rex4539/patch-22 Fix typo commit 775beb625beb1fc5f72388c076b295de4b8ff039 Merge: a0cf889 1027543 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:55:16 2018 +0200 Merge pull request #21 from rex4539/patch-21 Fix typo commit a0cf88971e756c37c406bab3066c11d6fc7f6d74 Merge: 4504b48 f3fa89b Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:54:44 2018 +0200 Merge pull request #20 from rex4539/patch-20 Fix typo commit 4504b4824b3438e931ca8d24a56b1887657e87cd Merge: dd0bcbf 2699eca Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:54:20 2018 +0200 Merge pull request #19 from rex4539/patch-19 Fix typo commit dd0bcbfc89293e9760156d5534f3a558451e1f29 Merge: abfb65a f02ef2e Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:53:46 2018 +0200 Merge pull request #18 from rex4539/patch-18 Fix typos commit abfb65afaed49c34b9875df79f6fe6eb2b7bf769 Merge: 68b46b7 6485c90 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:53:08 2018 +0200 Merge pull request #17 from rex4539/patch-17 Fix typo commit 68b46b75d2e5b7ae97e83fc5541c46b4907a7899 Merge: a131e84 fcc0828 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:52:39 2018 +0200 Merge pull request #16 from rex4539/patch-16 Fix typo commit a131e844652e58aff78fa8952e7547a9ba82b8a1 Merge: 8487c0e 8a688ff Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:51:54 2018 +0200 Merge pull request #15 from rex4539/patch-15 Fix typo commit 8487c0e39092b74e977c7a60f4a07a27606756a8 Merge: bcc4cb4 bb60b83 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:51:28 2018 +0200 Merge pull request #14 from rex4539/patch-14 Fix typos commit bcc4cb46130e789faa9adae9b159ca818f67ec52 Merge: 23e66e9 53539bb Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:51:00 2018 +0200 Merge pull request #13 from rex4539/patch-13 Fix typos commit 23e66e956bff2d6935c7a4dd570d457294018a77 Merge: 56956cf 0808445 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:50:27 2018 +0200 Merge pull request #12 from rex4539/patch-12 Fix typo commit 56956cf23ba1208aa39cb3ab1ef60375c6630263 Merge: 77007d4 7a4f064 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:49:59 2018 +0200 Merge pull request #11 from rex4539/patch-11 Fix typo commit 77007d49fa1d8cb80aef02bea1dd15e522a47c90 Merge: e78ad0c 48c33fb Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:49:16 2018 +0200 Merge pull request #10 from rex4539/patch-10 Fix typo commit e78ad0cf0d91955a848f5e953a042eabdcdac198 Merge: 38a3e08 809f01c Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:48:33 2018 +0200 Merge pull request #9 from rex4539/patch-9 Fix typo commit 38a3e08699fe4c4ec715b1783dba18bff6b829fb Merge: eee3c28 fec279c Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:48:05 2018 +0200 Merge pull request #8 from rex4539/patch-8 Fix typo commit eee3c286eb84f994310142a9e7fdbd36a671e593 Merge: 702635b cf81b4e Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:47:33 2018 +0200 Merge pull request #7 from rex4539/patch-7 Fix typo commit 702635bb34abb2f83ded27ae95deefd5b6e7df93 Merge: d7497ea 3bbcc3d Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:47:01 2018 +0200 Merge pull request #6 from rex4539/patch-6 Fix typo commit d7497ea070e03380cf1d4f533b7dc4b881f724f8 Merge: bfcc1e8 f639727 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:45:33 2018 +0200 Merge pull request #5 from rex4539/patch-5 Fix typos commit bfcc1e8ae2094ca4e9837f623999705f538aff04 Merge: f4440ec 55262fe Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:45:05 2018 +0200 Merge pull request #4 from rex4539/patch-4 Remove space for word "backup" commit f4440ecd4a7367e6bc4a5f75bea112290017ed2b Merge: f8b487f 61d5279 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:44:31 2018 +0200 Merge pull request #3 from rex4539/patch-3 Fix typos in zmq.md commit f8b487f5699990fabc7fc383d02bc728db3cb9aa Merge: 60104a7 f2ce50f Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:42:51 2018 +0200 Merge pull request #2 from rex4539/patch-2 Fix typo in security-warnings.md commit 60104a7034f55284afb814e81a1430a8b2b0d8d1 Merge: be262f0 af7dfe0 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 08:41:48 2018 +0200 Merge pull request #1 from rex4539/patch-1 Fix typos commit 1c65b2bd0c49f7f392d0e3a2db14ce1366a87171 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 07:35:26 2018 +0200 Fix typo commit 88fa2d966a3b462ed34a9a4659fc390711cc0276 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 07:21:00 2018 +0200 Fix typo commit 40e73e258671f21d2b2205509e9cae1f50294752 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 07:14:21 2018 +0200 Fix typo commit 4567667fcc8b4197dfd51da34fe82b0f2fb78127 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 06:44:40 2018 +0200 Fix typos commit 4aeaa3a3d6335302c53c0f5f4ef81de05e266479 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 05:55:25 2018 +0200 Fix typo commit 5cdd1b29b4c90492aa15fed7940984e1d675052f Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 05:36:46 2018 +0200 Fix typo commit 70130d05f1646c8b9fb1f33c4efbe2a5fcf7138b Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 05:28:21 2018 +0200 Fix typos commit 33774261b1c63e5640aa1dd251edb67892ed7a5b Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 05:00:56 2018 +0200 Fix typo commit 40643ebfcd85ee257a4576e85d2fb6c73dad17b5 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 04:51:57 2018 +0200 Fix typo commit 23ead80e05116ebfeaac0a00d5bd4a158fbeb54e Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 04:29:53 2018 +0200 Fix typo commit 3612eaba2dcf273e94cac9ad889723776ce55108 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 04:19:36 2018 +0200 Fix typos commit 5c3177f5d191d1f4e4d9f78ae4b75381010f7768 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 04:13:03 2018 +0200 Fix typo commit 60026efe27a39300e428879ad8dba94f19934870 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 04:08:09 2018 +0200 Fix typo commit f979c0074efd66804f229c8b3cc6e812d7f26406 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 04:01:44 2018 +0200 Fix typo commit c9007220a8a727c1cfe3b25b453c178eacd431f3 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 03:52:33 2018 +0200 Fix typo commit 1027543bd30701c4b09aa66226281a10563db910 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 03:36:19 2018 +0200 Fix typo commit f3fa89bcd30e0cb45ff4391e78d02452c9227be0 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 03:34:37 2018 +0200 Fix typo commit 2699eca938f1e413a29d4408a271aaafd27969cc Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 03:30:29 2018 +0200 Fix typo commit f02ef2e495fe43142d305f5c4f40dcfa3d2cb423 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 03:22:36 2018 +0200 Fix typos commit 6485c908433bb91fd70d7e18cf3611c9a96115a7 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 03:10:06 2018 +0200 Fix typo commit fcc082850564b14b86b1932dfc5a099816c72ef1 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 03:06:26 2018 +0200 Fix typo commit 8a688ff7405d67bd4c77b0aa0ebdd4b4a8a9a6a7 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 03:02:50 2018 +0200 Fix typo commit bb60b83853ed0a82ca47dd58d55f1849ddcf23ab Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 02:59:25 2018 +0200 Fix typos commit 53539bb720c7676b9d37e25dde3423db3aa7bfa1 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 02:50:55 2018 +0200 Fix typos commit 080844581d6488ab797ac188acae9c4b2e1d0c59 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 01:05:54 2018 +0200 Fix typo commit 7a4f0649ac5e71f39f0bef7f2e1fcb6fafad0291 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 00:16:31 2018 +0200 Fix typo commit 48c33fb3f9ab1ad287987d147ee4bbe186f7ade1 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 00:07:42 2018 +0200 Fix typo commit 809f01ca4f785a7b5bc9cc2c388e0ae814ecaa95 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Tue Feb 27 00:02:34 2018 +0200 Fix typo commit fec279cac89aa917be929447c81177811728361a Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Mon Feb 26 23:55:27 2018 +0200 Fix typo commit cf81b4e12399570545372d4c9daceca8e70142d5 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Mon Feb 26 23:48:43 2018 +0200 Fix typo commit 3bbcc3d9986caf8df99bec5d8a18d0f0c8990e06 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Mon Feb 26 23:28:52 2018 +0200 Fix typo commit f639727525dbd23f5f2d0f89e7be13d868e984c3 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Mon Feb 26 23:13:12 2018 +0200 Fix typos commit 55262fe9c5e1e127c6b817a0c2ab3f9db3ac35b9 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Mon Feb 26 22:46:52 2018 +0200 Remove space for word "backup" commit 61d52797d4d26a90dcc15e2bcd6f19a5f36faac3 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Mon Feb 26 22:23:31 2018 +0200 Fix typos in zmq.md commit f2ce50f10e67b4265e559a432681bc44828ae59b Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Mon Feb 26 22:12:58 2018 +0200 Fix typo in security-warnings.md commit af7dfe046c12109e44ddc18dff07ede8755cf4f9 Author: Dimitris Apostolou <dimitris.apostolou@icloud.com> Date: Mon Feb 26 21:59:24 2018 +0200 Fix typos Signed-off-by: Daira Hopwood <daira@jacaranda.org>
6 years ago
// If we also ignore spent notes at this depth, we won't find any notes.
6 years ago
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2, true);
EXPECT_EQ(0, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Tear down
chainActive.SetTip(NULL);
mapBlockIndex.erase(blockHash);
mapBlockIndex.erase(blockHash2);
mapBlockIndex.erase(blockHash3);
}
6 years ago
TEST(WalletTests, SetSproutNoteAddrsInCWalletTx) {
auto sk = libzcash::SproutSpendingKey::random();
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
6 years ago
EXPECT_EQ(0, wtx.mapSproutNoteData.size());
6 years ago
mapSproutNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
6 years ago
wtx.SetSproutNoteData(noteData);
EXPECT_EQ(noteData, wtx.mapSproutNoteData);
}
TEST(WalletTests, SetSaplingNoteAddrsInCWalletTx) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto consensusParams = Params().GetConsensus();
TestWallet wallet;
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
HDSeed seed(rawSeed);
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
auto expsk = sk.expsk;
auto fvk = expsk.full_viewing_key();
auto ivk = fvk.in_viewing_key();
auto pk = sk.DefaultAddress();
libzcash::SaplingNote note(pk, 50000);
auto cm = note.cm().get();
SaplingMerkleTree tree;
tree.append(cm);
auto anchor = tree.root();
auto witness = tree.witness();
auto nf = note.nullifier(fvk, witness.position());
ASSERT_TRUE(nf);
uint256 nullifier = nf.get();
auto builder = TransactionBuilder(consensusParams, 1);
ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
builder.AddSaplingOutput(fvk.ovk, pk, 50000, {});
builder.SetFee(0);
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx = maybe_tx.get();
CWalletTx wtx {&wallet, tx};
EXPECT_EQ(0, wtx.mapSaplingNoteData.size());
mapSaplingNoteData_t noteData;
SaplingOutPoint op {wtx.GetHash(), 0};
SaplingNoteData nd;
nd.nullifier = nullifier;
nd.ivk = ivk;
nd.witnesses.push_front(witness);
nd.witnessHeight = 123;
noteData.insert(std::make_pair(op, nd));
wtx.SetSaplingNoteData(noteData);
EXPECT_EQ(noteData, wtx.mapSaplingNoteData);
// Test individual fields in case equality operator is defined/changed.
EXPECT_EQ(ivk, wtx.mapSaplingNoteData[op].ivk);
EXPECT_EQ(nullifier, wtx.mapSaplingNoteData[op].nullifier);
EXPECT_EQ(nd.witnessHeight, wtx.mapSaplingNoteData[op].witnessHeight);
EXPECT_TRUE(witness == wtx.mapSaplingNoteData[op].witnesses.front());
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
6 years ago
TEST(WalletTests, SetSproutInvalidNoteAddrsInCWalletTx) {
CWalletTx wtx;
6 years ago
EXPECT_EQ(0, wtx.mapSproutNoteData.size());
6 years ago
mapSproutNoteData_t noteData;
auto sk = libzcash::SproutSpendingKey::random();
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), uint256()};
noteData[jsoutpt] = nd;
6 years ago
EXPECT_THROW(wtx.SetSproutNoteData(noteData), std::logic_error);
}
6 years ago
// The following test is the same as SetInvalidSaplingNoteDataInCWalletTx
// TEST(WalletTests, SetSaplingInvalidNoteAddrsInCWalletTx)
// Cannot add note data for an index which does not exist in tx.vShieldedOutput
TEST(WalletTests, SetInvalidSaplingNoteDataInCWalletTx) {
CWalletTx wtx;
EXPECT_EQ(0, wtx.mapSaplingNoteData.size());
mapSaplingNoteData_t noteData;
SaplingOutPoint op {uint256(), 1};
SaplingNoteData nd;
noteData.insert(std::make_pair(op, nd));
EXPECT_THROW(wtx.SetSaplingNoteData(noteData), std::logic_error);
}
TEST(WalletTests, GetSproutNoteNullifier) {
CWallet wallet;
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
auto address = sk.address();
auto dec = ZCNoteDecryption(sk.receiving_key());
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
auto hSig = wtx.vjoinsplit[0].h_sig(
*params, wtx.joinSplitPubKey);
6 years ago
auto ret = wallet.GetSproutNoteNullifier(
wtx.vjoinsplit[0],
address,
dec,
hSig, 1);
EXPECT_NE(nullifier, ret);
6 years ago
wallet.AddSproutSpendingKey(sk);
6 years ago
ret = wallet.GetSproutNoteNullifier(
wtx.vjoinsplit[0],
address,
dec,
hSig, 1);
EXPECT_EQ(nullifier, ret);
}
6 years ago
TEST(WalletTests, FindMySaplingNotes) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto consensusParams = Params().GetConsensus();
TestWallet wallet;
// Generate dummy Sapling address
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
HDSeed seed(rawSeed);
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
auto expsk = sk.expsk;
auto fvk = expsk.full_viewing_key();
auto pk = sk.DefaultAddress();
// Generate dummy Sapling note
libzcash::SaplingNote note(pk, 50000);
auto cm = note.cm().get();
SaplingMerkleTree tree;
tree.append(cm);
auto anchor = tree.root();
auto witness = tree.witness();
// Generate transaction
auto builder = TransactionBuilder(consensusParams, 1);
ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
builder.AddSaplingOutput(fvk.ovk, pk, 25000, {});
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx = maybe_tx.get();
// No Sapling notes can be found in tx which does not belong to the wallet
CWalletTx wtx {&wallet, tx};
ASSERT_FALSE(wallet.HaveSaplingSpendingKey(fvk));
auto noteMap = wallet.FindMySaplingNotes(wtx).first;
EXPECT_EQ(0, noteMap.size());
// Add spending key to wallet, so Sapling notes can be found
ASSERT_TRUE(wallet.AddSaplingZKey(sk, pk));
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
noteMap = wallet.FindMySaplingNotes(wtx).first;
EXPECT_EQ(2, noteMap.size());
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
TEST(WalletTests, FindMySaplingNotesWithIvkOnly) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto consensusParams = Params().GetConsensus();
TestWallet wallet;
// Generate dummy Sapling address
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
HDSeed seed(rawSeed);
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
auto addr = sk.DefaultAddress();
auto expsk = sk.expsk;
auto fvk = expsk.full_viewing_key();
auto pk = sk.DefaultAddress();
auto ivk = fvk.in_viewing_key();
// Generate dummy Sapling note
libzcash::SaplingNote note(pk, 50000);
auto cm = note.cm().get();
SaplingMerkleTree tree;
tree.append(cm);
auto anchor = tree.root();
auto witness = tree.witness();
// Generate transaction
auto builder = TransactionBuilder(consensusParams, 1);
ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
builder.AddSaplingOutput(fvk.ovk, pk, 25000, {});
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx = maybe_tx.get();
// No Sapling notes can be found in tx which does not belong to the wallet
CWalletTx wtx {&wallet, tx};
ASSERT_FALSE(wallet.HaveSaplingSpendingKey(fvk));
ASSERT_FALSE(wallet.HaveSaplingIncomingViewingKey(addr));
auto noteMap = wallet.FindMySaplingNotes(wtx).first;
EXPECT_EQ(0, noteMap.size());
// Add ivk to wallet, so Sapling notes can be found
ASSERT_TRUE(wallet.AddSaplingIncomingViewingKey(ivk, addr));
ASSERT_FALSE(wallet.HaveSaplingSpendingKey(fvk));
ASSERT_TRUE(wallet.HaveSaplingIncomingViewingKey(addr));
noteMap = wallet.FindMySaplingNotes(wtx).first;
EXPECT_EQ(2, noteMap.size());
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
6 years ago
TEST(WalletTests, FindMySproutNotes) {
CWallet wallet;
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
auto sk2 = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk2);
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
6 years ago
auto noteMap = wallet.FindMySproutNotes(wtx);
EXPECT_EQ(0, noteMap.size());
6 years ago
wallet.AddSproutSpendingKey(sk);
6 years ago
noteMap = wallet.FindMySproutNotes(wtx);
EXPECT_EQ(2, noteMap.size());
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
EXPECT_EQ(1, noteMap.count(jsoutpt));
EXPECT_EQ(nd, noteMap[jsoutpt]);
}
6 years ago
TEST(WalletTests, FindMySproutNotesInEncryptedWallet) {
TestWallet wallet;
uint256 r {GetRandHash()};
CKeyingMaterial vMasterKey (r.begin(), r.end());
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
ASSERT_TRUE(wallet.EncryptKeys(vMasterKey));
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
6 years ago
auto noteMap = wallet.FindMySproutNotes(wtx);
EXPECT_EQ(2, noteMap.size());
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
EXPECT_EQ(1, noteMap.count(jsoutpt));
EXPECT_NE(nd, noteMap[jsoutpt]);
ASSERT_TRUE(wallet.Unlock(vMasterKey));
6 years ago
noteMap = wallet.FindMySproutNotes(wtx);
EXPECT_EQ(2, noteMap.size());
EXPECT_EQ(1, noteMap.count(jsoutpt));
EXPECT_EQ(nd, noteMap[jsoutpt]);
}
6 years ago
TEST(WalletTests, GetConflictedSproutNotes) {
CWallet wallet;
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
auto wtx2 = GetValidSpend(sk, note, 5);
auto wtx3 = GetValidSpend(sk, note, 10);
auto hash2 = wtx2.GetHash();
auto hash3 = wtx3.GetHash();
// No conflicts for no spends
EXPECT_EQ(0, wallet.GetConflicts(hash2).size());
wallet.AddToWallet(wtx, true, NULL);
EXPECT_EQ(0, wallet.GetConflicts(hash2).size());
// No conflicts for one spend
wallet.AddToWallet(wtx2, true, NULL);
EXPECT_EQ(0, wallet.GetConflicts(hash2).size());
// Conflicts for two spends
wallet.AddToWallet(wtx3, true, NULL);
auto c3 = wallet.GetConflicts(hash2);
EXPECT_EQ(2, c3.size());
EXPECT_EQ(std::set<uint256>({hash2, hash3}), c3);
}
6 years ago
// Generate note A and spend to create note B, from which we spend to create two conflicting transactions
TEST(WalletTests, GetConflictedSaplingNotes) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto consensusParams = Params().GetConsensus();
TestWallet wallet;
// Generate Sapling address
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
HDSeed seed(rawSeed);
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
auto expsk = sk.expsk;
auto fvk = expsk.full_viewing_key();
auto ivk = fvk.in_viewing_key();
auto pk = sk.DefaultAddress();
ASSERT_TRUE(wallet.AddSaplingZKey(sk, pk));
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
// Generate note A
libzcash::SaplingNote note(pk, 50000);
auto cm = note.cm().get();
SaplingMerkleTree saplingTree;
saplingTree.append(cm);
auto anchor = saplingTree.root();
auto witness = saplingTree.witness();
// Generate tx to create output note B
auto builder = TransactionBuilder(consensusParams, 1);
ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
builder.AddSaplingOutput(fvk.ovk, pk, 35000, {});
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx = maybe_tx.get();
CWalletTx wtx {&wallet, tx};
// Fake-mine the transaction
EXPECT_EQ(-1, chainActive.Height());
SproutMerkleTree sproutTree;
CBlock block;
block.vtx.push_back(wtx);
block.hashMerkleRoot = block.BuildMerkleTree();
auto blockHash = block.GetHash();
CBlockIndex fakeIndex {block};
mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
chainActive.SetTip(&fakeIndex);
EXPECT_TRUE(chainActive.Contains(&fakeIndex));
EXPECT_EQ(0, chainActive.Height());
// Simulate SyncTransaction which calls AddToWalletIfInvolvingMe
auto saplingNoteData = wallet.FindMySaplingNotes(wtx).first;
ASSERT_TRUE(saplingNoteData.size() > 0);
wtx.SetSaplingNoteData(saplingNoteData);
wtx.SetMerkleBranch(block);
wallet.AddToWallet(wtx, true, NULL);
// Simulate receiving new block and ChainTip signal
wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
// Retrieve the updated wtx from wallet
uint256 hash = wtx.GetHash();
wtx = wallet.mapWallet[hash];
// Decrypt output note B
auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt(
wtx.vShieldedOutput[0].encCiphertext,
ivk,
wtx.vShieldedOutput[0].ephemeralKey,
wtx.vShieldedOutput[0].cm);
ASSERT_EQ(static_cast<bool>(maybe_pt), true);
auto maybe_note = maybe_pt.get().note(ivk);
ASSERT_EQ(static_cast<bool>(maybe_note), true);
auto note2 = maybe_note.get();
SaplingOutPoint sop0(wtx.GetHash(), 0);
auto spend_note_witness = wtx.mapSaplingNoteData[sop0].witnesses.front();
auto maybe_nf = note2.nullifier(fvk, spend_note_witness.position());
ASSERT_EQ(static_cast<bool>(maybe_nf), true);
auto nullifier2 = maybe_nf.get();
anchor = saplingTree.root();
// Create transaction to spend note B
auto builder2 = TransactionBuilder(consensusParams, 2);
ASSERT_TRUE(builder2.AddSaplingSpend(expsk, note2, anchor, spend_note_witness));
builder2.AddSaplingOutput(fvk.ovk, pk, 20000, {});
auto maybe_tx2 = builder2.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx2), true);
auto tx2 = maybe_tx2.get();
// Create conflicting transaction which also spends note B
auto builder3 = TransactionBuilder(consensusParams, 2);
ASSERT_TRUE(builder3.AddSaplingSpend(expsk, note2, anchor, spend_note_witness));
builder3.AddSaplingOutput(fvk.ovk, pk, 19999, {});
auto maybe_tx3 = builder3.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx3), true);
auto tx3 = maybe_tx3.get();
CWalletTx wtx2 {&wallet, tx2};
CWalletTx wtx3 {&wallet, tx3};
auto hash2 = wtx2.GetHash();
auto hash3 = wtx3.GetHash();
// No conflicts for no spends (wtx is currently the only transaction in the wallet)
EXPECT_EQ(0, wallet.GetConflicts(hash2).size());
EXPECT_EQ(0, wallet.GetConflicts(hash3).size());
// No conflicts for one spend
wallet.AddToWallet(wtx2, true, NULL);
EXPECT_EQ(0, wallet.GetConflicts(hash2).size());
// Conflicts for two spends
wallet.AddToWallet(wtx3, true, NULL);
auto c3 = wallet.GetConflicts(hash2);
EXPECT_EQ(2, c3.size());
EXPECT_EQ(std::set<uint256>({hash2, hash3}), c3);
// Tear down
chainActive.SetTip(NULL);
mapBlockIndex.erase(blockHash);
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
TEST(WalletTests, SproutNullifierIsSpent) {
CWallet wallet;
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
6 years ago
EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
wallet.AddToWallet(wtx, true, NULL);
6 years ago
EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
auto wtx2 = GetValidSpend(sk, note, 5);
wallet.AddToWallet(wtx2, true, NULL);
6 years ago
EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
// Fake-mine the transaction
EXPECT_EQ(-1, chainActive.Height());
CBlock block;
block.vtx.push_back(wtx2);
block.hashMerkleRoot = block.BuildMerkleTree();
auto blockHash = block.GetHash();
CBlockIndex fakeIndex {block};
mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
chainActive.SetTip(&fakeIndex);
EXPECT_TRUE(chainActive.Contains(&fakeIndex));
EXPECT_EQ(0, chainActive.Height());
wtx2.SetMerkleBranch(block);
wallet.AddToWallet(wtx2, true, NULL);
6 years ago
EXPECT_TRUE(wallet.IsSproutSpent(nullifier));
// Tear down
chainActive.SetTip(NULL);
mapBlockIndex.erase(blockHash);
}
6 years ago
TEST(WalletTests, SaplingNullifierIsSpent) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto consensusParams = Params().GetConsensus();
TestWallet wallet;
// Generate dummy Sapling address
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
HDSeed seed(rawSeed);
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
auto expsk = sk.expsk;
auto fvk = expsk.full_viewing_key();
auto pk = sk.DefaultAddress();
// Generate dummy Sapling note
libzcash::SaplingNote note(pk, 50000);
auto cm = note.cm().get();
SaplingMerkleTree tree;
tree.append(cm);
auto anchor = tree.root();
auto witness = tree.witness();
// Generate transaction
auto builder = TransactionBuilder(consensusParams, 1);
ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
builder.AddSaplingOutput(fvk.ovk, pk, 25000, {});
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx = maybe_tx.get();
CWalletTx wtx {&wallet, tx};
ASSERT_TRUE(wallet.AddSaplingZKey(sk, pk));
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
// Manually compute the nullifier based on the known position
auto nf = note.nullifier(fvk, witness.position());
ASSERT_TRUE(nf);
uint256 nullifier = nf.get();
// Verify note has not been spent
EXPECT_FALSE(wallet.IsSaplingSpent(nullifier));
// Fake-mine the transaction
EXPECT_EQ(-1, chainActive.Height());
CBlock block;
block.vtx.push_back(wtx);
block.hashMerkleRoot = block.BuildMerkleTree();
auto blockHash = block.GetHash();
CBlockIndex fakeIndex {block};
mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
chainActive.SetTip(&fakeIndex);
EXPECT_TRUE(chainActive.Contains(&fakeIndex));
EXPECT_EQ(0, chainActive.Height());
wtx.SetMerkleBranch(block);
wallet.AddToWallet(wtx, true, NULL);
// Verify note has been spent
EXPECT_TRUE(wallet.IsSaplingSpent(nullifier));
// Tear down
chainActive.SetTip(NULL);
mapBlockIndex.erase(blockHash);
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
TEST(WalletTests, NavigateFromSproutNullifierToNote) {
CWallet wallet;
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
6 years ago
mapSproutNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
6 years ago
wtx.SetSproutNoteData(noteData);
6 years ago
EXPECT_EQ(0, wallet.mapSproutNullifiersToNotes.count(nullifier));
wallet.AddToWallet(wtx, true, NULL);
6 years ago
EXPECT_EQ(1, wallet.mapSproutNullifiersToNotes.count(nullifier));
EXPECT_EQ(wtx.GetHash(), wallet.mapSproutNullifiersToNotes[nullifier].hash);
EXPECT_EQ(0, wallet.mapSproutNullifiersToNotes[nullifier].js);
EXPECT_EQ(1, wallet.mapSproutNullifiersToNotes[nullifier].n);
}
6 years ago
TEST(WalletTests, NavigateFromSaplingNullifierToNote) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto consensusParams = Params().GetConsensus();
TestWallet wallet;
// Generate dummy Sapling address
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
HDSeed seed(rawSeed);
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
auto expsk = sk.expsk;
auto fvk = expsk.full_viewing_key();
auto pk = sk.DefaultAddress();
// Generate dummy Sapling note
libzcash::SaplingNote note(pk, 50000);
auto cm = note.cm().get();
SaplingMerkleTree saplingTree;
saplingTree.append(cm);
auto anchor = saplingTree.root();
auto witness = saplingTree.witness();
// Generate transaction
auto builder = TransactionBuilder(consensusParams, 1);
ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
builder.AddSaplingOutput(fvk.ovk, pk, 25000, {});
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx = maybe_tx.get();
CWalletTx wtx {&wallet, tx};
ASSERT_TRUE(wallet.AddSaplingZKey(sk, pk));
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
// Manually compute the nullifier based on the expected position
auto nf = note.nullifier(fvk, witness.position());
ASSERT_TRUE(nf);
uint256 nullifier = nf.get();
// Verify dummy note is unspent
EXPECT_FALSE(wallet.IsSaplingSpent(nullifier));
// Fake-mine the transaction
EXPECT_EQ(-1, chainActive.Height());
SproutMerkleTree sproutTree;
CBlock block;
block.vtx.push_back(wtx);
block.hashMerkleRoot = block.BuildMerkleTree();
auto blockHash = block.GetHash();
CBlockIndex fakeIndex {block};
mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
chainActive.SetTip(&fakeIndex);
EXPECT_TRUE(chainActive.Contains(&fakeIndex));
EXPECT_EQ(0, chainActive.Height());
// Simulate SyncTransaction which calls AddToWalletIfInvolvingMe
wtx.SetMerkleBranch(block);
auto saplingNoteData = wallet.FindMySaplingNotes(wtx).first;
ASSERT_TRUE(saplingNoteData.size() > 0);
wtx.SetSaplingNoteData(saplingNoteData);
wallet.AddToWallet(wtx, true, NULL);
// Verify dummy note is now spent, as AddToWallet invokes AddToSpends()
EXPECT_TRUE(wallet.IsSaplingSpent(nullifier));
// Test invariant: no witnesses means no nullifier.
EXPECT_EQ(0, wallet.mapSaplingNullifiersToNotes.size());
for (mapSaplingNoteData_t::value_type &item : wtx.mapSaplingNoteData) {
SaplingNoteData nd = item.second;
ASSERT_TRUE(nd.witnesses.empty());
ASSERT_FALSE(nd.nullifier);
}
// Simulate receiving new block and ChainTip signal
wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
// Retrieve the updated wtx from wallet
uint256 hash = wtx.GetHash();
wtx = wallet.mapWallet[hash];
// Verify Sapling nullifiers map to SaplingOutPoints
EXPECT_EQ(2, wallet.mapSaplingNullifiersToNotes.size());
for (mapSaplingNoteData_t::value_type &item : wtx.mapSaplingNoteData) {
SaplingOutPoint op = item.first;
SaplingNoteData nd = item.second;
EXPECT_EQ(hash, op.hash);
EXPECT_EQ(1, nd.witnesses.size());
ASSERT_TRUE(nd.nullifier);
auto nf = nd.nullifier.get();
EXPECT_EQ(1, wallet.mapSaplingNullifiersToNotes.count(nf));
EXPECT_EQ(op.hash, wallet.mapSaplingNullifiersToNotes[nf].hash);
EXPECT_EQ(op.n, wallet.mapSaplingNullifiersToNotes[nf].n);
}
// Tear down
chainActive.SetTip(NULL);
mapBlockIndex.erase(blockHash);
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
TEST(WalletTests, SpentSproutNoteIsFromMe) {
CWallet wallet;
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
auto wtx2 = GetValidSpend(sk, note, 5);
EXPECT_FALSE(wallet.IsFromMe(wtx));
EXPECT_FALSE(wallet.IsFromMe(wtx2));
6 years ago
mapSproutNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
6 years ago
wtx.SetSproutNoteData(noteData);
EXPECT_FALSE(wallet.IsFromMe(wtx));
EXPECT_FALSE(wallet.IsFromMe(wtx2));
wallet.AddToWallet(wtx, true, NULL);
EXPECT_FALSE(wallet.IsFromMe(wtx));
EXPECT_TRUE(wallet.IsFromMe(wtx2));
}
6 years ago
// Create note A, spend A to create note B, spend and verify note B is from me.
TEST(WalletTests, SpentSaplingNoteIsFromMe) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto consensusParams = Params().GetConsensus();
TestWallet wallet;
6 years ago
// Generate Sapling address
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
HDSeed seed(rawSeed);
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
auto expsk = sk.expsk;
auto fvk = expsk.full_viewing_key();
auto ivk = fvk.in_viewing_key();
auto pk = sk.DefaultAddress();
// Generate Sapling note A
libzcash::SaplingNote note(pk, 50000);
auto cm = note.cm().get();
SaplingMerkleTree saplingTree;
saplingTree.append(cm);
auto anchor = saplingTree.root();
auto witness = saplingTree.witness();
// Generate transaction, which sends funds to note B
auto builder = TransactionBuilder(consensusParams, 1);
ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
builder.AddSaplingOutput(fvk.ovk, pk, 25000, {});
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx = maybe_tx.get();
CWalletTx wtx {&wallet, tx};
ASSERT_TRUE(wallet.AddSaplingZKey(sk, pk));
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
6 years ago
// Fake-mine the transaction
EXPECT_EQ(-1, chainActive.Height());
SproutMerkleTree sproutTree;
CBlock block;
block.vtx.push_back(wtx);
block.hashMerkleRoot = block.BuildMerkleTree();
auto blockHash = block.GetHash();
CBlockIndex fakeIndex {block};
mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
chainActive.SetTip(&fakeIndex);
EXPECT_TRUE(chainActive.Contains(&fakeIndex));
EXPECT_EQ(0, chainActive.Height());
auto saplingNoteData = wallet.FindMySaplingNotes(wtx).first;
ASSERT_TRUE(saplingNoteData.size() > 0);
wtx.SetSaplingNoteData(saplingNoteData);
wtx.SetMerkleBranch(block);
wallet.AddToWallet(wtx, true, NULL);
// Simulate receiving new block and ChainTip signal.
// This triggers calculation of nullifiers for notes belonging to this wallet
// in the output descriptions of wtx.
wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
// Retrieve the updated wtx from wallet
wtx = wallet.mapWallet[wtx.GetHash()];
// The test wallet never received the fake note which is being spent, so there
// is no mapping from nullifier to notedata stored in mapSaplingNullifiersToNotes.
// Therefore the wallet does not know the tx belongs to the wallet.
EXPECT_FALSE(wallet.IsFromMe(wtx));
// Manually compute the nullifier and check map entry does not exist
auto nf = note.nullifier(fvk, witness.position());
ASSERT_TRUE(nf);
ASSERT_FALSE(wallet.mapSaplingNullifiersToNotes.count(nf.get()));
// Decrypt note B
auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt(
wtx.vShieldedOutput[0].encCiphertext,
ivk,
wtx.vShieldedOutput[0].ephemeralKey,
wtx.vShieldedOutput[0].cm);
ASSERT_EQ(static_cast<bool>(maybe_pt), true);
auto maybe_note = maybe_pt.get().note(ivk);
ASSERT_EQ(static_cast<bool>(maybe_note), true);
auto note2 = maybe_note.get();
// Get witness to retrieve position of note B we want to spend
SaplingOutPoint sop0(wtx.GetHash(), 0);
auto spend_note_witness = wtx.mapSaplingNoteData[sop0].witnesses.front();
auto maybe_nf = note2.nullifier(fvk, spend_note_witness.position());
ASSERT_EQ(static_cast<bool>(maybe_nf), true);
auto nullifier2 = maybe_nf.get();
// NOTE: Not updating the anchor results in a core dump. Shouldn't builder just return error?
// *** Error in `./zcash-gtest': double free or corruption (out): 0x00007ffd8755d990 ***
anchor = saplingTree.root();
// Create transaction to spend note B
auto builder2 = TransactionBuilder(consensusParams, 2);
ASSERT_TRUE(builder2.AddSaplingSpend(expsk, note2, anchor, spend_note_witness));
builder2.AddSaplingOutput(fvk.ovk, pk, 12500, {});
auto maybe_tx2 = builder2.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx2), true);
auto tx2 = maybe_tx2.get();
EXPECT_EQ(tx2.vin.size(), 0);
EXPECT_EQ(tx2.vout.size(), 0);
EXPECT_EQ(tx2.vjoinsplit.size(), 0);
EXPECT_EQ(tx2.vShieldedSpend.size(), 1);
EXPECT_EQ(tx2.vShieldedOutput.size(), 2);
EXPECT_EQ(tx2.valueBalance, 10000);
CWalletTx wtx2 {&wallet, tx2};
// Fake-mine this tx into the next block
EXPECT_EQ(0, chainActive.Height());
CBlock block2;
block2.vtx.push_back(wtx2);
block2.hashMerkleRoot = block2.BuildMerkleTree();
block2.hashPrevBlock = blockHash;
auto blockHash2 = block2.GetHash();
CBlockIndex fakeIndex2 {block2};
mapBlockIndex.insert(std::make_pair(blockHash2, &fakeIndex2));
fakeIndex2.SetHeight(1);
chainActive.SetTip(&fakeIndex2);
EXPECT_TRUE(chainActive.Contains(&fakeIndex2));
EXPECT_EQ(1, chainActive.Height());
auto saplingNoteData2 = wallet.FindMySaplingNotes(wtx2).first;
ASSERT_TRUE(saplingNoteData2.size() > 0);
wtx2.SetSaplingNoteData(saplingNoteData2);
wtx2.SetMerkleBranch(block2);
wallet.AddToWallet(wtx2, true, NULL);
// Verify note B is spent. AddToWallet invokes AddToSpends which updates mapTxSaplingNullifiers
EXPECT_TRUE(wallet.IsSaplingSpent(nullifier2));
// Verify note B belongs to wallet.
EXPECT_TRUE(wallet.IsFromMe(wtx2));
ASSERT_TRUE(wallet.mapSaplingNullifiersToNotes.count(nullifier2));
// Tear down
chainActive.SetTip(NULL);
mapBlockIndex.erase(blockHash);
mapBlockIndex.erase(blockHash2);
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
TEST(WalletTests, CachedWitnessesEmptyChain) {
TestWallet wallet;
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true, 4);
auto note = GetNote(sk, wtx, 0, 0);
auto note2 = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
auto nullifier2 = note2.nullifier(sk);
6 years ago
mapSproutNoteData_t sproutNoteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 0};
JSOutPoint jsoutpt2 {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
SproutNoteData nd2 {sk.address(), nullifier2};
sproutNoteData[jsoutpt] = nd;
sproutNoteData[jsoutpt2] = nd2;
wtx.SetSproutNoteData(sproutNoteData);
std::vector<JSOutPoint> sproutNotes {jsoutpt, jsoutpt2};
std::vector<SaplingOutPoint> saplingNotes = SetSaplingNoteData(wtx);
std::vector<boost::optional<SproutWitness>> sproutWitnesses;
std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
6 years ago
::GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
6 years ago
EXPECT_FALSE((bool) sproutWitnesses[0]);
EXPECT_FALSE((bool) sproutWitnesses[1]);
EXPECT_FALSE((bool) saplingWitnesses[0]);
wallet.AddToWallet(wtx, true, NULL);
6 years ago
::GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
EXPECT_FALSE((bool) sproutWitnesses[0]);
EXPECT_FALSE((bool) sproutWitnesses[1]);
EXPECT_FALSE((bool) saplingWitnesses[0]);
CBlock block;
block.vtx.push_back(wtx);
CBlockIndex index(block);
6 years ago
SproutMerkleTree sproutTree;
SaplingMerkleTree saplingTree;
wallet.IncrementNoteWitnesses(&index, &block, sproutTree, saplingTree);
::GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
EXPECT_TRUE((bool) sproutWitnesses[0]);
EXPECT_TRUE((bool) sproutWitnesses[1]);
EXPECT_TRUE((bool) saplingWitnesses[0]);
8 years ago
// Until #1302 is implemented, this should triggger an assertion
EXPECT_DEATH(wallet.DecrementNoteWitnesses(&index),
6 years ago
".*nWitnessCacheSize > 0.*");
}
6 years ago
TEST(WalletTests, CachedWitnessesChainTip) {
TestWallet wallet;
6 years ago
std::pair<uint256, uint256> anchors1;
CBlock block1;
6 years ago
SproutMerkleTree sproutTree;
SaplingMerkleTree saplingTree;
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
{
// First block (case tested in _empty_chain)
CBlockIndex index1(block1);
6 years ago
index1.SetHeight(1);
auto outpts = CreateValidBlock(wallet, sk, index1, block1, sproutTree, saplingTree);
// Called to fetch anchor
6 years ago
std::vector<JSOutPoint> sproutNotes {outpts.first};
std::vector<SaplingOutPoint> saplingNotes {outpts.second};
std::vector<boost::optional<SproutWitness>> sproutWitnesses;
std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
anchors1 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
EXPECT_NE(anchors1.first, anchors1.second);
}
{
// Second transaction
6 years ago
auto wtx = GetValidReceive(sk, 50, true, 4);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
6 years ago
mapSproutNoteData_t sproutNoteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
sproutNoteData[jsoutpt] = nd;
wtx.SetSproutNoteData(sproutNoteData);
std::vector<SaplingOutPoint> saplingNotes = SetSaplingNoteData(wtx);
wallet.AddToWallet(wtx, true, NULL);
6 years ago
std::vector<JSOutPoint> sproutNotes {jsoutpt};
std::vector<boost::optional<SproutWitness>> sproutWitnesses;
std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
6 years ago
EXPECT_FALSE((bool) sproutWitnesses[0]);
EXPECT_FALSE((bool) saplingWitnesses[0]);
// Second block
CBlock block2;
block2.hashPrevBlock = block1.GetHash();
block2.vtx.push_back(wtx);
CBlockIndex index2(block2);
6 years ago
index2.SetHeight(2);
SproutMerkleTree sproutTree2 {sproutTree};
SaplingMerkleTree saplingTree2 {saplingTree};
wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree2, saplingTree2);
auto anchors2 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
EXPECT_NE(anchors2.first, anchors2.second);
EXPECT_TRUE((bool) sproutWitnesses[0]);
EXPECT_TRUE((bool) saplingWitnesses[0]);
EXPECT_NE(anchors1.first, anchors2.first);
EXPECT_NE(anchors1.second, anchors2.second);
// Decrementing should give us the previous anchor
wallet.DecrementNoteWitnesses(&index2);
6 years ago
auto anchors3 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
EXPECT_FALSE((bool) sproutWitnesses[0]);
EXPECT_FALSE((bool) saplingWitnesses[0]);
// Should not equal first anchor because none of these notes had witnesses
6 years ago
EXPECT_NE(anchors1.first, anchors3.first);
EXPECT_NE(anchors1.second, anchors3.second);
// Re-incrementing with the same block should give the same result
6 years ago
wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree);
auto anchors4 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
EXPECT_NE(anchors4.first, anchors4.second);
EXPECT_TRUE((bool) sproutWitnesses[0]);
EXPECT_TRUE((bool) saplingWitnesses[0]);
EXPECT_EQ(anchors2.first, anchors4.first);
EXPECT_EQ(anchors2.second, anchors4.second);
// Incrementing with the same block again should not change the cache
6 years ago
wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree);
std::vector<boost::optional<SproutWitness>> sproutWitnesses5;
std::vector<boost::optional<SaplingWitness>> saplingWitnesses5;
auto anchors5 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses5, saplingWitnesses5);
EXPECT_NE(anchors5.first, anchors5.second);
EXPECT_EQ(sproutWitnesses, sproutWitnesses5);
EXPECT_EQ(saplingWitnesses, saplingWitnesses5);
EXPECT_EQ(anchors4.first, anchors5.first);
EXPECT_EQ(anchors4.second, anchors5.second);
}
}
6 years ago
TEST(WalletTests, CachedWitnessesDecrementFirst) {
TestWallet wallet;
6 years ago
SproutMerkleTree sproutTree;
SaplingMerkleTree saplingTree;
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
{
// First block (case tested in _empty_chain)
CBlock block1;
CBlockIndex index1(block1);
6 years ago
index1.SetHeight(1);
CreateValidBlock(wallet, sk, index1, block1, sproutTree, saplingTree);
}
6 years ago
std::pair<uint256, uint256> anchors2;
CBlock block2;
CBlockIndex index2(block2);
{
// Second block (case tested in _chain_tip)
6 years ago
index2.SetHeight(2);
auto outpts = CreateValidBlock(wallet, sk, index2, block2, sproutTree, saplingTree);
// Called to fetch anchor
6 years ago
std::vector<JSOutPoint> sproutNotes {outpts.first};
std::vector<SaplingOutPoint> saplingNotes {outpts.second};
std::vector<boost::optional<SproutWitness>> sproutWitnesses;
std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
anchors2 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
}
6 years ago
{
// Third transaction - never mined
6 years ago
auto wtx = GetValidReceive(sk, 20, true, 4);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
6 years ago
mapSproutNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
6 years ago
wtx.SetSproutNoteData(noteData);
std::vector<SaplingOutPoint> saplingNotes = SetSaplingNoteData(wtx);
wallet.AddToWallet(wtx, true, NULL);
6 years ago
std::vector<JSOutPoint> sproutNotes {jsoutpt};
std::vector<boost::optional<SproutWitness>> sproutWitnesses;
std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
6 years ago
auto anchors3 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
EXPECT_FALSE((bool) sproutWitnesses[0]);
EXPECT_FALSE((bool) saplingWitnesses[0]);
// Decrementing (before the transaction has ever seen an increment)
// should give us the previous anchor
wallet.DecrementNoteWitnesses(&index2);
6 years ago
auto anchors4 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
EXPECT_FALSE((bool) sproutWitnesses[0]);
EXPECT_FALSE((bool) saplingWitnesses[0]);
// Should not equal second anchor because none of these notes had witnesses
6 years ago
EXPECT_NE(anchors2.first, anchors4.first);
EXPECT_NE(anchors2.second, anchors4.second);
// Re-incrementing with the same block should give the same result
6 years ago
wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree);
auto anchors5 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
EXPECT_FALSE((bool) sproutWitnesses[0]);
EXPECT_FALSE((bool) saplingWitnesses[0]);
EXPECT_EQ(anchors3.first, anchors5.first);
EXPECT_EQ(anchors3.second, anchors5.second);
}
}
6 years ago
TEST(WalletTests, CachedWitnessesCleanIndex) {
TestWallet wallet;
std::vector<CBlock> blocks;
std::vector<CBlockIndex> indices;
6 years ago
std::vector<JSOutPoint> sproutNotes;
std::vector<SaplingOutPoint> saplingNotes;
std::vector<uint256> sproutAnchors;
std::vector<uint256> saplingAnchors;
SproutMerkleTree sproutTree;
SproutMerkleTree sproutRiTree = sproutTree;
SaplingMerkleTree saplingTree;
SaplingMerkleTree saplingRiTree = saplingTree;
std::vector<boost::optional<SproutWitness>> sproutWitnesses;
std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
// Generate a chain
size_t numBlocks = WITNESS_CACHE_SIZE + 10;
blocks.resize(numBlocks);
indices.resize(numBlocks);
for (size_t i = 0; i < numBlocks; i++) {
6 years ago
indices[i].SetHeight(i);
auto oldSproutRoot = sproutTree.root();
auto oldSaplingRoot = saplingTree.root();
auto outpts = CreateValidBlock(wallet, sk, indices[i], blocks[i], sproutTree, saplingTree);
EXPECT_NE(oldSproutRoot, sproutTree.root());
EXPECT_NE(oldSaplingRoot, saplingTree.root());
sproutNotes.push_back(outpts.first);
saplingNotes.push_back(outpts.second);
auto anchors = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
for (size_t j = 0; j <= i; j++) {
6 years ago
EXPECT_TRUE((bool) sproutWitnesses[j]);
EXPECT_TRUE((bool) saplingWitnesses[j]);
}
6 years ago
sproutAnchors.push_back(anchors.first);
saplingAnchors.push_back(anchors.second);
}
// Now pretend we are reindexing: the chain is cleared, and each block is
// used to increment witnesses again.
for (size_t i = 0; i < numBlocks; i++) {
6 years ago
SproutMerkleTree sproutRiPrevTree {sproutRiTree};
SaplingMerkleTree saplingRiPrevTree {saplingRiTree};
wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), sproutRiTree, saplingRiTree);
auto anchors = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
for (size_t j = 0; j < numBlocks; j++) {
6 years ago
EXPECT_TRUE((bool) sproutWitnesses[j]);
EXPECT_TRUE((bool) saplingWitnesses[j]);
}
// Should equal final anchor because witness cache unaffected
6 years ago
EXPECT_EQ(sproutAnchors.back(), anchors.first);
EXPECT_EQ(saplingAnchors.back(), anchors.second);
if ((i == 5) || (i == 50)) {
// Pretend a reorg happened that was recorded in the block files
{
wallet.DecrementNoteWitnesses(&(indices[i]));
6 years ago
auto anchors = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
for (size_t j = 0; j < numBlocks; j++) {
6 years ago
EXPECT_TRUE((bool) sproutWitnesses[j]);
EXPECT_TRUE((bool) saplingWitnesses[j]);
}
// Should equal final anchor because witness cache unaffected
6 years ago
EXPECT_EQ(sproutAnchors.back(), anchors.first);
EXPECT_EQ(saplingAnchors.back(), anchors.second);
}
{
6 years ago
wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), sproutRiPrevTree, saplingRiPrevTree);
auto anchors = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
for (size_t j = 0; j < numBlocks; j++) {
6 years ago
EXPECT_TRUE((bool) sproutWitnesses[j]);
EXPECT_TRUE((bool) saplingWitnesses[j]);
}
// Should equal final anchor because witness cache unaffected
6 years ago
EXPECT_EQ(sproutAnchors.back(), anchors.first);
EXPECT_EQ(saplingAnchors.back(), anchors.second);
}
}
}
}
6 years ago
TEST(WalletTests, ClearNoteWitnessCache) {
TestWallet wallet;
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
6 years ago
auto wtx = GetValidReceive(sk, 10, true, 4);
auto hash = wtx.GetHash();
auto note = GetNote(sk, wtx, 0, 0);
auto nullifier = note.nullifier(sk);
6 years ago
mapSproutNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 0};
JSOutPoint jsoutpt2 {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
6 years ago
wtx.SetSproutNoteData(noteData);
auto saplingNotes = SetSaplingNoteData(wtx);
// Pretend we mined the tx by adding a fake witness
6 years ago
SproutMerkleTree sproutTree;
wtx.mapSproutNoteData[jsoutpt].witnesses.push_front(sproutTree.witness());
wtx.mapSproutNoteData[jsoutpt].witnessHeight = 1;
wallet.nWitnessCacheSize = 1;
6 years ago
SaplingMerkleTree saplingTree;
wtx.mapSaplingNoteData[saplingNotes[0]].witnesses.push_front(saplingTree.witness());
wtx.mapSaplingNoteData[saplingNotes[0]].witnessHeight = 1;
wallet.nWitnessCacheSize = 2;
wallet.AddToWallet(wtx, true, NULL);
6 years ago
std::vector<JSOutPoint> sproutNotes {jsoutpt, jsoutpt2};
std::vector<boost::optional<SproutWitness>> sproutWitnesses;
std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
// Before clearing, we should have a witness for one note
6 years ago
GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
EXPECT_TRUE((bool) sproutWitnesses[0]);
EXPECT_FALSE((bool) sproutWitnesses[1]);
EXPECT_TRUE((bool) saplingWitnesses[0]);
EXPECT_FALSE((bool) saplingWitnesses[1]);
EXPECT_EQ(1, wallet.mapWallet[hash].mapSproutNoteData[jsoutpt].witnessHeight);
EXPECT_EQ(1, wallet.mapWallet[hash].mapSaplingNoteData[saplingNotes[0]].witnessHeight);
EXPECT_EQ(2, wallet.nWitnessCacheSize);
// After clearing, we should not have a witness for either note
wallet.ClearNoteWitnessCache();
6 years ago
auto anchors2 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
EXPECT_FALSE((bool) sproutWitnesses[0]);
EXPECT_FALSE((bool) sproutWitnesses[1]);
EXPECT_FALSE((bool) saplingWitnesses[0]);
EXPECT_FALSE((bool) saplingWitnesses[1]);
EXPECT_EQ(-1, wallet.mapWallet[hash].mapSproutNoteData[jsoutpt].witnessHeight);
EXPECT_EQ(-1, wallet.mapWallet[hash].mapSaplingNoteData[saplingNotes[0]].witnessHeight);
EXPECT_EQ(0, wallet.nWitnessCacheSize);
}
6 years ago
TEST(WalletTests, WriteWitnessCache) {
TestWallet wallet;
MockWalletDB walletdb;
CBlockLocator loc;
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
wallet.AddToWallet(wtx, true, NULL);
// TxnBegin fails
EXPECT_CALL(walletdb, TxnBegin())
.WillOnce(Return(false));
wallet.SetBestChain(walletdb, loc);
EXPECT_CALL(walletdb, TxnBegin())
.WillRepeatedly(Return(true));
// WriteTx fails
EXPECT_CALL(walletdb, WriteTx(wtx.GetHash(), wtx))
.WillOnce(Return(false));
EXPECT_CALL(walletdb, TxnAbort())
.Times(1);
wallet.SetBestChain(walletdb, loc);
// WriteTx throws
EXPECT_CALL(walletdb, WriteTx(wtx.GetHash(), wtx))
.WillOnce(ThrowLogicError());
EXPECT_CALL(walletdb, TxnAbort())
.Times(1);
wallet.SetBestChain(walletdb, loc);
EXPECT_CALL(walletdb, WriteTx(wtx.GetHash(), wtx))
.WillRepeatedly(Return(true));
// WriteWitnessCacheSize fails
EXPECT_CALL(walletdb, WriteWitnessCacheSize(0))
.WillOnce(Return(false));
EXPECT_CALL(walletdb, TxnAbort())
.Times(1);
wallet.SetBestChain(walletdb, loc);
// WriteWitnessCacheSize throws
EXPECT_CALL(walletdb, WriteWitnessCacheSize(0))
.WillOnce(ThrowLogicError());
EXPECT_CALL(walletdb, TxnAbort())
.Times(1);
wallet.SetBestChain(walletdb, loc);
EXPECT_CALL(walletdb, WriteWitnessCacheSize(0))
.WillRepeatedly(Return(true));
// WriteBestBlock fails
EXPECT_CALL(walletdb, WriteBestBlock(loc))
.WillOnce(Return(false));
EXPECT_CALL(walletdb, TxnAbort())
.Times(1);
wallet.SetBestChain(walletdb, loc);
// WriteBestBlock throws
EXPECT_CALL(walletdb, WriteBestBlock(loc))
.WillOnce(ThrowLogicError());
EXPECT_CALL(walletdb, TxnAbort())
.Times(1);
wallet.SetBestChain(walletdb, loc);
EXPECT_CALL(walletdb, WriteBestBlock(loc))
.WillRepeatedly(Return(true));
// TxCommit fails
EXPECT_CALL(walletdb, TxnCommit())
.WillOnce(Return(false));
wallet.SetBestChain(walletdb, loc);
EXPECT_CALL(walletdb, TxnCommit())
.WillRepeatedly(Return(true));
// Everything succeeds
wallet.SetBestChain(walletdb, loc);
}
TEST(WalletTests, SetBestChainIgnoresTxsWithoutShieldedData) {
SelectParams(CBaseChainParams::REGTEST);
TestWallet wallet;
MockWalletDB walletdb;
CBlockLocator loc;
// Set up transparent address
CKey tsk = DecodeSecret(tSecretRegtest);
wallet.AddKey(tsk);
auto scriptPubKey = GetScriptForDestination(tsk.GetPubKey().GetID());
// Set up a Sprout address
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
// Generate a transparent transaction that is ours
CMutableTransaction t;
t.vout.resize(1);
t.vout[0].nValue = 90*CENT;
t.vout[0].scriptPubKey = scriptPubKey;
CWalletTx wtxTransparent {nullptr, t};
wallet.AddToWallet(wtxTransparent, true, NULL);
// Generate a Sprout transaction that is ours
auto wtxSprout = GetValidReceive(sk, 10, true);
auto noteMap = wallet.FindMySproutNotes(wtxSprout);
wtxSprout.SetSproutNoteData(noteMap);
wallet.AddToWallet(wtxSprout, true, NULL);
// Generate a Sprout transaction that only involves our transparent address
auto sk2 = libzcash::SproutSpendingKey::random();
auto wtxInput = GetValidReceive(sk2, 10, true);
auto note = GetNote(sk2, wtxInput, 0, 0);
auto wtxTmp = GetValidSpend(sk2, note, 5);
CMutableTransaction mtx {wtxTmp};
mtx.vout[0].scriptPubKey = scriptPubKey;
CWalletTx wtxSproutTransparent {NULL, mtx};
wallet.AddToWallet(wtxSproutTransparent, true, NULL);
EXPECT_CALL(walletdb, TxnBegin())
.WillOnce(Return(true));
EXPECT_CALL(walletdb, WriteTx(wtxTransparent.GetHash(), wtxTransparent))
.Times(0);
EXPECT_CALL(walletdb, WriteTx(wtxSprout.GetHash(), wtxSprout))
.Times(1).WillOnce(Return(true));
EXPECT_CALL(walletdb, WriteTx(wtxSproutTransparent.GetHash(), wtxSproutTransparent))
.Times(0);
EXPECT_CALL(walletdb, WriteWitnessCacheSize(0))
.WillOnce(Return(true));
EXPECT_CALL(walletdb, WriteBestBlock(loc))
.WillOnce(Return(true));
EXPECT_CALL(walletdb, TxnCommit())
.WillOnce(Return(true));
wallet.SetBestChain(walletdb, loc);
}
6 years ago
TEST(WalletTests, UpdateSproutNullifierNoteMap) {
TestWallet wallet;
uint256 r {GetRandHash()};
CKeyingMaterial vMasterKey (r.begin(), r.end());
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
ASSERT_TRUE(wallet.EncryptKeys(vMasterKey));
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
6 years ago
// Pretend that we called FindMySproutNotes while the wallet was locked
mapSproutNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
6 years ago
SproutNoteData nd {sk.address()};
noteData[jsoutpt] = nd;
6 years ago
wtx.SetSproutNoteData(noteData);
wallet.AddToWallet(wtx, true, NULL);
6 years ago
EXPECT_EQ(0, wallet.mapSproutNullifiersToNotes.count(nullifier));
EXPECT_FALSE(wallet.UpdateNullifierNoteMap());
ASSERT_TRUE(wallet.Unlock(vMasterKey));
EXPECT_TRUE(wallet.UpdateNullifierNoteMap());
6 years ago
EXPECT_EQ(1, wallet.mapSproutNullifiersToNotes.count(nullifier));
EXPECT_EQ(wtx.GetHash(), wallet.mapSproutNullifiersToNotes[nullifier].hash);
EXPECT_EQ(0, wallet.mapSproutNullifiersToNotes[nullifier].js);
EXPECT_EQ(1, wallet.mapSproutNullifiersToNotes[nullifier].n);
}
6 years ago
TEST(WalletTests, UpdatedSproutNoteData) {
TestWallet wallet;
6 years ago
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 0);
auto note2 = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
auto nullifier2 = note2.nullifier(sk);
auto wtx2 = wtx;
// First pretend we added the tx to the wallet and
// we don't have the key for the second note
6 years ago
mapSproutNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 0};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
6 years ago
wtx.SetSproutNoteData(noteData);
// Pretend we mined the tx by adding a fake witness
6 years ago
SproutMerkleTree tree;
wtx.mapSproutNoteData[jsoutpt].witnesses.push_front(tree.witness());
wtx.mapSproutNoteData[jsoutpt].witnessHeight = 100;
// Now pretend we added the key for the second note, and
// the tx was "added" to the wallet again to update it.
// This happens via the 'z_importkey' RPC method.
JSOutPoint jsoutpt2 {wtx2.GetHash(), 0, 1};
6 years ago
SproutNoteData nd2 {sk.address(), nullifier2};
noteData[jsoutpt2] = nd2;
6 years ago
wtx2.SetSproutNoteData(noteData);
// The txs should initially be different
6 years ago
EXPECT_NE(wtx.mapSproutNoteData, wtx2.mapSproutNoteData);
EXPECT_EQ(1, wtx.mapSproutNoteData[jsoutpt].witnesses.size());
EXPECT_EQ(100, wtx.mapSproutNoteData[jsoutpt].witnessHeight);
// After updating, they should be the same
8 years ago
EXPECT_TRUE(wallet.UpdatedNoteData(wtx2, wtx));
6 years ago
EXPECT_EQ(wtx.mapSproutNoteData, wtx2.mapSproutNoteData);
EXPECT_EQ(1, wtx.mapSproutNoteData[jsoutpt].witnesses.size());
EXPECT_EQ(100, wtx.mapSproutNoteData[jsoutpt].witnessHeight);
// TODO: The new note should get witnessed (but maybe not here) (#1350)
}
6 years ago
TEST(WalletTests, UpdatedSaplingNoteData) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto consensusParams = Params().GetConsensus();
TestWallet wallet;
6 years ago
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
HDSeed seed(rawSeed);
auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);
// Generate dummy Sapling address
auto sk = m.Derive(0);
auto expsk = sk.expsk;
auto fvk = expsk.full_viewing_key();
auto pk = sk.DefaultAddress();
// Generate dummy recipient Sapling address
auto sk2 = m.Derive(1);
auto expsk2 = sk2.expsk;
auto fvk2 = expsk2.full_viewing_key();
auto pk2 = sk2.DefaultAddress();
// Generate dummy Sapling note
libzcash::SaplingNote note(pk, 50000);
auto cm = note.cm().get();
SaplingMerkleTree saplingTree;
saplingTree.append(cm);
auto anchor = saplingTree.root();
auto witness = saplingTree.witness();
// Generate transaction
auto builder = TransactionBuilder(consensusParams, 1);
ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
builder.AddSaplingOutput(fvk.ovk, pk2, 25000, {});
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx = maybe_tx.get();
// Wallet contains fvk1 but not fvk2
CWalletTx wtx {&wallet, tx};
ASSERT_TRUE(wallet.AddSaplingZKey(sk, pk));
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
ASSERT_FALSE(wallet.HaveSaplingSpendingKey(fvk2));
// Fake-mine the transaction
EXPECT_EQ(-1, chainActive.Height());
SproutMerkleTree sproutTree;
CBlock block;
block.vtx.push_back(wtx);
block.hashMerkleRoot = block.BuildMerkleTree();
auto blockHash = block.GetHash();
CBlockIndex fakeIndex {block};
mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
chainActive.SetTip(&fakeIndex);
EXPECT_TRUE(chainActive.Contains(&fakeIndex));
EXPECT_EQ(0, chainActive.Height());
// Simulate SyncTransaction which calls AddToWalletIfInvolvingMe
auto saplingNoteData = wallet.FindMySaplingNotes(wtx).first;
ASSERT_TRUE(saplingNoteData.size() == 1); // wallet only has key for change output
wtx.SetSaplingNoteData(saplingNoteData);
wtx.SetMerkleBranch(block);
wallet.AddToWallet(wtx, true, NULL);
// Simulate receiving new block and ChainTip signal
wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
// Retrieve the updated wtx from wallet
uint256 hash = wtx.GetHash();
wtx = wallet.mapWallet[hash];
// Now lets add key fvk2 so wallet can find the payment note sent to pk2
ASSERT_TRUE(wallet.AddSaplingZKey(sk2, pk2));
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk2));
CWalletTx wtx2 = wtx;
auto saplingNoteData2 = wallet.FindMySaplingNotes(wtx2).first;
ASSERT_TRUE(saplingNoteData2.size() == 2);
wtx2.SetSaplingNoteData(saplingNoteData2);
// The payment note has not been witnessed yet, so let's fake the witness.
SaplingOutPoint sop0(wtx2.GetHash(), 0);
SaplingOutPoint sop1(wtx2.GetHash(), 1);
wtx2.mapSaplingNoteData[sop0].witnesses.push_front(saplingTree.witness());
wtx2.mapSaplingNoteData[sop0].witnessHeight = 0;
// The txs are different as wtx is aware of just the change output,
// whereas wtx2 is aware of both payment and change outputs.
EXPECT_NE(wtx.mapSaplingNoteData, wtx2.mapSaplingNoteData);
EXPECT_EQ(1, wtx.mapSaplingNoteData.size());
EXPECT_EQ(1, wtx.mapSaplingNoteData[sop1].witnesses.size()); // wtx has witness for change
EXPECT_EQ(2, wtx2.mapSaplingNoteData.size());
EXPECT_EQ(1, wtx2.mapSaplingNoteData[sop0].witnesses.size()); // wtx2 has fake witness for payment output
EXPECT_EQ(0, wtx2.mapSaplingNoteData[sop1].witnesses.size()); // wtx2 never had incrementnotewitness called
// After updating, they should be the same
EXPECT_TRUE(wallet.UpdatedNoteData(wtx2, wtx));
// We can't do this:
// EXPECT_EQ(wtx.mapSaplingNoteData, wtx2.mapSaplingNoteData);
// because nullifiers (if part of == comparator) have not all been computed
// Also note that mapwallet[hash] is not updated with the updated wtx.
// wtx = wallet.mapWallet[hash];
EXPECT_EQ(2, wtx.mapSaplingNoteData.size());
EXPECT_EQ(2, wtx2.mapSaplingNoteData.size());
// wtx copied over the fake witness from wtx2 for the payment output
EXPECT_EQ(wtx.mapSaplingNoteData[sop0].witnesses.front(), wtx2.mapSaplingNoteData[sop0].witnesses.front());
// wtx2 never had its change output witnessed even though it has been in wtx
EXPECT_EQ(0, wtx2.mapSaplingNoteData[sop1].witnesses.size());
EXPECT_EQ(wtx.mapSaplingNoteData[sop1].witnesses.front(), saplingTree.witness());
// Tear down
chainActive.SetTip(NULL);
mapBlockIndex.erase(blockHash);
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
TEST(WalletTests, MarkAffectedSproutTransactionsDirty) {
TestWallet wallet;
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
auto hash = wtx.GetHash();
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
auto wtx2 = GetValidSpend(sk, note, 5);
6 years ago
mapSproutNoteData_t noteData;
JSOutPoint jsoutpt {hash, 0, 1};
6 years ago
SproutNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
6 years ago
wtx.SetSproutNoteData(noteData);
wallet.AddToWallet(wtx, true, NULL);
wallet.MarkAffectedTransactionsDirty(wtx);
// After getting a cached value, the first tx should be clean
wallet.mapWallet[hash].GetDebit(ISMINE_ALL);
EXPECT_TRUE(wallet.mapWallet[hash].fDebitCached);
// After adding the note spend, the first tx should be dirty
wallet.AddToWallet(wtx2, true, NULL);
wallet.MarkAffectedTransactionsDirty(wtx2);
EXPECT_FALSE(wallet.mapWallet[hash].fDebitCached);
}
6 years ago
TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto consensusParams = Params().GetConsensus();
TestWallet wallet;
6 years ago
// Generate Sapling address
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
HDSeed seed(rawSeed);
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
auto expsk = sk.expsk;
auto fvk = expsk.full_viewing_key();
auto ivk = fvk.in_viewing_key();
auto pk = sk.DefaultAddress();
ASSERT_TRUE(wallet.AddSaplingZKey(sk, pk));
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
// Set up transparent address
CBasicKeyStore keystore;
CKey tsk = DecodeSecret(tSecretRegtest);
keystore.AddKey(tsk);
auto scriptPubKey = GetScriptForDestination(tsk.GetPubKey().GetID());
// Generate shielding tx from transparent to Sapling
// 0.0005 t-ZEC in, 0.0004 z-ZEC out, 0.0001 t-ZEC fee
auto builder = TransactionBuilder(consensusParams, 1, &keystore);
builder.AddTransparentInput(COutPoint(), scriptPubKey, 50000);
builder.AddSaplingOutput(fvk.ovk, pk, 40000, {});
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx1 = maybe_tx.get();
EXPECT_EQ(tx1.vin.size(), 1);
EXPECT_EQ(tx1.vout.size(), 0);
EXPECT_EQ(tx1.vjoinsplit.size(), 0);
EXPECT_EQ(tx1.vShieldedSpend.size(), 0);
EXPECT_EQ(tx1.vShieldedOutput.size(), 1);
EXPECT_EQ(tx1.valueBalance, -40000);
CWalletTx wtx {&wallet, tx1};
// Fake-mine the transaction
EXPECT_EQ(-1, chainActive.Height());
SaplingMerkleTree saplingTree;
SproutMerkleTree sproutTree;
CBlock block;
block.vtx.push_back(wtx);
block.hashMerkleRoot = block.BuildMerkleTree();
auto blockHash = block.GetHash();
CBlockIndex fakeIndex {block};
mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
chainActive.SetTip(&fakeIndex);
EXPECT_TRUE(chainActive.Contains(&fakeIndex));
EXPECT_EQ(0, chainActive.Height());
// Simulate SyncTransaction which calls AddToWalletIfInvolvingMe
auto saplingNoteData = wallet.FindMySaplingNotes(wtx).first;
ASSERT_TRUE(saplingNoteData.size() > 0);
wtx.SetSaplingNoteData(saplingNoteData);
wtx.SetMerkleBranch(block);
wallet.AddToWallet(wtx, true, NULL);
// Simulate receiving new block and ChainTip signal
wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
// Retrieve the updated wtx from wallet
uint256 hash = wtx.GetHash();
wtx = wallet.mapWallet[hash];
// Prepare to spend the note that was just created
auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt(
tx1.vShieldedOutput[0].encCiphertext, ivk, tx1.vShieldedOutput[0].ephemeralKey, tx1.vShieldedOutput[0].cm);
ASSERT_EQ(static_cast<bool>(maybe_pt), true);
auto maybe_note = maybe_pt.get().note(ivk);
ASSERT_EQ(static_cast<bool>(maybe_note), true);
auto note = maybe_note.get();
auto anchor = saplingTree.root();
auto witness = saplingTree.witness();
// Create a Sapling-only transaction
// 0.0004 z-ZEC in, 0.00025 z-ZEC out, 0.0001 t-ZEC fee, 0.00005 z-ZEC change
auto builder2 = TransactionBuilder(consensusParams, 2);
ASSERT_TRUE(builder2.AddSaplingSpend(expsk, note, anchor, witness));
builder2.AddSaplingOutput(fvk.ovk, pk, 25000, {});
auto maybe_tx2 = builder2.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx2), true);
auto tx2 = maybe_tx2.get();
EXPECT_EQ(tx2.vin.size(), 0);
EXPECT_EQ(tx2.vout.size(), 0);
EXPECT_EQ(tx2.vjoinsplit.size(), 0);
EXPECT_EQ(tx2.vShieldedSpend.size(), 1);
EXPECT_EQ(tx2.vShieldedOutput.size(), 2);
EXPECT_EQ(tx2.valueBalance, 10000);
CWalletTx wtx2 {&wallet, tx2};
auto hash2 = wtx2.GetHash();
wallet.MarkAffectedTransactionsDirty(wtx);
// After getting a cached value, the first tx should be clean
wallet.mapWallet[hash].GetDebit(ISMINE_ALL);
EXPECT_TRUE(wallet.mapWallet[hash].fDebitCached);
// After adding the note spend, the first tx should be dirty
wallet.AddToWallet(wtx2, true, NULL);
wallet.MarkAffectedTransactionsDirty(wtx2);
EXPECT_FALSE(wallet.mapWallet[hash].fDebitCached);
// Tear down
chainActive.SetTip(NULL);
mapBlockIndex.erase(blockHash);
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
TEST(WalletTests, SproutNoteLocking) {
TestWallet wallet;
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSproutSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
auto wtx2 = GetValidReceive(sk, 10, true);
JSOutPoint jsoutpt {wtx.GetHash(), 0, 0};
JSOutPoint jsoutpt2 {wtx2.GetHash(),0, 0};
// Test selective locking
wallet.LockNote(jsoutpt);
6 years ago
EXPECT_TRUE(wallet.IsLockedNote(jsoutpt));
EXPECT_FALSE(wallet.IsLockedNote(jsoutpt2));
// Test selective unlocking
wallet.UnlockNote(jsoutpt);
6 years ago
EXPECT_FALSE(wallet.IsLockedNote(jsoutpt));
// Test multiple locking
wallet.LockNote(jsoutpt);
wallet.LockNote(jsoutpt2);
6 years ago
EXPECT_TRUE(wallet.IsLockedNote(jsoutpt));
EXPECT_TRUE(wallet.IsLockedNote(jsoutpt2));
// Test unlock all
wallet.UnlockAllSproutNotes();
EXPECT_FALSE(wallet.IsLockedNote(jsoutpt));
EXPECT_FALSE(wallet.IsLockedNote(jsoutpt2));
}
TEST(WalletTests, SaplingNoteLocking) {
TestWallet wallet;
SaplingOutPoint sop1 {uint256(), 1};
SaplingOutPoint sop2 {uint256(), 2};
// Test selective locking
wallet.LockNote(sop1);
EXPECT_TRUE(wallet.IsLockedNote(sop1));
EXPECT_FALSE(wallet.IsLockedNote(sop2));
// Test selective unlocking
wallet.UnlockNote(sop1);
EXPECT_FALSE(wallet.IsLockedNote(sop1));
// Test multiple locking
wallet.LockNote(sop1);
wallet.LockNote(sop2);
EXPECT_TRUE(wallet.IsLockedNote(sop1));
EXPECT_TRUE(wallet.IsLockedNote(sop2));
// Test list
auto v = wallet.ListLockedSaplingNotes();
EXPECT_EQ(v.size(), 2);
EXPECT_TRUE(std::find(v.begin(), v.end(), sop1) != v.end());
EXPECT_TRUE(std::find(v.begin(), v.end(), sop2) != v.end());
// Test unlock all
6 years ago
wallet.UnlockAllSaplingNotes();
EXPECT_FALSE(wallet.IsLockedNote(sop1));
EXPECT_FALSE(wallet.IsLockedNote(sop2));
}