Merge remote-tracking branch 'zcash/master' into dev
# Conflicts: # .gitignore # README.md # src/Makefile.gtest.include # src/gtest/test_checkblock.cpp # src/init.cpp # src/main.cpp # src/main.h # src/rpcserver.cpp # src/test/checkblock_tests.cpp # src/util.cpp
This commit is contained in:
@@ -53,8 +53,9 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
|
||||
std::vector<SendManyRecipient> tOutputs,
|
||||
std::vector<SendManyRecipient> zOutputs,
|
||||
int minDepth,
|
||||
CAmount fee) :
|
||||
fromaddress_(fromAddress), t_outputs_(tOutputs), z_outputs_(zOutputs), mindepth_(minDepth), fee_(fee)
|
||||
CAmount fee,
|
||||
Value contextInfo) :
|
||||
fromaddress_(fromAddress), t_outputs_(tOutputs), z_outputs_(zOutputs), mindepth_(minDepth), fee_(fee), contextinfo_(contextInfo)
|
||||
{
|
||||
assert(fee_ > 0);
|
||||
|
||||
@@ -88,7 +89,7 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
|
||||
isfromzaddr_ = true;
|
||||
frompaymentaddress_ = addr;
|
||||
spendingkey_ = key;
|
||||
} catch (std::runtime_error e) {
|
||||
} catch (const std::runtime_error& e) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("runtime error: ") + e.what());
|
||||
}
|
||||
}
|
||||
@@ -108,17 +109,20 @@ void AsyncRPCOperation_sendmany::main() {
|
||||
|
||||
try {
|
||||
success = main_impl();
|
||||
} catch (Object objError) {
|
||||
} catch (const Object& objError) {
|
||||
int code = find_value(objError, "code").get_int();
|
||||
std::string message = find_value(objError, "message").get_str();
|
||||
set_error_code(code);
|
||||
set_error_message(message);
|
||||
} catch (runtime_error e) {
|
||||
} catch (const runtime_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("runtime error: " + string(e.what()));
|
||||
} catch (logic_error e) {
|
||||
} catch (const logic_error& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("logic error: " + string(e.what()));
|
||||
} catch (const exception& e) {
|
||||
set_error_code(-1);
|
||||
set_error_message("general exception: " + string(e.what()));
|
||||
} catch (...) {
|
||||
set_error_code(-2);
|
||||
set_error_message("unknown error");
|
||||
@@ -450,13 +454,22 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
info.notes.push_back(note);
|
||||
outPoints.push_back(outPoint);
|
||||
|
||||
|
||||
LogPrint("zrpc", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s)\n",
|
||||
int wtxHeight = -1;
|
||||
int wtxDepth = -1;
|
||||
{
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
const CWalletTx& wtx = pwalletMain->mapWallet[outPoint.hash];
|
||||
wtxHeight = mapBlockIndex[wtx.hashBlock]->nHeight;
|
||||
wtxDepth = wtx.GetDepthInMainChain();
|
||||
}
|
||||
LogPrint("zrpc", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n",
|
||||
getId().substr(0, 10),
|
||||
outPoint.hash.ToString().substr(0, 10),
|
||||
outPoint.js,
|
||||
int(outPoint.n), // uint8_t
|
||||
FormatMoney(noteFunds, false)
|
||||
FormatMoney(noteFunds, false),
|
||||
wtxHeight,
|
||||
wtxDepth
|
||||
);
|
||||
|
||||
|
||||
@@ -579,7 +592,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
FormatMoney(plaintext.value, false)
|
||||
);
|
||||
|
||||
} catch (const std::exception e) {
|
||||
} catch (const std::exception& e) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Error decrypting output note of previous JoinSplit: %s", e.what()));
|
||||
}
|
||||
}
|
||||
@@ -613,12 +626,22 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
|
||||
jsInputValue += noteFunds;
|
||||
|
||||
LogPrint("zrpc", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s)\n",
|
||||
int wtxHeight = -1;
|
||||
int wtxDepth = -1;
|
||||
{
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
const CWalletTx& wtx = pwalletMain->mapWallet[jso.hash];
|
||||
wtxHeight = mapBlockIndex[wtx.hashBlock]->nHeight;
|
||||
wtxDepth = wtx.GetDepthInMainChain();
|
||||
}
|
||||
LogPrint("zrpc", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n",
|
||||
getId().substr(0, 10),
|
||||
jso.hash.ToString().substr(0, 10),
|
||||
jso.js,
|
||||
int(jso.n), // uint8_t
|
||||
FormatMoney(noteFunds, false)
|
||||
FormatMoney(noteFunds, false),
|
||||
wtxHeight,
|
||||
wtxDepth
|
||||
);
|
||||
}
|
||||
|
||||
@@ -778,6 +801,12 @@ void AsyncRPCOperation_sendmany::sign_send_raw_transaction(Object obj)
|
||||
o.push_back(Pair("hex", signedtxn));
|
||||
set_result(Value(o));
|
||||
}
|
||||
|
||||
// Keep the signed transaction so we can hash to the same txid
|
||||
CDataStream stream(ParseHex(signedtxn), SER_NETWORK, PROTOCOL_VERSION);
|
||||
CTransaction tx;
|
||||
stream >> tx;
|
||||
tx_ = tx;
|
||||
}
|
||||
|
||||
|
||||
@@ -1096,4 +1125,18 @@ boost::array<unsigned char, ZC_MEMO_SIZE> AsyncRPCOperation_sendmany::get_memo_f
|
||||
return memo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override getStatus() to append the operation's input parameters to the default status object.
|
||||
*/
|
||||
Value AsyncRPCOperation_sendmany::getStatus() const {
|
||||
Value v = AsyncRPCOperation::getStatus();
|
||||
if (contextinfo_.is_null()) {
|
||||
return v;
|
||||
}
|
||||
|
||||
Object obj = v.get_obj();
|
||||
obj.push_back(Pair("method", "z_sendmany"));
|
||||
obj.push_back(Pair("params", contextinfo_ ));
|
||||
return Value(obj);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ struct WitnessAnchorData {
|
||||
|
||||
class AsyncRPCOperation_sendmany : public AsyncRPCOperation {
|
||||
public:
|
||||
AsyncRPCOperation_sendmany(std::string fromAddress, std::vector<SendManyRecipient> tOutputs, std::vector<SendManyRecipient> zOutputs, int minDepth, CAmount fee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE);
|
||||
AsyncRPCOperation_sendmany(std::string fromAddress, std::vector<SendManyRecipient> tOutputs, std::vector<SendManyRecipient> zOutputs, int minDepth, CAmount fee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE, Value contextInfo = Value::null);
|
||||
virtual ~AsyncRPCOperation_sendmany();
|
||||
|
||||
// We don't want to be copied or moved around
|
||||
@@ -61,11 +61,15 @@ public:
|
||||
|
||||
virtual void main();
|
||||
|
||||
virtual Value getStatus() const;
|
||||
|
||||
bool testmode = false; // Set to true to disable sending txs and generating proofs
|
||||
|
||||
private:
|
||||
friend class TEST_FRIEND_AsyncRPCOperation_sendmany; // class for unit testing
|
||||
|
||||
Value contextinfo_; // optional data to include in return value from getStatus()
|
||||
|
||||
CAmount fee_;
|
||||
int mindepth_;
|
||||
std::string fromaddress_;
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
|
||||
void IncrementNoteWitnesses(const CBlockIndex* pindex,
|
||||
const CBlock* pblock,
|
||||
ZCIncrementalMerkleTree tree) {
|
||||
ZCIncrementalMerkleTree& tree) {
|
||||
CWallet::IncrementNoteWitnesses(pindex, pblock, tree);
|
||||
}
|
||||
void DecrementNoteWitnesses(const CBlockIndex* pindex) {
|
||||
@@ -82,6 +82,28 @@ CWalletTx GetValidSpend(const libzcash::SpendingKey& sk,
|
||||
return GetValidSpend(*params, sk, note, value);
|
||||
}
|
||||
|
||||
JSOutPoint CreateValidBlock(TestWallet& wallet,
|
||||
const libzcash::SpendingKey& sk,
|
||||
const CBlockIndex& index,
|
||||
CBlock& block,
|
||||
ZCIncrementalMerkleTree& tree) {
|
||||
auto wtx = GetValidReceive(sk, 50, true);
|
||||
auto note = GetNote(sk, wtx, 0, 1);
|
||||
auto nullifier = note.nullifier(sk);
|
||||
|
||||
mapNoteData_t noteData;
|
||||
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
|
||||
CNoteData nd {sk.address(), nullifier};
|
||||
noteData[jsoutpt] = nd;
|
||||
wtx.SetNoteData(noteData);
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
|
||||
block.vtx.push_back(wtx);
|
||||
wallet.IncrementNoteWitnesses(&index, &block, tree);
|
||||
|
||||
return jsoutpt;
|
||||
}
|
||||
|
||||
TEST(wallet_tests, setup_datadir_location_run_as_first_test) {
|
||||
// Get temporary and unique path for file.
|
||||
boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
@@ -572,27 +594,14 @@ TEST(wallet_tests, cached_witnesses_chain_tip) {
|
||||
wallet.AddSpendingKey(sk);
|
||||
|
||||
{
|
||||
// First transaction (case tested in _empty_chain)
|
||||
auto wtx = GetValidReceive(sk, 10, true);
|
||||
auto note = GetNote(sk, wtx, 0, 1);
|
||||
auto nullifier = note.nullifier(sk);
|
||||
|
||||
mapNoteData_t noteData;
|
||||
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
|
||||
CNoteData nd {sk.address(), nullifier};
|
||||
noteData[jsoutpt] = nd;
|
||||
wtx.SetNoteData(noteData);
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
|
||||
std::vector<JSOutPoint> notes {jsoutpt};
|
||||
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
|
||||
|
||||
// First block (case tested in _empty_chain)
|
||||
block1.vtx.push_back(wtx);
|
||||
CBlockIndex index1(block1);
|
||||
index1.nHeight = 1;
|
||||
wallet.IncrementNoteWitnesses(&index1, &block1, tree);
|
||||
auto jsoutpt = CreateValidBlock(wallet, sk, index1, block1, tree);
|
||||
|
||||
// Called to fetch anchor
|
||||
std::vector<JSOutPoint> notes {jsoutpt};
|
||||
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor1);
|
||||
}
|
||||
|
||||
@@ -667,47 +676,21 @@ TEST(wallet_tests, CachedWitnessesDecrementFirst) {
|
||||
wallet.AddSpendingKey(sk);
|
||||
|
||||
{
|
||||
// First transaction (case tested in _empty_chain)
|
||||
auto wtx = GetValidReceive(sk, 10, true);
|
||||
auto note = GetNote(sk, wtx, 0, 1);
|
||||
auto nullifier = note.nullifier(sk);
|
||||
|
||||
mapNoteData_t noteData;
|
||||
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
|
||||
CNoteData nd {sk.address(), nullifier};
|
||||
noteData[jsoutpt] = nd;
|
||||
wtx.SetNoteData(noteData);
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
|
||||
// First block (case tested in _empty_chain)
|
||||
CBlock block1;
|
||||
block1.vtx.push_back(wtx);
|
||||
CBlockIndex index1(block1);
|
||||
index1.nHeight = 1;
|
||||
wallet.IncrementNoteWitnesses(&index1, &block1, tree);
|
||||
CreateValidBlock(wallet, sk, index1, block1, tree);
|
||||
}
|
||||
|
||||
{
|
||||
// Second transaction (case tested in _chain_tip)
|
||||
auto wtx = GetValidReceive(sk, 50, true);
|
||||
auto note = GetNote(sk, wtx, 0, 1);
|
||||
auto nullifier = note.nullifier(sk);
|
||||
|
||||
mapNoteData_t noteData;
|
||||
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
|
||||
CNoteData nd {sk.address(), nullifier};
|
||||
noteData[jsoutpt] = nd;
|
||||
wtx.SetNoteData(noteData);
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
// Second block (case tested in _chain_tip)
|
||||
index2.nHeight = 2;
|
||||
auto jsoutpt = CreateValidBlock(wallet, sk, index2, block2, tree);
|
||||
|
||||
// Called to fetch anchor
|
||||
std::vector<JSOutPoint> notes {jsoutpt};
|
||||
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
|
||||
|
||||
// Second block (case tested in _chain_tip)
|
||||
block2.vtx.push_back(wtx);
|
||||
index2.nHeight = 2;
|
||||
wallet.IncrementNoteWitnesses(&index2, &block2, tree);
|
||||
// Called to fetch anchor
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor2);
|
||||
}
|
||||
|
||||
@@ -753,116 +736,77 @@ TEST(wallet_tests, CachedWitnessesDecrementFirst) {
|
||||
|
||||
TEST(wallet_tests, CachedWitnessesCleanIndex) {
|
||||
TestWallet wallet;
|
||||
CBlock block1;
|
||||
CBlock block2;
|
||||
CBlock block3;
|
||||
CBlockIndex index1(block1);
|
||||
CBlockIndex index2(block2);
|
||||
CBlockIndex index3(block3);
|
||||
std::vector<CBlock> blocks;
|
||||
std::vector<CBlockIndex> indices;
|
||||
std::vector<JSOutPoint> notes;
|
||||
std::vector<uint256> anchors;
|
||||
ZCIncrementalMerkleTree tree;
|
||||
ZCIncrementalMerkleTree riTree = tree;
|
||||
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
|
||||
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
wallet.AddSpendingKey(sk);
|
||||
|
||||
{
|
||||
// First transaction (case tested in _empty_chain)
|
||||
auto wtx = GetValidReceive(sk, 10, true);
|
||||
auto note = GetNote(sk, wtx, 0, 1);
|
||||
auto nullifier = note.nullifier(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++) {
|
||||
indices[i].nHeight = i;
|
||||
auto old = tree.root();
|
||||
auto jsoutpt = CreateValidBlock(wallet, sk, indices[i], blocks[i], tree);
|
||||
EXPECT_NE(old, tree.root());
|
||||
notes.push_back(jsoutpt);
|
||||
|
||||
mapNoteData_t noteData;
|
||||
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
|
||||
CNoteData nd {sk.address(), nullifier};
|
||||
noteData[jsoutpt] = nd;
|
||||
wtx.SetNoteData(noteData);
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
|
||||
// First block (case tested in _empty_chain)
|
||||
block1.vtx.push_back(wtx);
|
||||
index1.nHeight = 1;
|
||||
wallet.IncrementNoteWitnesses(&index1, &block1, tree);
|
||||
witnesses.clear();
|
||||
uint256 anchor;
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor);
|
||||
for (size_t j = 0; j <= i; j++) {
|
||||
EXPECT_TRUE((bool) witnesses[j]);
|
||||
}
|
||||
anchors.push_back(anchor);
|
||||
}
|
||||
|
||||
{
|
||||
// Second transaction (case tested in _chain_tip)
|
||||
auto wtx = GetValidReceive(sk, 50, true);
|
||||
auto note = GetNote(sk, wtx, 0, 1);
|
||||
auto nullifier = note.nullifier(sk);
|
||||
|
||||
mapNoteData_t noteData;
|
||||
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
|
||||
CNoteData nd {sk.address(), nullifier};
|
||||
noteData[jsoutpt] = nd;
|
||||
wtx.SetNoteData(noteData);
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
|
||||
// Second block (case tested in _chain_tip)
|
||||
block2.vtx.push_back(wtx);
|
||||
index2.nHeight = 2;
|
||||
wallet.IncrementNoteWitnesses(&index2, &block2, tree);
|
||||
}
|
||||
|
||||
{
|
||||
// Third transaction
|
||||
auto wtx = GetValidReceive(sk, 20, true);
|
||||
auto note = GetNote(sk, wtx, 0, 1);
|
||||
auto nullifier = note.nullifier(sk);
|
||||
|
||||
mapNoteData_t noteData;
|
||||
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
|
||||
CNoteData nd {sk.address(), nullifier};
|
||||
noteData[jsoutpt] = nd;
|
||||
wtx.SetNoteData(noteData);
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
|
||||
std::vector<JSOutPoint> notes {jsoutpt};
|
||||
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
|
||||
uint256 anchor3;
|
||||
|
||||
// Third block
|
||||
block3.vtx.push_back(wtx);
|
||||
index3.nHeight = 3;
|
||||
wallet.IncrementNoteWitnesses(&index3, &block3, tree);
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor3);
|
||||
|
||||
// Now pretend we are reindexing: the chain is cleared, and each block is
|
||||
// used to increment witnesses again.
|
||||
wallet.IncrementNoteWitnesses(&index1, &block1, tree);
|
||||
uint256 anchor3a;
|
||||
// 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++) {
|
||||
ZCIncrementalMerkleTree riPrevTree {riTree};
|
||||
wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), riTree);
|
||||
witnesses.clear();
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor3a);
|
||||
EXPECT_TRUE((bool) witnesses[0]);
|
||||
// Should equal third anchor because witness cache unaffected
|
||||
EXPECT_EQ(anchor3, anchor3a);
|
||||
uint256 anchor;
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor);
|
||||
for (size_t j = 0; j < numBlocks; j++) {
|
||||
EXPECT_TRUE((bool) witnesses[j]);
|
||||
}
|
||||
// Should equal final anchor because witness cache unaffected
|
||||
EXPECT_EQ(anchors.back(), anchor);
|
||||
|
||||
wallet.IncrementNoteWitnesses(&index2, &block2, tree);
|
||||
uint256 anchor3b;
|
||||
witnesses.clear();
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor3b);
|
||||
EXPECT_TRUE((bool) witnesses[0]);
|
||||
EXPECT_EQ(anchor3, anchor3b);
|
||||
if ((i == 5) || (i == 50)) {
|
||||
// Pretend a reorg happened that was recorded in the block files
|
||||
{
|
||||
wallet.DecrementNoteWitnesses(&(indices[i]));
|
||||
witnesses.clear();
|
||||
uint256 anchor;
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor);
|
||||
for (size_t j = 0; j < numBlocks; j++) {
|
||||
EXPECT_TRUE((bool) witnesses[j]);
|
||||
}
|
||||
// Should equal final anchor because witness cache unaffected
|
||||
EXPECT_EQ(anchors.back(), anchor);
|
||||
}
|
||||
|
||||
// Pretend a reorg happened that was recorded in the block files
|
||||
wallet.DecrementNoteWitnesses(&index2);
|
||||
uint256 anchor3c;
|
||||
witnesses.clear();
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor3c);
|
||||
EXPECT_TRUE((bool) witnesses[0]);
|
||||
EXPECT_EQ(anchor3, anchor3c);
|
||||
|
||||
wallet.IncrementNoteWitnesses(&index2, &block2, tree);
|
||||
uint256 anchor3d;
|
||||
witnesses.clear();
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor3d);
|
||||
EXPECT_TRUE((bool) witnesses[0]);
|
||||
EXPECT_EQ(anchor3, anchor3d);
|
||||
|
||||
wallet.IncrementNoteWitnesses(&index3, &block3, tree);
|
||||
uint256 anchor3e;
|
||||
witnesses.clear();
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor3e);
|
||||
EXPECT_TRUE((bool) witnesses[0]);
|
||||
EXPECT_EQ(anchor3, anchor3e);
|
||||
{
|
||||
wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), riPrevTree);
|
||||
witnesses.clear();
|
||||
uint256 anchor;
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor);
|
||||
for (size_t j = 0; j < numBlocks; j++) {
|
||||
EXPECT_TRUE((bool) witnesses[j]);
|
||||
}
|
||||
// Should equal final anchor because witness cache unaffected
|
||||
EXPECT_EQ(anchors.back(), anchor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
218
src/wallet/gtest/test_wallet_zkeys.cpp
Normal file
218
src/wallet/gtest/test_wallet_zkeys.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "zcash/Address.hpp"
|
||||
#include "wallet/wallet.h"
|
||||
#include "wallet/walletdb.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
/**
|
||||
* This test covers methods on CWallet
|
||||
* GenerateNewZKey()
|
||||
* AddZKey()
|
||||
* LoadZKey()
|
||||
* LoadZKeyMetadata()
|
||||
*/
|
||||
TEST(wallet_zkeys_tests, store_and_load_zkeys) {
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
|
||||
CWallet wallet;
|
||||
|
||||
// wallet should be empty
|
||||
std::set<libzcash::PaymentAddress> addrs;
|
||||
wallet.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(0, addrs.size());
|
||||
|
||||
// wallet should have one key
|
||||
CZCPaymentAddress paymentAddress = wallet.GenerateNewZKey();
|
||||
wallet.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(1, addrs.size());
|
||||
|
||||
// verify wallet has spending key for the address
|
||||
auto addr = paymentAddress.Get();
|
||||
ASSERT_TRUE(wallet.HaveSpendingKey(addr));
|
||||
|
||||
// manually add new spending key to wallet
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
ASSERT_TRUE(wallet.AddZKey(sk));
|
||||
|
||||
// verify wallet did add it
|
||||
addr = sk.address();
|
||||
ASSERT_TRUE(wallet.HaveSpendingKey(addr));
|
||||
|
||||
// verify spending key stored correctly
|
||||
libzcash::SpendingKey keyOut;
|
||||
wallet.GetSpendingKey(addr, keyOut);
|
||||
ASSERT_EQ(sk, keyOut);
|
||||
|
||||
// verify there are two keys
|
||||
wallet.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(2, addrs.size());
|
||||
ASSERT_EQ(1, addrs.count(addr));
|
||||
|
||||
// Load a third key into the wallet
|
||||
sk = libzcash::SpendingKey::random();
|
||||
ASSERT_TRUE(wallet.LoadZKey(sk));
|
||||
|
||||
// attach metadata to this third key
|
||||
addr = sk.address();
|
||||
int64_t now = GetTime();
|
||||
CKeyMetadata meta(now);
|
||||
ASSERT_TRUE(wallet.LoadZKeyMetadata(addr, meta));
|
||||
|
||||
// check metadata is the same
|
||||
CKeyMetadata m= wallet.mapZKeyMetadata[addr];
|
||||
ASSERT_EQ(m.nCreateTime, now);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test covers methods on CWalletDB
|
||||
* WriteZKey()
|
||||
*/
|
||||
TEST(wallet_zkeys_tests, write_zkey_direct_to_db) {
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
|
||||
// Get temporary and unique path for file.
|
||||
// Note: / operator to append paths
|
||||
boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
boost::filesystem::create_directories(pathTemp);
|
||||
mapArgs["-datadir"] = pathTemp.string();
|
||||
|
||||
bool fFirstRun;
|
||||
CWallet wallet("wallet.dat");
|
||||
ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun));
|
||||
|
||||
// No default CPubKey set
|
||||
ASSERT_TRUE(fFirstRun);
|
||||
|
||||
// wallet should be empty
|
||||
std::set<libzcash::PaymentAddress> addrs;
|
||||
wallet.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(0, addrs.size());
|
||||
|
||||
// Add random key to the wallet
|
||||
auto paymentAddress = wallet.GenerateNewZKey();
|
||||
|
||||
// wallet should have one key
|
||||
wallet.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(1, addrs.size());
|
||||
|
||||
// create random key and add it to database directly, bypassing wallet
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
auto addr = sk.address();
|
||||
int64_t now = GetTime();
|
||||
CKeyMetadata meta(now);
|
||||
CWalletDB db("wallet.dat");
|
||||
db.WriteZKey(addr, sk, meta);
|
||||
|
||||
// wallet should not be aware of key
|
||||
ASSERT_FALSE(wallet.HaveSpendingKey(addr));
|
||||
|
||||
// wallet sees one key
|
||||
wallet.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(1, addrs.size());
|
||||
|
||||
// wallet should have default metadata for addr with null createtime
|
||||
CKeyMetadata m = wallet.mapZKeyMetadata[addr];
|
||||
ASSERT_EQ(m.nCreateTime, 0);
|
||||
ASSERT_NE(m.nCreateTime, now);
|
||||
|
||||
// load the wallet again
|
||||
ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun));
|
||||
|
||||
// wallet can now see the spending key
|
||||
ASSERT_TRUE(wallet.HaveSpendingKey(addr));
|
||||
|
||||
// check key is the same
|
||||
libzcash::SpendingKey keyOut;
|
||||
wallet.GetSpendingKey(addr, keyOut);
|
||||
ASSERT_EQ(sk, keyOut);
|
||||
|
||||
// wallet should have two keys
|
||||
wallet.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(2, addrs.size());
|
||||
|
||||
// check metadata is now the same
|
||||
m = wallet.mapZKeyMetadata[addr];
|
||||
ASSERT_EQ(m.nCreateTime, now);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This test covers methods on CWalletDB to load/save crypted z keys.
|
||||
*/
|
||||
TEST(wallet_zkeys_tests, write_cryptedzkey_direct_to_db) {
|
||||
ECC_Start();
|
||||
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
|
||||
// Get temporary and unique path for file.
|
||||
// Note: / operator to append paths
|
||||
boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
boost::filesystem::create_directories(pathTemp);
|
||||
mapArgs["-datadir"] = pathTemp.string();
|
||||
|
||||
bool fFirstRun;
|
||||
CWallet wallet("wallet_crypted.dat");
|
||||
ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun));
|
||||
|
||||
// No default CPubKey set
|
||||
ASSERT_TRUE(fFirstRun);
|
||||
|
||||
// wallet should be empty
|
||||
std::set<libzcash::PaymentAddress> addrs;
|
||||
wallet.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(0, addrs.size());
|
||||
|
||||
// Add random key to the wallet
|
||||
auto paymentAddress = wallet.GenerateNewZKey();
|
||||
|
||||
// wallet should have one key
|
||||
wallet.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(1, addrs.size());
|
||||
|
||||
// encrypt wallet
|
||||
SecureString strWalletPass;
|
||||
strWalletPass.reserve(100);
|
||||
strWalletPass = "hello";
|
||||
ASSERT_TRUE(wallet.EncryptWallet(strWalletPass));
|
||||
|
||||
// adding a new key will fail as the wallet is locked
|
||||
EXPECT_ANY_THROW(wallet.GenerateNewZKey());
|
||||
|
||||
// unlock wallet and then add
|
||||
wallet.Unlock(strWalletPass);
|
||||
auto paymentAddress2 = wallet.GenerateNewZKey();
|
||||
|
||||
// Create a new wallet from the existing wallet path
|
||||
CWallet wallet2("wallet_crypted.dat");
|
||||
ASSERT_EQ(DB_LOAD_OK, wallet2.LoadWallet(fFirstRun));
|
||||
|
||||
// Confirm it's not the same as the other wallet
|
||||
ASSERT_TRUE(&wallet != &wallet2);
|
||||
|
||||
// wallet should have two keys
|
||||
wallet2.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(2, addrs.size());
|
||||
|
||||
// check we have entries for our payment addresses
|
||||
ASSERT_TRUE(addrs.count(paymentAddress.Get()));
|
||||
ASSERT_TRUE(addrs.count(paymentAddress2.Get()));
|
||||
|
||||
// spending key is crypted, so we can't extract valid payment address
|
||||
libzcash::SpendingKey keyOut;
|
||||
wallet2.GetSpendingKey(paymentAddress.Get(), keyOut);
|
||||
ASSERT_FALSE(paymentAddress.Get() == keyOut.address());
|
||||
|
||||
// unlock wallet to get spending keys and verify payment addresses
|
||||
wallet2.Unlock(strWalletPass);
|
||||
|
||||
wallet2.GetSpendingKey(paymentAddress.Get(), keyOut);
|
||||
ASSERT_EQ(paymentAddress.Get(), keyOut.address());
|
||||
|
||||
wallet2.GetSpendingKey(paymentAddress2.Get(), keyOut);
|
||||
ASSERT_EQ(paymentAddress2.Get(), keyOut.address());
|
||||
}
|
||||
|
||||
@@ -430,7 +430,9 @@ Value z_exportwallet(const Array& params, bool fHelp)
|
||||
"z_exportwallet \"filename\"\n"
|
||||
"\nExports all wallet keys, for taddr and zaddr, in a human-readable format.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"filename\" (string, required) The filename\n"
|
||||
"1. \"filename\" (string, required) The filename, saved in folder set by zcashd -exportdir option\n"
|
||||
"\nResult:\n"
|
||||
"\"path\" (string) The full path of the destination file\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("z_exportwallet", "\"test\"")
|
||||
+ HelpExampleRpc("z_exportwallet", "\"test\"")
|
||||
@@ -449,7 +451,9 @@ Value dumpwallet(const Array& params, bool fHelp)
|
||||
"dumpwallet \"filename\"\n"
|
||||
"\nDumps taddr wallet keys in a human-readable format.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"filename\" (string, required) The filename\n"
|
||||
"1. \"filename\" (string, required) The filename, saved in folder set by zcashd -exportdir option\n"
|
||||
"\nResult:\n"
|
||||
"\"path\" (string) The full path of the destination file\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("dumpwallet", "\"test\"")
|
||||
+ HelpExampleRpc("dumpwallet", "\"test\"")
|
||||
@@ -464,8 +468,24 @@ Value dumpwallet_impl(const Array& params, bool fHelp, bool fDumpZKeys)
|
||||
|
||||
EnsureWalletIsUnlocked();
|
||||
|
||||
boost::filesystem::path exportdir;
|
||||
try {
|
||||
exportdir = GetExportDir();
|
||||
} catch (const std::runtime_error& e) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
|
||||
}
|
||||
if (exportdir.empty()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot export wallet until the zcashd -exportdir option has been set");
|
||||
}
|
||||
std::string unclean = params[0].get_str();
|
||||
std::string clean = SanitizeFilename(unclean);
|
||||
if (clean.compare(unclean) != 0) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
|
||||
}
|
||||
boost::filesystem::path exportfilepath = exportdir / clean;
|
||||
|
||||
ofstream file;
|
||||
file.open(params[0].get_str().c_str());
|
||||
file.open(exportfilepath.string().c_str());
|
||||
if (!file.is_open())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
|
||||
|
||||
@@ -523,7 +543,8 @@ Value dumpwallet_impl(const Array& params, bool fHelp, bool fDumpZKeys)
|
||||
|
||||
file << "# End of dump\n";
|
||||
file.close();
|
||||
return Value::null;
|
||||
|
||||
return exportfilepath.string();
|
||||
}
|
||||
|
||||
|
||||
@@ -575,6 +596,9 @@ Value z_importkey(const Array& params, bool fHelp)
|
||||
|
||||
pwalletMain->mapZKeyMetadata[addr].nCreateTime = 1;
|
||||
|
||||
// whenever a key is imported, we need to scan the whole chain
|
||||
pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
|
||||
|
||||
// We want to scan for transactions and notes
|
||||
if (fRescan) {
|
||||
pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#include "json/json_spirit_value.h"
|
||||
#include "asyncrpcqueue.h"
|
||||
|
||||
#include <numeric>
|
||||
|
||||
using namespace std;
|
||||
using namespace json_spirit;
|
||||
|
||||
@@ -1557,6 +1559,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
|
||||
entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
|
||||
if (fLong)
|
||||
WalletTxToJSON(wtx, entry);
|
||||
entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
|
||||
ret.push_back(entry);
|
||||
}
|
||||
}
|
||||
@@ -1593,6 +1596,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
|
||||
entry.push_back(Pair("vout", r.vout));
|
||||
if (fLong)
|
||||
WalletTxToJSON(wtx, entry);
|
||||
entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
|
||||
ret.push_back(entry);
|
||||
}
|
||||
}
|
||||
@@ -1661,6 +1665,7 @@ Value listtransactions(const Array& params, bool fHelp)
|
||||
" \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
|
||||
" from (for receiving funds, positive amounts), or went to (for sending funds,\n"
|
||||
" negative amounts).\n"
|
||||
" \"size\": n, (numeric) Transaction size in bytes\n"
|
||||
" }\n"
|
||||
"]\n"
|
||||
|
||||
@@ -1998,21 +2003,38 @@ Value backupwallet(const Array& params, bool fHelp)
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"backupwallet \"destination\"\n"
|
||||
"\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n"
|
||||
"\nSafely copies wallet.dat to destination filename\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"destination\" (string) The destination directory or file\n"
|
||||
"1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
|
||||
"\nResult:\n"
|
||||
"\"path\" (string) The full path of the destination file\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("backupwallet", "\"backup.dat\"")
|
||||
+ HelpExampleRpc("backupwallet", "\"backup.dat\"")
|
||||
+ HelpExampleCli("backupwallet", "\"backupdata\"")
|
||||
+ HelpExampleRpc("backupwallet", "\"backupdata\"")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
string strDest = params[0].get_str();
|
||||
if (!BackupWallet(*pwalletMain, strDest))
|
||||
boost::filesystem::path exportdir;
|
||||
try {
|
||||
exportdir = GetExportDir();
|
||||
} catch (const std::runtime_error& e) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
|
||||
}
|
||||
if (exportdir.empty()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
|
||||
}
|
||||
std::string unclean = params[0].get_str();
|
||||
std::string clean = SanitizeFilename(unclean);
|
||||
if (clean.compare(unclean) != 0) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
|
||||
}
|
||||
boost::filesystem::path exportfilepath = exportdir / clean;
|
||||
|
||||
if (!BackupWallet(*pwalletMain, exportfilepath.string()))
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
|
||||
|
||||
return Value::null;
|
||||
return exportfilepath.string();
|
||||
}
|
||||
|
||||
|
||||
@@ -2734,7 +2756,15 @@ Value zc_benchmark(const json_spirit::Array& params, bool fHelp)
|
||||
} else if (benchmarktype == "parameterloading") {
|
||||
sample_times.push_back(benchmark_parameter_loading());
|
||||
} else if (benchmarktype == "createjoinsplit") {
|
||||
sample_times.push_back(benchmark_create_joinsplit());
|
||||
if (params.size() < 3) {
|
||||
sample_times.push_back(benchmark_create_joinsplit());
|
||||
} else {
|
||||
int nThreads = params[2].get_int();
|
||||
std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
|
||||
// Divide by nThreads^2 to get average seconds per JoinSplit because
|
||||
// we are running one JoinSplit per thread.
|
||||
sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
|
||||
}
|
||||
} else if (benchmarktype == "verifyjoinsplit") {
|
||||
sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
|
||||
} else if (benchmarktype == "solveequihash") {
|
||||
@@ -3224,7 +3254,7 @@ Value z_listreceivedbyaddress(const Array& params, bool fHelp)
|
||||
CZCPaymentAddress address(fromaddress);
|
||||
try {
|
||||
zaddr = address.Get();
|
||||
} catch (std::runtime_error) {
|
||||
} catch (const std::runtime_error&) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
|
||||
}
|
||||
|
||||
@@ -3291,7 +3321,7 @@ Value z_getbalance(const Array& params, bool fHelp)
|
||||
CZCPaymentAddress address(fromaddress);
|
||||
try {
|
||||
zaddr = address.Get();
|
||||
} catch (std::runtime_error) {
|
||||
} catch (const std::runtime_error&) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
|
||||
}
|
||||
if (!pwalletMain->HaveSpendingKey(zaddr)) {
|
||||
@@ -3443,6 +3473,13 @@ Value z_getoperationstatus_IMPL(const Array& params, bool fRemoveFinishedOperati
|
||||
}
|
||||
}
|
||||
|
||||
// sort results chronologically by creation_time
|
||||
std::sort(ret.begin(), ret.end(), [](Value a, Value b) -> bool {
|
||||
const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
|
||||
const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
|
||||
return t1 < t2;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3497,7 +3534,7 @@ Value z_sendmany(const Array& params, bool fHelp)
|
||||
CZCPaymentAddress address(fromaddress);
|
||||
try {
|
||||
zaddr = address.Get();
|
||||
} catch (std::runtime_error) {
|
||||
} catch (const std::runtime_error&) {
|
||||
// invalid
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
|
||||
}
|
||||
@@ -3544,7 +3581,7 @@ Value z_sendmany(const Array& params, bool fHelp)
|
||||
CZCPaymentAddress zaddr(address);
|
||||
zaddr.Get();
|
||||
isZaddr = true;
|
||||
} catch (std::runtime_error) {
|
||||
} catch (const std::runtime_error&) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
|
||||
}
|
||||
}
|
||||
@@ -3624,9 +3661,17 @@ Value z_sendmany(const Array& params, bool fHelp)
|
||||
}
|
||||
}
|
||||
|
||||
// Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
|
||||
Object o;
|
||||
o.push_back(Pair("fromaddress", params[0]));
|
||||
o.push_back(Pair("amounts", params[1]));
|
||||
o.push_back(Pair("minconf", nMinDepth));
|
||||
o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
|
||||
Value contextInfo = Value(o);
|
||||
|
||||
// Create operation and add to global queue
|
||||
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
|
||||
q->addOperation(operation);
|
||||
AsyncRPCOperationId operationId = operation->getId();
|
||||
return operationId;
|
||||
|
||||
@@ -645,10 +645,14 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
|
||||
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
|
||||
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
|
||||
CNoteData* nd = &(item.second);
|
||||
// Check the validity of the cache
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
// Only increment witnesses that are behind the current height
|
||||
if (nd->witnessHeight < pindex->nHeight) {
|
||||
// Check the validity of the cache
|
||||
// The only time a note witnessed above the current height
|
||||
// would be invalid here is during a reindex when blocks
|
||||
// have been decremented, and we are incrementing the blocks
|
||||
// immediately after.
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
// Witnesses being incremented should always be either -1
|
||||
// (never incremented or decremented) or one below pindex
|
||||
assert((nd->witnessHeight == -1) ||
|
||||
@@ -687,10 +691,11 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
|
||||
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
|
||||
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
|
||||
CNoteData* nd = &(item.second);
|
||||
// Check the validity of the cache
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
if (nd->witnessHeight < pindex->nHeight &&
|
||||
nd->witnesses.size() > 0) {
|
||||
// Check the validity of the cache
|
||||
// See earlier comment about validity.
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
nd->witnesses.front().append(note_commitment);
|
||||
}
|
||||
}
|
||||
@@ -699,7 +704,8 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
|
||||
// If this is our note, witness it
|
||||
if (txIsOurs) {
|
||||
JSOutPoint jsoutpt {hash, i, j};
|
||||
if (mapWallet[hash].mapNoteData.count(jsoutpt)) {
|
||||
if (mapWallet[hash].mapNoteData.count(jsoutpt) &&
|
||||
mapWallet[hash].mapNoteData[jsoutpt].witnessHeight < pindex->nHeight) {
|
||||
CNoteData* nd = &(mapWallet[hash].mapNoteData[jsoutpt]);
|
||||
if (nd->witnesses.size() > 0) {
|
||||
// We think this can happen because we write out the
|
||||
@@ -735,9 +741,10 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
|
||||
CNoteData* nd = &(item.second);
|
||||
if (nd->witnessHeight < pindex->nHeight) {
|
||||
nd->witnessHeight = pindex->nHeight;
|
||||
// Check the validity of the cache
|
||||
// See earlier comment about validity.
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
}
|
||||
// Check the validity of the cache
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -755,10 +762,12 @@ void CWallet::DecrementNoteWitnesses(const CBlockIndex* pindex)
|
||||
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
|
||||
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
|
||||
CNoteData* nd = &(item.second);
|
||||
// Check the validity of the cache
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
// Only increment witnesses that are not above the current height
|
||||
if (nd->witnessHeight <= pindex->nHeight) {
|
||||
// Check the validity of the cache
|
||||
// See comment below (this would be invalid if there was a
|
||||
// prior decrement).
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
// Witnesses being decremented should always be either -1
|
||||
// (never incremented or decremented) or equal to pindex
|
||||
assert((nd->witnessHeight == -1) ||
|
||||
@@ -777,7 +786,18 @@ void CWallet::DecrementNoteWitnesses(const CBlockIndex* pindex)
|
||||
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
|
||||
CNoteData* nd = &(item.second);
|
||||
// Check the validity of the cache
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
// Technically if there are notes witnessed above the current
|
||||
// height, their cache will now be invalid (relative to the new
|
||||
// value of nWitnessCacheSize). However, this would only occur
|
||||
// during a reindex, and by the time the reindex reaches the tip
|
||||
// of the chain again, the existing witness caches will be valid
|
||||
// again.
|
||||
// We don't set nWitnessCacheSize to zero at the start of the
|
||||
// reindex because the on-disk blocks had already resulted in a
|
||||
// chain that didn't trigger the assertion below.
|
||||
if (nd->witnessHeight < pindex->nHeight) {
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( nWitnessCacheSize <= 0 )
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "util.h"
|
||||
#include "utiltime.h"
|
||||
#include "wallet/wallet.h"
|
||||
#include "zcash/Proof.hpp"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
@@ -411,7 +412,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
CWalletTx wtx;
|
||||
ssValue >> wtx;
|
||||
CValidationState state;
|
||||
if (!(CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid()))
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
if (!(CheckTransaction(wtx, state, verifier) && (wtx.GetHash() == hash) && state.IsValid()))
|
||||
return false;
|
||||
|
||||
// Undo serialize changes in 31600
|
||||
|
||||
Reference in New Issue
Block a user