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:
@@ -59,6 +59,7 @@ LIBZCASH_CONSENSUS=
|
||||
endif
|
||||
|
||||
bin_PROGRAMS =
|
||||
noinst_PROGRAMS =
|
||||
TESTS =
|
||||
|
||||
if BUILD_BITCOIND
|
||||
@@ -482,7 +483,7 @@ libzcashconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCO
|
||||
endif
|
||||
#
|
||||
|
||||
CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno
|
||||
CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno */*.gcno wallet/*/*.gcno
|
||||
|
||||
DISTCLEANFILES = obj/build.h
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
TESTS += komodo-gtest
|
||||
bin_PROGRAMS += komodo-gtest
|
||||
|
||||
@@ -10,6 +11,13 @@ komodo_gtest_SOURCES = \
|
||||
gtest/json_test_vectors.h \
|
||||
# gtest/test_foundersreward.cpp \
|
||||
gtest/test_wallet_zkeys.cpp \
|
||||
# These tests are order-dependent, because they
|
||||
# depend on global state (see #1539)
|
||||
if ENABLE_WALLET
|
||||
zcash_gtest_SOURCES += \
|
||||
wallet/gtest/test_wallet_zkeys.cpp
|
||||
endif
|
||||
zcash_gtest_SOURCES += \
|
||||
gtest/test_jsonspirit.cpp \
|
||||
gtest/test_tautology.cpp \
|
||||
gtest/test_equihash.cpp \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
TESTS += test/test_bitcoin
|
||||
bin_PROGRAMS += test/test_bitcoin
|
||||
noinst_PROGRAMS += test/test_bitcoin
|
||||
TEST_SRCDIR = test
|
||||
TEST_BINARY=test/test_bitcoin$(EXEEXT)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
bin_PROGRAMS += \
|
||||
zcash/GenerateParams
|
||||
noinst_PROGRAMS += \
|
||||
zcash/GenerateParams \
|
||||
zcash/CreateJoinSplit
|
||||
|
||||
# tool for generating our public parameters
|
||||
zcash_GenerateParams_SOURCES = zcash/GenerateParams.cpp
|
||||
@@ -9,3 +10,13 @@ zcash_GenerateParams_LDADD = \
|
||||
$(LIBBITCOIN_UTIL) \
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
$(LIBZCASH_LIBS)
|
||||
|
||||
# tool for profiling the creation of joinsplits
|
||||
zcash_CreateJoinSplit_SOURCES = zcash/CreateJoinSplit.cpp
|
||||
zcash_CreateJoinSplit_LDADD = \
|
||||
$(LIBBITCOIN_COMMON) \
|
||||
$(LIBBITCOIN_UTIL) \
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
$(LIBZCASH) \
|
||||
$(BOOST_LIBS) \
|
||||
$(LIBZCASH_LIBS)
|
||||
|
||||
@@ -66,7 +66,8 @@ public:
|
||||
return creation_time_;
|
||||
}
|
||||
|
||||
Value getStatus() const;
|
||||
// Override this method to add data to the default status object.
|
||||
virtual Value getStatus() const;
|
||||
|
||||
Value getError() const;
|
||||
|
||||
|
||||
@@ -87,6 +87,8 @@ static bool AppInitRPC(int argc, char* argv[])
|
||||
" komodo-cli [options] help <command> " + _("Get help for a command") + "\n";
|
||||
|
||||
strUsage += "\n" + HelpMessageCli();
|
||||
} else {
|
||||
strUsage += LicenseInfo();
|
||||
}
|
||||
|
||||
fprintf(stdout, "%s", strUsage.c_str());
|
||||
@@ -112,12 +114,6 @@ static bool AppInitRPC(int argc, char* argv[])
|
||||
|
||||
Object CallRPC(const string& strMethod, const Array& params)
|
||||
{
|
||||
if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
|
||||
throw runtime_error(strprintf(
|
||||
_("You must set rpcpassword=<password> in the configuration file:\n%s\n"
|
||||
"If the file does not exist, create it with owner-readable-only file permissions."),
|
||||
GetConfigFile().string().c_str()));
|
||||
|
||||
// Connect to localhost
|
||||
bool fUseSSL = GetBoolArg("-rpcssl", false);
|
||||
boost::asio::io_service io_service;
|
||||
@@ -131,10 +127,24 @@ Object CallRPC(const string& strMethod, const Array& params)
|
||||
if (!fConnected)
|
||||
throw CConnectionFailed("couldn't connect to server");
|
||||
|
||||
// Find credentials to use
|
||||
std::string strRPCUserColonPass;
|
||||
if (mapArgs["-rpcpassword"] == "") {
|
||||
// Try fall back to cookie-based authentication if no password is provided
|
||||
if (!GetAuthCookie(&strRPCUserColonPass)) {
|
||||
throw runtime_error(strprintf(
|
||||
_("You must set rpcpassword=<password> in the configuration file:\n%s\n"
|
||||
"If the file does not exist, create it with owner-readable-only file permissions."),
|
||||
GetConfigFile().string().c_str()));
|
||||
|
||||
}
|
||||
} else {
|
||||
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
|
||||
}
|
||||
|
||||
// HTTP basic authentication
|
||||
string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
|
||||
map<string, string> mapRequestHeaders;
|
||||
mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
|
||||
mapRequestHeaders["Authorization"] = string("Basic ") + EncodeBase64(strRPCUserColonPass);
|
||||
|
||||
// Send request
|
||||
string strRequest = JSONRPCRequest(strMethod, params, 1);
|
||||
|
||||
@@ -115,6 +115,24 @@ bool AppInit(int argc, char* argv[])
|
||||
try
|
||||
{
|
||||
ReadConfigFile(mapArgs, mapMultiArgs);
|
||||
} catch (const missing_zcash_conf& e) {
|
||||
fprintf(stderr,
|
||||
(_("Before starting zcashd, you need to create a configuration file:\n"
|
||||
"%s\n"
|
||||
"It can be completely empty! That indicates you are happy with the default\n"
|
||||
"configuration of zcashd. But requiring a configuration file to start ensures\n"
|
||||
"that zcashd won't accidentally compromise your privacy if there was a default\n"
|
||||
"option you needed to change.\n"
|
||||
"\n"
|
||||
"You can look at the example configuration file for suggestions of default\n"
|
||||
"options that you may want to change. It should be in one of these locations,\n"
|
||||
"depending on how you installed Zcash:\n") +
|
||||
_("- Source code: %s\n"
|
||||
"- .deb package: %s\n")).c_str(),
|
||||
GetConfigFile().string().c_str(),
|
||||
"contrib/DEBIAN/examples/zcash.conf",
|
||||
"/usr/share/doc/zcash/examples/zcash.conf");
|
||||
return false;
|
||||
} catch (const std::exception& e) {
|
||||
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
|
||||
return false;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
|
||||
#define CLIENT_VERSION_MAJOR 1
|
||||
#define CLIENT_VERSION_MINOR 0
|
||||
#define CLIENT_VERSION_REVISION 3
|
||||
#define CLIENT_VERSION_REVISION 5
|
||||
#define CLIENT_VERSION_BUILD 50
|
||||
|
||||
//! Set to true for release, false for prerelease or test build
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "consensus/validation.h"
|
||||
#include "main.h"
|
||||
#include "zcash/Proof.hpp"
|
||||
|
||||
class MockCValidationState : public CValidationState {
|
||||
public:
|
||||
@@ -22,12 +23,14 @@ public:
|
||||
};
|
||||
|
||||
TEST(CheckBlock, VersionTooLow) {
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
|
||||
CBlock block;
|
||||
block.nVersion = 1;
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "version-too-low", false)).Times(1);
|
||||
EXPECT_FALSE(CheckBlock(0,0,block, state, false, false));
|
||||
EXPECT_FALSE(CheckBlock(0,0,block, state, verifier, false, false));
|
||||
}
|
||||
|
||||
TEST(ContextualCheckBlock, BadCoinbaseHeight) {
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
#include "keystore.h"
|
||||
#include "random.h"
|
||||
#ifdef ENABLE_WALLET
|
||||
#include "wallet/crypter.h"
|
||||
#endif
|
||||
#include "zcash/Address.hpp"
|
||||
|
||||
TEST(keystore_tests, store_and_retrieve_spending_key) {
|
||||
@@ -44,6 +46,7 @@ TEST(keystore_tests, store_and_retrieve_note_decryptor) {
|
||||
EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
class TestCCryptoKeyStore : public CCryptoKeyStore
|
||||
{
|
||||
public:
|
||||
@@ -125,3 +128,4 @@ TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) {
|
||||
ASSERT_EQ(1, addrs.count(addr));
|
||||
ASSERT_EQ(1, addrs.count(addr2));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -79,6 +79,9 @@ void test_tree(
|
||||
// The tree doesn't have a 'last' element added since it's blank.
|
||||
ASSERT_THROW(tree.last(), std::runtime_error);
|
||||
|
||||
// The tree is empty.
|
||||
ASSERT_TRUE(tree.size() == 0);
|
||||
|
||||
// We need to witness at every single point in the tree, so
|
||||
// that the consistency of the tree and the merkle paths can
|
||||
// be checked.
|
||||
@@ -93,6 +96,9 @@ void test_tree(
|
||||
// Now append a commitment to the tree
|
||||
tree.append(test_commitment);
|
||||
|
||||
// Size incremented by one.
|
||||
ASSERT_TRUE(tree.size() == i+1);
|
||||
|
||||
// Last element added to the tree was `test_commitment`
|
||||
ASSERT_TRUE(tree.last() == test_commitment);
|
||||
|
||||
|
||||
@@ -22,6 +22,67 @@ typedef libsnark::default_r1cs_ppzksnark_pp::Fqe_type curve_Fq2;
|
||||
#include "version.h"
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
TEST(proofs, g2_subgroup_check)
|
||||
{
|
||||
// all G2 elements are order r
|
||||
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * curve_G2::random_element() == curve_G2::zero());
|
||||
|
||||
// but that doesn't mean all elements that satisfy the curve equation are in G2...
|
||||
curve_G2 p = curve_G2::one();
|
||||
|
||||
while (1) {
|
||||
// This will construct an order r(2q-r) point with high probability
|
||||
p.X = curve_Fq2::random_element();
|
||||
try {
|
||||
p.Y = ((p.X.squared() * p.X) + libsnark::alt_bn128_twist_coeff_b).sqrt();
|
||||
break;
|
||||
} catch(...) {}
|
||||
}
|
||||
|
||||
ASSERT_TRUE(p.is_well_formed()); // it's on the curve
|
||||
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * p != curve_G2::zero()); // but not the order r subgroup..
|
||||
|
||||
{
|
||||
// libsnark unfortunately doesn't check, and the pairing will complete
|
||||
auto e = curve_Fr("149");
|
||||
auto a = curve_pp::reduced_pairing(curve_G1::one(), p);
|
||||
auto b = curve_pp::reduced_pairing(e * curve_G1::one(), p);
|
||||
|
||||
// though it will not preserve bilinearity
|
||||
ASSERT_TRUE((a^e) != b);
|
||||
}
|
||||
|
||||
{
|
||||
// so, our decompression API should not allow you to decompress G2 elements of that form!
|
||||
CompressedG2 badp(p);
|
||||
try {
|
||||
auto newp = badp.to_libsnark_g2<curve_G2>();
|
||||
FAIL() << "Expected std::runtime_error";
|
||||
} catch (std::runtime_error const & err) {
|
||||
EXPECT_EQ(err.what(), std::string("point is not in G2"));
|
||||
} catch(...) {
|
||||
FAIL() << "Expected std::runtime_error";
|
||||
}
|
||||
}
|
||||
|
||||
// educational purposes: showing that E'(Fp2) is of order r(2q-r),
|
||||
// by multiplying our random point in E' by (2q-r) = (q + q - r) to
|
||||
// get an element in G2
|
||||
{
|
||||
auto p1 = libsnark::alt_bn128_modulus_q * p;
|
||||
p1 = p1 + p1;
|
||||
p1 = p1 - (libsnark::alt_bn128_modulus_r * p);
|
||||
|
||||
ASSERT_TRUE(p1.is_well_formed());
|
||||
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * p1 == curve_G2::zero());
|
||||
|
||||
CompressedG2 goodp(p1);
|
||||
auto newp = goodp.to_libsnark_g2<curve_G2>();
|
||||
|
||||
ASSERT_TRUE(newp == p1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, sqrt_zero)
|
||||
{
|
||||
ASSERT_TRUE(curve_Fq::zero() == curve_Fq::zero().sqrt());
|
||||
|
||||
17
src/init.cpp
17
src/init.cpp
@@ -289,6 +289,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
#endif
|
||||
}
|
||||
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
|
||||
strUsage += HelpMessageOpt("-exportdir=<dir>", _("Specify directory to be used when exporting data"));
|
||||
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
|
||||
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file") + " " + _("on startup"));
|
||||
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
|
||||
@@ -376,11 +377,12 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", 1));
|
||||
strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0));
|
||||
}
|
||||
string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, net, proxy, prune"; // Don't translate these and qt below
|
||||
string debugCategories = "addrman, alert, bench, coindb, db, estimatefee, lock, mempool, net, partitioncheck, pow, proxy, prune, "
|
||||
"rand, reindex, rpc, selectcoins, zrpc, zrpcunsafe"; // Don't translate these and qt below
|
||||
if (mode == HMM_BITCOIN_QT)
|
||||
debugCategories += ", qt";
|
||||
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
|
||||
_("If <category> is not supplied or if <category> = 1, output all debugging information.") + _("<category> can be:") + " " + debugCategories + ".");
|
||||
_("If <category> is not supplied or if <category> = 1, output all debugging information.") + " " + _("<category> can be:") + " " + debugCategories + ".");
|
||||
#ifdef ENABLE_WALLET
|
||||
strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0));
|
||||
strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 1));
|
||||
@@ -625,6 +627,17 @@ static void ZC_LoadParams()
|
||||
boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key";
|
||||
boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key";
|
||||
|
||||
if (!(boost::filesystem::exists(pk_path) && boost::filesystem::exists(vk_path))) {
|
||||
uiInterface.ThreadSafeMessageBox(strprintf(
|
||||
_("Cannot find the Zcash network parameters in the following directory:\n"
|
||||
"%s\n"
|
||||
"Please run 'zcash-fetch-params' or './zcutil/fetch-params.sh' and then restart."),
|
||||
ZC_GetParamsDir()),
|
||||
"", CClientUIInterface::MSG_ERROR);
|
||||
StartShutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
pzcashParams = ZCJoinSplit::Unopened();
|
||||
|
||||
LogPrintf("Loading verifying key from %s\n", vk_path.string().c_str());
|
||||
|
||||
@@ -34,7 +34,5 @@ enum HelpMessageMode {
|
||||
|
||||
/** Help for options shared between UI and daemon (for -help) */
|
||||
std::string HelpMessage(HelpMessageMode mode);
|
||||
/** Returns licensing information (for -version) */
|
||||
std::string LicenseInfo();
|
||||
|
||||
#endif // BITCOIN_INIT_H
|
||||
|
||||
47
src/main.cpp
47
src/main.cpp
@@ -860,7 +860,8 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
|
||||
return nSigOps;
|
||||
}
|
||||
|
||||
bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
||||
bool CheckTransaction(const CTransaction& tx, CValidationState &state,
|
||||
libzcash::ProofVerifier& verifier)
|
||||
{
|
||||
// Don't count coinbase transactions because mining skews the count
|
||||
if (!tx.IsCoinBase()) {
|
||||
@@ -871,7 +872,6 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
||||
return false;
|
||||
} else {
|
||||
// Ensure that zk-SNARKs verify
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
|
||||
if (!joinsplit.Verify(*pzcashParams, verifier, tx.joinSplitPubKey)) {
|
||||
return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"),
|
||||
@@ -1082,11 +1082,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
AssertLockHeld(cs_main);
|
||||
if (pfMissingInputs)
|
||||
*pfMissingInputs = false;
|
||||
if (!CheckTransaction(tx, state))
|
||||
{
|
||||
fprintf(stderr,"AcceptToMemoryPool CheckTransaction failed\n");
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
if (!CheckTransaction(tx, state, verifier))
|
||||
return error("AcceptToMemoryPool: CheckTransaction failed");
|
||||
}
|
||||
// Coinbase is only valid in a block, not as a loose transaction
|
||||
if (tx.IsCoinBase())
|
||||
{
|
||||
@@ -2142,7 +2140,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
const CChainParams& chainparams = Params();
|
||||
AssertLockHeld(cs_main);
|
||||
// Check it again in case a previous version let a bad block in
|
||||
if (!CheckBlock(pindex->nHeight,pindex,block, state, !fJustCheck, !fJustCheck))
|
||||
bool fExpensiveChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()));
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
auto disabledVerifier = libzcash::ProofVerifier::Disabled();
|
||||
|
||||
// Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in
|
||||
if (!CheckBlock(pindex->nHeight,pindex,block, state, fExpensiveChecks ? verifier : disabledVerifier, !fJustCheck, !fJustCheck))
|
||||
return false;
|
||||
|
||||
// verify that the view's current state corresponds to the previous block
|
||||
@@ -2161,9 +2164,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
return true;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
bool fScriptChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()));
|
||||
//if ( KOMODO_TESTNET_EXPIRATION != 0 && pindex->nHeight > KOMODO_TESTNET_EXPIRATION ) // "testnet"
|
||||
// return(false);
|
||||
=======
|
||||
>>>>>>> zcash/master
|
||||
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
|
||||
// unless those are already completely spent.
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx) {
|
||||
@@ -2189,7 +2195,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
|
||||
CBlockUndo blockundo;
|
||||
|
||||
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
|
||||
CCheckQueueControl<CScriptCheck> control(fExpensiveChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
|
||||
|
||||
int64_t nTimeStart = GetTimeMicros();
|
||||
CAmount nFees = 0;
|
||||
@@ -2251,7 +2257,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
nFees += view.GetValueIn(chainActive.Tip()->nHeight,&interest,tx,chainActive.Tip()->nTime) - tx.GetValueOut();
|
||||
sum += interest;
|
||||
std::vector<CScriptCheck> vChecks;
|
||||
if (!ContextualCheckInputs(tx, state, view, fScriptChecks, flags, false, chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL))
|
||||
if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL))
|
||||
return false;
|
||||
control.Add(vChecks);
|
||||
}
|
||||
@@ -3094,7 +3100,9 @@ bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& bl
|
||||
}
|
||||
|
||||
int32_t komodo_check_deposit(int32_t height,const CBlock& block);
|
||||
bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot)
|
||||
bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state,
|
||||
libzcash::ProofVerifier& verifier,
|
||||
bool fCheckPOW, bool fCheckMerkleRoot)
|
||||
{
|
||||
// These are checks that are independent of context.
|
||||
|
||||
@@ -3139,7 +3147,7 @@ bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidat
|
||||
|
||||
// Check transactions
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||
if (!CheckTransaction(tx, state))
|
||||
if (!CheckTransaction(tx, state, verifier))
|
||||
return error("CheckBlock(): CheckTransaction failed");
|
||||
|
||||
unsigned int nSigOps = 0;
|
||||
@@ -3310,7 +3318,9 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
|
||||
if (fTooFarAhead) return true; // Block height is too high
|
||||
}
|
||||
|
||||
if ((!CheckBlock(pindex->nHeight,pindex,block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) {
|
||||
// See method docstring for why this is always disabled
|
||||
auto verifier = libzcash::ProofVerifier::Disabled();
|
||||
if ((!CheckBlock(pindex->nHeight,block, state, verifier)) || !ContextualCheckBlock(block, state, pindex->pprev)) {
|
||||
if (state.IsInvalid() && !state.CorruptionPossible()) {
|
||||
pindex->nStatus |= BLOCK_FAILED_VALID;
|
||||
setDirtyBlockIndex.insert(pindex);
|
||||
@@ -3361,11 +3371,12 @@ bool ProcessNewBlock(int32_t height,CValidationState &state, CNode* pfrom, CBloc
|
||||
{
|
||||
// Preliminary checks
|
||||
bool checked;
|
||||
auto verifier = libzcash::ProofVerifier::Disabled();
|
||||
if ( chainActive.Tip() != 0 )
|
||||
komodo_currentheight_set(chainActive.Tip()->nHeight);
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
checked = CheckBlock(height!=0?height:komodo_block2height(pblock),0,*pblock, state);
|
||||
else checked = CheckBlock(0,0,*pblock, state);
|
||||
checked = CheckBlock(height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier);
|
||||
else checked = CheckBlock(0,0,*pblock, state, verifier);
|
||||
{
|
||||
LOCK(cs_main);
|
||||
bool fRequested = MarkBlockAsReceived(pblock->GetHash());
|
||||
@@ -3400,11 +3411,13 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
|
||||
CBlockIndex indexDummy(block);
|
||||
indexDummy.pprev = pindexPrev;
|
||||
indexDummy.nHeight = pindexPrev->nHeight + 1;
|
||||
// JoinSplit proofs are verified in ConnectBlock
|
||||
auto verifier = libzcash::ProofVerifier::Disabled();
|
||||
|
||||
// NOTE: CheckBlockHeader is called by CheckBlock
|
||||
if (!ContextualCheckBlockHeader(block, state, pindexPrev))
|
||||
return false;
|
||||
if (!CheckBlock(indexDummy.nHeight,0,block, state, fCheckPOW, fCheckMerkleRoot))
|
||||
if (!CheckBlock(indexDummy.nHeight,0,block, state, verifier, fCheckPOW, fCheckMerkleRoot))
|
||||
return false;
|
||||
if (!ContextualCheckBlock(block, state, pindexPrev))
|
||||
return false;
|
||||
@@ -3725,6 +3738,8 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
|
||||
CBlockIndex* pindexFailure = NULL;
|
||||
int nGoodTransactions = 0;
|
||||
CValidationState state;
|
||||
// No need to verify JoinSplits twice
|
||||
auto verifier = libzcash::ProofVerifier::Disabled();
|
||||
for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev)
|
||||
{
|
||||
boost::this_thread::interruption_point();
|
||||
@@ -3736,7 +3751,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
|
||||
if (!ReadBlockFromDisk(block, pindex))
|
||||
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
|
||||
// check level 1: verify block validity
|
||||
if (nCheckLevel >= 1 && !CheckBlock(pindex->nHeight,pindex,block, state))
|
||||
if (nCheckLevel >= 1 && !CheckBlock(pindex->nHeight,pindex,block, state, verifier))
|
||||
return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
|
||||
// check level 2: verify undo validity
|
||||
if (nCheckLevel >= 2 && pindex) {
|
||||
|
||||
16
src/main.h
16
src/main.h
@@ -339,7 +339,7 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c
|
||||
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight);
|
||||
|
||||
/** Context-independent validity checks */
|
||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
|
||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state, libzcash::ProofVerifier& verifier);
|
||||
bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state);
|
||||
|
||||
/** Check for standard transaction types
|
||||
@@ -415,8 +415,10 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
|
||||
|
||||
/** Context-independent validity checks */
|
||||
bool CheckBlockHeader(int32_t height,CBlockIndex *pindex,const CBlockHeader& blockhdr, CValidationState& state, bool fCheckPOW = true);
|
||||
bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||
bool CheckBlockHeader(int32_t height,CBlockIndex *pindex,const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
|
||||
bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state,
|
||||
libzcash::ProofVerifier& verifier,
|
||||
bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||
|
||||
/** Context-dependent validity checks */
|
||||
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev);
|
||||
@@ -425,7 +427,13 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
|
||||
/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
|
||||
bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||
|
||||
/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */
|
||||
/**
|
||||
* Store block on disk.
|
||||
* JoinSplit proofs are never verified, because:
|
||||
* - AcceptBlock doesn't perform script checks either.
|
||||
* - The only caller of AcceptBlock verifies JoinSplit proofs elsewhere.
|
||||
* If dbp is non-NULL, the file is known to already reside on disk
|
||||
*/
|
||||
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp);
|
||||
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
CCriticalSection cs_metrics;
|
||||
|
||||
boost::synchronized_value<int64_t> nNodeStartTime;
|
||||
boost::synchronized_value<int64_t> nNextRefresh;
|
||||
AtomicCounter transactionsValidated;
|
||||
AtomicCounter ehSolverRuns;
|
||||
AtomicCounter solutionTargetChecks;
|
||||
@@ -60,10 +61,20 @@ double GetLocalSolPS()
|
||||
return GetLocalSolPS_INTERNAL(GetUptime());
|
||||
}
|
||||
|
||||
void TriggerRefresh()
|
||||
{
|
||||
*nNextRefresh = GetTime();
|
||||
// Ensure that the refresh has started before we return
|
||||
MilliSleep(200);
|
||||
}
|
||||
|
||||
static bool metrics_ThreadSafeMessageBox(const std::string& message,
|
||||
const std::string& caption,
|
||||
unsigned int style)
|
||||
{
|
||||
// The SECURE flag has no effect in the metrics UI.
|
||||
style &= ~CClientUIInterface::SECURE;
|
||||
|
||||
std::string strCaption;
|
||||
// Check for usage of predefined caption
|
||||
switch (style) {
|
||||
@@ -85,6 +96,9 @@ static bool metrics_ThreadSafeMessageBox(const std::string& message,
|
||||
if (u->size() > 5) {
|
||||
u->pop_back();
|
||||
}
|
||||
|
||||
TriggerRefresh();
|
||||
return false;
|
||||
}
|
||||
|
||||
static void metrics_InitMessage(const std::string& message)
|
||||
@@ -247,8 +261,21 @@ int printMessageBox(size_t cols)
|
||||
std::cout << _("Messages:") << std::endl;
|
||||
for (auto it = u->cbegin(); it != u->cend(); ++it) {
|
||||
std::cout << *it << std::endl;
|
||||
// Handle wrapped lines
|
||||
lines += (it->size() / cols);
|
||||
// Handle newlines and wrapped lines
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
while (j < it->size()) {
|
||||
i = it->find('\n', j);
|
||||
if (i == std::string::npos) {
|
||||
i = it->size();
|
||||
} else {
|
||||
// Newline
|
||||
lines++;
|
||||
}
|
||||
// Wrapped lines
|
||||
lines += ((i-j) / cols);
|
||||
j = i + 1;
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
return lines;
|
||||
@@ -333,8 +360,8 @@ void ThreadShowMetricsScreen()
|
||||
std::cout << "----------------------------------------" << std::endl;
|
||||
}
|
||||
|
||||
int64_t nWaitEnd = GetTime() + nRefresh;
|
||||
while (GetTime() < nWaitEnd) {
|
||||
*nNextRefresh = GetTime() + nRefresh;
|
||||
while (GetTime() < *nNextRefresh) {
|
||||
boost::this_thread::interruption_point();
|
||||
MilliSleep(200);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ void TrackMinedBlock(uint256 hash);
|
||||
void MarkStartTime();
|
||||
double GetLocalSolPS();
|
||||
|
||||
void TriggerRefresh();
|
||||
|
||||
void ConnectMetricsScreen();
|
||||
void ThreadShowMetricsScreen();
|
||||
|
||||
|
||||
@@ -806,6 +806,7 @@ Value getblockchaininfo(const Array& params, bool fHelp)
|
||||
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
|
||||
" \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
|
||||
" \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
|
||||
" \"commitments\": xxxxxx, (numeric) the current number of note commitments in the commitment tree\n"
|
||||
" \"softforks\": [ (array) status of softforks in progress\n"
|
||||
" {\n"
|
||||
" \"id\": \"xxxx\", (string) name of softfork\n"
|
||||
@@ -837,6 +838,10 @@ Value getblockchaininfo(const Array& params, bool fHelp)
|
||||
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
|
||||
obj.push_back(Pair("pruned", fPruneMode));
|
||||
|
||||
ZCIncrementalMerkleTree tree;
|
||||
pcoinsTip->GetAnchorAt(pcoinsTip->GetBestAnchor(), tree);
|
||||
obj.push_back(Pair("commitments", tree.size()));
|
||||
|
||||
const Consensus::Params& consensusParams = Params().GetConsensus();
|
||||
CBlockIndex* tip = chainActive.Tip();
|
||||
Array softforks;
|
||||
|
||||
@@ -405,6 +405,7 @@ static Value BIP22ValidationResult(const CValidationState& state)
|
||||
return "valid?";
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
Value getblocktemplate(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() > 1)
|
||||
@@ -697,6 +698,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
class submitblock_StateCatcher : public CValidationInterface
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "rpcprotocol.h"
|
||||
|
||||
#include "clientversion.h"
|
||||
#include "random.h"
|
||||
#include "tinyformat.h"
|
||||
#include "util.h"
|
||||
#include "utilstrencodings.h"
|
||||
@@ -13,6 +14,7 @@
|
||||
#include "version.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
@@ -288,3 +290,68 @@ Object JSONRPCError(int code, const string& message)
|
||||
error.push_back(Pair("message", message));
|
||||
return error;
|
||||
}
|
||||
|
||||
/** Username used when cookie authentication is in use (arbitrary, only for
|
||||
* recognizability in debugging/logging purposes)
|
||||
*/
|
||||
static const std::string COOKIEAUTH_USER = "__cookie__";
|
||||
/** Default name for auth cookie file */
|
||||
static const std::string COOKIEAUTH_FILE = ".cookie";
|
||||
|
||||
boost::filesystem::path GetAuthCookieFile()
|
||||
{
|
||||
boost::filesystem::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE));
|
||||
if (!path.is_complete()) path = GetDataDir() / path;
|
||||
return path;
|
||||
}
|
||||
|
||||
bool GenerateAuthCookie(std::string *cookie_out)
|
||||
{
|
||||
unsigned char rand_pwd[32];
|
||||
GetRandBytes(rand_pwd, 32);
|
||||
std::string cookie = COOKIEAUTH_USER + ":" + EncodeBase64(&rand_pwd[0],32);
|
||||
|
||||
/** the umask determines what permissions are used to create this file -
|
||||
* these are set to 077 in init.cpp unless overridden with -sysperms.
|
||||
*/
|
||||
std::ofstream file;
|
||||
boost::filesystem::path filepath = GetAuthCookieFile();
|
||||
file.open(filepath.string().c_str());
|
||||
if (!file.is_open()) {
|
||||
LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string());
|
||||
return false;
|
||||
}
|
||||
file << cookie;
|
||||
file.close();
|
||||
LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());
|
||||
|
||||
if (cookie_out)
|
||||
*cookie_out = cookie;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetAuthCookie(std::string *cookie_out)
|
||||
{
|
||||
std::ifstream file;
|
||||
std::string cookie;
|
||||
boost::filesystem::path filepath = GetAuthCookieFile();
|
||||
file.open(filepath.string().c_str());
|
||||
if (!file.is_open())
|
||||
return false;
|
||||
std::getline(file, cookie);
|
||||
file.close();
|
||||
|
||||
if (cookie_out)
|
||||
*cookie_out = cookie;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeleteAuthCookie()
|
||||
{
|
||||
try {
|
||||
boost::filesystem::remove(GetAuthCookieFile());
|
||||
} catch (const boost::filesystem::filesystem_error& e) {
|
||||
LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "json/json_spirit_reader_template.h"
|
||||
#include "json/json_spirit_utils.h"
|
||||
@@ -165,4 +166,13 @@ json_spirit::Object JSONRPCReplyObj(const json_spirit::Value& result, const json
|
||||
std::string JSONRPCReply(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id);
|
||||
json_spirit::Object JSONRPCError(int code, const std::string& message);
|
||||
|
||||
/** Get name of RPC authentication cookie file */
|
||||
boost::filesystem::path GetAuthCookieFile();
|
||||
/** Generate a new RPC authentication cookie and write it to disk */
|
||||
bool GenerateAuthCookie(std::string *cookie_out);
|
||||
/** Read the RPC authentication cookie from disk */
|
||||
bool GetAuthCookie(std::string *cookie_out);
|
||||
/** Delete RPC authentication cookie from disk */
|
||||
void DeleteAuthCookie();
|
||||
|
||||
#endif // BITCOIN_RPCPROTOCOL_H
|
||||
|
||||
@@ -309,7 +309,9 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "blockchain", "kvupdate", &kvupdate, true },
|
||||
|
||||
/* Mining */
|
||||
#ifdef ENABLE_WALLET
|
||||
{ "mining", "getblocktemplate", &getblocktemplate, true },
|
||||
#endif
|
||||
{ "mining", "getmininginfo", &getmininginfo, true },
|
||||
{ "mining", "getlocalsolps", &getlocalsolps, true },
|
||||
{ "mining", "getnetworksolps", &getnetworksolps, true },
|
||||
@@ -629,10 +631,9 @@ void StartRPCThreads()
|
||||
strAllowed += subnet.ToString() + " ";
|
||||
LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed);
|
||||
|
||||
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
|
||||
if (((mapArgs["-rpcpassword"] == "") ||
|
||||
(mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword())
|
||||
if (mapArgs["-rpcpassword"] == "")
|
||||
{
|
||||
/*<<<<<<< HEAD
|
||||
unsigned char rand_pwd[32];
|
||||
GetRandBytes(rand_pwd, 32);
|
||||
uiInterface.ThreadSafeMessageBox(strprintf(
|
||||
@@ -651,6 +652,18 @@ void StartRPCThreads()
|
||||
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::SECURE);
|
||||
StartShutdown();
|
||||
return;
|
||||
=======*/
|
||||
LogPrintf("No rpcpassword set - using random cookie authentication\n");
|
||||
if (!GenerateAuthCookie(&strRPCUserColonPass)) {
|
||||
uiInterface.ThreadSafeMessageBox(
|
||||
_("Error: A fatal internal error occured, see debug.log for details"), // Same message as AbortNode
|
||||
"", CClientUIInterface::MSG_ERROR);
|
||||
StartShutdown();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
|
||||
//>>>>>>> zcash/master
|
||||
}
|
||||
|
||||
assert(rpc_io_service == NULL);
|
||||
@@ -817,6 +830,8 @@ void StopRPCThreads()
|
||||
}
|
||||
deadlineTimers.clear();
|
||||
|
||||
DeleteAuthCookie();
|
||||
|
||||
rpc_io_service->stop();
|
||||
g_rpcSignals.Stopped();
|
||||
if (rpc_worker_group != NULL)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "main.h"
|
||||
#include "test/test_bitcoin.h"
|
||||
#include "utiltime.h"
|
||||
#include "zcash/Proof.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
@@ -56,7 +57,8 @@ BOOST_AUTO_TEST_CASE(May15)
|
||||
|
||||
// After May 15'th, big blocks are OK:
|
||||
forkingBlock.nTime = tMay15; // Invalidates PoW
|
||||
BOOST_CHECK(CheckBlock(0,0,forkingBlock, state, false, false));
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
BOOST_CHECK(CheckBlock(forkingBlock, state, verifier, false, false));
|
||||
}
|
||||
|
||||
SetMockTime(0);
|
||||
|
||||
@@ -358,16 +358,26 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
|
||||
pwalletMain->GetPaymentAddresses(addrs);
|
||||
BOOST_CHECK(addrs.size()==1);
|
||||
|
||||
// Set up paths
|
||||
boost::filesystem::path tmppath = boost::filesystem::temp_directory_path();
|
||||
boost::filesystem::path tmpfilename = boost::filesystem::unique_path("%%%%%%%%");
|
||||
boost::filesystem::path exportfilepath = tmppath / tmpfilename;
|
||||
|
||||
// export will fail since exportdir is not set
|
||||
BOOST_CHECK_THROW(CallRPC(string("z_exportwallet ") + tmpfilename.string()), runtime_error);
|
||||
|
||||
// set exportdir
|
||||
mapArgs["-exportdir"] = tmppath.native();
|
||||
|
||||
// run some tests
|
||||
BOOST_CHECK_THROW(CallRPC("z_exportwallet"), runtime_error);
|
||||
|
||||
BOOST_CHECK_THROW(CallRPC("z_exportwallet toomany args"), runtime_error);
|
||||
|
||||
|
||||
boost::filesystem::path temp = boost::filesystem::temp_directory_path() /
|
||||
boost::filesystem::unique_path();
|
||||
const std::string path = temp.native();
|
||||
BOOST_CHECK_THROW(CallRPC(string("z_exportwallet invalid!*/_chars.txt")), runtime_error);
|
||||
|
||||
BOOST_CHECK_NO_THROW(CallRPC(string("z_exportwallet ") + tmpfilename.string()));
|
||||
|
||||
BOOST_CHECK_NO_THROW(CallRPC(string("z_exportwallet ") + path));
|
||||
|
||||
auto addr = paymentAddress.Get();
|
||||
libzcash::SpendingKey key;
|
||||
@@ -382,7 +392,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
|
||||
EnsureWalletIsUnlocked();
|
||||
|
||||
ifstream file;
|
||||
file.open(path.c_str(), std::ios::in | std::ios::ate);
|
||||
file.open(exportfilepath.string().c_str(), std::ios::in | std::ios::ate);
|
||||
BOOST_CHECK(file.is_open());
|
||||
bool fVerified = false;
|
||||
int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "zcash/Note.hpp"
|
||||
#include "zcash/Address.hpp"
|
||||
#include "zcash/Proof.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace json_spirit;
|
||||
@@ -97,6 +98,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
||||
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
|
||||
Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
|
||||
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
ScriptError err;
|
||||
BOOST_FOREACH(Value& tv, tests)
|
||||
{
|
||||
@@ -141,7 +143,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
||||
stream >> tx;
|
||||
|
||||
CValidationState state;
|
||||
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
|
||||
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier), strTest);
|
||||
BOOST_CHECK(state.IsValid());
|
||||
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
@@ -173,6 +175,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
||||
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
|
||||
Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
|
||||
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
ScriptError err;
|
||||
BOOST_FOREACH(Value& tv, tests)
|
||||
{
|
||||
@@ -217,7 +220,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
||||
stream >> tx;
|
||||
|
||||
CValidationState state;
|
||||
fValid = CheckTransaction(tx, state) && state.IsValid();
|
||||
fValid = CheckTransaction(tx, state, verifier) && state.IsValid();
|
||||
|
||||
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
|
||||
{
|
||||
@@ -246,11 +249,12 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
|
||||
CMutableTransaction tx;
|
||||
stream >> tx;
|
||||
CValidationState state;
|
||||
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid.");
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier) && state.IsValid(), "Simple deserialized transaction should be valid.");
|
||||
|
||||
// Check that duplicate txins fail
|
||||
tx.vin.push_back(tx.vin[0]);
|
||||
BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state) || !state.IsValid(), "Transaction with duplicate txins should be invalid.");
|
||||
BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state, verifier) || !state.IsValid(), "Transaction with duplicate txins should be invalid.");
|
||||
}
|
||||
|
||||
//
|
||||
@@ -373,6 +377,7 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
|
||||
{
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
CMutableTransaction tx;
|
||||
tx.nVersion = 2;
|
||||
{
|
||||
@@ -424,23 +429,23 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
|
||||
JSDescription *jsdesc = &newTx.vjoinsplit[0];
|
||||
jsdesc->vpub_old = -1;
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-negative");
|
||||
|
||||
jsdesc->vpub_old = MAX_MONEY + 1;
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-toolarge");
|
||||
|
||||
jsdesc->vpub_old = 0;
|
||||
jsdesc->vpub_new = -1;
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-negative");
|
||||
|
||||
jsdesc->vpub_new = MAX_MONEY + 1;
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-toolarge");
|
||||
|
||||
jsdesc->vpub_new = (MAX_MONEY / 2) + 10;
|
||||
@@ -450,7 +455,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
|
||||
JSDescription *jsdesc2 = &newTx.vjoinsplit[1];
|
||||
jsdesc2->vpub_new = (MAX_MONEY / 2) + 10;
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-txintotal-toolarge");
|
||||
}
|
||||
{
|
||||
@@ -464,7 +469,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
|
||||
jsdesc->nullifiers[0] = GetRandHash();
|
||||
jsdesc->nullifiers[1] = jsdesc->nullifiers[0];
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate");
|
||||
|
||||
jsdesc->nullifiers[1] = GetRandHash();
|
||||
@@ -475,7 +480,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
|
||||
jsdesc2->nullifiers[0] = GetRandHash();
|
||||
jsdesc2->nullifiers[1] = jsdesc->nullifiers[0];
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate");
|
||||
}
|
||||
{
|
||||
@@ -494,7 +499,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
|
||||
CTransaction finalNewTx(newTx);
|
||||
BOOST_CHECK(finalNewTx.IsCoinBase());
|
||||
}
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-cb-has-joinsplits");
|
||||
}
|
||||
}
|
||||
|
||||
35
src/util.cpp
35
src/util.cpp
@@ -501,6 +501,26 @@ const boost::filesystem::path &ZC_GetParamsDir()
|
||||
return path;
|
||||
}
|
||||
|
||||
// Return the user specified export directory. Create directory if it doesn't exist.
|
||||
// If user did not set option, return an empty path.
|
||||
// If there is a filesystem problem, throw an exception.
|
||||
const boost::filesystem::path GetExportDir()
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
fs::path path;
|
||||
if (mapArgs.count("-exportdir")) {
|
||||
path = fs::system_complete(mapArgs["-exportdir"]);
|
||||
if (fs::exists(path) && !fs::is_directory(path)) {
|
||||
throw std::runtime_error(strprintf("The -exportdir '%s' already exists and is not a directory", path.string()));
|
||||
}
|
||||
if (!fs::exists(path) && !fs::create_directories(path)) {
|
||||
throw std::runtime_error(strprintf("Failed to create directory at -exportdir '%s'", path.string()));
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
const boost::filesystem::path &GetDataDir(bool fNetSpecific)
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
@@ -556,7 +576,7 @@ void ReadConfigFile(map<string, string>& mapSettingsRet,
|
||||
{
|
||||
boost::filesystem::ifstream streamConfig(GetConfigFile());
|
||||
if (!streamConfig.good())
|
||||
return; // No komodo.conf file is OK
|
||||
throw missing_zcash_conf();
|
||||
|
||||
set<string> setOptions;
|
||||
setOptions.insert("*");
|
||||
@@ -837,3 +857,16 @@ void SetThreadPriority(int nPriority)
|
||||
#endif // PRIO_THREAD
|
||||
#endif // WIN32
|
||||
}
|
||||
|
||||
std::string LicenseInfo()
|
||||
{
|
||||
return FormatParagraph(strprintf(_("Copyright (C) 2009-%i The Bitcoin Core Developers"), COPYRIGHT_YEAR)) + "\n" +
|
||||
FormatParagraph(strprintf(_("Copyright (C) 2015-%i The Zcash Developers"), COPYRIGHT_YEAR)) + "\n" +
|
||||
"\n" +
|
||||
FormatParagraph(_("This is experimental software.")) + "\n" +
|
||||
"\n" +
|
||||
FormatParagraph(_("Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>.")) + "\n" +
|
||||
"\n" +
|
||||
FormatParagraph(_("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.")) +
|
||||
"\n";
|
||||
}
|
||||
|
||||
@@ -127,6 +127,10 @@ boost::filesystem::path GetConfigFile();
|
||||
boost::filesystem::path GetPidFile();
|
||||
void CreatePidFile(const boost::filesystem::path &path, pid_t pid);
|
||||
#endif
|
||||
class missing_zcash_conf : public std::runtime_error {
|
||||
public:
|
||||
missing_zcash_conf() : std::runtime_error("Missing komodo.conf") { }
|
||||
};
|
||||
void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
|
||||
#ifdef WIN32
|
||||
boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
|
||||
@@ -134,6 +138,10 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
|
||||
boost::filesystem::path GetTempPath();
|
||||
void ShrinkDebugFile();
|
||||
void runCommand(std::string strCommand);
|
||||
const boost::filesystem::path GetExportDir();
|
||||
|
||||
/** Returns licensing information (for -version) */
|
||||
std::string LicenseInfo();
|
||||
|
||||
inline bool IsSwitchChar(char c)
|
||||
{
|
||||
|
||||
@@ -30,6 +30,22 @@ string SanitizeString(const string& str)
|
||||
return strResult;
|
||||
}
|
||||
|
||||
string SanitizeFilename(const string& str)
|
||||
{
|
||||
/**
|
||||
* safeChars chosen to restrict filename, keeping it simple to avoid cross-platform issues.
|
||||
* http://stackoverflow.com/a/2306003
|
||||
*/
|
||||
static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890");
|
||||
string strResult;
|
||||
for (std::string::size_type i = 0; i < str.size(); i++)
|
||||
{
|
||||
if (safeChars.find(str[i]) != std::string::npos)
|
||||
strResult.push_back(str[i]);
|
||||
}
|
||||
return strResult;
|
||||
}
|
||||
|
||||
const signed char p_util_hexdigit[256] =
|
||||
{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
/** This is needed because the foreach macro can't get over the comma in pair<t1, t2> */
|
||||
#define PAIRTYPE(t1, t2) std::pair<t1, t2>
|
||||
|
||||
std::string SanitizeFilename(const std::string& str);
|
||||
std::string SanitizeString(const std::string& str);
|
||||
std::vector<unsigned char> ParseHex(const char* psz);
|
||||
std::vector<unsigned char> ParseHex(const std::string& str);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
35
src/zcash/CreateJoinSplit.cpp
Normal file
35
src/zcash/CreateJoinSplit.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2016 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "../util.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "zcash/JoinSplit.hpp"
|
||||
#include "libsnark/common/profiling.hpp"
|
||||
|
||||
using namespace libzcash;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
libsnark::start_profiling();
|
||||
|
||||
auto p = ZCJoinSplit::Unopened();
|
||||
p->loadVerifyingKey((ZC_GetParamsDir() / "sprout-verifying.key").string());
|
||||
p->setProvingKeyPath((ZC_GetParamsDir() / "sprout-proving.key").string());
|
||||
p->loadProvingKey();
|
||||
|
||||
// construct a proof.
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
uint256 anchor = ZCIncrementalMerkleTree().root();
|
||||
uint256 pubKeyHash;
|
||||
|
||||
JSDescription jsdesc(*p,
|
||||
pubKeyHash,
|
||||
anchor,
|
||||
{JSInput(), JSInput()},
|
||||
{JSOutput(), JSOutput()},
|
||||
0,
|
||||
0);
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,25 @@ Hash IncrementalMerkleTree<Depth, Hash>::last() const {
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t Depth, typename Hash>
|
||||
size_t IncrementalMerkleTree<Depth, Hash>::size() const {
|
||||
size_t ret = 0;
|
||||
if (left) {
|
||||
ret++;
|
||||
}
|
||||
if (right) {
|
||||
ret++;
|
||||
}
|
||||
// Treat occupation of parents array as a binary number
|
||||
// (right-shifted by 1)
|
||||
for (size_t i = 0; i < parents.size(); i++) {
|
||||
if (parents[i]) {
|
||||
ret += (1 << (i+1));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<size_t Depth, typename Hash>
|
||||
void IncrementalMerkleTree<Depth, Hash>::append(Hash obj) {
|
||||
if (is_complete(Depth)) {
|
||||
|
||||
@@ -75,6 +75,8 @@ public:
|
||||
parents.size() * 32; // parents
|
||||
}
|
||||
|
||||
size_t size() const;
|
||||
|
||||
void append(Hash obj);
|
||||
Hash root() const {
|
||||
return root(Depth, std::deque<Hash>());
|
||||
|
||||
@@ -163,6 +163,10 @@ curve_G2 CompressedG2::to_libsnark_g2() const
|
||||
|
||||
assert(r.is_well_formed());
|
||||
|
||||
if (alt_bn128_modulus_r * r != curve_G2::zero()) {
|
||||
throw std::runtime_error("point is not in G2");
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,27 @@ double benchmark_create_joinsplit()
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<double> benchmark_create_joinsplit_threaded(int nThreads)
|
||||
{
|
||||
std::vector<double> ret;
|
||||
std::vector<std::future<double>> tasks;
|
||||
std::vector<std::thread> threads;
|
||||
for (int i = 0; i < nThreads; i++) {
|
||||
std::packaged_task<double(void)> task(&benchmark_create_joinsplit);
|
||||
tasks.emplace_back(task.get_future());
|
||||
threads.emplace_back(std::move(task));
|
||||
}
|
||||
std::future_status status;
|
||||
for (auto it = tasks.begin(); it != tasks.end(); it++) {
|
||||
it->wait();
|
||||
ret.push_back(it->get());
|
||||
}
|
||||
for (auto it = threads.begin(); it != threads.end(); it++) {
|
||||
it->join();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
double benchmark_verify_joinsplit(const JSDescription &joinsplit)
|
||||
{
|
||||
struct timeval tv_start;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
extern double benchmark_sleep();
|
||||
extern double benchmark_parameter_loading();
|
||||
extern double benchmark_create_joinsplit();
|
||||
extern std::vector<double> benchmark_create_joinsplit_threaded(int nThreads);
|
||||
extern double benchmark_solve_equihash();
|
||||
extern std::vector<double> benchmark_solve_equihash_threaded(int nThreads);
|
||||
extern double benchmark_verify_joinsplit(const JSDescription &joinsplit);
|
||||
|
||||
Reference in New Issue
Block a user