Merge remote-tracking branch 'zcash/master' into dPoW
This commit is contained in:
@@ -69,17 +69,18 @@ if BUILD_BITCOIN_UTILS
|
||||
bin_PROGRAMS += komodo-cli bitcoin-tx
|
||||
endif
|
||||
|
||||
# TODO: rename to libzcash
|
||||
LIBZCASH_H = \
|
||||
zcash/IncrementalMerkleTree.h \
|
||||
zcash/IncrementalMerkleTree.hpp \
|
||||
zcash/NoteEncryption.hpp \
|
||||
zcash/Address.hpp \
|
||||
zcash/JoinSplit.hpp \
|
||||
zcash/Note.hpp \
|
||||
zcash/prf.h \
|
||||
zcash/util.h
|
||||
zcash/Proof.hpp \
|
||||
zcash/util.h \
|
||||
zcash/Zcash.h
|
||||
|
||||
.PHONY: FORCE check-security
|
||||
.PHONY: FORCE check-symbols check-security
|
||||
# bitcoin core #
|
||||
BITCOIN_CORE_H = \
|
||||
addrman.h \
|
||||
@@ -194,6 +195,7 @@ libbitcoin_server_a_SOURCES = \
|
||||
sendalert.cpp \
|
||||
addrman.cpp \
|
||||
alert.cpp \
|
||||
alertkeys.h \
|
||||
asyncrpcoperation.cpp \
|
||||
asyncrpcqueue.cpp \
|
||||
bloom.cpp \
|
||||
@@ -229,6 +231,7 @@ libbitcoin_server_a_SOURCES = \
|
||||
libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES)
|
||||
libbitcoin_wallet_a_SOURCES = \
|
||||
zcbenchmarks.cpp \
|
||||
zcbenchmarks.h \
|
||||
wallet/asyncrpcoperation_sendmany.cpp \
|
||||
wallet/crypter.cpp \
|
||||
wallet/db.cpp \
|
||||
@@ -246,6 +249,7 @@ crypto_libbitcoin_crypto_a_SOURCES = \
|
||||
crypto/common.h \
|
||||
crypto/equihash.cpp \
|
||||
crypto/equihash.h \
|
||||
crypto/equihash.tcc \
|
||||
crypto/hmac_sha256.cpp \
|
||||
crypto/hmac_sha256.h \
|
||||
crypto/hmac_sha512.cpp \
|
||||
@@ -420,7 +424,13 @@ libzcash_a_SOURCES = \
|
||||
zcash/Proof.cpp \
|
||||
zcash/Note.cpp \
|
||||
zcash/prf.cpp \
|
||||
zcash/util.cpp
|
||||
zcash/util.cpp \
|
||||
zcash/circuit/commitment.tcc \
|
||||
zcash/circuit/gadget.tcc \
|
||||
zcash/circuit/merkle.tcc \
|
||||
zcash/circuit/note.tcc \
|
||||
zcash/circuit/prfs.tcc \
|
||||
zcash/circuit/utils.tcc
|
||||
|
||||
libzcash_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS $(HARDENED_CPPFLAGS) -pipe -O1 -g -Wstack-protector -fstack-protector-all -fPIE -fvisibility=hidden -DSTATIC $(BITCOIN_INCLUDES)
|
||||
|
||||
@@ -482,6 +492,12 @@ clean-local:
|
||||
$(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
check-symbols: $(bin_PROGRAMS)
|
||||
if GLIBC_BACK_COMPAT
|
||||
@echo "Checking glibc back compat of [$(bin_PROGRAMS)]..."
|
||||
$(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py < $(bin_PROGRAMS)
|
||||
endif
|
||||
|
||||
check-security: $(bin_PROGRAMS)
|
||||
if HARDEN
|
||||
@echo "Checking binary security of [$(bin_PROGRAMS)]..."
|
||||
|
||||
@@ -4,10 +4,13 @@ bin_PROGRAMS += komodo-gtest
|
||||
# tool for generating our public parameters
|
||||
komodo_gtest_SOURCES = \
|
||||
gtest/main.cpp \
|
||||
gtest/test_checktransaction.cpp \
|
||||
gtest/json_test_vectors.cpp \
|
||||
gtest/json_test_vectors.h \
|
||||
gtest/test_foundersreward.cpp \
|
||||
gtest/test_wallet_zkeys.cpp \
|
||||
gtest/test_jsonspirit.cpp \
|
||||
gtest/test_tautology.cpp \
|
||||
gtest/test_checktransaction.cpp \
|
||||
gtest/test_equihash.cpp \
|
||||
gtest/test_joinsplit.cpp \
|
||||
gtest/test_keystore.cpp \
|
||||
@@ -17,7 +20,6 @@ komodo_gtest_SOURCES = \
|
||||
gtest/test_rpc.cpp \
|
||||
gtest/test_circuit.cpp \
|
||||
gtest/test_txid.cpp \
|
||||
gtest/test_wallet_zkeys.cpp \
|
||||
gtest/test_libzcash_utils.cpp \
|
||||
gtest/test_proofs.cpp \
|
||||
wallet/gtest/test_wallet.cpp
|
||||
@@ -34,5 +36,5 @@ komodo_gtest_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_L
|
||||
|
||||
komodo_gtest_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
|
||||
|
||||
komodo-gtest_check: komodo-gtest FORCE
|
||||
./komodo-gtest
|
||||
komodo-gtest-expected-failures: komodo-gtest FORCE
|
||||
./komodo-gtest --gtest_filter=*DISABLED_* --gtest_also_run_disabled_tests
|
||||
|
||||
@@ -41,7 +41,7 @@ void CUnsignedAlert::SetNull()
|
||||
|
||||
strComment.clear();
|
||||
strStatusBar.clear();
|
||||
strReserved.clear();
|
||||
strRPCError.clear();
|
||||
}
|
||||
|
||||
std::string CUnsignedAlert::ToString() const
|
||||
@@ -66,6 +66,7 @@ std::string CUnsignedAlert::ToString() const
|
||||
" nPriority = %d\n"
|
||||
" strComment = \"%s\"\n"
|
||||
" strStatusBar = \"%s\"\n"
|
||||
" strRPCError = \"%s\"\n"
|
||||
")\n",
|
||||
nVersion,
|
||||
nRelayUntil,
|
||||
@@ -78,7 +79,8 @@ std::string CUnsignedAlert::ToString() const
|
||||
strSetSubVer,
|
||||
nPriority,
|
||||
strComment,
|
||||
strStatusBar);
|
||||
strStatusBar,
|
||||
strRPCError);
|
||||
}
|
||||
|
||||
void CAlert::SetNull()
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
// Actions
|
||||
std::string strComment;
|
||||
std::string strStatusBar;
|
||||
std::string strReserved;
|
||||
std::string strRPCError;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
|
||||
READWRITE(LIMITED_STRING(strComment, 65536));
|
||||
READWRITE(LIMITED_STRING(strStatusBar, 256));
|
||||
READWRITE(LIMITED_STRING(strReserved, 256));
|
||||
READWRITE(LIMITED_STRING(strRPCError, 256));
|
||||
}
|
||||
|
||||
void SetNull();
|
||||
|
||||
@@ -179,9 +179,9 @@ bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBase58Data::SetString(const std::string& str)
|
||||
bool CBase58Data::SetString(const std::string& str, unsigned int nVersionBytes)
|
||||
{
|
||||
return SetString(str.c_str());
|
||||
return SetString(str.c_str(), nVersionBytes);
|
||||
}
|
||||
|
||||
std::string CBase58Data::ToString() const
|
||||
@@ -251,6 +251,16 @@ bool CBitcoinAddress::IsValid(const CChainParams& params) const
|
||||
return fCorrectSize && fKnownVersion;
|
||||
}
|
||||
|
||||
bool CBitcoinAddress::SetString(const char* pszAddress)
|
||||
{
|
||||
return CBase58Data::SetString(pszAddress, 2);
|
||||
}
|
||||
|
||||
bool CBitcoinAddress::SetString(const std::string& strAddress)
|
||||
{
|
||||
return SetString(strAddress.c_str());
|
||||
}
|
||||
|
||||
CTxDestination CBitcoinAddress::Get() const
|
||||
{
|
||||
if (!IsValid())
|
||||
@@ -305,7 +315,7 @@ bool CBitcoinSecret::IsValid() const
|
||||
|
||||
bool CBitcoinSecret::SetString(const char* pszSecret)
|
||||
{
|
||||
return CBase58Data::SetString(pszSecret) && IsValid();
|
||||
return CBase58Data::SetString(pszSecret, 1) && IsValid();
|
||||
}
|
||||
|
||||
bool CBitcoinSecret::SetString(const std::string& strSecret)
|
||||
@@ -313,21 +323,19 @@ bool CBitcoinSecret::SetString(const std::string& strSecret)
|
||||
return SetString(strSecret.c_str());
|
||||
}
|
||||
|
||||
const size_t serializedPaymentAddressSize = 64;
|
||||
|
||||
bool CZCPaymentAddress::Set(const libzcash::PaymentAddress& addr)
|
||||
{
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << addr;
|
||||
std::vector<unsigned char> addrSerialized(ss.begin(), ss.end());
|
||||
assert(addrSerialized.size() == serializedPaymentAddressSize);
|
||||
SetData(Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS), &addrSerialized[0], serializedPaymentAddressSize);
|
||||
assert(addrSerialized.size() == libzcash::SerializedPaymentAddressSize);
|
||||
SetData(Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS), &addrSerialized[0], libzcash::SerializedPaymentAddressSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
libzcash::PaymentAddress CZCPaymentAddress::Get() const
|
||||
{
|
||||
if (vchData.size() != serializedPaymentAddressSize) {
|
||||
if (vchData.size() != libzcash::SerializedPaymentAddressSize) {
|
||||
throw std::runtime_error(
|
||||
"payment address is invalid"
|
||||
);
|
||||
@@ -347,21 +355,19 @@ libzcash::PaymentAddress CZCPaymentAddress::Get() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
const size_t serializedSpendingKeySize = 32;
|
||||
|
||||
bool CZCSpendingKey::Set(const libzcash::SpendingKey& addr)
|
||||
{
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << addr;
|
||||
std::vector<unsigned char> addrSerialized(ss.begin(), ss.end());
|
||||
assert(addrSerialized.size() == serializedSpendingKeySize);
|
||||
SetData(Params().Base58Prefix(CChainParams::ZCSPENDING_KEY), &addrSerialized[0], serializedSpendingKeySize);
|
||||
assert(addrSerialized.size() == libzcash::SerializedSpendingKeySize);
|
||||
SetData(Params().Base58Prefix(CChainParams::ZCSPENDING_KEY), &addrSerialized[0], libzcash::SerializedSpendingKeySize);
|
||||
return true;
|
||||
}
|
||||
|
||||
libzcash::SpendingKey CZCSpendingKey::Get() const
|
||||
{
|
||||
if (vchData.size() != serializedSpendingKeySize) {
|
||||
if (vchData.size() != libzcash::SerializedSpendingKeySize) {
|
||||
throw std::runtime_error(
|
||||
"spending key is invalid"
|
||||
);
|
||||
|
||||
@@ -84,8 +84,8 @@ protected:
|
||||
void SetData(const std::vector<unsigned char> &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend);
|
||||
|
||||
public:
|
||||
bool SetString(const char* psz, unsigned int nVersionBytes = 1);
|
||||
bool SetString(const std::string& str);
|
||||
bool SetString(const char* psz, unsigned int nVersionBytes);
|
||||
bool SetString(const std::string& str, unsigned int nVersionBytes);
|
||||
std::string ToString() const;
|
||||
int CompareTo(const CBase58Data& b58) const;
|
||||
|
||||
@@ -131,6 +131,8 @@ public:
|
||||
bool Set(const CTxDestination &dest);
|
||||
bool IsValid() const;
|
||||
bool IsValid(const CChainParams ¶ms) const;
|
||||
bool SetString(const char* pszSecret);
|
||||
bool SetString(const std::string& strSecret);
|
||||
|
||||
CBitcoinAddress() {}
|
||||
CBitcoinAddress(const CTxDestination &dest) { Set(dest); }
|
||||
|
||||
10
src/chain.h
10
src/chain.h
@@ -138,6 +138,9 @@ public:
|
||||
//! Verification status of this block. See enum BlockStatus
|
||||
unsigned int nStatus;
|
||||
|
||||
//! The anchor for the tree state up to the start of this block
|
||||
uint256 hashAnchor;
|
||||
|
||||
//! block header
|
||||
int nVersion;
|
||||
uint256 hashMerkleRoot;
|
||||
@@ -163,6 +166,7 @@ public:
|
||||
nTx = 0;
|
||||
nChainTx = 0;
|
||||
nStatus = 0;
|
||||
hashAnchor = uint256();
|
||||
nSequenceId = 0;
|
||||
|
||||
nVersion = 0;
|
||||
@@ -320,6 +324,12 @@ public:
|
||||
READWRITE(VARINT(nDataPos));
|
||||
if (nStatus & BLOCK_HAVE_UNDO)
|
||||
READWRITE(VARINT(nUndoPos));
|
||||
uint8_t tag = 0;
|
||||
READWRITE(tag);
|
||||
if (ser_action.ForRead() && tag != 0) {
|
||||
assert(!"For the first time running zcashd after upgrading to v1.0.0-rc1, please use the -reindex option.");
|
||||
}
|
||||
READWRITE(hashAnchor);
|
||||
|
||||
// block header
|
||||
READWRITE(this->nVersion);
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
#include <boost/assign/list_of.hpp>
|
||||
|
||||
#include "base58.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "chainparamsseeds.h"
|
||||
@@ -131,6 +133,23 @@ public:
|
||||
// (the tx=... number in the SetBestChain debug.log lines)
|
||||
0 // * estimated number of transactions per day after checkpoint
|
||||
};
|
||||
|
||||
// Founders reward script expects a vector of 2-of-3 multisig addresses
|
||||
vFoundersRewardAddress = {
|
||||
"t3QW3CN6TzmTVH8M5E5aJoKzN838zAEBCuS", "t3c6yYJxXBGr3A2KjATDwDsbn8iLP9AsXfk", "t3TuV45WwNVwo3Qc4o2Mr1TenrY9FwRM18Z", "t3hmq4gpfPGhbaRaCsmD2ePidaPxWf3upsg",
|
||||
"t3Y8pxVmXa4URdCWLC4cmeGPQ9nu8eSJMvG", "t3aE5FYLigL7VZw6qjmM6ftjBiAvGiPkjo5", "t3eiUmJQGPykPH8U5gzbPd1SjGDK2k6SFvb", "t3N1ybrjKLyn7q7tpQSRxSZmYp7UgkEgHDb",
|
||||
"t3c8uR6tn6KWwrPWApBXJQuQ6daAr8bcaMg", "t3PGLi4mkL5FkMNjp9ERHtTBQguHPjT3yqA", "t3NYWdEZKfKwvBGCtJM2oMWhy1Rzot3yL3Q", "t3N7PKyV2yQnciu9cx5UbaqDRCVtev9qHpN",
|
||||
"t3YPB1besUqKeEtx9FZX1A6HcXnkXq9Vc3r", "t3UrKCimx2FA9LU4ZMHE5A9dWbxEzm5MgLj", "t3WF7VvMmEh5teWs3WnW6shMqMj3UbX6p33", "t3aBmkm1cZoF5dZuumscMjWviipvSx6hFLR",
|
||||
"t3VMf2EpazVsr4mKy4Gyp9qizCdQLrWTm9J", "t3NtLU7S7fYCtLMCjJHkxGd8kr79w7UhtpX", "t3SwJTa8B4zCEX6fth9BMaejp3pQW11DTB8", "t3PCnGjULLqDUq91XNAwU7aAx6v2WkAP12v",
|
||||
"t3MAXyTGySnb6b3No3LuoVuFL3fY7recEin", "t3hbK2KY4BQ1rQuzwufyxLzSKQQPiP9XidW", "t3aF3uT8jQSmVetYwP5qLAuTnNqWJRNLQu7", "t3PWLsr8ru9MXyq7YWGAHPcY3N9t3Zp45uo",
|
||||
"t3WzEt94EcdNXWjL8sb2KFTawZPUcL42MoX", "t3cjgEXQH2dp4Gozu6Mn45LC5HGfjrSAf9V", "t3ZmskqAyBLXkYBMGfBBpVmR3sNKN79anu3", "t3hGLeywDDaiqBro2Mi2eLD1i8LUttrBfbT",
|
||||
"t3eQdDzPZMdN4vCziFt5zar7qp1XyMwgnD6", "t3PXk3FyBi7q48paPDLtCKdzF1zDS4bpjM3", "t3W65DrnBYmU8DPJgQ44acpz3YPwoNE8pc5", "t3Tj5a6hNPksnpcRSXS2pv1f2mrPtL2bqGb",
|
||||
"t3heu9Ty3XwHAJbux6Bm4MakzS8jUL3EkFD", "t3WFEk3WwAXF6ByHxfLohtz22J1TUwsL6iu", "t3gxDHAf8iW7xBFB7JsScngfJjH6h3QBfot", "t3bn1o8hx4jYjxgC8Pdt6Z6oeFrPQPtT8pC",
|
||||
"t3XHGtWbALCLfY1jAtkUpVELPJMZpqxBtgE", "t3RUBEzMhjHpM2DQLsAmpAm9ZUHUxnEQAtM", "t3KdS1RGsiDXBKebyZvwVE2pfacNj28KLqB", "t3MmVaTutnXLqyD2F6EKnDtCKs38HxkVAdH",
|
||||
"t3LesWouCkeWkwkaQUoGnD4k1pqmn3AYkt4", "t3PmV5vRVByLMTjR1W8ZCp2xy82kpb6n99u", "t3KX34whzndhhxPKJwAyETkeVA2Q1TzBhor", "t3SPSmxWnzNYr7WQooNxkHMhVYdAKY6M5Dr",
|
||||
"t3KpcuJDA82TZhJoygng6eq72LWBCYtp7W8", "t3cHewjCnajURPGXA74kdLUkcqtRWpN3QkG", "t3a3zS49EqTFJWfDgNQhTNNFjkkhveqQssP", "t3eunPgNGpcSqEUSgAwip3Mm5nYQcPvacvX",
|
||||
};
|
||||
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight());
|
||||
}
|
||||
};
|
||||
static CMainParams mainParams;
|
||||
@@ -195,6 +214,22 @@ public:
|
||||
0
|
||||
};
|
||||
|
||||
// Founders reward script expects a vector of 2-of-3 multisig addresses
|
||||
vFoundersRewardAddress = {
|
||||
"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", "t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543", "t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2", "t27ktmq1kbeCWiQ5TZ7w5npSzcdbBmTB7v6",
|
||||
"t2GcBttAKD2WTHka8HyGc2dfvVTKYZUfHmJ", "t2Q3vxWaD9LrdqUE8Xd9Ddjpr9pUQ2aGotK", "t2TTfWDsYu998fHWzVP9Gns4fgxXXRi1Wzu", "t2KS6R4MMWdSBMjLCiw2iMyhWGRQPmyRqDn",
|
||||
"t2Q2ELrgotWv3Eec6LEtMMiiQ8dtW38u8Tj", "t2AEgJA88vTWAKqxJDFUEJWyHUtQAZi5G1D", "t2HCSdmpq1TQKksuwPQevwAzPTgfJ2rkMbG", "t2HQCPFAUQaUdJWHPhg5pPBxit7inaJzubE",
|
||||
"t2Fzqvq8Y9e6Mn3JNPb982aYsLmq4b5HmhH", "t2HEz7YZQqDUgC5h4y2WSD3mWneqJNVRjjJ", "t2GCR1SCk687Eeo5NEZ23MLsms7JjVWBgfG", "t2KyiPR9Lztq2w1w747X6W4nkUMAGL8M9KN",
|
||||
"t2UxymadyxSyVihmbq7S1yxw5dCBqJ1S4jT", "t2AVeMy7fdmTcJhckqiKRG8B7F1vccEhSqU", "t26m7LwihQzD2sH7ZVhYpPJM5j7kzwbfKW9", "t2DgwUNTe7NxuyPU6fxsB5xJXap3E4yWXrN",
|
||||
"t2U6funcXA11fC9SZehyvUL3rk3Vhuh7fzS", "t284JhyS8LGM72Tx1porSqwrcq3CejthP1p", "t29egu8QcpzKeLoPLqWS6QVMnUUPQdF6eNm", "t29LqD9p9D3B26euBwFi6mfcWu8HPA38VNs",
|
||||
"t28GsAMCxAyLy85XaasddDzaYFTtfewr86y", "t2GV44QyaikQPLUfm6oTfZnw71LLjnR7gDG", "t2U2QzNLQ1jtAu4L6xxVnRXLBsQpQvGRR2g", "t2QKGr5PNan7nrwDgseyHMN9NFeeuUjCh8b",
|
||||
"t2AfS8u6HwBeJpKpbuxztvRjupKQDXqnrwa", "t2CTRQUViQd3CWMhnKhFnUHqDLUyTxmWhJs", "t2CbM9EqszNURqh1UXZBXYhwp1R4GwEhWRE", "t2LM7uYiAsKDU42GNSnMwDxbZ8s1DowQzYH",
|
||||
"t2AgvT35LHR378AE3ouz6xKMhkTLHLJC6nD", "t285EAQXUVyi4NMddJv2QqTrnv45GRMbP8e", "t2EpMRCD5b8f2DCQ37npNULcpZhkjC8muqA", "t2BCmWXrRPiCeQTpizSWKKRPM5X6PS7umDY",
|
||||
"t2DN7X6wDFn5hYKBiBmn3Z98st419yaTVTH", "t2QJj8HeCwQ6mHwqekxxDLZntYpZTHNU62t", "t2QdHBR1Yciqn4j8gpS8DcQZZtYetKvfNj3", "t2E5cpLA1ey5VNxFNcuopeQMq2rH2NHiPdu",
|
||||
"t2EVRGtzjFAyz8CF8ndvLuiJu7qZUfDa93H", "t2KoQDk3BSFadBkuaWdLwchFuQamzw9RE4L", "t2FnR3yhTmuiejEJeu6qpidWTghRd1HpjLt", "t2BAuBAAospDc9d1u5nNGEi6x4NRJBD2PQ2",
|
||||
"t2RtKrLCGcyPkm4a4APg1YY9Wu2m4R2PgrB", "t28aUbSteZzBq2pFgj1K1XNZRZP5mMMyakV", "t2Urdy1ERfkvsFuy6Z4BkhvYGzWdmivfAFR", "t2ADinR4JrvCMd4Q1XGALPajzFrirqvhED6",
|
||||
};
|
||||
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight());
|
||||
}
|
||||
};
|
||||
static CTestNetParams testNetParams;
|
||||
@@ -252,6 +287,10 @@ public:
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
// Founders reward script expects a vector of 2-of-3 multisig addresses
|
||||
vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" };
|
||||
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight());
|
||||
}
|
||||
};
|
||||
static CRegTestParams regTestParams;
|
||||
@@ -280,6 +319,11 @@ CChainParams &Params(CBaseChainParams::Network network) {
|
||||
void SelectParams(CBaseChainParams::Network network) {
|
||||
SelectBaseParams(network);
|
||||
pCurrentParams = &Params(network);
|
||||
|
||||
// Some python qa rpc tests need to enforce the coinbase consensus rule
|
||||
if (network == CBaseChainParams::REGTEST && mapArgs.count("-regtestprotectcoinbase")) {
|
||||
regTestParams.SetRegTestCoinbaseMustBeProtected();
|
||||
}
|
||||
}
|
||||
|
||||
bool SelectParamsFromCommandLine()
|
||||
@@ -291,3 +335,41 @@ bool SelectParamsFromCommandLine()
|
||||
SelectParams(network);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Block height must be >0 and <=last founders reward block height
|
||||
// Index variable i ranges from 0 - (vFoundersRewardAddress.size()-1)
|
||||
std::string CChainParams::GetFoundersRewardAddressAtHeight(int nHeight) const {
|
||||
int maxHeight = consensus.GetLastFoundersRewardBlockHeight();
|
||||
assert(nHeight > 0 && nHeight <= maxHeight);
|
||||
|
||||
size_t addressChangeInterval = (maxHeight + vFoundersRewardAddress.size()) / vFoundersRewardAddress.size();
|
||||
size_t i = nHeight / addressChangeInterval;
|
||||
return vFoundersRewardAddress[i];
|
||||
}
|
||||
|
||||
// Block height must be >0 and <=last founders reward block height
|
||||
// The founders reward address is expected to be a multisig (P2SH) address
|
||||
CScript CChainParams::GetFoundersRewardScriptAtHeight(int nHeight) const {
|
||||
assert(nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight());
|
||||
|
||||
// #1398 START
|
||||
// We can remove this code when miner_tests no longer expect this script
|
||||
if (fMinerTestModeForFoundersRewardScript) {
|
||||
auto rewardScript = ParseHex("a9146708e6670db0b950dac68031025cc5b63213a49187");
|
||||
return CScript(rewardScript.begin(), rewardScript.end());
|
||||
}
|
||||
// #1398 END
|
||||
|
||||
CBitcoinAddress address(GetFoundersRewardAddressAtHeight(nHeight).c_str());
|
||||
assert(address.IsValid());
|
||||
assert(address.IsScript());
|
||||
CScriptID scriptID = get<CScriptID>(address.Get()); // Get() returns a boost variant
|
||||
CScript script = CScript() << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
|
||||
return script;
|
||||
}
|
||||
|
||||
std::string CChainParams::GetFoundersRewardAddressAtIndex(int i) const {
|
||||
assert(i >= 0 && i < vFoundersRewardAddress.size());
|
||||
return vFoundersRewardAddress[i];
|
||||
}
|
||||
|
||||
@@ -79,6 +79,14 @@ public:
|
||||
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
|
||||
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
|
||||
const Checkpoints::CCheckpointData& Checkpoints() const { return checkpointData; }
|
||||
/** Return the founder's reward address and script for a given block height */
|
||||
std::string GetFoundersRewardAddressAtHeight(int height) const;
|
||||
CScript GetFoundersRewardScriptAtHeight(int height) const;
|
||||
std::string GetFoundersRewardAddressAtIndex(int i) const;
|
||||
/** #1398 to return a fixed founders reward script for miner_tests */
|
||||
bool fMinerTestModeForFoundersRewardScript = false;
|
||||
/** Enforce coinbase consensus rule in regtest mode */
|
||||
void SetRegTestCoinbaseMustBeProtected() { consensus.fCoinbaseMustBeProtected = true; }
|
||||
protected:
|
||||
CChainParams() {}
|
||||
|
||||
@@ -104,6 +112,7 @@ protected:
|
||||
bool fMineBlocksOnDemand;
|
||||
bool fTestnetToBeDeprecatedFieldRPC;
|
||||
Checkpoints::CCheckpointData checkpointData;
|
||||
std::vector<std::string> vFoundersRewardAddress;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,12 +8,18 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/preprocessor/arithmetic/add.hpp>
|
||||
#include <boost/preprocessor/arithmetic/sub.hpp>
|
||||
#include <boost/preprocessor/comparison/equal.hpp>
|
||||
#include <boost/preprocessor/comparison/less.hpp>
|
||||
#include <boost/preprocessor/control/if.hpp>
|
||||
|
||||
/**
|
||||
* Name of client reported in the 'version' message. Report the same name
|
||||
* for both bitcoind and bitcoin-core, to make it harder for attackers to
|
||||
* target servers or GUI users specifically.
|
||||
*/
|
||||
const std::string CLIENT_NAME("Satoshi");
|
||||
const std::string CLIENT_NAME("MagicBean");
|
||||
|
||||
/**
|
||||
* Client version number
|
||||
@@ -48,14 +54,30 @@ const std::string CLIENT_NAME("Satoshi");
|
||||
#define GIT_COMMIT_DATE "$Format:%cD$"
|
||||
#endif
|
||||
|
||||
#define RENDER_BETA_STRING(num) "-beta" DO_STRINGIZE(num)
|
||||
#define RENDER_RC_STRING(num) "-rc" DO_STRINGIZE(num)
|
||||
#define RENDER_DEV_STRING(num) "-" DO_STRINGIZE(num)
|
||||
|
||||
#define RENDER_BUILD(build) \
|
||||
BOOST_PP_IF( \
|
||||
BOOST_PP_LESS(build, 25), \
|
||||
RENDER_BETA_STRING(BOOST_PP_ADD(build, 1)), \
|
||||
BOOST_PP_IF( \
|
||||
BOOST_PP_LESS(build, 50), \
|
||||
RENDER_RC_STRING(BOOST_PP_SUB(build, 24)), \
|
||||
BOOST_PP_IF( \
|
||||
BOOST_PP_EQUAL(build, 50), \
|
||||
"", \
|
||||
RENDER_DEV_STRING(BOOST_PP_SUB(build, 50)))))
|
||||
|
||||
#define BUILD_DESC_WITH_SUFFIX(maj, min, rev, build, suffix) \
|
||||
"v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-" DO_STRINGIZE(suffix)
|
||||
"v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) RENDER_BUILD(build) "-" DO_STRINGIZE(suffix)
|
||||
|
||||
#define BUILD_DESC_FROM_COMMIT(maj, min, rev, build, commit) \
|
||||
"v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-g" commit
|
||||
"v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) RENDER_BUILD(build) "-g" commit
|
||||
|
||||
#define BUILD_DESC_FROM_UNKNOWN(maj, min, rev, build) \
|
||||
"v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-unk"
|
||||
"v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) RENDER_BUILD(build) "-unk"
|
||||
|
||||
#ifndef BUILD_DESC
|
||||
#ifdef BUILD_SUFFIX
|
||||
@@ -80,10 +102,14 @@ const std::string CLIENT_DATE(BUILD_DATE);
|
||||
|
||||
static std::string FormatVersion(int nVersion)
|
||||
{
|
||||
if (nVersion % 100 == 0)
|
||||
if (nVersion % 100 < 25)
|
||||
return strprintf("%d.%d.%d-beta%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100, (nVersion % 100)+1);
|
||||
if (nVersion % 100 < 50)
|
||||
return strprintf("%d.%d.%d-rc%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100, (nVersion % 100)-24);
|
||||
else if (nVersion % 100 == 50)
|
||||
return strprintf("%d.%d.%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100);
|
||||
else
|
||||
return strprintf("%d.%d.%d.%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100, nVersion % 100);
|
||||
return strprintf("%d.%d.%d-%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100, (nVersion % 100)-50);
|
||||
}
|
||||
|
||||
std::string FormatFullVersion()
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#define CLIENT_VERSION_MAJOR 1
|
||||
#define CLIENT_VERSION_MINOR 0
|
||||
#define CLIENT_VERSION_REVISION 0
|
||||
#define CLIENT_VERSION_BUILD 0
|
||||
#define CLIENT_VERSION_BUILD 1
|
||||
|
||||
//! Set to true for release, false for prerelease or test build
|
||||
#define CLIENT_VERSION_IS_RELEASE false
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
static const unsigned int MAX_BLOCK_SIZE = 2000000;
|
||||
/** The maximum allowed number of signature check operations in a block (network rule) */
|
||||
static const unsigned int MAX_BLOCK_SIGOPS = 20000;
|
||||
/** The maximum size of a transaction (network rule) */
|
||||
static const unsigned int MAX_TX_SIZE = 100000;
|
||||
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
|
||||
static const int COINBASE_MATURITY = 100;
|
||||
|
||||
|
||||
@@ -32,6 +32,9 @@ struct Params {
|
||||
*/
|
||||
int SubsidySlowStartShift() const { return nSubsidySlowStartInterval / 2; }
|
||||
int nSubsidyHalvingInterval;
|
||||
int GetLastFoundersRewardBlockHeight() const {
|
||||
return nSubsidyHalvingInterval + SubsidySlowStartShift() - 1;
|
||||
}
|
||||
/** Used to check majorities for block version upgrade */
|
||||
int nMajorityEnforceBlockUpgrade;
|
||||
int nMajorityRejectBlockOutdated;
|
||||
|
||||
@@ -742,8 +742,8 @@ bool Equihash<N,K>::IsValidSolution(const eh_HashState& base_state, std::vector<
|
||||
return false;
|
||||
}
|
||||
if (X[i+1].IndicesBefore(X[i], hashLen, lenIndices)) {
|
||||
return false;
|
||||
LogPrint("pow", "Invalid solution: Index tree incorrectly ordered\n");
|
||||
return false;
|
||||
}
|
||||
if (!DistinctIndices(X[i], X[i+1], hashLen, lenIndices)) {
|
||||
LogPrint("pow", "Invalid solution: duplicate indices\n");
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "uint256.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
|
||||
namespace {
|
||||
@@ -62,6 +61,9 @@ int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned ch
|
||||
int n = 0;
|
||||
int i = recid / 2;
|
||||
|
||||
const BIGNUM *sig_r, *sig_s;
|
||||
ECDSA_SIG_get0(ecsig, &sig_r, &sig_s);
|
||||
|
||||
const EC_GROUP *group = EC_KEY_get0_group(eckey);
|
||||
if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
|
||||
BN_CTX_start(ctx);
|
||||
@@ -70,7 +72,7 @@ int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned ch
|
||||
x = BN_CTX_get(ctx);
|
||||
if (!BN_copy(x, order)) { ret=-1; goto err; }
|
||||
if (!BN_mul_word(x, i)) { ret=-1; goto err; }
|
||||
if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; }
|
||||
if (!BN_add(x, x, sig_r)) { ret=-1; goto err; }
|
||||
field = BN_CTX_get(ctx);
|
||||
if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
|
||||
if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
|
||||
@@ -91,9 +93,9 @@ int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned ch
|
||||
if (!BN_zero(zero)) { ret=-1; goto err; }
|
||||
if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
|
||||
rr = BN_CTX_get(ctx);
|
||||
if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; }
|
||||
if (!BN_mod_inverse(rr, sig_r, order, ctx)) { ret=-1; goto err; }
|
||||
sor = BN_CTX_get(ctx);
|
||||
if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; }
|
||||
if (!BN_mod_mul(sor, sig_s, rr, order, ctx)) { ret=-1; goto err; }
|
||||
eor = BN_CTX_get(ctx);
|
||||
if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
|
||||
if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
|
||||
@@ -177,9 +179,12 @@ bool CECKey::Recover(const uint256 &hash, const unsigned char *p64, int rec)
|
||||
if (rec<0 || rec>=3)
|
||||
return false;
|
||||
ECDSA_SIG *sig = ECDSA_SIG_new();
|
||||
BN_bin2bn(&p64[0], 32, sig->r);
|
||||
BN_bin2bn(&p64[32], 32, sig->s);
|
||||
bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
|
||||
BIGNUM *sig_r = BN_bin2bn(&p64[0], 32, nullptr);
|
||||
BIGNUM *sig_s = BN_bin2bn(&p64[32], 32, nullptr);
|
||||
assert(sig && sig_r && sig_s);
|
||||
bool ret = ECDSA_SIG_set0(sig, sig_r, sig_s);
|
||||
assert(ret);
|
||||
ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
|
||||
ECDSA_SIG_free(sig);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -121,17 +121,30 @@ TEST(checktransaction_tests, bad_txns_oversize) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
|
||||
mtx.vin[0].scriptSig = CScript();
|
||||
// 18 * (520char + DROP) + OP_1 = 9433 bytes
|
||||
std::vector<unsigned char> vchData(520);
|
||||
for (unsigned int i = 0; i < 4000; ++i)
|
||||
for (unsigned int i = 0; i < 190; ++i)
|
||||
mtx.vin[0].scriptSig << vchData << OP_DROP;
|
||||
mtx.vin[0].scriptSig << OP_1;
|
||||
|
||||
CTransaction tx(mtx);
|
||||
{
|
||||
// Transaction is just under the limit...
|
||||
CTransaction tx(mtx);
|
||||
CValidationState state;
|
||||
ASSERT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
|
||||
}
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-oversize", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
// Not anymore!
|
||||
mtx.vin[1].scriptSig << vchData << OP_DROP;
|
||||
mtx.vin[1].scriptSig << OP_1;
|
||||
|
||||
{
|
||||
CTransaction tx(mtx);
|
||||
ASSERT_EQ(::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION), 100202);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-oversize", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_vout_negative) {
|
||||
|
||||
180
src/gtest/test_foundersreward.cpp
Normal file
180
src/gtest/test_foundersreward.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "utilmoneystr.h"
|
||||
#include "chainparams.h"
|
||||
#include "utilstrencodings.h"
|
||||
#include "zcash/Address.hpp"
|
||||
#include "wallet/wallet.h"
|
||||
#include "amount.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "util.h"
|
||||
|
||||
// To run tests:
|
||||
// ./zcash-gtest --gtest_filter="founders_reward_test.*"
|
||||
|
||||
//
|
||||
// Enable this test to generate and print 48 testnet 2-of-3 multisig addresses.
|
||||
// The output can be copied into chainparams.cpp.
|
||||
// The temporary wallet file can be renamed as wallet.dat and used for testing with zcashd.
|
||||
//
|
||||
#if 0
|
||||
TEST(founders_reward_test, create_testnet_2of3multisig) {
|
||||
ECC_Start();
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
boost::filesystem::create_directories(pathTemp);
|
||||
mapArgs["-datadir"] = pathTemp.string();
|
||||
bool fFirstRun;
|
||||
auto pWallet = std::make_shared<CWallet>("wallet.dat");
|
||||
ASSERT_EQ(DB_LOAD_OK, pWallet->LoadWallet(fFirstRun));
|
||||
pWallet->TopUpKeyPool();
|
||||
std::cout << "Test wallet and logs saved in folder: " << pathTemp.native() << std::endl;
|
||||
|
||||
int numKeys = 48;
|
||||
std::vector<CPubKey> pubkeys;
|
||||
pubkeys.resize(3);
|
||||
CPubKey newKey;
|
||||
std::vector<std::string> addresses;
|
||||
for (int i = 0; i < numKeys; i++) {
|
||||
ASSERT_TRUE(pWallet->GetKeyFromPool(newKey));
|
||||
pubkeys[0] = newKey;
|
||||
ASSERT_TRUE(pWallet->GetKeyFromPool(newKey));
|
||||
pubkeys[1] = newKey;
|
||||
ASSERT_TRUE(pWallet->GetKeyFromPool(newKey));
|
||||
pubkeys[2] = newKey;
|
||||
CScript result = GetScriptForMultisig(2, pubkeys);
|
||||
ASSERT_FALSE(result.size() > MAX_SCRIPT_ELEMENT_SIZE);
|
||||
CScriptID innerID(result);
|
||||
std::string address = CBitcoinAddress(innerID).ToString();
|
||||
addresses.push_back(address);
|
||||
}
|
||||
|
||||
// Print out the addresses, 4 on each line.
|
||||
std::string s = "vFoundersRewardAddress = {\n";
|
||||
int i=0;
|
||||
int colsPerRow = 4;
|
||||
ASSERT_TRUE(numKeys % colsPerRow == 0);
|
||||
int numRows = numKeys/colsPerRow;
|
||||
for (int row=0; row<numRows; row++) {
|
||||
s += " ";
|
||||
for (int col=0; col<colsPerRow; col++) {
|
||||
s += "\"" + addresses[i++] + "\", ";
|
||||
}
|
||||
s += "\n";
|
||||
}
|
||||
s += " };";
|
||||
std::cout << s << std::endl;
|
||||
|
||||
pWallet->Flush(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Utility method to check the number of unique addresses from height 1 to maxHeight
|
||||
void checkNumberOfUniqueAddresses(int nUnique) {
|
||||
int maxHeight = Params().GetConsensus().GetLastFoundersRewardBlockHeight();
|
||||
std::set<std::string> addresses;
|
||||
for (int i = 1; i <= maxHeight; i++) {
|
||||
addresses.insert(Params().GetFoundersRewardAddressAtHeight(i));
|
||||
}
|
||||
ASSERT_TRUE(addresses.size() == nUnique);
|
||||
}
|
||||
|
||||
|
||||
TEST(founders_reward_test, general) {
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
|
||||
CChainParams params = Params();
|
||||
|
||||
// First testnet reward:
|
||||
// address = t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi
|
||||
// script = OP_HASH160 ef775f1f997f122a062fff1a2d7443abd1f9c642 OP_EQUAL
|
||||
// raw script = a914ef775f1f997f122a062fff1a2d7443abd1f9c64287
|
||||
EXPECT_EQ(params.GetFoundersRewardScriptAtHeight(1), ParseHex("a914ef775f1f997f122a062fff1a2d7443abd1f9c64287"));
|
||||
EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(1), "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi");
|
||||
|
||||
int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight();
|
||||
|
||||
// If the block height parameter is out of bounds, there is an assert.
|
||||
EXPECT_DEATH(params.GetFoundersRewardScriptAtHeight(0), "nHeight");
|
||||
EXPECT_DEATH(params.GetFoundersRewardScriptAtHeight(maxHeight+1), "nHeight");
|
||||
EXPECT_DEATH(params.GetFoundersRewardAddressAtHeight(0), "nHeight");
|
||||
EXPECT_DEATH(params.GetFoundersRewardAddressAtHeight(maxHeight+1), "nHeight");
|
||||
}
|
||||
|
||||
|
||||
#define NUM_MAINNET_FOUNDER_ADDRESSES 48
|
||||
|
||||
TEST(founders_reward_test, mainnet) {
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
checkNumberOfUniqueAddresses(NUM_MAINNET_FOUNDER_ADDRESSES);
|
||||
}
|
||||
|
||||
|
||||
#define NUM_TESTNET_FOUNDER_ADDRESSES 48
|
||||
|
||||
TEST(founders_reward_test, testnet) {
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
checkNumberOfUniqueAddresses(NUM_TESTNET_FOUNDER_ADDRESSES);
|
||||
}
|
||||
|
||||
|
||||
#define NUM_REGTEST_FOUNDER_ADDRESSES 1
|
||||
|
||||
TEST(founders_reward_test, regtest) {
|
||||
SelectParams(CBaseChainParams::REGTEST);
|
||||
checkNumberOfUniqueAddresses(NUM_REGTEST_FOUNDER_ADDRESSES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Test that 10% founders reward is fully rewarded after the first halving and slow start shift.
|
||||
// On Mainnet, this would be 2,100,000 ZEC after 850,000 blocks (840,000 + 10,000).
|
||||
TEST(founders_reward_test, slow_start_subsidy) {
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
CChainParams params = Params();
|
||||
|
||||
int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight();
|
||||
CAmount totalSubsidy = 0;
|
||||
for (int nHeight = 1; nHeight <= maxHeight; nHeight++) {
|
||||
CAmount nSubsidy = GetBlockSubsidy(nHeight, params.GetConsensus()) / 5;
|
||||
totalSubsidy += nSubsidy;
|
||||
}
|
||||
|
||||
ASSERT_TRUE(totalSubsidy == MAX_MONEY/10.0);
|
||||
}
|
||||
|
||||
|
||||
// For use with mainnet and testnet which each have 48 addresses.
|
||||
// Verify the number of rewards each individual address receives.
|
||||
void verifyNumberOfRewards() {
|
||||
CChainParams params = Params();
|
||||
int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight();
|
||||
std::multiset<std::string> ms;
|
||||
for (int nHeight = 1; nHeight <= maxHeight; nHeight++) {
|
||||
ms.insert(params.GetFoundersRewardAddressAtHeight(nHeight));
|
||||
}
|
||||
|
||||
ASSERT_TRUE(ms.count(params.GetFoundersRewardAddressAtIndex(0)) == 17708);
|
||||
for (int i = 1; i <= 46; i++) {
|
||||
ASSERT_TRUE(ms.count(params.GetFoundersRewardAddressAtIndex(i)) == 17709);
|
||||
}
|
||||
ASSERT_TRUE(ms.count(params.GetFoundersRewardAddressAtIndex(47)) == 17677);
|
||||
}
|
||||
|
||||
// Verify the number of rewards going to each mainnet address
|
||||
TEST(founders_reward_test, per_address_reward_mainnet) {
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
verifyNumberOfRewards();
|
||||
}
|
||||
|
||||
// Verify the number of rewards going to each testnet address
|
||||
TEST(founders_reward_test, per_address_reward_testnet) {
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
verifyNumberOfRewards();
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "keystore.h"
|
||||
#include "random.h"
|
||||
#include "wallet/crypter.h"
|
||||
#include "zcash/Address.hpp"
|
||||
|
||||
TEST(keystore_tests, store_and_retrieve_spending_key) {
|
||||
@@ -41,3 +43,85 @@ TEST(keystore_tests, store_and_retrieve_note_decryptor) {
|
||||
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
|
||||
EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut);
|
||||
}
|
||||
|
||||
class TestCCryptoKeyStore : public CCryptoKeyStore
|
||||
{
|
||||
public:
|
||||
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn) { return CCryptoKeyStore::EncryptKeys(vMasterKeyIn); }
|
||||
bool Unlock(const CKeyingMaterial& vMasterKeyIn) { return CCryptoKeyStore::Unlock(vMasterKeyIn); }
|
||||
};
|
||||
|
||||
TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) {
|
||||
TestCCryptoKeyStore keyStore;
|
||||
uint256 r {GetRandHash()};
|
||||
CKeyingMaterial vMasterKey (r.begin(), r.end());
|
||||
libzcash::SpendingKey keyOut;
|
||||
ZCNoteDecryption decOut;
|
||||
std::set<libzcash::PaymentAddress> addrs;
|
||||
|
||||
// 1) Test adding a key to an unencrypted key store, then encrypting it
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
auto addr = sk.address();
|
||||
EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut));
|
||||
|
||||
keyStore.AddSpendingKey(sk);
|
||||
ASSERT_TRUE(keyStore.HaveSpendingKey(addr));
|
||||
ASSERT_TRUE(keyStore.GetSpendingKey(addr, keyOut));
|
||||
ASSERT_EQ(sk, keyOut);
|
||||
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
|
||||
EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut);
|
||||
|
||||
ASSERT_TRUE(keyStore.EncryptKeys(vMasterKey));
|
||||
ASSERT_TRUE(keyStore.HaveSpendingKey(addr));
|
||||
ASSERT_FALSE(keyStore.GetSpendingKey(addr, keyOut));
|
||||
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
|
||||
EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut);
|
||||
|
||||
// Unlocking with a random key should fail
|
||||
uint256 r2 {GetRandHash()};
|
||||
CKeyingMaterial vRandomKey (r2.begin(), r2.end());
|
||||
EXPECT_FALSE(keyStore.Unlock(vRandomKey));
|
||||
|
||||
// Unlocking with a slightly-modified vMasterKey should fail
|
||||
CKeyingMaterial vModifiedKey (r.begin(), r.end());
|
||||
vModifiedKey[0] += 1;
|
||||
EXPECT_FALSE(keyStore.Unlock(vModifiedKey));
|
||||
|
||||
// Unlocking with vMasterKey should succeed
|
||||
ASSERT_TRUE(keyStore.Unlock(vMasterKey));
|
||||
ASSERT_TRUE(keyStore.GetSpendingKey(addr, keyOut));
|
||||
ASSERT_EQ(sk, keyOut);
|
||||
|
||||
keyStore.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(1, addrs.size());
|
||||
ASSERT_EQ(1, addrs.count(addr));
|
||||
|
||||
// 2) Test adding a spending key to an already-encrypted key store
|
||||
auto sk2 = libzcash::SpendingKey::random();
|
||||
auto addr2 = sk2.address();
|
||||
EXPECT_FALSE(keyStore.GetNoteDecryptor(addr2, decOut));
|
||||
|
||||
keyStore.AddSpendingKey(sk2);
|
||||
ASSERT_TRUE(keyStore.HaveSpendingKey(addr2));
|
||||
ASSERT_TRUE(keyStore.GetSpendingKey(addr2, keyOut));
|
||||
ASSERT_EQ(sk2, keyOut);
|
||||
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
|
||||
EXPECT_EQ(ZCNoteDecryption(sk2.viewing_key()), decOut);
|
||||
|
||||
ASSERT_TRUE(keyStore.Lock());
|
||||
ASSERT_TRUE(keyStore.HaveSpendingKey(addr2));
|
||||
ASSERT_FALSE(keyStore.GetSpendingKey(addr2, keyOut));
|
||||
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
|
||||
EXPECT_EQ(ZCNoteDecryption(sk2.viewing_key()), decOut);
|
||||
|
||||
ASSERT_TRUE(keyStore.Unlock(vMasterKey));
|
||||
ASSERT_TRUE(keyStore.GetSpendingKey(addr2, keyOut));
|
||||
ASSERT_EQ(sk2, keyOut);
|
||||
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
|
||||
EXPECT_EQ(ZCNoteDecryption(sk2.viewing_key()), decOut);
|
||||
|
||||
keyStore.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(2, addrs.size());
|
||||
ASSERT_EQ(1, addrs.count(addr));
|
||||
ASSERT_EQ(1, addrs.count(addr2));
|
||||
}
|
||||
|
||||
@@ -3,3 +3,8 @@
|
||||
TEST(tautologies, seven_eq_seven) {
|
||||
ASSERT_EQ(7, 7);
|
||||
}
|
||||
|
||||
TEST(tautologies, DISABLED_ObviousFailure)
|
||||
{
|
||||
FAIL() << "This is expected";
|
||||
}
|
||||
|
||||
@@ -75,12 +75,12 @@ TEST(wallet_zkeys_tests, write_zkey_direct_to_db) {
|
||||
|
||||
// Get temporary and unique path for file.
|
||||
// Note: / operator to append paths
|
||||
boost::filesystem::path temp = boost::filesystem::temp_directory_path() /
|
||||
boost::filesystem::unique_path();
|
||||
const std::string path = temp.native();
|
||||
boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
boost::filesystem::create_directories(pathTemp);
|
||||
mapArgs["-datadir"] = pathTemp.string();
|
||||
|
||||
bool fFirstRun;
|
||||
CWallet wallet(path);
|
||||
CWallet wallet("wallet.dat");
|
||||
ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun));
|
||||
|
||||
// No default CPubKey set
|
||||
@@ -103,7 +103,7 @@ TEST(wallet_zkeys_tests, write_zkey_direct_to_db) {
|
||||
auto addr = sk.address();
|
||||
int64_t now = GetTime();
|
||||
CKeyMetadata meta(now);
|
||||
CWalletDB db(path);
|
||||
CWalletDB db("wallet.dat");
|
||||
db.WriteZKey(addr, sk, meta);
|
||||
|
||||
// wallet should not be aware of key
|
||||
@@ -138,3 +138,81 @@ TEST(wallet_zkeys_tests, write_zkey_direct_to_db) {
|
||||
ASSERT_EQ(m.nCreateTime, now);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This test covers methods on CWalletDB to load/save crypted z keys.
|
||||
*/
|
||||
TEST(wallet_zkeys_tests, write_cryptedzkey_direct_to_db) {
|
||||
ECC_Start();
|
||||
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
|
||||
// Get temporary and unique path for file.
|
||||
// Note: / operator to append paths
|
||||
boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
boost::filesystem::create_directories(pathTemp);
|
||||
mapArgs["-datadir"] = pathTemp.string();
|
||||
|
||||
bool fFirstRun;
|
||||
CWallet wallet("wallet_crypted.dat");
|
||||
ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun));
|
||||
|
||||
// No default CPubKey set
|
||||
ASSERT_TRUE(fFirstRun);
|
||||
|
||||
// wallet should be empty
|
||||
std::set<libzcash::PaymentAddress> addrs;
|
||||
wallet.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(0, addrs.size());
|
||||
|
||||
// Add random key to the wallet
|
||||
auto paymentAddress = wallet.GenerateNewZKey();
|
||||
|
||||
// wallet should have one key
|
||||
wallet.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(1, addrs.size());
|
||||
|
||||
// encrypt wallet
|
||||
SecureString strWalletPass;
|
||||
strWalletPass.reserve(100);
|
||||
strWalletPass = "hello";
|
||||
ASSERT_TRUE(wallet.EncryptWallet(strWalletPass));
|
||||
|
||||
// adding a new key will fail as the wallet is locked
|
||||
EXPECT_ANY_THROW(wallet.GenerateNewZKey());
|
||||
|
||||
// unlock wallet and then add
|
||||
wallet.Unlock(strWalletPass);
|
||||
auto paymentAddress2 = wallet.GenerateNewZKey();
|
||||
|
||||
// Create a new wallet from the existing wallet path
|
||||
CWallet wallet2("wallet_crypted.dat");
|
||||
ASSERT_EQ(DB_LOAD_OK, wallet2.LoadWallet(fFirstRun));
|
||||
|
||||
// Confirm it's not the same as the other wallet
|
||||
ASSERT_TRUE(&wallet != &wallet2);
|
||||
|
||||
// wallet should have two keys
|
||||
wallet2.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(2, addrs.size());
|
||||
|
||||
// check we have entries for our payment addresses
|
||||
ASSERT_TRUE(addrs.count(paymentAddress.Get()));
|
||||
ASSERT_TRUE(addrs.count(paymentAddress2.Get()));
|
||||
|
||||
// spending key is crypted, so we can't extract valid payment address
|
||||
libzcash::SpendingKey keyOut;
|
||||
wallet2.GetSpendingKey(paymentAddress.Get(), keyOut);
|
||||
ASSERT_FALSE(paymentAddress.Get() == keyOut.address());
|
||||
|
||||
// unlock wallet to get spending keys and verify payment addresses
|
||||
wallet2.Unlock(strWalletPass);
|
||||
|
||||
wallet2.GetSpendingKey(paymentAddress.Get(), keyOut);
|
||||
ASSERT_EQ(paymentAddress.Get(), keyOut.address());
|
||||
|
||||
wallet2.GetSpendingKey(paymentAddress2.Get(), keyOut);
|
||||
ASSERT_EQ(paymentAddress2.Get(), keyOut.address());
|
||||
}
|
||||
|
||||
|
||||
@@ -532,6 +532,11 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
|
||||
RenameThread("bitcoin-loadblk");
|
||||
// -reindex
|
||||
if (fReindex) {
|
||||
#ifdef ENABLE_WALLET
|
||||
if (pwalletMain) {
|
||||
pwalletMain->ClearNoteWitnessCache();
|
||||
}
|
||||
#endif
|
||||
CImportingNow imp;
|
||||
int nFile = 0;
|
||||
while (true) {
|
||||
@@ -608,8 +613,8 @@ static void ZC_LoadParams()
|
||||
struct timeval tv_start, tv_end;
|
||||
float elapsed;
|
||||
|
||||
boost::filesystem::path pk_path = ZC_GetParamsDir() / "z9-proving.key";
|
||||
boost::filesystem::path vk_path = ZC_GetParamsDir() / "z9-verifying.key";
|
||||
boost::filesystem::path pk_path = ZC_GetParamsDir() / "beta2-proving.key";
|
||||
boost::filesystem::path vk_path = ZC_GetParamsDir() / "beta2-verifying.key";
|
||||
|
||||
pzcashParams = ZCJoinSplit::Unopened();
|
||||
|
||||
|
||||
@@ -172,5 +172,6 @@ public:
|
||||
|
||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
|
||||
typedef std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap;
|
||||
typedef std::map<libzcash::PaymentAddress, std::vector<unsigned char> > CryptedSpendingKeyMap;
|
||||
|
||||
#endif // BITCOIN_KEYSTORE_H
|
||||
|
||||
76
src/main.cpp
76
src/main.cpp
@@ -646,16 +646,6 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extremely large transactions with lots of inputs can cost the network
|
||||
// almost as much to process as they cost the sender in fees, because
|
||||
// computing signature hashes is O(ninputs*txsize). Limiting transactions
|
||||
// to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
|
||||
unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
|
||||
if (sz >= MAX_STANDARD_TX_SIZE) {
|
||||
reason = "tx-size";
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
{
|
||||
// Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
|
||||
@@ -873,7 +863,8 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
|
||||
REJECT_INVALID, "bad-txns-vout-empty");
|
||||
|
||||
// Size limits
|
||||
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
|
||||
BOOST_STATIC_ASSERT(MAX_BLOCK_SIZE > MAX_TX_SIZE); // sanity
|
||||
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_TX_SIZE)
|
||||
return state.DoS(100, error("CheckTransaction(): size limits failed"),
|
||||
REJECT_INVALID, "bad-txns-oversize");
|
||||
|
||||
@@ -2052,8 +2043,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
// Special case for the genesis block, skipping connection of its transactions
|
||||
// (its coinbase is unspendable)
|
||||
if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) {
|
||||
if (!fJustCheck)
|
||||
if (!fJustCheck) {
|
||||
view.SetBestBlock(pindex->GetBlockHash());
|
||||
// Before the genesis block, there was an empty tree
|
||||
ZCIncrementalMerkleTree tree;
|
||||
pindex->hashAnchor = tree.root();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2099,6 +2094,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
// Construct the incremental merkle tree at the current
|
||||
// block position,
|
||||
auto old_tree_root = view.GetBestAnchor();
|
||||
// saving the top anchor in the block index as we go.
|
||||
if (!fJustCheck) {
|
||||
pindex->hashAnchor = old_tree_root;
|
||||
}
|
||||
ZCIncrementalMerkleTree tree;
|
||||
// This should never fail: we should always be able to get the root
|
||||
// that is on the tip of our chain
|
||||
@@ -3103,26 +3102,6 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
|
||||
}
|
||||
}
|
||||
|
||||
// Coinbase transaction must include an output sending 20% of
|
||||
// the block reward to `FOUNDERS_REWARD_SCRIPT` until the first
|
||||
// subsidy halving block, with exception to the genesis block.
|
||||
/*if ((nHeight > 0) && (nHeight < consensusParams.nSubsidyHalvingInterval)) {
|
||||
bool found = false;
|
||||
|
||||
BOOST_FOREACH(const CTxOut& output, block.vtx[0].vout) {
|
||||
if (output.scriptPubKey == ParseHex(FOUNDERS_REWARD_SCRIPT)) {
|
||||
if (output.nValue == (GetBlockSubsidy(nHeight, consensusParams) / 5)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return state.DoS(100, error("%s: founders reward missing", __func__), REJECT_INVALID, "cb-no-founders-reward");
|
||||
}
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4089,6 +4068,9 @@ string GetWarnings(string strFor)
|
||||
{
|
||||
nPriority = alert.nPriority;
|
||||
strStatusBar = alert.strStatusBar;
|
||||
if (alert.nPriority >= ALERT_PRIORITY_SAFE_MODE) {
|
||||
strRPC = alert.strRPCError;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4677,13 +4659,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||
bool fMissingInputs = false;
|
||||
CValidationState state;
|
||||
|
||||
pfrom->setAskFor.erase(inv.hash);
|
||||
mapAlreadyAskedFor.erase(inv);
|
||||
|
||||
// Check for recently rejected (and do other quick existence checks)
|
||||
if (AlreadyHave(inv))
|
||||
return true;
|
||||
|
||||
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
|
||||
if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
|
||||
{
|
||||
mempool.check(pcoinsTip);
|
||||
RelayTransaction(tx);
|
||||
@@ -4764,13 +4743,21 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||
|
||||
if (pfrom->fWhitelisted) {
|
||||
// Always relay transactions received from whitelisted peers, even
|
||||
// if they were rejected from the mempool, allowing the node to
|
||||
// function as a gateway for nodes hidden behind it.
|
||||
// if they were already in the mempool or rejected from it due
|
||||
// to policy, allowing the node to function as a gateway for
|
||||
// nodes hidden behind it.
|
||||
//
|
||||
// FIXME: This includes invalid transactions, which means a
|
||||
// whitelisted peer could get us banned! We may want to change
|
||||
// that.
|
||||
RelayTransaction(tx);
|
||||
// Never relay transactions that we would assign a non-zero DoS
|
||||
// score for, as we expect peers to do the same with us in that
|
||||
// case.
|
||||
int nDoS = 0;
|
||||
if (!state.IsInvalid(nDoS) || nDoS == 0) {
|
||||
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id);
|
||||
RelayTransaction(tx);
|
||||
} else {
|
||||
LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s (code %d))\n",
|
||||
tx.GetHash().ToString(), pfrom->id, state.GetRejectReason(), state.GetRejectCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
int nDoS = 0;
|
||||
@@ -5475,6 +5462,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
||||
pto->PushMessage("getdata", vGetData);
|
||||
vGetData.clear();
|
||||
}
|
||||
} else {
|
||||
//If we're not going to ask, don't expect a response.
|
||||
pto->setAskFor.erase(inv.hash);
|
||||
}
|
||||
pto->mapAskFor.erase(pto->mapAskFor.begin());
|
||||
}
|
||||
|
||||
@@ -47,9 +47,6 @@ class CValidationState;
|
||||
|
||||
struct CNodeStateStats;
|
||||
|
||||
// This is a 2-of-3 multisig P2SH
|
||||
//static const char *FOUNDERS_REWARD_SCRIPT = "a9146708e6670db0b950dac68031025cc5b63213a49187";
|
||||
|
||||
/** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/
|
||||
static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
|
||||
static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0;
|
||||
@@ -57,8 +54,8 @@ static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0;
|
||||
static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000;
|
||||
/** Default for accepting alerts from the P2P network. */
|
||||
static const bool DEFAULT_ALERTS = true;
|
||||
/** The maximum size for transactions we're willing to relay/mine */
|
||||
static const unsigned int MAX_STANDARD_TX_SIZE = 100000;
|
||||
/** Minimum alert priority for enabling safe mode. */
|
||||
static const int ALERT_PRIORITY_SAFE_MODE = 4000;
|
||||
/** Maximum number of signature check operations in an IsStandard() P2SH script */
|
||||
static const unsigned int MAX_P2SH_SIGOPS = 15;
|
||||
/** The maximum number of sigops we're willing to relay/mine in a single tx */
|
||||
|
||||
@@ -100,7 +100,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||
{
|
||||
const CChainParams& chainparams = Params();
|
||||
// Create new block
|
||||
auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
|
||||
unique_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
|
||||
if(!pblocktemplate.get())
|
||||
return NULL;
|
||||
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
|
||||
@@ -334,20 +334,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||
txNew.vout.resize(1);
|
||||
txNew.vout[0].scriptPubKey = scriptPubKeyIn;
|
||||
txNew.vout[0].nValue = GetBlockSubsidy(nHeight, chainparams.GetConsensus());
|
||||
|
||||
/*if ((nHeight > 0) && (nHeight < chainparams.GetConsensus().nSubsidyHalvingInterval)) {
|
||||
// Founders reward is 20% of the block subsidy
|
||||
auto vFoundersReward = txNew.vout[0].nValue / 5;
|
||||
// Take some reward away from us
|
||||
txNew.vout[0].nValue -= vFoundersReward;
|
||||
|
||||
auto rewardScript = ParseHex(FOUNDERS_REWARD_SCRIPT);
|
||||
|
||||
// And give it to the founders
|
||||
txNew.vout.push_back(CTxOut(vFoundersReward, CScript(rewardScript.begin(),
|
||||
rewardScript.end())));
|
||||
}*/
|
||||
|
||||
// Add fees
|
||||
txNew.vout[0].nValue += nFees;
|
||||
txNew.vin[0].scriptSig = CScript() << nHeight << OP_0;
|
||||
@@ -502,7 +488,7 @@ void static BitcoinMiner(CWallet *pwallet)
|
||||
unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
|
||||
CBlockIndex* pindexPrev = chainActive.Tip();
|
||||
|
||||
auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
|
||||
unique_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
|
||||
if (!pblocktemplate.get())
|
||||
{
|
||||
LogPrintf("Error in ZcashMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");
|
||||
|
||||
@@ -2178,8 +2178,12 @@ CNode::~CNode()
|
||||
|
||||
void CNode::AskFor(const CInv& inv)
|
||||
{
|
||||
if (mapAskFor.size() > MAPASKFOR_MAX_SZ)
|
||||
if (mapAskFor.size() > MAPASKFOR_MAX_SZ || setAskFor.size() > SETASKFOR_MAX_SZ)
|
||||
return;
|
||||
// a peer may not have multiple non-responded queue positions for a single inv item
|
||||
if (!setAskFor.insert(inv.hash).second)
|
||||
return;
|
||||
|
||||
// We're using mapAskFor as a priority queue,
|
||||
// the key is the earliest time the request can be sent
|
||||
int64_t nRequestTime;
|
||||
|
||||
@@ -59,6 +59,8 @@ static const bool DEFAULT_UPNP = false;
|
||||
#endif
|
||||
/** The maximum number of entries in mapAskFor */
|
||||
static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ;
|
||||
/** The maximum number of entries in setAskFor (larger due to getdata latency)*/
|
||||
static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ;
|
||||
|
||||
unsigned int ReceiveFloodSize();
|
||||
unsigned int SendBufferSize();
|
||||
@@ -310,6 +312,7 @@ public:
|
||||
mruset<CInv> setInventoryKnown;
|
||||
std::vector<CInv> vInventoryToSend;
|
||||
CCriticalSection cs_inventory;
|
||||
std::set<uint256> setAskFor;
|
||||
std::multimap<int64_t, CInv> mapAskFor;
|
||||
|
||||
// Ping time measurement:
|
||||
|
||||
@@ -156,7 +156,7 @@ Value generate(const Array& params, bool fHelp)
|
||||
unsigned int k = Params().EquihashK();
|
||||
while (nHeight < nHeightEnd)
|
||||
{
|
||||
auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
|
||||
unique_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
|
||||
if (!pblocktemplate.get())
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty");
|
||||
CBlock *pblock = &pblocktemplate->block;
|
||||
@@ -795,11 +795,6 @@ Value getblocksubsidy(const Array& params, bool fHelp)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
|
||||
|
||||
CAmount nReward = GetBlockSubsidy(nHeight, Params().GetConsensus());
|
||||
/*CAmount nFoundersReward = 0;
|
||||
if ((nHeight > 0) && (nHeight < Params().GetConsensus().nSubsidyHalvingInterval)) {
|
||||
nFoundersReward = nReward/5;
|
||||
nReward -= nFoundersReward;
|
||||
}*/
|
||||
Object result;
|
||||
result.push_back(Pair("miner", ValueFromAmount(nReward)));
|
||||
//result.push_back(Pair("founders", ValueFromAmount(nFoundersReward)));
|
||||
|
||||
@@ -96,8 +96,8 @@ Value getpeerinfo(const Array& params, bool fHelp)
|
||||
" \"timeoffset\": ttt, (numeric) The time offset in seconds\n"
|
||||
" \"pingtime\": n, (numeric) ping time\n"
|
||||
" \"pingwait\": n, (numeric) ping wait\n"
|
||||
" \"version\": v, (numeric) The peer version, such as 7001\n"
|
||||
" \"subver\": \"/Satoshi:0.8.5/\", (string) The string version\n"
|
||||
" \"version\": v, (numeric) The peer version, such as 170002\n"
|
||||
" \"subver\": \"/MagicBean:x.y.z[-v]/\", (string) The string version\n"
|
||||
" \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n"
|
||||
" \"startingheight\": n, (numeric) The starting height (block) of the peer\n"
|
||||
" \"banscore\": n, (numeric) The ban score\n"
|
||||
@@ -387,7 +387,7 @@ Value getnetworkinfo(const Array& params, bool fHelp)
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"version\": xxxxx, (numeric) the server version\n"
|
||||
" \"subversion\": \"/Satoshi:x.x.x/\", (string) the server subversion string\n"
|
||||
" \"subversion\": \"/MagicBean:x.y.z[-v]/\", (string) the server subversion string\n"
|
||||
" \"protocolversion\": xxxxx, (numeric) the protocol version\n"
|
||||
" \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n"
|
||||
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
|
||||
|
||||
@@ -69,7 +69,7 @@ enum RPCErrorCode
|
||||
//! Wallet errors
|
||||
RPC_WALLET_ERROR = -4, //! Unspecified problem with wallet (key not found etc.)
|
||||
RPC_WALLET_INSUFFICIENT_FUNDS = -6, //! Not enough funds in wallet or account
|
||||
RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //! Invalid account name
|
||||
RPC_WALLET_ACCOUNTS_UNSUPPORTED = -11, //! Accounts are unsupported
|
||||
RPC_WALLET_KEYPOOL_RAN_OUT = -12, //! Keypool ran out, call keypoolrefill first
|
||||
RPC_WALLET_UNLOCK_NEEDED = -13, //! Enter the wallet passphrase with walletpassphrase first
|
||||
RPC_WALLET_PASSPHRASE_INCORRECT = -14, //! The wallet passphrase entered was incorrect
|
||||
|
||||
@@ -55,41 +55,8 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeH
|
||||
out.push_back(Pair("addresses", a));
|
||||
}
|
||||
|
||||
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
|
||||
{
|
||||
entry.push_back(Pair("txid", tx.GetHash().GetHex()));
|
||||
entry.push_back(Pair("version", tx.nVersion));
|
||||
entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
|
||||
Array vin;
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
|
||||
Object in;
|
||||
if (tx.IsCoinBase())
|
||||
in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
|
||||
else {
|
||||
in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
|
||||
in.push_back(Pair("vout", (int64_t)txin.prevout.n));
|
||||
Object o;
|
||||
o.push_back(Pair("asm", txin.scriptSig.ToString()));
|
||||
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
|
||||
in.push_back(Pair("scriptSig", o));
|
||||
}
|
||||
in.push_back(Pair("sequence", (int64_t)txin.nSequence));
|
||||
vin.push_back(in);
|
||||
}
|
||||
entry.push_back(Pair("vin", vin));
|
||||
Array vout;
|
||||
for (unsigned int i = 0; i < tx.vout.size(); i++) {
|
||||
const CTxOut& txout = tx.vout[i];
|
||||
Object out;
|
||||
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
|
||||
out.push_back(Pair("n", (int64_t)i));
|
||||
Object o;
|
||||
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
|
||||
out.push_back(Pair("scriptPubKey", o));
|
||||
vout.push_back(out);
|
||||
}
|
||||
entry.push_back(Pair("vout", vout));
|
||||
|
||||
Array TxJoinSplitToJSON(const CTransaction& tx) {
|
||||
Array vjoinsplit;
|
||||
for (unsigned int i = 0; i < tx.vjoinsplit.size(); i++) {
|
||||
const JSDescription& jsdescription = tx.vjoinsplit[i];
|
||||
@@ -126,7 +93,45 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
|
||||
|
||||
vjoinsplit.push_back(joinsplit);
|
||||
}
|
||||
return vjoinsplit;
|
||||
}
|
||||
|
||||
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
|
||||
{
|
||||
entry.push_back(Pair("txid", tx.GetHash().GetHex()));
|
||||
entry.push_back(Pair("version", tx.nVersion));
|
||||
entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
|
||||
Array vin;
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
|
||||
Object in;
|
||||
if (tx.IsCoinBase())
|
||||
in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
|
||||
else {
|
||||
in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
|
||||
in.push_back(Pair("vout", (int64_t)txin.prevout.n));
|
||||
Object o;
|
||||
o.push_back(Pair("asm", txin.scriptSig.ToString()));
|
||||
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
|
||||
in.push_back(Pair("scriptSig", o));
|
||||
}
|
||||
in.push_back(Pair("sequence", (int64_t)txin.nSequence));
|
||||
vin.push_back(in);
|
||||
}
|
||||
entry.push_back(Pair("vin", vin));
|
||||
Array vout;
|
||||
for (unsigned int i = 0; i < tx.vout.size(); i++) {
|
||||
const CTxOut& txout = tx.vout[i];
|
||||
Object out;
|
||||
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
|
||||
out.push_back(Pair("n", (int64_t)i));
|
||||
Object o;
|
||||
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
|
||||
out.push_back(Pair("scriptPubKey", o));
|
||||
vout.push_back(out);
|
||||
}
|
||||
entry.push_back(Pair("vout", vout));
|
||||
|
||||
Array vjoinsplit = TxJoinSplitToJSON(tx);
|
||||
entry.push_back(Pair("vjoinsplit", vjoinsplit));
|
||||
|
||||
if (!hashBlock.IsNull()) {
|
||||
|
||||
@@ -247,7 +247,6 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||
|
||||
CScript::const_iterator pc = script.begin();
|
||||
CScript::const_iterator pend = script.end();
|
||||
CScript::const_iterator pbegincodehash = script.begin();
|
||||
opcodetype opcode;
|
||||
valtype vchPushValue;
|
||||
vector<bool> vfExec;
|
||||
@@ -290,7 +289,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||
opcode == OP_DIV ||
|
||||
opcode == OP_MOD ||
|
||||
opcode == OP_LSHIFT ||
|
||||
opcode == OP_RSHIFT)
|
||||
opcode == OP_RSHIFT ||
|
||||
opcode == OP_CODESEPARATOR)
|
||||
return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes.
|
||||
|
||||
if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) {
|
||||
@@ -815,13 +815,6 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||
popstack(stack);
|
||||
stack.push_back(vchHash);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_CODESEPARATOR:
|
||||
{
|
||||
// Hash starts after the code separator
|
||||
pbegincodehash = pc;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_CHECKSIG:
|
||||
@@ -834,17 +827,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||
valtype& vchSig = stacktop(-2);
|
||||
valtype& vchPubKey = stacktop(-1);
|
||||
|
||||
// Subset of script starting at the most recent codeseparator
|
||||
CScript scriptCode(pbegincodehash, pend);
|
||||
|
||||
// Drop the signature, since there's no way for a signature to sign itself
|
||||
scriptCode.FindAndDelete(CScript(vchSig));
|
||||
|
||||
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
|
||||
//serror is set
|
||||
return false;
|
||||
}
|
||||
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode);
|
||||
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script);
|
||||
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
@@ -887,16 +874,6 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||
if ((int)stack.size() < i)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
// Subset of script starting at the most recent codeseparator
|
||||
CScript scriptCode(pbegincodehash, pend);
|
||||
|
||||
// Drop the signatures, since there's no way for a signature to sign itself
|
||||
for (int k = 0; k < nSigsCount; k++)
|
||||
{
|
||||
valtype& vchSig = stacktop(-isig-k);
|
||||
scriptCode.FindAndDelete(CScript(vchSig));
|
||||
}
|
||||
|
||||
bool fSuccess = true;
|
||||
while (fSuccess && nSigsCount > 0)
|
||||
{
|
||||
@@ -912,7 +889,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||
}
|
||||
|
||||
// Check signature
|
||||
bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode);
|
||||
bool fOk = checker.CheckSig(vchSig, vchPubKey, script);
|
||||
|
||||
if (fOk) {
|
||||
isig++;
|
||||
@@ -998,27 +975,12 @@ public:
|
||||
fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE),
|
||||
fHashNone((nHashTypeIn & 0x1f) == SIGHASH_NONE) {}
|
||||
|
||||
/** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */
|
||||
/** Serialize the passed scriptCode */
|
||||
template<typename S>
|
||||
void SerializeScriptCode(S &s, int nType, int nVersion) const {
|
||||
CScript::const_iterator it = scriptCode.begin();
|
||||
CScript::const_iterator itBegin = it;
|
||||
opcodetype opcode;
|
||||
unsigned int nCodeSeparators = 0;
|
||||
while (scriptCode.GetOp(it, opcode)) {
|
||||
if (opcode == OP_CODESEPARATOR)
|
||||
nCodeSeparators++;
|
||||
}
|
||||
::WriteCompactSize(s, scriptCode.size() - nCodeSeparators);
|
||||
it = itBegin;
|
||||
while (scriptCode.GetOp(it, opcode)) {
|
||||
if (opcode == OP_CODESEPARATOR) {
|
||||
s.write((char*)&itBegin[0], it-itBegin-1);
|
||||
itBegin = it;
|
||||
}
|
||||
}
|
||||
if (itBegin != scriptCode.end())
|
||||
s.write((char*)&itBegin[0], it-itBegin);
|
||||
auto size = scriptCode.size();
|
||||
::WriteCompactSize(s, size);
|
||||
s.write((char*)&scriptCode.begin()[0], size);
|
||||
}
|
||||
|
||||
/** Serialize an input of txTo */
|
||||
|
||||
@@ -543,34 +543,6 @@ public:
|
||||
return (opcodetype)(OP_1+n-1);
|
||||
}
|
||||
|
||||
int FindAndDelete(const CScript& b)
|
||||
{
|
||||
int nFound = 0;
|
||||
if (b.empty())
|
||||
return nFound;
|
||||
iterator pc = begin();
|
||||
opcodetype opcode;
|
||||
do
|
||||
{
|
||||
while (end() - pc >= (long)b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
|
||||
{
|
||||
pc = erase(pc, pc + b.size());
|
||||
++nFound;
|
||||
}
|
||||
}
|
||||
while (GetOp(pc, opcode));
|
||||
return nFound;
|
||||
}
|
||||
int Find(opcodetype op) const
|
||||
{
|
||||
int nFound = 0;
|
||||
opcodetype opcode;
|
||||
for (const_iterator pc = begin(); pc != end() && GetOp(pc, opcode);)
|
||||
if (opcode == op)
|
||||
++nFound;
|
||||
return nFound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs
|
||||
* as 20 sigops. With pay-to-script-hash, that changed:
|
||||
|
||||
@@ -70,7 +70,7 @@ noinst_PROGRAMS += tests
|
||||
tests_SOURCES = src/tests.c
|
||||
tests_CPPFLAGS = -DVERIFY $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
|
||||
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS)
|
||||
tests_LDFLAGS = -static
|
||||
tests_LDFLAGS = -static -pthread
|
||||
TESTS = tests
|
||||
endif
|
||||
|
||||
|
||||
@@ -85,12 +85,14 @@ void ThreadSendAlert()
|
||||
// 1000 for Misc warnings like out of disk space and clock is wrong
|
||||
// 2000 for longer invalid proof-of-work chain
|
||||
// Higher numbers mean higher priority
|
||||
// 4000 or higher will put the RPC into safe mode
|
||||
alert.nPriority = 5000;
|
||||
alert.strComment = "";
|
||||
alert.strStatusBar = "URGENT: Upgrade required: see https://z.cash";
|
||||
alert.strRPCError = "URGENT: Upgrade required: see https://z.cash";
|
||||
|
||||
// Set specific client version/versions here. If setSubVer is empty, no filtering on subver is done:
|
||||
// alert.setSubVer.insert(std::string("/Satoshi:0.7.2/"));
|
||||
// alert.setSubVer.insert(std::string("/MagicBean:0.7.2/"));
|
||||
|
||||
// Sign
|
||||
const CChainParams& chainparams = Params();
|
||||
|
||||
@@ -27,54 +27,55 @@
|
||||
* >> and << read and write unformatted data using the above serialization templates.
|
||||
* Fills with data in linear time; some stringstream implementations take N^2 time.
|
||||
*/
|
||||
class CDataStream
|
||||
template<typename SerializeType>
|
||||
class CBaseDataStream
|
||||
{
|
||||
protected:
|
||||
typedef CSerializeData vector_type;
|
||||
typedef SerializeType vector_type;
|
||||
vector_type vch;
|
||||
unsigned int nReadPos;
|
||||
public:
|
||||
int nType;
|
||||
int nVersion;
|
||||
|
||||
typedef vector_type::allocator_type allocator_type;
|
||||
typedef vector_type::size_type size_type;
|
||||
typedef vector_type::difference_type difference_type;
|
||||
typedef vector_type::reference reference;
|
||||
typedef vector_type::const_reference const_reference;
|
||||
typedef vector_type::value_type value_type;
|
||||
typedef vector_type::iterator iterator;
|
||||
typedef vector_type::const_iterator const_iterator;
|
||||
typedef vector_type::reverse_iterator reverse_iterator;
|
||||
typedef typename vector_type::allocator_type allocator_type;
|
||||
typedef typename vector_type::size_type size_type;
|
||||
typedef typename vector_type::difference_type difference_type;
|
||||
typedef typename vector_type::reference reference;
|
||||
typedef typename vector_type::const_reference const_reference;
|
||||
typedef typename vector_type::value_type value_type;
|
||||
typedef typename vector_type::iterator iterator;
|
||||
typedef typename vector_type::const_iterator const_iterator;
|
||||
typedef typename vector_type::reverse_iterator reverse_iterator;
|
||||
|
||||
explicit CDataStream(int nTypeIn, int nVersionIn)
|
||||
explicit CBaseDataStream(int nTypeIn, int nVersionIn)
|
||||
{
|
||||
Init(nTypeIn, nVersionIn);
|
||||
}
|
||||
|
||||
CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
|
||||
CBaseDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
|
||||
{
|
||||
Init(nTypeIn, nVersionIn);
|
||||
}
|
||||
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1300
|
||||
CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
|
||||
CBaseDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
|
||||
{
|
||||
Init(nTypeIn, nVersionIn);
|
||||
}
|
||||
#endif
|
||||
|
||||
CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
|
||||
CBaseDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
|
||||
{
|
||||
Init(nTypeIn, nVersionIn);
|
||||
}
|
||||
|
||||
CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
|
||||
CBaseDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
|
||||
{
|
||||
Init(nTypeIn, nVersionIn);
|
||||
}
|
||||
|
||||
CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
|
||||
CBaseDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
|
||||
{
|
||||
Init(nTypeIn, nVersionIn);
|
||||
}
|
||||
@@ -86,15 +87,15 @@ public:
|
||||
nVersion = nVersionIn;
|
||||
}
|
||||
|
||||
CDataStream& operator+=(const CDataStream& b)
|
||||
CBaseDataStream& operator+=(const CBaseDataStream& b)
|
||||
{
|
||||
vch.insert(vch.end(), b.begin(), b.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend CDataStream operator+(const CDataStream& a, const CDataStream& b)
|
||||
friend CBaseDataStream operator+(const CBaseDataStream& a, const CBaseDataStream& b)
|
||||
{
|
||||
CDataStream ret = a;
|
||||
CBaseDataStream ret = a;
|
||||
ret += b;
|
||||
return (ret);
|
||||
}
|
||||
@@ -207,7 +208,7 @@ public:
|
||||
// Stream subset
|
||||
//
|
||||
bool eof() const { return size() == 0; }
|
||||
CDataStream* rdbuf() { return this; }
|
||||
CBaseDataStream* rdbuf() { return this; }
|
||||
int in_avail() { return size(); }
|
||||
|
||||
void SetType(int n) { nType = n; }
|
||||
@@ -217,7 +218,7 @@ public:
|
||||
void ReadVersion() { *this >> nVersion; }
|
||||
void WriteVersion() { *this << nVersion; }
|
||||
|
||||
CDataStream& read(char* pch, size_t nSize)
|
||||
CBaseDataStream& read(char* pch, size_t nSize)
|
||||
{
|
||||
// Read from the beginning of the buffer
|
||||
unsigned int nReadPosNext = nReadPos + nSize;
|
||||
@@ -225,7 +226,7 @@ public:
|
||||
{
|
||||
if (nReadPosNext > vch.size())
|
||||
{
|
||||
throw std::ios_base::failure("CDataStream::read(): end of data");
|
||||
throw std::ios_base::failure("CBaseDataStream::read(): end of data");
|
||||
}
|
||||
memcpy(pch, &vch[nReadPos], nSize);
|
||||
nReadPos = 0;
|
||||
@@ -237,7 +238,7 @@ public:
|
||||
return (*this);
|
||||
}
|
||||
|
||||
CDataStream& ignore(int nSize)
|
||||
CBaseDataStream& ignore(int nSize)
|
||||
{
|
||||
// Ignore from the beginning of the buffer
|
||||
assert(nSize >= 0);
|
||||
@@ -245,7 +246,7 @@ public:
|
||||
if (nReadPosNext >= vch.size())
|
||||
{
|
||||
if (nReadPosNext > vch.size())
|
||||
throw std::ios_base::failure("CDataStream::ignore(): end of data");
|
||||
throw std::ios_base::failure("CBaseDataStream::ignore(): end of data");
|
||||
nReadPos = 0;
|
||||
vch.clear();
|
||||
return (*this);
|
||||
@@ -254,7 +255,7 @@ public:
|
||||
return (*this);
|
||||
}
|
||||
|
||||
CDataStream& write(const char* pch, size_t nSize)
|
||||
CBaseDataStream& write(const char* pch, size_t nSize)
|
||||
{
|
||||
// Write to the end of the buffer
|
||||
vch.insert(vch.end(), pch, pch + nSize);
|
||||
@@ -277,7 +278,7 @@ public:
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CDataStream& operator<<(const T& obj)
|
||||
CBaseDataStream& operator<<(const T& obj)
|
||||
{
|
||||
// Serialize to this stream
|
||||
::Serialize(*this, obj, nType, nVersion);
|
||||
@@ -285,7 +286,7 @@ public:
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CDataStream& operator>>(T& obj)
|
||||
CBaseDataStream& operator>>(T& obj)
|
||||
{
|
||||
// Unserialize from this stream
|
||||
::Unserialize(*this, obj, nType, nVersion);
|
||||
@@ -298,6 +299,30 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class CDataStream : public CBaseDataStream<CSerializeData>
|
||||
{
|
||||
public:
|
||||
explicit CDataStream(int nTypeIn, int nVersionIn) : CBaseDataStream(nTypeIn, nVersionIn) { }
|
||||
|
||||
CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) :
|
||||
CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
|
||||
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1300
|
||||
CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) :
|
||||
CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
|
||||
#endif
|
||||
|
||||
CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) :
|
||||
CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
|
||||
|
||||
CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) :
|
||||
CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
|
||||
|
||||
CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) :
|
||||
CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "data/alertTests.raw.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "rpcprotocol.h"
|
||||
#include "rpcserver.h"
|
||||
#include "serialize.h"
|
||||
#include "streams.h"
|
||||
#include "util.h"
|
||||
@@ -25,6 +27,7 @@
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include "json/json_spirit_reader_template.h"
|
||||
|
||||
#include "key.h"
|
||||
#include "alertkeys.h"
|
||||
@@ -163,12 +166,12 @@ void GenerateAlertTests()
|
||||
SignAndSerialize(alert, sBuffer);
|
||||
|
||||
// More tests go here ...
|
||||
alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
|
||||
alert.strStatusBar = "Alert 1 for Satoshi 0.1.0";
|
||||
alert.setSubVer.insert(std::string("/MagicBean:0.1.0/"));
|
||||
alert.strStatusBar = "Alert 1 for MagicBean 0.1.0";
|
||||
SignAndSerialize(alert, sBuffer);
|
||||
|
||||
alert.setSubVer.insert(std::string("/Satoshi:0.2.0/"));
|
||||
alert.strStatusBar = "Alert 1 for Satoshi 0.1.0, 0.2.0";
|
||||
alert.setSubVer.insert(std::string("/MagicBean:0.2.0/"));
|
||||
alert.strStatusBar = "Alert 1 for MagicBean 0.1.0, 0.2.0";
|
||||
SignAndSerialize(alert, sBuffer);
|
||||
|
||||
alert.setSubVer.clear();
|
||||
@@ -183,13 +186,26 @@ void GenerateAlertTests()
|
||||
SignAndSerialize(alert, sBuffer);
|
||||
|
||||
++alert.nID;
|
||||
alert.nMinVer = 11;
|
||||
alert.nMaxVer = 22;
|
||||
alert.nPriority = 5000;
|
||||
alert.strStatusBar = "Alert 3, disables RPC";
|
||||
alert.strRPCError = "RPC disabled";
|
||||
SignAndSerialize(alert, sBuffer);
|
||||
|
||||
++alert.nID;
|
||||
alert.strStatusBar = "Alert 2 for Satoshi 0.1.0";
|
||||
alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
|
||||
alert.nPriority = 5000;
|
||||
alert.strStatusBar = "Alert 4, re-enables RPC";
|
||||
alert.strRPCError = "";
|
||||
SignAndSerialize(alert, sBuffer);
|
||||
|
||||
++alert.nID;
|
||||
alert.nMinVer = 11;
|
||||
alert.nMaxVer = 22;
|
||||
alert.nPriority = 100;
|
||||
SignAndSerialize(alert, sBuffer);
|
||||
|
||||
++alert.nID;
|
||||
alert.strStatusBar = "Alert 2 for MagicBean 0.1.0";
|
||||
alert.setSubVer.insert(std::string("/MagicBean:0.1.0/"));
|
||||
SignAndSerialize(alert, sBuffer);
|
||||
|
||||
++alert.nID;
|
||||
@@ -280,27 +296,27 @@ BOOST_AUTO_TEST_CASE(AlertApplies)
|
||||
// Matches:
|
||||
BOOST_CHECK(alerts[0].AppliesTo(1, ""));
|
||||
BOOST_CHECK(alerts[0].AppliesTo(999001, ""));
|
||||
BOOST_CHECK(alerts[0].AppliesTo(1, "/Satoshi:11.11.11/"));
|
||||
BOOST_CHECK(alerts[0].AppliesTo(1, "/MagicBean:11.11.11/"));
|
||||
|
||||
BOOST_CHECK(alerts[1].AppliesTo(1, "/Satoshi:0.1.0/"));
|
||||
BOOST_CHECK(alerts[1].AppliesTo(999001, "/Satoshi:0.1.0/"));
|
||||
BOOST_CHECK(alerts[1].AppliesTo(1, "/MagicBean:0.1.0/"));
|
||||
BOOST_CHECK(alerts[1].AppliesTo(999001, "/MagicBean:0.1.0/"));
|
||||
|
||||
BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.1.0/"));
|
||||
BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.2.0/"));
|
||||
BOOST_CHECK(alerts[2].AppliesTo(1, "/MagicBean:0.1.0/"));
|
||||
BOOST_CHECK(alerts[2].AppliesTo(1, "/MagicBean:0.2.0/"));
|
||||
|
||||
// Don't match:
|
||||
BOOST_CHECK(!alerts[0].AppliesTo(-1, ""));
|
||||
BOOST_CHECK(!alerts[0].AppliesTo(999002, ""));
|
||||
|
||||
BOOST_CHECK(!alerts[1].AppliesTo(1, ""));
|
||||
BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0"));
|
||||
BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.1.0"));
|
||||
BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0/"));
|
||||
BOOST_CHECK(!alerts[1].AppliesTo(-1, "/Satoshi:0.1.0/"));
|
||||
BOOST_CHECK(!alerts[1].AppliesTo(999002, "/Satoshi:0.1.0/"));
|
||||
BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.2.0/"));
|
||||
BOOST_CHECK(!alerts[1].AppliesTo(1, "MagicBean:0.1.0"));
|
||||
BOOST_CHECK(!alerts[1].AppliesTo(1, "/MagicBean:0.1.0"));
|
||||
BOOST_CHECK(!alerts[1].AppliesTo(1, "MagicBean:0.1.0/"));
|
||||
BOOST_CHECK(!alerts[1].AppliesTo(-1, "/MagicBean:0.1.0/"));
|
||||
BOOST_CHECK(!alerts[1].AppliesTo(999002, "/MagicBean:0.1.0/"));
|
||||
BOOST_CHECK(!alerts[1].AppliesTo(1, "/MagicBean:0.2.0/"));
|
||||
|
||||
BOOST_CHECK(!alerts[2].AppliesTo(1, "/Satoshi:0.3.0/"));
|
||||
BOOST_CHECK(!alerts[2].AppliesTo(1, "/MagicBean:0.3.0/"));
|
||||
|
||||
SetMockTime(0);
|
||||
}
|
||||
@@ -320,7 +336,7 @@ BOOST_AUTO_TEST_CASE(AlertNotify)
|
||||
alert.ProcessAlert(alertKey, false);
|
||||
|
||||
std::vector<std::string> r = read_lines(temp);
|
||||
BOOST_CHECK_EQUAL(r.size(), 4u);
|
||||
BOOST_CHECK_EQUAL(r.size(), 6u);
|
||||
|
||||
// Windows built-in echo semantics are different than posixy shells. Quotes and
|
||||
// whitespace are printed literally.
|
||||
@@ -329,16 +345,43 @@ BOOST_AUTO_TEST_CASE(AlertNotify)
|
||||
BOOST_CHECK_EQUAL(r[0], "Alert 1");
|
||||
BOOST_CHECK_EQUAL(r[1], "Alert 2, cancels 1");
|
||||
BOOST_CHECK_EQUAL(r[2], "Alert 2, cancels 1");
|
||||
BOOST_CHECK_EQUAL(r[3], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed
|
||||
BOOST_CHECK_EQUAL(r[3], "Alert 3, disables RPC");
|
||||
BOOST_CHECK_EQUAL(r[4], "Alert 4, reenables RPC"); // dashes should be removed
|
||||
BOOST_CHECK_EQUAL(r[5], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed
|
||||
#else
|
||||
BOOST_CHECK_EQUAL(r[0], "'Alert 1' ");
|
||||
BOOST_CHECK_EQUAL(r[1], "'Alert 2, cancels 1' ");
|
||||
BOOST_CHECK_EQUAL(r[2], "'Alert 2, cancels 1' ");
|
||||
BOOST_CHECK_EQUAL(r[3], "'Evil Alert; /bin/ls; echo ' ");
|
||||
BOOST_CHECK_EQUAL(r[3], "'Alert 3, disables RPC' ");
|
||||
BOOST_CHECK_EQUAL(r[4], "'Alert 4, reenables RPC' "); // dashes should be removed
|
||||
BOOST_CHECK_EQUAL(r[5], "'Evil Alert; /bin/ls; echo ' ");
|
||||
#endif
|
||||
boost::filesystem::remove(temp);
|
||||
|
||||
SetMockTime(0);
|
||||
mapAlerts.clear();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(AlertDisablesRPC)
|
||||
{
|
||||
SetMockTime(11);
|
||||
const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
|
||||
|
||||
// Command should work before alerts
|
||||
BOOST_CHECK_EQUAL(GetWarnings("rpc"), "");
|
||||
|
||||
// First alert should disable RPC
|
||||
alerts[5].ProcessAlert(alertKey, false);
|
||||
BOOST_CHECK_EQUAL(alerts[5].strRPCError, "RPC disabled");
|
||||
BOOST_CHECK_EQUAL(GetWarnings("rpc"), "RPC disabled");
|
||||
|
||||
// Second alert should re-enable RPC
|
||||
alerts[6].ProcessAlert(alertKey, false);
|
||||
BOOST_CHECK_EQUAL(alerts[6].strRPCError, "");
|
||||
BOOST_CHECK_EQUAL(GetWarnings("rpc"), "");
|
||||
|
||||
SetMockTime(0);
|
||||
mapAlerts.clear();
|
||||
}
|
||||
|
||||
static bool falseFunc() { return false; }
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define BITCOIN_TEST_BIGNUM_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
@@ -23,48 +24,52 @@ public:
|
||||
|
||||
|
||||
/** C++ wrapper for BIGNUM (OpenSSL bignum) */
|
||||
class CBigNum : public BIGNUM
|
||||
class CBigNum
|
||||
{
|
||||
BIGNUM* bn;
|
||||
public:
|
||||
CBigNum()
|
||||
{
|
||||
BN_init(this);
|
||||
bn = BN_new();
|
||||
assert(bn);
|
||||
}
|
||||
|
||||
CBigNum(const CBigNum& b)
|
||||
{
|
||||
BN_init(this);
|
||||
if (!BN_copy(this, &b))
|
||||
bn = BN_new();
|
||||
assert(bn);
|
||||
if (!BN_copy(bn, b.bn))
|
||||
{
|
||||
BN_clear_free(this);
|
||||
BN_clear_free(bn);
|
||||
throw bignum_error("CBigNum::CBigNum(const CBigNum&): BN_copy failed");
|
||||
}
|
||||
}
|
||||
|
||||
CBigNum& operator=(const CBigNum& b)
|
||||
{
|
||||
if (!BN_copy(this, &b))
|
||||
if (!BN_copy(bn, b.bn))
|
||||
throw bignum_error("CBigNum::operator=: BN_copy failed");
|
||||
return (*this);
|
||||
}
|
||||
|
||||
~CBigNum()
|
||||
{
|
||||
BN_clear_free(this);
|
||||
BN_clear_free(bn);
|
||||
}
|
||||
|
||||
CBigNum(long long n) { BN_init(this); setint64(n); }
|
||||
CBigNum(long long n) { bn = BN_new(); assert(bn); setint64(n); }
|
||||
|
||||
explicit CBigNum(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
BN_init(this);
|
||||
bn = BN_new();
|
||||
assert(bn);
|
||||
setvch(vch);
|
||||
}
|
||||
|
||||
int getint() const
|
||||
{
|
||||
BN_ULONG n = BN_get_word(this);
|
||||
if (!BN_is_negative(this))
|
||||
BN_ULONG n = BN_get_word(bn);
|
||||
if (!BN_is_negative(bn))
|
||||
return (n > (BN_ULONG)std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n);
|
||||
else
|
||||
return (n > (BN_ULONG)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n);
|
||||
@@ -112,7 +117,7 @@ public:
|
||||
pch[1] = (nSize >> 16) & 0xff;
|
||||
pch[2] = (nSize >> 8) & 0xff;
|
||||
pch[3] = (nSize) & 0xff;
|
||||
BN_mpi2bn(pch, p - pch, this);
|
||||
BN_mpi2bn(pch, p - pch, bn);
|
||||
}
|
||||
|
||||
void setvch(const std::vector<unsigned char>& vch)
|
||||
@@ -127,22 +132,30 @@ public:
|
||||
vch2[3] = (nSize >> 0) & 0xff;
|
||||
// swap data to big endian
|
||||
reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4);
|
||||
BN_mpi2bn(&vch2[0], vch2.size(), this);
|
||||
BN_mpi2bn(&vch2[0], vch2.size(), bn);
|
||||
}
|
||||
|
||||
std::vector<unsigned char> getvch() const
|
||||
{
|
||||
unsigned int nSize = BN_bn2mpi(this, NULL);
|
||||
unsigned int nSize = BN_bn2mpi(bn, NULL);
|
||||
if (nSize <= 4)
|
||||
return std::vector<unsigned char>();
|
||||
std::vector<unsigned char> vch(nSize);
|
||||
BN_bn2mpi(this, &vch[0]);
|
||||
BN_bn2mpi(bn, &vch[0]);
|
||||
vch.erase(vch.begin(), vch.begin() + 4);
|
||||
reverse(vch.begin(), vch.end());
|
||||
return vch;
|
||||
}
|
||||
|
||||
friend inline const CBigNum operator+(const CBigNum& a, const CBigNum& b);
|
||||
friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b);
|
||||
friend inline const CBigNum operator-(const CBigNum& a);
|
||||
friend inline bool operator==(const CBigNum& a, const CBigNum& b);
|
||||
friend inline bool operator!=(const CBigNum& a, const CBigNum& b);
|
||||
friend inline bool operator<=(const CBigNum& a, const CBigNum& b);
|
||||
friend inline bool operator>=(const CBigNum& a, const CBigNum& b);
|
||||
friend inline bool operator<(const CBigNum& a, const CBigNum& b);
|
||||
friend inline bool operator>(const CBigNum& a, const CBigNum& b);
|
||||
};
|
||||
|
||||
|
||||
@@ -150,7 +163,7 @@ public:
|
||||
inline const CBigNum operator+(const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
CBigNum r;
|
||||
if (!BN_add(&r, &a, &b))
|
||||
if (!BN_add(r.bn, a.bn, b.bn))
|
||||
throw bignum_error("CBigNum::operator+: BN_add failed");
|
||||
return r;
|
||||
}
|
||||
@@ -158,7 +171,7 @@ inline const CBigNum operator+(const CBigNum& a, const CBigNum& b)
|
||||
inline const CBigNum operator-(const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
CBigNum r;
|
||||
if (!BN_sub(&r, &a, &b))
|
||||
if (!BN_sub(r.bn, a.bn, b.bn))
|
||||
throw bignum_error("CBigNum::operator-: BN_sub failed");
|
||||
return r;
|
||||
}
|
||||
@@ -166,15 +179,15 @@ inline const CBigNum operator-(const CBigNum& a, const CBigNum& b)
|
||||
inline const CBigNum operator-(const CBigNum& a)
|
||||
{
|
||||
CBigNum r(a);
|
||||
BN_set_negative(&r, !BN_is_negative(&r));
|
||||
BN_set_negative(r.bn, !BN_is_negative(r.bn));
|
||||
return r;
|
||||
}
|
||||
|
||||
inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) == 0); }
|
||||
inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) != 0); }
|
||||
inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) <= 0); }
|
||||
inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) >= 0); }
|
||||
inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) < 0); }
|
||||
inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); }
|
||||
inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) == 0); }
|
||||
inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) != 0); }
|
||||
inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) <= 0); }
|
||||
inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) >= 0); }
|
||||
inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) < 0); }
|
||||
inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) > 0); }
|
||||
|
||||
#endif // BITCOIN_TEST_BIGNUM_H
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
[
|
||||
[
|
||||
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
|
||||
"t1T8yaLVhNqxA5KJcmiqqFN88e8DNp2PBfF",
|
||||
"65a16059864a2fdbc7c99a4723a8395bc6f188eb",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
@@ -9,7 +9,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou",
|
||||
"t3VDyGHn9mbyCf448m2cHTu5uXvsJpKHbiZ",
|
||||
"74f209f6ea907e2ea48f74fae05782ae8a665257",
|
||||
{
|
||||
"addrType": "script",
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",
|
||||
"tmHMBeeYRuc2eVicLNfP15YLxbQsooCA6jb",
|
||||
"53c0307d6851aa0ce7825ba883c6bd9ad242b486",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
@@ -27,7 +27,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br",
|
||||
"t2Fbo6DBKKVYw1SfrY8bEgz56hYEhywhEN6",
|
||||
"6349a418fc4578d10a372b54b45c280cc8c4382f",
|
||||
{
|
||||
"addrType": "script",
|
||||
@@ -72,7 +72,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ",
|
||||
"t1TpfguJj5zxKUfWcsNTrh6eod2XXsTKtvB",
|
||||
"6d23156cbbdcc82a5a47eee4c2c7c583c18b6bf4",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
@@ -81,7 +81,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy",
|
||||
"t3hc9Y2stuEWjS2dRDtGdiu3enMpxAbeUiK",
|
||||
"fcc5460dd6e2487c7d75b1963625da0e8f4c5975",
|
||||
{
|
||||
"addrType": "script",
|
||||
@@ -90,7 +90,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ",
|
||||
"tmXm2g5ouU8Pzksmqx3KYmeoeaWrAvj3rB5",
|
||||
"f1d470f9b02370fdec2e6b708b08ac431bf7a5f7",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
@@ -99,7 +99,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
|
||||
"t2QYxHjM8btztWTsMnFnZNurm7RXENk9ZhR",
|
||||
"c579342c2c4c9220205e2cdc285617040c924a0a",
|
||||
{
|
||||
"addrType": "script",
|
||||
@@ -144,7 +144,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv",
|
||||
"t1UxCT4RrCbGH36etfQaPF1svNtZVhsqs5A",
|
||||
"7987ccaa53d02c8873487ef919677cd3db7a6912",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
@@ -153,7 +153,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks",
|
||||
"t3Teyxv1gF8FZ9MW8WN4MvTxQ4JScABsKfL",
|
||||
"63bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb",
|
||||
{
|
||||
"addrType": "script",
|
||||
@@ -162,7 +162,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk",
|
||||
"tmXYBLe2Q9MbXfgGb2QqdN7RWdi7tQ2z8ya",
|
||||
"ef66444b5b17f14e8fae6e7e19b045a78c54fd79",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
@@ -171,7 +171,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"2NB72XtkjpnATMggui83aEtPawyyKvnbX2o",
|
||||
"t2QQcXALz4745JEgzuAEsJNgt6nBQpsqegu",
|
||||
"c3e55fceceaa4391ed2a9677f4a4d34eacd021a0",
|
||||
{
|
||||
"addrType": "script",
|
||||
@@ -216,7 +216,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu",
|
||||
"t1ZiM4oLF7hvboF4LPqhbBg7RLgJCCJC6Tj",
|
||||
"adc1cc2081a27206fae25792f28bbc55b831549d",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
@@ -225,7 +225,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk",
|
||||
"t3LoV8q8R44fSbe84DBKDk3sAEoYum4hQYj",
|
||||
"188f91a931947eddd7432d6e614387e32b244709",
|
||||
{
|
||||
"addrType": "script",
|
||||
@@ -234,7 +234,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H",
|
||||
"tmBmkeJmwF3UgVXqJLzEin49ftK1HmsqYup",
|
||||
"1694f5bc1a7295b600f40018a618a6ea48eeb498",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
@@ -243,7 +243,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN",
|
||||
"t2Byypnbxh2Pfk7VqLMzYfiNeD72o6yvtqX",
|
||||
"3b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3",
|
||||
{
|
||||
"addrType": "script",
|
||||
@@ -288,7 +288,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4",
|
||||
"t1boxWWuUs3dVUFeUMiPqCdwD4QtL1AMx9G",
|
||||
"c4c1b72491ede1eedaca00618407ee0b772cad0d",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
@@ -297,7 +297,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y",
|
||||
"t3h5bvzkCXkiMttmQScK56UjVcqeD3NnReW",
|
||||
"f6fe69bcb548a829cce4c57bf6fff8af3a5981f9",
|
||||
{
|
||||
"addrType": "script",
|
||||
@@ -306,7 +306,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6",
|
||||
"tmDBvm2S5yAj5pVAvB4th1DDVpLq3KuN8S1",
|
||||
"261f83568a098a8638844bd7aeca039d5f2352c0",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
@@ -315,7 +315,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda",
|
||||
"t2TooyZ7BmQTBkgCVhdNQsPfeVdQoWqsHQa",
|
||||
"e930e1834a4d234702773951d627cce82fbb5d2e",
|
||||
{
|
||||
"addrType": "script",
|
||||
@@ -360,7 +360,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r",
|
||||
"t1SWDbHDTatR1ag8yTFLdVWd1erfu7Pbbjk",
|
||||
"5eadaf9bb7121f0f192561a5a62f5e5f54210292",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
@@ -369,7 +369,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3",
|
||||
"t3QKR6mLBwPY6DeqHwjJCxUwSsGUToB5sWJ",
|
||||
"3f210e7277c899c3a155cc1c90f4106cbddeec6e",
|
||||
{
|
||||
"addrType": "script",
|
||||
@@ -378,7 +378,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"myoqcgYiehufrsnnkqdqbp69dddVDMopJu",
|
||||
"tmU1EeoNHCfmWpeZWeRnKmNeVdHJgZjse5G",
|
||||
"c8a3c2a09a298592c3e180f02487cd91ba3400b5",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
@@ -387,7 +387,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C",
|
||||
"t2LZVwB5A2n5U9odwMbLd1g5Bz9Z3ZFoCJH",
|
||||
"99b31df7c9068d1481b596578ddbb4d3bd90baeb",
|
||||
{
|
||||
"addrType": "script",
|
||||
@@ -432,7 +432,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE",
|
||||
"t1Lgcj4m5r7eDWctWQM7ete85hHivQxMjBZ",
|
||||
"1ed467017f043e91ed4c44b4e8dd674db211c4e6",
|
||||
{
|
||||
"addrType": "pubkey",
|
||||
@@ -441,7 +441,7 @@
|
||||
}
|
||||
],
|
||||
[
|
||||
"3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G",
|
||||
"t3TCuHUxH3LGnsFYTUbSwHrRXxTaEA8hAaf",
|
||||
"5ece0cadddc415b1980f001785947120acdb36fc",
|
||||
{
|
||||
"addrType": "script",
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
|
||||
"in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18",
|
||||
"in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1",
|
||||
"outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
|
||||
"outaddr=4:1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46"],
|
||||
"outaddr=0.18:t1LmWJddYzkTmTQjZrX7ZkFjmuEu5XKpGKb",
|
||||
"outaddr=4:t1g1aXFye74HKJ24VviTxo3AW4BZbyCni5H"],
|
||||
"output_cmp": "txcreate1.hex"
|
||||
},
|
||||
{ "exec": "./bitcoin-tx",
|
||||
@@ -54,7 +54,7 @@
|
||||
"set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]",
|
||||
"set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\"}]",
|
||||
"sign=ALL",
|
||||
"outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"],
|
||||
"outaddr=0.001:t1Ruz6gK4QPZoPPGpHaieupnnh62mktjQE7"],
|
||||
"output_cmp": "txcreatesign.hex"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -439,7 +439,6 @@
|
||||
["0", "SHA256", "P2SH,STRICTENC"],
|
||||
["0", "HASH160", "P2SH,STRICTENC"],
|
||||
["0", "HASH256", "P2SH,STRICTENC"],
|
||||
["NOP", "CODESEPARATOR 1", "P2SH,STRICTENC"],
|
||||
|
||||
["NOP", "NOP1 1", "P2SH,STRICTENC"],
|
||||
["NOP", "NOP2 1", "P2SH,STRICTENC"],
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -9,9 +9,16 @@
|
||||
[[["6ca7ec7b1847f6bdbd737176050e6a08d66ccd55bb94ad24f4018024107a5827", 0, "0x41 0x043b640e983c9690a14c039a2037ecc3467b27a0dcd58f19d76c7bc118d09fec45adc5370a1c5bf8067ca9f5557a4cf885fdb0fe0dcc9c3a7137226106fbc779a5 CHECKSIG VERIFY 1"]],
|
||||
"010000000127587a10248001f424ad94bb55cd6cd6086a0e05767173bdbdf647187beca76c000000004948304502201b822ad10d6adc1a341ae8835be3f70a25201bbff31f59cbb9c5353a5f0eca18022100ea7b2f7074e9aa9cf70aa8d0ffee13e6b45dddabf1ab961bda378bcdb778fa4701ffffffff0100f2052a010000001976a914fc50c5907d86fed474ba5ce8b12a66e0a4c139d888ac00000000", "P2SH"],
|
||||
|
||||
["This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json"],
|
||||
["but with the signature duplicated in the scriptPubKey with a non-standard pushdata prefix"],
|
||||
["See FindAndDelete, which will only remove if it uses the same pushdata prefix as is standard"],
|
||||
["A nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG,"],
|
||||
["but with the signature duplicated in the scriptPubKey with the proper pushdata prefix."],
|
||||
["Valid in Bitcoin because of FindAndDelete, but invalid for Zcash."],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Same as above, but with the signature duplicated in the scriptPubKey with"],
|
||||
["a non-standard pushdata prefix. Invalid in both Bitcoin (FindAndDelete only"],
|
||||
["removes if it uses the same pushdata prefix as is standard) and Zcash (no"],
|
||||
["FindAndDelete)."],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
@@ -19,9 +26,10 @@
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006b4c473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json"],
|
||||
["This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG,"],
|
||||
["but with the signature duplicated in the scriptPubKey with a different hashtype suffix"],
|
||||
["See FindAndDelete, which will only remove if the signature, including the hash type, matches"],
|
||||
["Invalid in both Bitcoin (FindAndDelete only removes if the signature, including the hash"],
|
||||
["type, matches) and Zcash (no FindAndDelete)."],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a81"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
@@ -110,15 +118,6 @@
|
||||
"01000000013bfc220ec526583cb6b7e922b8b27f604cfe0a09764de61e80f58dc1723f50ad0000000000ffffffff0101000000000000002321027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5ac00000000", "P2SH"],
|
||||
|
||||
|
||||
["Inverted versions of tx_valid CODESEPARATOR IF block tests"],
|
||||
|
||||
["CODESEPARATOR in an unexecuted IF block does not change what is hashed"],
|
||||
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
|
||||
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a48304502207a6974a77c591fa13dff60cabbb85a0de9e025c09c65a4b2285e47ce8e22f761022100f0efaac9ff8ac36b10721e0aae1fb975c90500b50c56e8a0cc52b0403f0425dd0151ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["As above, with the IF block executed"],
|
||||
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
|
||||
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510100ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["CHECKLOCKTIMEVERIFY tests"],
|
||||
|
||||
|
||||
@@ -40,10 +40,6 @@
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["Same as above, but with the signature duplicated in the scriptPubKey with the proper pushdata prefix"],
|
||||
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
|
||||
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
|
||||
|
||||
["The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"],
|
||||
["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"],
|
||||
[[["b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"],
|
||||
@@ -127,48 +123,6 @@
|
||||
"0100000001c188aa82f268fcf08ba18950f263654a3ea6931dabc8bf3ed1d4d42aaed74cba000000004b0000483045022100940378576e069aca261a6b26fb38344e4497ca6751bb10905c76bb689f4222b002204833806b014c26fd801727b792b1260003c55710f87c5adbd7a9cb57446dbc9801ffffffff0101000000000000002321037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1ac00000000", "P2SH"],
|
||||
|
||||
|
||||
["OP_CODESEPARATOR tests"],
|
||||
|
||||
["Test that SignatureHash() removes OP_CODESEPARATOR with FindAndDelete()"],
|
||||
[[["bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224", 0, "CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]],
|
||||
"01000000012432b60dc72cebc1a27ce0969c0989c895bdd9e62e8234839117f8fc32d17fbc000000004a493046022100a576b52051962c25e642c0fd3d77ee6c92487048e5d90818bcf5b51abaccd7900221008204f8fb121be4ec3b24483b1f92d89b1b0548513a134e345c5442e86e8617a501ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
[[["83e194f90b6ef21fa2e3a365b63794fb5daa844bdc9b25de30899fcfe7b01047", 0, "CODESEPARATOR CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]],
|
||||
"01000000014710b0e7cf9f8930de259bdc4b84aa5dfb9437b665a3e3a21ff26e0bf994e183000000004a493046022100a166121a61b4eeb19d8f922b978ff6ab58ead8a5a5552bf9be73dc9c156873ea02210092ad9bc43ee647da4f6652c320800debcf08ec20a094a0aaf085f63ecb37a17201ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["Hashed data starts at the CODESEPARATOR"],
|
||||
[[["326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CODESEPARATOR CHECKSIG"]],
|
||||
"01000000015ebaa001d8e4ec7a88703a3bcf69d98c874bca6299cca0f191512bf2a7826832000000004948304502203bf754d1c6732fbf87c5dcd81258aefd30f2060d7bd8ac4a5696f7927091dad1022100f5bcb726c4cf5ed0ed34cc13dadeedf628ae1045b7cb34421bc60b89f4cecae701ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["But only if execution has reached it"],
|
||||
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 1"]],
|
||||
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000924830450221009c0a27f886a1d8cb87f6f595fbc3163d28f7a81ec3c4b252ee7f3ac77fd13ffa02203caa8dfa09713c8c4d7ef575c75ed97812072405d932bd11e6a1593a98b679370148304502201e3861ef39a526406bad1e20ecad06be7375ad40ddb582c9be42d26c3a0d7b240221009d0a3985e96522e59635d19cc4448547477396ce0ef17a58e7d74c3ef464292301ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["CODESEPARATOR in an unexecuted IF block does not change what is hashed"],
|
||||
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
|
||||
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a48304502207a6974a77c591fa13dff60cabbb85a0de9e025c09c65a4b2285e47ce8e22f761022100f0efaac9ff8ac36b10721e0aae1fb975c90500b50c56e8a0cc52b0403f0425dd0100ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["As above, with the IF block executed"],
|
||||
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
|
||||
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510151ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
|
||||
["CHECKSIG is legal in scriptSigs"],
|
||||
[[["ccf7f4053a02e653c36ac75c891b7496d0dc5ce5214f6c913d9cf8f1329ebee0", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
|
||||
"0100000001e0be9e32f1f89c3d916c4f21e55cdcd096741b895cc76ac353e6023a05f4f7cc00000000d86149304602210086e5f736a2c3622ebb62bd9d93d8e5d76508b98be922b97160edc3dcca6d8c47022100b23c312ac232a4473f19d2aeb95ab7bdf2b65518911a0d72d50e38b5dd31dc820121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac4730440220508fa761865c8abd81244a168392876ee1d94e8ed83897066b5e2df2400dad24022043f5ee7538e87e9c6aef7ef55133d3e51da7cc522830a9c4d736977a76ef755c0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["Same semantics for OP_CODESEPARATOR"],
|
||||
[[["10c9f0effe83e97f80f067de2b11c6a00c3088a4bce42c5ae761519af9306f3c", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
|
||||
"01000000013c6f30f99a5161e75a2ce4bca488300ca0c6112bde67f0807fe983feeff0c91001000000e608646561646265656675ab61493046022100ce18d384221a731c993939015e3d1bcebafb16e8c0b5b5d14097ec8177ae6f28022100bcab227af90bab33c3fe0a9abfee03ba976ee25dc6ce542526e9b2e56e14b7f10121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac493046022100c3b93edcc0fd6250eb32f2dd8a0bba1754b0f6c3be8ed4100ed582f3db73eba2022100bf75b5bd2eff4d6bf2bda2e34a40fcc07d4aa3cf862ceaa77b47b81eff829f9a01ab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["Signatures are removed from the script they are in by FindAndDelete() in the CHECKSIG code; even multiple instances of one signature can be removed."],
|
||||
[[["6056ebd549003b10cbbd915cea0d82209fe40b8617104be917a26fa92cbe3d6f", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
|
||||
"01000000016f3dbe2ca96fa217e94b1017860be49f20820dea5c91bdcb103b0049d5eb566000000000fd1d0147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac47304402203757e937ba807e4a5da8534c17f9d121176056406a6465054bdd260457515c1a02200f02eccf1bec0f3a0d65df37889143c2e88ab7acec61a7b6f5aa264139141a2b0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
["That also includes ahead of the opcode being executed."],
|
||||
[[["5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
|
||||
"01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
|
||||
|
||||
|
||||
|
||||
["CHECKLOCKTIMEVERIFY tests"],
|
||||
|
||||
|
||||
@@ -25,13 +25,13 @@ static const string strSecret1 ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmF
|
||||
static const string strSecret2 ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3");
|
||||
static const string strSecret1C ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw");
|
||||
static const string strSecret2C ("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g");
|
||||
static const CBitcoinAddress addr1 ("1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ");
|
||||
static const CBitcoinAddress addr2 ("1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ");
|
||||
static const CBitcoinAddress addr1C("1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs");
|
||||
static const CBitcoinAddress addr2C("1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs");
|
||||
static const CBitcoinAddress addr1 ("t1h8SqgtM3QM5e2M8EzhhT1yL2PXXtA6oqe");
|
||||
static const CBitcoinAddress addr2 ("t1Xxa5ZVPKvs9bGMn7aWTiHjyHvR31XkUst");
|
||||
static const CBitcoinAddress addr1C("t1ffus9J1vhxvFqLoExGBRPjE7BcJxiSCTC");
|
||||
static const CBitcoinAddress addr2C("t1VJL2dPUyXK7avDRGqhqQA5bw2eEMdhyg6");
|
||||
|
||||
|
||||
static const string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF");
|
||||
static const string strAddressBad("t1aMkLwU1LcMZYN7TgXUJAwzA1r44dbLkSp");
|
||||
|
||||
|
||||
#ifdef KEY_TESTS_DUMPINFO
|
||||
|
||||
@@ -137,6 +137,14 @@ struct {
|
||||
// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
|
||||
BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
{
|
||||
// #1398 START
|
||||
// Current test data expects to receive a reward script for the address
|
||||
// 2N2e2FRfP9D1dRN1oRWkH7pbFM69eGNAuQ4 even though the test is run on mainnet
|
||||
// and not testnet, and there are many founders reward addresses not just one.
|
||||
// When test data is re-generated, we will no longer need to do this.
|
||||
Params(CBaseChainParams::MAIN).fMinerTestModeForFoundersRewardScript = true;
|
||||
// #1398 END
|
||||
|
||||
CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
|
||||
CBlockTemplate *pblocktemplate;
|
||||
CMutableTransaction tx,tx2;
|
||||
|
||||
@@ -34,6 +34,12 @@ Value CallRPC(string args)
|
||||
boost::split(vArgs, args, boost::is_any_of(" \t"));
|
||||
string strMethod = vArgs[0];
|
||||
vArgs.erase(vArgs.begin());
|
||||
// Handle empty strings the same way as CLI
|
||||
for (auto i = 0; i < vArgs.size(); i++) {
|
||||
if (vArgs[i] == "\"\"") {
|
||||
vArgs[i] = "";
|
||||
}
|
||||
}
|
||||
Array params = RPCConvertValues(strMethod, vArgs);
|
||||
|
||||
rpcfn_type method = tableRPC[strMethod]->actor;
|
||||
@@ -99,7 +105,7 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign)
|
||||
"\"vout\":1,\"scriptPubKey\":\"a914b10c9df5f7edf436c697f02f1efdba4cf399615187\","
|
||||
"\"redeemScript\":\"512103debedc17b3df2badbcdd86d5feb4562b86fe182e5998abd8bcd4f122c6155b1b21027e940bb73ab8732bfdf7f9216ecefca5b94d6df834e77e108f68e66f126044c052ae\"}]";
|
||||
r = CallRPC(string("createrawtransaction ")+prevout+" "+
|
||||
"{\"3HqAe9LtNBjnsfM4CyYaWTnvCaUYT7v4oZ\":11}");
|
||||
"{\"t3ahmeUm2LWXPUJPx9QMheGtqTEfdDdgr7p\":11}");
|
||||
string notsigned = r.get_str();
|
||||
string privkey1 = "\"KzsXybp9jX64P5ekX1KUxRQ79Jht9uzW7LorgwE65i5rWACL6LQe\"";
|
||||
string privkey2 = "\"Kyhdf5LuKTRx4ge69ybABsiUAWjVRK4XGxAKk2FQLp2HjGMy87Z4\"";
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace json_spirit;
|
||||
@@ -93,7 +94,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
||||
CPubKey demoPubkey = pwalletMain->GenerateNewKey();
|
||||
CBitcoinAddress demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID()));
|
||||
Value retValue;
|
||||
string strAccount = "walletDemoAccount";
|
||||
string strAccount = "";
|
||||
string strPurpose = "receive";
|
||||
BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */
|
||||
CWalletDB walletdb(pwalletMain->strWalletFile);
|
||||
@@ -109,19 +110,21 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
||||
/*********************************
|
||||
* setaccount
|
||||
*********************************/
|
||||
BOOST_CHECK_NO_THROW(CallRPC("setaccount " + setaccountDemoAddress.ToString() + " nullaccount"));
|
||||
/* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ is not owned by the test wallet. */
|
||||
BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ nullaccount"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(CallRPC("setaccount " + setaccountDemoAddress.ToString() + " \"\""));
|
||||
/* Accounts are disabled */
|
||||
BOOST_CHECK_THROW(CallRPC("setaccount " + setaccountDemoAddress.ToString() + " nullaccount"), runtime_error);
|
||||
/* t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV is not owned by the test wallet. */
|
||||
BOOST_CHECK_THROW(CallRPC("setaccount t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV nullaccount"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error);
|
||||
/* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X (33 chars) is an illegal address (should be 34 chars) */
|
||||
BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X nullaccount"), runtime_error);
|
||||
/* t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1Gpg (34 chars) is an illegal address (should be 35 chars) */
|
||||
BOOST_CHECK_THROW(CallRPC("setaccount t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1Gpg nullaccount"), runtime_error);
|
||||
|
||||
|
||||
/*********************************
|
||||
* getbalance
|
||||
*********************************/
|
||||
BOOST_CHECK_NO_THROW(CallRPC("getbalance"));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("getbalance " + demoAddress.ToString()));
|
||||
BOOST_CHECK_THROW(CallRPC("getbalance " + demoAddress.ToString()), runtime_error);
|
||||
|
||||
/*********************************
|
||||
* listunspent
|
||||
@@ -192,13 +195,16 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
||||
* getnewaddress
|
||||
*********************************/
|
||||
BOOST_CHECK_NO_THROW(CallRPC("getnewaddress"));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("getnewaddress getnewaddress_demoaccount"));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("getnewaddress \"\""));
|
||||
/* Accounts are deprecated */
|
||||
BOOST_CHECK_THROW(CallRPC("getnewaddress getnewaddress_demoaccount"), runtime_error);
|
||||
|
||||
/*********************************
|
||||
* getaccountaddress
|
||||
*********************************/
|
||||
BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress \"\""));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress accountThatDoesntExists")); // Should generate a new account
|
||||
/* Accounts are deprecated */
|
||||
BOOST_CHECK_THROW(CallRPC("getaccountaddress accountThatDoesntExists"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount));
|
||||
BOOST_CHECK(CBitcoinAddress(retValue.get_str()).Get() == demoAddress.Get());
|
||||
|
||||
@@ -214,15 +220,15 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + demoAddress.ToString() + " mymessage"));
|
||||
BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error);
|
||||
/* Should throw error because this address is not loaded in the wallet */
|
||||
BOOST_CHECK_THROW(CallRPC("signmessage 1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ mymessage"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("signmessage t1h8SqgtM3QM5e2M8EzhhT1yL2PXXtA6oqe mymessage"), runtime_error);
|
||||
|
||||
/* missing arguments */
|
||||
BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString()), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str()), runtime_error);
|
||||
/* Illegal address */
|
||||
BOOST_CHECK_THROW(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X " + retValue.get_str() + " mymessage"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("verifymessage t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1Gpg " + retValue.get_str() + " mymessage"), runtime_error);
|
||||
/* wrong address */
|
||||
BOOST_CHECK(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ " + retValue.get_str() + " mymessage").get_bool() == false);
|
||||
BOOST_CHECK(CallRPC("verifymessage t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV " + retValue.get_str() + " mymessage").get_bool() == false);
|
||||
/* Correct address and signature but wrong message */
|
||||
BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " wrongmessage").get_bool() == false);
|
||||
/* Correct address, message and signature*/
|
||||
@@ -234,8 +240,12 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
||||
BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount));
|
||||
Array arr = retValue.get_array();
|
||||
BOOST_CHECK(arr.size() > 0);
|
||||
BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get());
|
||||
BOOST_CHECK_EQUAL(4, arr.size());
|
||||
bool notFound = true;
|
||||
for (auto a : arr) {
|
||||
notFound &= CBitcoinAddress(a.get_str()).Get() != demoAddress.Get();
|
||||
}
|
||||
BOOST_CHECK(!notFound);
|
||||
|
||||
/*
|
||||
* getblocksubsidy
|
||||
@@ -265,9 +275,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_getbalance)
|
||||
|
||||
BOOST_CHECK_THROW(CallRPC("z_getbalance too many args"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("z_getbalance invalidaddress"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(CallRPC("z_getbalance mhu9XfNv9o9JfTmEoTA6xKJHBfH2BVF8qG"));
|
||||
BOOST_CHECK_THROW(CallRPC("z_getbalance mhu9XfNv9o9JfTmEoTA6xKJHBfH2BVF8qG -1"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(CallRPC("z_getbalance mhu9XfNv9o9JfTmEoTA6xKJHBfH2BVF8qG 0"));
|
||||
BOOST_CHECK_NO_THROW(CallRPC("z_getbalance tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab"));
|
||||
BOOST_CHECK_THROW(CallRPC("z_getbalance tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab -1"), runtime_error);
|
||||
BOOST_CHECK_NO_THROW(CallRPC("z_getbalance tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab 0"));
|
||||
BOOST_CHECK_THROW(CallRPC("z_getbalance tnRZ8bPq2pff3xBWhTJhNkVUkm2uhzksDeW5PvEa7aFKGT9Qi3YgTALZfjaY4jU3HLVKBtHdSXxoPoLA3naMPcHBcY88FcF 1"), runtime_error);
|
||||
|
||||
|
||||
@@ -278,9 +288,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_getbalance)
|
||||
|
||||
BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress too many args"), runtime_error);
|
||||
// negative minconf not allowed
|
||||
BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress mhu9XfNv9o9JfTmEoTA6xKJHBfH2BVF8qG -1"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab -1"), runtime_error);
|
||||
// invalid zaddr, taddr not allowed
|
||||
BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress mhu9XfNv9o9JfTmEoTA6xKJHBfH2BVF8qG 0"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab 0"), runtime_error);
|
||||
// don't have the spending key
|
||||
BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress tnRZ8bPq2pff3xBWhTJhNkVUkm2uhzksDeW5PvEa7aFKGT9Qi3YgTALZfjaY4jU3HLVKBtHdSXxoPoLA3naMPcHBcY88FcF 1"), runtime_error);
|
||||
}
|
||||
@@ -303,7 +313,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
|
||||
BOOST_CHECK(addrs.size()==1);
|
||||
|
||||
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();
|
||||
@@ -353,6 +365,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
|
||||
// error if no args
|
||||
BOOST_CHECK_THROW(CallRPC("z_importwallet"), runtime_error);
|
||||
|
||||
// error if too many args
|
||||
BOOST_CHECK_THROW(CallRPC("z_importwallet toomany args"), runtime_error);
|
||||
|
||||
// create a random key locally
|
||||
auto testSpendingKey = libzcash::SpendingKey::random();
|
||||
auto testPaymentAddress = testSpendingKey.address();
|
||||
@@ -421,6 +436,10 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
|
||||
BOOST_CHECK_THROW(CallRPC("z_importkey"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("z_exportkey"), runtime_error);
|
||||
|
||||
// error if too many args
|
||||
BOOST_CHECK_THROW(CallRPC("z_importkey too many args"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("z_exportkey toomany args"), runtime_error);
|
||||
|
||||
// wallet should currently be empty
|
||||
std::set<libzcash::PaymentAddress> addrs;
|
||||
pwalletMain->GetPaymentAddresses(addrs);
|
||||
@@ -481,6 +500,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
|
||||
CZCPaymentAddress pa(newaddress);
|
||||
auto newAddr = pa.Get();
|
||||
BOOST_CHECK(pwalletMain->HaveSpendingKey(newAddr));
|
||||
|
||||
// Check if too many args
|
||||
BOOST_CHECK_THROW(CallRPC("z_getnewaddress toomanyargs"), runtime_error);
|
||||
}
|
||||
|
||||
|
||||
@@ -700,6 +722,9 @@ BOOST_AUTO_TEST_CASE(rpc_z_getoperations)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
BOOST_CHECK(q->getOperationCount() == 0);
|
||||
|
||||
// Check if too many args
|
||||
BOOST_CHECK_THROW(CallRPC("z_listoperationids toomany args"), runtime_error);
|
||||
|
||||
Value retValue;
|
||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listoperationids"));
|
||||
BOOST_CHECK(retValue.get_array().size() == 2);
|
||||
@@ -753,10 +778,10 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
|
||||
|
||||
// bad from address
|
||||
BOOST_CHECK_THROW(CallRPC("z_sendmany "
|
||||
"INVALIDmwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs []"), runtime_error);
|
||||
"INVALIDtmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ []"), runtime_error);
|
||||
// empty amounts
|
||||
BOOST_CHECK_THROW(CallRPC("z_sendmany "
|
||||
"mwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs []"), runtime_error);
|
||||
"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ []"), runtime_error);
|
||||
|
||||
// don't have the spending key for this address
|
||||
BOOST_CHECK_THROW(CallRPC("z_sendmany "
|
||||
@@ -765,9 +790,9 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
|
||||
|
||||
// duplicate address
|
||||
BOOST_CHECK_THROW(CallRPC("z_sendmany "
|
||||
"mwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs "
|
||||
"[{\"address\":\"mvBkHw3UTeV2ivipmSA6uo8yjN4DqZ5KoG\", \"amount\":50.0},"
|
||||
" {\"address\":\"mvBkHw3UTeV2ivipmSA6uo8yjN4DqZ5KoG\", \"amount\":12.0} ]"
|
||||
"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
|
||||
"[{\"address\":\"tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn\", \"amount\":50.0},"
|
||||
" {\"address\":\"tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn\", \"amount\":12.0} ]"
|
||||
), runtime_error);
|
||||
|
||||
// memo bigger than allowed length of ZC_MEMO_SIZE
|
||||
@@ -776,7 +801,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
|
||||
std::string badmemo(v.begin(), v.end());
|
||||
CZCPaymentAddress pa = pwalletMain->GenerateNewZKey();
|
||||
std::string zaddr1 = pa.ToString();
|
||||
BOOST_CHECK_THROW(CallRPC(string("z_sendmany mwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs ")
|
||||
BOOST_CHECK_THROW(CallRPC(string("z_sendmany tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ ")
|
||||
+ "[{\"address\":\"" + zaddr1 + "\", \"amount\":123.456}]"), runtime_error);
|
||||
|
||||
// Test constructor of AsyncRPCOperation_sendmany
|
||||
@@ -793,7 +818,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
|
||||
}
|
||||
|
||||
try {
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany("mwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs", {}, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany("tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ", {}, {}, 1) );
|
||||
} catch (const Object& objError) {
|
||||
BOOST_CHECK( find_error(objError, "No recipients"));
|
||||
}
|
||||
@@ -805,7 +830,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
|
||||
BOOST_CHECK( find_error(objError, "payment address is invalid"));
|
||||
}
|
||||
|
||||
// This test is for testnet addresses which begin with 't' not 'z'.
|
||||
// Testnet payment addresses begin with 'zt'. This test detects an incorrect prefix.
|
||||
try {
|
||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient("dummy",1.0, "") };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany("zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U", recipients, {}, 1) );
|
||||
@@ -817,7 +842,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
|
||||
// invokes a method on pwalletMain, which is undefined in the google test environment.
|
||||
try {
|
||||
std::vector<SendManyRecipient> recipients = { SendManyRecipient("dummy",1.0, "") };
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany("tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkBUkJ1oSfbhTJhm72WiZizvkZz5aH1", recipients, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany("ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP", recipients, {}, 1) );
|
||||
} catch (const Object& objError) {
|
||||
BOOST_CHECK( find_error(objError, "no spending key found for zaddr"));
|
||||
}
|
||||
@@ -938,9 +963,9 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||
// add_taddr_outputs_to_tx() will append many vouts to a raw transaction
|
||||
{
|
||||
std::vector<SendManyRecipient> recipients = {
|
||||
SendManyRecipient("my53aS89nQ8SgJ8YgJ34cMHTWR33P5RTJ5",CAmount(1.23), ""),
|
||||
SendManyRecipient("mzFCFsENQq5VxfCeKwTTb1QPWKYcKXPNvj",CAmount(4.56), ""),
|
||||
SendManyRecipient("n4MmVRZdq7EgcJXgcvF5jkZT7wzH2CaWkv",CAmount(7.89), ""),
|
||||
SendManyRecipient("tmTGScYwiLMzHe4uGZtBYmuqoW4iEoYNMXt",CAmount(1.23), ""),
|
||||
SendManyRecipient("tmUSbHz3vxnwLvRyNDXbwkZxjVyDodMJEhh",CAmount(4.56), ""),
|
||||
SendManyRecipient("tmYZAXYPCP56Xa5JQWWPZuK7o7bfUQW6kkd",CAmount(7.89), ""),
|
||||
};
|
||||
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(zaddr1, recipients, {}, 1) );
|
||||
std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
|
||||
@@ -1041,4 +1066,60 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This test covers storing encrypted zkeys in the wallet.
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE(rpc_wallet_encrypted_wallet_zkeys)
|
||||
{
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
Value retValue;
|
||||
int n = 100;
|
||||
|
||||
// wallet should currently be empty
|
||||
std::set<libzcash::PaymentAddress> addrs;
|
||||
pwalletMain->GetPaymentAddresses(addrs);
|
||||
BOOST_CHECK(addrs.size()==0);
|
||||
|
||||
// create keys
|
||||
for (int i = 0; i < n; i++) {
|
||||
CallRPC("z_getnewaddress");
|
||||
}
|
||||
|
||||
// Verify we can list the keys imported
|
||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listaddresses"));
|
||||
Array arr = retValue.get_array();
|
||||
BOOST_CHECK(arr.size() == n);
|
||||
|
||||
// Encrypt the wallet (we can't call RPC encryptwallet as that shuts down node)
|
||||
SecureString strWalletPass;
|
||||
strWalletPass.reserve(100);
|
||||
strWalletPass = "hello";
|
||||
|
||||
boost::filesystem::current_path(GetArg("-datadir","/tmp/thisshouldnothappen"));
|
||||
BOOST_CHECK(pwalletMain->EncryptWallet(strWalletPass));
|
||||
|
||||
// Verify we can still list the keys imported
|
||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listaddresses"));
|
||||
arr = retValue.get_array();
|
||||
BOOST_CHECK(arr.size() == n);
|
||||
|
||||
// Try to add a new key, but we can't as the wallet is locked
|
||||
BOOST_CHECK_THROW(CallRPC("z_getnewaddress"), runtime_error);
|
||||
|
||||
// We can't call RPC walletpassphrase as that invokes RPCRunLater which breaks tests.
|
||||
// So we manually unlock.
|
||||
BOOST_CHECK(pwalletMain->Unlock(strWalletPass));
|
||||
|
||||
// Now add a key
|
||||
BOOST_CHECK_NO_THROW(CallRPC("z_getnewaddress"));
|
||||
|
||||
// Verify the key has been added
|
||||
BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listaddresses"));
|
||||
arr = retValue.get_array();
|
||||
BOOST_CHECK(arr.size() == n+1);
|
||||
|
||||
// We can't simulate over RPC the wallet closing and being reloaded
|
||||
// but there are tests for this in gtest.
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
@@ -35,10 +35,6 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
|
||||
}
|
||||
CMutableTransaction txTmp(txTo);
|
||||
|
||||
// In case concatenating two scripts ends up with two codeseparators,
|
||||
// or an extra one at the end, this prevents all those possible incompatibilities.
|
||||
scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR));
|
||||
|
||||
// Blank out other inputs' signatures
|
||||
for (unsigned int i = 0; i < txTmp.vin.size(); i++)
|
||||
txTmp.vin[i].scriptSig = CScript();
|
||||
@@ -91,7 +87,7 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
|
||||
}
|
||||
|
||||
void static RandomScript(CScript &script) {
|
||||
static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR};
|
||||
static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN};
|
||||
script = CScript();
|
||||
int ops = (insecure_rand() % 10);
|
||||
for (int i=0; i<ops; i++)
|
||||
|
||||
@@ -351,8 +351,16 @@ BOOST_AUTO_TEST_CASE(test_FormatSubVersion)
|
||||
std::vector<std::string> comments2;
|
||||
comments2.push_back(std::string("comment1"));
|
||||
comments2.push_back(std::string("comment2"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector<std::string>()),std::string("/Test:0.9.99/"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments),std::string("/Test:0.9.99(comment1)/"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2),std::string("/Test:0.9.99(comment1; comment2)/"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector<std::string>()), std::string("/Test:0.9.99-beta1/"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99924, std::vector<std::string>()), std::string("/Test:0.9.99-beta25/"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99925, std::vector<std::string>()), std::string("/Test:0.9.99-rc1/"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99949, std::vector<std::string>()), std::string("/Test:0.9.99-rc25/"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99950, std::vector<std::string>()), std::string("/Test:0.9.99/"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99951, std::vector<std::string>()), std::string("/Test:0.9.99-1/"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99999, std::vector<std::string>()), std::string("/Test:0.9.99-49/"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments), std::string("/Test:0.9.99-beta1(comment1)/"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99950, comments), std::string("/Test:0.9.99(comment1)/"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2), std::string("/Test:0.9.99-beta1(comment1; comment2)/"));
|
||||
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99950, comments2), std::string("/Test:0.9.99(comment1; comment2)/"));
|
||||
}
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
@@ -299,6 +299,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
|
||||
pindexNew->nFile = diskindex.nFile;
|
||||
pindexNew->nDataPos = diskindex.nDataPos;
|
||||
pindexNew->nUndoPos = diskindex.nUndoPos;
|
||||
pindexNew->hashAnchor = diskindex.hashAnchor;
|
||||
pindexNew->nVersion = diskindex.nVersion;
|
||||
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
|
||||
pindexNew->nTime = diskindex.nTime;
|
||||
|
||||
@@ -478,7 +478,6 @@ const boost::filesystem::path &ZC_GetParamsDir()
|
||||
return path;
|
||||
|
||||
path = ZC_GetBaseParamsDir();
|
||||
path /= BaseParams().DataDir();
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -218,13 +218,13 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
tx_ = CTransaction(rawTx);
|
||||
}
|
||||
|
||||
LogPrint("asyncrpc", "%s: spending %s to send %s with fee %s\n",
|
||||
LogPrint("zrpc", "%s: spending %s to send %s with fee %s\n",
|
||||
getId().substr(0,10), FormatMoney(targetAmount, false), FormatMoney(sendAmount, false), FormatMoney(minersFee, false));
|
||||
LogPrint("asyncrpc", " - transparent input: %s (to choose from)\n", FormatMoney(t_inputs_total, false));
|
||||
LogPrint("asyncrpc", " - private input: %s (to choose from)\n", FormatMoney(z_inputs_total, false));
|
||||
LogPrint("asyncrpc", " - transparent output: %s\n", FormatMoney(t_outputs_total, false));
|
||||
LogPrint("asyncrpc", " - private output: %s\n", FormatMoney(z_outputs_total, false));
|
||||
LogPrint("asyncrpc", " - fee: %s\n", FormatMoney(minersFee, false));
|
||||
LogPrint("zrpc", " - transparent input: %s (to choose from)\n", FormatMoney(t_inputs_total, false));
|
||||
LogPrint("zrpc", " - private input: %s (to choose from)\n", FormatMoney(z_inputs_total, false));
|
||||
LogPrint("zrpc", " - transparent output: %s\n", FormatMoney(t_outputs_total, false));
|
||||
LogPrint("zrpc", " - private output: %s\n", FormatMoney(z_outputs_total, false));
|
||||
LogPrint("zrpc", " - fee: %s\n", FormatMoney(minersFee, false));
|
||||
|
||||
/**
|
||||
* SCENARIO #1
|
||||
@@ -243,7 +243,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
if (change > 0) {
|
||||
add_taddr_change_output_to_tx(change);
|
||||
|
||||
LogPrint("asyncrpc", "%s: transparent change in transaction output (amount=%s)\n",
|
||||
LogPrint("zrpc", "%s: transparent change in transaction output (amount=%s)\n",
|
||||
getId().substr(0, 10),
|
||||
FormatMoney(change, false)
|
||||
);
|
||||
@@ -301,7 +301,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
SendManyRecipient smr(address, change, std::string());
|
||||
zOutputsDeque.push_back(smr);
|
||||
|
||||
LogPrint("asyncrpc", "%s: change from coinbase utxo is also sent to the recipient (amount=%s)\n",
|
||||
LogPrint("zrpc", "%s: change from coinbase utxo is also sent to the recipient (amount=%s)\n",
|
||||
getId().substr(0, 10),
|
||||
FormatMoney(change, false)
|
||||
);
|
||||
@@ -313,7 +313,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
// If there is a single zaddr and no coinbase utxos, just use a regular output for change.
|
||||
add_taddr_change_output_to_tx(change);
|
||||
|
||||
LogPrint("asyncrpc", "%s: transparent change in transaction output (amount=%s)\n",
|
||||
LogPrint("zrpc", "%s: transparent change in transaction output (amount=%s)\n",
|
||||
getId().substr(0, 10),
|
||||
FormatMoney(change, false)
|
||||
);
|
||||
@@ -395,7 +395,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
outPoints.push_back(outPoint);
|
||||
|
||||
|
||||
LogPrint("asyncrpc", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s)\n",
|
||||
LogPrint("zrpc", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s)\n",
|
||||
getId().substr(0, 10),
|
||||
outPoint.hash.ToString().substr(0, 10),
|
||||
outPoint.js,
|
||||
@@ -422,7 +422,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
info.vjsout.push_back(JSOutput());
|
||||
info.vjsout.push_back(JSOutput(frompaymentaddress_, jsChange));
|
||||
|
||||
LogPrint("asyncrpc", "%s: generating note for change (amount=%s)\n",
|
||||
LogPrint("zrpc", "%s: generating note for change (amount=%s)\n",
|
||||
getId().substr(0, 10),
|
||||
FormatMoney(jsChange, false)
|
||||
);
|
||||
@@ -510,7 +510,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
|
||||
jsInputValue += plaintext.value;
|
||||
|
||||
LogPrint("asyncrpc", "%s: spending change (amount=%s)\n",
|
||||
LogPrint("zrpc", "%s: spending change (amount=%s)\n",
|
||||
getId().substr(0, 10),
|
||||
FormatMoney(plaintext.value, false)
|
||||
);
|
||||
@@ -540,7 +540,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
|
||||
jsInputValue += noteFunds;
|
||||
|
||||
LogPrint("asyncrpc", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s)\n",
|
||||
LogPrint("zrpc", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s)\n",
|
||||
getId().substr(0, 10),
|
||||
jso.hash.ToString().substr(0, 10),
|
||||
jso.js,
|
||||
@@ -638,7 +638,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
if (jsChange>0) {
|
||||
info.vjsout.push_back(JSOutput(frompaymentaddress_, jsChange));
|
||||
|
||||
LogPrint("asyncrpc", "%s: generating note for change (amount=%s)\n",
|
||||
LogPrint("zrpc", "%s: generating note for change (amount=%s)\n",
|
||||
getId().substr(0, 10),
|
||||
FormatMoney(jsChange, false)
|
||||
);
|
||||
@@ -715,7 +715,7 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) {
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
|
||||
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true, fAcceptCoinbase);
|
||||
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs) {
|
||||
if (out.nDepth < mindepth_) {
|
||||
@@ -758,7 +758,7 @@ bool AsyncRPCOperation_sendmany::find_unspent_notes() {
|
||||
for (CNotePlaintextEntry & entry : entries) {
|
||||
z_inputs_.push_back(SendManyInputJSOP(entry.jsop, entry.plaintext.note(frompaymentaddress_), CAmount(entry.plaintext.value)));
|
||||
std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
|
||||
LogPrint("asyncrpc", "%s: found unspent note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, memo=%s)\n",
|
||||
LogPrint("zrpc", "%s: found unspent note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, memo=%s)\n",
|
||||
getId().substr(0, 10),
|
||||
entry.jsop.hash.ToString().substr(0, 10),
|
||||
entry.jsop.js,
|
||||
@@ -836,7 +836,7 @@ Object AsyncRPCOperation_sendmany::perform_joinsplit(
|
||||
|
||||
CMutableTransaction mtx(tx_);
|
||||
|
||||
LogPrint("asyncrpc", "%s: creating joinsplit at index %d (vpub_old=%s, vpub_new=%s, in[0]=%s, in[1]=%s, out[0]=%s, out[1]=%s)\n",
|
||||
LogPrint("zrpc", "%s: creating joinsplit at index %d (vpub_old=%s, vpub_new=%s, in[0]=%s, in[1]=%s, out[0]=%s, out[1]=%s)\n",
|
||||
getId().substr(0,10),
|
||||
tx_.vjoinsplit.size(),
|
||||
FormatMoney(info.vpub_old, false), FormatMoney(info.vpub_new, false),
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "script/script.h"
|
||||
#include "script/standard.h"
|
||||
#include "streams.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <string>
|
||||
@@ -58,15 +59,14 @@ bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned
|
||||
int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
|
||||
vchCiphertext = std::vector<unsigned char> (nCLen);
|
||||
|
||||
EVP_CIPHER_CTX ctx;
|
||||
|
||||
bool fOk = true;
|
||||
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
|
||||
if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
|
||||
if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
|
||||
assert(ctx);
|
||||
if (fOk) fOk = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
|
||||
if (fOk) fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
|
||||
if (fOk) fOk = EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
if (!fOk) return false;
|
||||
|
||||
@@ -85,15 +85,14 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
|
||||
|
||||
vchPlaintext = CKeyingMaterial(nPLen);
|
||||
|
||||
EVP_CIPHER_CTX ctx;
|
||||
|
||||
bool fOk = true;
|
||||
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
|
||||
if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
|
||||
if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
|
||||
assert(ctx);
|
||||
if (fOk) fOk = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
|
||||
if (fOk) fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
|
||||
if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
if (!fOk) return false;
|
||||
|
||||
@@ -135,12 +134,29 @@ static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsi
|
||||
return key.VerifyPubKey(vchPubKey);
|
||||
}
|
||||
|
||||
static bool DecryptSpendingKey(const CKeyingMaterial& vMasterKey,
|
||||
const std::vector<unsigned char>& vchCryptedSecret,
|
||||
const libzcash::PaymentAddress& address,
|
||||
libzcash::SpendingKey& sk)
|
||||
{
|
||||
CKeyingMaterial vchSecret;
|
||||
if(!DecryptSecret(vMasterKey, vchCryptedSecret, address.GetHash(), vchSecret))
|
||||
return false;
|
||||
|
||||
if (vchSecret.size() != libzcash::SerializedSpendingKeySize)
|
||||
return false;
|
||||
|
||||
CSecureDataStream ss(vchSecret, SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> sk;
|
||||
return sk.address() == address;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::SetCrypted()
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (fUseCrypto)
|
||||
return true;
|
||||
if (!mapKeys.empty())
|
||||
if (!(mapKeys.empty() && mapSpendingKeys.empty()))
|
||||
return false;
|
||||
fUseCrypto = true;
|
||||
return true;
|
||||
@@ -184,6 +200,21 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
|
||||
if (fDecryptionThoroughlyChecked)
|
||||
break;
|
||||
}
|
||||
CryptedSpendingKeyMap::const_iterator skmi = mapCryptedSpendingKeys.begin();
|
||||
for (; skmi != mapCryptedSpendingKeys.end(); ++skmi)
|
||||
{
|
||||
const libzcash::PaymentAddress &address = (*skmi).first;
|
||||
const std::vector<unsigned char> &vchCryptedSecret = (*skmi).second;
|
||||
libzcash::SpendingKey sk;
|
||||
if (!DecryptSpendingKey(vMasterKeyIn, vchCryptedSecret, address, sk))
|
||||
{
|
||||
keyFail = true;
|
||||
break;
|
||||
}
|
||||
keyPass = true;
|
||||
if (fDecryptionThoroughlyChecked)
|
||||
break;
|
||||
}
|
||||
if (keyPass && keyFail)
|
||||
{
|
||||
LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
|
||||
@@ -267,10 +298,66 @@ bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) co
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk)
|
||||
{
|
||||
{
|
||||
LOCK(cs_SpendingKeyStore);
|
||||
if (!IsCrypted())
|
||||
return CBasicKeyStore::AddSpendingKey(sk);
|
||||
|
||||
if (IsLocked())
|
||||
return false;
|
||||
|
||||
std::vector<unsigned char> vchCryptedSecret;
|
||||
CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << sk;
|
||||
CKeyingMaterial vchSecret(ss.begin(), ss.end());
|
||||
auto address = sk.address();
|
||||
if (!EncryptSecret(vMasterKey, vchSecret, address.GetHash(), vchCryptedSecret))
|
||||
return false;
|
||||
|
||||
if (!AddCryptedSpendingKey(address, sk.viewing_key(), vchCryptedSecret))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::PaymentAddress &address,
|
||||
const libzcash::ViewingKey &vk,
|
||||
const std::vector<unsigned char> &vchCryptedSecret)
|
||||
{
|
||||
{
|
||||
LOCK(cs_SpendingKeyStore);
|
||||
if (!SetCrypted())
|
||||
return false;
|
||||
|
||||
mapCryptedSpendingKeys[address] = vchCryptedSecret;
|
||||
mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(vk)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey &skOut) const
|
||||
{
|
||||
{
|
||||
LOCK(cs_SpendingKeyStore);
|
||||
if (!IsCrypted())
|
||||
return CBasicKeyStore::GetSpendingKey(address, skOut);
|
||||
|
||||
CryptedSpendingKeyMap::const_iterator mi = mapCryptedSpendingKeys.find(address);
|
||||
if (mi != mapCryptedSpendingKeys.end())
|
||||
{
|
||||
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second;
|
||||
return DecryptSpendingKey(vMasterKey, vchCryptedSecret, address, skOut);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
|
||||
{
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
LOCK2(cs_KeyStore, cs_SpendingKeyStore);
|
||||
if (!mapCryptedKeys.empty() || IsCrypted())
|
||||
return false;
|
||||
|
||||
@@ -287,6 +374,20 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
|
||||
return false;
|
||||
}
|
||||
mapKeys.clear();
|
||||
BOOST_FOREACH(SpendingKeyMap::value_type& mSpendingKey, mapSpendingKeys)
|
||||
{
|
||||
const libzcash::SpendingKey &sk = mSpendingKey.second;
|
||||
CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << sk;
|
||||
CKeyingMaterial vchSecret(ss.begin(), ss.end());
|
||||
libzcash::PaymentAddress address = sk.address();
|
||||
std::vector<unsigned char> vchCryptedSecret;
|
||||
if (!EncryptSecret(vMasterKeyIn, vchSecret, address.GetHash(), vchCryptedSecret))
|
||||
return false;
|
||||
if (!AddCryptedSpendingKey(address, sk.viewing_key(), vchCryptedSecret))
|
||||
return false;
|
||||
}
|
||||
mapSpendingKeys.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
|
||||
#include "keystore.h"
|
||||
#include "serialize.h"
|
||||
#include "streams.h"
|
||||
#include "support/allocators/secure.h"
|
||||
#include "zcash/Address.hpp"
|
||||
|
||||
class uint256;
|
||||
|
||||
@@ -66,6 +68,18 @@ public:
|
||||
|
||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
|
||||
|
||||
class CSecureDataStream : public CBaseDataStream<CKeyingMaterial>
|
||||
{
|
||||
public:
|
||||
explicit CSecureDataStream(int nTypeIn, int nVersionIn) : CBaseDataStream(nTypeIn, nVersionIn) { }
|
||||
|
||||
CSecureDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) :
|
||||
CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
|
||||
|
||||
CSecureDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) :
|
||||
CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
|
||||
};
|
||||
|
||||
/** Encryption/decryption context with key information */
|
||||
class CCrypter
|
||||
{
|
||||
@@ -114,10 +128,11 @@ class CCryptoKeyStore : public CBasicKeyStore
|
||||
{
|
||||
private:
|
||||
CryptedKeyMap mapCryptedKeys;
|
||||
CryptedSpendingKeyMap mapCryptedSpendingKeys;
|
||||
|
||||
CKeyingMaterial vMasterKey;
|
||||
|
||||
//! if fUseCrypto is true, mapKeys must be empty
|
||||
//! if fUseCrypto is true, mapKeys and mapSpendingKeys must be empty
|
||||
//! if fUseCrypto is false, vMasterKey must be empty
|
||||
bool fUseCrypto;
|
||||
|
||||
@@ -185,6 +200,36 @@ public:
|
||||
mi++;
|
||||
}
|
||||
}
|
||||
virtual bool AddCryptedSpendingKey(const libzcash::PaymentAddress &address,
|
||||
const libzcash::ViewingKey &vk,
|
||||
const std::vector<unsigned char> &vchCryptedSecret);
|
||||
bool AddSpendingKey(const libzcash::SpendingKey &sk);
|
||||
bool HaveSpendingKey(const libzcash::PaymentAddress &address) const
|
||||
{
|
||||
{
|
||||
LOCK(cs_KeyStore);
|
||||
if (!IsCrypted())
|
||||
return CBasicKeyStore::HaveSpendingKey(address);
|
||||
return mapCryptedSpendingKeys.count(address) > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey &skOut) const;
|
||||
void GetPaymentAddresses(std::set<libzcash::PaymentAddress> &setAddress) const
|
||||
{
|
||||
if (!IsCrypted())
|
||||
{
|
||||
CBasicKeyStore::GetPaymentAddresses(setAddress);
|
||||
return;
|
||||
}
|
||||
setAddress.clear();
|
||||
CryptedSpendingKeyMap::const_iterator mi = mapCryptedSpendingKeys.begin();
|
||||
while (mi != mapCryptedSpendingKeys.end())
|
||||
{
|
||||
setAddress.insert((*mi).first);
|
||||
mi++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wallet status (encrypted, locked) changed.
|
||||
|
||||
@@ -43,7 +43,7 @@ void CDBEnv::EnvShutdown()
|
||||
if (ret != 0)
|
||||
LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
|
||||
if (!fMockDb)
|
||||
DbEnv(0).remove(strPath.c_str(), 0);
|
||||
DbEnv(u_int32_t{0}).remove(strPath.c_str(), 0);
|
||||
}
|
||||
|
||||
void CDBEnv::Reset()
|
||||
|
||||
@@ -11,15 +11,38 @@
|
||||
#include "zcash/Note.hpp"
|
||||
#include "zcash/NoteEncryption.hpp"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Return;
|
||||
|
||||
ZCJoinSplit* params = ZCJoinSplit::Unopened();
|
||||
|
||||
ACTION(ThrowLogicError) {
|
||||
throw std::logic_error("Boom");
|
||||
}
|
||||
|
||||
class MockWalletDB {
|
||||
public:
|
||||
MOCK_METHOD0(TxnBegin, bool());
|
||||
MOCK_METHOD0(TxnCommit, bool());
|
||||
MOCK_METHOD0(TxnAbort, bool());
|
||||
|
||||
MOCK_METHOD2(WriteTx, bool(uint256 hash, const CWalletTx& wtx));
|
||||
MOCK_METHOD1(WriteWitnessCacheSize, bool(int64_t nWitnessCacheSize));
|
||||
};
|
||||
|
||||
template void CWallet::WriteWitnessCache<MockWalletDB>(MockWalletDB& walletdb);
|
||||
|
||||
class TestWallet : public CWallet {
|
||||
public:
|
||||
TestWallet() : CWallet() { }
|
||||
|
||||
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn) {
|
||||
return CCryptoKeyStore::EncryptKeys(vMasterKeyIn);
|
||||
}
|
||||
|
||||
bool Unlock(const CKeyingMaterial& vMasterKeyIn) {
|
||||
return CCryptoKeyStore::Unlock(vMasterKeyIn);
|
||||
}
|
||||
|
||||
void IncrementNoteWitnesses(const CBlockIndex* pindex,
|
||||
const CBlock* pblock,
|
||||
ZCIncrementalMerkleTree tree) {
|
||||
@@ -28,6 +51,9 @@ public:
|
||||
void DecrementNoteWitnesses() {
|
||||
CWallet::DecrementNoteWitnesses();
|
||||
}
|
||||
void WriteWitnessCache(MockWalletDB& walletdb) {
|
||||
CWallet::WriteWitnessCache(walletdb);
|
||||
}
|
||||
bool UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx) {
|
||||
return CWallet::UpdatedNoteData(wtxIn, wtx);
|
||||
}
|
||||
@@ -175,12 +201,10 @@ TEST(wallet_tests, note_data_serialisation) {
|
||||
EXPECT_EQ(noteData[jsoutpt].witnesses, noteData2[jsoutpt].witnesses);
|
||||
}
|
||||
|
||||
|
||||
TEST(wallet_tests, find_unspent_notes) {
|
||||
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
|
||||
CWallet wallet;
|
||||
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
wallet.AddSpendingKey(sk);
|
||||
|
||||
@@ -188,44 +212,28 @@ TEST(wallet_tests, find_unspent_notes) {
|
||||
auto note = GetNote(sk, wtx, 0, 1);
|
||||
auto nullifier = note.nullifier(sk);
|
||||
|
||||
auto noteMap = wallet.FindMyNotes(wtx);
|
||||
EXPECT_EQ(2, noteMap.size());
|
||||
|
||||
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);
|
||||
EXPECT_FALSE(wallet.IsSpent(nullifier));
|
||||
|
||||
auto wtx2 = GetValidSpend(sk, note, 5);
|
||||
wallet.AddToWallet(wtx2, true, NULL);
|
||||
|
||||
// two notes, one is spent but wallet doesn't see it as spent yet until mined
|
||||
// We currently have an unspent and unconfirmed note in the wallet (depth of -1)
|
||||
std::vector<CNotePlaintextEntry> entries;
|
||||
wallet.GetFilteredNotes(entries, "", 0);
|
||||
EXPECT_EQ(2, entries.size());
|
||||
|
||||
// Create new payment address, add new note, and filter
|
||||
auto user2_sk = libzcash::SpendingKey::random();
|
||||
wallet.AddSpendingKey(user2_sk);
|
||||
auto user2_pa = user2_sk.address();
|
||||
auto user2_payment_address = CZCPaymentAddress(user2_pa).ToString();
|
||||
auto wtx3 = GetValidReceive(user2_sk, 15, true); // adds 2 more notes
|
||||
auto note2 = GetNote(user2_sk, wtx3, 0, 1);
|
||||
auto nullifier2 = note2.nullifier(user2_sk);
|
||||
wallet.AddToWallet(wtx3, true, NULL);
|
||||
EXPECT_FALSE(wallet.IsSpent(nullifier2));
|
||||
EXPECT_EQ(0, entries.size());
|
||||
entries.clear();
|
||||
wallet.GetFilteredNotes(entries, "", -1);
|
||||
EXPECT_EQ(1, entries.size());
|
||||
entries.clear();
|
||||
|
||||
// 4 notes in wallet, 1 spent (not seen), 1 is the new payment address
|
||||
entries.clear();
|
||||
wallet.GetFilteredNotes(entries, "", 0);
|
||||
EXPECT_EQ(4, entries.size());
|
||||
entries.clear();
|
||||
wallet.GetFilteredNotes(entries, user2_payment_address, 0);
|
||||
EXPECT_EQ(2, entries.size());
|
||||
|
||||
// Fake-mine the transaction
|
||||
EXPECT_EQ(-1, chainActive.Height());
|
||||
|
||||
CBlock block;
|
||||
block.vtx.push_back(wtx2);
|
||||
block.vtx.push_back(wtx);
|
||||
block.hashMerkleRoot = block.BuildMerkleTree();
|
||||
auto blockHash = block.GetHash();
|
||||
CBlockIndex fakeIndex {block};
|
||||
@@ -234,22 +242,122 @@ TEST(wallet_tests, find_unspent_notes) {
|
||||
EXPECT_TRUE(chainActive.Contains(&fakeIndex));
|
||||
EXPECT_EQ(0, chainActive.Height());
|
||||
|
||||
wtx2.SetMerkleBranch(block);
|
||||
wtx.SetMerkleBranch(block);
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
EXPECT_FALSE(wallet.IsSpent(nullifier));
|
||||
|
||||
|
||||
// We now have an unspent and confirmed note in the wallet (depth of 1)
|
||||
wallet.GetFilteredNotes(entries, "", 0);
|
||||
EXPECT_EQ(1, entries.size());
|
||||
entries.clear();
|
||||
wallet.GetFilteredNotes(entries, "", 1);
|
||||
EXPECT_EQ(1, entries.size());
|
||||
entries.clear();
|
||||
wallet.GetFilteredNotes(entries, "", 2);
|
||||
EXPECT_EQ(0, entries.size());
|
||||
entries.clear();
|
||||
|
||||
|
||||
// Let's spend the note.
|
||||
auto wtx2 = GetValidSpend(sk, note, 5);
|
||||
wallet.AddToWallet(wtx2, true, NULL);
|
||||
EXPECT_FALSE(wallet.IsSpent(nullifier));
|
||||
|
||||
// Fake-mine a spend transaction
|
||||
EXPECT_EQ(0, chainActive.Height());
|
||||
CBlock block2;
|
||||
block2.vtx.push_back(wtx2);
|
||||
block2.hashMerkleRoot = block2.BuildMerkleTree();
|
||||
block2.hashPrevBlock = blockHash;
|
||||
auto blockHash2 = block2.GetHash();
|
||||
CBlockIndex fakeIndex2 {block2};
|
||||
mapBlockIndex.insert(std::make_pair(blockHash2, &fakeIndex2));
|
||||
fakeIndex2.nHeight = 1;
|
||||
chainActive.SetTip(&fakeIndex2);
|
||||
EXPECT_TRUE(chainActive.Contains(&fakeIndex2));
|
||||
EXPECT_EQ(1, chainActive.Height());
|
||||
|
||||
wtx2.SetMerkleBranch(block2);
|
||||
wallet.AddToWallet(wtx2, true, NULL);
|
||||
EXPECT_TRUE(wallet.IsSpent(nullifier));
|
||||
|
||||
// 4 notes, 1 spent (now seen)
|
||||
entries.clear();
|
||||
// The note has been spent. By default, GetFilteredNotes() ignores spent notes.
|
||||
wallet.GetFilteredNotes(entries, "", 0);
|
||||
EXPECT_EQ(3, entries.size());
|
||||
EXPECT_EQ(0, entries.size());
|
||||
entries.clear();
|
||||
// no change to user2 and their two notes.
|
||||
wallet.GetFilteredNotes(entries, user2_payment_address, 0);
|
||||
// Let's include spent notes to retrieve it.
|
||||
wallet.GetFilteredNotes(entries, "", 0, false);
|
||||
EXPECT_EQ(1, entries.size());
|
||||
entries.clear();
|
||||
// The spent note has two confirmations.
|
||||
wallet.GetFilteredNotes(entries, "", 2, false);
|
||||
EXPECT_EQ(1, entries.size());
|
||||
entries.clear();
|
||||
// It does not have 3 confirmations.
|
||||
wallet.GetFilteredNotes(entries, "", 3, false);
|
||||
EXPECT_EQ(0, entries.size());
|
||||
entries.clear();
|
||||
|
||||
|
||||
// Let's receive a new note
|
||||
CWalletTx wtx3;
|
||||
{
|
||||
auto wtx = GetValidReceive(sk, 20, true);
|
||||
auto note = GetNote(sk, wtx, 0, 1);
|
||||
auto nullifier = note.nullifier(sk);
|
||||
|
||||
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);
|
||||
EXPECT_FALSE(wallet.IsSpent(nullifier));
|
||||
|
||||
wtx3 = wtx;
|
||||
}
|
||||
|
||||
// Fake-mine the new transaction
|
||||
EXPECT_EQ(1, chainActive.Height());
|
||||
CBlock block3;
|
||||
block3.vtx.push_back(wtx3);
|
||||
block3.hashMerkleRoot = block3.BuildMerkleTree();
|
||||
block3.hashPrevBlock = blockHash2;
|
||||
auto blockHash3 = block3.GetHash();
|
||||
CBlockIndex fakeIndex3 {block3};
|
||||
mapBlockIndex.insert(std::make_pair(blockHash3, &fakeIndex3));
|
||||
fakeIndex3.nHeight = 2;
|
||||
chainActive.SetTip(&fakeIndex3);
|
||||
EXPECT_TRUE(chainActive.Contains(&fakeIndex3));
|
||||
EXPECT_EQ(2, chainActive.Height());
|
||||
|
||||
wtx3.SetMerkleBranch(block3);
|
||||
wallet.AddToWallet(wtx3, true, NULL);
|
||||
|
||||
// We now have an unspent note which has one confirmation, in addition to our spent note.
|
||||
wallet.GetFilteredNotes(entries, "", 1);
|
||||
EXPECT_EQ(1, entries.size());
|
||||
entries.clear();
|
||||
// Let's return the spent note too.
|
||||
wallet.GetFilteredNotes(entries, "", 1, false);
|
||||
EXPECT_EQ(2, entries.size());
|
||||
|
||||
entries.clear();
|
||||
// Increasing number of confirmations will exclude our new unspent note.
|
||||
wallet.GetFilteredNotes(entries, "", 2, false);
|
||||
EXPECT_EQ(1, entries.size());
|
||||
entries.clear();
|
||||
// If we also ignore spent notes at thie depth, we won't find any notes.
|
||||
wallet.GetFilteredNotes(entries, "", 2, true);
|
||||
EXPECT_EQ(0, entries.size());
|
||||
entries.clear();
|
||||
|
||||
// Tear down
|
||||
chainActive.SetTip(NULL);
|
||||
mapBlockIndex.erase(blockHash);
|
||||
mapBlockIndex.erase(blockHash2);
|
||||
mapBlockIndex.erase(blockHash3);
|
||||
}
|
||||
|
||||
|
||||
@@ -282,12 +390,72 @@ TEST(wallet_tests, set_invalid_note_addrs_in_cwallettx) {
|
||||
EXPECT_THROW(wtx.SetNoteData(noteData), std::logic_error);
|
||||
}
|
||||
|
||||
TEST(wallet_tests, find_note_in_tx) {
|
||||
TEST(wallet_tests, GetNoteNullifier) {
|
||||
CWallet wallet;
|
||||
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
auto address = sk.address();
|
||||
auto dec = ZCNoteDecryption(sk.viewing_key());
|
||||
|
||||
auto wtx = GetValidReceive(sk, 10, true);
|
||||
auto note = GetNote(sk, wtx, 0, 1);
|
||||
auto nullifier = note.nullifier(sk);
|
||||
|
||||
auto hSig = wtx.vjoinsplit[0].h_sig(
|
||||
*params, wtx.joinSplitPubKey);
|
||||
|
||||
auto ret = wallet.GetNoteNullifier(
|
||||
wtx.vjoinsplit[0],
|
||||
address,
|
||||
dec,
|
||||
hSig, 1);
|
||||
EXPECT_NE(nullifier, ret);
|
||||
|
||||
wallet.AddSpendingKey(sk);
|
||||
|
||||
ret = wallet.GetNoteNullifier(
|
||||
wtx.vjoinsplit[0],
|
||||
address,
|
||||
dec,
|
||||
hSig, 1);
|
||||
EXPECT_EQ(nullifier, ret);
|
||||
}
|
||||
|
||||
TEST(wallet_tests, FindMyNotes) {
|
||||
CWallet wallet;
|
||||
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
auto sk2 = libzcash::SpendingKey::random();
|
||||
wallet.AddSpendingKey(sk2);
|
||||
|
||||
auto wtx = GetValidReceive(sk, 10, true);
|
||||
auto note = GetNote(sk, wtx, 0, 1);
|
||||
auto nullifier = note.nullifier(sk);
|
||||
|
||||
auto noteMap = wallet.FindMyNotes(wtx);
|
||||
EXPECT_EQ(0, noteMap.size());
|
||||
|
||||
wallet.AddSpendingKey(sk);
|
||||
|
||||
noteMap = wallet.FindMyNotes(wtx);
|
||||
EXPECT_EQ(2, noteMap.size());
|
||||
|
||||
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
|
||||
CNoteData nd {sk.address(), nullifier};
|
||||
EXPECT_EQ(1, noteMap.count(jsoutpt));
|
||||
EXPECT_EQ(nd, noteMap[jsoutpt]);
|
||||
}
|
||||
|
||||
TEST(wallet_tests, FindMyNotesInEncryptedWallet) {
|
||||
TestWallet wallet;
|
||||
uint256 r {GetRandHash()};
|
||||
CKeyingMaterial vMasterKey (r.begin(), r.end());
|
||||
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
wallet.AddSpendingKey(sk);
|
||||
|
||||
ASSERT_TRUE(wallet.EncryptKeys(vMasterKey));
|
||||
|
||||
auto wtx = GetValidReceive(sk, 10, true);
|
||||
auto note = GetNote(sk, wtx, 0, 1);
|
||||
auto nullifier = note.nullifier(sk);
|
||||
@@ -298,6 +466,13 @@ TEST(wallet_tests, find_note_in_tx) {
|
||||
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
|
||||
CNoteData nd {sk.address(), nullifier};
|
||||
EXPECT_EQ(1, noteMap.count(jsoutpt));
|
||||
EXPECT_NE(nd, noteMap[jsoutpt]);
|
||||
|
||||
ASSERT_TRUE(wallet.Unlock(vMasterKey));
|
||||
|
||||
noteMap = wallet.FindMyNotes(wtx);
|
||||
EXPECT_EQ(2, noteMap.size());
|
||||
EXPECT_EQ(1, noteMap.count(jsoutpt));
|
||||
EXPECT_EQ(nd, noteMap[jsoutpt]);
|
||||
}
|
||||
|
||||
@@ -463,8 +638,9 @@ TEST(wallet_tests, cached_witnesses_empty_chain) {
|
||||
|
||||
CBlock block;
|
||||
block.vtx.push_back(wtx);
|
||||
CBlockIndex index(block);
|
||||
ZCIncrementalMerkleTree tree;
|
||||
wallet.IncrementNoteWitnesses(NULL, &block, tree);
|
||||
wallet.IncrementNoteWitnesses(&index, &block, tree);
|
||||
witnesses.clear();
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor);
|
||||
EXPECT_TRUE((bool) witnesses[0]);
|
||||
@@ -502,7 +678,9 @@ TEST(wallet_tests, cached_witnesses_chain_tip) {
|
||||
|
||||
// First block (case tested in _empty_chain)
|
||||
block1.vtx.push_back(wtx);
|
||||
wallet.IncrementNoteWitnesses(NULL, &block1, tree);
|
||||
CBlockIndex index1(block1);
|
||||
index1.nHeight = 1;
|
||||
wallet.IncrementNoteWitnesses(&index1, &block1, tree);
|
||||
// Called to fetch anchor
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor1);
|
||||
}
|
||||
@@ -531,8 +709,10 @@ TEST(wallet_tests, cached_witnesses_chain_tip) {
|
||||
CBlock block2;
|
||||
block2.hashPrevBlock = block1.GetHash();
|
||||
block2.vtx.push_back(wtx);
|
||||
CBlockIndex index2(block2);
|
||||
index2.nHeight = 2;
|
||||
ZCIncrementalMerkleTree tree2 {tree};
|
||||
wallet.IncrementNoteWitnesses(NULL, &block2, tree2);
|
||||
wallet.IncrementNoteWitnesses(&index2, &block2, tree2);
|
||||
witnesses.clear();
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor2);
|
||||
EXPECT_TRUE((bool) witnesses[0]);
|
||||
@@ -549,7 +729,7 @@ TEST(wallet_tests, cached_witnesses_chain_tip) {
|
||||
|
||||
// Re-incrementing with the same block should give the same result
|
||||
uint256 anchor4;
|
||||
wallet.IncrementNoteWitnesses(NULL, &block2, tree);
|
||||
wallet.IncrementNoteWitnesses(&index2, &block2, tree);
|
||||
witnesses.clear();
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor4);
|
||||
EXPECT_TRUE((bool) witnesses[0]);
|
||||
@@ -557,6 +737,141 @@ TEST(wallet_tests, cached_witnesses_chain_tip) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(wallet_tests, ClearNoteWitnessCache) {
|
||||
TestWallet wallet;
|
||||
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
wallet.AddSpendingKey(sk);
|
||||
|
||||
auto wtx = GetValidReceive(sk, 10, true);
|
||||
auto note = GetNote(sk, wtx, 0, 0);
|
||||
auto nullifier = note.nullifier(sk);
|
||||
|
||||
mapNoteData_t noteData;
|
||||
JSOutPoint jsoutpt {wtx.GetHash(), 0, 0};
|
||||
JSOutPoint jsoutpt2 {wtx.GetHash(), 0, 1};
|
||||
CNoteData nd {sk.address(), nullifier};
|
||||
noteData[jsoutpt] = nd;
|
||||
wtx.SetNoteData(noteData);
|
||||
|
||||
// Pretend we mined the tx by adding a fake witness
|
||||
ZCIncrementalMerkleTree tree;
|
||||
wtx.mapNoteData[jsoutpt].witnesses.push_front(tree.witness());
|
||||
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
|
||||
std::vector<JSOutPoint> notes {jsoutpt, jsoutpt2};
|
||||
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
|
||||
uint256 anchor2;
|
||||
|
||||
// Before clearing, we should have a witness for one note
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor2);
|
||||
EXPECT_TRUE((bool) witnesses[0]);
|
||||
EXPECT_FALSE((bool) witnesses[1]);
|
||||
|
||||
// After clearing, we should not have a witness for either note
|
||||
wallet.ClearNoteWitnessCache();
|
||||
witnesses.clear();
|
||||
wallet.GetNoteWitnesses(notes, witnesses, anchor2);
|
||||
EXPECT_FALSE((bool) witnesses[0]);
|
||||
EXPECT_FALSE((bool) witnesses[1]);
|
||||
}
|
||||
|
||||
TEST(wallet_tests, WriteWitnessCache) {
|
||||
TestWallet wallet;
|
||||
MockWalletDB walletdb;
|
||||
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
wallet.AddSpendingKey(sk);
|
||||
|
||||
auto wtx = GetValidReceive(sk, 10, true);
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
|
||||
// TxnBegin fails
|
||||
EXPECT_CALL(walletdb, TxnBegin())
|
||||
.WillOnce(Return(false));
|
||||
wallet.WriteWitnessCache(walletdb);
|
||||
EXPECT_CALL(walletdb, TxnBegin())
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
// WriteTx fails
|
||||
EXPECT_CALL(walletdb, WriteTx(wtx.GetHash(), wtx))
|
||||
.WillOnce(Return(false));
|
||||
EXPECT_CALL(walletdb, TxnAbort())
|
||||
.Times(1);
|
||||
wallet.WriteWitnessCache(walletdb);
|
||||
|
||||
// WriteTx throws
|
||||
EXPECT_CALL(walletdb, WriteTx(wtx.GetHash(), wtx))
|
||||
.WillOnce(ThrowLogicError());
|
||||
EXPECT_CALL(walletdb, TxnAbort())
|
||||
.Times(1);
|
||||
wallet.WriteWitnessCache(walletdb);
|
||||
EXPECT_CALL(walletdb, WriteTx(wtx.GetHash(), wtx))
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
// WriteWitnessCacheSize fails
|
||||
EXPECT_CALL(walletdb, WriteWitnessCacheSize(0))
|
||||
.WillOnce(Return(false));
|
||||
EXPECT_CALL(walletdb, TxnAbort())
|
||||
.Times(1);
|
||||
wallet.WriteWitnessCache(walletdb);
|
||||
|
||||
// WriteWitnessCacheSize throws
|
||||
EXPECT_CALL(walletdb, WriteWitnessCacheSize(0))
|
||||
.WillOnce(ThrowLogicError());
|
||||
EXPECT_CALL(walletdb, TxnAbort())
|
||||
.Times(1);
|
||||
wallet.WriteWitnessCache(walletdb);
|
||||
EXPECT_CALL(walletdb, WriteWitnessCacheSize(0))
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
// TxCommit fails
|
||||
EXPECT_CALL(walletdb, TxnCommit())
|
||||
.WillOnce(Return(false));
|
||||
wallet.WriteWitnessCache(walletdb);
|
||||
EXPECT_CALL(walletdb, TxnCommit())
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
// Everything succeeds
|
||||
wallet.WriteWitnessCache(walletdb);
|
||||
}
|
||||
|
||||
TEST(wallet_tests, UpdateNullifierNoteMap) {
|
||||
TestWallet wallet;
|
||||
uint256 r {GetRandHash()};
|
||||
CKeyingMaterial vMasterKey (r.begin(), r.end());
|
||||
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
wallet.AddSpendingKey(sk);
|
||||
|
||||
ASSERT_TRUE(wallet.EncryptKeys(vMasterKey));
|
||||
|
||||
auto wtx = GetValidReceive(sk, 10, true);
|
||||
auto note = GetNote(sk, wtx, 0, 1);
|
||||
auto nullifier = note.nullifier(sk);
|
||||
|
||||
// Pretend that we called FindMyNotes while the wallet was locked
|
||||
mapNoteData_t noteData;
|
||||
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
|
||||
CNoteData nd {sk.address()};
|
||||
noteData[jsoutpt] = nd;
|
||||
wtx.SetNoteData(noteData);
|
||||
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
EXPECT_EQ(0, wallet.mapNullifiersToNotes.count(nullifier));
|
||||
|
||||
EXPECT_FALSE(wallet.UpdateNullifierNoteMap());
|
||||
|
||||
ASSERT_TRUE(wallet.Unlock(vMasterKey));
|
||||
|
||||
EXPECT_TRUE(wallet.UpdateNullifierNoteMap());
|
||||
EXPECT_EQ(1, wallet.mapNullifiersToNotes.count(nullifier));
|
||||
EXPECT_EQ(wtx.GetHash(), wallet.mapNullifiersToNotes[nullifier].hash);
|
||||
EXPECT_EQ(0, wallet.mapNullifiersToNotes[nullifier].js);
|
||||
EXPECT_EQ(1, wallet.mapNullifiersToNotes[nullifier].n);
|
||||
}
|
||||
|
||||
TEST(wallet_tests, UpdatedNoteData) {
|
||||
TestWallet wallet;
|
||||
|
||||
@@ -592,12 +907,12 @@ TEST(wallet_tests, UpdatedNoteData) {
|
||||
|
||||
// The txs should initially be different
|
||||
EXPECT_NE(wtx.mapNoteData, wtx2.mapNoteData);
|
||||
EXPECT_NE(wtx.mapNoteData[jsoutpt].witnesses, wtx2.mapNoteData[jsoutpt].witnesses);
|
||||
EXPECT_EQ(1, wtx.mapNoteData[jsoutpt].witnesses.size());
|
||||
|
||||
// After updating, they should be the same
|
||||
EXPECT_TRUE(wallet.UpdatedNoteData(wtx, wtx2));
|
||||
EXPECT_TRUE(wallet.UpdatedNoteData(wtx2, wtx));
|
||||
EXPECT_EQ(wtx.mapNoteData, wtx2.mapNoteData);
|
||||
EXPECT_EQ(wtx.mapNoteData[jsoutpt].witnesses, wtx2.mapNoteData[jsoutpt].witnesses);
|
||||
EXPECT_EQ(1, wtx.mapNoteData[jsoutpt].witnesses.size());
|
||||
// TODO: The new note should get witnessed (but maybe not here) (#1350)
|
||||
}
|
||||
|
||||
|
||||
@@ -305,11 +305,11 @@ Value importwallet_impl(const Array& params, bool fHelp, bool fImportZKeys)
|
||||
libzcash::SpendingKey key = spendingkey.Get();
|
||||
libzcash::PaymentAddress addr = key.address();
|
||||
if (pwalletMain->HaveSpendingKey(addr)) {
|
||||
LogPrintf("Skipping import of zaddr %s (key already present)\n", CZCPaymentAddress(addr).ToString());
|
||||
LogPrint("zrpc", "Skipping import of zaddr %s (key already present)\n", CZCPaymentAddress(addr).ToString());
|
||||
continue;
|
||||
}
|
||||
int64_t nTime = DecodeDumpTime(vstr[1]);
|
||||
LogPrintf("Importing zaddr %s...\n", CZCPaymentAddress(addr).ToString());
|
||||
LogPrint("zrpc", "Importing zaddr %s...\n", CZCPaymentAddress(addr).ToString());
|
||||
if (!pwalletMain->AddZKey(key)) {
|
||||
// Something went wrong
|
||||
fGood = false;
|
||||
@@ -320,7 +320,7 @@ Value importwallet_impl(const Array& params, bool fHelp, bool fImportZKeys)
|
||||
continue;
|
||||
}
|
||||
catch (const std::runtime_error &e) {
|
||||
LogPrintf("Importing detected an error: %s\n", e.what());
|
||||
LogPrint("zrpc","Importing detected an error: %s\n", e.what());
|
||||
// Not a valid spending key, so carry on and see if it's a Bitcoin style address.
|
||||
}
|
||||
}
|
||||
@@ -532,9 +532,9 @@ Value z_importkey(const Array& params, bool fHelp)
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return Value::null;
|
||||
|
||||
if (fHelp || params.size() < 1 || params.size() > 3)
|
||||
if (fHelp || params.size() < 1 || params.size() > 2)
|
||||
throw runtime_error(
|
||||
"z_importkey \"zkey\" ( \"label\" rescan )\n"
|
||||
"z_importkey \"zkey\" ( rescan )\n"
|
||||
"\nAdds a zkey (as returned by z_exportkey) to your wallet.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"zkey\" (string, required) The zkey (see z_exportkey)\n"
|
||||
@@ -545,10 +545,8 @@ Value z_importkey(const Array& params, bool fHelp)
|
||||
+ HelpExampleCli("z_exportkey", "\"myaddress\"") +
|
||||
"\nImport the zkey with rescan\n"
|
||||
+ HelpExampleCli("z_importkey", "\"mykey\"") +
|
||||
"\nImport using a label and without rescan\n"
|
||||
+ HelpExampleCli("z_importkey", "\"mykey\" \"testing\" false") +
|
||||
"\nAs a JSON-RPC call\n"
|
||||
+ HelpExampleRpc("z_importkey", "\"mykey\", \"testing\", false")
|
||||
+ HelpExampleRpc("z_importkey", "\"mykey\", false")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
@@ -39,6 +39,8 @@ using namespace json_spirit;
|
||||
|
||||
using namespace libzcash;
|
||||
|
||||
extern Array TxJoinSplitToJSON(const CTransaction& tx);
|
||||
|
||||
int64_t nWalletUnlockTime;
|
||||
static CCriticalSection cs_nWalletUnlockTime;
|
||||
|
||||
@@ -92,13 +94,15 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
|
||||
entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
|
||||
BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
|
||||
entry.push_back(Pair(item.first, item.second));
|
||||
|
||||
entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
|
||||
}
|
||||
|
||||
string AccountFromValue(const Value& value)
|
||||
{
|
||||
string strAccount = value.get_str();
|
||||
if (strAccount == "*")
|
||||
throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
|
||||
if (strAccount != "")
|
||||
throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
|
||||
return strAccount;
|
||||
}
|
||||
|
||||
@@ -111,10 +115,8 @@ Value getnewaddress(const Array& params, bool fHelp)
|
||||
throw runtime_error(
|
||||
"getnewaddress ( \"account\" )\n"
|
||||
"\nReturns a new Bitcoin address for receiving payments.\n"
|
||||
"If 'account' is specified (DEPRECATED), it is added to the address book \n"
|
||||
"so payments received with the address will be credited to 'account'.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"account\" (string, optional) DEPRECATED. The account name for the address to be linked to. If not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n"
|
||||
"1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
|
||||
"\nResult:\n"
|
||||
"\"bitcoinaddress\" (string) The new bitcoin address\n"
|
||||
"\nExamples:\n"
|
||||
@@ -191,7 +193,7 @@ Value getaccountaddress(const Array& params, bool fHelp)
|
||||
"getaccountaddress \"account\"\n"
|
||||
"\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"account\" (string, required) The account name for the address. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name.\n"
|
||||
"1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
|
||||
"\nResult:\n"
|
||||
"\"bitcoinaddress\" (string) The account bitcoin address\n"
|
||||
"\nExamples:\n"
|
||||
@@ -259,7 +261,7 @@ Value setaccount(const Array& params, bool fHelp)
|
||||
"\nDEPRECATED. Sets the account associated with the given address.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"bitcoinaddress\" (string, required) The bitcoin address to be associated with an account.\n"
|
||||
"2. \"account\" (string, required) The account to assign the address to.\n"
|
||||
"2. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"tabby\"")
|
||||
+ HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"tabby\"")
|
||||
@@ -336,7 +338,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
|
||||
"getaddressesbyaccount \"account\"\n"
|
||||
"\nDEPRECATED. Returns the list of addresses for the given account.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"account\" (string, required) The account name.\n"
|
||||
"1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
|
||||
"\nResult:\n"
|
||||
"[ (json array of string)\n"
|
||||
" \"bitcoinaddress\" (string) a bitcoin address associated with the given account\n"
|
||||
@@ -625,7 +627,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
|
||||
"getreceivedbyaccount \"account\" ( minconf )\n"
|
||||
"\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"account\" (string, required) The selected account, may be the default account using \"\".\n"
|
||||
"1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
|
||||
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
|
||||
"\nResult:\n"
|
||||
"amount (numeric) The total amount in btc received for this account.\n"
|
||||
@@ -712,12 +714,9 @@ Value getbalance(const Array& params, bool fHelp)
|
||||
if (fHelp || params.size() > 3)
|
||||
throw runtime_error(
|
||||
"getbalance ( \"account\" minconf includeWatchonly )\n"
|
||||
"\nIf account is not specified, returns the server's total available balance.\n"
|
||||
"If account is specified (DEPRECATED), returns the balance in the account.\n"
|
||||
"Note that the account \"\" is not the same as leaving the parameter out.\n"
|
||||
"The server total may be different to the balance in the default \"\" account.\n"
|
||||
"\nReturns the server's total available balance.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"account\" (string, optional) DEPRECATED. The selected account, or \"*\" for entire wallet. It may be the default account using \"\".\n"
|
||||
"1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" or to the string \"*\", either of which will give the total available balance. Passing any other string will result in an error.\n"
|
||||
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
|
||||
"3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
|
||||
"\nResult:\n"
|
||||
@@ -805,8 +804,8 @@ Value movecmd(const Array& params, bool fHelp)
|
||||
"move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
|
||||
"\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n"
|
||||
"2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\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"
|
||||
"2. \"toaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
|
||||
"3. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
|
||||
"4. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
|
||||
"\nResult:\n"
|
||||
@@ -877,7 +876,7 @@ Value sendfrom(const Array& params, bool fHelp)
|
||||
"The amount is a real and is rounded to the nearest 0.00000001."
|
||||
+ HelpRequiringPassphrase() + "\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\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"
|
||||
"2. \"tobitcoinaddress\" (string, required) The bitcoin address to send funds to.\n"
|
||||
"3. amount (numeric, required) The amount in btc. (transaction fee is added on top).\n"
|
||||
"4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
|
||||
@@ -939,7 +938,7 @@ Value sendmany(const Array& params, bool fHelp)
|
||||
"\nSend multiple times. Amounts are double-precision floating point numbers."
|
||||
+ HelpRequiringPassphrase() + "\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"fromaccount\" (string, required) DEPRECATED. The account to send the funds from. Should be \"\" for the default account\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"
|
||||
"2. \"amounts\" (string, required) A json object with addresses and amounts\n"
|
||||
" {\n"
|
||||
" \"address\":amount (numeric) The bitcoin address is the key, the numeric amount in btc is the value\n"
|
||||
@@ -1056,7 +1055,7 @@ Value addmultisigaddress(const Array& params, bool fHelp)
|
||||
" \"address\" (string) bitcoin address or hex-encoded public key\n"
|
||||
" ...,\n"
|
||||
" ]\n"
|
||||
"3. \"account\" (string, optional) DEPRECATED. An account to assign the addresses to.\n"
|
||||
"3. \"account\" (string, optional) DEPRECATED. If provided, MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
|
||||
|
||||
"\nResult:\n"
|
||||
"\"bitcoinaddress\" (string) A bitcoin address associated with the keys.\n"
|
||||
@@ -1702,6 +1701,17 @@ Value gettransaction(const Array& params, bool fHelp)
|
||||
" }\n"
|
||||
" ,...\n"
|
||||
" ],\n"
|
||||
" \"vjoinsplit\" : [\n"
|
||||
" {\n"
|
||||
" \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
|
||||
" \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
|
||||
" \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
|
||||
" \"macs\" : [ string, ... ] (string) Message authentication tags\n"
|
||||
" \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
|
||||
" \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
|
||||
" }\n"
|
||||
" ,...\n"
|
||||
" ],\n"
|
||||
" \"hex\" : \"data\" (string) Raw data for transaction\n"
|
||||
"}\n"
|
||||
|
||||
@@ -1867,6 +1877,8 @@ Value walletpassphrase(const Array& params, bool fHelp)
|
||||
"walletpassphrase <passphrase> <timeout>\n"
|
||||
"Stores the wallet decryption key in memory for <timeout> seconds.");
|
||||
|
||||
// No need to check return values, because the wallet was unlocked above
|
||||
pwalletMain->UpdateNullifierNoteMap();
|
||||
pwalletMain->TopUpKeyPool();
|
||||
|
||||
int64_t nSleepTime = params[1].get_int64();
|
||||
@@ -2447,10 +2459,11 @@ Value zc_benchmark(const json_spirit::Array& params, bool fHelp)
|
||||
sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
|
||||
} else if (benchmarktype == "solveequihash") {
|
||||
if (params.size() < 3) {
|
||||
sample_times.push_back(benchmark_solve_equihash(true));
|
||||
sample_times.push_back(benchmark_solve_equihash());
|
||||
} else {
|
||||
int nThreads = params[2].get_int();
|
||||
sample_times.push_back(benchmark_solve_equihash_threaded(nThreads));
|
||||
std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
|
||||
sample_times.insert(sample_times.end(), vals.begin(), vals.end());
|
||||
}
|
||||
} else if (benchmarktype == "verifyequihash") {
|
||||
sample_times.push_back(benchmark_verify_equihash());
|
||||
@@ -2462,9 +2475,9 @@ Value zc_benchmark(const json_spirit::Array& params, bool fHelp)
|
||||
}
|
||||
|
||||
Array results;
|
||||
for (int i = 0; i < samplecount; i++) {
|
||||
for (auto time : sample_times) {
|
||||
Object result;
|
||||
result.push_back(Pair("runningtime", sample_times.at(i)));
|
||||
result.push_back(Pair("runningtime", time));
|
||||
results.push_back(result);
|
||||
}
|
||||
|
||||
@@ -2781,7 +2794,7 @@ Value z_getnewaddress(const Array& params, bool fHelp)
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return Value::null;
|
||||
|
||||
if (fHelp || params.size() > 1)
|
||||
if (fHelp || params.size() > 0)
|
||||
throw runtime_error(
|
||||
"z_getnewaddress\n"
|
||||
"\nReturns a new zaddr for receiving payments.\n"
|
||||
@@ -2795,6 +2808,8 @@ Value z_getnewaddress(const Array& params, bool fHelp)
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked();
|
||||
|
||||
CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
|
||||
std::string result = pubaddr.ToString();
|
||||
return result;
|
||||
@@ -2832,7 +2847,7 @@ Value z_listaddresses(const Array& params, bool fHelp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
CAmount getBalanceTaddr(std::string transparentAddress, size_t minDepth=1) {
|
||||
CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1) {
|
||||
set<CBitcoinAddress> setAddress;
|
||||
vector<COutput> vecOutputs;
|
||||
CAmount balance = 0;
|
||||
@@ -2871,7 +2886,7 @@ CAmount getBalanceTaddr(std::string transparentAddress, size_t minDepth=1) {
|
||||
return balance;
|
||||
}
|
||||
|
||||
CAmount getBalanceZaddr(std::string address, size_t minDepth = 1) {
|
||||
CAmount getBalanceZaddr(std::string address, int minDepth = 1) {
|
||||
CAmount balance = 0;
|
||||
std::vector<CNotePlaintextEntry> entries;
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
#include "script/script.h"
|
||||
#include "script/sign.h"
|
||||
#include "timedata.h"
|
||||
#include "util.h"
|
||||
#include "utilmoneystr.h"
|
||||
#include "zcash/Note.hpp"
|
||||
#include "crypter.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@@ -169,6 +169,7 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
|
||||
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
|
||||
const vector<unsigned char> &vchCryptedSecret)
|
||||
{
|
||||
|
||||
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
|
||||
return false;
|
||||
if (!fFileBacked)
|
||||
@@ -187,6 +188,32 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CWallet::AddCryptedSpendingKey(const libzcash::PaymentAddress &address,
|
||||
const libzcash::ViewingKey &vk,
|
||||
const std::vector<unsigned char> &vchCryptedSecret)
|
||||
{
|
||||
if (!CCryptoKeyStore::AddCryptedSpendingKey(address, vk, vchCryptedSecret))
|
||||
return false;
|
||||
if (!fFileBacked)
|
||||
return true;
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
if (pwalletdbEncryption) {
|
||||
return pwalletdbEncryption->WriteCryptedZKey(address,
|
||||
vk,
|
||||
vchCryptedSecret,
|
||||
mapZKeyMetadata[address]);
|
||||
} else {
|
||||
return CWalletDB(strWalletFile).WriteCryptedZKey(address,
|
||||
vk,
|
||||
vchCryptedSecret,
|
||||
mapZKeyMetadata[address]);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
|
||||
{
|
||||
AssertLockHeld(cs_wallet); // mapKeyMetadata
|
||||
@@ -209,6 +236,11 @@ bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigne
|
||||
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
|
||||
}
|
||||
|
||||
bool CWallet::LoadCryptedZKey(const libzcash::PaymentAddress &addr, const libzcash::ViewingKey &vk, const std::vector<unsigned char> &vchCryptedSecret)
|
||||
{
|
||||
return CCryptoKeyStore::AddCryptedSpendingKey(addr, vk, vchCryptedSecret);
|
||||
}
|
||||
|
||||
bool CWallet::LoadZKey(const libzcash::SpendingKey &key)
|
||||
{
|
||||
return CCryptoKeyStore::AddSpendingKey(key);
|
||||
@@ -592,9 +624,19 @@ void CWallet::AddToSpends(const uint256& wtxid)
|
||||
}
|
||||
}
|
||||
|
||||
void CWallet::ClearNoteWitnessCache()
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
|
||||
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
|
||||
item.second.witnesses.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
|
||||
const CBlock* pblockIn,
|
||||
ZCIncrementalMerkleTree tree)
|
||||
ZCIncrementalMerkleTree& tree)
|
||||
{
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
@@ -603,15 +645,25 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
|
||||
CNoteData* nd = &(item.second);
|
||||
// Check the validity of the cache
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
// Copy the witness for the previous block if we have one
|
||||
if (nd->witnesses.size() > 0) {
|
||||
nd->witnesses.push_front(nd->witnesses.front());
|
||||
}
|
||||
if (nd->witnesses.size() > WITNESS_CACHE_SIZE) {
|
||||
nd->witnesses.pop_back();
|
||||
// Only increment witnesses that are behind the current height
|
||||
if (nd->witnessHeight < pindex->nHeight) {
|
||||
// Witnesses being incremented should always be either -1
|
||||
// (never incremented) or one below pindex
|
||||
assert((nd->witnessHeight == -1) ||
|
||||
(nd->witnessHeight == pindex->nHeight - 1));
|
||||
// Copy the witness for the previous block if we have one
|
||||
if (nd->witnesses.size() > 0) {
|
||||
nd->witnesses.push_front(nd->witnesses.front());
|
||||
}
|
||||
if (nd->witnesses.size() > WITNESS_CACHE_SIZE) {
|
||||
nd->witnesses.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nWitnessCacheSize < WITNESS_CACHE_SIZE) {
|
||||
nWitnessCacheSize += 1;
|
||||
}
|
||||
|
||||
const CBlock* pblock {pblockIn};
|
||||
CBlock block;
|
||||
@@ -633,7 +685,10 @@ 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);
|
||||
if (nd->witnesses.size() > 0) {
|
||||
// Check the validity of the cache
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
if (nd->witnessHeight < pindex->nHeight &&
|
||||
nd->witnesses.size() > 0) {
|
||||
nd->witnesses.front().append(note_commitment);
|
||||
}
|
||||
}
|
||||
@@ -643,22 +698,34 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
|
||||
if (txIsOurs) {
|
||||
JSOutPoint jsoutpt {hash, i, j};
|
||||
if (mapWallet[hash].mapNoteData.count(jsoutpt)) {
|
||||
mapWallet[hash].mapNoteData[jsoutpt].witnesses.push_front(
|
||||
tree.witness());
|
||||
CNoteData* nd = &(mapWallet[hash].mapNoteData[jsoutpt]);
|
||||
assert(nd->witnesses.size() == 0);
|
||||
nd->witnesses.push_front(tree.witness());
|
||||
// Set height to one less than pindex so it gets incremented
|
||||
nd->witnessHeight = pindex->nHeight - 1;
|
||||
// Check the validity of the cache
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nWitnessCacheSize < WITNESS_CACHE_SIZE) {
|
||||
nWitnessCacheSize += 1;
|
||||
|
||||
// Update witness heights
|
||||
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
|
||||
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
|
||||
CNoteData* nd = &(item.second);
|
||||
if (nd->witnessHeight < pindex->nHeight) {
|
||||
nd->witnessHeight = pindex->nHeight;
|
||||
}
|
||||
// Check the validity of the cache
|
||||
assert(nWitnessCacheSize >= nd->witnesses.size());
|
||||
}
|
||||
}
|
||||
|
||||
if (fFileBacked) {
|
||||
CWalletDB walletdb(strWalletFile);
|
||||
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
|
||||
walletdb.WriteTx(wtxItem.first, wtxItem.second);
|
||||
}
|
||||
walletdb.WriteWitnessCacheSize(nWitnessCacheSize);
|
||||
WriteWitnessCache(walletdb);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -670,20 +737,27 @@ void CWallet::DecrementNoteWitnesses()
|
||||
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->witnesses.size() > 0) {
|
||||
nd->witnesses.pop_front();
|
||||
}
|
||||
nd->witnessHeight -= 1;
|
||||
}
|
||||
}
|
||||
nWitnessCacheSize -= 1;
|
||||
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());
|
||||
}
|
||||
}
|
||||
// TODO: If nWitnessCache is zero, we need to regenerate the caches (#1302)
|
||||
assert(nWitnessCacheSize > 0);
|
||||
if (fFileBacked) {
|
||||
CWalletDB walletdb(strWalletFile);
|
||||
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
|
||||
walletdb.WriteTx(wtxItem.first, wtxItem.second);
|
||||
}
|
||||
walletdb.WriteWitnessCacheSize(nWitnessCacheSize);
|
||||
WriteWitnessCache(walletdb);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -827,12 +901,50 @@ void CWallet::MarkDirty()
|
||||
}
|
||||
}
|
||||
|
||||
void CWallet::UpdateNullifierNoteMap(const CWalletTx& wtx)
|
||||
/**
|
||||
* Ensure that every note in the wallet has a cached nullifier.
|
||||
*/
|
||||
bool CWallet::UpdateNullifierNoteMap()
|
||||
{
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
|
||||
if (IsLocked())
|
||||
return false;
|
||||
|
||||
ZCNoteDecryption dec;
|
||||
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
|
||||
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
|
||||
if (!item.second.nullifier) {
|
||||
auto i = item.first.js;
|
||||
GetNoteDecryptor(item.second.address, dec);
|
||||
auto hSig = wtxItem.second.vjoinsplit[i].h_sig(
|
||||
*pzcashParams, wtxItem.second.joinSplitPubKey);
|
||||
item.second.nullifier = GetNoteNullifier(
|
||||
wtxItem.second.vjoinsplit[i],
|
||||
item.second.address,
|
||||
dec,
|
||||
hSig,
|
||||
item.first.n);
|
||||
}
|
||||
}
|
||||
UpdateNullifierNoteMapWithTx(wtxItem.second);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update mapNullifiersToNotes with the cached nullifiers in this tx.
|
||||
*/
|
||||
void CWallet::UpdateNullifierNoteMapWithTx(const CWalletTx& wtx)
|
||||
{
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
for (const mapNoteData_t::value_type& item : wtx.mapNoteData) {
|
||||
mapNullifiersToNotes[item.second.nullifier] = item.first;
|
||||
if (item.second.nullifier) {
|
||||
mapNullifiersToNotes[*item.second.nullifier] = item.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -845,7 +957,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
|
||||
{
|
||||
mapWallet[hash] = wtxIn;
|
||||
mapWallet[hash].BindWallet(this);
|
||||
UpdateNullifierNoteMap(mapWallet[hash]);
|
||||
UpdateNullifierNoteMapWithTx(mapWallet[hash]);
|
||||
AddToSpends(hash);
|
||||
}
|
||||
else
|
||||
@@ -855,7 +967,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
|
||||
pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
|
||||
CWalletTx& wtx = (*ret.first).second;
|
||||
wtx.BindWallet(this);
|
||||
UpdateNullifierNoteMap(wtx);
|
||||
UpdateNullifierNoteMapWithTx(wtx);
|
||||
bool fInsertedNew = ret.second;
|
||||
if (fInsertedNew)
|
||||
{
|
||||
@@ -1056,34 +1168,73 @@ void CWallet::EraseFromWallet(const uint256 &hash)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a nullifier if the SpendingKey is available
|
||||
* Throws std::runtime_error if the decryptor doesn't match this note
|
||||
*/
|
||||
boost::optional<uint256> CWallet::GetNoteNullifier(const JSDescription& jsdesc,
|
||||
const libzcash::PaymentAddress& address,
|
||||
const ZCNoteDecryption& dec,
|
||||
const uint256& hSig,
|
||||
uint8_t n) const
|
||||
{
|
||||
boost::optional<uint256> ret;
|
||||
auto note_pt = libzcash::NotePlaintext::decrypt(
|
||||
dec,
|
||||
jsdesc.ciphertexts[n],
|
||||
jsdesc.ephemeralKey,
|
||||
hSig,
|
||||
(unsigned char) n);
|
||||
auto note = note_pt.note(address);
|
||||
// SpendingKeys are only available if the wallet is unlocked
|
||||
libzcash::SpendingKey key;
|
||||
if (GetSpendingKey(address, key)) {
|
||||
ret = note.nullifier(key);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all output notes in the given transaction that have been sent to
|
||||
* PaymentAddresses in this wallet.
|
||||
*
|
||||
* It should never be necessary to call this method with a CWalletTx, because
|
||||
* the result of FindMyNotes (for the addresses available at the time) will
|
||||
* already have been cached in CWalletTx.mapNoteData.
|
||||
*/
|
||||
mapNoteData_t CWallet::FindMyNotes(const CTransaction& tx) const
|
||||
{
|
||||
LOCK(cs_SpendingKeyStore);
|
||||
uint256 hash = tx.GetHash();
|
||||
|
||||
mapNoteData_t noteData;
|
||||
libzcash::SpendingKey key;
|
||||
for (size_t i = 0; i < tx.vjoinsplit.size(); i++) {
|
||||
auto hSig = tx.vjoinsplit[i].h_sig(*pzcashParams, tx.joinSplitPubKey);
|
||||
for (uint8_t j = 0; j < tx.vjoinsplit[i].ciphertexts.size(); j++) {
|
||||
for (const NoteDecryptorMap::value_type& item : mapNoteDecryptors) {
|
||||
try {
|
||||
auto note_pt = libzcash::NotePlaintext::decrypt(
|
||||
item.second,
|
||||
tx.vjoinsplit[i].ciphertexts[j],
|
||||
tx.vjoinsplit[i].ephemeralKey,
|
||||
hSig,
|
||||
(unsigned char) j);
|
||||
auto address = item.first;
|
||||
// Decryptors are only cached when SpendingKeys are added
|
||||
assert(GetSpendingKey(address, key));
|
||||
auto note = note_pt.note(address);
|
||||
JSOutPoint jsoutpt {hash, i, j};
|
||||
CNoteData nd {address, note.nullifier(key)};
|
||||
noteData.insert(std::make_pair(jsoutpt, nd));
|
||||
auto nullifier = GetNoteNullifier(
|
||||
tx.vjoinsplit[i],
|
||||
address,
|
||||
item.second,
|
||||
hSig, j);
|
||||
if (nullifier) {
|
||||
CNoteData nd {address, *nullifier};
|
||||
noteData.insert(std::make_pair(jsoutpt, nd));
|
||||
} else {
|
||||
CNoteData nd {address};
|
||||
noteData.insert(std::make_pair(jsoutpt, nd));
|
||||
}
|
||||
break;
|
||||
} catch (const std::runtime_error &) {
|
||||
// Couldn't decrypt with this spending key
|
||||
} catch (const std::runtime_error &err) {
|
||||
if (memcmp("Could not decrypt message", err.what(), 25) != 0) {
|
||||
// Unexpected failure
|
||||
LogPrintf("FindMyNotes(): Unexpected runtime error while testing decrypt:\n");
|
||||
LogPrintf("%s\n", err.what());
|
||||
} // else
|
||||
// Couldn't decrypt with this decryptor
|
||||
} catch (const std::exception &exc) {
|
||||
// Unexpected failure
|
||||
LogPrintf("FindMyNotes(): Unexpected error while testing decrypt:\n");
|
||||
@@ -1328,6 +1479,7 @@ int CWalletTx::GetRequestCount() const
|
||||
return nRequests;
|
||||
}
|
||||
|
||||
// GetAmounts will determine the transparent debits and credits for a given wallet tx.
|
||||
void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
|
||||
list<COutputEntry>& listSent, CAmount& nFee, string& strSentAccount, const isminefilter& filter) const
|
||||
{
|
||||
@@ -1336,12 +1488,77 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
|
||||
listSent.clear();
|
||||
strSentAccount = strFromAccount;
|
||||
|
||||
// Compute fee:
|
||||
// Is this tx sent/signed by me?
|
||||
CAmount nDebit = GetDebit(filter);
|
||||
if (nDebit > 0) // debit>0 means we signed/sent this transaction
|
||||
{
|
||||
CAmount nValueOut = GetValueOut();
|
||||
nFee = nDebit - nValueOut;
|
||||
bool isFromMyTaddr = nDebit > 0; // debit>0 means we signed/sent this transaction
|
||||
|
||||
// Does this tx spend my notes?
|
||||
bool isFromMyZaddr = false;
|
||||
for (const JSDescription& js : vjoinsplit) {
|
||||
for (const uint256& nullifier : js.nullifiers) {
|
||||
if (pwallet->IsFromMe(nullifier)) {
|
||||
isFromMyZaddr = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isFromMyZaddr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute fee if we sent this transaction.
|
||||
if (isFromMyTaddr) {
|
||||
CAmount nValueOut = GetValueOut(); // transparent outputs plus all vpub_old
|
||||
CAmount nValueIn = 0;
|
||||
for (const JSDescription & js : vjoinsplit) {
|
||||
nValueIn += js.vpub_new;
|
||||
}
|
||||
nFee = nDebit - nValueOut + nValueIn;
|
||||
}
|
||||
|
||||
// Create output entry for vpub_old/new, if we sent utxos from this transaction
|
||||
if (isFromMyTaddr) {
|
||||
CAmount myVpubOld = 0;
|
||||
CAmount myVpubNew = 0;
|
||||
for (const JSDescription& js : vjoinsplit) {
|
||||
bool fMyJSDesc = false;
|
||||
|
||||
// Check input side
|
||||
for (const uint256& nullifier : js.nullifiers) {
|
||||
if (pwallet->IsFromMe(nullifier)) {
|
||||
fMyJSDesc = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check output side
|
||||
if (!fMyJSDesc) {
|
||||
for (const std::pair<JSOutPoint, CNoteData> nd : this->mapNoteData) {
|
||||
if (nd.first.js < vjoinsplit.size() && nd.first.n < vjoinsplit[nd.first.js].ciphertexts.size()) {
|
||||
fMyJSDesc = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fMyJSDesc) {
|
||||
myVpubOld += js.vpub_old;
|
||||
myVpubNew += js.vpub_new;
|
||||
}
|
||||
|
||||
if (!MoneyRange(js.vpub_old) || !MoneyRange(js.vpub_new) || !MoneyRange(myVpubOld) || !MoneyRange(myVpubNew)) {
|
||||
throw std::runtime_error("CWalletTx::GetAmounts: value out of range");
|
||||
}
|
||||
}
|
||||
|
||||
// Create an output for the value taken from or added to the transparent value pool by JoinSplits
|
||||
if (myVpubOld > myVpubNew) {
|
||||
COutputEntry output = {CNoDestination(), myVpubOld - myVpubNew, (int)vout.size()};
|
||||
listSent.push_back(output);
|
||||
} else if (myVpubNew > myVpubOld) {
|
||||
COutputEntry output = {CNoDestination(), myVpubNew - myVpubOld, (int)vout.size()};
|
||||
listReceived.push_back(output);
|
||||
}
|
||||
}
|
||||
|
||||
// Sent/received.
|
||||
@@ -1516,6 +1733,14 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
||||
if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
|
||||
ret++;
|
||||
}
|
||||
|
||||
ZCIncrementalMerkleTree tree;
|
||||
// This should never fail: we should always be able to get the tree
|
||||
// state on the path to the tip of our chain
|
||||
assert(pcoinsTip->GetAnchorAt(pindex->hashAnchor, tree));
|
||||
// Increment note witness caches
|
||||
IncrementNoteWitnesses(pindex, &block, tree);
|
||||
|
||||
pindex = chainActive.Next(pindex);
|
||||
if (GetTime() >= nNow + 60) {
|
||||
nNow = GetTime();
|
||||
@@ -1923,7 +2148,7 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
|
||||
/**
|
||||
* populate vCoins with vector of available COutputs.
|
||||
*/
|
||||
void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue) const
|
||||
void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue, bool fIncludeCoinBase) const
|
||||
{
|
||||
vCoins.clear();
|
||||
|
||||
@@ -1940,6 +2165,9 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
|
||||
if (fOnlyConfirmed && !pcoin->IsTrusted())
|
||||
continue;
|
||||
|
||||
if (pcoin->IsCoinBase() && !fIncludeCoinBase)
|
||||
continue;
|
||||
|
||||
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
|
||||
continue;
|
||||
|
||||
@@ -2105,10 +2333,38 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const
|
||||
bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool& fOnlyCoinbaseCoinsRet, bool& fNeedCoinbaseCoinsRet, const CCoinControl* coinControl) const
|
||||
{
|
||||
vector<COutput> vCoins;
|
||||
AvailableCoins(vCoins, true, coinControl);
|
||||
// Output parameter fOnlyCoinbaseCoinsRet is set to true when the only available coins are coinbase utxos.
|
||||
vector<COutput> vCoinsNoCoinbase, vCoinsWithCoinbase;
|
||||
AvailableCoins(vCoinsNoCoinbase, true, coinControl, false, false);
|
||||
AvailableCoins(vCoinsWithCoinbase, true, coinControl, false, true);
|
||||
fOnlyCoinbaseCoinsRet = vCoinsNoCoinbase.size() == 0 && vCoinsWithCoinbase.size() > 0;
|
||||
|
||||
// If coinbase utxos can only be sent to zaddrs, exclude any coinbase utxos from coin selection.
|
||||
bool fProtectCoinbase = Params().GetConsensus().fCoinbaseMustBeProtected;
|
||||
vector<COutput> vCoins = (fProtectCoinbase) ? vCoinsNoCoinbase : vCoinsWithCoinbase;
|
||||
|
||||
// Output parameter fNeedCoinbaseCoinsRet is set to true if coinbase utxos need to be spent to meet target amount
|
||||
if (fProtectCoinbase && vCoinsWithCoinbase.size() > vCoinsNoCoinbase.size()) {
|
||||
CAmount value = 0;
|
||||
for (const COutput& out : vCoinsNoCoinbase) {
|
||||
if (!out.fSpendable) {
|
||||
continue;
|
||||
}
|
||||
value += out.tx->vout[out.i].nValue;
|
||||
}
|
||||
if (value <= nTargetValue) {
|
||||
CAmount valueWithCoinbase = 0;
|
||||
for (const COutput& out : vCoinsWithCoinbase) {
|
||||
if (!out.fSpendable) {
|
||||
continue;
|
||||
}
|
||||
valueWithCoinbase += out.tx->vout[out.i].nValue;
|
||||
}
|
||||
fNeedCoinbaseCoinsRet = (valueWithCoinbase >= nTargetValue);
|
||||
}
|
||||
}
|
||||
|
||||
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
|
||||
if (coinControl && coinControl->HasSelected())
|
||||
@@ -2228,9 +2484,17 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend,
|
||||
// Choose coins to use
|
||||
set<pair<const CWalletTx*,unsigned int> > setCoins;
|
||||
CAmount nValueIn = 0;
|
||||
if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl))
|
||||
bool fOnlyCoinbaseCoins = false;
|
||||
bool fNeedCoinbaseCoins = false;
|
||||
if (!SelectCoins(nTotalValue, setCoins, nValueIn, fOnlyCoinbaseCoins, fNeedCoinbaseCoins, coinControl))
|
||||
{
|
||||
strFailReason = _("Insufficient funds");
|
||||
if (fOnlyCoinbaseCoins && Params().GetConsensus().fCoinbaseMustBeProtected) {
|
||||
strFailReason = _("Coinbase funds can only be sent to a zaddr");
|
||||
} else if (fNeedCoinbaseCoins) {
|
||||
strFailReason = _("Insufficient funds, coinbase funds can only be spent after they have been sent to a zaddr");
|
||||
} else {
|
||||
strFailReason = _("Insufficient funds");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
|
||||
@@ -2344,7 +2608,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend,
|
||||
|
||||
// Limit size
|
||||
unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
|
||||
if (nBytes >= MAX_STANDARD_TX_SIZE)
|
||||
if (nBytes >= MAX_TX_SIZE)
|
||||
{
|
||||
strFailReason = _("Transaction too large");
|
||||
return false;
|
||||
@@ -3187,7 +3451,11 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
|
||||
return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee);
|
||||
}
|
||||
|
||||
bool CWallet::GetFilteredNotes(std::vector<CNotePlaintextEntry> & outEntries, std::string address, size_t minDepth = 1, bool ignoreSpent)
|
||||
/**
|
||||
* Find notes in the wallet filtered by payment address, min depth and ability to spend.
|
||||
* These notes are decrypted and added to the output parameter vector, outEntries.
|
||||
*/
|
||||
void CWallet::GetFilteredNotes(std::vector<CNotePlaintextEntry> & outEntries, std::string address, int minDepth, bool ignoreSpent)
|
||||
{
|
||||
bool fFilterAddress = false;
|
||||
libzcash::PaymentAddress filterPaymentAddress;
|
||||
@@ -3206,13 +3474,11 @@ bool CWallet::GetFilteredNotes(std::vector<CNotePlaintextEntry> & outEntries, st
|
||||
continue;
|
||||
}
|
||||
|
||||
mapNoteData_t mapNoteData = FindMyNotes(wtx);
|
||||
|
||||
if (mapNoteData.size() == 0) {
|
||||
if (wtx.mapNoteData.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto & pair : mapNoteData) {
|
||||
for (auto & pair : wtx.mapNoteData) {
|
||||
JSOutPoint jsop = pair.first;
|
||||
CNoteData nd = pair.second;
|
||||
PaymentAddress pa = nd.address;
|
||||
@@ -3223,7 +3489,7 @@ bool CWallet::GetFilteredNotes(std::vector<CNotePlaintextEntry> & outEntries, st
|
||||
}
|
||||
|
||||
// skip note which has been spent
|
||||
if (ignoreSpent && IsSpent(nd.nullifier)) {
|
||||
if (ignoreSpent && nd.nullifier && IsSpent(*nd.nullifier)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "primitives/transaction.h"
|
||||
#include "tinyformat.h"
|
||||
#include "ui_interface.h"
|
||||
#include "util.h"
|
||||
#include "utilstrencodings.h"
|
||||
#include "validationinterface.h"
|
||||
#include "wallet/crypter.h"
|
||||
@@ -200,12 +201,19 @@ class CNoteData
|
||||
public:
|
||||
libzcash::PaymentAddress address;
|
||||
|
||||
// It's okay to cache the nullifier in the wallet, because we are storing
|
||||
// the spending key there too, which could be used to derive this.
|
||||
// If PR #1210 is merged, we need to revisit the threat model and decide
|
||||
// whether it is okay to store this unencrypted while the spending key is
|
||||
// encrypted.
|
||||
uint256 nullifier;
|
||||
/**
|
||||
* Cached note nullifier. May not be set if the wallet was not unlocked when
|
||||
* this was CNoteData was created. If not set, we always assume that the
|
||||
* note has not been spent.
|
||||
*
|
||||
* It's okay to cache the nullifier in the wallet, because we are storing
|
||||
* the spending key there too, which could be used to derive this.
|
||||
* If the wallet is encrypted, this means that someone with access to the
|
||||
* locked wallet cannot spend notes, but can connect received notes to the
|
||||
* transactions they are spent in. This is the same security semantics as
|
||||
* for transparent addresses.
|
||||
*/
|
||||
boost::optional<uint256> nullifier;
|
||||
|
||||
/**
|
||||
* Cached incremental witnesses for spendable Notes.
|
||||
@@ -213,8 +221,14 @@ public:
|
||||
*/
|
||||
std::list<ZCIncrementalWitness> witnesses;
|
||||
|
||||
CNoteData() : address(), nullifier() { }
|
||||
CNoteData(libzcash::PaymentAddress a, uint256 n) : address {a}, nullifier {n} { }
|
||||
/** Block height corresponding to the most current witness. */
|
||||
int witnessHeight;
|
||||
|
||||
CNoteData() : address(), nullifier(), witnessHeight {-1} { }
|
||||
CNoteData(libzcash::PaymentAddress a) :
|
||||
address {a}, nullifier(), witnessHeight {-1} { }
|
||||
CNoteData(libzcash::PaymentAddress a, uint256 n) :
|
||||
address {a}, nullifier {n}, witnessHeight {-1} { }
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
@@ -223,6 +237,7 @@ public:
|
||||
READWRITE(address);
|
||||
READWRITE(nullifier);
|
||||
READWRITE(witnesses);
|
||||
READWRITE(witnessHeight);
|
||||
}
|
||||
|
||||
friend bool operator<(const CNoteData& a, const CNoteData& b) {
|
||||
@@ -241,7 +256,7 @@ public:
|
||||
|
||||
typedef std::map<JSOutPoint, CNoteData> mapNoteData_t;
|
||||
|
||||
|
||||
/** Decrypted note and its location in a transaction. */
|
||||
struct CNotePlaintextEntry
|
||||
{
|
||||
JSOutPoint jsop;
|
||||
@@ -556,7 +571,7 @@ public:
|
||||
class CWallet : public CCryptoKeyStore, public CValidationInterface
|
||||
{
|
||||
private:
|
||||
bool SelectCoins(const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const;
|
||||
bool SelectCoins(const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool& fOnlyCoinbaseCoinsRet, bool& fNeedCoinbaseCoinsRet, const CCoinControl *coinControl = NULL) const;
|
||||
|
||||
CWalletDB *pwalletdbEncryption;
|
||||
|
||||
@@ -598,12 +613,48 @@ public:
|
||||
*/
|
||||
int64_t nWitnessCacheSize;
|
||||
|
||||
void ClearNoteWitnessCache();
|
||||
|
||||
protected:
|
||||
void IncrementNoteWitnesses(const CBlockIndex* pindex,
|
||||
const CBlock* pblock,
|
||||
ZCIncrementalMerkleTree tree);
|
||||
ZCIncrementalMerkleTree& tree);
|
||||
void DecrementNoteWitnesses();
|
||||
|
||||
template <typename WalletDB>
|
||||
void WriteWitnessCache(WalletDB& walletdb) {
|
||||
if (!walletdb.TxnBegin()) {
|
||||
// This needs to be done atomically, so don't do it at all
|
||||
LogPrintf("WriteWitnessCache(): Couldn't start atomic write\n");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
|
||||
if (!walletdb.WriteTx(wtxItem.first, wtxItem.second)) {
|
||||
LogPrintf("WriteWitnessCache(): Failed to write CWalletTx, aborting atomic write\n");
|
||||
walletdb.TxnAbort();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!walletdb.WriteWitnessCacheSize(nWitnessCacheSize)) {
|
||||
LogPrintf("WriteWitnessCache(): Failed to write nWitnessCacheSize, aborting atomic write\n");
|
||||
walletdb.TxnAbort();
|
||||
return;
|
||||
}
|
||||
} catch (const std::exception &exc) {
|
||||
// Unexpected failure
|
||||
LogPrintf("WriteWitnessCache(): Unexpected error during atomic write:\n");
|
||||
LogPrintf("%s\n", exc.what());
|
||||
walletdb.TxnAbort();
|
||||
return;
|
||||
}
|
||||
if (!walletdb.TxnCommit()) {
|
||||
// Couldn't commit all to db, but in-memory state is fine
|
||||
LogPrintf("WriteWitnessCache(): Couldn't commit atomic write\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <class T>
|
||||
void SyncMetaData(std::pair<typename TxSpendMap<T>::iterator, typename TxSpendMap<T>::iterator>);
|
||||
@@ -667,7 +718,56 @@ public:
|
||||
nWitnessCacheSize = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The reverse mapping of nullifiers to notes.
|
||||
*
|
||||
* The mapping cannot be updated while an encrypted wallet is locked,
|
||||
* because we need the SpendingKey to create the nullifier (#1502). This has
|
||||
* several implications for transactions added to the wallet while locked:
|
||||
*
|
||||
* - Parent transactions can't be marked dirty when a child transaction that
|
||||
* spends their output notes is updated.
|
||||
*
|
||||
* - We currently don't cache any note values, so this is not a problem,
|
||||
* yet.
|
||||
*
|
||||
* - GetFilteredNotes can't filter out spent notes.
|
||||
*
|
||||
* - Per the comment in CNoteData, we assume that if we don't have a
|
||||
* cached nullifier, the note is not spent.
|
||||
*
|
||||
* Another more problematic implication is that the wallet can fail to
|
||||
* detect transactions on the blockchain that spend our notes. There are two
|
||||
* possible cases in which this could happen:
|
||||
*
|
||||
* - We receive a note when the wallet is locked, and then spend it using a
|
||||
* different wallet client.
|
||||
*
|
||||
* - We spend from a PaymentAddress we control, then we export the
|
||||
* SpendingKey and import it into a new wallet, and reindex/rescan to find
|
||||
* the old transactions.
|
||||
*
|
||||
* The wallet will only miss "pure" spends - transactions that are only
|
||||
* linked to us by the fact that they contain notes we spent. If it also
|
||||
* sends notes to us, or interacts with our transparent addresses, we will
|
||||
* detect the transaction and add it to the wallet (again without caching
|
||||
* nullifiers for new notes). As by default JoinSplits send change back to
|
||||
* the origin PaymentAddress, the wallet should rarely miss transactions.
|
||||
*
|
||||
* To work around these issues, whenever the wallet is unlocked, we scan all
|
||||
* cached notes, and cache any missing nullifiers. Since the wallet must be
|
||||
* unlocked in order to spend notes, this means that GetFilteredNotes will
|
||||
* always behave correctly within that context (and any other uses will give
|
||||
* correct responses afterwards), for the transactions that the wallet was
|
||||
* able to detect. Any missing transactions can be rediscovered by:
|
||||
*
|
||||
* - Unlocking the wallet (to fill all nullifier caches).
|
||||
*
|
||||
* - Restarting the node with -reindex (which operates on a locked wallet
|
||||
* but with the now-cached nullifiers).
|
||||
*/
|
||||
std::map<uint256, JSOutPoint> mapNullifiersToNotes;
|
||||
|
||||
std::map<uint256, CWalletTx> mapWallet;
|
||||
|
||||
int64_t nOrderPosNext;
|
||||
@@ -686,7 +786,7 @@ public:
|
||||
//! check whether we are allowed to upgrade (or already support) to the named feature
|
||||
bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
|
||||
|
||||
void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false) const;
|
||||
void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false, bool fIncludeCoinBase=true) const;
|
||||
bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const;
|
||||
|
||||
bool IsSpent(const uint256& hash, unsigned int n) const;
|
||||
@@ -751,7 +851,10 @@ public:
|
||||
bool LoadZKey(const libzcash::SpendingKey &key);
|
||||
//! Load spending key metadata (used by LoadWallet)
|
||||
bool LoadZKeyMetadata(const libzcash::PaymentAddress &addr, const CKeyMetadata &meta);
|
||||
|
||||
//! Adds an encrypted spending key to the store, without saving it to disk (used by LoadWallet)
|
||||
bool LoadCryptedZKey(const libzcash::PaymentAddress &addr, const libzcash::ViewingKey &vk, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
//! Adds an encrypted spending key to the store, and saves it to disk (virtual method, declared in crypter.h)
|
||||
bool AddCryptedSpendingKey(const libzcash::PaymentAddress &address, const libzcash::ViewingKey &vk, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
|
||||
/**
|
||||
* Increment the next transaction order id
|
||||
@@ -770,7 +873,8 @@ public:
|
||||
TxItems OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount = "");
|
||||
|
||||
void MarkDirty();
|
||||
void UpdateNullifierNoteMap(const CWalletTx& wtx);
|
||||
bool UpdateNullifierNoteMap();
|
||||
void UpdateNullifierNoteMapWithTx(const CWalletTx& wtx);
|
||||
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb);
|
||||
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
|
||||
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
|
||||
@@ -810,6 +914,12 @@ public:
|
||||
|
||||
std::set<CTxDestination> GetAccountAddresses(std::string strAccount) const;
|
||||
|
||||
boost::optional<uint256> GetNoteNullifier(
|
||||
const JSDescription& jsdesc,
|
||||
const libzcash::PaymentAddress& address,
|
||||
const ZCNoteDecryption& dec,
|
||||
const uint256& hSig,
|
||||
uint8_t n) const;
|
||||
mapNoteData_t FindMyNotes(const CTransaction& tx) const;
|
||||
bool IsFromMe(const uint256& nullifier) const;
|
||||
void GetNoteWitnesses(
|
||||
@@ -905,7 +1015,7 @@ public:
|
||||
void SetBroadcastTransactions(bool broadcast) { fBroadcastTransactions = broadcast; }
|
||||
|
||||
/* Find notes filtered by payment address, min depth, ability to spend */
|
||||
bool GetFilteredNotes(std::vector<CNotePlaintextEntry> & outEntries, std::string address, size_t minDepth, bool ignoreSpent=true);
|
||||
void GetFilteredNotes(std::vector<CNotePlaintextEntry> & outEntries, std::string address, int minDepth=1, bool ignoreSpent=true);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -104,6 +104,26 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteCryptedZKey(const libzcash::PaymentAddress & addr,
|
||||
const libzcash::ViewingKey &vk,
|
||||
const std::vector<unsigned char>& vchCryptedSecret,
|
||||
const CKeyMetadata &keyMeta)
|
||||
{
|
||||
const bool fEraseUnencryptedKey = true;
|
||||
nWalletDBUpdated++;
|
||||
|
||||
if (!Write(std::make_pair(std::string("zkeymeta"), addr), keyMeta))
|
||||
return false;
|
||||
|
||||
if (!Write(std::make_pair(std::string("czkey"), addr), std::make_pair(vk, vchCryptedSecret), false))
|
||||
return false;
|
||||
if (fEraseUnencryptedKey)
|
||||
{
|
||||
Erase(std::make_pair(std::string("zkey"), addr));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
@@ -348,6 +368,7 @@ public:
|
||||
unsigned int nCKeys;
|
||||
unsigned int nKeyMeta;
|
||||
unsigned int nZKeys;
|
||||
unsigned int nCZKeys;
|
||||
unsigned int nZKeyMeta;
|
||||
bool fIsEncrypted;
|
||||
bool fAnyUnordered;
|
||||
@@ -355,7 +376,7 @@ public:
|
||||
vector<uint256> vWalletUpgrade;
|
||||
|
||||
CWalletScanState() {
|
||||
nKeys = nCKeys = nKeyMeta = nZKeys = nZKeyMeta = 0;
|
||||
nKeys = nCKeys = nKeyMeta = nZKeys = nCZKeys = nZKeyMeta = 0;
|
||||
fIsEncrypted = false;
|
||||
fAnyUnordered = false;
|
||||
nFileVersion = 0;
|
||||
@@ -557,6 +578,25 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
}
|
||||
wss.fIsEncrypted = true;
|
||||
}
|
||||
else if (strType == "czkey")
|
||||
{
|
||||
libzcash::PaymentAddress addr;
|
||||
ssKey >> addr;
|
||||
// Deserialization of a pair is just one item after another
|
||||
uint256 vkValue;
|
||||
ssValue >> vkValue;
|
||||
libzcash::ViewingKey vk(vkValue);
|
||||
vector<unsigned char> vchCryptedSecret;
|
||||
ssValue >> vchCryptedSecret;
|
||||
wss.nCKeys++;
|
||||
|
||||
if (!pwallet->LoadCryptedZKey(addr, vk, vchCryptedSecret))
|
||||
{
|
||||
strErr = "Error reading wallet database: LoadCryptedZKey failed";
|
||||
return false;
|
||||
}
|
||||
wss.fIsEncrypted = true;
|
||||
}
|
||||
else if (strType == "keymeta")
|
||||
{
|
||||
CPubKey vchPubKey;
|
||||
@@ -651,7 +691,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
static bool IsKeyType(string strType)
|
||||
{
|
||||
return (strType== "key" || strType == "wkey" ||
|
||||
strType == "zkey" ||
|
||||
strType == "zkey" || strType == "czkey" ||
|
||||
strType == "mkey" || strType == "ckey");
|
||||
}
|
||||
|
||||
@@ -736,9 +776,8 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
||||
LogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
|
||||
wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
|
||||
|
||||
// TODO: Keep track of encrypted ZKeys
|
||||
LogPrintf("ZKeys: %u plaintext, -- encrypted, %u w/metadata, %u total\n",
|
||||
wss.nZKeys, wss.nZKeyMeta, wss.nZKeys + 0);
|
||||
LogPrintf("ZKeys: %u plaintext, %u encrypted, %u w/metadata, %u total\n",
|
||||
wss.nZKeys, wss.nCZKeys, wss.nZKeyMeta, wss.nZKeys + wss.nCZKeys);
|
||||
|
||||
// nTimeFirstKey is only reliable if all keys have metadata
|
||||
if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta)
|
||||
|
||||
@@ -135,6 +135,10 @@ public:
|
||||
|
||||
/// Write spending key to wallet database, where key is payment address and value is spending key.
|
||||
bool WriteZKey(const libzcash::PaymentAddress& addr, const libzcash::SpendingKey& key, const CKeyMetadata &keyMeta);
|
||||
bool WriteCryptedZKey(const libzcash::PaymentAddress & addr,
|
||||
const libzcash::ViewingKey & vk,
|
||||
const std::vector<unsigned char>& vchCryptedSecret,
|
||||
const CKeyMetadata &keyMeta);
|
||||
|
||||
private:
|
||||
CWalletDB(const CWalletDB&);
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
#include "Address.hpp"
|
||||
#include "NoteEncryption.hpp"
|
||||
#include "hash.h"
|
||||
#include "prf.h"
|
||||
#include "streams.h"
|
||||
|
||||
namespace libzcash {
|
||||
|
||||
uint256 PaymentAddress::GetHash() const {
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << *this;
|
||||
return Hash(ss.begin(), ss.end());
|
||||
}
|
||||
|
||||
uint256 ViewingKey::pk_enc() {
|
||||
return ZCNoteEncryption::generate_pubkey(*this);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
namespace libzcash {
|
||||
|
||||
const size_t SerializedPaymentAddressSize = 64;
|
||||
const size_t SerializedSpendingKeySize = 32;
|
||||
|
||||
class PaymentAddress {
|
||||
public:
|
||||
uint256 a_pk;
|
||||
@@ -23,6 +26,9 @@ public:
|
||||
READWRITE(pk_enc);
|
||||
}
|
||||
|
||||
//! Get the 256-bit SHA256d hash of this payment address.
|
||||
uint256 GetHash() const;
|
||||
|
||||
friend inline bool operator==(const PaymentAddress& a, const PaymentAddress& b) {
|
||||
return a.a_pk == b.a_pk && a.pk_enc == b.pk_enc;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include "coins.h"
|
||||
#include "util.h"
|
||||
#include "init.h"
|
||||
@@ -24,14 +26,12 @@
|
||||
|
||||
using namespace libzcash;
|
||||
|
||||
struct timeval tv_start;
|
||||
|
||||
void timer_start()
|
||||
void timer_start(timeval &tv_start)
|
||||
{
|
||||
gettimeofday(&tv_start, 0);
|
||||
}
|
||||
|
||||
double timer_stop()
|
||||
double timer_stop(timeval &tv_start)
|
||||
{
|
||||
double elapsed;
|
||||
struct timeval tv_end;
|
||||
@@ -43,18 +43,20 @@ double timer_stop()
|
||||
|
||||
double benchmark_sleep()
|
||||
{
|
||||
timer_start();
|
||||
struct timeval tv_start;
|
||||
timer_start(tv_start);
|
||||
sleep(1);
|
||||
return timer_stop();
|
||||
return timer_stop(tv_start);
|
||||
}
|
||||
|
||||
double benchmark_parameter_loading()
|
||||
{
|
||||
// FIXME: this is duplicated with the actual loading code
|
||||
boost::filesystem::path pk_path = ZC_GetParamsDir() / "z9-proving.key";
|
||||
boost::filesystem::path vk_path = ZC_GetParamsDir() / "z9-verifying.key";
|
||||
boost::filesystem::path pk_path = ZC_GetParamsDir() / "beta2-proving.key";
|
||||
boost::filesystem::path vk_path = ZC_GetParamsDir() / "beta2-verifying.key";
|
||||
|
||||
timer_start();
|
||||
struct timeval tv_start;
|
||||
timer_start(tv_start);
|
||||
|
||||
auto newParams = ZCJoinSplit::Unopened();
|
||||
|
||||
@@ -62,7 +64,7 @@ double benchmark_parameter_loading()
|
||||
newParams->setProvingKeyPath(pk_path.string());
|
||||
newParams->loadProvingKey();
|
||||
|
||||
double ret = timer_stop();
|
||||
double ret = timer_stop(tv_start);
|
||||
|
||||
delete newParams;
|
||||
|
||||
@@ -76,7 +78,8 @@ double benchmark_create_joinsplit()
|
||||
/* Get the anchor of an empty commitment tree. */
|
||||
uint256 anchor = ZCIncrementalMerkleTree().root();
|
||||
|
||||
timer_start();
|
||||
struct timeval tv_start;
|
||||
timer_start(tv_start);
|
||||
JSDescription jsdesc(*pzcashParams,
|
||||
pubKeyHash,
|
||||
anchor,
|
||||
@@ -84,7 +87,7 @@ double benchmark_create_joinsplit()
|
||||
{JSOutput(), JSOutput()},
|
||||
0,
|
||||
0);
|
||||
double ret = timer_stop();
|
||||
double ret = timer_stop(tv_start);
|
||||
|
||||
assert(jsdesc.Verify(*pzcashParams, pubKeyHash));
|
||||
return ret;
|
||||
@@ -92,13 +95,14 @@ double benchmark_create_joinsplit()
|
||||
|
||||
double benchmark_verify_joinsplit(const JSDescription &joinsplit)
|
||||
{
|
||||
timer_start();
|
||||
struct timeval tv_start;
|
||||
timer_start(tv_start);
|
||||
uint256 pubKeyHash;
|
||||
joinsplit.Verify(*pzcashParams, pubKeyHash);
|
||||
return timer_stop();
|
||||
return timer_stop(tv_start);
|
||||
}
|
||||
|
||||
double benchmark_solve_equihash(bool time)
|
||||
double benchmark_solve_equihash()
|
||||
{
|
||||
CBlock pblock;
|
||||
CEquihashInput I{pblock};
|
||||
@@ -117,25 +121,33 @@ double benchmark_solve_equihash(bool time)
|
||||
nonce.begin(),
|
||||
nonce.size());
|
||||
|
||||
if (time)
|
||||
timer_start();
|
||||
struct timeval tv_start;
|
||||
timer_start(tv_start);
|
||||
std::set<std::vector<unsigned int>> solns;
|
||||
EhOptimisedSolveUncancellable(n, k, eh_state,
|
||||
[](std::vector<unsigned char> soln) { return false; });
|
||||
if (time)
|
||||
return timer_stop();
|
||||
else
|
||||
return 0;
|
||||
return timer_stop(tv_start);
|
||||
}
|
||||
|
||||
double benchmark_solve_equihash_threaded(int nThreads)
|
||||
std::vector<double> benchmark_solve_equihash_threaded(int nThreads)
|
||||
{
|
||||
boost::thread_group solverThreads;
|
||||
timer_start();
|
||||
for (int i = 0; i < nThreads; i++)
|
||||
solverThreads.create_thread(boost::bind(&benchmark_solve_equihash, false));
|
||||
solverThreads.join_all();
|
||||
return timer_stop();
|
||||
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_solve_equihash);
|
||||
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_equihash()
|
||||
@@ -143,15 +155,16 @@ double benchmark_verify_equihash()
|
||||
CChainParams params = Params(CBaseChainParams::MAIN);
|
||||
CBlock genesis = Params(CBaseChainParams::MAIN).GenesisBlock();
|
||||
CBlockHeader genesis_header = genesis.GetBlockHeader();
|
||||
timer_start();
|
||||
struct timeval tv_start;
|
||||
timer_start(tv_start);
|
||||
CheckEquihashSolution(&genesis_header, params);
|
||||
return timer_stop();
|
||||
return timer_stop(tv_start);
|
||||
}
|
||||
|
||||
double benchmark_large_tx()
|
||||
{
|
||||
// Number of inputs in the spending transaction that we will simulate
|
||||
const size_t NUM_INPUTS = 11100;
|
||||
const size_t NUM_INPUTS = 555;
|
||||
|
||||
// Create priv/pub key
|
||||
CKey priv;
|
||||
@@ -188,16 +201,17 @@ double benchmark_large_tx()
|
||||
ss << spending_tx;
|
||||
//std::cout << "SIZE OF SPENDING TX: " << ss.size() << std::endl;
|
||||
|
||||
auto error = MAX_BLOCK_SIZE / 20; // 5% error
|
||||
assert(ss.size() < MAX_BLOCK_SIZE + error);
|
||||
assert(ss.size() > MAX_BLOCK_SIZE - error);
|
||||
auto error = MAX_TX_SIZE / 20; // 5% error
|
||||
assert(ss.size() < MAX_TX_SIZE + error);
|
||||
assert(ss.size() > MAX_TX_SIZE - error);
|
||||
}
|
||||
|
||||
// Spending tx has all its inputs signed and does not need to be mutated anymore
|
||||
CTransaction final_spending_tx(spending_tx);
|
||||
|
||||
// Benchmark signature verification costs:
|
||||
timer_start();
|
||||
struct timeval tv_start;
|
||||
timer_start(tv_start);
|
||||
for (size_t i = 0; i < NUM_INPUTS; i++) {
|
||||
ScriptError serror = SCRIPT_ERR_OK;
|
||||
assert(VerifyScript(final_spending_tx.vin[i].scriptSig,
|
||||
@@ -206,6 +220,6 @@ double benchmark_large_tx()
|
||||
TransactionSignatureChecker(&final_spending_tx, i),
|
||||
&serror));
|
||||
}
|
||||
return timer_stop();
|
||||
return timer_stop(tv_start);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
extern double benchmark_sleep();
|
||||
extern double benchmark_parameter_loading();
|
||||
extern double benchmark_create_joinsplit();
|
||||
extern double benchmark_solve_equihash(bool time);
|
||||
extern double benchmark_solve_equihash_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);
|
||||
extern double benchmark_verify_equihash();
|
||||
extern double benchmark_large_tx();
|
||||
|
||||
Reference in New Issue
Block a user