Auto merge of #3711 - str4d:wallet-atomic-write-optimisation, r=Eirik0

wallet: Skip transactions with no shielded data in CWallet::SetBestChain()

Co-authored-by: Daira Hopwood <daira@jacaranda.org>

Closes #3495.
This commit is contained in:
Homu 2019-01-21 13:16:00 -08:00
commit 08dc0904fb
2 changed files with 101 additions and 4 deletions

View File

@ -1559,6 +1559,14 @@ TEST(WalletTests, WriteWitnessCache) {
wallet.AddSproutSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
mapSproutNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
SproutNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
wtx.SetSproutNoteData(noteData);
wallet.AddToWallet(wtx, true, NULL);
// TxnBegin fails
@ -1627,6 +1635,88 @@ TEST(WalletTests, WriteWitnessCache) {
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, nullptr);
// 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, nullptr);
// 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 {nullptr, mtx};
wallet.AddToWallet(wtxSproutTransparent, true, nullptr);
// Generate a fake Sapling transaction
CMutableTransaction mtxSapling;
mtxSapling.fOverwintered = true;
mtxSapling.nVersion = SAPLING_TX_VERSION;
mtxSapling.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
mtxSapling.vShieldedOutput.resize(1);
mtxSapling.vShieldedOutput[0].cv = libzcash::random_uint256();
CWalletTx wtxSapling {nullptr, mtxSapling};
SetSaplingNoteData(wtxSapling);
wallet.AddToWallet(wtxSapling, true, nullptr);
// Generate a fake Sapling transaction that would only involve our transparent addresses
CMutableTransaction mtxSaplingTransparent;
mtxSaplingTransparent.fOverwintered = true;
mtxSaplingTransparent.nVersion = SAPLING_TX_VERSION;
mtxSaplingTransparent.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
mtxSaplingTransparent.vShieldedOutput.resize(1);
mtxSaplingTransparent.vShieldedOutput[0].cv = libzcash::random_uint256();
CWalletTx wtxSaplingTransparent {nullptr, mtxSaplingTransparent};
wallet.AddToWallet(wtxSaplingTransparent, true, nullptr);
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, WriteTx(wtxSapling.GetHash(), wtxSapling))
.Times(1).WillOnce(Return(true));
EXPECT_CALL(walletdb, WriteTx(wtxSaplingTransparent.GetHash(), wtxSaplingTransparent))
.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);
}
TEST(WalletTests, UpdateSproutNullifierNoteMap) {
TestWallet wallet;
uint256 r {GetRandHash()};

View File

@ -790,10 +790,17 @@ protected:
}
try {
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
if (!walletdb.WriteTx(wtxItem.first, wtxItem.second)) {
LogPrintf("SetBestChain(): Failed to write CWalletTx, aborting atomic write\n");
walletdb.TxnAbort();
return;
auto wtx = wtxItem.second;
// We skip transactions for which mapSproutNoteData and mapSaplingNoteData
// are empty. This covers transactions that have no Sprout or Sapling data
// (i.e. are purely transparent), as well as shielding and unshielding
// transactions in which we only have transparent addresses involved.
if (!(wtx.mapSproutNoteData.empty() && wtx.mapSaplingNoteData.empty())) {
if (!walletdb.WriteTx(wtxItem.first, wtx)) {
LogPrintf("SetBestChain(): Failed to write CWalletTx, aborting atomic write\n");
walletdb.TxnAbort();
return;
}
}
}
if (!walletdb.WriteWitnessCacheSize(nWitnessCacheSize)) {