Integrate latest Zcash fixes and update for non-latin user names

This commit is contained in:
miketout
2018-10-27 20:29:03 -07:00
33 changed files with 1422 additions and 306 deletions

View File

@@ -18,7 +18,7 @@
#define CLIENT_VERSION_MAJOR 2
#define CLIENT_VERSION_MINOR 0
#define CLIENT_VERSION_REVISION 15
#define CLIENT_VERSION_BUILD 25
#define CLIENT_VERSION_BUILD 26
//! Set to true for release, false for prerelease or test build
#define CLIENT_VERSION_IS_RELEASE true

View File

@@ -8,7 +8,7 @@
// Deprecation policy:
// * Shut down 16 weeks' worth of blocks after the estimated release block height.
// * A warning is shown during the 2 weeks' worth of blocks prior to shut down.
static const int APPROX_RELEASE_HEIGHT = 200000;
static const int APPROX_RELEASE_HEIGHT = 227000;
static const int WEEKS_UNTIL_DEPRECATION = 24;
static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 60 * 24);

View File

@@ -34,19 +34,25 @@ int main(int argc, char **argv) {
boost::filesystem::path sapling_output = ZC_GetParamsDir() / "sapling-output.params";
boost::filesystem::path sprout_groth16 = ZC_GetParamsDir() / "sprout-groth16.params";
std::string sapling_spend_str = sapling_spend.string();
std::string sapling_output_str = sapling_output.string();
std::string sprout_groth16_str = sprout_groth16.string();
static_assert(
sizeof(boost::filesystem::path::value_type) == sizeof(codeunit),
"librustzcash not configured correctly");
auto sapling_spend_str = sapling_spend.native();
auto sapling_output_str = sapling_output.native();
auto sprout_groth16_str = sprout_groth16.native();
librustzcash_init_zksnark_params(
reinterpret_cast<const codeunit*>(sapling_spend_str.c_str()),
sapling_spend_str.length(),
"8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c",
reinterpret_cast<const codeunit*>(sapling_output_str.c_str()),
sapling_output_str.length(),
"657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028",
reinterpret_cast<const codeunit*>(sprout_groth16_str.c_str()),
sprout_groth16_str.length(),
"e9b238411bd6c0ec4791e9d04245ec350c9c5744f5610dfcce4365d5ca49dfefd5054e371842b3f88fa1b9d7e8e075249b3ebabd167fa8b0f3161292d36c180a"
);
librustzcash_init_zksnark_params(
sapling_spend_str.c_str(),
"8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c",
sapling_output_str.c_str(),
"657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028",
sprout_groth16_str.c_str(),
"e9b238411bd6c0ec4791e9d04245ec350c9c5744f5610dfcce4365d5ca49dfefd5054e371842b3f88fa1b9d7e8e075249b3ebabd167fa8b0f3161292d36c180a"
);
testing::InitGoogleMock(&argc, argv);
auto ret = RUN_ALL_TESTS();

View File

@@ -728,21 +728,27 @@ static void ZC_LoadParams(
elapsed = float(tv_end.tv_sec-tv_start.tv_sec) + (tv_end.tv_usec-tv_start.tv_usec)/float(1000000);
LogPrintf("Loaded verifying key in %fs seconds.\n", elapsed);
std::string sapling_spend_str = sapling_spend.string();
std::string sapling_output_str = sapling_output.string();
std::string sprout_groth16_str = sprout_groth16.string();
static_assert(
sizeof(boost::filesystem::path::value_type) == sizeof(codeunit),
"librustzcash not configured correctly");
auto sapling_spend_str = sapling_spend.native();
auto sapling_output_str = sapling_output.native();
auto sprout_groth16_str = sprout_groth16.native();
LogPrintf("Loading Sapling (Spend) parameters from %s\n", sapling_spend_str.c_str());
LogPrintf("Loading Sapling (Output) parameters from %s\n", sapling_output_str.c_str());
LogPrintf("Loading Sapling (Sprout Groth16) parameters from %s\n", sprout_groth16_str.c_str());
LogPrintf("Loading Sapling (Spend) parameters from %s\n", sapling_spend.string().c_str());
LogPrintf("Loading Sapling (Output) parameters from %s\n", sapling_output.string().c_str());
LogPrintf("Loading Sapling (Sprout Groth16) parameters from %s\n", sprout_groth16.string().c_str());
gettimeofday(&tv_start, 0);
librustzcash_init_zksnark_params(
sapling_spend_str.c_str(),
reinterpret_cast<const codeunit*>(sapling_spend_str.c_str()),
sapling_spend_str.length(),
"8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c",
sapling_output_str.c_str(),
reinterpret_cast<const codeunit*>(sapling_output_str.c_str()),
sapling_output_str.length(),
"657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028",
sprout_groth16_str.c_str(),
reinterpret_cast<const codeunit*>(sprout_groth16_str.c_str()),
sprout_groth16_str.length(),
"e9b238411bd6c0ec4791e9d04245ec350c9c5744f5610dfcce4365d5ca49dfefd5054e371842b3f88fa1b9d7e8e075249b3ebabd167fa8b0f3161292d36c180a"
);

View File

@@ -404,10 +404,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
BOOST_CHECK(addrs.size()==0);
// wallet should have one key
auto address = pwalletMain->GenerateNewZKey();
BOOST_CHECK(IsValidPaymentAddress(address));
BOOST_ASSERT(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
auto addr = boost::get<libzcash::SproutPaymentAddress>(address);
libzcash::SproutPaymentAddress addr = pwalletMain->GenerateNewSproutZKey();
pwalletMain->GetSproutPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==1);
@@ -603,7 +600,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
// Make new addresses for the set
for (int i=0; i<n2; i++) {
myaddrs.insert(EncodePaymentAddress(pwalletMain->GenerateNewZKey()));
myaddrs.insert(EncodePaymentAddress(pwalletMain->GenerateNewSproutZKey()));
}
// Verify number of addresses stored in wallet is n1+n2
@@ -956,7 +953,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
std::vector<char> v (2 * (ZC_MEMO_SIZE+1)); // x2 for hexadecimal string format
std::fill(v.begin(),v.end(), 'A');
std::string badmemo(v.begin(), v.end());
auto pa = pwalletMain->GenerateNewZKey();
auto pa = pwalletMain->GenerateNewSproutZKey();
std::string zaddr1 = EncodePaymentAddress(pa);
BOOST_CHECK_THROW(CallRPC(string("z_sendmany tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ ")
+ "[{\"address\":\"" + zaddr1 + "\", \"amount\":123.456}]"), runtime_error);
@@ -1034,7 +1031,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
// add keys manually
BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress"));
std::string taddr1 = retValue.get_str();
auto pa = pwalletMain->GenerateNewZKey();
auto pa = pwalletMain->GenerateNewSproutZKey();
std::string zaddr1 = EncodePaymentAddress(pa);
// there are no utxos to spend
@@ -1618,7 +1615,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals)
mapArgs["-mempooltxinputlimit"] = "1";
// Add keys manually
auto pa = pwalletMain->GenerateNewZKey();
auto pa = pwalletMain->GenerateNewSproutZKey();
std::string zaddr = EncodePaymentAddress(pa);
// Supply 2 inputs when mempool limit is 1
@@ -1743,7 +1740,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_parameters)
std::vector<char> v (2 * (ZC_MEMO_SIZE+1)); // x2 for hexadecimal string format
std::fill(v.begin(),v.end(), 'A');
std::string badmemo(v.begin(), v.end());
auto pa = pwalletMain->GenerateNewZKey();
auto pa = pwalletMain->GenerateNewSproutZKey();
std::string zaddr1 = EncodePaymentAddress(pa);
BOOST_CHECK_THROW(CallRPC(string("z_mergetoaddress [\"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ\"] ")
+ zaddr1 + " 0.0001 100 100 " + badmemo), runtime_error);
@@ -1814,7 +1811,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_internals)
// Add keys manually
BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress"));
MergeToAddressRecipient taddr1(retValue.get_str(), "");
auto pa = pwalletMain->GenerateNewZKey();
auto pa = pwalletMain->GenerateNewSproutZKey();
MergeToAddressRecipient zaddr1(EncodePaymentAddress(pa), "DEADBEEF");
// Supply 2 inputs when mempool limit is 1

View File

@@ -46,16 +46,22 @@ JoinSplitTestingSetup::JoinSplitTestingSetup()
boost::filesystem::path sapling_output = ZC_GetParamsDir() / "sapling-output.params";
boost::filesystem::path sprout_groth16 = ZC_GetParamsDir() / "sprout-groth16.params";
std::string sapling_spend_str = sapling_spend.string();
std::string sapling_output_str = sapling_output.string();
std::string sprout_groth16_str = sprout_groth16.string();
static_assert(
sizeof(boost::filesystem::path::value_type) == sizeof(codeunit),
"librustzcash not configured correctly");
auto sapling_spend_str = sapling_spend.native();
auto sapling_output_str = sapling_output.native();
auto sprout_groth16_str = sprout_groth16.native();
librustzcash_init_zksnark_params(
sapling_spend_str.c_str(),
reinterpret_cast<const codeunit*>(sapling_spend_str.c_str()),
sapling_spend_str.length(),
"8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c",
sapling_output_str.c_str(),
reinterpret_cast<const codeunit*>(sapling_output_str.c_str()),
sapling_output_str.length(),
"657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028",
sprout_groth16_str.c_str(),
reinterpret_cast<const codeunit*>(sprout_groth16_str.c_str()),
sprout_groth16_str.length(),
"e9b238411bd6c0ec4791e9d04245ec350c9c5744f5610dfcce4365d5ca49dfefd5054e371842b3f88fa1b9d7e8e075249b3ebabd167fa8b0f3161292d36c180a"
);
}

View File

@@ -556,13 +556,6 @@ static boost::filesystem::path ZC_GetBaseParamsDir()
// Unix: ~/.zcash-params
fs::path pathRet;
#ifdef _WIN32
// Windows
if (mapArgs.count("-zcashparamsdir")) {
pathRet = fs::system_complete(mapArgs["-zcashparamsdir"]);
if (fs::is_directory(pathRet)) {
return pathRet;
}
}
return GetSpecialFolderPath(CSIDL_APPDATA) / "ZcashParams";
#else
char* pszHome = getenv("HOME");

View File

@@ -399,7 +399,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
if (!pwalletMain->GetHDSeed(seed)) {
throw JSONRPCError(
RPC_WALLET_ERROR,
"CWallet::GenerateNewSaplingZKey(): HD seed not found");
"AsyncRPCOperation_sendmany::main_impl(): HD seed not found");
}
ovk = ovkForShieldingFromTaddr(seed);
}

View File

@@ -105,7 +105,7 @@ TEST(wallet_zkeys_tests, StoreAndLoadSaplingZkeys) {
/**
* This test covers methods on CWallet
* GenerateNewZKey()
* GenerateNewSproutZKey()
* AddSproutZKey()
* LoadZKey()
* LoadZKeyMetadata()
@@ -121,9 +121,7 @@ TEST(wallet_zkeys_tests, store_and_load_zkeys) {
ASSERT_EQ(0, addrs.size());
// wallet should have one key
auto address = wallet.GenerateNewZKey();
ASSERT_NE(boost::get<libzcash::SproutPaymentAddress>(&address), nullptr);
auto addr = boost::get<libzcash::SproutPaymentAddress>(address);
auto addr = wallet.GenerateNewSproutZKey();
wallet.GetSproutPaymentAddresses(addrs);
ASSERT_EQ(1, addrs.size());
@@ -236,7 +234,7 @@ TEST(wallet_zkeys_tests, write_zkey_direct_to_db) {
ASSERT_EQ(0, addrs.size());
// Add random key to the wallet
auto paymentAddress = wallet.GenerateNewZKey();
auto paymentAddress = wallet.GenerateNewSproutZKey();
// wallet should have one key
wallet.GetSproutPaymentAddresses(addrs);
@@ -353,9 +351,7 @@ TEST(wallet_zkeys_tests, write_cryptedzkey_direct_to_db) {
ASSERT_EQ(0, addrs.size());
// Add random key to the wallet
auto address = wallet.GenerateNewZKey();
ASSERT_NE(boost::get<libzcash::SproutPaymentAddress>(&address), nullptr);
auto paymentAddress = boost::get<libzcash::SproutPaymentAddress>(address);
auto paymentAddress = wallet.GenerateNewSproutZKey();
// wallet should have one key
wallet.GetSproutPaymentAddresses(addrs);
@@ -368,13 +364,11 @@ TEST(wallet_zkeys_tests, write_cryptedzkey_direct_to_db) {
ASSERT_TRUE(wallet.EncryptWallet(strWalletPass));
// adding a new key will fail as the wallet is locked
EXPECT_ANY_THROW(wallet.GenerateNewZKey());
EXPECT_ANY_THROW(wallet.GenerateNewSproutZKey());
// unlock wallet and then add
wallet.Unlock(strWalletPass);
auto address2 = wallet.GenerateNewZKey();
ASSERT_NE(boost::get<libzcash::SproutPaymentAddress>(&address2), nullptr);
auto paymentAddress2 = boost::get<libzcash::SproutPaymentAddress>(address2);
auto paymentAddress2 = wallet.GenerateNewSproutZKey();
// Create a new wallet from the existing wallet path
CWallet wallet2("wallet_crypted.dat");

View File

@@ -1244,7 +1244,7 @@ UniValue sendmany(const UniValue& params, bool fHelp)
if (fHelp || params.size() < 2 || params.size() > 5)
throw runtime_error(
"sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
"\nSend multiple times. Amounts are double-precision floating point numbers."
"\nSend multiple times. Amounts are decimal numbers with at most 8 digits of precision."
+ HelpRequiringPassphrase() + "\n"
"\nArguments:\n"
"1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
@@ -2909,17 +2909,17 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
UniValue results(UniValue::VARR);
if (zaddrs.size() > 0) {
std::vector<CUnspentSproutNotePlaintextEntry> sproutEntries;
std::vector<UnspentSaplingNoteEntry> saplingEntries;
pwalletMain->GetUnspentFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, !fIncludeWatchonly);
std::vector<CSproutNotePlaintextEntry> sproutEntries;
std::vector<SaplingNoteEntry> saplingEntries;
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false);
std::set<std::pair<PaymentAddress, uint256>> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs);
for (CUnspentSproutNotePlaintextEntry & entry : sproutEntries) {
for (auto & entry : sproutEntries) {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("txid", entry.jsop.hash.ToString()));
obj.push_back(Pair("jsindex", (int)entry.jsop.js ));
obj.push_back(Pair("jsoutindex", (int)entry.jsop.n));
obj.push_back(Pair("confirmations", entry.nHeight));
obj.push_back(Pair("confirmations", entry.confirmations));
bool hasSproutSpendingKey = pwalletMain->HaveSproutSpendingKey(boost::get<libzcash::SproutPaymentAddress>(entry.address));
obj.push_back(Pair("spendable", hasSproutSpendingKey));
obj.push_back(Pair("address", EncodePaymentAddress(entry.address)));
@@ -2932,11 +2932,11 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
results.push_back(obj);
}
for (UnspentSaplingNoteEntry & entry : saplingEntries) {
for (auto & entry : saplingEntries) {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("txid", entry.op.hash.ToString()));
obj.push_back(Pair("outindex", (int)entry.op.n));
obj.push_back(Pair("confirmations", entry.nHeight));
obj.push_back(Pair("confirmations", entry.confirmations));
libzcash::SaplingIncomingViewingKey ivk;
libzcash::SaplingFullViewingKey fvk;
pwalletMain->GetSaplingIncomingViewingKey(boost::get<libzcash::SaplingPaymentAddress>(entry.address), ivk);
@@ -3143,6 +3143,14 @@ UniValue zc_benchmark(const UniValue& params, bool fHelp)
sample_times.push_back(benchmark_loadwallet());
} else if (benchmarktype == "listunspent") {
sample_times.push_back(benchmark_listunspent());
} else if (benchmarktype == "createsaplingspend") {
sample_times.push_back(benchmark_create_sapling_spend());
} else if (benchmarktype == "createsaplingoutput") {
sample_times.push_back(benchmark_create_sapling_output());
} else if (benchmarktype == "verifysaplingspend") {
sample_times.push_back(benchmark_verify_sapling_spend());
} else if (benchmarktype == "verifysaplingoutput") {
sample_times.push_back(benchmark_verify_sapling_output());
} else {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
}
@@ -3511,7 +3519,7 @@ UniValue z_getnewaddress(const UniValue& params, bool fHelp)
}
if (addrType == ADDR_TYPE_SPROUT) {
return EncodePaymentAddress(pwalletMain->GenerateNewZKey());
return EncodePaymentAddress(pwalletMain->GenerateNewSproutZKey());
} else if (addrType == ADDR_TYPE_SAPLING) {
return EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey());
} else {
@@ -3969,7 +3977,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
if (fHelp || params.size() < 2 || params.size() > 4)
throw runtime_error(
"z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
"\nSend multiple times. Amounts are double-precision floating point numbers."
"\nSend multiple times. Amounts are decimal numbers with at most 8 digits of precision."
"\nChange generated from a taddr flows to a new taddr address, while change generated from a zaddr returns to itself."
"\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
+ strprintf("\nBefore Sapling activates, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS_BEFORE_SAPLING)

View File

@@ -93,23 +93,23 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
}
// Generate a new spending key and return its public payment address
libzcash::PaymentAddress CWallet::GenerateNewZKey()
libzcash::SproutPaymentAddress CWallet::GenerateNewSproutZKey()
{
AssertLockHeld(cs_wallet); // mapSproutZKeyMetadata
// TODO: Add Sapling support
auto k = SproutSpendingKey::random();
auto addr = k.address();
// Check for collision, even though it is unlikely to ever occur
if (CCryptoKeyStore::HaveSproutSpendingKey(addr))
throw std::runtime_error("CWallet::GenerateNewZKey(): Collision detected");
throw std::runtime_error("CWallet::GenerateNewSproutZKey(): Collision detected");
// Create new metadata
int64_t nCreationTime = GetTime();
mapSproutZKeyMetadata[addr] = CKeyMetadata(nCreationTime);
if (!AddSproutZKey(k))
throw std::runtime_error("CWallet::GenerateNewZKey(): AddSproutZKey failed");
throw std::runtime_error("CWallet::GenerateNewSproutZKey(): AddSproutZKey failed");
return addr;
}
@@ -4879,7 +4879,7 @@ void CWallet::GetFilteredNotes(
std::string address,
int minDepth,
bool ignoreSpent,
bool ignoreUnspendable)
bool requireSpendingKey)
{
std::set<PaymentAddress> filterAddresses;
@@ -4887,11 +4887,12 @@ void CWallet::GetFilteredNotes(
filterAddresses.insert(DecodePaymentAddress(address));
}
GetFilteredNotes(sproutEntries, saplingEntries, filterAddresses, minDepth, ignoreSpent, ignoreUnspendable);
GetFilteredNotes(sproutEntries, saplingEntries, filterAddresses, minDepth, INT_MAX, ignoreSpent, requireSpendingKey);
}
/**
* Find notes in the wallet filtered by payment addresses, min depth and ability to spend.
* Find notes in the wallet filtered by payment addresses, min depth, max depth,
* if the note is spent, if a spending key is required, and if the notes are locked.
* These notes are decrypted and added to the output parameter vector, outEntries.
*/
void CWallet::GetFilteredNotes(
@@ -4899,8 +4900,10 @@ void CWallet::GetFilteredNotes(
std::vector<SaplingNoteEntry>& saplingEntries,
std::set<PaymentAddress>& filterAddresses,
int minDepth,
int maxDepth,
bool ignoreSpent,
bool ignoreUnspendable)
bool requireSpendingKey,
bool ignoreLocked)
{
LOCK2(cs_main, cs_wallet);
@@ -4908,7 +4911,10 @@ void CWallet::GetFilteredNotes(
CWalletTx wtx = p.second;
// Filter the transactions before checking for notes
if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < minDepth) {
if (!CheckFinalTx(wtx) ||
wtx.GetBlocksToMaturity() > 0 ||
wtx.GetDepthInMainChain() < minDepth ||
wtx.GetDepthInMainChain() > maxDepth) {
continue;
}
@@ -4928,12 +4934,12 @@ void CWallet::GetFilteredNotes(
}
// skip notes which cannot be spent
if (ignoreUnspendable && !HaveSproutSpendingKey(pa)) {
if (requireSpendingKey && !HaveSproutSpendingKey(pa)) {
continue;
}
// skip locked notes
if (IsLockedNote(jsop)) {
if (ignoreLocked && IsLockedNote(jsop)) {
continue;
}
@@ -4957,7 +4963,7 @@ void CWallet::GetFilteredNotes(
hSig,
(unsigned char) j);
sproutEntries.push_back(CSproutNotePlaintextEntry{jsop, pa, plaintext});
sproutEntries.push_back(CSproutNotePlaintextEntry{jsop, pa, plaintext, wtx.GetDepthInMainChain()});
} catch (const note_decryption_failed &err) {
// Couldn't decrypt with this spending key
@@ -4994,7 +5000,7 @@ void CWallet::GetFilteredNotes(
}
// skip notes which cannot be spent
if (ignoreUnspendable) {
if (requireSpendingKey) {
libzcash::SaplingIncomingViewingKey ivk;
libzcash::SaplingFullViewingKey fvk;
if (!(GetSaplingIncomingViewingKey(pa, ivk) &&
@@ -5006,137 +5012,18 @@ void CWallet::GetFilteredNotes(
// skip locked notes
// TODO: Add locking for Sapling notes
// if (IsLockedNote(jsop)) {
// if (ignoreLocked && IsLockedNote(op)) {
// continue;
// }
auto note = notePt.note(nd.ivk).get();
saplingEntries.push_back(SaplingNoteEntry {
op, pa, note, notePt.memo() });
}
}
}
/* Find unspent notes filtered by payment address, min depth and max depth */
void CWallet::GetUnspentFilteredNotes(
std::vector<CUnspentSproutNotePlaintextEntry>& sproutEntries,
std::vector<UnspentSaplingNoteEntry>& saplingEntries,
std::set<PaymentAddress>& filterAddresses,
int minDepth,
int maxDepth,
bool requireSpendingKey)
{
LOCK2(cs_main, cs_wallet);
for (auto & p : mapWallet) {
CWalletTx wtx = p.second;
// Filter the transactions before checking for notes
if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < minDepth || wtx.GetDepthInMainChain() > maxDepth) {
continue;
}
for (auto & pair : wtx.mapSproutNoteData) {
JSOutPoint jsop = pair.first;
SproutNoteData nd = pair.second;
SproutPaymentAddress pa = nd.address;
// skip notes which belong to a different payment address in the wallet
if (!(filterAddresses.empty() || filterAddresses.count(pa))) {
continue;
}
// skip note which has been spent
if (nd.nullifier && IsSproutSpent(*nd.nullifier)) {
continue;
}
// skip notes where the spending key is not available
if (requireSpendingKey && !HaveSproutSpendingKey(pa)) {
continue;
}
// skip locked notes
if (IsLockedNote(jsop)) {
continue;
}
int i = jsop.js; // Index into CTransaction.vjoinsplit
int j = jsop.n; // Index into JSDescription.ciphertexts
// Get cached decryptor
ZCNoteDecryption decryptor;
if (!GetNoteDecryptor(pa, decryptor)) {
// Note decryptors are created when the wallet is loaded, so it should always exist
throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", EncodePaymentAddress(pa)));
}
// determine amount of funds in the note
auto hSig = wtx.vjoinsplit[i].h_sig(*pzcashParams, wtx.joinSplitPubKey);
try {
SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt(
decryptor,
wtx.vjoinsplit[i].ciphertexts[j],
wtx.vjoinsplit[i].ephemeralKey,
hSig,
(unsigned char) j);
sproutEntries.push_back(CUnspentSproutNotePlaintextEntry{jsop, pa, plaintext, wtx.GetDepthInMainChain()});
} catch (const note_decryption_failed &err) {
// Couldn't decrypt with this spending key
throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", EncodePaymentAddress(pa)));
} catch (const std::exception &exc) {
// Unexpected failure
throw std::runtime_error(strprintf("Error while decrypting note for payment address %s: %s", EncodePaymentAddress(pa), exc.what()));
}
}
for (auto & pair : wtx.mapSaplingNoteData) {
SaplingOutPoint op = pair.first;
SaplingNoteData nd = pair.second;
auto maybe_pt = SaplingNotePlaintext::decrypt(
wtx.vShieldedOutput[op.n].encCiphertext,
nd.ivk,
wtx.vShieldedOutput[op.n].ephemeralKey,
wtx.vShieldedOutput[op.n].cm);
assert(static_cast<bool>(maybe_pt));
auto notePt = maybe_pt.get();
auto maybe_pa = nd.ivk.address(notePt.d);
assert(static_cast<bool>(maybe_pa));
auto pa = maybe_pa.get();
// skip notes which belong to a different payment address in the wallet
if (!(filterAddresses.empty() || filterAddresses.count(pa))) {
continue;
}
// skip note which has been spent
if (nd.nullifier && IsSaplingSpent(*nd.nullifier)) {
continue;
}
// skip notes where the spending key is not available
if (requireSpendingKey) {
libzcash::SaplingIncomingViewingKey ivk;
libzcash::SaplingFullViewingKey fvk;
if (!(GetSaplingIncomingViewingKey(pa, ivk) &&
GetSaplingFullViewingKey(ivk, fvk) &&
HaveSaplingSpendingKey(fvk))) {
continue;
}
}
auto note = notePt.note(nd.ivk).get();
saplingEntries.push_back(UnspentSaplingNoteEntry {
op, pa, note, notePt.memo(), wtx.GetDepthInMainChain() });
}
}
}
//
// Shielded key and address generalizations
//

View File

@@ -310,38 +310,23 @@ public:
typedef std::map<JSOutPoint, SproutNoteData> mapSproutNoteData_t;
typedef std::map<SaplingOutPoint, SaplingNoteData> mapSaplingNoteData_t;
/** Decrypted note and its location in a transaction. */
/** Decrypted note, its location in a transaction, and number of confirmations. */
struct CSproutNotePlaintextEntry
{
JSOutPoint jsop;
libzcash::SproutPaymentAddress address;
libzcash::SproutNotePlaintext plaintext;
int confirmations;
};
/** Decrypted note, location in a transaction, and confirmation height. */
struct CUnspentSproutNotePlaintextEntry {
JSOutPoint jsop;
libzcash::SproutPaymentAddress address;
libzcash::SproutNotePlaintext plaintext;
int nHeight;
};
/** Sapling note and its location in a transaction. */
/** Sapling note, its location in a transaction, and number of confirmations. */
struct SaplingNoteEntry
{
SaplingOutPoint op;
libzcash::SaplingPaymentAddress address;
libzcash::SaplingNote note;
std::array<unsigned char, ZC_MEMO_SIZE> memo;
};
/** Sapling note, location in a transaction, and confirmation height. */
struct UnspentSaplingNoteEntry {
SaplingOutPoint op;
libzcash::SaplingPaymentAddress address;
libzcash::SaplingNote note;
std::array<unsigned char, ZC_MEMO_SIZE> memo;
int nHeight;
int confirmations;
};
/** A transaction with a merkle branch linking it to the block chain. */
@@ -1044,10 +1029,10 @@ public:
void GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const;
/**
* ZKeys
* Sprout ZKeys
*/
//! Generates a new zaddr
libzcash::PaymentAddress GenerateNewZKey();
//! Generates a new Sprout zaddr
libzcash::SproutPaymentAddress GenerateNewSproutZKey();
//! Adds spending key to the store, and saves it to disk
bool AddSproutZKey(const libzcash::SproutSpendingKey &key);
//! Adds spending key to the store, without saving it to disk (used by LoadWallet)
@@ -1300,27 +1285,22 @@ public:
std::string address,
int minDepth=1,
bool ignoreSpent=true,
bool ignoreUnspendable=true);
bool requireSpendingKey=true);
/* Find notes filtered by payment addresses, min depth, ability to spend */
/* Find notes filtered by payment addresses, min depth, max depth, if they are spent,
if a spending key is required, and if they are locked */
void GetFilteredNotes(std::vector<CSproutNotePlaintextEntry>& sproutEntries,
std::vector<SaplingNoteEntry>& saplingEntries,
std::set<libzcash::PaymentAddress>& filterAddresses,
int minDepth=1,
int maxDepth=INT_MAX,
bool ignoreSpent=true,
bool ignoreUnspendable=true);
bool requireSpendingKey=true,
bool ignoreLocked=true);
// staking functions
bool VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, uint32_t &bnTarget) const;
int32_t VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &bnTarget, arith_uint256 &hashResult, uint8_t *utxosig, CPubKey pk) const;
/* Find unspent notes filtered by payment address, min depth and max depth */
void GetUnspentFilteredNotes(std::vector<CUnspentSproutNotePlaintextEntry>& sproutEntries,
std::vector<UnspentSaplingNoteEntry>& saplingEntries,
std::set<libzcash::PaymentAddress>& filterAddresses,
int minDepth=1,
int maxDepth=INT_MAX,
bool requireSpendingKey=true);
};
/** A key allocated from the key pool. */

View File

@@ -30,6 +30,8 @@
#include "zcash/Zcash.h"
#include "zcash/IncrementalMerkleTree.hpp"
#include "zcash/Note.hpp"
#include "librustzcash.h"
using namespace libzcash;
// This method is based on Shutdown from init.cpp
@@ -472,3 +474,159 @@ double benchmark_listunspent()
auto unspent = listunspent(params, false);
return timer_stop(tv_start);
}
double benchmark_create_sapling_spend()
{
auto sk = libzcash::SaplingSpendingKey::random();
auto expsk = sk.expanded_spending_key();
auto address = sk.default_address();
SaplingNote note(address, GetRand(MAX_MONEY));
SaplingMerkleTree tree;
auto maybe_cm = note.cm();
tree.append(maybe_cm.get());
auto anchor = tree.root();
auto witness = tree.witness();
auto maybe_nf = note.nullifier(expsk.full_viewing_key(), witness.position());
if (!(maybe_cm && maybe_nf)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not create note commitment and nullifier");
}
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << witness.path();
std::vector<unsigned char> witnessChars(ss.begin(), ss.end());
uint256 alpha;
librustzcash_sapling_generate_r(alpha.begin());
auto ctx = librustzcash_sapling_proving_ctx_init();
struct timeval tv_start;
timer_start(tv_start);
SpendDescription sdesc;
bool result = librustzcash_sapling_spend_proof(
ctx,
expsk.full_viewing_key().ak.begin(),
expsk.nsk.begin(),
note.d.data(),
note.r.begin(),
alpha.begin(),
note.value(),
anchor.begin(),
witnessChars.data(),
sdesc.cv.begin(),
sdesc.rk.begin(),
sdesc.zkproof.data());
double t = timer_stop(tv_start);
librustzcash_sapling_proving_ctx_free(ctx);
if (!result) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_spend_proof() should return true");
}
return t;
}
double benchmark_create_sapling_output()
{
auto sk = libzcash::SaplingSpendingKey::random();
auto address = sk.default_address();
std::array<unsigned char, ZC_MEMO_SIZE> memo;
SaplingNote note(address, GetRand(MAX_MONEY));
libzcash::SaplingNotePlaintext notePlaintext(note, memo);
auto res = notePlaintext.encrypt(note.pk_d);
if (!res) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "SaplingNotePlaintext::encrypt() failed");
}
auto enc = res.get();
auto encryptor = enc.second;
auto ctx = librustzcash_sapling_proving_ctx_init();
struct timeval tv_start;
timer_start(tv_start);
OutputDescription odesc;
bool result = librustzcash_sapling_output_proof(
ctx,
encryptor.get_esk().begin(),
note.d.data(),
note.pk_d.begin(),
note.r.begin(),
note.value(),
odesc.cv.begin(),
odesc.zkproof.begin());
double t = timer_stop(tv_start);
librustzcash_sapling_proving_ctx_free(ctx);
if (!result) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_output_proof() should return true");
}
return t;
}
// Verify Sapling spend from testnet
// txid: abbd823cbd3d4e3b52023599d81a96b74817e95ce5bb58354f979156bd22ecc8
// position: 0
double benchmark_verify_sapling_spend()
{
SpendDescription spend;
CDataStream ss(ParseHex("8c6cf86bbb83bf0d075e5bd9bb4b5cd56141577be69f032880b11e26aa32aa5ef09fd00899e4b469fb11f38e9d09dc0379f0b11c23b5fe541765f76695120a03f0261d32af5d2a2b1e5c9a04200cd87d574dc42349de9790012ce560406a8a876a1e54cfcdc0eb74998abec2a9778330eeb2a0ac0e41d0c9ed5824fbd0dbf7da930ab299966ce333fd7bc1321dada0817aac5444e02c754069e218746bf879d5f2a20a8b028324fb2c73171e63336686aa5ec2e6e9a08eb18b87c14758c572f4531ccf6b55d09f44beb8b47563be4eff7a52598d80959dd9c9fee5ac4783d8370cb7d55d460053d3e067b5f9fe75ff2722623fb1825fcba5e9593d4205b38d1f502ff03035463043bd393a5ee039ce75a5d54f21b395255df6627ef96751566326f7d4a77d828aa21b1827282829fcbc42aad59cdb521e1a3aaa08b99ea8fe7fff0a04da31a52260fc6daeccd79bb877bdd8506614282258e15b3fe74bf71a93f4be3b770119edf99a317b205eea7d5ab800362b97384273888106c77d633600"), SER_NETWORK, PROTOCOL_VERSION);
ss >> spend;
uint256 dataToBeSigned = uint256S("0x2dbf83fe7b88a7cbd80fac0c719483906bb9a0c4fc69071e4780d5f2c76e592c");
auto ctx = librustzcash_sapling_verification_ctx_init();
struct timeval tv_start;
timer_start(tv_start);
bool result = librustzcash_sapling_check_spend(
ctx,
spend.cv.begin(),
spend.anchor.begin(),
spend.nullifier.begin(),
spend.rk.begin(),
spend.zkproof.begin(),
spend.spendAuthSig.begin(),
dataToBeSigned.begin()
);
double t = timer_stop(tv_start);
librustzcash_sapling_verification_ctx_free(ctx);
if (!result) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_check_spend() should return true");
}
return t;
}
// Verify Sapling output from testnet
// txid: abbd823cbd3d4e3b52023599d81a96b74817e95ce5bb58354f979156bd22ecc8
// position: 0
double benchmark_verify_sapling_output()
{
OutputDescription output;
CDataStream ss(ParseHex("edd742af18857e5ec2d71d346a7fe2ac97c137339bd5268eea86d32e0ff4f38f76213fa8cfed3347ac4e8572dd88aff395c0c10a59f8b3f49d2bc539ed6c726667e29d4763f914ddd0abf1cdfa84e44de87c233434c7e69b8b5b8f4623c8aa444163425bae5cef842972fed66046c1c6ce65c866ad894d02e6e6dcaae7a962d9f2ef95757a09c486928e61f0f7aed90ad0a542b0d3dc5fe140dfa7626b9315c77e03b055f19cbacd21a866e46f06c00e0c7792b2a590a611439b510a9aaffcf1073bad23e712a9268b36888e3727033eee2ab4d869f54a843f93b36ef489fb177bf74b41a9644e5d2a0a417c6ac1c8869bc9b83273d453f878ed6fd96b82a5939903f7b64ecaf68ea16e255a7fb7cc0b6d8b5608a1c6b0ed3024cc62c2f0f9c5cfc7b431ae6e9d40815557aa1d010523f9e1960de77b2274cb6710d229d475c87ae900183206ba90cb5bbc8ec0df98341b82726c705e0308ca5dc08db4db609993a1046dfb43dfd8c760be506c0bed799bb2205fc29dc2e654dce731034a23b0aaf6da0199248702ee0523c159f41f4cbfff6c35ace4dd9ae834e44e09c76a0cbdda1d3f6a2c75ad71212daf9575ab5f09ca148718e667f29ddf18c8a330a86ace18a86e89454653902aa393c84c6b694f27d0d42e24e7ac9fe34733de5ec15f5066081ce912c62c1a804a2bb4dedcef7cc80274f6bb9e89e2fce91dc50d6a73c8aefb9872f1cf3524a92626a0b8f39bbf7bf7d96ca2f770fc04d7f457021c536a506a187a93b2245471ddbfb254a71bc4a0d72c8d639a31c7b1920087ffca05c24214157e2e7b28184e91989ef0b14f9b34c3dc3cc0ac64226b9e337095870cb0885737992e120346e630a416a9b217679ce5a778fb15779c136bcecca5efe79012013d77d90b4e99dd22c8f35bc77121716e160d05bd30d288ee8886390ee436f85bdc9029df888a3a3326d9d4ddba5cb5318b3274928829d662e96fea1d601f7a306251ed8c6cc4e5a3a7a98c35a3650482a0eee08f3b4c2da9b22947c96138f1505c2f081f8972d429f3871f32bef4aaa51aa6945df8e9c9760531ac6f627d17c1518202818a91ca304fb4037875c666060597976144fcbbc48a776a2c61beb9515fa8f3ae6d3a041d320a38a8ac75cb47bb9c866ee497fc3cd13299970c4b369c1c2ceb4220af082fbecdd8114492a8e4d713b5a73396fd224b36c1185bd5e20d683e6c8db35346c47ae7401988255da7cfffdced5801067d4d296688ee8fe424b4a8a69309ce257eefb9345ebfda3f6de46bb11ec94133e1f72cd7ac54934d6cf17b3440800e70b80ebc7c7bfc6fb0fc2c"), SER_NETWORK, PROTOCOL_VERSION);
ss >> output;
auto ctx = librustzcash_sapling_verification_ctx_init();
struct timeval tv_start;
timer_start(tv_start);
bool result = librustzcash_sapling_check_output(
ctx,
output.cv.begin(),
output.cm.begin(),
output.ephemeralKey.begin(),
output.zkproof.begin()
);
double t = timer_stop(tv_start);
librustzcash_sapling_verification_ctx_free(ctx);
if (!result) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_check_output() should return true");
}
return timer_stop(tv_start);
}

View File

@@ -19,5 +19,9 @@ extern double benchmark_connectblock_slow();
extern double benchmark_sendtoaddress(CAmount amount);
extern double benchmark_loadwallet();
extern double benchmark_listunspent();
extern double benchmark_create_sapling_spend();
extern double benchmark_create_sapling_output();
extern double benchmark_verify_sapling_spend();
extern double benchmark_verify_sapling_output();
#endif