Major updates integration from all upstreams

This commit is contained in:
miketout
2018-09-18 14:33:53 -07:00
396 changed files with 25517 additions and 6854 deletions

View File

@@ -3,6 +3,7 @@ DIST_SUBDIRS = secp256k1 univalue cryptoconditions
AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(SAN_LDFLAGS) $(HARDENED_LDFLAGS)
AM_CXXFLAGS = $(SAN_CXXFLAGS) $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS)
AM_CPPFLAGS = $(HARDENED_CPPFLAGS)
EXTRA_LIBRARIES =
if EMBEDDED_LEVELDB
LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include
@@ -20,7 +21,7 @@ $(LIBLEVELDB) $(LIBMEMENV):
endif
BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/include
@@ -34,7 +35,7 @@ endif
if TARGET_DARWIN
LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl
else
LIBBITCOIN_SERVER=libbitcoin_server.a
LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl
endif
LIBBITCOIN_WALLET=libbitcoin_wallet.a
@@ -48,57 +49,68 @@ LIBSECP256K1=secp256k1/libsecp256k1.la
LIBCRYPTOCONDITIONS=cryptoconditions/libcryptoconditions_core.la
LIBSNARK=snark/libsnark.a
LIBUNIVALUE=univalue/libunivalue.la
LIBZCASH=libzcash.a -lcurl
LIBZCASH=libzcash.a
if ENABLE_ZMQ
LIBBITCOIN_ZMQ=libbitcoin_zmq.a
endif
if ENABLE_PROTON
LIBBITCOIN_PROTON=libbitcoin_proton.a
endif
if BUILD_BITCOIN_LIBS
LIBZCASH_CONSENSUS=libzcashconsensus.la
endif
if ENABLE_WALLET
LIBBITCOIN_WALLET=libbitcoin_wallet.a
endif
$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*)
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -march=x86-64 -g "
LIBSNARK_CXXFLAGS = -fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 -fstack-protector-all
LIBSNARK_CXXFLAGS = $(AM_CXXFLAGS) $(PIC_FLAGS) -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 -fstack-protector-all
LIBSNARK_CONFIG_FLAGS = CURVE=ALT_BN128 NO_PROCPS=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 NO_COMPILE_LIBGTEST=1
if HAVE_OPENMP
LIBSNARK_CONFIG_FLAGS += MULTICORE=1
endif
if TARGET_DARWIN
LIBSNARK_CONFIG_FLAGS += PLATFORM=darwin
endif
$(LIBSNARK): $(wildcard snark/src/*)
$(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64 -g "
$(AM_V_at) CC="$(CC)" CXX="$(CXX)" AR="$(AR)" CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64"
libsnark-tests: $(wildcard snark/src/*)
$(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64 -g "
$(AM_V_at) CC="$(CC)" CXX="$(CXX)" AR="$(AR)" CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64"
$(LIBUNIVALUE): $(wildcard univalue/lib/*)
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue/ OPTFLAGS="-O2 -march=x86-64 -g "
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -march=x86-64 -g "
$(LIBCRYPTOCONDITIONS): $(wildcard cryptoconditions/src/*) $(wildcard cryptoconditions/include/*)
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -march=x86-64 -g "
# Make is not made aware of per-object dependencies to avoid limiting building parallelization
# But to build the less dependent modules first, we manually select their order here:
EXTRA_LIBRARIES = \
crypto/libbitcoin_crypto.a \
crypto/libverus_crypto.a \
crypto/libverus_portable_crypto.a \
libbitcoin_util.a \
libbitcoin_common.a \
libbitcoin_server.a \
libbitcoin_cli.a \
EXTRA_LIBRARIES += \
$(LIBBITCOIN_CRYPTO) \
$(LIBVERUS_CRYPTO) \
$(LIBVERUS_PORTABLE_CRYPTO) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_CLI) \
libzcash.a
if ENABLE_WALLET
BITCOIN_INCLUDES += $(BDB_CPPFLAGS)
EXTRA_LIBRARIES += libbitcoin_wallet.a
EXTRA_LIBRARIES += $(LIBBITCOIN_WALLET)
endif
if ENABLE_ZMQ
EXTRA_LIBRARIES += libbitcoin_zmq.a
EXTRA_LIBRARIES += $(LIBBITCOIN_ZMQ)
endif
if ENABLE_PROTON
EXTRA_LIBRARIES += libbitcoin_proton.a
EXTRA_LIBRARIES += $(LIBBITCOIN_PROTON)
endif
if BUILD_BITCOIN_LIBS
lib_LTLIBRARIES = libzcashconsensus.la
LIBZCASH_CONSENSUS=libzcashconsensus.la
else
LIBZCASH_CONSENSUS=
endif
lib_LTLIBRARIES = $(LIBZCASH_CONSENSUS)
bin_PROGRAMS =
noinst_PROGRAMS =
@@ -125,7 +137,8 @@ LIBZCASH_H = \
zcash/prf.h \
zcash/Proof.hpp \
zcash/util.h \
zcash/Zcash.h
zcash/Zcash.h \
zcash/zip32.h
.PHONY: FORCE collate-libsnark check-symbols check-security
# bitcoin core #
@@ -144,6 +157,7 @@ BITCOIN_CORE_H = \
asyncrpcoperation.h \
asyncrpcqueue.h \
base58.h \
bech32.h \
bloom.h \
cc/eval.h \
chain.h \
@@ -175,8 +189,9 @@ BITCOIN_CORE_H = \
httpserver.h \
init.h \
key.h \
key_io.h \
keystore.h \
leveldbwrapper.h \
dbwrapper.h \
limitedmap.h \
main.h \
memusage.h \
@@ -191,6 +206,7 @@ BITCOIN_CORE_H = \
paymentdisclosuredb.h \
policy/fees.h \
pow.h \
prevector.h \
primitives/block.h \
primitives/transaction.h \
primitives/nonce.h \
@@ -198,9 +214,10 @@ BITCOIN_CORE_H = \
pubkey.h \
random.h \
reverselock.h \
rpcclient.h \
rpcprotocol.h \
rpcserver.h \
rpc/client.h \
rpc/protocol.h \
rpc/server.h \
rpc/register.h \
scheduler.h \
script/interpreter.h \
script/script.h \
@@ -220,6 +237,7 @@ BITCOIN_CORE_H = \
timedata.h \
tinyformat.h \
torcontrol.h \
transaction_builder.h \
txdb.h \
txmempool.h \
ui_interface.h \
@@ -237,6 +255,7 @@ BITCOIN_CORE_H = \
wallet/asyncrpcoperation_shieldcoinbase.h \
wallet/crypter.h \
wallet/db.h \
wallet/rpcwallet.h \
wallet/wallet.h \
wallet/wallet_ismine.h \
wallet/walletdb.h \
@@ -297,10 +316,10 @@ libbitcoin_server_a_SOURCES = \
httprpc.cpp \
httpserver.cpp \
init.cpp \
leveldbwrapper.cpp \
dbwrapper.cpp \
main.cpp \
merkleblock.cpp \
metrics.cpp \
metrics.h \
miner.cpp \
net.cpp \
noui.cpp \
@@ -310,14 +329,15 @@ libbitcoin_server_a_SOURCES = \
policy/fees.cpp \
pow.cpp \
rest.cpp \
rpcblockchain.cpp \
rpccrosschain.cpp \
rpcmining.cpp \
rpcmisc.cpp \
rpcnet.cpp \
rpcrawtransaction.cpp \
rpcserver.cpp \
rpc/blockchain.cpp \
rpc/crosschain.cpp \
rpc/mining.cpp \
rpc/misc.cpp \
rpc/net.cpp \
rpc/rawtransaction.cpp \
rpc/server.cpp \
script/serverchecker.cpp \
script/sigcache.cpp \
timedata.cpp \
torcontrol.cpp \
txdb.cpp \
@@ -327,8 +347,6 @@ libbitcoin_server_a_SOURCES = \
$(LIBZCASH_H)
if ENABLE_ZMQ
LIBBITCOIN_ZMQ=libbitcoin_zmq.a
libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS)
libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_zmq_a_SOURCES = \
@@ -338,8 +356,6 @@ libbitcoin_zmq_a_SOURCES = \
endif
if ENABLE_PROTON
LIBBITCOIN_PROTON=libbitcoin_proton.a
libbitcoin_proton_a_CPPFLAGS = $(BITCOIN_INCLUDES)
libbitcoin_proton_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_proton_a_SOURCES = \
@@ -363,6 +379,7 @@ libbitcoin_wallet_a_SOURCES = \
wallet/db.cpp \
paymentdisclosure.cpp \
paymentdisclosuredb.cpp \
transaction_builder.cpp \
wallet/rpcdisclosure.cpp \
wallet/rpcdump.cpp \
cc/CCassetstx.cpp \
@@ -371,6 +388,7 @@ libbitcoin_wallet_a_SOURCES = \
wallet/wallet.cpp \
wallet/wallet_ismine.cpp \
wallet/walletdb.cpp \
zcash/zip32.cpp \
$(BITCOIN_CORE_H) \
$(LIBZCASH_H)
@@ -432,6 +450,7 @@ libbitcoin_common_a_SOURCES = \
amount.cpp \
arith_uint256.cpp \
base58.cpp \
bech32.cpp \
chainparams.cpp \
coins.cpp \
compressor.cpp \
@@ -445,8 +464,10 @@ libbitcoin_common_a_SOURCES = \
hash.cpp \
importcoin.cpp \
key.cpp \
key_io.cpp \
keystore.cpp \
netbase.cpp \
metrics.cpp \
primitives/block.cpp \
primitives/transaction.cpp \
primitives/nonce.cpp \
@@ -461,6 +482,7 @@ libbitcoin_common_a_SOURCES = \
script/sign.cpp \
script/standard.cpp \
veruslaunch.cpp \
transaction_builder.cpp \
$(BITCOIN_CORE_H) \
$(LIBZCASH_H)
@@ -470,23 +492,23 @@ libbitcoin_common_a_SOURCES = \
libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_util_a_SOURCES = \
support/pagelocker.cpp \
chainparamsbase.cpp \
clientversion.cpp \
compat/glibc_sanity.cpp \
compat/glibcxx_sanity.cpp \
compat/strnlen.cpp \
random.cpp \
rpcprotocol.cpp \
support/cleanse.cpp \
sync.cpp \
uint256.cpp \
util.cpp \
utilmoneystr.cpp \
utilstrencodings.cpp \
utiltime.cpp \
$(BITCOIN_CORE_H) \
$(LIBZCASH_H)
support/pagelocker.cpp \
chainparamsbase.cpp \
clientversion.cpp \
compat/glibc_sanity.cpp \
compat/glibcxx_sanity.cpp \
compat/strnlen.cpp \
random.cpp \
rpc/protocol.cpp \
support/cleanse.cpp \
sync.cpp \
uint256.cpp \
util.cpp \
utilmoneystr.cpp \
utilstrencodings.cpp \
utiltime.cpp \
$(BITCOIN_CORE_H) \
$(LIBZCASH_H)
if GLIBC_BACK_COMPAT
libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp
@@ -496,9 +518,9 @@ endif
libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_cli_a_SOURCES = \
rpcclient.cpp \
$(BITCOIN_CORE_H) \
$(LIBZCASH_H)
rpc/client.cpp \
$(BITCOIN_CORE_H) \
$(LIBZCASH_H)
nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h
#
@@ -518,6 +540,8 @@ komodod_LDADD = \
$(LIBBITCOIN_COMMON) \
$(LIBUNIVALUE) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_ZMQ) \
$(LIBBITCOIN_PROTON) \
$(LIBBITCOIN_CRYPTO) \
$(LIBVERUS_CRYPTO) \
$(LIBVERUS_PORTABLE_CRYPTO) \
@@ -528,12 +552,8 @@ komodod_LDADD = \
$(LIBSECP256K1) \
$(LIBCRYPTOCONDITIONS)
if ENABLE_ZMQ
komodod_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
if ENABLE_WALLET
komodod_LDADD += libbitcoin_wallet.a
komodod_LDADD += $(LIBBITCOIN_WALLET)
endif
komodod_LDADD += \
@@ -543,6 +563,8 @@ komodod_LDADD += \
$(CRYPTO_LIBS) \
$(EVENT_PTHREADS_LIBS) \
$(EVENT_LIBS) \
$(ZMQ_LIBS) \
$(PROTON_LIBS) \
$(LIBBITCOIN_CRYPTO) \
$(LIBVERUS_CRYPTO) \
$(LIBVERUS_PORTABLE_CRYPTO) \
@@ -639,6 +661,7 @@ libzcash_a_SOURCES = \
zcash/Note.cpp \
zcash/prf.cpp \
zcash/util.cpp \
zcash/zip32.cpp \
zcash/circuit/commitment.tcc \
zcash/circuit/gadget.tcc \
zcash/circuit/merkle.tcc \
@@ -648,6 +671,10 @@ libzcash_a_SOURCES = \
libzcash_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS $(HARDENED_CPPFLAGS) $(HARDENED_CXXFLAGS) $(HARDENED_LDFLAGS) -pipe $(SAN_LDFLAGS) -O1 -g -Wstack-protector $(SAN_CXXFLAGS) -fstack-protector-all -fPIE -fvisibility=hidden -DSTATIC $(BITCOIN_INCLUDES)
#libzcash_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
#libzcash_a_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
#libzcash_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMONTGOMERY_OUTPUT
libzcash_a_CXXFLAGS = $(SAN_CXXFLAGS) $(HARDENED_CXXFLAGS) -fwrapv -fno-strict-aliasing
libzcash_a_LDFLAGS = $(SAN_LDFLAGS) $(HARDENED_LDFLAGS)
libzcash_a_CPPFLAGS += -DMONTGOMERY_OUTPUT
@@ -694,6 +721,7 @@ clean-local:
-$(MAKE) -C leveldb clean
-$(MAKE) -C secp256k1 clean
-$(MAKE) -C snark clean
-$(MAKE) -C univalue clean
rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno
-rm -f config.h
@@ -726,5 +754,3 @@ include Makefile.ktest.include
#include Makefile.test.include
#include Makefile.gtest.include
endif
include Makefile.zcash.include

View File

@@ -23,6 +23,7 @@ zcash_gtest_SOURCES += \
gtest/test_equihash.cpp \
gtest/test_httprpc.cpp \
gtest/test_joinsplit.cpp \
gtest/test_keys.cpp \
gtest/test_keystore.cpp \
gtest/test_noteencryption.cpp \
gtest/test_mempool.cpp \
@@ -32,7 +33,9 @@ zcash_gtest_SOURCES += \
gtest/test_pow.cpp \
gtest/test_random.cpp \
gtest/test_rpc.cpp \
gtest/test_sapling_note.cpp \
gtest/test_transaction.cpp \
gtest/test_transaction_builder.cpp \
gtest/test_upgrades.cpp \
gtest/test_validation.cpp \
gtest/test_circuit.cpp \
@@ -40,7 +43,9 @@ zcash_gtest_SOURCES += \
gtest/test_libzcash_utils.cpp \
gtest/test_proofs.cpp \
gtest/test_paymentdisclosure.cpp \
gtest/test_checkblock.cpp
gtest/test_pedersen_hash.cpp \
gtest/test_checkblock.cpp \
gtest/test_zip32.cpp
if ENABLE_WALLET
zcash_gtest_SOURCES += \
wallet/gtest/test_wallet.cpp

View File

@@ -20,78 +20,89 @@ EXTRA_DIST += \
test/data/wallet.dat
JSON_TEST_FILES = \
test/data/script_valid.json \
test/data/base58_keys_valid.json \
test/data/base58_encode_decode.json \
test/data/base58_keys_invalid.json \
test/data/script_invalid.json \
test/data/tx_invalid.json \
test/data/tx_valid.json \
test/data/sighash.json \
test/data/merkle_roots.json \
test/data/merkle_roots_empty.json \
test/data/merkle_serialization.json \
test/data/merkle_witness_serialization.json \
test/data/merkle_path.json \
test/data/merkle_commitments.json \
test/data/g1_compressed.json \
test/data/g2_compressed.json
test/data/script_valid.json \
test/data/base58_keys_valid.json \
test/data/base58_encode_decode.json \
test/data/base58_keys_invalid.json \
test/data/script_invalid.json \
test/data/tx_invalid.json \
test/data/tx_valid.json \
test/data/sighash.json \
test/data/merkle_roots.json \
test/data/merkle_roots_empty.json \
test/data/merkle_serialization.json \
test/data/merkle_witness_serialization.json \
test/data/merkle_path.json \
test/data/merkle_commitments.json \
test/data/merkle_roots_sapling.json \
test/data/merkle_roots_empty_sapling.json \
test/data/merkle_serialization_sapling.json \
test/data/merkle_witness_serialization_sapling.json \
test/data/merkle_path_sapling.json \
test/data/merkle_commitments_sapling.json \
test/data/g1_compressed.json \
test/data/g2_compressed.json \
test/data/sapling_key_components.json
RAW_TEST_FILES = test/data/alertTests.raw
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
BITCOIN_TESTS =\
test/arith_uint256_tests.cpp \
test/bignum.h \
test/addrman_tests.cpp \
test/allocator_tests.cpp \
test/base32_tests.cpp \
test/base58_tests.cpp \
test/base64_tests.cpp \
test/bip32_tests.cpp \
test/bloom_tests.cpp \
test/checkblock_tests.cpp \
test/Checkpoints_tests.cpp \
test/coins_tests.cpp \
test/compress_tests.cpp \
test/crypto_tests.cpp \
test/DoS_tests.cpp \
test/equihash_tests.cpp \
test/getarg_tests.cpp \
test/hash_tests.cpp \
test/key_tests.cpp \
test/main_tests.cpp \
test/mempool_tests.cpp \
test/miner_tests.cpp \
test/mruset_tests.cpp \
test/multisig_tests.cpp \
test/netbase_tests.cpp \
test/pmt_tests.cpp \
test/policyestimator_tests.cpp \
test/pow_tests.cpp \
test/raii_event_tests.cpp \
test/reverselock_tests.cpp \
test/rpc_tests.cpp \
test/sanity_tests.cpp \
test/scheduler_tests.cpp \
test/script_P2SH_tests.cpp \
test/script_P2PKH_tests.cpp \
test/script_tests.cpp \
test/scriptnum_tests.cpp \
test/serialize_tests.cpp \
test/sighash_tests.cpp \
test/sigopcount_tests.cpp \
test/skiplist_tests.cpp \
test/test_bitcoin.cpp \
test/test_bitcoin.h \
test/timedata_tests.cpp \
test/torcontrol_tests.cpp \
test/transaction_tests.cpp \
test/uint256_tests.cpp \
test/univalue_tests.cpp \
test/util_tests.cpp \
test/sha256compress_tests.cpp
test/arith_uint256_tests.cpp \
test/bignum.h \
test/addrman_tests.cpp \
test/alert_tests.cpp \
test/allocator_tests.cpp \
test/base32_tests.cpp \
test/base58_tests.cpp \
test/base64_tests.cpp \
test/bech32_tests.cpp \
test/bip32_tests.cpp \
test/bloom_tests.cpp \
test/checkblock_tests.cpp \
test/Checkpoints_tests.cpp \
test/coins_tests.cpp \
test/compress_tests.cpp \
test/convertbits_tests.cpp \
test/crypto_tests.cpp \
test/DoS_tests.cpp \
test/equihash_tests.cpp \
test/getarg_tests.cpp \
test/hash_tests.cpp \
test/key_tests.cpp \
test/dbwrapper_tests.cpp \
test/main_tests.cpp \
test/mempool_tests.cpp \
test/miner_tests.cpp \
test/mruset_tests.cpp \
test/multisig_tests.cpp \
test/netbase_tests.cpp \
test/pmt_tests.cpp \
test/policyestimator_tests.cpp \
test/pow_tests.cpp \
test/prevector_tests.cpp \
test/raii_event_tests.cpp \
test/reverselock_tests.cpp \
test/rpc_tests.cpp \
test/sanity_tests.cpp \
test/scheduler_tests.cpp \
test/script_P2SH_tests.cpp \
test/script_tests.cpp \
test/scriptnum_tests.cpp \
test/serialize_tests.cpp \
test/sighash_tests.cpp \
test/sigopcount_tests.cpp \
test/skiplist_tests.cpp \
test/test_bitcoin.cpp \
test/test_bitcoin.h \
test/timedata_tests.cpp \
test/torcontrol_tests.cpp \
test/transaction_tests.cpp \
test/uint256_tests.cpp \
test/univalue_tests.cpp \
test/util_tests.cpp \
test/sha256compress_tests.cpp
if ENABLE_WALLET
BITCOIN_TESTS += \
@@ -108,6 +119,9 @@ test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
endif
test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \
$(LIBLEVELDB) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_test_bitcoin_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(LIBZCASH) $(LIBSNARK) $(LIBZCASH_LIBS)
test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static

View File

@@ -54,7 +54,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*(CAddress*)this);
READWRITE(source);
READWRITE(nLastSuccess);
@@ -279,7 +279,7 @@ public:
* very little in common.
*/
template<typename Stream>
void Serialize(Stream &s, int nType, int nVersionDummy) const
void Serialize(Stream &s) const
{
LOCK(cs);
@@ -329,7 +329,7 @@ public:
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersionDummy)
void Unserialize(Stream& s)
{
LOCK(cs);
@@ -434,11 +434,6 @@ public:
Check();
}
unsigned int GetSerializeSize(int nType, int nVersion) const
{
return (CSizeComputer(nType, nVersion) << *this).size();
}
void Clear()
{
std::vector<int>().swap(vRandom);

View File

@@ -49,9 +49,8 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(nRelayUntil);
READWRITE(nExpiration);
READWRITE(nID);
@@ -87,7 +86,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(vchMsg);
READWRITE(vchSig);
}

View File

@@ -58,7 +58,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(nSatoshisPerK);
}
};

View File

@@ -16,7 +16,7 @@ using namespace std;
static boost::uuids::random_generator uuidgen;
std::map<OperationStatus, std::string> OperationStatusMap = {
static std::map<OperationStatus, std::string> OperationStatusMap = {
{OperationStatus::READY, "queued"},
{OperationStatus::EXECUTING, "executing"},
{OperationStatus::CANCELLED, "cancelled"},

View File

@@ -4,15 +4,12 @@
#include "base58.h"
#include "hash.h"
#include "uint256.h"
#include "version.h"
#include "streams.h"
#include <hash.h>
#include <uint256.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <stdint.h>
#include <vector>
#include <string>
#include <boost/variant/apply_visitor.hpp>
@@ -104,7 +101,7 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
std::string EncodeBase58(const std::vector<unsigned char>& vch)
{
return EncodeBase58(&vch[0], &vch[0] + vch.size());
return EncodeBase58(vch.data(), vch.data() + vch.size());
}
bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
@@ -143,6 +140,7 @@ bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRe
return DecodeBase58Check(str.c_str(), vchRet);
}
CBase58Data::CBase58Data()
{
vchVersion.clear();
@@ -381,27 +379,3 @@ DATA_TYPE CZCEncoding<DATA_TYPE, PREFIX, SER_SIZE>::Get() const
ss >> ret;
return ret;
}
// Explicit instantiations for libzcash::PaymentAddress
template bool CZCEncoding<libzcash::PaymentAddress,
CChainParams::ZCPAYMENT_ADDRRESS,
libzcash::SerializedPaymentAddressSize>::Set(const libzcash::PaymentAddress& addr);
template libzcash::PaymentAddress CZCEncoding<libzcash::PaymentAddress,
CChainParams::ZCPAYMENT_ADDRRESS,
libzcash::SerializedPaymentAddressSize>::Get() const;
// Explicit instantiations for libzcash::ViewingKey
template bool CZCEncoding<libzcash::ViewingKey,
CChainParams::ZCVIEWING_KEY,
libzcash::SerializedViewingKeySize>::Set(const libzcash::ViewingKey& vk);
template libzcash::ViewingKey CZCEncoding<libzcash::ViewingKey,
CChainParams::ZCVIEWING_KEY,
libzcash::SerializedViewingKeySize>::Get() const;
// Explicit instantiations for libzcash::SpendingKey
template bool CZCEncoding<libzcash::SpendingKey,
CChainParams::ZCSPENDING_KEY,
libzcash::SerializedSpendingKeySize>::Set(const libzcash::SpendingKey& sk);
template libzcash::SpendingKey CZCEncoding<libzcash::SpendingKey,
CChainParams::ZCSPENDING_KEY,
libzcash::SerializedSpendingKeySize>::Get() const;

View File

@@ -58,13 +58,13 @@ std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn);
* Decode a base58-encoded string (psz) that includes a checksum into a byte
* vector (vchRet), return true if decoding is successful
*/
inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet);
bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet);
/**
* Decode a base58-encoded string (str) that includes a checksum into a byte
* vector (vchRet), return true if decoding is successful
*/
inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet);
bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet);
/**
* Base class for all base58-encoded data
@@ -107,39 +107,6 @@ public:
DATA_TYPE Get() const;
};
class CZCPaymentAddress : public CZCEncoding<libzcash::PaymentAddress, CChainParams::ZCPAYMENT_ADDRRESS, libzcash::SerializedPaymentAddressSize> {
protected:
std::string PrependName(const std::string& s) const { return "payment address" + s; }
public:
CZCPaymentAddress() {}
CZCPaymentAddress(const std::string& strAddress) { SetString(strAddress.c_str(), 2); }
CZCPaymentAddress(const libzcash::PaymentAddress& addr) { Set(addr); }
};
class CZCViewingKey : public CZCEncoding<libzcash::ViewingKey, CChainParams::ZCVIEWING_KEY, libzcash::SerializedViewingKeySize> {
protected:
std::string PrependName(const std::string& s) const { return "viewing key" + s; }
public:
CZCViewingKey() {}
CZCViewingKey(const std::string& strViewingKey) { SetString(strViewingKey.c_str(), 3); }
CZCViewingKey(const libzcash::ViewingKey& vk) { Set(vk); }
};
class CZCSpendingKey : public CZCEncoding<libzcash::SpendingKey, CChainParams::ZCSPENDING_KEY, libzcash::SerializedSpendingKeySize> {
protected:
std::string PrependName(const std::string& s) const { return "spending key" + s; }
public:
CZCSpendingKey() {}
CZCSpendingKey(const std::string& strAddress) { SetString(strAddress.c_str(), 2); }
CZCSpendingKey(const libzcash::SpendingKey& addr) { Set(addr); }
};
/** base58-encoded Bitcoin addresses.
* Public-key-hash-addresses have version 0 (or 111 testnet).
* The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.

194
src/bech32.cpp Normal file
View File

@@ -0,0 +1,194 @@
// Copyright (c) 2017 Pieter Wuille
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "bech32.h"
namespace
{
typedef std::vector<uint8_t> data;
/** The Bech32 character set for encoding. */
const char* CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
/** The Bech32 character set for decoding. */
const int8_t CHARSET_REV[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
};
/** Concatenate two byte arrays. */
data Cat(data x, const data& y)
{
x.insert(x.end(), y.begin(), y.end());
return x;
}
/** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to
* make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher
* bits correspond to earlier values. */
uint32_t PolyMod(const data& v)
{
// The input is interpreted as a list of coefficients of a polynomial over F = GF(32), with an
// implicit 1 in front. If the input is [v0,v1,v2,v3,v4], that polynomial is v(x) =
// 1*x^5 + v0*x^4 + v1*x^3 + v2*x^2 + v3*x + v4. The implicit 1 guarantees that
// [v0,v1,v2,...] has a distinct checksum from [0,v0,v1,v2,...].
// The output is a 30-bit integer whose 5-bit groups are the coefficients of the remainder of
// v(x) mod g(x), where g(x) is the Bech32 generator,
// x^6 + {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}. g(x) is chosen in such a way
// that the resulting code is a BCH code, guaranteeing detection of up to 3 errors within a
// window of 1023 characters. Among the various possible BCH codes, one was selected to in
// fact guarantee detection of up to 4 errors within a window of 89 characters.
// Note that the coefficients are elements of GF(32), here represented as decimal numbers
// between {}. In this finite field, addition is just XOR of the corresponding numbers. For
// example, {27} + {13} = {27 ^ 13} = {22}. Multiplication is more complicated, and requires
// treating the bits of values themselves as coefficients of a polynomial over a smaller field,
// GF(2), and multiplying those polynomials mod a^5 + a^3 + 1. For example, {5} * {26} =
// (a^2 + 1) * (a^4 + a^3 + a) = (a^4 + a^3 + a) * a^2 + (a^4 + a^3 + a) = a^6 + a^5 + a^4 + a
// = a^3 + 1 (mod a^5 + a^3 + 1) = {9}.
// During the course of the loop below, `c` contains the bitpacked coefficients of the
// polynomial constructed from just the values of v that were processed so far, mod g(x). In
// the above example, `c` initially corresponds to 1 mod (x), and after processing 2 inputs of
// v, it corresponds to x^2 + v0*x + v1 mod g(x). As 1 mod g(x) = 1, that is the starting value
// for `c`.
uint32_t c = 1;
for (auto v_i : v) {
// We want to update `c` to correspond to a polynomial with one extra term. If the initial
// value of `c` consists of the coefficients of c(x) = f(x) mod g(x), we modify it to
// correspond to c'(x) = (f(x) * x + v_i) mod g(x), where v_i is the next input to
// process. Simplifying:
// c'(x) = (f(x) * x + v_i) mod g(x)
// ((f(x) mod g(x)) * x + v_i) mod g(x)
// (c(x) * x + v_i) mod g(x)
// If c(x) = c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5, we want to compute
// c'(x) = (c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5) * x + v_i mod g(x)
// = c0*x^6 + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i mod g(x)
// = c0*(x^6 mod g(x)) + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i
// If we call (x^6 mod g(x)) = k(x), this can be written as
// c'(x) = (c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i) + c0*k(x)
// First, determine the value of c0:
uint8_t c0 = c >> 25;
// Then compute c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i:
c = ((c & 0x1ffffff) << 5) ^ v_i;
// Finally, for each set bit n in c0, conditionally add {2^n}k(x):
if (c0 & 1) c ^= 0x3b6a57b2; // k(x) = {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}
if (c0 & 2) c ^= 0x26508e6d; // {2}k(x) = {19}x^5 + {5}x^4 + x^3 + {3}x^2 + {19}x + {13}
if (c0 & 4) c ^= 0x1ea119fa; // {4}k(x) = {15}x^5 + {10}x^4 + {2}x^3 + {6}x^2 + {15}x + {26}
if (c0 & 8) c ^= 0x3d4233dd; // {8}k(x) = {30}x^5 + {20}x^4 + {4}x^3 + {12}x^2 + {30}x + {29}
if (c0 & 16) c ^= 0x2a1462b3; // {16}k(x) = {21}x^5 + x^4 + {8}x^3 + {24}x^2 + {21}x + {19}
}
return c;
}
/** Convert to lower case. */
inline unsigned char LowerCase(unsigned char c)
{
return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c;
}
/** Expand a HRP for use in checksum computation. */
data ExpandHRP(const std::string& hrp)
{
data ret;
ret.reserve(hrp.size() + 90);
ret.resize(hrp.size() * 2 + 1);
for (size_t i = 0; i < hrp.size(); ++i) {
unsigned char c = hrp[i];
ret[i] = c >> 5;
ret[i + hrp.size() + 1] = c & 0x1f;
}
ret[hrp.size()] = 0;
return ret;
}
/** Verify a checksum. */
bool VerifyChecksum(const std::string& hrp, const data& values)
{
// PolyMod computes what value to xor into the final values to make the checksum 0. However,
// if we required that the checksum was 0, it would be the case that appending a 0 to a valid
// list of values would result in a new valid list. For that reason, Bech32 requires the
// resulting checksum to be 1 instead.
return PolyMod(Cat(ExpandHRP(hrp), values)) == 1;
}
/** Create a checksum. */
data CreateChecksum(const std::string& hrp, const data& values)
{
data enc = Cat(ExpandHRP(hrp), values);
enc.resize(enc.size() + 6); // Append 6 zeroes
uint32_t mod = PolyMod(enc) ^ 1; // Determine what to XOR into those 6 zeroes.
data ret(6);
for (size_t i = 0; i < 6; ++i) {
// Convert the 5-bit groups in mod to checksum values.
ret[i] = (mod >> (5 * (5 - i))) & 31;
}
return ret;
}
} // namespace
namespace bech32
{
/** Encode a Bech32 string. */
std::string Encode(const std::string& hrp, const data& values) {
data checksum = CreateChecksum(hrp, values);
data combined = Cat(values, checksum);
std::string ret = hrp + '1';
ret.reserve(ret.size() + combined.size());
for (auto c : combined) {
if (c >= 32) {
return "";
}
ret += CHARSET[c];
}
return ret;
}
/** Decode a Bech32 string. */
std::pair<std::string, data> Decode(const std::string& str) {
bool lower = false, upper = false;
for (size_t i = 0; i < str.size(); ++i) {
unsigned char c = str[i];
if (c < 33 || c > 126) return {};
if (c >= 'a' && c <= 'z') lower = true;
if (c >= 'A' && c <= 'Z') upper = true;
}
if (lower && upper) return {};
size_t pos = str.rfind('1');
if (str.size() > 1023 || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
return {};
}
data values(str.size() - 1 - pos);
for (size_t i = 0; i < str.size() - 1 - pos; ++i) {
unsigned char c = str[i + pos + 1];
int8_t rev = (c < 33 || c > 126) ? -1 : CHARSET_REV[c];
if (rev == -1) {
return {};
}
values[i] = rev;
}
std::string hrp;
for (size_t i = 0; i < pos; ++i) {
hrp += LowerCase(str[i]);
}
if (!VerifyChecksum(hrp, values)) {
return {};
}
return {hrp, data(values.begin(), values.end() - 6)};
}
} // namespace bech32

30
src/bech32.h Normal file
View File

@@ -0,0 +1,30 @@
// Copyright (c) 2017 Pieter Wuille
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// Bech32 is a string encoding format used in newer address types.
// The output consists of a human-readable part (alphanumeric), a
// separator character (1), and a base32 data section, the last
// 6 characters of which are a checksum.
//
// For more information, see BIP 173.
#ifndef BITCOIN_BECH32_H
#define BITCOIN_BECH32_H
#include <stdint.h>
#include <string>
#include <vector>
namespace bech32
{
/** Encode a Bech32 string. Returns the empty string in case of failure. */
std::string Encode(const std::string& hrp, const std::vector<uint8_t>& values);
/** Decode a Bech32 string. Returns (hrp, data). Empty hrp means failure. */
std::pair<std::string, std::vector<uint8_t>> Decode(const std::string& str);
} // namespace bech32
#endif // BITCOIN_BECH32_H

View File

@@ -5,8 +5,8 @@
#include "chainparamsbase.h"
#include "clientversion.h"
#include "rpcclient.h"
#include "rpcprotocol.h"
#include "rpc/client.h"
#include "rpc/protocol.h"
#include "util.h"
#include "utilstrencodings.h"
@@ -21,14 +21,12 @@
using namespace std;
int64_t MAX_MONEY = 200000000 * 100000000LL;
uint64_t komodo_maxallowed(int32_t baseid) { return(100000000LL * 1000000); } // stub
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
static const int CONTINUE_EXECUTION=-1;
std::string HelpMessageCli()
{
string strUsage;
std::string strUsage;
strUsage += HelpMessageGroup(_("Options:"));
strUsage += HelpMessageOpt("-?", _("This help message"));
strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), "komodo.conf"));
@@ -42,6 +40,7 @@ std::string HelpMessageCli()
strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases)"));
return strUsage;
}
@@ -86,8 +85,16 @@ uint32_t komodo_heightstamp(int32_t height)
return(0);
}
static bool AppInitRPC(int argc, char* argv[])
//
// This function returns either one of EXIT_ codes when it's expected to stop the process or
// CONTINUE_EXECUTION when it's expected to continue further.
//
static int AppInitRPC(int argc, char* argv[])
{
static_assert(CONTINUE_EXECUTION != EXIT_FAILURE,
"CONTINUE_EXECUTION should be different from EXIT_FAILURE");
static_assert(CONTINUE_EXECUTION != EXIT_SUCCESS,
"CONTINUE_EXECUTION should be different from EXIT_SUCCESS");
//
// Parameters
//
@@ -107,29 +114,33 @@ static bool AppInitRPC(int argc, char* argv[])
}
fprintf(stdout, "%s", strUsage.c_str());
return false;
if (argc < 2) {
fprintf(stderr, "Error: too few parameters\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
if (!boost::filesystem::is_directory(GetDataDir(false))) {
fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
return false;
return EXIT_FAILURE;
}
try {
ReadConfigFile(mapArgs, mapMultiArgs);
} catch (const std::exception& e) {
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
return false;
return EXIT_FAILURE;
}
// Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
if (!SelectBaseParamsFromCommandLine()) {
fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
return false;
return EXIT_FAILURE;
}
if (GetBoolArg("-rpcssl", false))
{
fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
return false;
return EXIT_FAILURE;
}
return true;
return CONTINUE_EXECUTION;
}
@@ -198,7 +209,7 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx)
}
#endif
UniValue CallRPC(const string& strMethod, const UniValue& params)
UniValue CallRPC(const std::string& strMethod, const UniValue& params)
{
std::string host = GetArg("-rpcconnect", "127.0.0.1");
int port = GetArg("-rpcport", BaseParams().RPCPort());
@@ -213,7 +224,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
HTTPReply response;
raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
if (req == NULL)
throw runtime_error("create http request failed");
throw std::runtime_error("create http request failed");
#if LIBEVENT_VERSION_NUMBER >= 0x02010300
evhttp_request_set_error_cb(req.get(), http_error_cb);
#endif
@@ -223,7 +234,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
if (mapArgs["-rpcpassword"] == "") {
// Try fall back to cookie-based authentication if no password is provided
if (!GetAuthCookie(&strRPCUserColonPass)) {
throw runtime_error(strprintf(
throw std::runtime_error(strprintf(
_("Could not locate RPC credentials. No authentication cookie could be found,\n"
"and no rpcpassword is set in the configuration file (%s)."),
GetConfigFile().string().c_str()));
@@ -256,26 +267,26 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
if (response.status == 0)
throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error));
else if (response.status == HTTP_UNAUTHORIZED)
throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
throw runtime_error(strprintf("server returned HTTP error %d", response.status));
throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
else if (response.body.empty())
throw runtime_error("no response from server");
throw std::runtime_error("no response from server");
// Parse reply
UniValue valReply(UniValue::VSTR);
if (!valReply.read(response.body))
throw runtime_error("couldn't parse reply from server");
throw std::runtime_error("couldn't parse reply from server");
const UniValue& reply = valReply.get_obj();
if (reply.empty())
throw runtime_error("expected reply to have result, error and id properties");
throw std::runtime_error("expected reply to have result, error and id properties");
return reply;
}
int CommandLineRPC(int argc, char *argv[])
{
string strPrint;
std::string strPrint;
int nRet = 0;
try {
// Skip switches
@@ -283,15 +294,17 @@ int CommandLineRPC(int argc, char *argv[])
argc--;
argv++;
}
// Method
if (argc < 2)
throw runtime_error("too few parameters");
string strMethod = argv[1];
// Parameters default to strings
std::vector<std::string> strParams(&argv[2], &argv[argc]);
UniValue params = RPCConvertValues(strMethod, strParams);
std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
if (GetBoolArg("-stdin", false)) {
// Read one arg per line from stdin and append
std::string line;
while (std::getline(std::cin,line))
args.push_back(line);
}
if (args.size() < 1)
throw std::runtime_error("too few parameters (need at least command)");
std::string strMethod = args[0];
UniValue params = RPCConvertValues(strMethod, std::vector<std::string>(args.begin()+1, args.end()));
// Execute and handle connection failures with -rpcwait
const bool fWait = GetBoolArg("-rpcwait", false);
@@ -343,7 +356,7 @@ int CommandLineRPC(int argc, char *argv[])
throw;
}
catch (const std::exception& e) {
strPrint = string("error: ") + e.what();
strPrint = std::string("error: ") + e.what();
nRet = EXIT_FAILURE;
}
catch (...) {
@@ -362,12 +375,13 @@ int main(int argc, char* argv[])
SetupEnvironment();
if (!SetupNetworking()) {
fprintf(stderr, "Error: Initializing networking failed\n");
exit(1);
return EXIT_FAILURE;
}
try {
if(!AppInitRPC(argc, argv))
return EXIT_FAILURE;
int ret = AppInitRPC(argc, argv);
if (ret != CONTINUE_EXECUTION)
return ret;
}
catch (const std::exception& e) {
PrintExceptionContinue(&e, "AppInitRPC()");

View File

@@ -4,7 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "clientversion.h"
#include "rpcserver.h"
#include "rpc/server.h"
#include "init.h"
#include "main.h"
#include "noui.h"
@@ -12,7 +12,6 @@
#include "util.h"
#include "httpserver.h"
#include "httprpc.h"
#include "rpcserver.h"
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
@@ -115,7 +114,7 @@ bool AppInit(int argc, char* argv[])
}
fprintf(stdout, "%s", strUsage.c_str());
return false;
return true;
}
try
@@ -179,7 +178,7 @@ bool AppInit(int argc, char* argv[])
if (fCommandLine)
{
fprintf(stderr, "Error: There is no RPC client functionality in komodod. Use the komodo-cli utility instead.\n");
exit(1);
exit(EXIT_FAILURE);
}
#ifndef _WIN32
@@ -236,5 +235,5 @@ int main(int argc, char* argv[])
// Connect bitcoind signal handlers
noui_connect();
return (AppInit(argc, argv) ? 0 : 1);
return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
}

View File

@@ -73,7 +73,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(vData);
READWRITE(nHashFuncs);
READWRITE(nTweak);

View File

@@ -14,6 +14,7 @@
******************************************************************************/
#include "CCinclude.h"
#include "key_io.h"
/*
FinalizeCCTx is a very useful function that will properly sign both CC and normal inputs, adds normal change and the opreturn.

View File

@@ -29,7 +29,7 @@ public:
uint256 notarisationHash;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(branch);
READWRITE(notarisationHash);
}

View File

@@ -170,10 +170,9 @@ CPubKey DiceFundingPk(CScript scriptPubKey)
CPubKey pk; uint8_t *ptr,*dest; int32_t i;
if ( scriptPubKey.size() == 35 )
{
ptr = (uint8_t *)scriptPubKey.data();
dest = (uint8_t *)pk.begin();
for (i=0; i<33; i++)
dest[i] = ptr[i+1];
dest[i] = scriptPubKey[i+1];
} else fprintf(stderr,"DiceFundingPk invalid size.%d\n",(int32_t)scriptPubKey.size());
return(pk);
}
@@ -514,13 +513,12 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
fprintf(stderr,"bidTx.%s\n",uint256_str(str,txid));
fprintf(stderr,"entropyTx.%s v%d\n",uint256_str(str,tx.vin[0].prevout.hash),(int32_t)tx.vin[0].prevout.n);
fprintf(stderr,"entropyTx vin0 %s v%d\n",uint256_str(str,vinTx.vin[0].prevout.hash),(int32_t)vinTx.vin[0].prevout.n);
ptr0 = (uint8_t *)vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey.data();
ptr1 = (uint8_t *)fundingPubKey.data();
const CScript &s0 = vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey;
for (i=0; i<vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey.size(); i++)
fprintf(stderr,"%02x",ptr0[i]);
fprintf(stderr,"%02x",s0[i]);
fprintf(stderr," script vs ");
for (i=0; i<fundingPubKey.size(); i++)
fprintf(stderr,"%02x",ptr1[i]);
fprintf(stderr,"%02x",fundingPubKey[i]);
fprintf(stderr," (%c) entropy vin.%d fundingPubKey mismatch %s\n",funcid,vinTx.vin[0].prevout.n,uint256_str(str,vinTx.vin[0].prevout.hash));
return eval->Invalid("vin1 of entropy tx not fundingPubKey for bet");
}
@@ -562,7 +560,7 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
return eval->Invalid("vout[0] != inputs-txfee for loss");
else if ( tx.vout[2].scriptPubKey != fundingPubKey )
{
if ( tx.vout[2].scriptPubKey.size() == 0 || ((uint8_t *)tx.vout[2].scriptPubKey.data())[0] != 0x6a )
if ( tx.vout[2].scriptPubKey.size() == 0 || tx.vout[2].scriptPubKey[0] != 0x6a )
return eval->Invalid("vout[2] not send to fundingPubKey for loss");
}
iswin = -1;
@@ -586,7 +584,7 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
}
else if ( tx.vout[3].scriptPubKey != fundingPubKey )
{
if ( tx.vout[3].scriptPubKey.size() == 0 || ((uint8_t *)tx.vout[3].scriptPubKey.data())[0] != 0x6a )
if ( tx.vout[3].scriptPubKey.size() == 0 || tx.vout[3].scriptPubKey[0] != 0x6a )
return eval->Invalid("vout[3] not send to fundingPubKey for win/timeout");
}
iswin = (funcid == 'W');
@@ -700,13 +698,12 @@ int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbit
if ( vinTx.vout[tx.vin[0].prevout.n].scriptPubKey != fundingPubKey )
{
uint8_t *ptr0,*ptr1; int32_t i; char str[65];
ptr0 = (uint8_t *)vinTx.vout[tx.vin[0].prevout.n].scriptPubKey.data();
ptr1 = (uint8_t *)fundingPubKey.data();
const CScript &s0 = vinTx.vout[tx.vin[0].prevout.n].scriptPubKey;
for (i=0; i<vinTx.vout[tx.vin[0].prevout.n].scriptPubKey.size(); i++)
fprintf(stderr,"%02x",ptr0[i]);
fprintf(stderr,"%02x",s0[i]);
fprintf(stderr," script vs ");
for (i=0; i<fundingPubKey.size(); i++)
fprintf(stderr,"%02x",ptr1[i]);
fprintf(stderr,"%02x",fundingPubKey[i]);
fprintf(stderr," (%c) entropy vin.%d fundingPubKey mismatch %s\n",funcid,tx.vin[0].prevout.n,uint256_str(str,tx.vin[0].prevout.hash));
continue;
}
@@ -718,13 +715,12 @@ int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbit
else
{
uint8_t *ptr0,*ptr1; int32_t i; char str[65];
ptr0 = (uint8_t *)tx.vout[1].scriptPubKey.data();
ptr1 = (uint8_t *)fundingPubKey.data();
const CScript &s0 = tx.vout[1].scriptPubKey;
for (i=0; i<tx.vout[1].scriptPubKey.size(); i++)
fprintf(stderr,"%02x",ptr0[i]);
fprintf(stderr,"%02x",s0[i]);
fprintf(stderr," script vs ");
for (i=0; i<fundingPubKey.size(); i++)
fprintf(stderr,"%02x",ptr1[i]);
fprintf(stderr,"%02x",fundingPubKey[i]);
fprintf(stderr," (%c) tx vin.%d fundingPubKey mismatch %s\n",funcid,tx.vin[0].prevout.n,uint256_str(str,tx.vin[0].prevout.hash));
}
}
@@ -900,13 +896,11 @@ std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int6
if ( 0 )
{
uint8_t *ptr0,*ptr1; int32_t i;
ptr0 = (uint8_t *)scriptPubKey.data();
ptr1 = (uint8_t *)fundingPubKey.data();
for (i=0; i<35; i++)
fprintf(stderr,"%02x",ptr0[i]);
fprintf(stderr,"%02x",scriptPubKey[i]);
fprintf(stderr," script vs ");
for (i=0; i<35; i++)
fprintf(stderr,"%02x",ptr1[i]);
fprintf(stderr,"%02x",fundingPubKey[i]);
fprintf(stderr," funding\n");
}
if ( scriptPubKey == fundingPubKey )

View File

@@ -161,7 +161,8 @@ bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t t
if (tx.vout.size() < txIn.prevout.n) return false;
CScript spk = tx.vout[txIn.prevout.n].scriptPubKey;
if (spk.size() != 35) return false;
const unsigned char *pk = spk.data();
std::vector<unsigned char> scriptVec = std::vector<unsigned char>(spk.begin(),spk.end());
const unsigned char *pk = scriptVec.data();
if (pk++[0] != 33) return false;
if (pk[33] != OP_CHECKSIG) return false;

View File

@@ -174,7 +174,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
bool IsBack = IsBackNotarisation;
if (2 == IsBackNotarisation) IsBack = DetectBackNotarisation(s, ser_action);
@@ -270,7 +270,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(VARINT(nIndex));
READWRITE(branch);
}

View File

@@ -94,6 +94,7 @@ CBlockIndex* CBlockIndex::GetAncestor(int height)
pindexWalk = pindexWalk->pskip;
heightWalk = heightSkip;
} else {
assert(pindexWalk->pprev);
pindexWalk = pindexWalk->pprev;
heightWalk--;
}

View File

@@ -17,6 +17,7 @@
#include <boost/foreach.hpp>
static const int SPROUT_VALUE_VERSION = 1001400;
static const int SAPLING_VALUE_VERSION = 1010100;
struct CDiskBlockPos
{
@@ -26,7 +27,7 @@ struct CDiskBlockPos
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(VARINT(nFile));
READWRITE(VARINT(nPos));
}
@@ -152,10 +153,10 @@ public:
boost::optional<uint32_t> nCachedBranchId;
//! The anchor for the tree state up to the start of this block
uint256 hashAnchor;
uint256 hashSproutAnchor;
//! (memory only) The anchor for the tree state up to the end of this block
uint256 hashAnchorEnd;
uint256 hashFinalSproutRoot;
//! Change in value held by the Sprout circuit over this block.
//! Will be boost::none for older blocks on old nodes until a reindex has taken place.
@@ -166,10 +167,19 @@ public:
//! Will be boost::none if nChainTx is zero.
boost::optional<CAmount> nChainSproutValue;
//! Change in value held by the Sapling circuit over this block.
//! Not a boost::optional because this was added before Sapling activated, so we can
//! rely on the invariant that every block before this was added had nSaplingValue = 0.
CAmount nSaplingValue;
//! (memory only) Total value held by the Sapling circuit up to and including this block.
//! Will be boost::none if nChainTx is zero.
boost::optional<CAmount> nChainSaplingValue;
//! block header
int nVersion;
uint256 hashMerkleRoot;
uint256 hashReserved;
uint256 hashFinalSaplingRoot;
unsigned int nTime;
unsigned int nBits;
uint256 nNonce;
@@ -194,15 +204,17 @@ public:
nChainTx = 0;
nStatus = 0;
nCachedBranchId = boost::none;
hashAnchor = uint256();
hashAnchorEnd = uint256();
hashSproutAnchor = uint256();
hashFinalSproutRoot = uint256();
nSequenceId = 0;
nSproutValue = boost::none;
nChainSproutValue = boost::none;
nSaplingValue = 0;
nChainSaplingValue = boost::none;
nVersion = 0;
hashMerkleRoot = uint256();
hashReserved = uint256();
hashFinalSaplingRoot = uint256();
nTime = 0;
nBits = 0;
nNonce = uint256();
@@ -220,7 +232,7 @@ public:
nVersion = block.nVersion;
hashMerkleRoot = block.hashMerkleRoot;
hashReserved = block.hashReserved;
hashFinalSaplingRoot = block.hashFinalSaplingRoot;
nTime = block.nTime;
nBits = block.nBits;
nNonce = block.nNonce;
@@ -252,7 +264,7 @@ public:
if (pprev)
block.hashPrevBlock = pprev->GetBlockHash();
block.hashMerkleRoot = hashMerkleRoot;
block.hashReserved = hashReserved;
block.hashFinalSaplingRoot = hashFinalSaplingRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
@@ -352,8 +364,9 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
if (!(nType & SER_GETHASH))
inline void SerializationOp(Stream& s, Operation ser_action) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH))
READWRITE(VARINT(nVersion));
READWRITE(VARINT(nHeight));
@@ -377,13 +390,13 @@ public:
READWRITE(branchId);
}
}
READWRITE(hashAnchor);
READWRITE(hashSproutAnchor);
// block header
READWRITE(this->nVersion);
READWRITE(hashPrev);
READWRITE(hashMerkleRoot);
READWRITE(hashReserved);
READWRITE(hashFinalSaplingRoot);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
@@ -391,9 +404,15 @@ public:
// Only read/write nSproutValue if the client version used to create
// this index was storing them.
if ((nType & SER_DISK) && (nVersion >= SPROUT_VALUE_VERSION)) {
if ((s.GetType() & SER_DISK) && (nVersion >= SPROUT_VALUE_VERSION)) {
READWRITE(nSproutValue);
}
// Only read/write nSaplingValue if the client version used to create
// this index was storing them.
if ((s.GetType() & SER_DISK) && (nVersion >= SAPLING_VALUE_VERSION)) {
READWRITE(nSaplingValue);
}
}
uint256 GetBlockHash() const
@@ -402,7 +421,7 @@ public:
block.nVersion = nVersion;
block.hashPrevBlock = hashPrev;
block.hashMerkleRoot = hashMerkleRoot;
block.hashReserved = hashReserved;
block.hashFinalSaplingRoot = hashFinalSaplingRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;

View File

@@ -3,6 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "key_io.h"
#include "main.h"
#include "crypto/equihash.h"
@@ -13,14 +14,12 @@
#include <boost/assign/list_of.hpp>
#include "base58.h"
#include "chainparamsseeds.h"
static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, const uint256& nNonce, const std::vector<unsigned char>& nSolution, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
// To create a genesis block for a new chain which is Overwintered:
// txNew.nVersion = 3
// txNew.nVersion = OVERWINTER_TX_VERSION
// txNew.fOverwintered = true
// txNew.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID
// txNew.nExpiryHeight = <default value>
@@ -92,6 +91,7 @@ public:
{
strNetworkID = "main";
strCurrencyUnits = "KMD";
bip44CoinType = 133; // As registered in https://github.com/satoshilabs/slips/blob/master/slip-0044.md (ZCASH, should be VRSC)
consensus.fCoinbaseMustBeProtected = false; // true this is only true wuth Verus and enforced after block 12800
consensus.nSubsidySlowStartInterval = 20000;
consensus.nSubsidyHalvingInterval = 840000;
@@ -114,9 +114,13 @@ public:
consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nProtocolVersion = 170002;
consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170004;
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170005;
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 227520;
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170007;
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 227520;
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000281b32ff3198a1");
/**
* The message start string is designed to be unlikely to occur in normal data.
@@ -128,6 +132,7 @@ public:
pchMessageStart[2] = 0xe4;
pchMessageStart[3] = 0x8d;
vAlertPubKey = ParseHex("020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9");
// (Zcash) vAlertPubKey = ParseHex("04b7ecf0baa90495ceb4e4090f6b2fd37eec1e9c85fac68a487f3ce11589692e4a317479316ee814e066638e1db54e37a10689b70286e6315b1087b6615d179264");
nDefaultPort = 7770;
nMinerThreads = 0;
nMaxTipAge = 24 * 60 * 60;
@@ -182,6 +187,11 @@ public:
// guarantees the first two characters, when base58 encoded, are "SK"
base58Prefixes[ZCSPENDING_KEY] = {171,54};
bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zs";
bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviews";
bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivks";
bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-main";
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
fMiningRequiresPeers = true;
@@ -455,6 +465,7 @@ public:
CTestNetParams() {
strNetworkID = "test";
strCurrencyUnits = "TAZ";
bip44CoinType = 1;
consensus.fCoinbaseMustBeProtected = true;
consensus.nSubsidySlowStartInterval = 20000;
consensus.nSubsidyHalvingInterval = 840000;
@@ -481,6 +492,11 @@ public:
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170003;
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 207500;
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170007;
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 280000;
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000000001d0c4d9cd");
consensus.fPowAllowMinDifficultyBlocks = true;
pchMessageStart[0] = 0x5A;
@@ -518,6 +534,11 @@ public:
base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C};
base58Prefixes[ZCSPENDING_KEY] = {177,235};
bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "ztestsapling";
bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewtestsapling";
bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivktestsapling";
bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-test";
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
//fRequireRPCPassword = true;
@@ -527,6 +548,7 @@ public:
fMineBlocksOnDemand = false;
fTestnetToBeDeprecatedFieldRPC = true;
checkpointData = (CCheckpointData) {
boost::assign::map_list_of
(0, consensus.hashGenesisBlock)
@@ -548,6 +570,7 @@ public:
CRegTestParams() {
strNetworkID = "regtest";
strCurrencyUnits = "REG";
bip44CoinType = 1;
consensus.fCoinbaseMustBeProtected = false;
consensus.nSubsidySlowStartInterval = 0;
consensus.nSubsidyHalvingInterval = 150;
@@ -571,6 +594,12 @@ public:
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170003;
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170006;
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");
pchMessageStart[0] = 0xaa;
pchMessageStart[1] = 0x8e;
@@ -628,6 +657,11 @@ public:
base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C};
base58Prefixes[ZCSPENDING_KEY] = {0xAC,0x08};
bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zregtestsapling";
bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewregtestsapling";
bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivkregtestsapling";
bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-regtest";
// Founders reward script expects a vector of 2-of-3 multisig addresses
vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" };
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight());
@@ -699,10 +733,10 @@ std::string CChainParams::GetFoundersRewardAddressAtHeight(int nHeight) const {
CScript CChainParams::GetFoundersRewardScriptAtHeight(int nHeight) const {
assert(nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight());
CBitcoinAddress address(GetFoundersRewardAddressAtHeight(nHeight).c_str());
assert(address.IsValid());
assert(address.IsScript());
CScriptID scriptID = boost::get<CScriptID>(address.Get()); // Get() returns a boost variant
CTxDestination address = DecodeDestination(GetFoundersRewardAddressAtHeight(nHeight).c_str());
assert(IsValidDestination(address));
assert(boost::get<CScriptID>(&address) != nullptr);
CScriptID scriptID = boost::get<CScriptID>(address); // address is a boost variant
CScript script = CScript() << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
return script;
}

View File

@@ -58,6 +58,15 @@ public:
double fTransactionsPerDay;
};
enum Bech32Type {
SAPLING_PAYMENT_ADDRESS,
SAPLING_FULL_VIEWING_KEY,
SAPLING_INCOMING_VIEWING_KEY,
SAPLING_EXTENDED_SPEND_KEY,
MAX_BECH32_TYPES
};
const Consensus::Params& GetConsensus() const { return consensus; }
const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
@@ -70,11 +79,11 @@ public:
bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }
/** Policy: Filter transactions that do not match well-defined patterns */
bool RequireStandard() const { return fRequireStandard; }
int64_t MaxTipAge() const { return nMaxTipAge; }
int64_t PruneAfterHeight() const { return nPruneAfterHeight; }
unsigned int EquihashN() const { return nEquihashN; }
unsigned int EquihashK() const { return nEquihashK; }
std::string CurrencyUnits() const { return strCurrencyUnits; }
uint32_t BIP44CoinType() const { return bip44CoinType; }
/** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */
bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }
/** In the future use NetworkIDString() for RPC fields */
@@ -83,6 +92,7 @@ public:
std::string NetworkIDString() const { return strNetworkID; }
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
const std::string& Bech32HRP(Bech32Type type) const { return bech32HRPs[type]; }
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
const CCheckpointData& Checkpoints() const { return checkpointData; }
/** Return the founder's reward address and script for a given block height */
@@ -99,7 +109,6 @@ public:
//void settimestamp(uint32_t timestamp) { genesis.nTime = timestamp; }
//void setgenesis(CBlock &block) { genesis = block; }
//void recalc_genesis(uint32_t nonce) { genesis = CreateGenesisBlock(ASSETCHAINS_TIMESTAMP, nonce, GENESIS_NBITS, 1, COIN); };
int nDefaultPort = 0;
CMessageHeader::MessageStartChars pchMessageStart; // jl777 moved
Consensus::Params consensus;
@@ -110,13 +119,16 @@ protected:
std::vector<unsigned char> vAlertPubKey;
int nMinerThreads = 0;
long nMaxTipAge = 0;
int nDefaultPort = 0;
uint64_t nPruneAfterHeight = 0;
unsigned int nEquihashN = 0;
unsigned int nEquihashK = 0;
std::vector<CDNSSeedData> vSeeds;
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
std::string bech32HRPs[MAX_BECH32_TYPES];
std::string strNetworkID;
std::string strCurrencyUnits;
uint32_t bip44CoinType;
CBlock genesis;
std::vector<SeedSpec6> vFixedSeeds;
bool fMiningRequiresPeers = false;

View File

@@ -15,7 +15,7 @@
*/
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 1
#define CLIENT_VERSION_MAJOR 2
#define CLIENT_VERSION_MINOR 0
#define CLIENT_VERSION_REVISION 15
#define CLIENT_VERSION_BUILD 52

View File

@@ -44,34 +44,42 @@ bool CCoins::Spend(uint32_t nPos)
Cleanup();
return true;
}
bool CCoinsView::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return false; }
bool CCoinsView::GetNullifier(const uint256 &nullifier) const { return false; }
bool CCoinsView::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { return false; }
bool CCoinsView::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return false; }
bool CCoinsView::GetNullifier(const uint256 &nullifier, ShieldedType type) const { return false; }
bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
uint256 CCoinsView::GetBestAnchor() const { return uint256(); };
uint256 CCoinsView::GetBestAnchor(ShieldedType type) const { return uint256(); };
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) { return false; }
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CAnchorsSaplingMap &mapSaplingAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers) { return false; }
bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
bool CCoinsViewBacked::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return base->GetAnchorAt(rt, tree); }
bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier) const { return base->GetNullifier(nullifier); }
bool CCoinsViewBacked::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { return base->GetSproutAnchorAt(rt, tree); }
bool CCoinsViewBacked::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return base->GetSaplingAnchorAt(rt, tree); }
bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier, ShieldedType type) const { return base->GetNullifier(nullifier, type); }
bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); }
bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
uint256 CCoinsViewBacked::GetBestAnchor() const { return base->GetBestAnchor(); }
uint256 CCoinsViewBacked::GetBestAnchor(ShieldedType type) const { return base->GetBestAnchor(type); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) { return base->BatchWrite(mapCoins, hashBlock, hashAnchor, mapAnchors, mapNullifiers); }
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CAnchorsSaplingMap &mapSaplingAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers) { return base->BatchWrite(mapCoins, hashBlock, hashSproutAnchor, hashSaplingAnchor, mapSproutAnchors, mapSaplingAnchors, mapSproutNullifiers, mapSaplingNullifiers); }
bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); }
CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
@@ -85,8 +93,10 @@ CCoinsViewCache::~CCoinsViewCache()
size_t CCoinsViewCache::DynamicMemoryUsage() const {
return memusage::DynamicUsage(cacheCoins) +
memusage::DynamicUsage(cacheAnchors) +
memusage::DynamicUsage(cacheNullifiers) +
memusage::DynamicUsage(cacheSproutAnchors) +
memusage::DynamicUsage(cacheSaplingAnchors) +
memusage::DynamicUsage(cacheSproutNullifiers) +
memusage::DynamicUsage(cacheSaplingNullifiers) +
cachedCoinsUsage;
}
@@ -109,9 +119,9 @@ CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const
}
bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
CAnchorsMap::const_iterator it = cacheAnchors.find(rt);
if (it != cacheAnchors.end()) {
bool CCoinsViewCache::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const {
CAnchorsSproutMap::const_iterator it = cacheSproutAnchors.find(rt);
if (it != cacheSproutAnchors.end()) {
if (it->second.entered) {
tree = it->second.tree;
return true;
@@ -120,11 +130,11 @@ bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tr
}
}
if (!base->GetAnchorAt(rt, tree)) {
if (!base->GetSproutAnchorAt(rt, tree)) {
return false;
}
CAnchorsMap::iterator ret = cacheAnchors.insert(std::make_pair(rt, CAnchorsCacheEntry())).first;
CAnchorsSproutMap::iterator ret = cacheSproutAnchors.insert(std::make_pair(rt, CAnchorsSproutCacheEntry())).first;
ret->second.entered = true;
ret->second.tree = tree;
cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
@@ -132,24 +142,65 @@ bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tr
return true;
}
bool CCoinsViewCache::GetNullifier(const uint256 &nullifier) const {
CNullifiersMap::iterator it = cacheNullifiers.find(nullifier);
if (it != cacheNullifiers.end())
bool CCoinsViewCache::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const {
CAnchorsSaplingMap::const_iterator it = cacheSaplingAnchors.find(rt);
if (it != cacheSaplingAnchors.end()) {
if (it->second.entered) {
tree = it->second.tree;
return true;
} else {
return false;
}
}
if (!base->GetSaplingAnchorAt(rt, tree)) {
return false;
}
CAnchorsSaplingMap::iterator ret = cacheSaplingAnchors.insert(std::make_pair(rt, CAnchorsSaplingCacheEntry())).first;
ret->second.entered = true;
ret->second.tree = tree;
cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
return true;
}
bool CCoinsViewCache::GetNullifier(const uint256 &nullifier, ShieldedType type) const {
CNullifiersMap* cacheToUse;
switch (type) {
case SPROUT:
cacheToUse = &cacheSproutNullifiers;
break;
case SAPLING:
cacheToUse = &cacheSaplingNullifiers;
break;
default:
throw std::runtime_error("Unknown shielded type");
}
CNullifiersMap::iterator it = cacheToUse->find(nullifier);
if (it != cacheToUse->end())
return it->second.entered;
CNullifiersCacheEntry entry;
bool tmp = base->GetNullifier(nullifier);
bool tmp = base->GetNullifier(nullifier, type);
entry.entered = tmp;
cacheNullifiers.insert(std::make_pair(nullifier, entry));
cacheToUse->insert(std::make_pair(nullifier, entry));
return tmp;
}
void CCoinsViewCache::PushAnchor(const ZCIncrementalMerkleTree &tree) {
template<typename Tree, typename Cache, typename CacheIterator, typename CacheEntry>
void CCoinsViewCache::AbstractPushAnchor(
const Tree &tree,
ShieldedType type,
Cache &cacheAnchors,
uint256 &hash
)
{
uint256 newrt = tree.root();
auto currentRoot = GetBestAnchor();
auto currentRoot = GetBestAnchor(type);
// We don't want to overwrite an anchor we already have.
// This occurs when a block doesn't modify mapAnchors at all,
@@ -157,24 +208,69 @@ void CCoinsViewCache::PushAnchor(const ZCIncrementalMerkleTree &tree) {
// different way (make all blocks modify mapAnchors somehow)
// but this is simpler to reason about.
if (currentRoot != newrt) {
auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CAnchorsCacheEntry()));
CAnchorsMap::iterator ret = insertRet.first;
auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CacheEntry()));
CacheIterator ret = insertRet.first;
ret->second.entered = true;
ret->second.tree = tree;
ret->second.flags = CAnchorsCacheEntry::DIRTY;
ret->second.flags = CacheEntry::DIRTY;
if (insertRet.second) {
// An insert took place
cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
}
hashAnchor = newrt;
hash = newrt;
}
}
void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
auto currentRoot = GetBestAnchor();
template<> void CCoinsViewCache::PushAnchor(const SproutMerkleTree &tree)
{
AbstractPushAnchor<SproutMerkleTree, CAnchorsSproutMap, CAnchorsSproutMap::iterator, CAnchorsSproutCacheEntry>(
tree,
SPROUT,
cacheSproutAnchors,
hashSproutAnchor
);
}
template<> void CCoinsViewCache::PushAnchor(const SaplingMerkleTree &tree)
{
AbstractPushAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(
tree,
SAPLING,
cacheSaplingAnchors,
hashSaplingAnchor
);
}
template<>
void CCoinsViewCache::BringBestAnchorIntoCache(
const uint256 &currentRoot,
SproutMerkleTree &tree
)
{
assert(GetSproutAnchorAt(currentRoot, tree));
}
template<>
void CCoinsViewCache::BringBestAnchorIntoCache(
const uint256 &currentRoot,
SaplingMerkleTree &tree
)
{
assert(GetSaplingAnchorAt(currentRoot, tree));
}
template<typename Tree, typename Cache, typename CacheEntry>
void CCoinsViewCache::AbstractPopAnchor(
const uint256 &newrt,
ShieldedType type,
Cache &cacheAnchors,
uint256 &hash
)
{
auto currentRoot = GetBestAnchor(type);
// Blocks might not change the commitment tree, in which
// case restoring the "old" anchor during a reorg must
@@ -183,25 +279,57 @@ void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
// Bring the current best anchor into our local cache
// so that its tree exists in memory.
{
ZCIncrementalMerkleTree tree;
assert(GetAnchorAt(currentRoot, tree));
Tree tree;
BringBestAnchorIntoCache(currentRoot, tree);
}
// Mark the anchor as unentered, removing it from view
cacheAnchors[currentRoot].entered = false;
// Mark the cache entry as dirty so it's propagated
cacheAnchors[currentRoot].flags = CAnchorsCacheEntry::DIRTY;
cacheAnchors[currentRoot].flags = CacheEntry::DIRTY;
// Mark the new root as the best anchor
hashAnchor = newrt;
hash = newrt;
}
}
void CCoinsViewCache::SetNullifier(const uint256 &nullifier, bool spent) {
std::pair<CNullifiersMap::iterator, bool> ret = cacheNullifiers.insert(std::make_pair(nullifier, CNullifiersCacheEntry()));
ret.first->second.entered = spent;
ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
void CCoinsViewCache::PopAnchor(const uint256 &newrt, ShieldedType type) {
switch (type) {
case SPROUT:
AbstractPopAnchor<SproutMerkleTree, CAnchorsSproutMap, CAnchorsSproutCacheEntry>(
newrt,
SPROUT,
cacheSproutAnchors,
hashSproutAnchor
);
break;
case SAPLING:
AbstractPopAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingCacheEntry>(
newrt,
SAPLING,
cacheSaplingAnchors,
hashSaplingAnchor
);
break;
default:
throw std::runtime_error("Unknown shielded type");
}
}
void CCoinsViewCache::SetNullifiers(const CTransaction& tx, bool spent) {
for (const JSDescription &joinsplit : tx.vjoinsplit) {
for (const uint256 &nullifier : joinsplit.nullifiers) {
std::pair<CNullifiersMap::iterator, bool> ret = cacheSproutNullifiers.insert(std::make_pair(nullifier, CNullifiersCacheEntry()));
ret.first->second.entered = spent;
ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
}
}
for (const SpendDescription &spendDescription : tx.vShieldedSpend) {
std::pair<CNullifiersMap::iterator, bool> ret = cacheSaplingNullifiers.insert(std::make_pair(spendDescription.nullifier, CNullifiersCacheEntry()));
ret.first->second.entered = spent;
ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
}
}
bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
@@ -268,21 +396,90 @@ uint256 CCoinsViewCache::GetBestBlock() const {
}
uint256 CCoinsViewCache::GetBestAnchor() const {
if (hashAnchor.IsNull())
hashAnchor = base->GetBestAnchor();
return hashAnchor;
uint256 CCoinsViewCache::GetBestAnchor(ShieldedType type) const {
switch (type) {
case SPROUT:
if (hashSproutAnchor.IsNull())
hashSproutAnchor = base->GetBestAnchor(type);
return hashSproutAnchor;
break;
case SAPLING:
if (hashSaplingAnchor.IsNull())
hashSaplingAnchor = base->GetBestAnchor(type);
return hashSaplingAnchor;
break;
default:
throw std::runtime_error("Unknown shielded type");
}
}
void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
hashBlock = hashBlockIn;
}
void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNullifiers)
{
for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();) {
if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
if (parent_it == cacheNullifiers.end()) {
CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first];
entry.entered = child_it->second.entered;
entry.flags = CNullifiersCacheEntry::DIRTY;
} else {
if (parent_it->second.entered != child_it->second.entered) {
parent_it->second.entered = child_it->second.entered;
parent_it->second.flags |= CNullifiersCacheEntry::DIRTY;
}
}
}
CNullifiersMap::iterator itOld = child_it++;
mapNullifiers.erase(itOld);
}
}
template<typename Map, typename MapIterator, typename MapEntry>
void BatchWriteAnchors(
Map &mapAnchors,
Map &cacheAnchors,
size_t &cachedCoinsUsage
)
{
for (MapIterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();)
{
if (child_it->second.flags & MapEntry::DIRTY) {
MapIterator parent_it = cacheAnchors.find(child_it->first);
if (parent_it == cacheAnchors.end()) {
MapEntry& entry = cacheAnchors[child_it->first];
entry.entered = child_it->second.entered;
entry.tree = child_it->second.tree;
entry.flags = MapEntry::DIRTY;
cachedCoinsUsage += entry.tree.DynamicMemoryUsage();
} else {
if (parent_it->second.entered != child_it->second.entered) {
// The parent may have removed the entry.
parent_it->second.entered = child_it->second.entered;
parent_it->second.flags |= MapEntry::DIRTY;
}
}
}
MapIterator itOld = child_it++;
mapAnchors.erase(itOld);
}
}
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlockIn,
const uint256 &hashAnchorIn,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) {
const uint256 &hashSproutAnchorIn,
const uint256 &hashSaplingAnchorIn,
CAnchorsSproutMap &mapSproutAnchors,
CAnchorsSaplingMap &mapSaplingAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers) {
assert(!hasModifier);
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
@@ -319,61 +516,25 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
mapCoins.erase(itOld);
}
for (CAnchorsMap::iterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();)
{
if (child_it->second.flags & CAnchorsCacheEntry::DIRTY) {
CAnchorsMap::iterator parent_it = cacheAnchors.find(child_it->first);
::BatchWriteAnchors<CAnchorsSproutMap, CAnchorsSproutMap::iterator, CAnchorsSproutCacheEntry>(mapSproutAnchors, cacheSproutAnchors, cachedCoinsUsage);
::BatchWriteAnchors<CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(mapSaplingAnchors, cacheSaplingAnchors, cachedCoinsUsage);
if (parent_it == cacheAnchors.end()) {
CAnchorsCacheEntry& entry = cacheAnchors[child_it->first];
entry.entered = child_it->second.entered;
entry.tree = child_it->second.tree;
entry.flags = CAnchorsCacheEntry::DIRTY;
::BatchWriteNullifiers(mapSproutNullifiers, cacheSproutNullifiers);
::BatchWriteNullifiers(mapSaplingNullifiers, cacheSaplingNullifiers);
cachedCoinsUsage += entry.tree.DynamicMemoryUsage();
} else {
if (parent_it->second.entered != child_it->second.entered) {
// The parent may have removed the entry.
parent_it->second.entered = child_it->second.entered;
parent_it->second.flags |= CAnchorsCacheEntry::DIRTY;
}
}
}
CAnchorsMap::iterator itOld = child_it++;
mapAnchors.erase(itOld);
}
for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();)
{
if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
if (parent_it == cacheNullifiers.end()) {
CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first];
entry.entered = child_it->second.entered;
entry.flags = CNullifiersCacheEntry::DIRTY;
} else {
if (parent_it->second.entered != child_it->second.entered) {
parent_it->second.entered = child_it->second.entered;
parent_it->second.flags |= CNullifiersCacheEntry::DIRTY;
}
}
}
CNullifiersMap::iterator itOld = child_it++;
mapNullifiers.erase(itOld);
}
hashAnchor = hashAnchorIn;
hashSproutAnchor = hashSproutAnchorIn;
hashSaplingAnchor = hashSaplingAnchorIn;
hashBlock = hashBlockIn;
return true;
}
bool CCoinsViewCache::Flush() {
bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashAnchor, cacheAnchors, cacheNullifiers);
bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashSproutAnchor, hashSaplingAnchor, cacheSproutAnchors, cacheSaplingAnchors, cacheSproutNullifiers, cacheSaplingNullifiers);
cacheCoins.clear();
cacheAnchors.clear();
cacheNullifiers.clear();
cacheSproutAnchors.clear();
cacheSaplingAnchors.clear();
cacheSproutNullifiers.clear();
cacheSaplingNullifiers.clear();
cachedCoinsUsage = 0;
return fOk;
}
@@ -445,7 +606,7 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr
}
#endif
}
nResult += tx.GetJoinSplitValueIn();
nResult += tx.GetShieldedValueIn();
return nResult;
}
@@ -453,24 +614,24 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr
bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
{
boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates;
boost::unordered_map<uint256, SproutMerkleTree, CCoinsKeyHasher> intermediates;
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit)
{
BOOST_FOREACH(const uint256& nullifier, joinsplit.nullifiers)
{
if (GetNullifier(nullifier)) {
if (GetNullifier(nullifier, SPROUT)) {
// If the nullifier is set, this transaction
// double-spends!
return false;
}
}
ZCIncrementalMerkleTree tree;
SproutMerkleTree tree;
auto it = intermediates.find(joinsplit.anchor);
if (it != intermediates.end()) {
tree = it->second;
} else if (!GetAnchorAt(joinsplit.anchor, tree)) {
} else if (!GetSproutAnchorAt(joinsplit.anchor, tree)) {
return false;
}
@@ -482,6 +643,16 @@ bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
intermediates.insert(std::make_pair(tree.root(), tree));
}
for (const SpendDescription &spendDescription : tx.vShieldedSpend) {
if (GetNullifier(spendDescription.nullifier, SAPLING)) // Prevent double spends
return false;
SaplingMerkleTree tree;
if (!GetSaplingAnchorAt(spendDescription.anchor, tree)) {
return false;
}
}
return true;
}

View File

@@ -162,31 +162,8 @@ public:
return fCoinBase;
}
unsigned int GetSerializeSize(int nType, int nVersion) const {
unsigned int nSize = 0;
unsigned int nMaskSize = 0, nMaskCode = 0;
CalcMaskSize(nMaskSize, nMaskCode);
bool fFirst = vout.size() > 0 && !vout[0].IsNull();
bool fSecond = vout.size() > 1 && !vout[1].IsNull();
assert(fFirst || fSecond || nMaskCode);
unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0);
// version
nSize += ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion);
// size of header code
nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion);
// spentness bitmask
nSize += nMaskSize;
// txouts
for (unsigned int i = 0; i < vout.size(); i++)
if (!vout[i].IsNull())
nSize += ::GetSerializeSize(CTxOutCompressor(REF(vout[i])), nType, nVersion);
// height
nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion);
return nSize;
}
template<typename Stream>
void Serialize(Stream &s, int nType, int nVersion) const {
void Serialize(Stream &s) const {
unsigned int nMaskSize = 0, nMaskCode = 0;
CalcMaskSize(nMaskSize, nMaskCode);
bool fFirst = vout.size() > 0 && !vout[0].IsNull();
@@ -194,33 +171,33 @@ public:
assert(fFirst || fSecond || nMaskCode);
unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0);
// version
::Serialize(s, VARINT(this->nVersion), nType, nVersion);
::Serialize(s, VARINT(this->nVersion));
// header code
::Serialize(s, VARINT(nCode), nType, nVersion);
::Serialize(s, VARINT(nCode));
// spentness bitmask
for (unsigned int b = 0; b<nMaskSize; b++) {
unsigned char chAvail = 0;
for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++)
if (!vout[2+b*8+i].IsNull())
chAvail |= (1 << i);
::Serialize(s, chAvail, nType, nVersion);
::Serialize(s, chAvail);
}
// txouts themself
for (unsigned int i = 0; i < vout.size(); i++) {
if (!vout[i].IsNull())
::Serialize(s, CTxOutCompressor(REF(vout[i])), nType, nVersion);
::Serialize(s, CTxOutCompressor(REF(vout[i])));
}
// coinbase height
::Serialize(s, VARINT(nHeight), nType, nVersion);
::Serialize(s, VARINT(nHeight));
}
template<typename Stream>
void Unserialize(Stream &s, int nType, int nVersion) {
void Unserialize(Stream &s) {
unsigned int nCode = 0;
// version
::Unserialize(s, VARINT(this->nVersion), nType, nVersion);
::Unserialize(s, VARINT(this->nVersion));
// header code
::Unserialize(s, VARINT(nCode), nType, nVersion);
::Unserialize(s, VARINT(nCode));
fCoinBase = nCode & 1;
std::vector<bool> vAvail(2, false);
vAvail[0] = (nCode & 2) != 0;
@@ -229,7 +206,7 @@ public:
// spentness bitmask
while (nMaskCode > 0) {
unsigned char chAvail = 0;
::Unserialize(s, chAvail, nType, nVersion);
::Unserialize(s, chAvail);
for (unsigned int p = 0; p < 8; p++) {
bool f = (chAvail & (1 << p)) != 0;
vAvail.push_back(f);
@@ -241,10 +218,10 @@ public:
vout.assign(vAvail.size(), CTxOut());
for (unsigned int i = 0; i < vAvail.size(); i++) {
if (vAvail[i])
::Unserialize(s, REF(CTxOutCompressor(vout[i])), nType, nVersion);
::Unserialize(s, REF(CTxOutCompressor(vout[i])));
}
// coinbase height
::Unserialize(s, VARINT(nHeight), nType, nVersion);
::Unserialize(s, VARINT(nHeight));
Cleanup();
}
@@ -313,17 +290,30 @@ struct CCoinsCacheEntry
CCoinsCacheEntry() : coins(), flags(0) {}
};
struct CAnchorsCacheEntry
struct CAnchorsSproutCacheEntry
{
bool entered; // This will be false if the anchor is removed from the cache
ZCIncrementalMerkleTree tree; // The tree itself
SproutMerkleTree tree; // The tree itself
unsigned char flags;
enum Flags {
DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
};
CAnchorsCacheEntry() : entered(false), flags(0) {}
CAnchorsSproutCacheEntry() : entered(false), flags(0) {}
};
struct CAnchorsSaplingCacheEntry
{
bool entered; // This will be false if the anchor is removed from the cache
SaplingMerkleTree tree; // The tree itself
unsigned char flags;
enum Flags {
DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
};
CAnchorsSaplingCacheEntry() : entered(false), flags(0) {}
};
struct CNullifiersCacheEntry
@@ -338,8 +328,15 @@ struct CNullifiersCacheEntry
CNullifiersCacheEntry() : entered(false), flags(0) {}
};
enum ShieldedType
{
SPROUT,
SAPLING,
};
typedef boost::unordered_map<uint256, CCoinsCacheEntry, CCoinsKeyHasher> CCoinsMap;
typedef boost::unordered_map<uint256, CAnchorsCacheEntry, CCoinsKeyHasher> CAnchorsMap;
typedef boost::unordered_map<uint256, CAnchorsSproutCacheEntry, CCoinsKeyHasher> CAnchorsSproutMap;
typedef boost::unordered_map<uint256, CAnchorsSaplingCacheEntry, CCoinsKeyHasher> CAnchorsSaplingMap;
typedef boost::unordered_map<uint256, CNullifiersCacheEntry, CCoinsKeyHasher> CNullifiersMap;
struct CCoinsStats
@@ -360,11 +357,14 @@ struct CCoinsStats
class CCoinsView
{
public:
//! Retrieve the tree at a particular anchored root in the chain
virtual bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
//! Retrieve the tree (Sprout) at a particular anchored root in the chain
virtual bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const;
//! Retrieve the tree (Sapling) at a particular anchored root in the chain
virtual bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const;
//! Determine whether a nullifier is spent or not
virtual bool GetNullifier(const uint256 &nullifier) const;
virtual bool GetNullifier(const uint256 &nullifier, ShieldedType type) const;
//! Retrieve the CCoins (unspent transaction outputs) for a given txid
virtual bool GetCoins(const uint256 &txid, CCoins &coins) const;
@@ -377,15 +377,18 @@ public:
virtual uint256 GetBestBlock() const;
//! Get the current "tip" or the latest anchored tree root in the chain
virtual uint256 GetBestAnchor() const;
virtual uint256 GetBestAnchor(ShieldedType type) const;
//! Do a bulk modification (multiple CCoins changes + BestBlock change).
//! The passed mapCoins can be modified.
virtual bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers);
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CAnchorsSaplingMap &mapSaplingAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers);
//! Calculate statistics about the unspent transaction output set
virtual bool GetStats(CCoinsStats &stats) const;
@@ -403,18 +406,22 @@ protected:
public:
CCoinsViewBacked(CCoinsView *viewIn);
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
bool GetNullifier(const uint256 &nullifier) const;
bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const;
bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const;
bool GetNullifier(const uint256 &nullifier, ShieldedType type) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
uint256 GetBestAnchor() const;
uint256 GetBestAnchor(ShieldedType type) const;
void SetBackend(CCoinsView &viewIn);
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers);
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CAnchorsSaplingMap &mapSaplingAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers);
bool GetStats(CCoinsStats &stats) const;
};
@@ -485,9 +492,12 @@ protected:
*/
mutable uint256 hashBlock;
mutable CCoinsMap cacheCoins;
mutable uint256 hashAnchor;
mutable CAnchorsMap cacheAnchors;
mutable CNullifiersMap cacheNullifiers;
mutable uint256 hashSproutAnchor;
mutable uint256 hashSaplingAnchor;
mutable CAnchorsSproutMap cacheSproutAnchors;
mutable CAnchorsSaplingMap cacheSaplingAnchors;
mutable CNullifiersMap cacheSproutNullifiers;
mutable CNullifiersMap cacheSaplingNullifiers;
/* Cached dynamic memory usage for the inner CCoins objects. */
mutable size_t cachedCoinsUsage;
@@ -498,30 +508,34 @@ public:
// Standard CCoinsView methods
static CLaunchMap &LaunchMap() { return launchMap; }
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
bool GetNullifier(const uint256 &nullifier) const;
bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const;
bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const;
bool GetNullifier(const uint256 &nullifier, ShieldedType type) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
uint256 GetBestAnchor() const;
uint256 GetBestAnchor(ShieldedType type) const;
void SetBestBlock(const uint256 &hashBlock);
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers);
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CAnchorsSaplingMap &mapSaplingAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers);
// Adds the tree to mapAnchors and sets the current commitment
// root to this root.
void PushAnchor(const ZCIncrementalMerkleTree &tree);
// Adds the tree to mapSproutAnchors (or mapSaplingAnchors based on the type of tree)
// and sets the current commitment root to this root.
template<typename Tree> void PushAnchor(const Tree &tree);
// Removes the current commitment root from mapAnchors and sets
// the new current root.
void PopAnchor(const uint256 &rt);
void PopAnchor(const uint256 &rt, ShieldedType type);
// Marks a nullifier as spent or not.
void SetNullifier(const uint256 &nullifier, bool spent);
// Marks nullifiers for a given transaction as spent or not.
void SetNullifiers(const CTransaction& tx, bool spent);
/**
* Return a pointer to CCoins in the cache, or NULL if not found. This is
@@ -556,7 +570,7 @@ public:
* so may not be able to calculate this.
*
* @param[in] tx transaction for which we are checking input total
* @return Sum of value of all inputs (scriptSigs)
* @return Sum of value of all inputs (scriptSigs), (positive valueBalance or zero) and JoinSplit vpub_new
*/
CAmount GetValueIn(int32_t nHeight,int64_t *interestp,const CTransaction& tx,uint32_t prevblocktime) const;
@@ -583,6 +597,31 @@ private:
* By making the copy constructor private, we prevent accidentally using it when one intends to create a cache on top of a base cache.
*/
CCoinsViewCache(const CCoinsViewCache &);
//! Generalized interface for popping anchors
template<typename Tree, typename Cache, typename CacheEntry>
void AbstractPopAnchor(
const uint256 &newrt,
ShieldedType type,
Cache &cacheAnchors,
uint256 &hash
);
//! Generalized interface for pushing anchors
template<typename Tree, typename Cache, typename CacheIterator, typename CacheEntry>
void AbstractPushAnchor(
const Tree &tree,
ShieldedType type,
Cache &cacheAnchors,
uint256 &hash
);
//! Interface for bringing an anchor into the cache.
template<typename Tree>
void BringBestAnchorIntoCache(
const uint256 &currentRoot,
Tree &tree
);
};
#endif // BITCOIN_COINS_H

View File

@@ -55,16 +55,8 @@ protected:
public:
CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
unsigned int GetSerializeSize(int nType, int nVersion) const {
std::vector<unsigned char> compr;
if (Compress(compr))
return compr.size();
unsigned int nSize = script.size() + nSpecialScripts;
return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion);
}
template<typename Stream>
void Serialize(Stream &s, int nType, int nVersion) const {
void Serialize(Stream &s) const {
std::vector<unsigned char> compr;
if (Compress(compr)) {
s << CFlatData(compr);
@@ -76,7 +68,7 @@ public:
}
template<typename Stream>
void Unserialize(Stream &s, int nType, int nVersion) {
void Unserialize(Stream &s) {
unsigned int nSize = 0;
s >> VARINT(nSize);
if (nSize < nSpecialScripts) {
@@ -112,7 +104,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
if (!ser_action.ForRead()) {
uint64_t nVal = CompressAmount(txout.nValue);
READWRITE(VARINT(nVal));

View File

@@ -10,16 +10,21 @@
static const int32_t MIN_BLOCK_VERSION = 4;
/** The minimum allowed transaction version (network rule) */
static const int32_t SPROUT_MIN_TX_VERSION = 1;
/** The minimum allowed transaction version (network rule) */
/** The minimum allowed Overwinter transaction version (network rule) */
static const int32_t OVERWINTER_MIN_TX_VERSION = 3;
/** The maximum allowed transaction version (network rule) */
/** The maximum allowed Overwinter transaction version (network rule) */
static const int32_t OVERWINTER_MAX_TX_VERSION = 3;
/** The minimum allowed Sapling transaction version (network rule) */
static const int32_t SAPLING_MIN_TX_VERSION = 4;
/** The maximum allowed Sapling transaction version (network rule) */
static const int32_t SAPLING_MAX_TX_VERSION = 4;
/** The maximum allowed size for a serialized block, in bytes (network rule) */
static const unsigned int MAX_BLOCK_SIZE = 2000000;
/** The maximum allowed number of signature check operations in a block (network rule) */
extern unsigned int MAX_BLOCK_SIGOPS;
/** The maximum size of a transaction (network rule) */
static const unsigned int MAX_TX_SIZE = 100000;
static const unsigned int MAX_TX_SIZE_BEFORE_SAPLING = 100000;
static const unsigned int MAX_TX_SIZE_AFTER_SAPLING = MAX_BLOCK_SIZE;
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
extern int COINBASE_MATURITY;
/** The minimum value which is invalid for expiry height, used by CTransaction and CMutableTransaction */

View File

@@ -23,6 +23,7 @@ enum UpgradeIndex {
BASE_SPROUT,
UPGRADE_TESTDUMMY,
UPGRADE_OVERWINTER,
UPGRADE_SAPLING,
// NOTE: Also add new upgrades to NetworkUpgradeInfo in upgrades.cpp
MAX_NETWORK_UPGRADES
};
@@ -111,6 +112,7 @@ struct Params {
int64_t AveragingWindowTimespan() const { return nPowAveragingWindow * nPowTargetSpacing; }
int64_t MinActualTimespan() const { return (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp )) / 100; }
int64_t MaxActualTimespan() const { return (AveragingWindowTimespan() * (100 + nPowMaxAdjustDown)) / 100; }
uint256 nMinimumChainWork;
};
} // namespace Consensus

View File

@@ -23,6 +23,11 @@ const struct NUInfo NetworkUpgradeInfo[Consensus::MAX_NETWORK_UPGRADES] = {
/*.nBranchId =*/ 0x5ba81b19,
/*.strName =*/ "Overwinter",
/*.strInfo =*/ "See https://z.cash/upgrade/overwinter.html for details.",
},
{
/*.nBranchId =*/ 0x76b809bb,
/*.strName =*/ "Sapling",
/*.strInfo =*/ "See https://z.cash/upgrade/sapling.html for details.",
}
};
@@ -69,6 +74,8 @@ int CurrentEpoch(int nHeight, const Consensus::Params& params) {
return idxInt;
}
}
// Base case
return Consensus::BASE_SPROUT;
}
uint32_t CurrentEpochBranchId(int nHeight, const Consensus::Params& params) {

View File

@@ -16,6 +16,7 @@ class UniValue;
// core_read.cpp
extern CScript ParseScript(const std::string& s);
extern std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
extern bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
extern uint256 ParseHashUV(const UniValue& v, const std::string& strName);
@@ -25,8 +26,7 @@ extern std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::strin
// core_write.cpp
extern std::string FormatScript(const CScript& script);
extern std::string EncodeHexTx(const CTransaction& tx);
extern void ScriptPubKeyToUniv(const CScript& scriptPubKey,
UniValue& out, bool fIncludeHex);
extern void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
extern void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry);
#endif // BITCOIN_CORE_IO_H

View File

@@ -10,7 +10,7 @@
#include "memusage.h"
static inline size_t RecursiveDynamicUsage(const CScript& script) {
return memusage::DynamicUsage(*static_cast<const std::vector<unsigned char>*>(&script));
return memusage::DynamicUsage(*static_cast<const CScriptBase*>(&script));
}
static inline size_t RecursiveDynamicUsage(const COutPoint& out) {

View File

@@ -4,7 +4,7 @@
#include "core_io.h"
#include "base58.h"
#include "key_io.h"
#include "primitives/transaction.h"
#include "script/script.h"
#include "script/standard.h"
@@ -15,6 +15,7 @@
#include "utilmoneystr.h"
#include "utilstrencodings.h"
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>
using namespace std;
@@ -54,6 +55,67 @@ string FormatScript(const CScript& script)
return ret.substr(0, ret.size() - 1);
}
const map<unsigned char, string> mapSigHashTypes =
boost::assign::map_list_of
(static_cast<unsigned char>(SIGHASH_ALL), string("ALL"))
(static_cast<unsigned char>(SIGHASH_ALL|SIGHASH_ANYONECANPAY), string("ALL|ANYONECANPAY"))
(static_cast<unsigned char>(SIGHASH_NONE), string("NONE"))
(static_cast<unsigned char>(SIGHASH_NONE|SIGHASH_ANYONECANPAY), string("NONE|ANYONECANPAY"))
(static_cast<unsigned char>(SIGHASH_SINGLE), string("SINGLE"))
(static_cast<unsigned char>(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), string("SINGLE|ANYONECANPAY"))
;
/**
* Create the assembly string representation of a CScript object.
* @param[in] script CScript object to convert into the asm string representation.
* @param[in] fAttemptSighashDecode Whether to attempt to decode sighash types on data within the script that matches the format
* of a signature. Only pass true for scripts you believe could contain signatures. For example,
* pass false, or omit the this argument (defaults to false), for scriptPubKeys.
*/
string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode)
{
string str;
opcodetype opcode;
vector<unsigned char> vch;
CScript::const_iterator pc = script.begin();
while (pc < script.end()) {
if (!str.empty()) {
str += " ";
}
if (!script.GetOp(pc, opcode, vch)) {
str += "[error]";
return str;
}
if (0 <= opcode && opcode <= OP_PUSHDATA4) {
if (vch.size() <= static_cast<vector<unsigned char>::size_type>(4)) {
str += strprintf("%d", CScriptNum(vch, false).getint());
} else {
// the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature
if (fAttemptSighashDecode && !script.IsUnspendable()) {
string strSigHashDecode;
// goal: only attempt to decode a defined sighash type from data that looks like a signature within a scriptSig.
// this won't decode correctly formatted public keys in Pubkey or Multisig scripts due to
// the restrictions on the pubkey formats (see IsCompressedOrUncompressedPubKey) being incongruous with the
// checks in CheckSignatureEncoding.
if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, NULL)) {
const unsigned char chSigHashType = vch.back();
if (mapSigHashTypes.count(chSigHashType)) {
strSigHashDecode = "[" + mapSigHashTypes.find(chSigHashType)->second + "]";
vch.pop_back(); // remove the sighash type byte. it will be replaced by the decode.
}
}
str += HexStr(vch) + strSigHashDecode;
} else {
str += HexStr(vch);
}
}
} else {
str += GetOpName(opcode);
}
}
return str;
}
string EncodeHexTx(const CTransaction& tx)
{
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
@@ -68,7 +130,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
vector<CTxDestination> addresses;
int nRequired;
out.pushKV("asm", scriptPubKey.ToString());
out.pushKV("asm", ScriptToAsmStr(scriptPubKey));
if (fIncludeHex)
out.pushKV("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
@@ -81,8 +143,9 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
out.pushKV("type", GetTxnOutputType(type));
UniValue a(UniValue::VARR);
BOOST_FOREACH(const CTxDestination& addr, addresses)
a.push_back(CBitcoinAddress(addr).ToString());
for (const CTxDestination& addr : addresses) {
a.push_back(EncodeDestination(addr));
}
out.pushKV("addresses", a);
}
@@ -101,7 +164,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
in.pushKV("txid", txin.prevout.hash.GetHex());
in.pushKV("vout", (int64_t)txin.prevout.n);
UniValue o(UniValue::VOBJ);
o.pushKV("asm", txin.scriptSig.ToString());
o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true));
o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));
in.pushKV("scriptSig", o);
}

View File

@@ -11,6 +11,7 @@
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include "sodium.h"
#include "compat/endian.h"
@@ -21,52 +22,67 @@
uint16_t static inline ReadLE16(const unsigned char* ptr)
{
return le16toh(*((uint16_t*)ptr));
uint16_t x;
memcpy((char*)&x, ptr, 2);
return le16toh(x);
}
uint32_t static inline ReadLE32(const unsigned char* ptr)
{
return le32toh(*((uint32_t*)ptr));
uint32_t x;
memcpy((char*)&x, ptr, 4);
return le32toh(x);
}
uint64_t static inline ReadLE64(const unsigned char* ptr)
{
return le64toh(*((uint64_t*)ptr));
uint64_t x;
memcpy((char*)&x, ptr, 8);
return le64toh(x);
}
void static inline WriteLE16(unsigned char* ptr, uint16_t x)
{
*((uint16_t*)ptr) = htole16(x);
uint16_t v = htole16(x);
memcpy(ptr, (char*)&v, 2);
}
void static inline WriteLE32(unsigned char* ptr, uint32_t x)
{
*((uint32_t*)ptr) = htole32(x);
uint32_t v = htole32(x);
memcpy(ptr, (char*)&v, 4);
}
void static inline WriteLE64(unsigned char* ptr, uint64_t x)
{
*((uint64_t*)ptr) = htole64(x);
uint64_t v = htole64(x);
memcpy(ptr, (char*)&v, 8);
}
uint32_t static inline ReadBE32(const unsigned char* ptr)
{
return be32toh(*((uint32_t*)ptr));
uint32_t x;
memcpy((char*)&x, ptr, 4);
return be32toh(x);
}
uint64_t static inline ReadBE64(const unsigned char* ptr)
{
return be64toh(*((uint64_t*)ptr));
uint64_t x;
memcpy((char*)&x, ptr, 8);
return be64toh(x);
}
void static inline WriteBE32(unsigned char* ptr, uint32_t x)
{
*((uint32_t*)ptr) = htobe32(x);
uint32_t v = htobe32(x);
memcpy(ptr, (char*)&v, 4);
}
void static inline WriteBE64(unsigned char* ptr, uint64_t x)
{
*((uint64_t*)ptr) = htobe64(x);
uint64_t v = htobe64(x);
memcpy(ptr, (char*)&v, 8);
}
int inline init_and_check_sodium()

View File

@@ -54,7 +54,7 @@
#define __BYTE_ORDER BYTE_ORDER
#endif
*/
EhSolverCancelledException solver_cancelled;
static EhSolverCancelledException solver_cancelled;
template<unsigned int N, unsigned int K>
int Equihash<N,K>::InitialiseState(eh_HashState& base_state)

View File

@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "leveldbwrapper.h"
#include "dbwrapper.h"
#include "util.h"
@@ -12,20 +12,7 @@
#include <leveldb/env.h>
#include <leveldb/filter_policy.h>
#include <memenv.h>
void HandleError(const leveldb::Status& status)
{
if (status.ok())
return;
LogPrintf("%s\n", status.ToString());
if (status.IsCorruption())
throw leveldb_error("Database corrupted");
if (status.IsIOError())
throw leveldb_error("Database I/O error");
if (status.IsNotFound())
throw leveldb_error("Database entry missing");
throw leveldb_error("Unknown database error");
}
#include <stdint.h>
static leveldb::Options GetOptions(size_t nCacheSize, bool compression, int maxOpenFiles)
{
@@ -43,7 +30,7 @@ static leveldb::Options GetOptions(size_t nCacheSize, bool compression, int maxO
return options;
}
CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool compression, int maxOpenFiles)
CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool compression, int maxOpenFiles)
{
penv = NULL;
readoptions.verify_checksums = true;
@@ -59,17 +46,17 @@ CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCa
if (fWipe) {
LogPrintf("Wiping LevelDB in %s\n", path.string());
leveldb::Status result = leveldb::DestroyDB(path.string(), options);
HandleError(result);
dbwrapper_private::HandleError(result);
}
TryCreateDirectory(path);
LogPrintf("Opening LevelDB in %s\n", path.string());
}
leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
HandleError(status);
dbwrapper_private::HandleError(status);
LogPrintf("Opened LevelDB successfully\n");
}
CLevelDBWrapper::~CLevelDBWrapper()
CDBWrapper::~CDBWrapper()
{
delete pdb;
pdb = NULL;
@@ -81,9 +68,41 @@ CLevelDBWrapper::~CLevelDBWrapper()
options.env = NULL;
}
bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync)
bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
{
leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
HandleError(status);
dbwrapper_private::HandleError(status);
return true;
}
bool CDBWrapper::IsEmpty()
{
boost::scoped_ptr<CDBIterator> it(NewIterator());
it->SeekToFirst();
return !(it->Valid());
}
CDBIterator::~CDBIterator() { delete piter; }
bool CDBIterator::Valid() { return piter->Valid(); }
void CDBIterator::SeekToFirst() { piter->SeekToFirst(); }
void CDBIterator::SeekToLast() { piter->SeekToLast(); }
void CDBIterator::Next() { piter->Next(); }
void CDBIterator::Prev() { piter->Prev(); }
namespace dbwrapper_private {
void HandleError(const leveldb::Status& status)
{
if (status.ok())
return;
LogPrintf("%s\n", status.ToString());
if (status.IsCorruption())
throw dbwrapper_error("Database corrupted");
if (status.IsIOError())
throw dbwrapper_error("Database I/O error");
if (status.IsNotFound())
throw dbwrapper_error("Database entry missing");
throw dbwrapper_error("Unknown database error");
}
};

267
src/dbwrapper.h Normal file
View File

@@ -0,0 +1,267 @@
// Copyright (c) 2012-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_DBWRAPPER_H
#define BITCOIN_DBWRAPPER_H
#include "clientversion.h"
#include "serialize.h"
#include "streams.h"
#include "util.h"
#include "version.h"
#include <boost/filesystem/path.hpp>
#include <leveldb/db.h>
#include <leveldb/write_batch.h>
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
class dbwrapper_error : public std::runtime_error
{
public:
dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
};
class CDBWrapper;
/** These should be considered an implementation detail of the specific database.
*/
namespace dbwrapper_private {
/** Handle database error by throwing dbwrapper_error exception.
*/
void HandleError(const leveldb::Status& status);
};
/** Batch of changes queued to be written to a CDBWrapper */
class CDBBatch
{
friend class CDBWrapper;
private:
const CDBWrapper &parent;
leveldb::WriteBatch batch;
public:
/**
* @param[in] _parent CDBWrapper that this batch is to be submitted to
*/
CDBBatch(const CDBWrapper &_parent) : parent(_parent) { };
template <typename K, typename V>
void Write(const K& key, const V& value)
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
leveldb::Slice slKey(&ssKey[0], ssKey.size());
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);
ssValue << value;
leveldb::Slice slValue(&ssValue[0], ssValue.size());
batch.Put(slKey, slValue);
}
template <typename K>
void Erase(const K& key)
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
leveldb::Slice slKey(&ssKey[0], ssKey.size());
batch.Delete(slKey);
}
};
class CDBIterator
{
private:
const CDBWrapper &parent;
leveldb::Iterator *piter;
public:
/**
* @param[in] _parent Parent CDBWrapper instance.
* @param[in] _piter The original leveldb iterator.
*/
CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter) :
parent(_parent), piter(_piter) { };
~CDBIterator();
bool Valid();
void SeekToFirst();
void SeekToLast();
template<typename K> void Seek(const K& key) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(GetSerializeSize(ssKey, key));
ssKey << key;
leveldb::Slice slKey(&ssKey[0], ssKey.size());
piter->Seek(slKey);
}
void Next();
void Prev();
template<typename K> bool GetKey(K& key) {
leveldb::Slice slKey = piter->key();
try {
CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
ssKey >> key;
} catch(std::exception &e) {
return false;
}
return true;
}
unsigned int GetKeySize() {
return piter->key().size();
}
template<typename V> bool GetValue(V& value) {
leveldb::Slice slValue = piter->value();
try {
CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION);
ssValue >> value;
} catch(std::exception &e) {
return false;
}
return true;
}
unsigned int GetValueSize() {
return piter->value().size();
}
};
class CDBWrapper
{
private:
//! custom environment this database is using (may be NULL in case of default environment)
leveldb::Env* penv;
//! database options used
leveldb::Options options;
//! options used when reading from the database
leveldb::ReadOptions readoptions;
//! options used when iterating over values of the database
leveldb::ReadOptions iteroptions;
//! options used when writing to the database
leveldb::WriteOptions writeoptions;
//! options used when sync writing to the database
leveldb::WriteOptions syncoptions;
//! the database itself
leveldb::DB* pdb;
public:
/**
* @param[in] path Location in the filesystem where leveldb data will be stored.
* @param[in] nCacheSize Configures various leveldb cache settings.
* @param[in] fMemory If true, use leveldb's memory environment.
* @param[in] fWipe If true, remove all existing data.
*/
CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool compression = false, int maxOpenFiles = 64);
~CDBWrapper();
template <typename K, typename V>
bool Read(const K& key, V& value) const
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
leveldb::Slice slKey(&ssKey[0], ssKey.size());
std::string strValue;
leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
if (!status.ok()) {
if (status.IsNotFound())
return false;
LogPrintf("LevelDB read failure: %s\n", status.ToString());
dbwrapper_private::HandleError(status);
}
try {
CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
ssValue >> value;
} catch (const std::exception&) {
return false;
}
return true;
}
template <typename K, typename V>
bool Write(const K& key, const V& value, bool fSync = false)
{
CDBBatch batch(*this);
batch.Write(key, value);
return WriteBatch(batch, fSync);
}
template <typename K>
bool Exists(const K& key) const
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
leveldb::Slice slKey(&ssKey[0], ssKey.size());
std::string strValue;
leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
if (!status.ok()) {
if (status.IsNotFound())
return false;
LogPrintf("LevelDB read failure: %s\n", status.ToString());
dbwrapper_private::HandleError(status);
}
return true;
}
template <typename K>
bool Erase(const K& key, bool fSync = false)
{
CDBBatch batch(*this);
batch.Erase(key);
return WriteBatch(batch, fSync);
}
bool WriteBatch(CDBBatch& batch, bool fSync = false);
// not available for LevelDB; provide for compatibility with BDB
bool Flush()
{
return true;
}
bool Sync()
{
CDBBatch batch(*this);
return WriteBatch(batch, true);
}
CDBIterator *NewIterator()
{
return new CDBIterator(*this, pdb->NewIterator(iteroptions));
}
/**
* Return true if the database managed by this class contains no entries.
*/
bool IsEmpty();
};
#endif // BITCOIN_DBWRAPPER_H

View File

@@ -4,6 +4,7 @@
#include "deprecation.h"
#include "alert.h"
#include "clientversion.h"
#include "init.h"
#include "ui_interface.h"
@@ -13,14 +14,15 @@
static const std::string CLIENT_VERSION_STR = FormatVersion(CLIENT_VERSION);
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
void EnforceNodeDeprecation(int nHeight, bool forceLogging) {
void EnforceNodeDeprecation(int nHeight, bool forceLogging, bool fThread) {
// Do not enforce deprecation in regtest or on testnet
std::string networkID = Params().NetworkIDString();
std::string msg;
if (networkID != "main" || ASSETCHAINS_SYMBOL[0] != 0 ) return;
int blocksToDeprecation = DEPRECATION_HEIGHT - nHeight;
bool disableDeprecation = (GetArg("-disabledeprecation", "") == CLIENT_VERSION_STR);
if (blocksToDeprecation <= 0) {
// In order to ensure we only log once per process when deprecation is
// disabled (to avoid log spam), we only need to log in two cases:
@@ -29,34 +31,20 @@ void EnforceNodeDeprecation(int nHeight, bool forceLogging) {
// occurs, but that's an irregular event that won't cause spam.
// - The node is starting
if (blocksToDeprecation == 0 || forceLogging) {
auto msg = strprintf(_("This version has been deprecated as of block height %d."),
msg = strprintf(_("This version has been deprecated as of block height %d."),
DEPRECATION_HEIGHT) + " " +
_("You should upgrade to the latest version of Komodo.");
if (!disableDeprecation) {
msg += " " + strprintf(_("To disable deprecation for this version, set %s%s."),
"-disabledeprecation=", CLIENT_VERSION_STR);
}
LogPrintf("*** %s\n", msg);
CAlert::Notify(msg, fThread);
uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR);
}
if (!disableDeprecation) {
StartShutdown();
}
} else if (blocksToDeprecation == DEPRECATION_WARN_LIMIT ||
(blocksToDeprecation < DEPRECATION_WARN_LIMIT && forceLogging)) {
std::string msg;
if (disableDeprecation) {
msg = strprintf(_("This version will be deprecated at block height %d."),
StartShutdown();
} else if (blocksToDeprecation == DEPRECATION_WARN_LIMIT || (blocksToDeprecation < DEPRECATION_WARN_LIMIT && forceLogging)) {
msg = strprintf(_("This version will be deprecated at block height %d, and will automatically shut down."),
DEPRECATION_HEIGHT) + " " +
_("You should upgrade to the latest version of Komodo.");
} else {
msg = strprintf(_("This version will be deprecated at block height %d, and will automatically shut down."),
DEPRECATION_HEIGHT) + " " +
_("You should upgrade to the latest version of Komodo.") + " " +
strprintf(_("To disable deprecation for this version, set %s%s."),
"-disabledeprecation=", CLIENT_VERSION_STR);
}
LogPrintf("*** %s\n", msg);
uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_WARNING);
}
LogPrintf("*** %s\n", msg);
CAlert::Notify(msg, fThread);
uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_WARNING);
}

View File

@@ -18,8 +18,11 @@ static const int DEPRECATION_WARN_LIMIT = 60 * 24 * 60; // 2 months
/**
* Checks whether the node is deprecated based on the current block height, and
* shuts down the node with an error if so (and deprecation is not disabled for
* the current client version).
* the current client version). Warning and error messages are sent to the debug
* log, the metrics UI, and (if configured) -alertnofity.
*
* fThread means run -alertnotify in a free-running thread.
*/
void EnforceNodeDeprecation(int nHeight, bool forceLogging=false);
void EnforceNodeDeprecation(int nHeight, bool forceLogging=false, bool fThread=true);
#endif // ZCASH_DEPRECATION_H

View File

@@ -26,7 +26,7 @@ void expect_deser_same(const T& expected)
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
ss2 << object;
ASSERT_TRUE(serialized_size == ss2.size());
ASSERT_EQ(serialized_size, ss2.size());
ASSERT_TRUE(memcmp(&*ss1.begin(), &*ss2.begin(), serialized_size) == 0);
}
@@ -45,7 +45,7 @@ void expect_test_vector(T& v, const U& expected)
std::string raw = v.get_str();
CDataStream ss2(ParseHex(raw), SER_NETWORK, PROTOCOL_VERSION);
ASSERT_TRUE(ss1.size() == ss2.size());
ASSERT_EQ(ss1.size(), ss2.size());
ASSERT_TRUE(memcmp(&*ss1.begin(), &*ss2.begin(), ss1.size()) == 0);
#endif
}

View File

@@ -1,5 +1,6 @@
#include "gmock/gmock.h"
#include "crypto/common.h"
#include "key.h"
#include "pubkey.h"
#include "zcash/JoinSplit.hpp"
#include "util.h"
@@ -7,6 +8,8 @@
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include "librustzcash.h"
struct ECCryptoClosure
{
ECCVerifyHandle handle;
@@ -18,13 +21,36 @@ ZCJoinSplit* params;
int main(int argc, char **argv) {
assert(init_and_check_sodium() != -1);
ECC_Start();
libsnark::default_r1cs_ppzksnark_pp::init_public_params();
libsnark::inhibit_profiling_info = true;
libsnark::inhibit_profiling_counters = true;
boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key";
boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key";
params = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string());
boost::filesystem::path sapling_spend = ZC_GetParamsDir() / "sapling-spend.params";
boost::filesystem::path sapling_output = ZC_GetParamsDir() / "sapling-output.params";
boost::filesystem::path sprout_groth16 = ZC_GetParamsDir() / "sprout-groth16.params";
std::string sapling_spend_str = sapling_spend.string();
std::string sapling_output_str = sapling_output.string();
std::string sprout_groth16_str = sprout_groth16.string();
librustzcash_init_zksnark_params(
sapling_spend_str.c_str(),
"8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c",
sapling_output_str.c_str(),
"657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028",
sprout_groth16_str.c_str(),
"e9b238411bd6c0ec4791e9d04245ec350c9c5744f5610dfcce4365d5ca49dfefd5054e371842b3f88fa1b9d7e8e075249b3ebabd167fa8b0f3161292d36c180a"
);
testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
auto ret = RUN_ALL_TESTS();
ECC_Stop();
return ret;
}

View File

@@ -68,27 +68,99 @@ TEST(CheckBlock, BlockSproutRejectsBadVersion) {
}
TEST(ContextualCheckBlock, BadCoinbaseHeight) {
SelectParams(CBaseChainParams::MAIN);
class ContextualCheckBlockTest : public ::testing::Test {
protected:
virtual void SetUp() {
SelectParams(CBaseChainParams::MAIN);
}
// Create a block with no height in scriptSig
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
virtual void TearDown() {
// Revert to test default. No-op on mainnet params.
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Returns a valid but empty mutable transaction at block height 1.
CMutableTransaction GetFirstBlockCoinbaseTx() {
CMutableTransaction mtx;
// No inputs.
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
// Set height to 1.
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
// Give it a single zero-valued, always-valid output.
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
// Give it a Founder's Reward vout for height 1.
mtx.vout.push_back(CTxOut(
GetBlockSubsidy(1, Params().GetConsensus())/5,
Params().GetFoundersRewardScriptAtHeight(1)));
return mtx;
}
// Expects a height-1 block containing a given transaction to pass
// ContextualCheckBlock. This is used in accepting (Sprout-Sprout,
// Overwinter-Overwinter, ...) tests. You should not call it without
// calling a SCOPED_TRACE macro first to usefully label any failures.
void ExpectValidBlockFromTx(const CTransaction& tx) {
// Create a block and add the transaction to it.
CBlock block;
block.vtx.push_back(tx);
// Set the previous block index to the genesis block.
CBlockIndex indexPrev {Params().GenesisBlock()};
// We now expect this to be a valid block.
MockCValidationState state;
EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev));
}
// Expects a height-1 block containing a given transaction to fail
// ContextualCheckBlock. This is used in rejecting (Sprout-Overwinter,
// Overwinter-Sprout, ...) tests. You should not call it without
// calling a SCOPED_TRACE macro first to usefully label any failures.
void ExpectInvalidBlockFromTx(const CTransaction& tx, int level, std::string reason) {
// Create a block and add the transaction to it.
CBlock block;
block.vtx.push_back(tx);
// Set the previous block index to the genesis block.
CBlockIndex indexPrev {Params().GenesisBlock()};
// We now expect this to be an invalid block, for the given reason.
MockCValidationState state;
EXPECT_CALL(state, DoS(level, false, REJECT_INVALID, reason, false)).Times(1);
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
}
};
TEST_F(ContextualCheckBlockTest, BadCoinbaseHeight) {
// Put a transaction in a block with no height in scriptSig
CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
mtx.vin[0].scriptSig = CScript() << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
CTransaction tx {mtx};
mtx.vout.pop_back(); // remove the FR output
CBlock block;
block.vtx.push_back(tx);
block.vtx.push_back(mtx);
// Treating block as genesis should pass
MockCValidationState state;
EXPECT_TRUE(ContextualCheckBlock(block, state, NULL));
// Give the transaction a Founder's Reward vout
mtx.vout.push_back(CTxOut(
GetBlockSubsidy(1, Params().GetConsensus())/5,
Params().GetFoundersRewardScriptAtHeight(1)));
// Treating block as non-genesis should fail
mtx.vout.push_back(CTxOut(GetBlockSubsidy(1, Params().GetConsensus())/5, Params().GetFoundersRewardScriptAtHeight(1)));
CTransaction tx2 {mtx};
block.vtx[0] = tx2;
CBlock prev;
@@ -111,124 +183,142 @@ TEST(ContextualCheckBlock, BadCoinbaseHeight) {
EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev));
}
// Test that a block evaluated under Sprout rules cannot contain Overwinter transactions.
// TEST PLAN: first, check that each ruleset accepts its own transaction type.
// Currently (May 2018) this means we'll test Sprout-Sprout,
// Overwinter-Overwinter, and Sapling-Sapling.
// Test block evaluated under Sprout rules will accept Sprout transactions.
// This test assumes that mainnet Overwinter activation is at least height 2.
TEST(ContextualCheckBlock, BlockSproutRulesRejectOverwinterTx) {
SelectParams(CBaseChainParams::MAIN);
TEST_F(ContextualCheckBlockTest, BlockSproutRulesAcceptSproutTx) {
CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1);
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
}
// Test block evaluated under Sprout rules will accept Sprout transactions
TEST(ContextualCheckBlock, BlockSproutRulesAcceptSproutTx) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
mtx.vout.push_back(CTxOut(
GetBlockSubsidy(1, Params().GetConsensus())/5,
Params().GetFoundersRewardScriptAtHeight(1)));
// Make it a Sprout transaction w/o JoinSplits
mtx.fOverwintered = false;
mtx.nVersion = 1;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev));
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
SCOPED_TRACE("BlockSproutRulesAcceptSproutTx");
ExpectValidBlockFromTx(CTransaction(mtx));
}
// Test block evaluated under Overwinter rules will accept Overwinter transactions
TEST(ContextualCheckBlock, BlockOverwinterRulesAcceptOverwinterTx) {
// Test block evaluated under Overwinter rules will accept Overwinter transactions.
TEST_F(ContextualCheckBlockTest, BlockOverwinterRulesAcceptOverwinterTx) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
mtx.vout.push_back(CTxOut(
GetBlockSubsidy(1, Params().GetConsensus())/5,
Params().GetFoundersRewardScriptAtHeight(1)));
CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
// Make it an Overwinter transaction
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersion = OVERWINTER_TX_VERSION;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev));
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
SCOPED_TRACE("BlockOverwinterRulesAcceptOverwinterTx");
ExpectValidBlockFromTx(CTransaction(mtx));
}
// Test that a block evaluated under Sapling rules can contain Sapling transactions.
TEST_F(ContextualCheckBlockTest, BlockSaplingRulesAcceptSaplingTx) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, 1);
// Test block evaluated under Overwinter rules will reject Sprout transactions
TEST(ContextualCheckBlock, BlockOverwinterRulesRejectSproutTx) {
CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
// Make it a Sapling transaction
mtx.fOverwintered = true;
mtx.nVersion = SAPLING_TX_VERSION;
mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
SCOPED_TRACE("BlockSaplingRulesAcceptSaplingTx");
ExpectValidBlockFromTx(CTransaction(mtx));
}
// TEST PLAN: next, check that each ruleset will not accept other transaction
// types. Currently (May 2018) this means we'll test Sprout-Overwinter,
// Sprout-Sapling, Overwinter-Sprout, Overwinter-Sapling, Sapling-Sprout, and
// Sapling-Overwinter.
// Test that a block evaluated under Sprout rules cannot contain non-Sprout
// transactions which require Overwinter to be active. This test assumes that
// mainnet Overwinter activation is at least height 2.
TEST_F(ContextualCheckBlockTest, BlockSproutRulesRejectOtherTx) {
CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
// Make it an Overwinter transaction
mtx.fOverwintered = true;
mtx.nVersion = OVERWINTER_TX_VERSION;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
{
SCOPED_TRACE("BlockSproutRulesRejectOverwinterTx");
ExpectInvalidBlockFromTx(CTransaction(mtx), 0, "tx-overwinter-not-active");
}
// Make it a Sapling transaction
mtx.fOverwintered = true;
mtx.nVersion = SAPLING_TX_VERSION;
mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
{
SCOPED_TRACE("BlockSproutRulesRejectSaplingTx");
ExpectInvalidBlockFromTx(CTransaction(mtx), 0, "tx-overwinter-not-active");
}
};
// Test block evaluated under Overwinter rules cannot contain non-Overwinter
// transactions.
TEST_F(ContextualCheckBlockTest, BlockOverwinterRulesRejectOtherTx) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
// Set the version to Sprout+JoinSplit (but nJoinSplit will be 0).
mtx.nVersion = 2;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
{
SCOPED_TRACE("BlockOverwinterRulesRejectSproutTx");
ExpectInvalidBlockFromTx(CTransaction(mtx), 100, "tx-overwinter-active");
}
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
// Make it a Sapling transaction
mtx.fOverwintered = true;
mtx.nVersion = SAPLING_TX_VERSION;
mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-active", false)).Times(1);
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
{
SCOPED_TRACE("BlockOverwinterRulesRejectSaplingTx");
ExpectInvalidBlockFromTx(CTransaction(mtx), 100, "bad-overwinter-tx-version-group-id");
}
}
// Test block evaluated under Sapling rules cannot contain non-Sapling transactions.
TEST_F(ContextualCheckBlockTest, BlockSaplingRulesRejectOtherTx) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, 1);
CMutableTransaction mtx = GetFirstBlockCoinbaseTx();
// Set the version to Sprout+JoinSplit (but nJoinSplit will be 0).
mtx.nVersion = 2;
{
SCOPED_TRACE("BlockSaplingRulesRejectSproutTx");
ExpectInvalidBlockFromTx(CTransaction(mtx), 100, "tx-overwinter-active");
}
// Make it an Overwinter transaction
mtx.fOverwintered = true;
mtx.nVersion = OVERWINTER_TX_VERSION;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
{
SCOPED_TRACE("BlockSaplingRulesRejectOverwinterTx");
ExpectInvalidBlockFromTx(CTransaction(mtx), 100, "bad-sapling-tx-version-group-id");
}
}

View File

@@ -6,6 +6,8 @@
#include "primitives/transaction.h"
#include "consensus/validation.h"
extern ZCJoinSplit* params;
TEST(checktransaction_tests, check_vpub_not_both_nonzero) {
CMutableTransaction tx;
tx.nVersion = 2;
@@ -43,6 +45,7 @@ public:
MOCK_CONST_METHOD0(GetRejectReason, std::string());
};
void CreateJoinSplitSignature(CMutableTransaction& mtx, uint32_t consensusBranchId);
CMutableTransaction GetValidTransaction() {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
@@ -63,7 +66,11 @@ CMutableTransaction GetValidTransaction() {
mtx.vjoinsplit[1].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
mtx.vjoinsplit[1].nullifiers.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000003");
CreateJoinSplitSignature(mtx, consensusBranchId);
return mtx;
}
void CreateJoinSplitSignature(CMutableTransaction& mtx, uint32_t consensusBranchId) {
// Generate an ephemeral keypair.
uint256 joinSplitPubKey;
unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
@@ -86,7 +93,6 @@ CMutableTransaction GetValidTransaction() {
dataToBeSigned.begin(), 32,
joinSplitPrivKey
) == 0);
return mtx;
}
TEST(checktransaction_tests, valid_transaction) {
@@ -129,7 +135,8 @@ TEST(checktransaction_tests, bad_txns_vout_empty) {
CheckTransactionWithoutProofVerification(tx, state);
}
TEST(checktransaction_tests, bad_txns_oversize) {
TEST(checktransaction_tests, BadTxnsOversize) {
SelectParams(CBaseChainParams::REGTEST);
CMutableTransaction mtx = GetValidTransaction();
mtx.vin[0].scriptSig = CScript();
@@ -153,10 +160,100 @@ TEST(checktransaction_tests, bad_txns_oversize) {
CTransaction tx(mtx);
ASSERT_EQ(::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION), 100202);
// Passes non-contextual checks...
MockCValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
// ... but fails contextual ones!
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-oversize", false)).Times(1);
EXPECT_FALSE(ContextualCheckTransaction(tx, state, 1, 100));
}
{
// But should be fine again once Sapling activates!
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
mtx.fOverwintered = true;
mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
mtx.nVersion = SAPLING_TX_VERSION;
// Change the proof types (which requires re-signing the JoinSplit data)
mtx.vjoinsplit[0].proof = libzcash::GrothProof();
mtx.vjoinsplit[1].proof = libzcash::GrothProof();
CreateJoinSplitSignature(mtx, NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId);
CTransaction tx(mtx);
EXPECT_EQ(::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION), 103713);
MockCValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
EXPECT_TRUE(ContextualCheckTransaction(tx, state, 1, 100));
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
}
TEST(checktransaction_tests, OversizeSaplingTxns) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
CMutableTransaction mtx = GetValidTransaction();
mtx.fOverwintered = true;
mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
mtx.nVersion = SAPLING_TX_VERSION;
// Change the proof types (which requires re-signing the JoinSplit data)
mtx.vjoinsplit[0].proof = libzcash::GrothProof();
mtx.vjoinsplit[1].proof = libzcash::GrothProof();
CreateJoinSplitSignature(mtx, NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId);
// Transaction just under the limit
mtx.vin[0].scriptSig = CScript();
std::vector<unsigned char> vchData(520);
for (unsigned int i = 0; i < 3809; ++i)
mtx.vin[0].scriptSig << vchData << OP_DROP;
std::vector<unsigned char> vchDataRemainder(453);
mtx.vin[0].scriptSig << vchDataRemainder << OP_DROP;
mtx.vin[0].scriptSig << OP_1;
{
CTransaction tx(mtx);
EXPECT_EQ(::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION), MAX_TX_SIZE_AFTER_SAPLING - 1);
CValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
}
// Transaction equal to the limit
mtx.vin[1].scriptSig << OP_1;
{
CTransaction tx(mtx);
EXPECT_EQ(::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION), MAX_TX_SIZE_AFTER_SAPLING);
CValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
}
// Transaction just over the limit
mtx.vin[1].scriptSig << OP_1;
{
CTransaction tx(mtx);
EXPECT_EQ(::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION), MAX_TX_SIZE_AFTER_SAPLING + 1);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-oversize", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
EXPECT_FALSE(CheckTransactionWithoutProofVerification(tx, state));
}
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
TEST(checktransaction_tests, bad_txns_vout_negative) {
@@ -193,6 +290,54 @@ TEST(checktransaction_tests, bad_txns_txouttotal_toolarge_outputs) {
CheckTransactionWithoutProofVerification(tx, state);
}
TEST(checktransaction_tests, ValueBalanceNonZero) {
CMutableTransaction mtx = GetValidTransaction();
mtx.valueBalance = 10;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-valuebalance-nonzero", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
TEST(checktransaction_tests, PositiveValueBalanceTooLarge) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vShieldedSpend.resize(1);
mtx.valueBalance = MAX_MONEY + 1;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-valuebalance-toolarge", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
TEST(checktransaction_tests, NegativeValueBalanceTooLarge) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vShieldedSpend.resize(1);
mtx.valueBalance = -(MAX_MONEY + 1);
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-valuebalance-toolarge", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
TEST(checktransaction_tests, ValueBalanceOverflowsTotal) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vShieldedSpend.resize(1);
mtx.vout[0].nValue = 1;
mtx.valueBalance = -MAX_MONEY;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
TEST(checktransaction_tests, bad_txns_txouttotal_toolarge_joinsplit) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vout[0].nValue = 1;
@@ -361,7 +506,7 @@ TEST(checktransaction_tests, bad_txns_invalid_joinsplit_signature) {
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1);
EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1);
ContextualCheckTransaction(tx, state, 0, 100);
}
@@ -394,14 +539,14 @@ TEST(checktransaction_tests, non_canonical_ed25519_signature) {
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1);
EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1);
ContextualCheckTransaction(tx, state, 0, 100);
}
TEST(checktransaction_tests, OverwinterConstructors) {
CMutableTransaction mtx;
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersion = OVERWINTER_TX_VERSION;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 20;
@@ -432,7 +577,7 @@ TEST(checktransaction_tests, OverwinterConstructors) {
TEST(checktransaction_tests, OverwinterSerialization) {
CMutableTransaction mtx;
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersion = OVERWINTER_TX_VERSION;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 99;
@@ -496,7 +641,7 @@ TEST(checktransaction_tests, OverwinterValidTx) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersion = OVERWINTER_TX_VERSION;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
CTransaction tx(mtx);
@@ -508,7 +653,7 @@ TEST(checktransaction_tests, OverwinterExpiryHeight) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersion = OVERWINTER_TX_VERSION;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
@@ -567,6 +712,58 @@ class UNSAFE_CTransaction : public CTransaction {
UNSAFE_CTransaction(const CMutableTransaction &tx) : CTransaction(tx, true) {}
};
TEST(checktransaction_tests, SaplingSproutInputSumsTooLarge) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = SAPLING_TX_VERSION;
mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
{
// create JSDescription
uint256 rt;
uint256 joinSplitPubKey;
std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> inputs = {
libzcash::JSInput(),
libzcash::JSInput()
};
std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS> outputs = {
libzcash::JSOutput(),
libzcash::JSOutput()
};
std::array<size_t, ZC_NUM_JS_INPUTS> inputMap;
std::array<size_t, ZC_NUM_JS_OUTPUTS> outputMap;
auto jsdesc = JSDescription::Randomized(
true,
*params, joinSplitPubKey, rt,
inputs, outputs,
inputMap, outputMap,
0, 0, false);
mtx.vjoinsplit.push_back(jsdesc);
}
mtx.vShieldedSpend.push_back(SpendDescription());
mtx.vjoinsplit[0].vpub_new = (MAX_MONEY / 2) + 10;
{
UNSAFE_CTransaction tx(mtx);
CValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
}
mtx.valueBalance = (MAX_MONEY / 2) + 10;
{
UNSAFE_CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-txintotal-toolarge", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
}
// Test bad Overwinter version number in CheckTransactionWithoutProofVerification
TEST(checktransaction_tests, OverwinterVersionNumberLow) {
@@ -610,7 +807,7 @@ TEST(checktransaction_tests, OverwinterBadVersionGroupId) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersion = OVERWINTER_TX_VERSION;
mtx.nExpiryHeight = 0;
mtx.nVersionGroupId = 0x12345678;
@@ -626,13 +823,13 @@ TEST(checktransaction_tests, OverwinterNotActive) {
CMutableTransaction mtx = GetValidTransaction();
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersion = OVERWINTER_TX_VERSION;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1);
EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1);
ContextualCheckTransaction(tx, state, 1, 100);
}
@@ -643,7 +840,7 @@ TEST(checktransaction_tests, OverwinterFlagNotSet) {
CMutableTransaction mtx = GetValidTransaction();
mtx.fOverwintered = false;
mtx.nVersion = 3;
mtx.nVersion = OVERWINTER_TX_VERSION;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
@@ -684,7 +881,9 @@ TEST(checktransaction_tests, OverwinteredContextualCreateTx) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& consensusParams = Params().GetConsensus();
int activationHeight = 5;
int saplingActivationHeight = 30;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, activationHeight);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, saplingActivationHeight);
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(
@@ -704,10 +903,64 @@ TEST(checktransaction_tests, OverwinteredContextualCreateTx) {
EXPECT_EQ(mtx.nVersion, 3);
EXPECT_EQ(mtx.fOverwintered, true);
EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID);
EXPECT_EQ(mtx.nExpiryHeight, 0);
EXPECT_EQ(mtx.nExpiryHeight, activationHeight + expiryDelta);
}
// Close to Sapling activation
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(
consensusParams, saplingActivationHeight - expiryDelta - 2);
EXPECT_EQ(mtx.fOverwintered, true);
EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID);
EXPECT_EQ(mtx.nVersion, OVERWINTER_TX_VERSION);
EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight - 2);
}
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(
consensusParams, saplingActivationHeight - expiryDelta - 1);
EXPECT_EQ(mtx.fOverwintered, true);
EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID);
EXPECT_EQ(mtx.nVersion, OVERWINTER_TX_VERSION);
EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight - 1);
}
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(
consensusParams, saplingActivationHeight - expiryDelta);
EXPECT_EQ(mtx.fOverwintered, true);
EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID);
EXPECT_EQ(mtx.nVersion, OVERWINTER_TX_VERSION);
EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight - 1);
}
// Just before Sapling activation
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(
consensusParams, saplingActivationHeight - 1);
EXPECT_EQ(mtx.fOverwintered, true);
EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID);
EXPECT_EQ(mtx.nVersion, OVERWINTER_TX_VERSION);
EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight - 1);
}
// Sapling activates
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(
consensusParams, saplingActivationHeight);
EXPECT_EQ(mtx.fOverwintered, true);
EXPECT_EQ(mtx.nVersionGroupId, SAPLING_VERSION_GROUP_ID);
EXPECT_EQ(mtx.nVersion, SAPLING_TX_VERSION);
EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight + expiryDelta);
}
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
@@ -771,4 +1024,4 @@ TEST(checktransaction_tests, BadTxReceivedOverNetwork)
FAIL() << "Expected std::ios_base::failure 'Unknown transaction format', got some other exception";
}
}
}
}

View File

@@ -106,7 +106,7 @@ bool test_merkle_gadget(
mgadget1.generate_r1cs_constraints();
mgadget2.generate_r1cs_constraints();
ZCIncrementalMerkleTree tree;
SproutMerkleTree tree;
uint256 commitment1_data = uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c");
uint256 commitment2_data = uint256S("59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7");
tree.append(commitment1_data);

View File

@@ -1,12 +1,16 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "chainparams.h"
#include "clientversion.h"
#include "deprecation.h"
#include "init.h"
#include "ui_interface.h"
#include "util.h"
#include "chainparams.h"
#include "utilstrencodings.h"
#include <boost/filesystem/operations.hpp>
#include <fstream>
using ::testing::StrictMock;
@@ -43,6 +47,18 @@ protected:
}
StrictMock<MockUIInterface> mock_;
static std::vector<std::string> read_lines(boost::filesystem::path filepath) {
std::vector<std::string> result;
std::ifstream f(filepath.string().c_str());
std::string line;
while (std::getline(f,line)) {
result.push_back(line);
}
return result;
}
};
TEST_F(DeprecationTest, NonDeprecatedNodeKeepsRunning) {
@@ -91,22 +107,6 @@ TEST_F(DeprecationTest, DeprecatedNodeErrorIsRepeatedOnStartup) {
EXPECT_TRUE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeShutsDownIfOldVersionDisabled) {
EXPECT_FALSE(ShutdownRequested());
mapArgs["-disabledeprecation"] = "1.0.0";
EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_ERROR));
EnforceNodeDeprecation(DEPRECATION_HEIGHT);
EXPECT_TRUE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeKeepsRunningIfCurrentVersionDisabled) {
EXPECT_FALSE(ShutdownRequested());
mapArgs["-disabledeprecation"] = CLIENT_VERSION_STR;
EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_ERROR));
EnforceNodeDeprecation(DEPRECATION_HEIGHT);
EXPECT_FALSE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeIgnoredOnRegtest) {
SelectParams(CBaseChainParams::REGTEST);
EXPECT_FALSE(ShutdownRequested());
@@ -119,4 +119,31 @@ TEST_F(DeprecationTest, DeprecatedNodeIgnoredOnTestnet) {
EXPECT_FALSE(ShutdownRequested());
EnforceNodeDeprecation(DEPRECATION_HEIGHT+1);
EXPECT_FALSE(ShutdownRequested());
}
}
TEST_F(DeprecationTest, AlertNotify) {
boost::filesystem::path temp = GetTempPath() /
boost::filesystem::unique_path("alertnotify-%%%%.txt");
mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string();
EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_WARNING));
EnforceNodeDeprecation(DEPRECATION_HEIGHT - DEPRECATION_WARN_LIMIT, false, false);
std::vector<std::string> r = read_lines(temp);
EXPECT_EQ(r.size(), 1u);
// -alertnotify restricts the message to safe characters.
auto expectedMsg = strprintf(
"This version will be deprecated at block height %d, and will automatically shut down. You should upgrade to the latest version of Zcash.",
DEPRECATION_HEIGHT);
// Windows built-in echo semantics are different than posixy shells. Quotes and
// whitespace are printed literally.
#ifndef WIN32
EXPECT_EQ(r[0], expectedMsg);
#else
EXPECT_EQ(r[0], strprintf("'%s' ", expectedMsg));
#endif
boost::filesystem::remove(temp);
}

View File

@@ -25,7 +25,6 @@
//
#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);
@@ -60,7 +59,7 @@ TEST(founders_reward_test, create_testnet_2of3multisig) {
pWallet->AddCScript(result);
pWallet->SetAddressBook(innerID, "", "receive");
std::string address = CBitcoinAddress(innerID).ToString();
std::string address = EncodeDestination(innerID);
addresses.push_back(address);
}
@@ -81,8 +80,6 @@ TEST(founders_reward_test, create_testnet_2of3multisig) {
std::cout << s << std::endl;
pWallet->Flush(true);
ECC_Stop();
}
#endif
@@ -107,11 +104,11 @@ TEST(founders_reward_test, general) {
// address = t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy
// script.ToString() = OP_HASH160 55d64928e69829d9376c776550b6cc710d427153 OP_EQUAL
// HexStr(script) = a91455d64928e69829d9376c776550b6cc710d42715387
EXPECT_EQ(params.GetFoundersRewardScriptAtHeight(1), ParseHex("a914ef775f1f997f122a062fff1a2d7443abd1f9c64287"));
EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(1)), "a914ef775f1f997f122a062fff1a2d7443abd1f9c64287");
EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(1), "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi");
EXPECT_EQ(params.GetFoundersRewardScriptAtHeight(53126), ParseHex("a914ac67f4c072668138d88a86ff21b27207b283212f87"));
EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(53126)), "a914ac67f4c072668138d88a86ff21b27207b283212f87");
EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(53126), "t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2");
EXPECT_EQ(params.GetFoundersRewardScriptAtHeight(53127), ParseHex("a91455d64928e69829d9376c776550b6cc710d42715387"));
EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(53127)), "a91455d64928e69829d9376c776550b6cc710d42715387");
EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(53127), "t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy");
int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight();

View File

@@ -3,192 +3,222 @@
#include "utilstrencodings.h"
#include <boost/foreach.hpp>
#include <boost/variant/get.hpp>
#include "zcash/prf.h"
#include "util.h"
#include "streams.h"
#include "version.h"
#include "serialize.h"
#include "primitives/transaction.h"
#include "zcash/JoinSplit.hpp"
#include "zcash/Note.hpp"
#include "zcash/NoteEncryption.hpp"
#include "zcash/IncrementalMerkleTree.hpp"
#include <array>
using namespace libzcash;
extern ZCJoinSplit* params;
typedef std::array<JSDescription, 2> SproutProofs;
// Make both the PHGR and Groth proof for a Sprout statement,
// and store the results in JSDescription objects.
SproutProofs makeSproutProofs(
ZCJoinSplit& js,
const std::array<JSInput, 2>& inputs,
const std::array<JSOutput, 2>& outputs,
const uint256& joinSplitPubKey,
uint64_t vpub_old,
uint64_t vpub_new,
const uint256& rt
){
//Making the PHGR proof
JSDescription phgr(false, js, joinSplitPubKey, rt, inputs, outputs, vpub_old, vpub_new);
//Making the Groth proof
JSDescription groth(true, js, joinSplitPubKey, rt, inputs, outputs, vpub_old, vpub_new);
return {phgr, groth};
}
bool verifySproutProofs(
ZCJoinSplit& js,
const SproutProofs& jsdescs,
const uint256& joinSplitPubKey
)
{
auto verifier = libzcash::ProofVerifier::Strict();
bool phgrPassed = jsdescs[0].Verify(js, verifier, joinSplitPubKey);
bool grothPassed = jsdescs[1].Verify(js, verifier, joinSplitPubKey);
return phgrPassed && grothPassed;
}
void test_full_api(ZCJoinSplit* js)
{
// Create verification context.
auto verifier = libzcash::ProofVerifier::Strict();
// The recipient's information.
SpendingKey recipient_key = SpendingKey::random();
PaymentAddress recipient_addr = recipient_key.address();
SproutSpendingKey recipient_key = SproutSpendingKey::random();
SproutPaymentAddress recipient_addr = recipient_key.address();
// Create the commitment tree
ZCIncrementalMerkleTree tree;
SproutMerkleTree tree;
// Set up a JoinSplit description
uint256 ephemeralKey;
uint256 randomSeed;
uint64_t vpub_old = 10;
uint64_t vpub_new = 0;
uint256 pubKeyHash = random_uint256();
boost::array<uint256, 2> macs;
boost::array<uint256, 2> nullifiers;
boost::array<uint256, 2> commitments;
uint256 joinSplitPubKey = random_uint256();
uint256 rt = tree.root();
boost::array<ZCNoteEncryption::Ciphertext, 2> ciphertexts;
ZCProof proof;
SproutProofs jsdescs;
{
boost::array<JSInput, 2> inputs = {
std::array<JSInput, 2> inputs = {
JSInput(), // dummy input
JSInput() // dummy input
};
boost::array<JSOutput, 2> outputs = {
std::array<JSOutput, 2> outputs = {
JSOutput(recipient_addr, 10),
JSOutput() // dummy output
};
boost::array<Note, 2> output_notes;
std::array<SproutNote, 2> output_notes;
// Perform the proof
proof = js->prove(
// Perform the proofs
jsdescs = makeSproutProofs(
*js,
inputs,
outputs,
output_notes,
ciphertexts,
ephemeralKey,
pubKeyHash,
randomSeed,
macs,
nullifiers,
commitments,
joinSplitPubKey,
vpub_old,
vpub_new,
rt
);
}
// Verify the transaction:
ASSERT_TRUE(js->verify(
proof,
verifier,
pubKeyHash,
randomSeed,
macs,
nullifiers,
commitments,
vpub_old,
vpub_new,
rt
));
// Recipient should decrypt
// Now the recipient should spend the money again
auto h_sig = js->h_sig(randomSeed, nullifiers, pubKeyHash);
ZCNoteDecryption decryptor(recipient_key.receiving_key());
auto note_pt = NotePlaintext::decrypt(
decryptor,
ciphertexts[0],
ephemeralKey,
h_sig,
0
);
auto decrypted_note = note_pt.note(recipient_addr);
ASSERT_TRUE(decrypted_note.value == 10);
// Insert the commitments from the last tx into the tree
tree.append(commitments[0]);
auto witness_recipient = tree.witness();
tree.append(commitments[1]);
witness_recipient.append(commitments[1]);
vpub_old = 0;
vpub_new = 1;
rt = tree.root();
pubKeyHash = random_uint256();
// Verify both PHGR and Groth Proof:
ASSERT_TRUE(verifySproutProofs(*js, jsdescs, joinSplitPubKey));
// Run tests using both phgr and groth as basis for field values
for (auto jsdesc : jsdescs)
{
boost::array<JSInput, 2> inputs = {
JSInput(), // dummy input
JSInput(witness_recipient, decrypted_note, recipient_key)
};
SproutMerkleTree tree;
SproutProofs jsdescs2;
// Recipient should decrypt
// Now the recipient should spend the money again
auto h_sig = js->h_sig(jsdesc.randomSeed, jsdesc.nullifiers, joinSplitPubKey);
ZCNoteDecryption decryptor(recipient_key.receiving_key());
SpendingKey second_recipient = SpendingKey::random();
PaymentAddress second_addr = second_recipient.address();
boost::array<JSOutput, 2> outputs = {
JSOutput(second_addr, 9),
JSOutput() // dummy output
};
boost::array<Note, 2> output_notes;
// Perform the proof
proof = js->prove(
inputs,
outputs,
output_notes,
ciphertexts,
ephemeralKey,
pubKeyHash,
randomSeed,
macs,
nullifiers,
commitments,
vpub_old,
vpub_new,
rt
auto note_pt = SproutNotePlaintext::decrypt(
decryptor,
jsdesc.ciphertexts[0],
jsdesc.ephemeralKey,
h_sig,
0
);
}
// Verify the transaction:
ASSERT_TRUE(js->verify(
proof,
verifier,
pubKeyHash,
randomSeed,
macs,
nullifiers,
commitments,
vpub_old,
vpub_new,
rt
));
auto decrypted_note = note_pt.note(recipient_addr);
ASSERT_TRUE(decrypted_note.value() == 10);
// Insert the commitments from the last tx into the tree
tree.append(jsdesc.commitments[0]);
auto witness_recipient = tree.witness();
tree.append(jsdesc.commitments[1]);
witness_recipient.append(jsdesc.commitments[1]);
vpub_old = 0;
vpub_new = 1;
rt = tree.root();
auto joinSplitPubKey2 = random_uint256();
{
std::array<JSInput, 2> inputs = {
JSInput(), // dummy input
JSInput(witness_recipient, decrypted_note, recipient_key)
};
SproutSpendingKey second_recipient = SproutSpendingKey::random();
SproutPaymentAddress second_addr = second_recipient.address();
std::array<JSOutput, 2> outputs = {
JSOutput(second_addr, 9),
JSOutput() // dummy output
};
std::array<SproutNote, 2> output_notes;
// Perform the proofs
jsdescs2 = makeSproutProofs(
*js,
inputs,
outputs,
joinSplitPubKey2,
vpub_old,
vpub_new,
rt
);
}
// Verify both PHGR and Groth Proof:
ASSERT_TRUE(verifySproutProofs(*js, jsdescs2, joinSplitPubKey2));
}
}
// Invokes the API (but does not compute a proof)
// to test exceptions
void invokeAPI(
ZCJoinSplit* js,
const boost::array<JSInput, 2>& inputs,
const boost::array<JSOutput, 2>& outputs,
const std::array<JSInput, 2>& inputs,
const std::array<JSOutput, 2>& outputs,
uint64_t vpub_old,
uint64_t vpub_new,
const uint256& rt
) {
uint256 ephemeralKey;
uint256 randomSeed;
uint256 pubKeyHash = random_uint256();
boost::array<uint256, 2> macs;
boost::array<uint256, 2> nullifiers;
boost::array<uint256, 2> commitments;
boost::array<ZCNoteEncryption::Ciphertext, 2> ciphertexts;
uint256 joinSplitPubKey = random_uint256();
std::array<uint256, 2> macs;
std::array<uint256, 2> nullifiers;
std::array<uint256, 2> commitments;
std::array<ZCNoteEncryption::Ciphertext, 2> ciphertexts;
boost::array<Note, 2> output_notes;
std::array<SproutNote, 2> output_notes;
ZCProof proof = js->prove(
// PHGR
SproutProof proof = js->prove(
false,
inputs,
outputs,
output_notes,
ciphertexts,
ephemeralKey,
pubKeyHash,
joinSplitPubKey,
randomSeed,
macs,
nullifiers,
commitments,
vpub_old,
vpub_new,
rt,
false
);
// Groth
proof = js->prove(
true,
inputs,
outputs,
output_notes,
ciphertexts,
ephemeralKey,
joinSplitPubKey,
randomSeed,
macs,
nullifiers,
@@ -202,8 +232,8 @@ void invokeAPI(
void invokeAPIFailure(
ZCJoinSplit* js,
const boost::array<JSInput, 2>& inputs,
const boost::array<JSOutput, 2>& outputs,
const std::array<JSInput, 2>& inputs,
const std::array<JSOutput, 2>& outputs,
uint64_t vpub_old,
uint64_t vpub_new,
const uint256& rt,
@@ -228,9 +258,9 @@ TEST(joinsplit, h_sig)
import pyblake2
import binascii
def hSig(randomSeed, nf1, nf2, pubKeyHash):
def hSig(randomSeed, nf1, nf2, joinSplitPubKey):
return pyblake2.blake2b(
data=(randomSeed + nf1 + nf2 + pubKeyHash),
data=(randomSeed + nf1 + nf2 + joinSplitPubKey),
digest_size=32,
person=b"ZcashComputehSig"
).digest()
@@ -297,12 +327,12 @@ for test_input in TEST_VECTORS:
void increment_note_witnesses(
const uint256& element,
std::vector<ZCIncrementalWitness>& witnesses,
ZCIncrementalMerkleTree& tree
std::vector<SproutWitness>& witnesses,
SproutMerkleTree& tree
)
{
tree.append(element);
for (ZCIncrementalWitness& w : witnesses) {
for (SproutWitness& w : witnesses) {
w.append(element);
}
witnesses.push_back(tree.witness());
@@ -311,20 +341,20 @@ void increment_note_witnesses(
TEST(joinsplit, full_api_test)
{
{
std::vector<ZCIncrementalWitness> witnesses;
ZCIncrementalMerkleTree tree;
std::vector<SproutWitness> witnesses;
SproutMerkleTree tree;
increment_note_witnesses(uint256(), witnesses, tree);
SpendingKey sk = SpendingKey::random();
PaymentAddress addr = sk.address();
Note note1(addr.a_pk, 100, random_uint256(), random_uint256());
SproutSpendingKey sk = SproutSpendingKey::random();
SproutPaymentAddress addr = sk.address();
SproutNote note1(addr.a_pk, 100, random_uint256(), random_uint256());
increment_note_witnesses(note1.cm(), witnesses, tree);
Note note2(addr.a_pk, 100, random_uint256(), random_uint256());
SproutNote note2(addr.a_pk, 100, random_uint256(), random_uint256());
increment_note_witnesses(note2.cm(), witnesses, tree);
Note note3(addr.a_pk, 2100000000000001, random_uint256(), random_uint256());
SproutNote note3(addr.a_pk, 2100000000000001, random_uint256(), random_uint256());
increment_note_witnesses(note3.cm(), witnesses, tree);
Note note4(addr.a_pk, 1900000000000000, random_uint256(), random_uint256());
SproutNote note4(addr.a_pk, 1900000000000000, random_uint256(), random_uint256());
increment_note_witnesses(note4.cm(), witnesses, tree);
Note note5(addr.a_pk, 1900000000000000, random_uint256(), random_uint256());
SproutNote note5(addr.a_pk, 1900000000000000, random_uint256(), random_uint256());
increment_note_witnesses(note5.cm(), witnesses, tree);
// Should work
@@ -419,7 +449,7 @@ TEST(joinsplit, full_api_test)
// Wrong secret key
invokeAPIFailure(params,
{
JSInput(witnesses[1], note1, SpendingKey::random()),
JSInput(witnesses[1], note1, SproutSpendingKey::random()),
JSInput()
},
{
@@ -516,34 +546,71 @@ TEST(joinsplit, note_plaintexts)
uint256 a_pk = PRF_addr_a_pk(a_sk);
uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk);
uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc);
PaymentAddress addr_pk(a_pk, pk_enc);
SproutPaymentAddress addr_pk(a_pk, pk_enc);
uint256 h_sig;
ZCNoteEncryption encryptor(h_sig);
uint256 epk = encryptor.get_epk();
Note note(a_pk,
SproutNote note(a_pk,
1945813,
random_uint256(),
random_uint256()
);
boost::array<unsigned char, ZC_MEMO_SIZE> memo;
std::array<unsigned char, ZC_MEMO_SIZE> memo;
NotePlaintext note_pt(note, memo);
SproutNotePlaintext note_pt(note, memo);
ZCNoteEncryption::Ciphertext ct = note_pt.encrypt(encryptor, pk_enc);
ZCNoteDecryption decryptor(sk_enc);
auto decrypted = NotePlaintext::decrypt(decryptor, ct, epk, h_sig, 0);
auto decrypted = SproutNotePlaintext::decrypt(decryptor, ct, epk, h_sig, 0);
auto decrypted_note = decrypted.note(addr_pk);
ASSERT_TRUE(decrypted_note.a_pk == note.a_pk);
ASSERT_TRUE(decrypted_note.rho == note.rho);
ASSERT_TRUE(decrypted_note.r == note.r);
ASSERT_TRUE(decrypted_note.value == note.value);
ASSERT_TRUE(decrypted_note.value() == note.value());
ASSERT_TRUE(decrypted.memo == note_pt.memo);
ASSERT_TRUE(decrypted.memo() == note_pt.memo());
// Check memo() returns by reference, not return by value, for use cases such as:
// std::string data(plaintext.memo().begin(), plaintext.memo().end());
ASSERT_TRUE(decrypted.memo().data() == decrypted.memo().data());
// Check serialization of note plaintext
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
ss << note_pt;
SproutNotePlaintext note_pt2;
ss >> note_pt2;
ASSERT_EQ(note_pt.value(), note.value());
ASSERT_EQ(note_pt.value(), note_pt2.value());
ASSERT_EQ(note_pt.memo(), note_pt2.memo());
ASSERT_EQ(note_pt.rho, note_pt2.rho);
ASSERT_EQ(note_pt.r, note_pt2.r);
}
TEST(joinsplit, note_class)
{
uint252 a_sk = uint252(uint256S("f6da8716682d600f74fc16bd0187faad6a26b4aa4c24d5c055b216d94516840e"));
uint256 a_pk = PRF_addr_a_pk(a_sk);
uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk);
uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc);
SproutPaymentAddress addr_pk(a_pk, pk_enc);
SproutNote note(a_pk,
1945813,
random_uint256(),
random_uint256());
SproutNote clone = note;
ASSERT_NE(&note, &clone);
ASSERT_EQ(note.value(), clone.value());
ASSERT_EQ(note.cm(), clone.cm());
ASSERT_EQ(note.rho, clone.rho);
ASSERT_EQ(note.r, clone.r);
ASSERT_EQ(note.a_pk, clone.a_pk);
}

47
src/gtest/test_keys.cpp Normal file
View File

@@ -0,0 +1,47 @@
#include <chainparams.h>
#include <key_io.h>
#include <zcash/Address.hpp>
#include <zcash/zip32.h>
#include <gtest/gtest.h>
TEST(Keys, DISABLED_EncodeAndDecodeSapling)
{
SelectParams(CBaseChainParams::MAIN);
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
HDSeed seed(rawSeed);
auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);
for (uint32_t i = 0; i < 1000; i++) {
auto sk = m.Derive(i);
{
std::string sk_string = EncodeSpendingKey(sk);
EXPECT_EQ(
sk_string.substr(0, 24),
Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY));
auto spendingkey2 = DecodeSpendingKey(sk_string);
EXPECT_TRUE(IsValidSpendingKey(spendingkey2));
ASSERT_TRUE(boost::get<libzcash::SaplingExtendedSpendingKey>(&spendingkey2) != nullptr);
auto sk2 = boost::get<libzcash::SaplingExtendedSpendingKey>(spendingkey2);
EXPECT_EQ(sk, sk2);
}
{
auto addr = sk.DefaultAddress();
std::string addr_string = EncodePaymentAddress(addr);
EXPECT_EQ(
addr_string.substr(0, 2),
Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS));
auto paymentaddr2 = DecodePaymentAddress(addr_string);
EXPECT_TRUE(IsValidPaymentAddress(paymentaddr2));
ASSERT_TRUE(boost::get<libzcash::SaplingPaymentAddress>(&paymentaddr2) != nullptr);
auto addr2 = boost::get<libzcash::SaplingPaymentAddress>(paymentaddr2);
EXPECT_EQ(addr, addr2);
}
}
}

View File

@@ -1,33 +1,121 @@
#include <gtest/gtest.h>
#include "test/data/sapling_key_components.json.h"
#include "keystore.h"
#include "random.h"
#ifdef ENABLE_WALLET
#include "wallet/crypter.h"
#endif
#include "zcash/Address.hpp"
#include "zcash/zip32.h"
#include "json_test_vectors.h"
#define MAKE_STRING(x) std::string((x), (x)+sizeof(x))
TEST(keystore_tests, StoreAndRetrieveHDSeed) {
CBasicKeyStore keyStore;
HDSeed seedOut;
// When we haven't set a seed, we shouldn't get one
EXPECT_FALSE(keyStore.HaveHDSeed());
EXPECT_FALSE(keyStore.GetHDSeed(seedOut));
// Generate a random seed
auto seed = HDSeed::Random();
// We should be able to set and retrieve the seed
ASSERT_TRUE(keyStore.SetHDSeed(seed));
EXPECT_TRUE(keyStore.HaveHDSeed());
ASSERT_TRUE(keyStore.GetHDSeed(seedOut));
EXPECT_EQ(seed, seedOut);
// Generate another random seed
auto seed2 = HDSeed::Random();
EXPECT_NE(seed, seed2);
// We should not be able to set and retrieve a different seed
EXPECT_FALSE(keyStore.SetHDSeed(seed2));
ASSERT_TRUE(keyStore.GetHDSeed(seedOut));
EXPECT_EQ(seed, seedOut);
}
TEST(keystore_tests, sapling_keys) {
// ["sk, ask, nsk, ovk, ak, nk, ivk, default_d, default_pk_d, note_v, note_r, note_cm, note_pos, note_nf"],
UniValue sapling_keys = read_json(MAKE_STRING(json_tests::sapling_key_components));
// Skipping over comments in sapling_key_components.json file
for (size_t i = 2; i < 12; i++) {
uint256 skSeed, ask, nsk, ovk, ak, nk, ivk;
skSeed.SetHex(sapling_keys[i][0].getValStr());
ask.SetHex(sapling_keys[i][1].getValStr());
nsk.SetHex(sapling_keys[i][2].getValStr());
ovk.SetHex(sapling_keys[i][3].getValStr());
ak.SetHex(sapling_keys[i][4].getValStr());
nk.SetHex(sapling_keys[i][5].getValStr());
ivk.SetHex(sapling_keys[i][6].getValStr());
libzcash::diversifier_t default_d;
std::copy_n(ParseHex(sapling_keys[i][7].getValStr()).begin(), 11, default_d.begin());
uint256 default_pk_d;
default_pk_d.SetHex(sapling_keys[i][8].getValStr());
auto sk = libzcash::SaplingSpendingKey(skSeed);
// Check that expanded spending key from primitives and from sk are the same
auto exp_sk_2 = libzcash::SaplingExpandedSpendingKey(ask, nsk, ovk);
auto exp_sk = sk.expanded_spending_key();
EXPECT_EQ(exp_sk, exp_sk_2);
// Check that full viewing key derived from sk and expanded sk are the same
auto full_viewing_key = sk.full_viewing_key();
EXPECT_EQ(full_viewing_key, exp_sk.full_viewing_key());
// Check that full viewing key from primitives and from sk are the same
auto full_viewing_key_2 = libzcash::SaplingFullViewingKey(ak, nk, ovk);
EXPECT_EQ(full_viewing_key, full_viewing_key_2);
// Check that incoming viewing key from primitives and from sk are the same
auto in_viewing_key = full_viewing_key.in_viewing_key();
auto in_viewing_key_2 = libzcash::SaplingIncomingViewingKey(ivk);
EXPECT_EQ(in_viewing_key, in_viewing_key_2);
// Check that the default address from primitives and from sk method are the same
auto default_addr = sk.default_address();
auto addrOpt2 = in_viewing_key.address(default_d);
EXPECT_TRUE(addrOpt2);
auto default_addr_2 = addrOpt2.value();
EXPECT_EQ(default_addr, default_addr_2);
auto default_addr_3 = libzcash::SaplingPaymentAddress(default_d, default_pk_d);
EXPECT_EQ(default_addr_2, default_addr_3);
EXPECT_EQ(default_addr, default_addr_3);
}
}
TEST(keystore_tests, store_and_retrieve_spending_key) {
CBasicKeyStore keyStore;
libzcash::SpendingKey skOut;
libzcash::SproutSpendingKey skOut;
std::set<libzcash::PaymentAddress> addrs;
keyStore.GetPaymentAddresses(addrs);
std::set<libzcash::SproutPaymentAddress> addrs;
keyStore.GetSproutPaymentAddresses(addrs);
EXPECT_EQ(0, addrs.size());
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto addr = sk.address();
// Sanity-check: we can't get a key we haven't added
EXPECT_FALSE(keyStore.HaveSpendingKey(addr));
EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut));
EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr));
EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut));
keyStore.AddSpendingKey(sk);
EXPECT_TRUE(keyStore.HaveSpendingKey(addr));
EXPECT_TRUE(keyStore.GetSpendingKey(addr, skOut));
keyStore.AddSproutSpendingKey(sk);
EXPECT_TRUE(keyStore.HaveSproutSpendingKey(addr));
EXPECT_TRUE(keyStore.GetSproutSpendingKey(addr, skOut));
EXPECT_EQ(sk, skOut);
keyStore.GetPaymentAddresses(addrs);
keyStore.GetSproutPaymentAddresses(addrs);
EXPECT_EQ(1, addrs.size());
EXPECT_EQ(1, addrs.count(addr));
}
@@ -36,48 +124,48 @@ TEST(keystore_tests, store_and_retrieve_note_decryptor) {
CBasicKeyStore keyStore;
ZCNoteDecryption decOut;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto addr = sk.address();
EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut));
keyStore.AddSpendingKey(sk);
keyStore.AddSproutSpendingKey(sk);
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
}
TEST(keystore_tests, StoreAndRetrieveViewingKey) {
CBasicKeyStore keyStore;
libzcash::ViewingKey vkOut;
libzcash::SpendingKey skOut;
libzcash::SproutViewingKey vkOut;
libzcash::SproutSpendingKey skOut;
ZCNoteDecryption decOut;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto vk = sk.viewing_key();
auto addr = sk.address();
// Sanity-check: we can't get a viewing key we haven't added
EXPECT_FALSE(keyStore.HaveViewingKey(addr));
EXPECT_FALSE(keyStore.GetViewingKey(addr, vkOut));
EXPECT_FALSE(keyStore.HaveSproutViewingKey(addr));
EXPECT_FALSE(keyStore.GetSproutViewingKey(addr, vkOut));
// and we shouldn't have a spending key or decryptor either
EXPECT_FALSE(keyStore.HaveSpendingKey(addr));
EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut));
EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr));
EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut));
EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut));
// and we can't find it in our list of addresses
std::set<libzcash::PaymentAddress> addresses;
keyStore.GetPaymentAddresses(addresses);
std::set<libzcash::SproutPaymentAddress> addresses;
keyStore.GetSproutPaymentAddresses(addresses);
EXPECT_FALSE(addresses.count(addr));
keyStore.AddViewingKey(vk);
EXPECT_TRUE(keyStore.HaveViewingKey(addr));
EXPECT_TRUE(keyStore.GetViewingKey(addr, vkOut));
keyStore.AddSproutViewingKey(vk);
EXPECT_TRUE(keyStore.HaveSproutViewingKey(addr));
EXPECT_TRUE(keyStore.GetSproutViewingKey(addr, vkOut));
EXPECT_EQ(vk, vkOut);
// We should still not have the spending key...
EXPECT_FALSE(keyStore.HaveSpendingKey(addr));
EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut));
EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr));
EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut));
// ... but we should have a decryptor
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
@@ -85,16 +173,16 @@ TEST(keystore_tests, StoreAndRetrieveViewingKey) {
// ... and we should find it in our list of addresses
addresses.clear();
keyStore.GetPaymentAddresses(addresses);
keyStore.GetSproutPaymentAddresses(addresses);
EXPECT_TRUE(addresses.count(addr));
keyStore.RemoveViewingKey(vk);
EXPECT_FALSE(keyStore.HaveViewingKey(addr));
EXPECT_FALSE(keyStore.GetViewingKey(addr, vkOut));
EXPECT_FALSE(keyStore.HaveSpendingKey(addr));
EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut));
keyStore.RemoveSproutViewingKey(vk);
EXPECT_FALSE(keyStore.HaveSproutViewingKey(addr));
EXPECT_FALSE(keyStore.GetSproutViewingKey(addr, vkOut));
EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr));
EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut));
addresses.clear();
keyStore.GetPaymentAddresses(addresses);
keyStore.GetSproutPaymentAddresses(addresses);
EXPECT_FALSE(addresses.count(addr));
// We still have a decryptor because those are cached in memory
@@ -103,6 +191,49 @@ TEST(keystore_tests, StoreAndRetrieveViewingKey) {
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
}
// Sapling
TEST(keystore_tests, StoreAndRetrieveSaplingSpendingKey) {
CBasicKeyStore keyStore;
libzcash::SaplingExtendedSpendingKey skOut;
libzcash::SaplingFullViewingKey fvkOut;
libzcash::SaplingIncomingViewingKey ivkOut;
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
HDSeed seed(rawSeed);
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
auto fvk = sk.expsk.full_viewing_key();
auto ivk = fvk.in_viewing_key();
auto addr = sk.DefaultAddress();
// Sanity-check: we can't get a key we haven't added
EXPECT_FALSE(keyStore.HaveSaplingSpendingKey(fvk));
EXPECT_FALSE(keyStore.GetSaplingSpendingKey(fvk, skOut));
// Sanity-check: we can't get a full viewing key we haven't added
EXPECT_FALSE(keyStore.HaveSaplingFullViewingKey(ivk));
EXPECT_FALSE(keyStore.GetSaplingFullViewingKey(ivk, fvkOut));
// Sanity-check: we can't get an incoming viewing key we haven't added
EXPECT_FALSE(keyStore.HaveSaplingIncomingViewingKey(addr));
EXPECT_FALSE(keyStore.GetSaplingIncomingViewingKey(addr, ivkOut));
// If we don't specify the default address, that mapping isn't created
keyStore.AddSaplingSpendingKey(sk);
EXPECT_TRUE(keyStore.HaveSaplingSpendingKey(fvk));
EXPECT_TRUE(keyStore.HaveSaplingFullViewingKey(ivk));
EXPECT_FALSE(keyStore.HaveSaplingIncomingViewingKey(addr));
// When we specify the default address, we get the full mapping
keyStore.AddSaplingSpendingKey(sk, addr);
EXPECT_TRUE(keyStore.HaveSaplingSpendingKey(fvk));
EXPECT_TRUE(keyStore.GetSaplingSpendingKey(fvk, skOut));
EXPECT_TRUE(keyStore.HaveSaplingFullViewingKey(ivk));
EXPECT_TRUE(keyStore.GetSaplingFullViewingKey(ivk, fvkOut));
EXPECT_TRUE(keyStore.HaveSaplingIncomingViewingKey(addr));
EXPECT_TRUE(keyStore.GetSaplingIncomingViewingKey(addr, ivkOut));
EXPECT_EQ(sk, skOut);
EXPECT_EQ(fvk, fvkOut);
EXPECT_EQ(ivk, ivkOut);
}
#ifdef ENABLE_WALLET
class TestCCryptoKeyStore : public CCryptoKeyStore
{
@@ -111,29 +242,89 @@ public:
bool Unlock(const CKeyingMaterial& vMasterKeyIn) { return CCryptoKeyStore::Unlock(vMasterKeyIn); }
};
TEST(keystore_tests, StoreAndRetrieveHDSeedInEncryptedStore) {
TestCCryptoKeyStore keyStore;
CKeyingMaterial vMasterKey(32, 0);
GetRandBytes(vMasterKey.data(), 32);
HDSeed seedOut;
// 1) Test adding a seed to an unencrypted key store, then encrypting it
auto seed = HDSeed::Random();
EXPECT_FALSE(keyStore.HaveHDSeed());
EXPECT_FALSE(keyStore.GetHDSeed(seedOut));
ASSERT_TRUE(keyStore.SetHDSeed(seed));
EXPECT_TRUE(keyStore.HaveHDSeed());
ASSERT_TRUE(keyStore.GetHDSeed(seedOut));
EXPECT_EQ(seed, seedOut);
ASSERT_TRUE(keyStore.EncryptKeys(vMasterKey));
EXPECT_FALSE(keyStore.GetHDSeed(seedOut));
// Unlocking with a random key should fail
CKeyingMaterial vRandomKey(32, 0);
GetRandBytes(vRandomKey.data(), 32);
EXPECT_FALSE(keyStore.Unlock(vRandomKey));
// Unlocking with a slightly-modified vMasterKey should fail
CKeyingMaterial vModifiedKey(vMasterKey);
vModifiedKey[0] += 1;
EXPECT_FALSE(keyStore.Unlock(vModifiedKey));
// Unlocking with vMasterKey should succeed
ASSERT_TRUE(keyStore.Unlock(vMasterKey));
ASSERT_TRUE(keyStore.GetHDSeed(seedOut));
EXPECT_EQ(seed, seedOut);
// 2) Test replacing the seed in an already-encrypted key store fails
auto seed2 = HDSeed::Random();
EXPECT_FALSE(keyStore.SetHDSeed(seed2));
EXPECT_TRUE(keyStore.HaveHDSeed());
ASSERT_TRUE(keyStore.GetHDSeed(seedOut));
EXPECT_EQ(seed, seedOut);
// 3) Test adding a new seed to an already-encrypted key store
TestCCryptoKeyStore keyStore2;
// Add a Sprout address so the wallet has something to test when decrypting
ASSERT_TRUE(keyStore2.AddSproutSpendingKey(libzcash::SproutSpendingKey::random()));
ASSERT_TRUE(keyStore2.EncryptKeys(vMasterKey));
ASSERT_TRUE(keyStore2.Unlock(vMasterKey));
EXPECT_FALSE(keyStore2.HaveHDSeed());
EXPECT_FALSE(keyStore2.GetHDSeed(seedOut));
auto seed3 = HDSeed::Random();
ASSERT_TRUE(keyStore2.SetHDSeed(seed3));
EXPECT_TRUE(keyStore2.HaveHDSeed());
ASSERT_TRUE(keyStore2.GetHDSeed(seedOut));
EXPECT_EQ(seed3, seedOut);
}
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;
libzcash::SproutSpendingKey keyOut;
ZCNoteDecryption decOut;
std::set<libzcash::PaymentAddress> addrs;
std::set<libzcash::SproutPaymentAddress> addrs;
// 1) Test adding a key to an unencrypted key store, then encrypting it
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::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));
keyStore.AddSproutSpendingKey(sk);
ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr));
ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr, keyOut));
ASSERT_EQ(sk, keyOut);
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
ASSERT_TRUE(keyStore.EncryptKeys(vMasterKey));
ASSERT_TRUE(keyStore.HaveSpendingKey(addr));
ASSERT_FALSE(keyStore.GetSpendingKey(addr, keyOut));
ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr));
ASSERT_FALSE(keyStore.GetSproutSpendingKey(addr, keyOut));
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
@@ -149,38 +340,38 @@ TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) {
// Unlocking with vMasterKey should succeed
ASSERT_TRUE(keyStore.Unlock(vMasterKey));
ASSERT_TRUE(keyStore.GetSpendingKey(addr, keyOut));
ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr, keyOut));
ASSERT_EQ(sk, keyOut);
keyStore.GetPaymentAddresses(addrs);
keyStore.GetSproutPaymentAddresses(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 sk2 = libzcash::SproutSpendingKey::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));
keyStore.AddSproutSpendingKey(sk2);
ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr2));
ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr2, keyOut));
ASSERT_EQ(sk2, keyOut);
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut);
ASSERT_TRUE(keyStore.Lock());
ASSERT_TRUE(keyStore.HaveSpendingKey(addr2));
ASSERT_FALSE(keyStore.GetSpendingKey(addr2, keyOut));
ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr2));
ASSERT_FALSE(keyStore.GetSproutSpendingKey(addr2, keyOut));
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut);
ASSERT_TRUE(keyStore.Unlock(vMasterKey));
ASSERT_TRUE(keyStore.GetSpendingKey(addr2, keyOut));
ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr2, keyOut));
ASSERT_EQ(sk2, keyOut);
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut);
keyStore.GetPaymentAddresses(addrs);
keyStore.GetSproutPaymentAddresses(addrs);
ASSERT_EQ(2, addrs.size());
ASSERT_EQ(1, addrs.count(addr));
ASSERT_EQ(1, addrs.count(addr2));

View File

@@ -19,11 +19,15 @@ class FakeCoinsViewDB : public CCoinsView {
public:
FakeCoinsViewDB() {}
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf) const {
bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf, ShieldedType type) const {
return false;
}
@@ -47,16 +51,19 @@ public:
return a;
}
uint256 GetBestAnchor() const {
uint256 GetBestAnchor(ShieldedType type) const {
uint256 a;
return a;
}
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) {
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CAnchorsSaplingMap &mapSaplingAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers) {
return false;
}
@@ -96,7 +103,7 @@ TEST(Mempool, PriorityStatsDoNotCrash) {
}
TEST(Mempool, TxInputLimit) {
SelectParams(CBaseChainParams::TESTNET);
SelectParams(CBaseChainParams::REGTEST);
CTxMemPool pool(::minRelayTxFee);
bool missingInputs;
@@ -133,13 +140,30 @@ TEST(Mempool, TxInputLimit) {
// The -mempooltxinputlimit check doesn't set a reason
EXPECT_EQ(state3.GetRejectReason(), "");
// Clear the limit
mapArgs.erase("-mempooltxinputlimit");
// Activate Overwinter
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
// Check it no longer fails due to exceeding the limit
CValidationState state4;
EXPECT_FALSE(AcceptToMemoryPool(pool, state4, tx3, false, &missingInputs));
EXPECT_EQ(state4.GetRejectReason(), "bad-txns-version-too-low");
// Deactivate Overwinter
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
// Check it now fails due to exceeding the limit
CValidationState state5;
EXPECT_FALSE(AcceptToMemoryPool(pool, state5, tx3, false, &missingInputs));
// The -mempooltxinputlimit check doesn't set a reason
EXPECT_EQ(state5.GetRejectReason(), "");
// Clear the limit
mapArgs.erase("-mempooltxinputlimit");
// Check it no longer fails due to exceeding the limit
CValidationState state6;
EXPECT_FALSE(AcceptToMemoryPool(pool, state6, tx3, false, &missingInputs));
EXPECT_EQ(state6.GetRejectReason(), "bad-txns-version-too-low");
}
// Valid overwinter v3 format tx gets rejected because overwinter hasn't activated yet.
@@ -152,7 +176,7 @@ TEST(Mempool, OverwinterNotActiveYet) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0); // no joinsplits
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersion = OVERWINTER_TX_VERSION;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
CValidationState state1;
@@ -224,7 +248,7 @@ TEST(Mempool, SproutNegativeVersionTxWhenOverwinterActive) {
mtx.vjoinsplit.resize(0); // no joinsplits
mtx.fOverwintered = false;
// A Sprout transaction with version -3 is created using Sprout code (as found in Zcashd <= 1.0.14).
// A Sprout transaction with version -3 is created using Sprout code (as found in zcashd <= 1.0.14).
// First four bytes of transaction, parsed as an uint32_t, has the value: 0xfffffffd
// This test simulates an Overwinter node receiving this transaction, but incorrectly deserializing the
// transaction due to a (pretend) bug of not detecting the most significant bit, which leads
@@ -242,7 +266,7 @@ TEST(Mempool, SproutNegativeVersionTxWhenOverwinterActive) {
EXPECT_EQ(state1.GetRejectReason(), "bad-txns-version-too-low");
}
// A Sprout transaction with version -3 created using Overwinter code (as found in Zcashd >= 1.0.15).
// A Sprout transaction with version -3 created using Overwinter code (as found in zcashd >= 1.0.15).
// First four bytes of transaction, parsed as an uint32_t, has the value: 0x80000003
// This test simulates the same pretend bug described above.
// The resulting Sprout tx with nVersion -2147483645 should be rejected by the Overwinter node's mempool.

View File

@@ -7,6 +7,13 @@
#include "test/data/merkle_path.json.h"
#include "test/data/merkle_commitments.json.h"
#include "test/data/merkle_roots_sapling.json.h"
#include "test/data/merkle_roots_empty_sapling.json.h"
#include "test/data/merkle_serialization_sapling.json.h"
#include "test/data/merkle_witness_serialization_sapling.json.h"
#include "test/data/merkle_path_sapling.json.h"
#include "test/data/merkle_commitments_sapling.json.h"
#include <iostream>
#include <stdexcept>
@@ -32,7 +39,7 @@ using namespace std;
using namespace libsnark;
template<>
void expect_deser_same(const ZCTestingIncrementalWitness& expected)
void expect_deser_same(const SproutTestingWitness& expected)
{
// Cannot check this; IncrementalWitness cannot be
// deserialized because it can only be constructed by
@@ -40,16 +47,6 @@ void expect_deser_same(const ZCTestingIncrementalWitness& expected)
// canonical serialized representation.
}
template<>
void expect_deser_same(const libzcash::MerklePath& expected)
{
// This deserialization check is pointless for MerklePath,
// since we only serialize it to check it against test
// vectors. See `expect_test_vector` for that. Also,
// it doesn't seem that vector<bool> can be properly
// deserialized by Bitcoin's serialization code.
}
template<typename A, typename B, typename C>
void expect_ser_test_vector(B& b, const C& c, const A& tree) {
expect_test_vector<B, C>(b, c);
@@ -61,7 +58,8 @@ void test_tree(
UniValue root_tests,
UniValue ser_tests,
UniValue witness_ser_tests,
UniValue path_tests
UniValue path_tests,
bool libsnark_test
)
{
size_t witness_ser_i = 0;
@@ -116,10 +114,9 @@ void test_tree(
ASSERT_THROW(wit.element(), std::runtime_error);
} else {
auto path = wit.path();
expect_test_vector(path_tests[path_i++], path);
{
expect_test_vector(path_tests[path_i++], path);
if (libsnark_test) {
typedef Fr<default_r1cs_ppzksnark_pp> FieldT;
protoboard<FieldT> pb;
@@ -146,7 +143,7 @@ void test_tree(
size_t path_index = convertVectorToInt(path.index);
commitment.bits.fill_with_bits(pb, bit_vector(commitment_bv));
positions.fill_with_bits_of_ulong(pb, path_index);
positions.fill_with_bits_of_uint64(pb, path_index);
authvars.generate_r1cs_witness(path_index, path.authentication_path);
auth.generate_r1cs_witness();
@@ -198,7 +195,31 @@ TEST(merkletree, vectors) {
UniValue path_tests = read_json(MAKE_STRING(json_tests::merkle_path));
UniValue commitment_tests = read_json(MAKE_STRING(json_tests::merkle_commitments));
test_tree<ZCTestingIncrementalMerkleTree, ZCTestingIncrementalWitness>(commitment_tests, root_tests, ser_tests, witness_ser_tests, path_tests);
test_tree<SproutTestingMerkleTree, SproutTestingWitness>(
commitment_tests,
root_tests,
ser_tests,
witness_ser_tests,
path_tests,
true
);
}
TEST(merkletree, SaplingVectors) {
UniValue root_tests = read_json(MAKE_STRING(json_tests::merkle_roots_sapling));
UniValue ser_tests = read_json(MAKE_STRING(json_tests::merkle_serialization_sapling));
UniValue witness_ser_tests = read_json(MAKE_STRING(json_tests::merkle_witness_serialization_sapling));
UniValue path_tests = read_json(MAKE_STRING(json_tests::merkle_path_sapling));
UniValue commitment_tests = read_json(MAKE_STRING(json_tests::merkle_commitments_sapling));
test_tree<SaplingTestingMerkleTree, SaplingTestingWitness>(
commitment_tests,
root_tests,
ser_tests,
witness_ser_tests,
path_tests,
false
);
}
TEST(merkletree, emptyroots) {
@@ -214,19 +235,41 @@ TEST(merkletree, emptyroots) {
ASSERT_TRUE(INCREMENTAL_MERKLE_TREE_DEPTH <= 64);
}
TEST(merkletree, EmptyrootsSapling) {
UniValue empty_roots = read_json(MAKE_STRING(json_tests::merkle_roots_empty_sapling));
libzcash::EmptyMerkleRoots<62, libzcash::PedersenHash> emptyroots;
for (size_t depth = 0; depth <= 62; depth++) {
expect_test_vector(empty_roots[depth], emptyroots.empty_root(depth));
}
// Double check that we're testing (at least) all the empty roots we'll use.
ASSERT_TRUE(INCREMENTAL_MERKLE_TREE_DEPTH <= 62);
}
TEST(merkletree, emptyroot) {
// This literal is the depth-20 empty tree root with the bytes reversed to
// account for the fact that uint256S() loads a big-endian representation of
// an integer which converted to little-endian internally.
uint256 expected = uint256S("59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7");
ASSERT_TRUE(ZCIncrementalMerkleTree::empty_root() == expected);
ASSERT_TRUE(SproutMerkleTree::empty_root() == expected);
}
TEST(merkletree, EmptyrootSapling) {
// This literal is the depth-20 empty tree root with the bytes reversed to
// account for the fact that uint256S() loads a big-endian representation of
// an integer which converted to little-endian internally.
uint256 expected = uint256S("3e49b5f954aa9d3545bc6c37744661eea48d7c34e3000d82b7f0010c30f4c2fb");
ASSERT_TRUE(SaplingMerkleTree::empty_root() == expected);
}
TEST(merkletree, deserializeInvalid) {
// attempt to deserialize a small tree from a serialized large tree
// (exceeds depth well-formedness check)
ZCIncrementalMerkleTree newTree;
SproutMerkleTree newTree;
for (size_t i = 0; i < 16; i++) {
newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c"));
@@ -237,7 +280,7 @@ TEST(merkletree, deserializeInvalid) {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << newTree;
ZCTestingIncrementalMerkleTree newTreeSmall;
SproutTestingMerkleTree newTreeSmall;
ASSERT_THROW({ss >> newTreeSmall;}, std::ios_base::failure);
}
@@ -249,7 +292,7 @@ TEST(merkletree, deserializeInvalid2) {
PROTOCOL_VERSION
);
ZCIncrementalMerkleTree tree;
SproutMerkleTree tree;
ASSERT_THROW(ss >> tree, std::ios_base::failure);
}
@@ -261,7 +304,7 @@ TEST(merkletree, deserializeInvalid3) {
PROTOCOL_VERSION
);
ZCIncrementalMerkleTree tree;
SproutMerkleTree tree;
ASSERT_THROW(ss >> tree, std::ios_base::failure);
}
@@ -273,15 +316,15 @@ TEST(merkletree, deserializeInvalid4) {
PROTOCOL_VERSION
);
ZCIncrementalMerkleTree tree;
SproutMerkleTree tree;
ASSERT_THROW(ss >> tree, std::ios_base::failure);
}
TEST(merkletree, testZeroElements) {
for (int start = 0; start < 20; start++) {
ZCIncrementalMerkleTree newTree;
SproutMerkleTree newTree;
ASSERT_TRUE(newTree.root() == ZCIncrementalMerkleTree::empty_root());
ASSERT_TRUE(newTree.root() == SproutMerkleTree::empty_root());
for (int i = start; i > 0; i--) {
newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c"));

View File

@@ -1,11 +1,15 @@
#include <gtest/gtest.h>
#include "sodium.h"
#include <array>
#include <stdexcept>
#include "zcash/Note.hpp"
#include "zcash/NoteEncryption.hpp"
#include "zcash/prf.h"
#include "zcash/Address.hpp"
#include "crypto/sha256.h"
#include "librustzcash.h"
class TestNoteDecryption : public ZCNoteDecryption {
public:
@@ -16,6 +20,327 @@ public:
}
};
TEST(noteencryption, NotePlaintext)
{
using namespace libzcash;
auto xsk = SaplingSpendingKey(uint256()).expanded_spending_key();
auto fvk = xsk.full_viewing_key();
auto ivk = fvk.in_viewing_key();
SaplingPaymentAddress addr = *ivk.address({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
std::array<unsigned char, ZC_MEMO_SIZE> memo;
for (size_t i = 0; i < ZC_MEMO_SIZE; i++) {
// Fill the message with dummy data
memo[i] = (unsigned char) i;
}
SaplingNote note(addr, 39393);
auto cmu_opt = note.cm();
if (!cmu_opt) {
FAIL();
}
uint256 cmu = cmu_opt.get();
SaplingNotePlaintext pt(note, memo);
auto res = pt.encrypt(addr.pk_d);
if (!res) {
FAIL();
}
auto enc = res.get();
auto ct = enc.first;
auto encryptor = enc.second;
auto epk = encryptor.get_epk();
// Try to decrypt with incorrect commitment
ASSERT_FALSE(SaplingNotePlaintext::decrypt(
ct,
ivk,
epk,
uint256()
));
// Try to decrypt with correct commitment
auto foo = SaplingNotePlaintext::decrypt(
ct,
ivk,
epk,
cmu
);
if (!foo) {
FAIL();
}
auto bar = foo.get();
ASSERT_TRUE(bar.value() == pt.value());
ASSERT_TRUE(bar.memo() == pt.memo());
ASSERT_TRUE(bar.d == pt.d);
ASSERT_TRUE(bar.rcm == pt.rcm);
auto foobar = bar.note(ivk);
if (!foobar) {
FAIL();
}
auto new_note = foobar.get();
ASSERT_TRUE(note.value() == new_note.value());
ASSERT_TRUE(note.d == new_note.d);
ASSERT_TRUE(note.pk_d == new_note.pk_d);
ASSERT_TRUE(note.r == new_note.r);
ASSERT_TRUE(note.cm() == new_note.cm());
SaplingOutgoingPlaintext out_pt;
out_pt.pk_d = note.pk_d;
out_pt.esk = encryptor.get_esk();
auto ovk = random_uint256();
auto cv = random_uint256();
auto cm = random_uint256();
auto out_ct = out_pt.encrypt(
ovk,
cv,
cm,
encryptor
);
auto decrypted_out_ct = out_pt.decrypt(
out_ct,
ovk,
cv,
cm,
encryptor.get_epk()
);
if (!decrypted_out_ct) {
FAIL();
}
auto decrypted_out_ct_unwrapped = decrypted_out_ct.get();
ASSERT_TRUE(decrypted_out_ct_unwrapped.pk_d == out_pt.pk_d);
ASSERT_TRUE(decrypted_out_ct_unwrapped.esk == out_pt.esk);
// Test sender won't accept invalid commitments
ASSERT_FALSE(
SaplingNotePlaintext::decrypt(
ct,
epk,
decrypted_out_ct_unwrapped.esk,
decrypted_out_ct_unwrapped.pk_d,
uint256()
)
);
// Test sender can decrypt the note ciphertext.
foo = SaplingNotePlaintext::decrypt(
ct,
epk,
decrypted_out_ct_unwrapped.esk,
decrypted_out_ct_unwrapped.pk_d,
cmu
);
if (!foo) {
FAIL();
}
bar = foo.get();
ASSERT_TRUE(bar.value() == pt.value());
ASSERT_TRUE(bar.memo() == pt.memo());
ASSERT_TRUE(bar.d == pt.d);
ASSERT_TRUE(bar.rcm == pt.rcm);
}
TEST(noteencryption, SaplingApi)
{
using namespace libzcash;
// Create recipient addresses
auto sk = SaplingSpendingKey(uint256()).expanded_spending_key();
auto vk = sk.full_viewing_key();
auto ivk = vk.in_viewing_key();
SaplingPaymentAddress pk_1 = *ivk.address({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
SaplingPaymentAddress pk_2 = *ivk.address({4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
// Blob of stuff we're encrypting
std::array<unsigned char, ZC_SAPLING_ENCPLAINTEXT_SIZE> message;
for (size_t i = 0; i < ZC_SAPLING_ENCPLAINTEXT_SIZE; i++) {
// Fill the message with dummy data
message[i] = (unsigned char) i;
}
std::array<unsigned char, ZC_SAPLING_OUTPLAINTEXT_SIZE> small_message;
for (size_t i = 0; i < ZC_SAPLING_OUTPLAINTEXT_SIZE; i++) {
// Fill the message with dummy data
small_message[i] = (unsigned char) i;
}
// Invalid diversifier
ASSERT_EQ(boost::none, SaplingNoteEncryption::FromDiversifier({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}));
// Encrypt to pk_1
auto enc = *SaplingNoteEncryption::FromDiversifier(pk_1.d);
auto ciphertext_1 = *enc.encrypt_to_recipient(
pk_1.pk_d,
message
);
auto epk_1 = enc.get_epk();
{
uint256 test_epk;
uint256 test_esk = enc.get_esk();
ASSERT_TRUE(librustzcash_sapling_ka_derivepublic(pk_1.d.begin(), test_esk.begin(), test_epk.begin()));
ASSERT_TRUE(test_epk == epk_1);
}
auto cv_1 = random_uint256();
auto cm_1 = random_uint256();
auto out_ciphertext_1 = enc.encrypt_to_ourselves(
sk.ovk,
cv_1,
cm_1,
small_message
);
// Encrypt to pk_2
enc = *SaplingNoteEncryption::FromDiversifier(pk_2.d);
auto ciphertext_2 = *enc.encrypt_to_recipient(
pk_2.pk_d,
message
);
auto epk_2 = enc.get_epk();
auto cv_2 = random_uint256();
auto cm_2 = random_uint256();
auto out_ciphertext_2 = enc.encrypt_to_ourselves(
sk.ovk,
cv_2,
cm_2,
small_message
);
// Test nonce-reuse resistance of API
{
auto tmp_enc = *SaplingNoteEncryption::FromDiversifier(pk_1.d);
tmp_enc.encrypt_to_recipient(
pk_1.pk_d,
message
);
ASSERT_THROW(tmp_enc.encrypt_to_recipient(
pk_1.pk_d,
message
), std::logic_error);
tmp_enc.encrypt_to_ourselves(
sk.ovk,
cv_2,
cm_2,
small_message
);
ASSERT_THROW(tmp_enc.encrypt_to_ourselves(
sk.ovk,
cv_2,
cm_2,
small_message
), std::logic_error);
}
// Try to decrypt
auto plaintext_1 = *AttemptSaplingEncDecryption(
ciphertext_1,
ivk,
epk_1
);
ASSERT_TRUE(message == plaintext_1);
auto small_plaintext_1 = *AttemptSaplingOutDecryption(
out_ciphertext_1,
sk.ovk,
cv_1,
cm_1,
epk_1
);
ASSERT_TRUE(small_message == small_plaintext_1);
auto plaintext_2 = *AttemptSaplingEncDecryption(
ciphertext_2,
ivk,
epk_2
);
ASSERT_TRUE(message == plaintext_2);
auto small_plaintext_2 = *AttemptSaplingOutDecryption(
out_ciphertext_2,
sk.ovk,
cv_2,
cm_2,
epk_2
);
ASSERT_TRUE(small_message == small_plaintext_2);
// Try to decrypt out ciphertext with wrong key material
ASSERT_FALSE(AttemptSaplingOutDecryption(
out_ciphertext_1,
random_uint256(),
cv_1,
cm_1,
epk_1
));
ASSERT_FALSE(AttemptSaplingOutDecryption(
out_ciphertext_1,
sk.ovk,
random_uint256(),
cm_1,
epk_1
));
ASSERT_FALSE(AttemptSaplingOutDecryption(
out_ciphertext_1,
sk.ovk,
cv_1,
random_uint256(),
epk_1
));
ASSERT_FALSE(AttemptSaplingOutDecryption(
out_ciphertext_1,
sk.ovk,
cv_1,
cm_1,
random_uint256()
));
// Try to decrypt with wrong ephemeral key
ASSERT_FALSE(AttemptSaplingEncDecryption(
ciphertext_1,
ivk,
epk_2
));
ASSERT_FALSE(AttemptSaplingEncDecryption(
ciphertext_2,
ivk,
epk_1
));
// Try to decrypt with wrong ivk
ASSERT_FALSE(AttemptSaplingEncDecryption(
ciphertext_1,
uint256(),
epk_1
));
ASSERT_FALSE(AttemptSaplingEncDecryption(
ciphertext_2,
uint256(),
epk_2
));
}
TEST(noteencryption, api)
{
uint256 sk_enc = ZCNoteEncryption::generate_privkey(uint252(uint256S("21035d60bc1983e37950ce4803418a8fb33ea68d5b937ca382ecbae7564d6a07")));
@@ -29,7 +354,7 @@ TEST(noteencryption, api)
ASSERT_TRUE(b.get_epk() != c.get_epk());
}
boost::array<unsigned char, ZC_NOTEPLAINTEXT_SIZE> message;
std::array<unsigned char, ZC_NOTEPLAINTEXT_SIZE> message;
for (size_t i = 0; i < ZC_NOTEPLAINTEXT_SIZE; i++) {
// Fill the message with dummy data
message[i] = (unsigned char) i;

View File

@@ -7,6 +7,8 @@
#include "zcash/Address.hpp"
#include "wallet/wallet.h"
#include "amount.h"
#include <array>
#include <memory>
#include <string>
#include <set>
@@ -91,14 +93,13 @@ public:
// Note that the zpd: prefix is not part of the payment disclosure blob itself. It is only
// used as convention to improve the user experience when sharing payment disclosure blobs.
TEST(paymentdisclosure, mainnet) {
ECC_Start();
SelectParams(CBaseChainParams::MAIN);
boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
boost::filesystem::create_directories(pathTemp);
mapArgs["-datadir"] = pathTemp.string();
std::cout << "Test payment disclosure database created in folder: " << pathTemp.native() << std::endl;
std::cout << "Test payment disclosure database created in folder: " << pathTemp.string() << std::endl;
PaymentDisclosureDBTest mydb(pathTemp);
@@ -120,7 +121,7 @@ TEST(paymentdisclosure, mainnet) {
PaymentDisclosureInfo info;
info.esk = random_uint256();
info.joinSplitPrivKey = joinSplitPrivKey;
info.zaddr = libzcash::SpendingKey::random().address();
info.zaddr = libzcash::SproutSpendingKey::random().address();
ASSERT_TRUE(mydb.Put(key, info));
// Retrieve info from test database into new local variable and test it matches
@@ -131,7 +132,7 @@ TEST(paymentdisclosure, mainnet) {
// Modify this local variable and confirm it no longer matches
info2.esk = random_uint256();
info2.joinSplitPrivKey = random_uint256();
info2.zaddr = libzcash::SpendingKey::random().address();
info2.zaddr = libzcash::SproutSpendingKey::random().address();
ASSERT_NE(info, info2);
// Using the payment info object, let's create a dummy payload
@@ -167,7 +168,7 @@ TEST(paymentdisclosure, mainnet) {
}
// Convert signature buffer to boost array
boost::array<unsigned char, 64> arrayPayloadSig;
std::array<unsigned char, 64> arrayPayloadSig;
memcpy(arrayPayloadSig.data(), &payloadSig[0], 64);
// Payment disclosure blob to pass around
@@ -207,6 +208,4 @@ TEST(paymentdisclosure, mainnet) {
#if DUMP_DATABASE_TO_STDOUT == true
mydb.DebugDumpAllStdout();
#endif
ECC_Stop();
}

View File

@@ -0,0 +1,15 @@
#include <gtest/gtest.h>
#include "librustzcash.h"
#include "uint256.h"
TEST(PedersenHash, TestAPI) {
const uint256 a = uint256S("87a086ae7d2252d58729b30263fb7b66308bf94ef59a76c9c86e7ea016536505");
const uint256 b = uint256S("a75b84a125b2353da7e8d96ee2a15efe4de23df9601b9d9564ba59de57130406");
uint256 result;
librustzcash_merkle_hash(25, a.begin(), b.begin(), result.begin());
uint256 expected_result = uint256S("5bf43b5736c19b714d1f462c9d22ba3492c36e3d9bbd7ca24d94b440550aa561");
ASSERT_TRUE(result == expected_result);
}

View File

@@ -241,7 +241,7 @@ TEST(proofs, sqrt_fq2)
TEST(proofs, size_is_expected)
{
ZCProof p;
PHGRProof p;
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << p;
@@ -444,7 +444,7 @@ TEST(proofs, zksnark_serializes_properly)
auto vkprecomp = libsnark::r1cs_ppzksnark_verifier_process_vk(kp.vk);
for (size_t i = 0; i < 20; i++) {
auto badproof = ZCProof::random_invalid();
auto badproof = PHGRProof::random_invalid();
auto proof = badproof.to_libsnark_proof<libsnark::r1cs_ppzksnark_proof<curve_pp>>();
auto verifierEnabled = ProofVerifier::Strict();
@@ -496,12 +496,12 @@ TEST(proofs, zksnark_serializes_properly)
proof
));
ZCProof compressed_proof_0(proof);
PHGRProof compressed_proof_0(proof);
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << compressed_proof_0;
ZCProof compressed_proof_1;
PHGRProof compressed_proof_1;
ss >> compressed_proof_1;
ASSERT_TRUE(compressed_proof_0 == compressed_proof_1);

View File

@@ -5,7 +5,7 @@
#include "chainparams.h"
#include "clientversion.h"
#include "primitives/block.h"
#include "rpcserver.h"
#include "rpc/server.h"
#include "streams.h"
#include "utilstrencodings.h"

View File

@@ -0,0 +1,72 @@
#include <gtest/gtest.h>
#include "zcash/Address.hpp"
#include "zcash/Note.hpp"
#include "amount.h"
#include "random.h"
#include "librustzcash.h"
#include <array>
using namespace libzcash;
// Test data from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_key_components.py
TEST(SaplingNote, TestVectors)
{
uint64_t v = 0;
uint64_t note_pos = 0;
std::array<uint8_t, 11> diversifier{0xf1, 0x9d, 0x9b, 0x79, 0x7e, 0x39, 0xf3, 0x37, 0x44, 0x58, 0x39};
std::vector<uint8_t> v_sk{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
std::vector<uint8_t> v_pk_d{
0xdb, 0x4c, 0xd2, 0xb0, 0xaa, 0xc4, 0xf7, 0xeb, 0x8c, 0xa1, 0x31, 0xf1, 0x65, 0x67,
0xc4, 0x45, 0xa9, 0x55, 0x51, 0x26, 0xd3, 0xc2, 0x9f, 0x14, 0xe3, 0xd7, 0x76, 0xe8,
0x41, 0xae, 0x74, 0x15};
std::vector<uint8_t> v_r{
0x39, 0x17, 0x6d, 0xac, 0x39, 0xac, 0xe4, 0x98, 0x0e, 0xcc, 0x8d, 0x77, 0x8e, 0x89,
0x86, 0x02, 0x55, 0xec, 0x36, 0x15, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
std::vector<uint8_t> v_cm{
0xcb, 0x3c, 0xf9, 0x15, 0x32, 0x70, 0xd5, 0x7e, 0xb9, 0x14, 0xc6, 0xc2, 0xbc, 0xc0,
0x18, 0x50, 0xc9, 0xfe, 0xd4, 0x4f, 0xce, 0x08, 0x06, 0x27, 0x8f, 0x08, 0x3e, 0xf2,
0xdd, 0x07, 0x64, 0x39};
std::vector<uint8_t> v_nf{
0x44, 0xfa, 0xd6, 0x56, 0x4f, 0xfd, 0xec, 0x9f, 0xa1, 0x9c, 0x43, 0xa2, 0x8f, 0x86,
0x1d, 0x5e, 0xbf, 0x60, 0x23, 0x46, 0x00, 0x7d, 0xe7, 0x62, 0x67, 0xd9, 0x75, 0x27,
0x47, 0xab, 0x40, 0x63};
uint256 sk(v_sk);
uint256 pk_d(v_pk_d);
uint256 r(v_r);
uint256 cm(v_cm);
uint256 nf(v_nf);
// Test commitment
SaplingNote note = SaplingNote(diversifier, pk_d, v, r);
ASSERT_EQ(note.cm().get(), cm);
// Test nullifier
SaplingSpendingKey spendingKey(sk);
ASSERT_EQ(note.nullifier(spendingKey.full_viewing_key(), note_pos), nf);
}
TEST(SaplingNote, Random)
{
// Test creating random notes using the same spending key
auto address = SaplingSpendingKey::random().default_address();
SaplingNote note1(address, GetRand(MAX_MONEY));
SaplingNote note2(address, GetRand(MAX_MONEY));
ASSERT_EQ(note1.d, note2.d);
ASSERT_EQ(note1.pk_d, note2.pk_d);
ASSERT_NE(note1.value(), note2.value());
ASSERT_NE(note1.r, note2.r);
// Test diversifier and pk_d are not the same for different spending keys
SaplingNote note3(SaplingSpendingKey::random().default_address(), GetRand(MAX_MONEY));
ASSERT_NE(note1.d, note3.d);
ASSERT_NE(note1.pk_d, note3.pk_d);
}

View File

@@ -4,18 +4,20 @@
#include "zcash/Note.hpp"
#include "zcash/Address.hpp"
#include <array>
extern ZCJoinSplit* params;
extern int GenZero(int n);
extern int GenMax(int n);
TEST(Transaction, JSDescriptionRandomized) {
// construct a merkle tree
ZCIncrementalMerkleTree merkleTree;
SproutMerkleTree merkleTree;
libzcash::SpendingKey k = libzcash::SpendingKey::random();
libzcash::PaymentAddress addr = k.address();
libzcash::SproutSpendingKey k = libzcash::SproutSpendingKey::random();
libzcash::SproutPaymentAddress addr = k.address();
libzcash::Note note(addr.a_pk, 100, uint256(), uint256());
libzcash::SproutNote note(addr.a_pk, 100, uint256(), uint256());
// commitment from coin
uint256 commitment = note.cm();
@@ -29,81 +31,59 @@ TEST(Transaction, JSDescriptionRandomized) {
auto witness = merkleTree.witness();
// create JSDescription
uint256 pubKeyHash;
boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> inputs = {
uint256 joinSplitPubKey;
std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> inputs = {
libzcash::JSInput(witness, note, k),
libzcash::JSInput() // dummy input of zero value
};
boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS> outputs = {
std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS> outputs = {
libzcash::JSOutput(addr, 50),
libzcash::JSOutput(addr, 50)
};
#ifdef __LP64__ // required for building on MacOS
boost::array<uint64_t, ZC_NUM_JS_INPUTS> inputMap;
boost::array<uint64_t, ZC_NUM_JS_OUTPUTS> outputMap;
#else
boost::array<size_t, ZC_NUM_JS_INPUTS> inputMap;
boost::array<size_t, ZC_NUM_JS_OUTPUTS> outputMap;
#endif
std::array<size_t, ZC_NUM_JS_INPUTS> inputMap;
std::array<size_t, ZC_NUM_JS_OUTPUTS> outputMap;
{
auto jsdesc = JSDescription::Randomized(
*params, pubKeyHash, rt,
false,
*params, joinSplitPubKey, rt,
inputs, outputs,
inputMap, outputMap,
0, 0, false);
#ifdef __LP64__ // required for building on MacOS
std::set<uint64_t> inputSet(inputMap.begin(), inputMap.end());
std::set<uint64_t> expectedInputSet {0, 1};
#else
std::set<size_t> inputSet(inputMap.begin(), inputMap.end());
std::set<size_t> expectedInputSet {0, 1};
#endif
EXPECT_EQ(expectedInputSet, inputSet);
#ifdef __LP64__ // required for building on MacOS
std::set<uint64_t> outputSet(outputMap.begin(), outputMap.end());
std::set<uint64_t> expectedOutputSet {0, 1};
#else
std::set<size_t> outputSet(outputMap.begin(), outputMap.end());
std::set<size_t> expectedOutputSet {0, 1};
#endif
EXPECT_EQ(expectedOutputSet, outputSet);
}
{
auto jsdesc = JSDescription::Randomized(
*params, pubKeyHash, rt,
false,
*params, joinSplitPubKey, rt,
inputs, outputs,
inputMap, outputMap,
0, 0, false, nullptr, GenZero);
#ifdef __LP64__ // required for building on MacOS
boost::array<uint64_t, ZC_NUM_JS_INPUTS> expectedInputMap {1, 0};
boost::array<uint64_t, ZC_NUM_JS_OUTPUTS> expectedOutputMap {1, 0};
#else
boost::array<size_t, ZC_NUM_JS_INPUTS> expectedInputMap {1, 0};
boost::array<size_t, ZC_NUM_JS_OUTPUTS> expectedOutputMap {1, 0};
#endif
std::array<size_t, ZC_NUM_JS_INPUTS> expectedInputMap {1, 0};
std::array<size_t, ZC_NUM_JS_OUTPUTS> expectedOutputMap {1, 0};
EXPECT_EQ(expectedInputMap, inputMap);
EXPECT_EQ(expectedOutputMap, outputMap);
}
{
auto jsdesc = JSDescription::Randomized(
*params, pubKeyHash, rt,
false,
*params, joinSplitPubKey, rt,
inputs, outputs,
inputMap, outputMap,
0, 0, false, nullptr, GenMax);
#ifdef __LP64__ // required for building on MacOS
boost::array<uint64_t, ZC_NUM_JS_INPUTS> expectedInputMap {0, 1};
boost::array<uint64_t, ZC_NUM_JS_OUTPUTS> expectedOutputMap {0, 1};
#else
boost::array<size_t, ZC_NUM_JS_INPUTS> expectedInputMap {0, 1};
boost::array<size_t, ZC_NUM_JS_OUTPUTS> expectedOutputMap {0, 1};
#endif
std::array<size_t, ZC_NUM_JS_INPUTS> expectedInputMap {0, 1};
std::array<size_t, ZC_NUM_JS_OUTPUTS> expectedOutputMap {0, 1};
EXPECT_EQ(expectedInputMap, inputMap);
EXPECT_EQ(expectedOutputMap, outputMap);
}

View File

@@ -0,0 +1,335 @@
#include "chainparams.h"
#include "consensus/params.h"
#include "consensus/validation.h"
#include "key_io.h"
#include "main.h"
#include "pubkey.h"
#include "transaction_builder.h"
#include "zcash/Address.hpp"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
static const std::string tSecretRegtest = "cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN";
TEST(TransactionBuilder, Invoke)
{
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto consensusParams = Params().GetConsensus();
CBasicKeyStore keystore;
CKey tsk = DecodeSecret(tSecretRegtest);
keystore.AddKey(tsk);
auto scriptPubKey = GetScriptForDestination(tsk.GetPubKey().GetID());
auto sk_from = libzcash::SaplingSpendingKey::random();
auto fvk_from = sk_from.full_viewing_key();
auto sk = libzcash::SaplingSpendingKey::random();
auto expsk = sk.expanded_spending_key();
auto fvk = sk.full_viewing_key();
auto ivk = fvk.in_viewing_key();
libzcash::diversifier_t d = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
auto pk = *ivk.address(d);
// Create a shielding transaction from transparent to Sapling
// 0.0005 t-ZEC in, 0.0004 z-ZEC out, 0.0001 t-ZEC fee
auto builder1 = TransactionBuilder(consensusParams, 1, &keystore);
builder1.AddTransparentInput(COutPoint(), scriptPubKey, 50000);
builder1.AddSaplingOutput(fvk_from, pk, 40000, {});
auto maybe_tx1 = builder1.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx1), true);
auto tx1 = maybe_tx1.get();
EXPECT_EQ(tx1.vin.size(), 1);
EXPECT_EQ(tx1.vout.size(), 0);
EXPECT_EQ(tx1.vjoinsplit.size(), 0);
EXPECT_EQ(tx1.vShieldedSpend.size(), 0);
EXPECT_EQ(tx1.vShieldedOutput.size(), 1);
EXPECT_EQ(tx1.valueBalance, -40000);
CValidationState state;
EXPECT_TRUE(ContextualCheckTransaction(tx1, state, 2, 0));
EXPECT_EQ(state.GetRejectReason(), "");
// Prepare to spend the note that was just created
auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt(
tx1.vShieldedOutput[0].encCiphertext, ivk, tx1.vShieldedOutput[0].ephemeralKey, tx1.vShieldedOutput[0].cm);
ASSERT_EQ(static_cast<bool>(maybe_pt), true);
auto maybe_note = maybe_pt.get().note(ivk);
ASSERT_EQ(static_cast<bool>(maybe_note), true);
auto note = maybe_note.get();
SaplingMerkleTree tree;
tree.append(tx1.vShieldedOutput[0].cm);
auto anchor = tree.root();
auto witness = tree.witness();
// Create a Sapling-only transaction
// 0.0004 z-ZEC in, 0.00025 z-ZEC out, 0.0001 t-ZEC fee, 0.00005 z-ZEC change
auto builder2 = TransactionBuilder(consensusParams, 2);
ASSERT_TRUE(builder2.AddSaplingSpend(expsk, note, anchor, witness));
// Check that trying to add a different anchor fails
ASSERT_FALSE(builder2.AddSaplingSpend(expsk, note, uint256(), witness));
builder2.AddSaplingOutput(fvk, pk, 25000, {});
auto maybe_tx2 = builder2.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx2), true);
auto tx2 = maybe_tx2.get();
EXPECT_EQ(tx2.vin.size(), 0);
EXPECT_EQ(tx2.vout.size(), 0);
EXPECT_EQ(tx2.vjoinsplit.size(), 0);
EXPECT_EQ(tx2.vShieldedSpend.size(), 1);
EXPECT_EQ(tx2.vShieldedOutput.size(), 2);
EXPECT_EQ(tx2.valueBalance, 10000);
EXPECT_TRUE(ContextualCheckTransaction(tx2, state, 3, 0));
EXPECT_EQ(state.GetRejectReason(), "");
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
TEST(TransactionBuilder, ThrowsOnTransparentInputWithoutKeyStore)
{
auto consensusParams = Params().GetConsensus();
auto builder = TransactionBuilder(consensusParams, 1);
ASSERT_THROW(builder.AddTransparentInput(COutPoint(), CScript(), 1), std::runtime_error);
}
TEST(TransactionBuilder, RejectsInvalidTransparentOutput)
{
auto consensusParams = Params().GetConsensus();
// Default CTxDestination type is an invalid address
CTxDestination taddr;
auto builder = TransactionBuilder(consensusParams, 1);
EXPECT_FALSE(builder.AddTransparentOutput(taddr, 50));
}
TEST(TransactionBuilder, RejectsInvalidTransparentChangeAddress)
{
auto consensusParams = Params().GetConsensus();
// Default CTxDestination type is an invalid address
CTxDestination taddr;
auto builder = TransactionBuilder(consensusParams, 1);
EXPECT_FALSE(builder.SendChangeTo(taddr));
}
TEST(TransactionBuilder, FailsWithNegativeChange)
{
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto consensusParams = Params().GetConsensus();
// Generate dummy Sapling address
auto sk = libzcash::SaplingSpendingKey::random();
auto expsk = sk.expanded_spending_key();
auto fvk = sk.full_viewing_key();
auto pk = sk.default_address();
// Set up dummy transparent address
CBasicKeyStore keystore;
CKey tsk = DecodeSecret(tSecretRegtest);
keystore.AddKey(tsk);
auto tkeyid = tsk.GetPubKey().GetID();
auto scriptPubKey = GetScriptForDestination(tkeyid);
CTxDestination taddr = tkeyid;
// Generate dummy Sapling note
libzcash::SaplingNote note(pk, 59999);
auto cm = note.cm().value();
SaplingMerkleTree tree;
tree.append(cm);
auto anchor = tree.root();
auto witness = tree.witness();
// Fail if there is only a Sapling output
// 0.0005 z-ZEC out, 0.0001 t-ZEC fee
auto builder = TransactionBuilder(consensusParams, 1);
builder.AddSaplingOutput(fvk, pk, 50000, {});
EXPECT_FALSE(static_cast<bool>(builder.Build()));
// Fail if there is only a transparent output
// 0.0005 t-ZEC out, 0.0001 t-ZEC fee
builder = TransactionBuilder(consensusParams, 1, &keystore);
EXPECT_TRUE(builder.AddTransparentOutput(taddr, 50000));
EXPECT_FALSE(static_cast<bool>(builder.Build()));
// Fails if there is insufficient input
// 0.0005 t-ZEC out, 0.0001 t-ZEC fee, 0.00059999 z-ZEC in
EXPECT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
EXPECT_FALSE(static_cast<bool>(builder.Build()));
// Succeeds if there is sufficient input
builder.AddTransparentInput(COutPoint(), scriptPubKey, 1);
EXPECT_TRUE(static_cast<bool>(builder.Build()));
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
TEST(TransactionBuilder, ChangeOutput)
{
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto consensusParams = Params().GetConsensus();
// Generate dummy Sapling address
auto sk = libzcash::SaplingSpendingKey::random();
auto expsk = sk.expanded_spending_key();
auto pk = sk.default_address();
// Generate dummy Sapling note
libzcash::SaplingNote note(pk, 25000);
auto cm = note.cm().value();
SaplingMerkleTree tree;
tree.append(cm);
auto anchor = tree.root();
auto witness = tree.witness();
// Generate change Sapling address
auto sk2 = libzcash::SaplingSpendingKey::random();
auto fvkOut = sk2.full_viewing_key();
auto zChangeAddr = sk2.default_address();
// Set up dummy transparent address
CBasicKeyStore keystore;
CKey tsk = DecodeSecret(tSecretRegtest);
keystore.AddKey(tsk);
auto tkeyid = tsk.GetPubKey().GetID();
auto scriptPubKey = GetScriptForDestination(tkeyid);
CTxDestination taddr = tkeyid;
// No change address and no Sapling spends
{
auto builder = TransactionBuilder(consensusParams, 1, &keystore);
builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000);
EXPECT_FALSE(static_cast<bool>(builder.Build()));
}
// Change to the same address as the first Sapling spend
{
auto builder = TransactionBuilder(consensusParams, 1, &keystore);
builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000);
ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx = maybe_tx.get();
EXPECT_EQ(tx.vin.size(), 1);
EXPECT_EQ(tx.vout.size(), 0);
EXPECT_EQ(tx.vjoinsplit.size(), 0);
EXPECT_EQ(tx.vShieldedSpend.size(), 1);
EXPECT_EQ(tx.vShieldedOutput.size(), 1);
EXPECT_EQ(tx.valueBalance, -15000);
}
// Change to a Sapling address
{
auto builder = TransactionBuilder(consensusParams, 1, &keystore);
builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000);
builder.SendChangeTo(zChangeAddr, fvkOut);
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx = maybe_tx.get();
EXPECT_EQ(tx.vin.size(), 1);
EXPECT_EQ(tx.vout.size(), 0);
EXPECT_EQ(tx.vjoinsplit.size(), 0);
EXPECT_EQ(tx.vShieldedSpend.size(), 0);
EXPECT_EQ(tx.vShieldedOutput.size(), 1);
EXPECT_EQ(tx.valueBalance, -15000);
}
// Change to a transparent address
{
auto builder = TransactionBuilder(consensusParams, 1, &keystore);
builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000);
ASSERT_TRUE(builder.SendChangeTo(taddr));
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx = maybe_tx.get();
EXPECT_EQ(tx.vin.size(), 1);
EXPECT_EQ(tx.vout.size(), 1);
EXPECT_EQ(tx.vjoinsplit.size(), 0);
EXPECT_EQ(tx.vShieldedSpend.size(), 0);
EXPECT_EQ(tx.vShieldedOutput.size(), 0);
EXPECT_EQ(tx.valueBalance, 0);
EXPECT_EQ(tx.vout[0].nValue, 15000);
}
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
TEST(TransactionBuilder, SetFee)
{
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto consensusParams = Params().GetConsensus();
// Generate dummy Sapling address
auto sk = libzcash::SaplingSpendingKey::random();
auto expsk = sk.expanded_spending_key();
auto fvk = sk.full_viewing_key();
auto pk = sk.default_address();
// Generate dummy Sapling note
libzcash::SaplingNote note(pk, 50000);
auto cm = note.cm().value();
SaplingMerkleTree tree;
tree.append(cm);
auto anchor = tree.root();
auto witness = tree.witness();
// Default fee
{
auto builder = TransactionBuilder(consensusParams, 1);
ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
builder.AddSaplingOutput(fvk, pk, 25000, {});
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx = maybe_tx.get();
EXPECT_EQ(tx.vin.size(), 0);
EXPECT_EQ(tx.vout.size(), 0);
EXPECT_EQ(tx.vjoinsplit.size(), 0);
EXPECT_EQ(tx.vShieldedSpend.size(), 1);
EXPECT_EQ(tx.vShieldedOutput.size(), 2);
EXPECT_EQ(tx.valueBalance, 10000);
}
// Configured fee
{
auto builder = TransactionBuilder(consensusParams, 1);
ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
builder.AddSaplingOutput(fvk, pk, 25000, {});
builder.SetFee(20000);
auto maybe_tx = builder.Build();
ASSERT_EQ(static_cast<bool>(maybe_tx), true);
auto tx = maybe_tx.get();
EXPECT_EQ(tx.vin.size(), 0);
EXPECT_EQ(tx.vout.size(), 0);
EXPECT_EQ(tx.vjoinsplit.size(), 0);
EXPECT_EQ(tx.vShieldedSpend.size(), 1);
EXPECT_EQ(tx.vShieldedOutput.size(), 2);
EXPECT_EQ(tx.valueBalance, 20000);
}
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}

View File

@@ -21,11 +21,15 @@ class FakeCoinsViewDB : public CCoinsView {
public:
FakeCoinsViewDB() {}
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf) const {
bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf, ShieldedType type) const {
return false;
}
@@ -42,16 +46,19 @@ public:
return a;
}
uint256 GetBestAnchor() const {
uint256 GetBestAnchor(ShieldedType type) const {
uint256 a;
return a;
}
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) {
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CAnchorsSaplingMap &mapSaplingAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap saplingNullifiersMap) {
return false;
}
@@ -71,14 +78,16 @@ TEST(Validation, ContextualCheckInputsPassesWithCoinbase) {
FakeCoinsViewDB fakeDB;
CCoinsViewCache view(&fakeDB);
auto consensusBranchId = SPROUT_BRANCH_ID;
CValidationState state;
PrecomputedTransactionData txdata(tx);
EXPECT_TRUE(ContextualCheckInputs(tx, state, view, false, 0, false, txdata, Params(CBaseChainParams::MAIN).GetConsensus(), consensusBranchId));
for (int idx = Consensus::BASE_SPROUT; idx < Consensus::MAX_NETWORK_UPGRADES; idx++) {
auto consensusBranchId = NetworkUpgradeInfo[idx].nBranchId;
CValidationState state;
PrecomputedTransactionData txdata(tx);
EXPECT_TRUE(ContextualCheckInputs(tx, state, view, false, 0, false, txdata, Params(CBaseChainParams::MAIN).GetConsensus(), consensusBranchId));
}
}
TEST(Validation, ReceivedBlockTransactions) {
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
// Create a fake genesis block
CBlock block1;

134
src/gtest/test_zip32.cpp Normal file
View File

@@ -0,0 +1,134 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <zcash/zip32.h>
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_zip32.py
// Sapling consistently uses little-endian encoding, but uint256S takes its input in
// big-endian byte order, so the test vectors below are byte-reversed.
TEST(ZIP32, TestVectors) {
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
HDSeed seed(rawSeed);
auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);
EXPECT_EQ(m.depth, 0);
EXPECT_EQ(m.parentFVKTag, 0);
EXPECT_EQ(m.childIndex, 0);
EXPECT_EQ(
m.chaincode,
uint256S("8e661820750d557e8b34733ebf7ecdfdf31c6d27724fb47aa372bf034b7c94d0"));
EXPECT_EQ(
m.expsk.ask,
uint256S("06257454c907f6510ba1c1830ebf60657760a8869ee968a2b93260d3930cc0b6"));
EXPECT_EQ(
m.expsk.nsk,
uint256S("06ea21888a749fd38eb443d20a030abd2e6e997f5db4f984bd1f2f3be8ed0482"));
EXPECT_EQ(
m.expsk.ovk,
uint256S("21fb4adfa42183848306ffb27719f27d76cf9bb81d023c93d4b9230389845839"));
EXPECT_EQ(
m.dk,
uint256S("72a196f93e8abc0935280ea2a96fa57d6024c9913e0f9fb3af96775bb77cc177"));
EXPECT_THAT(
m.ToXFVK().DefaultAddress().d,
testing::ElementsAreArray({ 0xd8, 0x62, 0x1b, 0x98, 0x1c, 0xf3, 0x00, 0xe9, 0xd4, 0xcc, 0x89 }));
auto m_1 = m.Derive(1);
EXPECT_EQ(m_1.depth, 1);
EXPECT_EQ(m_1.parentFVKTag, 0x3a71c214);
EXPECT_EQ(m_1.childIndex, 1);
EXPECT_EQ(
m_1.chaincode,
uint256S("e6bcda05678a43fad229334ef0b795a590e7c50590baf0d9b9031a690c114701"));
EXPECT_EQ(
m_1.expsk.ask,
uint256S("0c357a2655b4b8d761794095df5cb402d3ba4a428cf6a88e7c2816a597c12b28"));
EXPECT_EQ(
m_1.expsk.nsk,
uint256S("01ba6bff1018fd4eac04da7e3f2c6be9c229e662c5c4d1d6fc1ecafd8829a3e7"));
EXPECT_EQ(
m_1.expsk.ovk,
uint256S("7474a4c518551bd82f14a7f7365a8ffa403c50cfeffedf026ada8688fc81135f"));
EXPECT_EQ(
m_1.dk,
uint256S("dcb4c170d878510e96c4a74192d7eecde9c9912b00b99a12ec91d7a232e84de0"));
EXPECT_THAT(
m_1.ToXFVK().DefaultAddress().d,
testing::ElementsAreArray({ 0x8b, 0x41, 0x38, 0x32, 0x0d, 0xfa, 0xfd, 0x7b, 0x39, 0x97, 0x81 }));
auto m_1_2h = m_1.Derive(2 | ZIP32_HARDENED_KEY_LIMIT);
EXPECT_EQ(m_1_2h.depth, 2);
EXPECT_EQ(m_1_2h.parentFVKTag, 0x079e99db);
EXPECT_EQ(m_1_2h.childIndex, 2 | ZIP32_HARDENED_KEY_LIMIT);
EXPECT_EQ(
m_1_2h.chaincode,
uint256S("35d4a883737742ca41a4baa92323bdb3c93dcb3b462a26b039971bedf415ce97"));
EXPECT_EQ(
m_1_2h.expsk.ask,
uint256S("0dc6e4fe846bda925c82e632980434e17b51dac81fc4821fa71334ee3c11e88b"));
EXPECT_EQ(
m_1_2h.expsk.nsk,
uint256S("0c99a63a275c1c66734761cfb9c62fe9bd1b953f579123d3d0e769c59d057837"));
EXPECT_EQ(
m_1_2h.expsk.ovk,
uint256S("bc1328fc5eb693e18875c5149d06953b11d39447ebd6e38c023c22962e1881cf"));
EXPECT_EQ(
m_1_2h.dk,
uint256S("377bb062dce7e0dcd8a0054d0ca4b4d1481b3710bfa1df12ca46ff9e9fa1eda3"));
EXPECT_THAT(
m_1_2h.ToXFVK().DefaultAddress().d,
testing::ElementsAreArray({ 0xe8, 0xd0, 0x37, 0x93, 0xcd, 0xd2, 0xba, 0xcc, 0x9c, 0x70, 0x41 }));
auto m_1_2hv = m_1_2h.ToXFVK();
EXPECT_EQ(m_1_2hv.depth, 2);
EXPECT_EQ(m_1_2hv.parentFVKTag, 0x079e99db);
EXPECT_EQ(m_1_2hv.childIndex, 2 | ZIP32_HARDENED_KEY_LIMIT);
EXPECT_EQ(
m_1_2hv.chaincode,
uint256S("35d4a883737742ca41a4baa92323bdb3c93dcb3b462a26b039971bedf415ce97"));
EXPECT_EQ(
m_1_2hv.fvk.ak,
uint256S("4138cffdf7200e52d4e9f4384481b4a4c4d070493a5e401e4ffa850f5a92c5a6"));
EXPECT_EQ(
m_1_2hv.fvk.nk,
uint256S("11eee22577304f660cc036bc84b3fc88d1ec50ae8a4d657beb6b211659304e30"));
EXPECT_EQ(
m_1_2hv.fvk.ovk,
uint256S("bc1328fc5eb693e18875c5149d06953b11d39447ebd6e38c023c22962e1881cf"));
EXPECT_EQ(
m_1_2hv.dk,
uint256S("377bb062dce7e0dcd8a0054d0ca4b4d1481b3710bfa1df12ca46ff9e9fa1eda3"));
EXPECT_EQ(m_1_2hv.DefaultAddress(), m_1_2h.ToXFVK().DefaultAddress());
// Hardened derivation from an xfvk fails
EXPECT_FALSE(m_1_2hv.Derive(3 | ZIP32_HARDENED_KEY_LIMIT));
// Non-hardened derivation succeeds
auto maybe_m_1_2hv_3 = m_1_2hv.Derive(3);
EXPECT_TRUE(maybe_m_1_2hv_3);
auto m_1_2hv_3 = maybe_m_1_2hv_3.get();
EXPECT_EQ(m_1_2hv_3.depth, 3);
EXPECT_EQ(m_1_2hv_3.parentFVKTag, 0x7583c148);
EXPECT_EQ(m_1_2hv_3.childIndex, 3);
EXPECT_EQ(
m_1_2hv_3.chaincode,
uint256S("e8e7d6a74a5a1c05be41baec7998d91f7b3603a4c0af495b0d43ba81cf7b938d"));
EXPECT_EQ(
m_1_2hv_3.fvk.ak,
uint256S("a3a697bdda9d648d32a97553de4754b2fac866d726d3f2c436259c507bc585b1"));
EXPECT_EQ(
m_1_2hv_3.fvk.nk,
uint256S("4f66c0814b769963f3bf1bc001270b50edabb27de042fc8a5607d2029e0488db"));
EXPECT_EQ(
m_1_2hv_3.fvk.ovk,
uint256S("f61a699934dc78441324ef628b4b4721611571e8ee3bd591eb3d4b1cfae0b969"));
EXPECT_EQ(
m_1_2hv_3.dk,
uint256S("6ee53b1261f2c9c0f7359ab236f87b52a0f1b0ce43305cdad92ebb63c350cbbe"));
EXPECT_THAT(
m_1_2hv_3.DefaultAddress().d,
testing::ElementsAreArray({ 0x03, 0x0f, 0xfb, 0x26, 0x3a, 0x93, 0x9e, 0x23, 0x0e, 0x96, 0xdd }));
}

View File

@@ -9,6 +9,7 @@
#include "crypto/ripemd160.h"
#include "crypto/sha256.h"
#include "crypto/verus_hash.h"
#include "prevector.h"
#include "serialize.h"
#include "uint256.h"
#include "version.h"
@@ -121,21 +122,30 @@ inline uint160 Hash160(const std::vector<unsigned char>& vch)
return Hash160(vch.begin(), vch.end());
}
/** Compute the 160-bit hash of a vector. */
template<unsigned int N>
inline uint160 Hash160(const prevector<N, unsigned char>& vch)
{
return Hash160(vch.begin(), vch.end());
}
/** A writer stream (for serialization) that computes a 256-bit hash. */
class CHashWriter
{
private:
CHash256 ctx;
const int nType;
const int nVersion;
public:
int nType;
int nVersion;
CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {}
CHashWriter& write(const char *pch, size_t size) {
int GetType() const { return nType; }
int GetVersion() const { return nVersion; }
void write(const char *pch, size_t size) {
ctx.Write((const unsigned char*)pch, size);
return (*this);
}
// invalidates the object
@@ -148,7 +158,7 @@ public:
template<typename T>
CHashWriter& operator<<(const T& obj) {
// Serialize to this stream
::Serialize(*this, obj, nType, nVersion);
::Serialize(*this, obj);
return (*this);
}
};
@@ -173,6 +183,9 @@ public:
personal) == 0);
}
int GetType() const { return nType; }
int GetVersion() const { return nVersion; }
CBLAKE2bWriter& write(const char *pch, size_t size) {
crypto_generichash_blake2b_update(&state, (const unsigned char*)pch, size);
return (*this);
@@ -188,7 +201,7 @@ public:
template<typename T>
CBLAKE2bWriter& operator<<(const T& obj) {
// Serialize to this stream
::Serialize(*this, obj, nType, nVersion);
::Serialize(*this, obj);
return (*this);
}
};
@@ -224,7 +237,7 @@ public:
template<typename T>
CVerusHashWriter& operator<<(const T& obj) {
// Serialize to this stream
::Serialize(*this, obj, nType, nVersion);
::Serialize(*this, obj);
return (*this);
}
};
@@ -260,7 +273,7 @@ public:
template<typename T>
CVerusHashV2Writer& operator<<(const T& obj) {
// Serialize to this stream
::Serialize(*this, obj, nType, nVersion);
::Serialize(*this, obj);
return (*this);
}
};

View File

@@ -1,10 +1,10 @@
#include "httprpc.h"
#include "base58.h"
#include "chainparams.h"
#include "httpserver.h"
#include "rpcprotocol.h"
#include "rpcserver.h"
#include "key_io.h"
#include "rpc/protocol.h"
#include "rpc/server.h"
#include "random.h"
#include "sync.h"
#include "util.h"

View File

@@ -8,7 +8,7 @@
#include "compat.h"
#include "util.h"
#include "netbase.h"
#include "rpcprotocol.h" // For HTTP status codes
#include "rpc/protocol.h" // For HTTP status codes
#include "sync.h"
#include "ui_interface.h"

View File

@@ -12,9 +12,6 @@
#include "primitives/block.h"
#include "addrman.h"
#include "amount.h"
#ifdef ENABLE_MINING
#include "base58.h"
#endif
#include "checkpoints.h"
#include "compat/sanity.h"
#include "consensus/upgrades.h"
@@ -23,11 +20,15 @@
#include "httprpc.h"
#include "key.h"
#include "notarisationdb.h"
#ifdef ENABLE_MINING
#include "key_io.h"
#endif
#include "main.h"
#include "metrics.h"
#include "miner.h"
#include "net.h"
#include "rpcserver.h"
#include "rpc/server.h"
#include "rpc/register.h"
#include "script/standard.h"
#include "scheduler.h"
#include "txdb.h"
@@ -68,6 +69,8 @@
#include "amqp/amqpnotificationinterface.h"
#endif
#include "librustzcash.h"
using namespace std;
extern void ThreadSendAlert();
@@ -352,13 +355,11 @@ std::string HelpMessage(HelpMessageMode mode)
#endif
}
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
strUsage += HelpMessageOpt("-disabledeprecation=<version>", strprintf(_("Disable block-height node deprecation and automatic shutdown (example: -disabledeprecation=%s)"),
FormatVersion(CLIENT_VERSION)));
strUsage += HelpMessageOpt("-exportdir=<dir>", _("Specify directory to be used when exporting data"));
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file") + " " + _("on startup"));
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
strUsage += HelpMessageOpt("-mempooltxinputlimit=<n>", _("Set the maximum number of transparent inputs in a transaction that the mempool will accept (default: 0 = no limit applied)"));
strUsage += HelpMessageOpt("-mempooltxinputlimit=<n>", _("[DEPRECATED FROM OVERWINTER] Set the maximum number of transparent inputs in a transaction that the mempool will accept (default: 0 = no limit applied)"));
strUsage += HelpMessageOpt("-par=<n>", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"),
-(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));
#ifndef _WIN32
@@ -394,6 +395,9 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-onion=<ip:port>", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy"));
strUsage += HelpMessageOpt("-onlynet=<net>", _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)"));
strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), 1));
strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with Bloom filters (default: %u)"), 1));
if (showDebug)
strUsage += HelpMessageOpt("-enforcenodebloom", strprintf("Enforce minimum protocol version to limit use of Bloom filters (default: %u)", 0));
strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), 7770, 17770));
strUsage += HelpMessageOpt("-proxy=<ip:port>", _("Connect through SOCKS5 proxy"));
strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), 1));
@@ -472,6 +476,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", 15));
strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 0));
strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> entries (default: %u)", 50000));
strUsage += HelpMessageOpt("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE));
}
strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s)"),
CURRENCY_UNIT, FormatMoney(::minRelayTxFee.GetFeePerK())));
@@ -683,15 +688,26 @@ bool InitSanityCheck(void)
}
static void ZC_LoadParams()
static void ZC_LoadParams(
const CChainParams& chainparams
)
{
struct timeval tv_start, tv_end;
float elapsed;
boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key";
boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key";
boost::filesystem::path sapling_spend = ZC_GetParamsDir() / "sapling-spend.params";
boost::filesystem::path sapling_output = ZC_GetParamsDir() / "sapling-output.params";
boost::filesystem::path sprout_groth16 = ZC_GetParamsDir() / "sprout-groth16.params";
if (!(boost::filesystem::exists(pk_path) && boost::filesystem::exists(vk_path))) {
if (!(
boost::filesystem::exists(pk_path) &&
boost::filesystem::exists(vk_path) &&
boost::filesystem::exists(sapling_spend) &&
boost::filesystem::exists(sapling_output) &&
boost::filesystem::exists(sprout_groth16)
)) {
uiInterface.ThreadSafeMessageBox(strprintf(
_("Cannot find the Zcash network parameters in the following directory:\n"
"%s\n"
@@ -710,6 +726,28 @@ static void ZC_LoadParams()
gettimeofday(&tv_end, 0);
elapsed = float(tv_end.tv_sec-tv_start.tv_sec) + (tv_end.tv_usec-tv_start.tv_usec)/float(1000000);
LogPrintf("Loaded verifying key in %fs seconds.\n", elapsed);
std::string sapling_spend_str = sapling_spend.string();
std::string sapling_output_str = sapling_output.string();
std::string sprout_groth16_str = sprout_groth16.string();
LogPrintf("Loading Sapling (Spend) parameters from %s\n", sapling_spend_str.c_str());
LogPrintf("Loading Sapling (Output) parameters from %s\n", sapling_output_str.c_str());
LogPrintf("Loading Sapling (Sprout Groth16) parameters from %s\n", sprout_groth16_str.c_str());
gettimeofday(&tv_start, 0);
librustzcash_init_zksnark_params(
sapling_spend_str.c_str(),
"8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c",
sapling_output_str.c_str(),
"657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028",
sprout_groth16_str.c_str(),
"e9b238411bd6c0ec4791e9d04245ec350c9c5744f5610dfcce4365d5ca49dfefd5054e371842b3f88fa1b9d7e8e075249b3ebabd167fa8b0f3161292d36c180a"
);
gettimeofday(&tv_end, 0);
elapsed = float(tv_end.tv_sec-tv_start.tv_sec) + (tv_end.tv_usec-tv_start.tv_usec)/float(1000000);
LogPrintf("Loaded Sapling parameters in %fs seconds.\n", elapsed);
}
bool AppInitServers(boost::thread_group& threadGroup)
@@ -792,6 +830,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
signal(SIGPIPE, SIG_IGN);
#endif
std::set_new_handler(new_handler_terminate);
// ********************************************************* Step 2: parameter interactions
const CChainParams& chainparams = Params();
@@ -960,8 +1000,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fPruneMode = true;
}
RegisterAllCoreRPCCommands(tableRPC);
#ifdef ENABLE_WALLET
bool fDisableWallet = GetBoolArg("-disablewallet", false);
if (!fDisableWallet)
RegisterWalletRPCCommands(tableRPC);
#endif
nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
@@ -1036,10 +1079,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Option to startup with mocktime set (used for regression testing):
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
if (GetBoolArg("-peerbloomfilters", true))
nLocalServices |= NODE_BLOOM;
nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
#ifdef ENABLE_MINING
if (mapArgs.count("-mineraddress")) {
CBitcoinAddress addr;
if (!addr.SetString(mapArgs["-mineraddress"])) {
CTxDestination addr = DecodeDestination(mapArgs["-mineraddress"]);
if (!IsValidDestination(addr)) {
return InitError(strprintf(
_("Invalid address for -mineraddress=<addr>: '%s' (must be a transparent address)"),
mapArgs["-mineraddress"]));
@@ -1183,7 +1231,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
libsnark::inhibit_profiling_counters = true;
// Initialize Zcash circuit parameters
ZC_LoadParams();
ZC_LoadParams(chainparams);
/* Start the RPC server already. It will be started in "warmup" mode
* and not really process calls already (but it will signify connections
@@ -1222,6 +1270,20 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
RegisterNodeSignals(GetNodeSignals());
// sanitize comments per BIP-0014, format user agent and check total size
std::vector<string> uacomments;
BOOST_FOREACH(string cmt, mapMultiArgs["-uacomment"])
{
if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT))
return InitError(strprintf("User Agent comment (%s) contains unsafe characters.", cmt));
uacomments.push_back(SanitizeString(cmt, SAFE_CHARS_UA_COMMENT));
}
strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments);
if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) {
return InitError(strprintf("Total length of network version string %i exceeds maximum of %i characters. Reduce the number and/or size of uacomments.",
strSubVersion.size(), MAX_SUBVERSION_LENGTH));
}
if (mapArgs.count("-onlynet")) {
std::set<enum Network> nets;
BOOST_FOREACH(const std::string& snet, mapMultiArgs["-onlynet"]) {
@@ -1432,6 +1494,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
bool clearWitnessCaches = false;
bool fLoaded = false;
while (!fLoaded) {
bool fReset = fReindex;
@@ -1494,7 +1558,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (!fReindex) {
uiInterface.InitMessage(_("Rewinding blocks if needed..."));
if (!RewindBlockIndex(chainparams)) {
if (!RewindBlockIndex(chainparams, clearWitnessCaches)) {
strLoadError = _("Unable to rewind the database to a pre-upgrade state. You will need to redownload the blockchain");
break;
}
@@ -1628,6 +1692,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
pwalletMain->SetMaxVersion(nMaxVersion);
}
if (!pwalletMain->HaveHDSeed())
{
// generate a new HD seed
pwalletMain->GenerateNewSeed();
}
if (fFirstRun)
{
// Create new keyUser and set as default key
@@ -1647,7 +1717,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
RegisterValidationInterface(pwalletMain);
CBlockIndex *pindexRescan = chainActive.Tip();
if (GetBoolArg("-rescan", false))
if (clearWitnessCaches || GetBoolArg("-rescan", false))
{
pwalletMain->ClearNoteWitnessCache();
pindexRescan = chainActive.Genesis();
@@ -1717,9 +1787,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
bool minerAddressInLocalWallet = false;
if (pwalletMain) {
// Address has alreday been validated
CBitcoinAddress addr(mapArgs["-mineraddress"]);
CKeyID keyID;
addr.GetKeyID(keyID);
CTxDestination addr = DecodeDestination(mapArgs["-mineraddress"]);
CKeyID keyID = boost::get<CKeyID>(addr);
minerAddressInLocalWallet = pwalletMain->HaveKey(keyID);
}
if (GetBoolArg("-minetolocalwallet", true) && !minerAddressInLocalWallet) {

View File

@@ -307,7 +307,7 @@ CExtPubKey CExtKey::Neuter() const {
return ret;
}
void CExtKey::Encode(unsigned char code[74]) const {
void CExtKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
code[0] = nDepth;
memcpy(code+1, vchFingerprint, 4);
code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
@@ -318,12 +318,12 @@ void CExtKey::Encode(unsigned char code[74]) const {
memcpy(code+42, key.begin(), 32);
}
void CExtKey::Decode(const unsigned char code[74]) {
void CExtKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) {
nDepth = code[0];
memcpy(vchFingerprint, code+1, 4);
nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8];
memcpy(chaincode.begin(), code+9, 32);
key.Set(code+42, code+74, true);
key.Set(code+42, code+BIP32_EXTKEY_SIZE, true);
}
bool ECC_InitSanityCheck() {

View File

@@ -170,11 +170,28 @@ struct CExtKey {
a.chaincode == b.chaincode && a.key == b.key;
}
void Encode(unsigned char code[74]) const;
void Decode(const unsigned char code[74]);
void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const;
void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
bool Derive(CExtKey& out, unsigned int nChild) const;
CExtPubKey Neuter() const;
void SetMaster(const unsigned char* seed, unsigned int nSeedLen);
template <typename Stream>
void Serialize(Stream& s) const
{
unsigned int len = BIP32_EXTKEY_SIZE;
::WriteCompactSize(s, len);
unsigned char code[BIP32_EXTKEY_SIZE];
Encode(code);
s.write((const char *)&code[0], len);
}
template <typename Stream>
void Unserialize(Stream& s)
{
unsigned int len = ::ReadCompactSize(s);
unsigned char code[BIP32_EXTKEY_SIZE];
s.read((char *)&code[0], len);
Decode(code);
}
};
/** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */

377
src/key_io.cpp Normal file
View File

@@ -0,0 +1,377 @@
// Copyright (c) 2014-2016 The Bitcoin Core developers
// Copyright (c) 2016-2018 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key_io.h>
#include <base58.h>
#include <bech32.h>
#include <script/script.h>
#include <utilstrencodings.h>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <assert.h>
#include <string.h>
#include <algorithm>
namespace
{
class DestinationEncoder : public boost::static_visitor<std::string>
{
private:
const CChainParams& m_params;
public:
DestinationEncoder(const CChainParams& params) : m_params(params) {}
std::string operator()(const CKeyID& id) const
{
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
data.insert(data.end(), id.begin(), id.end());
return EncodeBase58Check(data);
}
std::string operator()(const CScriptID& id) const
{
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
data.insert(data.end(), id.begin(), id.end());
return EncodeBase58Check(data);
}
std::string operator()(const CNoDestination& no) const { return {}; }
};
CTxDestination DecodeDestination(const std::string& str, const CChainParams& params)
{
std::vector<unsigned char> data;
uint160 hash;
if (DecodeBase58Check(str, data)) {
// base58-encoded Bitcoin addresses.
// Public-key-hash-addresses have version 0 (or 111 testnet).
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
return CKeyID(hash);
}
// Script-hash-addresses have version 5 (or 196 testnet).
// The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
return CScriptID(hash);
}
}
return CNoDestination();
}
class PaymentAddressEncoder : public boost::static_visitor<std::string>
{
private:
const CChainParams& m_params;
public:
PaymentAddressEncoder(const CChainParams& params) : m_params(params) {}
std::string operator()(const libzcash::SproutPaymentAddress& zaddr) const
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << zaddr;
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
data.insert(data.end(), ss.begin(), ss.end());
return EncodeBase58Check(data);
}
std::string operator()(const libzcash::SaplingPaymentAddress& zaddr) const
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << zaddr;
// ConvertBits requires unsigned char, but CDataStream uses char
std::vector<unsigned char> seraddr(ss.begin(), ss.end());
std::vector<unsigned char> data;
// See calculation comment below
data.reserve((seraddr.size() * 8 + 4) / 5);
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, seraddr.begin(), seraddr.end());
return bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS), data);
}
std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
};
class ViewingKeyEncoder : public boost::static_visitor<std::string>
{
private:
const CChainParams& m_params;
public:
ViewingKeyEncoder(const CChainParams& params) : m_params(params) {}
std::string operator()(const libzcash::SproutViewingKey& vk) const
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << vk;
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCVIEWING_KEY);
data.insert(data.end(), ss.begin(), ss.end());
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
}
std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
};
class SpendingKeyEncoder : public boost::static_visitor<std::string>
{
private:
const CChainParams& m_params;
public:
SpendingKeyEncoder(const CChainParams& params) : m_params(params) {}
std::string operator()(const libzcash::SproutSpendingKey& zkey) const
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << zkey;
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCSPENDING_KEY);
data.insert(data.end(), ss.begin(), ss.end());
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
}
std::string operator()(const libzcash::SaplingExtendedSpendingKey& zkey) const
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << zkey;
// ConvertBits requires unsigned char, but CDataStream uses char
std::vector<unsigned char> serkey(ss.begin(), ss.end());
std::vector<unsigned char> data;
// See calculation comment below
data.reserve((serkey.size() * 8 + 4) / 5);
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end());
std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY), data);
memory_cleanse(serkey.data(), serkey.size());
memory_cleanse(data.data(), data.size());
return ret;
}
std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
};
// Sizes of SaplingPaymentAddress and SaplingSpendingKey after
// ConvertBits<8, 5, true>(). The calculations below take the
// regular serialized size in bytes, convert to bits, and then
// perform ceiling division to get the number of 5-bit clusters.
const size_t ConvertedSaplingPaymentAddressSize = ((32 + 11) * 8 + 4) / 5;
const size_t ConvertedSaplingExtendedSpendingKeySize = (ZIP32_XSK_SIZE * 8 + 4) / 5;
} // namespace
CKey DecodeSecret(const std::string& str)
{
CKey key;
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
bool compressed = data.size() == 33 + privkey_prefix.size();
key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
}
}
memory_cleanse(data.data(), data.size());
return key;
}
std::string EncodeSecret(const CKey& key)
{
assert(key.IsValid());
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
data.insert(data.end(), key.begin(), key.end());
if (key.IsCompressed()) {
data.push_back(1);
}
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
}
CExtPubKey DecodeExtPubKey(const std::string& str)
{
CExtPubKey key;
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
key.Decode(data.data() + prefix.size());
}
}
return key;
}
std::string EncodeExtPubKey(const CExtPubKey& key)
{
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
size_t size = data.size();
data.resize(size + BIP32_EXTKEY_SIZE);
key.Encode(data.data() + size);
std::string ret = EncodeBase58Check(data);
return ret;
}
CExtKey DecodeExtKey(const std::string& str)
{
CExtKey key;
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
key.Decode(data.data() + prefix.size());
}
}
return key;
}
std::string EncodeExtKey(const CExtKey& key)
{
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
size_t size = data.size();
data.resize(size + BIP32_EXTKEY_SIZE);
key.Encode(data.data() + size);
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
}
std::string EncodeDestination(const CTxDestination& dest)
{
return boost::apply_visitor(DestinationEncoder(Params()), dest);
}
CTxDestination DecodeDestination(const std::string& str)
{
return DecodeDestination(str, Params());
}
bool IsValidDestinationString(const std::string& str, const CChainParams& params)
{
return IsValidDestination(DecodeDestination(str, params));
}
bool IsValidDestinationString(const std::string& str)
{
return IsValidDestinationString(str, Params());
}
std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr)
{
return boost::apply_visitor(PaymentAddressEncoder(Params()), zaddr);
}
libzcash::PaymentAddress DecodePaymentAddress(const std::string& str)
{
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char>& zaddr_prefix = Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
if ((data.size() == libzcash::SerializedSproutPaymentAddressSize + zaddr_prefix.size()) &&
std::equal(zaddr_prefix.begin(), zaddr_prefix.end(), data.begin())) {
CSerializeData serialized(data.begin() + zaddr_prefix.size(), data.end());
CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
libzcash::SproutPaymentAddress ret;
ss >> ret;
return ret;
}
}
data.clear();
auto bech = bech32::Decode(str);
bool allowSapling = Params().NetworkIDString() == "regtest" || (
Params().NetworkIDString() == "test" &&
GetBoolArg("-experimentalfeatures", false) &&
GetBoolArg("-developersapling", false));
if (allowSapling && bech.first == Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS) &&
bech.second.size() == ConvertedSaplingPaymentAddressSize) {
// Bech32 decoding
data.reserve((bech.second.size() * 5) / 8);
if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
libzcash::SaplingPaymentAddress ret;
ss >> ret;
return ret;
}
}
return libzcash::InvalidEncoding();
}
bool IsValidPaymentAddressString(const std::string& str) {
return IsValidPaymentAddress(DecodePaymentAddress(str));
}
std::string EncodeViewingKey(const libzcash::ViewingKey& vk)
{
return boost::apply_visitor(ViewingKeyEncoder(Params()), vk);
}
libzcash::ViewingKey DecodeViewingKey(const std::string& str)
{
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char>& vk_prefix = Params().Base58Prefix(CChainParams::ZCVIEWING_KEY);
if ((data.size() == libzcash::SerializedSproutViewingKeySize + vk_prefix.size()) &&
std::equal(vk_prefix.begin(), vk_prefix.end(), data.begin())) {
CSerializeData serialized(data.begin() + vk_prefix.size(), data.end());
CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
libzcash::SproutViewingKey ret;
ss >> ret;
memory_cleanse(serialized.data(), serialized.size());
memory_cleanse(data.data(), data.size());
return ret;
}
}
memory_cleanse(data.data(), data.size());
return libzcash::InvalidEncoding();
}
std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey)
{
return boost::apply_visitor(SpendingKeyEncoder(Params()), zkey);
}
libzcash::SpendingKey DecodeSpendingKey(const std::string& str)
{
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char>& zkey_prefix = Params().Base58Prefix(CChainParams::ZCSPENDING_KEY);
if ((data.size() == libzcash::SerializedSproutSpendingKeySize + zkey_prefix.size()) &&
std::equal(zkey_prefix.begin(), zkey_prefix.end(), data.begin())) {
CSerializeData serialized(data.begin() + zkey_prefix.size(), data.end());
CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
libzcash::SproutSpendingKey ret;
ss >> ret;
memory_cleanse(serialized.data(), serialized.size());
memory_cleanse(data.data(), data.size());
return ret;
}
}
data.clear();
auto bech = bech32::Decode(str);
bool allowSapling = Params().NetworkIDString() == "regtest" || (
Params().NetworkIDString() == "test" &&
GetBoolArg("-experimentalfeatures", false) &&
GetBoolArg("-developersapling", false));
if (allowSapling && bech.first == Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY) &&
bech.second.size() == ConvertedSaplingExtendedSpendingKeySize) {
// Bech32 decoding
data.reserve((bech.second.size() * 5) / 8);
if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
libzcash::SaplingExtendedSpendingKey ret;
ss >> ret;
memory_cleanse(data.data(), data.size());
return ret;
}
}
memory_cleanse(data.data(), data.size());
return libzcash::InvalidEncoding();
}

42
src/key_io.h Normal file
View File

@@ -0,0 +1,42 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2016-2018 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KEYIO_H
#define BITCOIN_KEYIO_H
#include <chainparams.h>
#include <key.h>
#include <pubkey.h>
#include <script/standard.h>
#include <zcash/Address.hpp>
#include <zcash/zip32.h>
#include <string>
CKey DecodeSecret(const std::string& str);
std::string EncodeSecret(const CKey& key);
CExtKey DecodeExtKey(const std::string& str);
std::string EncodeExtKey(const CExtKey& extkey);
CExtPubKey DecodeExtPubKey(const std::string& str);
std::string EncodeExtPubKey(const CExtPubKey& extpubkey);
std::string EncodeDestination(const CTxDestination& dest);
CTxDestination DecodeDestination(const std::string& str);
bool IsValidDestinationString(const std::string& str);
bool IsValidDestinationString(const std::string& str, const CChainParams& params);
std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr);
libzcash::PaymentAddress DecodePaymentAddress(const std::string& str);
bool IsValidPaymentAddressString(const std::string& str);
std::string EncodeViewingKey(const libzcash::ViewingKey& vk);
libzcash::ViewingKey DecodeViewingKey(const std::string& str);
std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey);
libzcash::SpendingKey DecodeSpendingKey(const std::string& str);
#endif // BITCOIN_KEYIO_H

View File

@@ -23,6 +23,35 @@ bool CKeyStore::AddKey(const CKey &key) {
return AddKeyPubKey(key, key.GetPubKey());
}
bool CBasicKeyStore::SetHDSeed(const HDSeed& seed)
{
LOCK(cs_SpendingKeyStore);
if (!hdSeed.IsNull()) {
// Don't allow an existing seed to be changed. We can maybe relax this
// restriction later once we have worked out the UX implications.
return false;
}
hdSeed = seed;
return true;
}
bool CBasicKeyStore::HaveHDSeed() const
{
LOCK(cs_SpendingKeyStore);
return !hdSeed.IsNull();
}
bool CBasicKeyStore::GetHDSeed(HDSeed& seedOut) const
{
LOCK(cs_SpendingKeyStore);
if (hdSeed.IsNull()) {
return false;
} else {
seedOut = hdSeed;
return true;
}
}
bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
{
LOCK(cs_KeyStore);
@@ -84,45 +113,116 @@ bool CBasicKeyStore::HaveWatchOnly() const
return (!setWatchOnly.empty());
}
bool CBasicKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk)
bool CBasicKeyStore::AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk)
{
LOCK(cs_SpendingKeyStore);
auto address = sk.address();
mapSpendingKeys[address] = sk;
mapSproutSpendingKeys[address] = sk;
mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(sk.receiving_key())));
return true;
}
bool CBasicKeyStore::AddViewingKey(const libzcash::ViewingKey &vk)
//! Sapling
bool CBasicKeyStore::AddSaplingSpendingKey(
const libzcash::SaplingExtendedSpendingKey &sk,
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr)
{
LOCK(cs_SpendingKeyStore);
auto fvk = sk.expsk.full_viewing_key();
// if SaplingFullViewingKey is not in SaplingFullViewingKeyMap, add it
if (!AddSaplingFullViewingKey(fvk, defaultAddr)){
return false;
}
mapSaplingSpendingKeys[fvk] = sk;
return true;
}
bool CBasicKeyStore::AddSproutViewingKey(const libzcash::SproutViewingKey &vk)
{
LOCK(cs_SpendingKeyStore);
auto address = vk.address();
mapViewingKeys[address] = vk;
mapSproutViewingKeys[address] = vk;
mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(vk.sk_enc)));
return true;
}
bool CBasicKeyStore::RemoveViewingKey(const libzcash::ViewingKey &vk)
bool CBasicKeyStore::AddSaplingFullViewingKey(
const libzcash::SaplingFullViewingKey &fvk,
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr)
{
LOCK(cs_SpendingKeyStore);
mapViewingKeys.erase(vk.address());
auto ivk = fvk.in_viewing_key();
mapSaplingFullViewingKeys[ivk] = fvk;
if (defaultAddr) {
// Add defaultAddr -> SaplingIncomingViewing to SaplingIncomingViewingKeyMap
mapSaplingIncomingViewingKeys[defaultAddr.get()] = ivk;
}
return true;
}
bool CBasicKeyStore::HaveViewingKey(const libzcash::PaymentAddress &address) const
bool CBasicKeyStore::RemoveSproutViewingKey(const libzcash::SproutViewingKey &vk)
{
LOCK(cs_SpendingKeyStore);
return mapViewingKeys.count(address) > 0;
mapSproutViewingKeys.erase(vk.address());
return true;
}
bool CBasicKeyStore::GetViewingKey(const libzcash::PaymentAddress &address,
libzcash::ViewingKey &vkOut) const
bool CBasicKeyStore::HaveSproutViewingKey(const libzcash::SproutPaymentAddress &address) const
{
LOCK(cs_SpendingKeyStore);
ViewingKeyMap::const_iterator mi = mapViewingKeys.find(address);
if (mi != mapViewingKeys.end()) {
return mapSproutViewingKeys.count(address) > 0;
}
bool CBasicKeyStore::HaveSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk) const
{
LOCK(cs_SpendingKeyStore);
return mapSaplingFullViewingKeys.count(ivk) > 0;
}
bool CBasicKeyStore::HaveSaplingIncomingViewingKey(const libzcash::SaplingPaymentAddress &addr) const
{
LOCK(cs_SpendingKeyStore);
return mapSaplingIncomingViewingKeys.count(addr) > 0;
}
bool CBasicKeyStore::GetSproutViewingKey(
const libzcash::SproutPaymentAddress &address,
libzcash::SproutViewingKey &vkOut) const
{
LOCK(cs_SpendingKeyStore);
SproutViewingKeyMap::const_iterator mi = mapSproutViewingKeys.find(address);
if (mi != mapSproutViewingKeys.end()) {
vkOut = mi->second;
return true;
}
return false;
}
bool CBasicKeyStore::GetSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk,
libzcash::SaplingFullViewingKey &fvkOut) const
{
LOCK(cs_SpendingKeyStore);
SaplingFullViewingKeyMap::const_iterator mi = mapSaplingFullViewingKeys.find(ivk);
if (mi != mapSaplingFullViewingKeys.end()) {
fvkOut = mi->second;
return true;
}
return false;
}
bool CBasicKeyStore::GetSaplingIncomingViewingKey(const libzcash::SaplingPaymentAddress &addr,
libzcash::SaplingIncomingViewingKey &ivkOut) const
{
LOCK(cs_SpendingKeyStore);
SaplingIncomingViewingKeyMap::const_iterator mi = mapSaplingIncomingViewingKeys.find(addr);
if (mi != mapSaplingIncomingViewingKeys.end()) {
ivkOut = mi->second;
return true;
}
return false;
}

View File

@@ -14,6 +14,7 @@
#include "sync.h"
#include "zcash/Address.hpp"
#include "zcash/NoteEncryption.hpp"
#include "zcash/zip32.h"
#include <boost/signals2/signal.hpp>
#include <boost/variant.hpp>
@@ -28,6 +29,12 @@ protected:
public:
virtual ~CKeyStore() {}
//! Set the HD seed for this keystore
virtual bool SetHDSeed(const HDSeed& seed) =0;
virtual bool HaveHDSeed() const =0;
//! Get the HD seed for this keystore
virtual bool GetHDSeed(HDSeed& seedOut) const =0;
//! Add a key to the store.
virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) =0;
virtual bool AddKey(const CKey &key);
@@ -50,39 +57,82 @@ public:
virtual bool HaveWatchOnly() const =0;
//! Add a spending key to the store.
virtual bool AddSpendingKey(const libzcash::SpendingKey &sk) =0;
virtual bool AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk) =0;
//! Check whether a spending key corresponding to a given payment address is present in the store.
virtual bool HaveSpendingKey(const libzcash::PaymentAddress &address) const =0;
virtual bool GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey& skOut) const =0;
virtual void GetPaymentAddresses(std::set<libzcash::PaymentAddress> &setAddress) const =0;
virtual bool HaveSproutSpendingKey(const libzcash::SproutPaymentAddress &address) const =0;
virtual bool GetSproutSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey& skOut) const =0;
virtual void GetSproutPaymentAddresses(std::set<libzcash::SproutPaymentAddress> &setAddress) const =0;
//! Add a Sapling spending key to the store.
virtual bool AddSaplingSpendingKey(
const libzcash::SaplingExtendedSpendingKey &sk,
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none) =0;
//! Check whether a Sapling spending key corresponding to a given Sapling viewing key is present in the store.
virtual bool HaveSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk) const =0;
virtual bool GetSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, libzcash::SaplingExtendedSpendingKey& skOut) const =0;
//! Support for viewing keys
virtual bool AddViewingKey(const libzcash::ViewingKey &vk) =0;
virtual bool RemoveViewingKey(const libzcash::ViewingKey &vk) =0;
virtual bool HaveViewingKey(const libzcash::PaymentAddress &address) const =0;
virtual bool GetViewingKey(const libzcash::PaymentAddress &address, libzcash::ViewingKey& vkOut) const =0;
//! Support for Sapling full viewing keys
virtual bool AddSaplingFullViewingKey(
const libzcash::SaplingFullViewingKey &fvk,
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none) =0;
virtual bool HaveSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk) const =0;
virtual bool GetSaplingFullViewingKey(
const libzcash::SaplingIncomingViewingKey &ivk,
libzcash::SaplingFullViewingKey& fvkOut) const =0;
//! Sapling incoming viewing keys
virtual bool HaveSaplingIncomingViewingKey(const libzcash::SaplingPaymentAddress &addr) const =0;
virtual bool GetSaplingIncomingViewingKey(
const libzcash::SaplingPaymentAddress &addr,
libzcash::SaplingIncomingViewingKey& ivkOut) const =0;
virtual void GetSaplingPaymentAddresses(std::set<libzcash::SaplingPaymentAddress> &setAddress) const =0;
//! Support for Sprout viewing keys
virtual bool AddSproutViewingKey(const libzcash::SproutViewingKey &vk) =0;
virtual bool RemoveSproutViewingKey(const libzcash::SproutViewingKey &vk) =0;
virtual bool HaveSproutViewingKey(const libzcash::SproutPaymentAddress &address) const =0;
virtual bool GetSproutViewingKey(
const libzcash::SproutPaymentAddress &address,
libzcash::SproutViewingKey& vkOut) const =0;
};
typedef std::map<CKeyID, CKey> KeyMap;
typedef std::map<CScriptID, CScript > ScriptMap;
typedef std::set<CScript> WatchOnlySet;
typedef std::map<libzcash::PaymentAddress, libzcash::SpendingKey> SpendingKeyMap;
typedef std::map<libzcash::PaymentAddress, libzcash::ViewingKey> ViewingKeyMap;
typedef std::map<libzcash::PaymentAddress, ZCNoteDecryption> NoteDecryptorMap;
typedef std::map<libzcash::SproutPaymentAddress, libzcash::SproutSpendingKey> SproutSpendingKeyMap;
typedef std::map<libzcash::SproutPaymentAddress, libzcash::SproutViewingKey> SproutViewingKeyMap;
typedef std::map<libzcash::SproutPaymentAddress, ZCNoteDecryption> NoteDecryptorMap;
// Full viewing key has equivalent functionality to a transparent address
// When encrypting wallet, encrypt SaplingSpendingKeyMap, while leaving SaplingFullViewingKeyMap unencrypted
typedef std::map<libzcash::SaplingFullViewingKey, libzcash::SaplingExtendedSpendingKey> SaplingSpendingKeyMap;
typedef std::map<libzcash::SaplingIncomingViewingKey, libzcash::SaplingFullViewingKey> SaplingFullViewingKeyMap;
// Only maps from default addresses to ivk, may need to be reworked when adding diversified addresses.
typedef std::map<libzcash::SaplingPaymentAddress, libzcash::SaplingIncomingViewingKey> SaplingIncomingViewingKeyMap;
/** Basic key store, that keeps keys in an address->secret map */
class CBasicKeyStore : public CKeyStore
{
protected:
HDSeed hdSeed;
KeyMap mapKeys;
ScriptMap mapScripts;
WatchOnlySet setWatchOnly;
SpendingKeyMap mapSpendingKeys;
ViewingKeyMap mapViewingKeys;
SproutSpendingKeyMap mapSproutSpendingKeys;
SproutViewingKeyMap mapSproutViewingKeys;
NoteDecryptorMap mapNoteDecryptors;
SaplingSpendingKeyMap mapSaplingSpendingKeys;
SaplingFullViewingKeyMap mapSaplingFullViewingKeys;
SaplingIncomingViewingKeyMap mapSaplingIncomingViewingKeys;
public:
bool SetHDSeed(const HDSeed& seed);
bool HaveHDSeed() const;
bool GetHDSeed(HDSeed& seedOut) const;
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
bool HaveKey(const CKeyID &address) const
{
@@ -128,22 +178,22 @@ public:
virtual bool HaveWatchOnly(const CScript &dest) const;
virtual bool HaveWatchOnly() const;
bool AddSpendingKey(const libzcash::SpendingKey &sk);
bool HaveSpendingKey(const libzcash::PaymentAddress &address) const
bool AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk);
bool HaveSproutSpendingKey(const libzcash::SproutPaymentAddress &address) const
{
bool result;
{
LOCK(cs_SpendingKeyStore);
result = (mapSpendingKeys.count(address) > 0);
result = (mapSproutSpendingKeys.count(address) > 0);
}
return result;
}
bool GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey &skOut) const
bool GetSproutSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey &skOut) const
{
{
LOCK(cs_SpendingKeyStore);
SpendingKeyMap::const_iterator mi = mapSpendingKeys.find(address);
if (mi != mapSpendingKeys.end())
SproutSpendingKeyMap::const_iterator mi = mapSproutSpendingKeys.find(address);
if (mi != mapSproutSpendingKeys.end())
{
skOut = mi->second;
return true;
@@ -151,7 +201,7 @@ public:
}
return false;
}
bool GetNoteDecryptor(const libzcash::PaymentAddress &address, ZCNoteDecryption &decOut) const
bool GetNoteDecryptor(const libzcash::SproutPaymentAddress &address, ZCNoteDecryption &decOut) const
{
{
LOCK(cs_SpendingKeyStore);
@@ -164,34 +214,93 @@ public:
}
return false;
}
void GetPaymentAddresses(std::set<libzcash::PaymentAddress> &setAddress) const
void GetSproutPaymentAddresses(std::set<libzcash::SproutPaymentAddress> &setAddress) const
{
setAddress.clear();
{
LOCK(cs_SpendingKeyStore);
SpendingKeyMap::const_iterator mi = mapSpendingKeys.begin();
while (mi != mapSpendingKeys.end())
SproutSpendingKeyMap::const_iterator mi = mapSproutSpendingKeys.begin();
while (mi != mapSproutSpendingKeys.end())
{
setAddress.insert((*mi).first);
mi++;
}
ViewingKeyMap::const_iterator mvi = mapViewingKeys.begin();
while (mvi != mapViewingKeys.end())
SproutViewingKeyMap::const_iterator mvi = mapSproutViewingKeys.begin();
while (mvi != mapSproutViewingKeys.end())
{
setAddress.insert((*mvi).first);
mvi++;
}
}
}
//! Sapling
bool AddSaplingSpendingKey(
const libzcash::SaplingExtendedSpendingKey &sk,
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none);
bool HaveSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk) const
{
bool result;
{
LOCK(cs_SpendingKeyStore);
result = (mapSaplingSpendingKeys.count(fvk) > 0);
}
return result;
}
bool GetSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, libzcash::SaplingExtendedSpendingKey &skOut) const
{
{
LOCK(cs_SpendingKeyStore);
SaplingSpendingKeyMap::const_iterator mi = mapSaplingSpendingKeys.find(fvk);
if (mi != mapSaplingSpendingKeys.end())
{
skOut = mi->second;
return true;
}
}
return false;
}
virtual bool AddViewingKey(const libzcash::ViewingKey &vk);
virtual bool RemoveViewingKey(const libzcash::ViewingKey &vk);
virtual bool HaveViewingKey(const libzcash::PaymentAddress &address) const;
virtual bool GetViewingKey(const libzcash::PaymentAddress &address, libzcash::ViewingKey& vkOut) const;
virtual bool AddSaplingFullViewingKey(
const libzcash::SaplingFullViewingKey &fvk,
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none);
virtual bool HaveSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk) const;
virtual bool GetSaplingFullViewingKey(
const libzcash::SaplingIncomingViewingKey &ivk,
libzcash::SaplingFullViewingKey& fvkOut) const;
virtual bool HaveSaplingIncomingViewingKey(const libzcash::SaplingPaymentAddress &addr) const;
virtual bool GetSaplingIncomingViewingKey(
const libzcash::SaplingPaymentAddress &addr,
libzcash::SaplingIncomingViewingKey& ivkOut) const;
void GetSaplingPaymentAddresses(std::set<libzcash::SaplingPaymentAddress> &setAddress) const
{
setAddress.clear();
{
LOCK(cs_SpendingKeyStore);
auto mi = mapSaplingIncomingViewingKeys.begin();
while (mi != mapSaplingIncomingViewingKeys.end())
{
setAddress.insert((*mi).first);
mi++;
}
}
}
virtual bool AddSproutViewingKey(const libzcash::SproutViewingKey &vk);
virtual bool RemoveSproutViewingKey(const libzcash::SproutViewingKey &vk);
virtual bool HaveSproutViewingKey(const libzcash::SproutPaymentAddress &address) const;
virtual bool GetSproutViewingKey(
const libzcash::SproutPaymentAddress &address,
libzcash::SproutViewingKey& vkOut) const;
};
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;
typedef std::map<libzcash::SproutPaymentAddress, std::vector<unsigned char> > CryptedSproutSpendingKeyMap;
//! Sapling
typedef std::map<libzcash::SaplingFullViewingKey, std::vector<unsigned char> > CryptedSaplingSpendingKeyMap;
#endif // BITCOIN_KEYSTORE_H

View File

@@ -2,12 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
#include "clientversion.h"
#include "coins.h"
#include "consensus/consensus.h"
#include "consensus/upgrades.h"
#include "core_io.h"
#include "key_io.h"
#include "keystore.h"
#include "primitives/transaction.h"
#include "script/script.h"
@@ -38,9 +38,14 @@ uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256
}
static bool fCreateBlank;
static map<string,UniValue> registers;
static std::map<std::string,UniValue> registers;
static const int CONTINUE_EXECUTION=-1;
static bool AppInitRawTx(int argc, char* argv[])
//
// This function returns either one of EXIT_ codes when it's expected to stop the process or
// CONTINUE_EXECUTION when it's expected to continue further.
//
static int AppInitRawTx(int argc, char* argv[])
{
//
// Parameters
@@ -79,7 +84,7 @@ static bool AppInitRawTx(int argc, char* argv[])
strUsage = HelpMessageGroup(_("Commands:"));
strUsage += HelpMessageOpt("delin=N", _("Delete input N from TX"));
strUsage += HelpMessageOpt("delout=N", _("Delete output N from TX"));
strUsage += HelpMessageOpt("in=TXID:VOUT", _("Add input to TX"));
strUsage += HelpMessageOpt("in=TXID:VOUT(:SEQUENCE_NUMBER)", _("Add input to TX"));
strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N"));
strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
@@ -96,57 +101,61 @@ static bool AppInitRawTx(int argc, char* argv[])
strUsage += HelpMessageOpt("set=NAME:JSON-STRING", _("Set register NAME to given JSON-STRING"));
fprintf(stdout, "%s", strUsage.c_str());
return false;
if (argc < 2) {
fprintf(stderr, "Error: too few parameters\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
return true;
return CONTINUE_EXECUTION;
}
static void RegisterSetJson(const string& key, const string& rawJson)
static void RegisterSetJson(const std::string& key, const std::string& rawJson)
{
UniValue val;
if (!val.read(rawJson)) {
string strErr = "Cannot parse JSON for key " + key;
throw runtime_error(strErr);
std::string strErr = "Cannot parse JSON for key " + key;
throw std::runtime_error(strErr);
}
registers[key] = val;
}
static void RegisterSet(const string& strInput)
static void RegisterSet(const std::string& strInput)
{
// separate NAME:VALUE in string
size_t pos = strInput.find(':');
if ((pos == string::npos) ||
if ((pos == std::string::npos) ||
(pos == 0) ||
(pos == (strInput.size() - 1)))
throw runtime_error("Register input requires NAME:VALUE");
throw std::runtime_error("Register input requires NAME:VALUE");
string key = strInput.substr(0, pos);
string valStr = strInput.substr(pos + 1, string::npos);
std::string key = strInput.substr(0, pos);
std::string valStr = strInput.substr(pos + 1, std::string::npos);
RegisterSetJson(key, valStr);
}
static void RegisterLoad(const string& strInput)
static void RegisterLoad(const std::string& strInput)
{
// separate NAME:FILENAME in string
size_t pos = strInput.find(':');
if ((pos == string::npos) ||
if ((pos == std::string::npos) ||
(pos == 0) ||
(pos == (strInput.size() - 1)))
throw runtime_error("Register load requires NAME:FILENAME");
throw std::runtime_error("Register load requires NAME:FILENAME");
string key = strInput.substr(0, pos);
string filename = strInput.substr(pos + 1, string::npos);
std::string key = strInput.substr(0, pos);
std::string filename = strInput.substr(pos + 1, std::string::npos);
FILE *f = fopen(filename.c_str(), "r");
if (!f) {
string strErr = "Cannot open file " + filename;
throw runtime_error(strErr);
std::string strErr = "Cannot open file " + filename;
throw std::runtime_error(strErr);
}
// load file chunks into one big buffer
string valStr;
std::string valStr;
while ((!feof(f)) && (!ferror(f))) {
char buf[4096];
int bread = fread(buf, 1, sizeof(buf), f);
@@ -160,115 +169,119 @@ static void RegisterLoad(const string& strInput)
fclose(f);
if (error) {
string strErr = "Error reading file " + filename;
throw runtime_error(strErr);
std::string strErr = "Error reading file " + filename;
throw std::runtime_error(strErr);
}
// evaluate as JSON buffer register
RegisterSetJson(key, valStr);
}
static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal)
static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
{
int64_t newVersion = atoi64(cmdVal);
if (newVersion < CTransaction::SPROUT_MIN_CURRENT_VERSION || newVersion > CTransaction::SPROUT_MAX_CURRENT_VERSION)
throw runtime_error("Invalid TX version requested");
throw std::runtime_error("Invalid TX version requested");
tx.nVersion = (int) newVersion;
}
static void MutateTxExpiry(CMutableTransaction& tx, const string& cmdVal)
static void MutateTxExpiry(CMutableTransaction& tx, const std::string& cmdVal)
{
int64_t newExpiry = atoi64(cmdVal);
if (newExpiry >= TX_EXPIRY_HEIGHT_THRESHOLD) {
throw runtime_error("Invalid TX expiry requested");
throw std::runtime_error("Invalid TX expiry requested");
}
tx.nExpiryHeight = (int) newExpiry;
}
static void MutateTxLocktime(CMutableTransaction& tx, const string& cmdVal)
static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
{
int64_t newLocktime = atoi64(cmdVal);
if (newLocktime < 0LL || newLocktime > 0xffffffffLL)
throw runtime_error("Invalid TX locktime requested");
throw std::runtime_error("Invalid TX locktime requested");
tx.nLockTime = (unsigned int) newLocktime;
}
static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput)
static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)
{
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
// separate TXID:VOUT in string
size_t pos = strInput.find(':');
if ((pos == string::npos) ||
(pos == 0) ||
(pos == (strInput.size() - 1)))
throw runtime_error("TX input missing separator");
if (vStrInputParts.size()<2)
throw std::runtime_error("TX input missing separator");
// extract and validate TXID
string strTxid = strInput.substr(0, pos);
std::string strTxid = vStrInputParts[0];
if ((strTxid.size() != 64) || !IsHex(strTxid))
throw runtime_error("invalid TX input txid");
throw std::runtime_error("invalid TX input txid");
uint256 txid(uint256S(strTxid));
static const unsigned int minTxOutSz = 9;
static const unsigned int maxVout = MAX_BLOCK_SIZE / minTxOutSz;
// extract and validate vout
string strVout = strInput.substr(pos + 1, string::npos);
std::string strVout = vStrInputParts[1];
int vout = atoi(strVout);
if ((vout < 0) || (vout > (int)maxVout))
throw runtime_error("invalid TX input vout");
throw std::runtime_error("invalid TX input vout");
// extract the optional sequence number
uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max();
if (vStrInputParts.size() > 2)
nSequenceIn = atoi(vStrInputParts[2]);
// append to transaction input list
CTxIn txin(txid, vout);
CTxIn txin(txid, vout, CScript(), nSequenceIn);
tx.vin.push_back(txin);
}
static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput)
static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput)
{
// separate VALUE:ADDRESS in string
size_t pos = strInput.find(':');
if ((pos == string::npos) ||
if ((pos == std::string::npos) ||
(pos == 0) ||
(pos == (strInput.size() - 1)))
throw runtime_error("TX output missing separator");
throw std::runtime_error("TX output missing separator");
// extract and validate VALUE
string strValue = strInput.substr(0, pos);
std::string strValue = strInput.substr(0, pos);
CAmount value;
if (!ParseMoney(strValue, value))
throw runtime_error("invalid TX output value");
throw std::runtime_error("invalid TX output value");
// extract and validate ADDRESS
string strAddr = strInput.substr(pos + 1, string::npos);
CBitcoinAddress addr(strAddr);
if (!addr.IsValid())
throw runtime_error("invalid TX output address");
// build standard output script via GetScriptForDestination()
CScript scriptPubKey = GetScriptForDestination(addr.Get());
std::string strAddr = strInput.substr(pos + 1, std::string::npos);
CTxDestination destination = DecodeDestination(strAddr);
if (!IsValidDestination(destination)) {
throw std::runtime_error("invalid TX output address");
}
CScript scriptPubKey = GetScriptForDestination(destination);
// construct TxOut, append to transaction output list
CTxOut txout(value, scriptPubKey);
tx.vout.push_back(txout);
}
static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput)
static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput)
{
// separate VALUE:SCRIPT in string
size_t pos = strInput.find(':');
if ((pos == string::npos) ||
if ((pos == std::string::npos) ||
(pos == 0))
throw runtime_error("TX output missing separator");
throw std::runtime_error("TX output missing separator");
// extract and validate VALUE
string strValue = strInput.substr(0, pos);
std::string strValue = strInput.substr(0, pos);
CAmount value;
if (!ParseMoney(strValue, value))
throw runtime_error("invalid TX output value");
throw std::runtime_error("invalid TX output value");
// extract and validate script
string strScript = strInput.substr(pos + 1, string::npos);
std::string strScript = strInput.substr(pos + 1, std::string::npos);
CScript scriptPubKey = ParseScript(strScript); // throws on err
// construct TxOut, append to transaction output list
@@ -276,26 +289,26 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput
tx.vout.push_back(txout);
}
static void MutateTxDelInput(CMutableTransaction& tx, const string& strInIdx)
static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx)
{
// parse requested deletion index
int inIdx = atoi(strInIdx);
if (inIdx < 0 || inIdx >= (int)tx.vin.size()) {
string strErr = "Invalid TX input index '" + strInIdx + "'";
throw runtime_error(strErr.c_str());
std::string strErr = "Invalid TX input index '" + strInIdx + "'";
throw std::runtime_error(strErr.c_str());
}
// delete input from transaction
tx.vin.erase(tx.vin.begin() + inIdx);
}
static void MutateTxDelOutput(CMutableTransaction& tx, const string& strOutIdx)
static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx)
{
// parse requested deletion index
int outIdx = atoi(strOutIdx);
if (outIdx < 0 || outIdx >= (int)tx.vout.size()) {
string strErr = "Invalid TX output index '" + strOutIdx + "'";
throw runtime_error(strErr.c_str());
std::string strErr = "Invalid TX output index '" + strOutIdx + "'";
throw std::runtime_error(strErr.c_str());
}
// delete output from transaction
@@ -315,7 +328,7 @@ static const struct {
{"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},
};
static bool findSighashFlags(int& flags, const string& flagStr)
static bool findSighashFlags(int& flags, const std::string& flagStr)
{
flags = 0;
@@ -329,17 +342,17 @@ static bool findSighashFlags(int& flags, const string& flagStr)
return false;
}
uint256 ParseHashUO(map<string,UniValue>& o, string strKey)
uint256 ParseHashUO(std::map<std::string,UniValue>& o, std::string strKey)
{
if (!o.count(strKey))
return uint256();
return ParseHashUV(o[strKey], strKey);
}
vector<unsigned char> ParseHexUO(map<string,UniValue>& o, string strKey)
std::vector<unsigned char> ParseHexUO(std::map<std::string,UniValue>& o, std::string strKey)
{
if (!o.count(strKey)) {
vector<unsigned char> emptyVec;
std::vector<unsigned char> emptyVec;
return emptyVec;
}
return ParseHexUV(o[strKey], strKey);
@@ -348,41 +361,41 @@ vector<unsigned char> ParseHexUO(map<string,UniValue>& o, string strKey)
static CAmount AmountFromValue(const UniValue& value)
{
if (!value.isNum() && !value.isStr())
throw runtime_error("Amount is not a number or string");
throw std::runtime_error("Amount is not a number or string");
CAmount amount;
if (!ParseFixedPoint(value.getValStr(), 8, &amount))
throw runtime_error("Invalid amount");
throw std::runtime_error("Invalid amount");
if (!MoneyRange(amount))
throw runtime_error("Amount out of range");
throw std::runtime_error("Amount out of range");
return amount;
}
static void MutateTxSign(CMutableTransaction& tx, const string& strInput)
static void MutateTxSign(CMutableTransaction& tx, const std::string& strInput)
{
// separate HEIGHT:SIGHASH-FLAGS in string
size_t pos = strInput.find(':');
if ((pos == 0) ||
(pos == (strInput.size() - 1)))
throw runtime_error("Invalid sighash flag separator");
throw std::runtime_error("Invalid sighash flag separator");
// extract and validate HEIGHT
string strHeight = strInput.substr(0, pos);
std::string strHeight = strInput.substr(0, pos);
int nHeight = atoi(strHeight);
if (nHeight <= 0) {
throw runtime_error("invalid height");
throw std::runtime_error("invalid height");
}
// extract and validate SIGHASH-FLAGS
int nHashType = SIGHASH_ALL;
string flagStr;
if (pos != string::npos) {
flagStr = strInput.substr(pos + 1, string::npos);
std::string flagStr;
if (pos != std::string::npos) {
flagStr = strInput.substr(pos + 1, std::string::npos);
}
if (flagStr.size() > 0)
if (!findSighashFlags(nHashType, flagStr))
throw runtime_error("unknown sighash flag/sign option");
throw std::runtime_error("unknown sighash flag/sign option");
vector<CTransaction> txVariants;
std::vector<CTransaction> txVariants;
txVariants.push_back(tx);
// mergedTx will end up with all the signatures; it
@@ -393,7 +406,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& strInput)
CCoinsViewCache view(&viewDummy);
if (!registers.count("privatekeys"))
throw runtime_error("privatekeys register variable must be set.");
throw std::runtime_error("privatekeys register variable must be set.");
bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
UniValue keysObj = registers["privatekeys"];
@@ -401,46 +414,44 @@ static void MutateTxSign(CMutableTransaction& tx, const string& strInput)
for (size_t kidx = 0; kidx < keysObj.size(); kidx++) {
if (!keysObj[kidx].isStr())
throw runtime_error("privatekey not a string");
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(keysObj[kidx].getValStr());
if (!fGood)
throw runtime_error("privatekey not valid");
CKey key = vchSecret.GetKey();
throw std::runtime_error("privatekey not a std::string");
CKey key = DecodeSecret(keysObj[kidx].getValStr());
if (!key.IsValid()) {
throw std::runtime_error("privatekey not valid");
}
tempKeystore.AddKey(key);
}
// Add previous txouts given in the RPC call:
if (!registers.count("prevtxs"))
throw runtime_error("prevtxs register variable must be set.");
throw std::runtime_error("prevtxs register variable must be set.");
UniValue prevtxsObj = registers["prevtxs"];
{
for (size_t previdx = 0; previdx < prevtxsObj.size(); previdx++) {
UniValue prevOut = prevtxsObj[previdx];
if (!prevOut.isObject())
throw runtime_error("expected prevtxs internal object");
throw std::runtime_error("expected prevtxs internal object");
map<string,UniValue::VType> types = boost::assign::map_list_of("txid", UniValue::VSTR)("vout",UniValue::VNUM)("scriptPubKey",UniValue::VSTR);
std::map<std::string,UniValue::VType> types = boost::assign::map_list_of("txid", UniValue::VSTR)("vout",UniValue::VNUM)("scriptPubKey",UniValue::VSTR);
if (!prevOut.checkObject(types))
throw runtime_error("prevtxs internal object typecheck fail");
throw std::runtime_error("prevtxs internal object typecheck fail");
uint256 txid = ParseHashUV(prevOut["txid"], "txid");
int nOut = atoi(prevOut["vout"].getValStr());
if (nOut < 0)
throw runtime_error("vout must be positive");
throw std::runtime_error("vout must be positive");
vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
CScript scriptPubKey(pkData.begin(), pkData.end());
{
CCoinsModifier coins = view.ModifyCoins(txid);
if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
string err("Previous output scriptPubKey mismatch:\n");
err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
scriptPubKey.ToString();
throw runtime_error(err);
std::string err("Previous output scriptPubKey mismatch:\n");
err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+
ScriptToAsmStr(scriptPubKey);
throw std::runtime_error(err);
}
if ((unsigned int)nOut >= coins->vout.size())
coins->vout.resize(nOut+1);
@@ -456,7 +467,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& strInput)
if (fGivenKeys && scriptPubKey.IsPayToScriptHash() &&
prevOut.exists("redeemScript")) {
UniValue v = prevOut["redeemScript"];
vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
std::vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
CScript redeemScript(rsData.begin(), rsData.end());
tempKeystore.AddCScript(redeemScript);
}
@@ -516,8 +527,8 @@ public:
}
};
static void MutateTx(CMutableTransaction& tx, const string& command,
const string& commandVal)
static void MutateTx(CMutableTransaction& tx, const std::string& command,
const std::string& commandVal)
{
boost::scoped_ptr<Secp256k1Init> ecc;
@@ -552,7 +563,7 @@ static void MutateTx(CMutableTransaction& tx, const string& command,
RegisterSet(commandVal);
else
throw runtime_error("unknown command");
throw std::runtime_error("unknown command");
}
static void OutputTxJSON(const CTransaction& tx)
@@ -560,20 +571,20 @@ static void OutputTxJSON(const CTransaction& tx)
UniValue entry(UniValue::VOBJ);
TxToUniv(tx, uint256(), entry);
string jsonOutput = entry.write(4);
std::string jsonOutput = entry.write(4);
fprintf(stdout, "%s\n", jsonOutput.c_str());
}
static void OutputTxHash(const CTransaction& tx)
{
string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
std::string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
fprintf(stdout, "%s\n", strHexHash.c_str());
}
static void OutputTxHex(const CTransaction& tx)
{
string strHex = EncodeHexTx(tx);
std::string strHex = EncodeHexTx(tx);
fprintf(stdout, "%s\n", strHex.c_str());
}
@@ -588,10 +599,10 @@ static void OutputTx(const CTransaction& tx)
OutputTxHex(tx);
}
static string readStdin()
static std::string readStdin()
{
char buf[4096];
string ret;
std::string ret;
while (!feof(stdin)) {
size_t bread = fread(buf, 1, sizeof(buf), stdin);
@@ -601,7 +612,7 @@ static string readStdin()
}
if (ferror(stdin))
throw runtime_error("error reading stdin");
throw std::runtime_error("error reading stdin");
boost::algorithm::trim_right(ret);
@@ -610,7 +621,7 @@ static string readStdin()
static int CommandLineRawTx(int argc, char* argv[])
{
string strPrint;
std::string strPrint;
int nRet = 0;
try {
// Skip switches; Permit common stdin convention "-"
@@ -626,15 +637,15 @@ static int CommandLineRawTx(int argc, char* argv[])
if (!fCreateBlank) {
// require at least one param
if (argc < 2)
throw runtime_error("too few parameters");
throw std::runtime_error("too few parameters");
// param: hex-encoded bitcoin transaction
string strHexTx(argv[1]);
std::string strHexTx(argv[1]);
if (strHexTx == "-") // "-" implies standard input
strHexTx = readStdin();
if (!DecodeHexTx(txDecodeTmp, strHexTx))
throw runtime_error("invalid transaction encoding");
throw std::runtime_error("invalid transaction encoding");
startArg = 2;
} else
@@ -643,10 +654,10 @@ static int CommandLineRawTx(int argc, char* argv[])
CMutableTransaction tx(txDecodeTmp);
for (int i = startArg; i < argc; i++) {
string arg = argv[i];
string key, value;
std::string arg = argv[i];
std::string key, value;
size_t eqpos = arg.find('=');
if (eqpos == string::npos)
if (eqpos == std::string::npos)
key = arg;
else {
key = arg.substr(0, eqpos);
@@ -663,7 +674,7 @@ static int CommandLineRawTx(int argc, char* argv[])
throw;
}
catch (const std::exception& e) {
strPrint = string("error: ") + e.what();
strPrint = std::string("error: ") + e.what();
nRet = EXIT_FAILURE;
}
catch (...) {
@@ -682,8 +693,9 @@ int main(int argc, char* argv[])
SetupEnvironment();
try {
if(!AppInitRawTx(argc, argv))
return EXIT_FAILURE;
int ret = AppInitRawTx(argc, argv);
if (ret != CONTINUE_EXECUTION)
return ret;
}
catch (const std::exception& e) {
PrintExceptionContinue(&e, "AppInitRawTx()");

View File

@@ -885,7 +885,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
{
/*if ( i == 0 && j == 0 )
{
uint8_t *script = (uint8_t *)block.vtx[0].vout[numvouts-1].scriptPubKey.data();
uint8_t *script = (uint8_t *)&block.vtx[0].vout[numvouts-1].scriptPubKey[0];
if ( numvouts <= 2 || script[0] != 0x6a )
{
if ( numvouts == 2 && block.vtx[0].vout[1].nValue != 0 )
@@ -902,11 +902,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
len = block.vtx[i].vout[j].scriptPubKey.size();
if ( len >= sizeof(uint32_t) && len <= sizeof(scriptbuf) )
{
#ifdef KOMODO_ZCASH
memcpy(scriptbuf,block.vtx[i].vout[j].scriptPubKey.data(),len);
#else
memcpy(scriptbuf,(uint8_t *)&block.vtx[i].vout[j].scriptPubKey[0],len);
#endif
notaryid = komodo_voutupdate(&isratification,notaryid,scriptbuf,len,height,txhash,i,j,&voutmask,&specialtx,&notarizedheight,(uint64_t)block.vtx[i].vout[j].nValue,notarized,signedmask,(uint32_t)chainActive.LastTip()->GetBlockTime());
if ( 0 && i > 0 )
{
@@ -936,11 +932,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
len = block.vtx[i].vout[j].scriptPubKey.size();
if ( len >= sizeof(uint32_t) && len <= sizeof(scriptbuf) )
{
#ifdef KOMODO_ZCASH
memcpy(scriptbuf,block.vtx[i].vout[j].scriptPubKey.data(),len);
#else
memcpy(scriptbuf,(uint8_t *)&block.vtx[i].vout[j].scriptPubKey[0],len);
#endif
if ( len == 35 && scriptbuf[0] == 33 && scriptbuf[34] == 0xac )
{
memcpy(pubkeys[numvalid++],scriptbuf+1,33);

View File

@@ -15,14 +15,10 @@
// komodo functions that interact with bitcoind C++
#ifdef _WIN32
#include <curl/curl.h>
#include <curl/easy.h>
#else
#include <curl/curl.h>
#include <curl/easy.h>
#endif
#include "primitives/nonce.h"
#include "consensus/params.h"
#include "komodo_defs.h"
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
@@ -648,11 +644,7 @@ int32_t komodo_is_notarytx(const CTransaction& tx)
uint8_t *ptr; static uint8_t crypto777[33];
if ( tx.vout.size() > 0 )
{
#ifdef KOMODO_ZCASH
ptr = (uint8_t *)tx.vout[0].scriptPubKey.data();
#else
ptr = (uint8_t *)&tx.vout[0].scriptPubKey[0];
#endif
if ( ptr != 0 )
{
if ( crypto777[0] == 0 )
@@ -679,11 +671,7 @@ int32_t komodo_block2height(CBlock *block)
}
if ( block != 0 && block->vtx[0].vin.size() > 0 )
{
#ifdef KOMODO_ZCASH
ptr = (uint8_t *)block->vtx[0].vin[0].scriptSig.data();
#else
ptr = (uint8_t *)&block->vtx[0].vin[0].scriptSig[0];
#endif
if ( ptr != 0 && block->vtx[0].vin[0].scriptSig.size() > 5 )
{
//for (i=0; i<6; i++)
@@ -1473,6 +1461,7 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
uint256 txid, blkHash;
int32_t txn_count;
uint32_t voutNum;
CAmount value;
bool isPOS = false;
CTxDestination voutaddress, destaddress, cbaddress;
arith_uint256 target, hash;
@@ -1481,8 +1470,8 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
if (!pblock->IsVerusPOSBlock())
{
printf("%s, height %d not POS block\n", pblock->nNonce.GetHex().c_str(), height);
pblock->nNonce.SetPOSTarget(pblock->nNonce.GetPOSTarget());
printf("%s after setting POS target\n", pblock->nNonce.GetHex().c_str());
//pblock->nNonce.SetPOSTarget(pblock->nNonce.GetPOSTarget());
//printf("%s after setting POS target\n", pblock->nNonce.GetHex().c_str());
return false;
}
@@ -1495,90 +1484,128 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
target.SetCompact(pblock->GetVerusPOSTarget());
txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
voutNum = pblock->vtx[txn_count-1].vin[0].prevout.n;
value = pblock->vtx[txn_count-1].vout[0].nValue;
#ifndef KOMODO_ZCASH
if (!GetTransaction(txid, tx, Params().GetConsensus(), blkHash, true))
#else
if (!GetTransaction(txid, tx, blkHash, true))
#endif
{
fprintf(stderr,"ERROR: invalid PoS block %s - no transaction\n",blkHash.ToString().c_str());
}
else if (!(pastBlockIndex = komodo_chainactive(height - 100)))
{
fprintf(stderr,"WARNING: chain not fully loaded or invalid PoS block %s - no past block found\n",blkHash.ToString().c_str());
}
else
{
CBlockHeader bh = pastBlockIndex->GetBlockHeader();
uint256 pastHash = bh.GetVerusEntropyHash(height - 100);
// if height is over when Nonce is required to be the new format, we check that the new format is correct
// if over when we have the new POS hash function, we validate that as well
// they are 100 blocks apart
CPOSNonce nonce = pblock->nNonce;
hash = UintToArith256(tx.GetVerusPOSHash(&nonce, voutNum, height, pastHash));
if (hash <= target)
bool validHash;
bool enablePOSNonce = CPOSNonce::NewPOSActive(height);
bool newPOSActive = enablePOSNonce || (Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight <= height);
uint256 rawHash;
arith_uint256 posHash;
if (newPOSActive)
{
if ((mapBlockIndex.count(blkHash) == 0) ||
!(pastBlockIndex = mapBlockIndex[blkHash]) ||
(height - pastBlockIndex->nHeight) < VERUS_MIN_STAKEAGE)
validHash = pblock->GetRawVerusPOSHash(rawHash, height);
posHash = UintToArith256(rawHash) / value;
//if (slowflag)
//{
// printf("first nNonce: %s, height: %d\n", pblock->nNonce.GetHex().c_str(), height);
// printf("Raw POShash: %s\n", posHash.GetHex().c_str());
//}
}
if (newPOSActive && !(validHash && posHash <= target))
{
printf("ERROR: invalid nonce value for PoS block\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %ull\n",
pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value);
}
//else
{
if (slowflag == 0)
{
fprintf(stderr,"ERROR: invalid PoS block %s - stake transaction too new\n",blkHash.ToString().c_str());
isPOS = true;
}
else if ( slowflag != 0 )
else if (!(pastBlockIndex = komodo_chainactive(height - 100)))
{
// make sure we have the right target
CBlockIndex *previndex;
if (!(previndex = mapBlockIndex[pblock->hashPrevBlock]))
{
fprintf(stderr,"ERROR: invalid PoS block %s - no prev block found\n",blkHash.ToString().c_str());
}
else
{
arith_uint256 cTarget;
uint32_t nBits = lwmaGetNextPOSRequired(previndex, Params().GetConsensus());
cTarget.SetCompact(nBits);
bool nonceOK = true;
if (CPOSNonce::NewNonceActive(height) && !nonce.CheckPOSEntropy(pastHash, txid, voutNum))
{
fprintf(stderr,"ERROR: invalid PoS block %s - nonce entropy corrupted or forged\n",blkHash.ToString().c_str());
nonceOK = false;
}
else
{
if (cTarget != target)
{
fprintf(stderr,"ERROR: invalid PoS block %s - invalid diff target\n",blkHash.ToString().c_str());
nonceOK = false;
}
}
if ( nonceOK && ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey, voutaddress) &&
ExtractDestination(tx.vout[voutNum].scriptPubKey, destaddress) &&
CScriptExt::ExtractVoutDestination(pblock->vtx[0], 0, cbaddress) )
{
strcpy(voutaddr, CBitcoinAddress(voutaddress).ToString().c_str());
strcpy(destaddr, CBitcoinAddress(destaddress).ToString().c_str());
strcpy(cbaddr, CBitcoinAddress(cbaddress).ToString().c_str());
if ( !strcmp(destaddr,voutaddr) && ( !strcmp(destaddr,cbaddr) || (height < 17840)) )
{
isPOS = true;
}
else
{
fprintf(stderr,"ERROR: invalid PoS block %s - invalid stake or coinbase destination\n",blkHash.ToString().c_str());
}
}
}
fprintf(stderr,"ERROR: chain not fully loaded or invalid PoS block %s - no past block found\n",blkHash.ToString().c_str());
}
else
#ifndef KOMODO_ZCASH
if (!GetTransaction(txid, tx, Params().GetConsensus(), blkHash, true))
#else
if (!GetTransaction(txid, tx, blkHash, true))
#endif
{
fprintf(stderr,"ERROR: invalid PoS block %s - no source transaction\n",blkHash.ToString().c_str());
}
else
{
// with fast check, we get true here, slow check ensures destination address
// of staking transaction matches original source and that the target
// matches the consensus target
isPOS = true;
CBlockHeader bh = pastBlockIndex->GetBlockHeader();
uint256 pastHash = bh.GetVerusEntropyHash(height - 100);
// if height is over when Nonce is required to be the new format, we check that the new format is correct
// if over when we have the new POS hash function, we validate that as well
// they are 100 blocks apart
CPOSNonce nonce = pblock->nNonce;
//printf("before nNonce: %s, height: %d\n", pblock->nNonce.GetHex().c_str(), height);
//validHash = pblock->GetRawVerusPOSHash(rawHash, height);
//hash = UintToArith256(rawHash) / tx.vout[voutNum].nValue;
//printf("Raw POShash: %s\n", hash.GetHex().c_str());
hash = UintToArith256(tx.GetVerusPOSHash(&nonce, voutNum, height, pastHash));
//printf("after nNonce: %s, height: %d\n", nonce.GetHex().c_str(), height);
//printf("POShash: %s\n\n", hash.GetHex().c_str());
//if ((!newPOSActive || posHash == hash) && hash <= target)
if (hash <= target)
{
if ((mapBlockIndex.count(blkHash) == 0) ||
!(pastBlockIndex = mapBlockIndex[blkHash]) ||
(height - pastBlockIndex->nHeight) < VERUS_MIN_STAKEAGE)
{
fprintf(stderr,"ERROR: invalid PoS block %s - stake transaction too new\n",blkHash.ToString().c_str());
}
else
{
// make sure we have the right target
CBlockIndex *previndex;
if (!(previndex = mapBlockIndex[pblock->hashPrevBlock]))
{
fprintf(stderr,"ERROR: invalid PoS block %s - no prev block found\n",blkHash.ToString().c_str());
}
else
{
arith_uint256 cTarget;
uint32_t nBits = lwmaGetNextPOSRequired(previndex, Params().GetConsensus());
cTarget.SetCompact(nBits);
bool nonceOK = true;
// check to see how many fail
//if (nonce != pblock->nNonce)
// printf("Mismatched nNonce: %s\nblkHash: %s, height: %d\n", nonce.GetHex().c_str(), pblock->GetHash().GetHex().c_str(), height);
if (CPOSNonce::NewNonceActive(height) && !nonce.CheckPOSEntropy(pastHash, txid, voutNum))
{
fprintf(stderr,"ERROR: invalid PoS block %s - nonce entropy corrupted or forged\n",blkHash.ToString().c_str());
nonceOK = false;
}
else
{
if (cTarget != target)
{
fprintf(stderr,"ERROR: invalid PoS block %s - invalid diff target\n",blkHash.ToString().c_str());
nonceOK = false;
}
}
if ( nonceOK && ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey, voutaddress) &&
ExtractDestination(tx.vout[voutNum].scriptPubKey, destaddress) &&
CScriptExt::ExtractVoutDestination(pblock->vtx[0], 0, cbaddress) )
{
strcpy(voutaddr, CBitcoinAddress(voutaddress).ToString().c_str());
strcpy(destaddr, CBitcoinAddress(destaddress).ToString().c_str());
strcpy(cbaddr, CBitcoinAddress(cbaddress).ToString().c_str());
if ( !strcmp(destaddr,voutaddr) && ( !strcmp(destaddr,cbaddr) || (height < 17840)) )
{
isPOS = true;
}
else
{
fprintf(stderr,"ERROR: invalid PoS block %s - invalid stake or coinbase destination\n",blkHash.ToString().c_str());
}
}
}
}
}
}
}
}
@@ -1596,7 +1623,7 @@ int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
return(-1);
else if ( checktoshis != 0 )
{
script = (uint8_t *)pblock->vtx[0].vout[1].scriptPubKey.data();
script = (uint8_t *)&pblock->vtx[0].vout[1].scriptPubKey[0];
if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
return(-1);
if ( pblock->vtx[0].vout[1].nValue != checktoshis )
@@ -1702,7 +1729,7 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
{
if ( height == 1 )
{
script = (uint8_t *)pblock->vtx[0].vout[0].scriptPubKey.data();
script = (uint8_t *)&pblock->vtx[0].vout[0].scriptPubKey[0];
if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
return(-1);
}
@@ -1725,7 +1752,7 @@ int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
for (i=0; i<n; i++)
{
CTransaction vintx,&tx = pblock->vtx[i];
zfunds += (tx.GetJoinSplitValueOut() - tx.GetJoinSplitValueIn());
zfunds += (tx.GetValueOut() - tx.GetShieldedValueIn());
if ( (m= tx.vin.size()) > 0 )
{
for (j=0; j<m; j++)
@@ -1750,7 +1777,7 @@ int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
voutsum += tx.vout[j].nValue;
else printf("skip %.8f -> %s\n",dstr(tx.vout[j].nValue),CBitcoinAddress(address).ToString().c_str());
}
script = (uint8_t *)tx.vout[j].scriptPubKey.data();
script = (uint8_t *)&tx.vout[j].scriptPubKey[0];
if ( script == 0 || script[0] != 0x6a )
{
if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )

View File

@@ -10,7 +10,7 @@
#define IGUANA_MAXSCRIPTSIZE 10001
#define KOMODO_MAXMEMPOOLTIME 3600 // affects consensus
#define CRYPTO777_PUBSECPSTR "020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9"
#define VRSC_KMD_MERGE_FIX 227520 // height that the inadvertent KMD merge/coinbase output changes to VRSC are removed
#define VRSC_SAPLING_UPGRADE 227520 // height that the inadvertent KMD merge/coinbase output changes to VRSC are removed
// approximately October 28th
#endif

View File

@@ -690,14 +690,14 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim
// we don't want any of these checks in VRSC, leave it for other chains until/unless KMD removes
if ( ASSETCHAINS_SYMBOL[0] == 0 ||
(ASSETCHAINS_COMMISSION != 0 && height > 1) ||
(strcmp(ASSETCHAINS_SYMBOL,"VRSC") == 0 && height < VRSC_KMD_MERGE_FIX) )
(strcmp(ASSETCHAINS_SYMBOL,"VRSC") == 0 && height < VRSC_SAPLING_UPGRADE) )
{
n = block.vtx[0].vout.size();
int64_t val,prevtotal = 0; int32_t strangeout=0,overflow = 0;
total = 0;
for (i=1; i<n; i++)
{
script = (uint8_t *)block.vtx[0].vout[i].scriptPubKey.data();
script = (uint8_t *)&block.vtx[0].vout[i].scriptPubKey[0];
if ( (val= block.vtx[0].vout[i].nValue) < 0 || val >= MAX_MONEY )
{
overflow = 1;
@@ -739,7 +739,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim
}
else if ( height > 814000 )
{
script = (uint8_t *)block.vtx[0].vout[0].scriptPubKey.data();
script = (uint8_t *)&block.vtx[0].vout[0].scriptPubKey[0];
return(-1 * (komodo_electednotary(&num,script+1,height,0) >= 0) * (height > 1000000));
}
}

View File

@@ -55,6 +55,8 @@ uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC,KOMODO_STOPAT;
uint32_t ASSETCHAINS_MAGIC = 2387029918;
int64_t ASSETCHAINS_GENESISTXVAL = 5000000000;
int64_t MAX_MONEY = 200000000 * 100000000LL;
// consensus variables for coinbase timelock control and timelock transaction support
// time locks are specified enough to enable their use initially to lock specific coinbase transactions for emission control
// to be verifiable, timelocks require additional data that enables them to be validated and their ownership and

View File

@@ -20,7 +20,7 @@
#define KOMODO_ENDOFERA 7777777
#define KOMODO_INTEREST ((uint64_t)5000000) //((uint64_t)(0.05 * COIN)) // 5%
int64_t MAX_MONEY = 200000000 * 100000000LL;
extern int64_t MAX_MONEY;
extern uint8_t NOTARY_PUBKEY33[];
#ifdef notanymore

View File

@@ -1643,9 +1643,10 @@ uint64_t komodo_ac_block_subsidy(int nHeight)
return(subsidy);
}
extern int64_t MAX_MONEY;
void komodo_args(char *argv0)
{
extern int64_t MAX_MONEY;
extern const char *Notaries_elected1[][2];
std::string name,addn; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[256],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,baseid,len,n,extralen = 0;
IS_KOMODO_NOTARY = GetBoolArg("-notary", false);

View File

@@ -1,173 +0,0 @@
// Copyright (c) 2012-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_LEVELDBWRAPPER_H
#define BITCOIN_LEVELDBWRAPPER_H
#include "clientversion.h"
#include "serialize.h"
#include "streams.h"
#include "util.h"
#include "version.h"
#include <boost/filesystem/path.hpp>
#include <leveldb/db.h>
#include <leveldb/write_batch.h>
class leveldb_error : public std::runtime_error
{
public:
leveldb_error(const std::string& msg) : std::runtime_error(msg) {}
};
void HandleError(const leveldb::Status& status);
/** Batch of changes queued to be written to a CLevelDBWrapper */
class CLevelDBBatch
{
friend class CLevelDBWrapper;
private:
leveldb::WriteBatch batch;
public:
template <typename K, typename V>
void Write(const K& key, const V& value)
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(ssKey.GetSerializeSize(key));
ssKey << key;
leveldb::Slice slKey(&ssKey[0], ssKey.size());
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
ssValue.reserve(ssValue.GetSerializeSize(value));
ssValue << value;
leveldb::Slice slValue(&ssValue[0], ssValue.size());
batch.Put(slKey, slValue);
}
template <typename K>
void Erase(const K& key)
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(ssKey.GetSerializeSize(key));
ssKey << key;
leveldb::Slice slKey(&ssKey[0], ssKey.size());
batch.Delete(slKey);
}
};
class CLevelDBWrapper
{
private:
//! custom environment this database is using (may be NULL in case of default environment)
leveldb::Env* penv;
//! database options used
leveldb::Options options;
//! options used when reading from the database
leveldb::ReadOptions readoptions;
//! options used when iterating over values of the database
leveldb::ReadOptions iteroptions;
//! options used when writing to the database
leveldb::WriteOptions writeoptions;
//! options used when sync writing to the database
leveldb::WriteOptions syncoptions;
//! the database itself
leveldb::DB* pdb;
public:
CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool compression = false, int maxOpenFiles = 64);
~CLevelDBWrapper();
template <typename K, typename V>
bool Read(const K& key, V& value) const
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(ssKey.GetSerializeSize(key));
ssKey << key;
leveldb::Slice slKey(&ssKey[0], ssKey.size());
std::string strValue;
leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
if (!status.ok()) {
if (status.IsNotFound())
return false;
LogPrintf("LevelDB read failure: %s\n", status.ToString());
HandleError(status);
}
try {
CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
ssValue >> value;
} catch (const std::exception&) {
return false;
}
return true;
}
template <typename K, typename V>
bool Write(const K& key, const V& value, bool fSync = false)
{
CLevelDBBatch batch;
batch.Write(key, value);
return WriteBatch(batch, fSync);
}
template <typename K>
bool Exists(const K& key) const
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(ssKey.GetSerializeSize(key));
ssKey << key;
leveldb::Slice slKey(&ssKey[0], ssKey.size());
std::string strValue;
leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
if (!status.ok()) {
if (status.IsNotFound())
return false;
LogPrintf("LevelDB read failure: %s\n", status.ToString());
HandleError(status);
}
return true;
}
template <typename K>
bool Erase(const K& key, bool fSync = false)
{
CLevelDBBatch batch;
batch.Erase(key);
return WriteBatch(batch, fSync);
}
bool WriteBatch(CLevelDBBatch& batch, bool fSync = false);
// not available for LevelDB; provide for compatibility with BDB
bool Flush()
{
return true;
}
bool Sync()
{
CLevelDBBatch batch;
return WriteBatch(batch, true);
}
// not exactly clean encapsulation, but it's easiest for now
leveldb::Iterator* NewIterator()
{
return pdb->NewIterator(iteroptions);
}
};
#endif // BITCOIN_LEVELDBWRAPPER_H

File diff suppressed because it is too large Load Diff

View File

@@ -102,6 +102,7 @@ static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;
static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
/** Maximum length of reject messages. */
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
//static const bool DEFAULT_ADDRESSINDEX = false;
//static const bool DEFAULT_SPENTINDEX = false;
@@ -149,6 +150,7 @@ extern bool fCoinbaseEnforcedProtectionEnabled;
extern size_t nCoinCacheUsage;
extern CFeeRate minRelayTxFee;
extern bool fAlerts;
extern int64_t nMaxTipAge;
/** Best header we've seen so far (used for getheaders queries' starting points). */
extern CBlockIndex *pindexBestHeader;
@@ -287,11 +289,11 @@ struct CTimestampIndexIteratorKey {
return 4;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
void Serialize(Stream& s) const {
ser_writedata32be(s, timestamp);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
void Unserialize(Stream& s) {
timestamp = ser_readdata32be(s);
}
@@ -316,14 +318,14 @@ struct CTimestampIndexKey {
return 36;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
void Serialize(Stream& s) const {
ser_writedata32be(s, timestamp);
blockHash.Serialize(s, nType, nVersion);
blockHash.Serialize(s);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
void Unserialize(Stream& s) {
timestamp = ser_readdata32be(s);
blockHash.Unserialize(s, nType, nVersion);
blockHash.Unserialize(s);
}
CTimestampIndexKey(unsigned int time, uint256 hash) {
@@ -349,13 +351,13 @@ struct CTimestampBlockIndexKey {
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
blockHash.Serialize(s, nType, nVersion);
void Serialize(Stream& s) const {
blockHash.Serialize(s);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
blockHash.Unserialize(s, nType, nVersion);
void Unserialize(Stream& s) {
blockHash.Unserialize(s);
}
CTimestampBlockIndexKey(uint256 hash) {
@@ -378,12 +380,12 @@ struct CTimestampBlockIndexValue {
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
void Serialize(Stream& s) const {
ser_writedata32be(s, ltimestamp);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
void Unserialize(Stream& s) {
ltimestamp = ser_readdata32be(s);
}
@@ -410,17 +412,17 @@ struct CAddressUnspentKey {
return 57;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
void Serialize(Stream& s) const {
ser_writedata8(s, type);
hashBytes.Serialize(s, nType, nVersion);
txhash.Serialize(s, nType, nVersion);
hashBytes.Serialize(s);
txhash.Serialize(s);
ser_writedata32(s, index);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
void Unserialize(Stream& s) {
type = ser_readdata8(s);
hashBytes.Unserialize(s, nType, nVersion);
txhash.Unserialize(s, nType, nVersion);
hashBytes.Unserialize(s);
txhash.Unserialize(s);
index = ser_readdata32(s);
}
@@ -443,7 +445,7 @@ struct CAddressUnspentKey {
}
};
struct CAddressUnspentValue {
struct CAddressUnspentValue {
CAmount satoshis;
CScript script;
int blockHeight;
@@ -451,9 +453,9 @@ struct CAddressUnspentValue {
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(satoshis);
READWRITE(script);
READWRITE(*(CScriptBase*)(&script));
READWRITE(blockHeight);
}
@@ -491,24 +493,24 @@ struct CAddressIndexKey {
return 66;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
void Serialize(Stream& s) const {
ser_writedata8(s, type);
hashBytes.Serialize(s, nType, nVersion);
hashBytes.Serialize(s);
// Heights are stored big-endian for key sorting in LevelDB
ser_writedata32be(s, blockHeight);
ser_writedata32be(s, txindex);
txhash.Serialize(s, nType, nVersion);
txhash.Serialize(s);
ser_writedata32(s, index);
char f = spending;
ser_writedata8(s, f);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
void Unserialize(Stream& s) {
type = ser_readdata8(s);
hashBytes.Unserialize(s, nType, nVersion);
hashBytes.Unserialize(s);
blockHeight = ser_readdata32be(s);
txindex = ser_readdata32be(s);
txhash.Unserialize(s, nType, nVersion);
txhash.Unserialize(s);
index = ser_readdata32(s);
char f = ser_readdata8(s);
spending = f;
@@ -549,14 +551,14 @@ struct CAddressIndexIteratorKey {
return 21;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
void Serialize(Stream& s) const {
ser_writedata8(s, type);
hashBytes.Serialize(s, nType, nVersion);
hashBytes.Serialize(s);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
void Unserialize(Stream& s) {
type = ser_readdata8(s);
hashBytes.Unserialize(s, nType, nVersion);
hashBytes.Unserialize(s);
}
CAddressIndexIteratorKey(unsigned int addressType, uint160 addressHash) {
@@ -583,15 +585,15 @@ struct CAddressIndexIteratorHeightKey {
return 25;
}
template<typename Stream>
void Serialize(Stream& s, int nType, int nVersion) const {
void Serialize(Stream& s) const {
ser_writedata8(s, type);
hashBytes.Serialize(s, nType, nVersion);
hashBytes.Serialize(s);
ser_writedata32be(s, blockHeight);
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersion) {
void Unserialize(Stream& s) {
type = ser_readdata8(s);
hashBytes.Unserialize(s, nType, nVersion);
hashBytes.Unserialize(s);
blockHeight = ser_readdata32be(s);
}
@@ -619,7 +621,7 @@ struct CDiskTxPos : public CDiskBlockPos
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*(CDiskBlockPos*)this);
READWRITE(VARINT(nTxOffset));
}
@@ -829,8 +831,11 @@ bool AcceptBlockHeader(int32_t *futureblockp,const CBlockHeader& block, CValidat
* When there are blocks in the active chain with missing data (e.g. if the
* activation height and branch ID of a particular upgrade have been altered),
* rewind the chainstate and remove them from the block index.
*
* clearWitnessCaches is an output parameter that will be set to true iff
* witness caches should be cleared in order to handle an intended long rewind.
*/
bool RewindBlockIndex(const CChainParams& params);
bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches);
class CBlockFileInfo
{
@@ -846,7 +851,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(VARINT(nBlocks));
READWRITE(VARINT(nSize));
READWRITE(VARINT(nUndoSize));

View File

@@ -46,7 +46,9 @@ template<typename X> static inline size_t DynamicUsage(const X * const &v) { ret
static inline size_t MallocUsage(size_t alloc)
{
// Measured on libc6 2.19 on Linux.
if (sizeof(void*) == 8) {
if (alloc == 0) {
return 0;
} else if (sizeof(void*) == 8) {
return ((alloc + 31) >> 4) << 4;
} else if (sizeof(void*) == 4) {
return ((alloc + 15) >> 3) << 3;
@@ -74,6 +76,12 @@ static inline size_t DynamicUsage(const std::vector<X>& v)
return MallocUsage(v.capacity() * sizeof(X));
}
template<unsigned int N, typename X, typename S, typename D>
static inline size_t DynamicUsage(const prevector<N, X, S, D>& v)
{
return MallocUsage(v.allocated_memory());
}
template<typename X>
static inline size_t DynamicUsage(const std::set<X>& s)
{

View File

@@ -85,7 +85,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(nTransactions);
READWRITE(vHash);
std::vector<unsigned char> vBytes;
@@ -147,7 +147,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(header);
READWRITE(txn);
}

View File

@@ -73,6 +73,14 @@ double AtomicTimer::rate(const AtomicCounter& count)
return duration > 0 ? (double)count.get() / duration : 0;
}
boost::synchronized_value<int64_t> nNodeStartTime;
boost::synchronized_value<int64_t> nNextRefresh;
int64_t nHashCount;
AtomicCounter transactionsValidated;
AtomicCounter ehSolverRuns;
AtomicCounter solutionTargetChecks;
static AtomicCounter minedBlocks;
AtomicTimer miningTimer;
CCriticalSection cs_metrics;
double AtomicTimer::rate(const int64_t count)
@@ -87,20 +95,11 @@ double AtomicTimer::rate(const int64_t count)
return duration > 0 ? (double)count / duration : 0;
}
boost::synchronized_value<int64_t> nNodeStartTime;
boost::synchronized_value<int64_t> nNextRefresh;
int64_t nHashCount;
AtomicCounter transactionsValidated;
AtomicCounter ehSolverRuns;
AtomicCounter solutionTargetChecks;
AtomicCounter minedBlocks;
AtomicTimer miningTimer;
static boost::synchronized_value<std::list<uint256>> trackedBlocks;
boost::synchronized_value<std::list<uint256>> trackedBlocks;
boost::synchronized_value<std::list<std::string>> messageBox;
boost::synchronized_value<std::string> initMessage;
bool loaded = false;
static boost::synchronized_value<std::list<std::string>> messageBox;
static boost::synchronized_value<std::string> initMessage;
static bool loaded = false;
extern int64_t GetNetworkHashPS(int lookup, int height);
@@ -439,6 +438,30 @@ int printInitMessage()
return 2;
}
#ifdef WIN32
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
bool enableVTMode()
{
// Set output mode to handle virtual terminal sequences
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut == INVALID_HANDLE_VALUE) {
return false;
}
DWORD dwMode = 0;
if (!GetConsoleMode(hOut, &dwMode)) {
return false;
}
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(hOut, dwMode)) {
return false;
}
return true;
}
#endif
void ThreadShowMetricsScreen()
{
// Make this thread recognisable as the metrics screen thread
@@ -450,6 +473,10 @@ void ThreadShowMetricsScreen()
int64_t nRefresh = GetArg("-metricsrefreshtime", isTTY ? 1 : 600);
if (isScreen) {
#ifdef WIN32
enableVTMode();
#endif
// Clear screen
std::cout << "\e[2J";
@@ -474,15 +501,16 @@ void ThreadShowMetricsScreen()
// Get current window size
if (isTTY) {
#ifdef _WIN32
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
#else
struct winsize w;
w.ws_col = 0;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1 && w.ws_col != 0) {
cols = w.ws_col;
}
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) != 0) {
cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
}
#else
struct winsize w;
w.ws_col = 0;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1 && w.ws_col != 0) {
cols = w.ws_col;
}
#endif
}
@@ -508,7 +536,13 @@ void ThreadShowMetricsScreen()
if (isScreen) {
// Explain how to exit
std::cout << "[" << _("Press Ctrl+C to exit") << "] [" << _("Set 'showmetrics=0' to hide") << "]" << std::endl;
std::cout << "[";
#ifdef WIN32
std::cout << _("'zcash-cli.exe stop' to exit");
#else
std::cout << _("Press Ctrl+C to exit");
#endif
std::cout << "] [" << _("Set 'showmetrics=0' to hide") << "]" << std::endl;
} else {
// Print delineator
std::cout << "----------------------------------------" << std::endl;

View File

@@ -9,7 +9,6 @@
#endif
#include "amount.h"
#include "base58.h"
#include "chainparams.h"
#include "importcoin.h"
#include "consensus/consensus.h"
@@ -20,7 +19,7 @@
#include "crypto/verus_hash.h"
#endif
#include "hash.h"
#include "key_io.h"
#include "main.h"
#include "metrics.h"
#include "net.h"
@@ -198,6 +197,9 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
CCoinsViewCache view(pcoinsTip);
uint32_t expired; uint64_t commission;
SaplingMerkleTree sapling_tree;
assert(view.GetSaplingAnchorAt(view.GetBestAnchor(SAPLING), sapling_tree));
// Priority order to process transactions
list<COrphan> vOrphan; // list memory doesn't move
map<uint256, vector<COrphan*> > mapDependers;
@@ -275,7 +277,7 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
dPriority += (double)nValueIn * nConf;
}
nTotalIn += tx.GetJoinSplitValueIn();
nTotalIn += tx.GetShieldedValueIn();
}
if (fMissingInputs) continue;
@@ -377,7 +379,11 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
continue;
}
UpdateCoins(tx, view, nHeight);
BOOST_FOREACH(const OutputDescription &outDescription, tx.vShieldedOutput) {
sapling_tree.append(outDescription.cm);
}
// Added
pblock->vtx.push_back(tx);
pblocktemplate->vTxFees.push_back(nTxFees);
@@ -495,7 +501,7 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
txNew.vout.resize(2);
txNew.vout[1].nValue = commission;
txNew.vout[1].scriptPubKey.resize(35);
ptr = (uint8_t *)txNew.vout[1].scriptPubKey.data();
ptr = (uint8_t *)&txNew.vout[1].scriptPubKey[0];
ptr[0] = 33;
for (i=0; i<33; i++)
ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i];
@@ -520,7 +526,7 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
pblock->hashReserved = uint256();
pblock->hashFinalSaplingRoot = sapling_tree.root();
// all Verus PoS chains need this data in the block at all times
if ( ASSETCHAINS_LWMAPOS || ASSETCHAINS_SYMBOL[0] == 0 || ASSETCHAINS_STAKED == 0 || KOMODO_MININGTHREADS > 0 )
@@ -569,32 +575,12 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
//fprintf(stderr,"check validity\n");
if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false)) // invokes CC checks
{
//static uint32_t counter;
//if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 )
// fprintf(stderr,"warning: miner testblockvalidity failed\n");
fprintf(stderr,"invalid\n");
return(0);
throw std::runtime_error("CreateNewBlock(): TestBlockValidity failed");
}
//fprintf(stderr,"valid\n");
}
}
/* skip checking validity outside of lock. if inside lock and CC contract is being validated, can deadlock.
if ( ASSETCHAINS_CC != 0 && pindexPrev != 0 && ASSETCHAINS_STAKED == 0 && (ASSETCHAINS_SYMBOL[0] != 0 || IS_KOMODO_NOTARY == 0 || My_notaryid < 0) )
{
CValidationState state;
//fprintf(stderr,"check validity\n");
if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false)) // invokes CC checks
{
//static uint32_t counter;
//if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 )
// fprintf(stderr,"warning: miner testblockvalidity failed\n");
fprintf(stderr,"invalid\n");
return(0);
}
//fprintf(stderr,"valid\n");
}*/
//fprintf(stderr,"done new block\n");
return pblocktemplate.release();
}
@@ -675,7 +661,7 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight, int32_t gpucount, bool isStake)
{
CPubKey pubkey; CScript scriptPubKey; uint8_t *script,*ptr; int32_t i;
CPubKey pubkey; CScript scriptPubKey; uint8_t *ptr; int32_t i;
if ( nHeight == 1 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
{
scriptPubKey = CScript() << ParseHex(ASSETCHAINS_OVERRIDE_PUBKEY) << OP_CHECKSIG;
@@ -693,11 +679,10 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight,
}
scriptPubKey.resize(35);
ptr = (uint8_t *)pubkey.begin();
script = (uint8_t *)scriptPubKey.data();
script[0] = 33;
scriptPubKey[0] = 33;
for (i=0; i<33; i++)
script[i+1] = ptr[i];
script[34] = OP_CHECKSIG;
scriptPubKey[i+1] = ptr[i];
scriptPubKey[34] = OP_CHECKSIG;
//scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
}
return CreateNewBlock(scriptPubKey, gpucount, isStake);

View File

@@ -76,6 +76,7 @@ static std::vector<ListenSocket> vhListenSocket;
CAddrMan addrman;
int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS;
bool fAddressesInitialized = false;
std::string strSubVersion;
vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
@@ -85,10 +86,10 @@ CCriticalSection cs_mapRelay;
limitedmap<CInv, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);
static deque<string> vOneShots;
CCriticalSection cs_vOneShots;
static CCriticalSection cs_vOneShots;
set<CNetAddr> setservAddNodeAddresses;
CCriticalSection cs_setservAddNodeAddresses;
static set<CNetAddr> setservAddNodeAddresses;
static CCriticalSection cs_setservAddNodeAddresses;
vector<std::string> vAddedNodes;
CCriticalSection cs_vAddedNodes;
@@ -97,7 +98,7 @@ NodeId nLastNodeId = 0;
CCriticalSection cs_nLastNodeId;
static CSemaphore *semOutbound = NULL;
boost::condition_variable messageHandlerCondition;
static boost::condition_variable messageHandlerCondition;
// Signals for message handling
static CNodeSignals g_signals;
@@ -439,7 +440,7 @@ void CNode::PushVersion()
else
LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight, true);
nLocalHostNonce, strSubVersion, nBestHeight, true);
}
@@ -823,7 +824,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
}
const Consensus::Params& params = Params().GetConsensus();
int nActivationHeight = params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight;
int nActivationHeight = params.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight;
if (nActivationHeight > 0 &&
height < nActivationHeight &&
@@ -831,7 +832,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
{
// Find any nodes which don't support Overwinter protocol version
BOOST_FOREACH(const CNodeRef &node, vEvictionCandidates) {
if (node->nVersion < params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion) {
if (node->nVersion < params.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion) {
vTmpEvictionCandidates.push_back(node);
}
}
@@ -1819,7 +1820,7 @@ bool StopNode()
return true;
}
class CNetCleanup
static class CNetCleanup
{
public:
CNetCleanup() {}

View File

@@ -49,6 +49,8 @@ static const unsigned int MAX_INV_SZ = 50000;
static const unsigned int MAX_ADDR_TO_SEND = 1000;
/** Maximum length of incoming protocol messages (no message over 2 MiB is currently acceptable). */
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 2 * 1024 * 1024;
/** Maximum length of strSubVer in `version` message */
static const unsigned int MAX_SUBVERSION_LENGTH = 256;
/** -listen default */
static const bool DEFAULT_LISTEN = true;
/** The maximum number of entries in mapAskFor */
@@ -156,6 +158,9 @@ extern CCriticalSection cs_vAddedNodes;
extern NodeId nLastNodeId;
extern CCriticalSection cs_nLastNodeId;
/** Subversion as sent to the P2P network in `version` messages */
extern std::string strSubVersion;
struct LocalServiceInfo {
int nScore;
int nPort;

View File

@@ -97,7 +97,7 @@ class CNetAddr
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(FLATDATA(ip));
}
@@ -162,7 +162,7 @@ class CService : public CNetAddr
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(FLATDATA(ip));
unsigned short portN = htons(port);
READWRITE(FLATDATA(portN));

View File

@@ -1,4 +1,4 @@
#include "leveldbwrapper.h"
#include "dbwrapper.h"
#include "notarisationdb.h"
#include "uint256.h"
#include "cc/eval.h"
@@ -10,7 +10,7 @@
NotarisationDB *pnotarisations;
NotarisationDB::NotarisationDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "notarisations", nCacheSize, fMemory, fWipe, false, 64) { }
NotarisationDB::NotarisationDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "notarisations", nCacheSize, fMemory, fWipe, false, 64) { }
NotarisationsInBlock ScanBlockNotarisations(const CBlock &block, int nHeight)
@@ -67,7 +67,7 @@ bool GetBackNotarisation(uint256 notarisationHash, Notarisation &n)
/*
* Write an index of KMD notarisation id -> backnotarisation
*/
void WriteBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBatch &batch)
void WriteBackNotarisations(const NotarisationsInBlock notarisations, CDBBatch &batch)
{
int wrote = 0;
BOOST_FOREACH(const Notarisation &n, notarisations)
@@ -80,7 +80,7 @@ void WriteBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBa
}
void EraseBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBatch &batch)
void EraseBackNotarisations(const NotarisationsInBlock notarisations, CDBBatch &batch)
{
BOOST_FOREACH(const Notarisation &n, notarisations)
{

View File

@@ -2,11 +2,11 @@
#define NOTARISATIONDB_H
#include "uint256.h"
#include "leveldbwrapper.h"
#include "dbwrapper.h"
#include "cc/eval.h"
class NotarisationDB : public CLevelDBWrapper
class NotarisationDB : public CDBWrapper
{
public:
NotarisationDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
@@ -21,8 +21,8 @@ typedef std::vector<Notarisation> NotarisationsInBlock;
NotarisationsInBlock ScanBlockNotarisations(const CBlock &block, int nHeight);
bool GetBlockNotarisations(uint256 blockHash, NotarisationsInBlock &nibs);
bool GetBackNotarisation(uint256 notarisationHash, Notarisation &n);
void WriteBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBatch &batch);
void EraseBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBatch &batch);
void WriteBackNotarisations(const NotarisationsInBlock notarisations, CDBBatch &batch);
void EraseBackNotarisations(const NotarisationsInBlock notarisations, CDBBatch &batch);
int ScanNotarisationsDB(int height, std::string symbol, int scanLimitBlocks, Notarisation& out);
bool IsTXSCL(const char* symbol);

View File

@@ -3,11 +3,13 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "paymentdisclosure.h"
#include "key_io.h"
#include "util.h"
std::string PaymentDisclosureInfo::ToString() const {
return strprintf("PaymentDisclosureInfo(version=%d, esk=%s, joinSplitPrivKey=<omitted>, address=%s)",
version, esk.ToString(), CZCPaymentAddress(zaddr).ToString());
version, esk.ToString(), EncodePaymentAddress(zaddr));
}
std::string PaymentDisclosure::ToString() const {
@@ -17,7 +19,7 @@ std::string PaymentDisclosure::ToString() const {
std::string PaymentDisclosurePayload::ToString() const {
return strprintf("PaymentDisclosurePayload(version=%d, esk=%s, txid=%s, js=%d, n=%d, address=%s, message=%s)",
version, esk.ToString(), txid.ToString(), js, n, CZCPaymentAddress(zaddr).ToString(), message);
version, esk.ToString(), txid.ToString(), js, n, EncodePaymentAddress(zaddr), message);
}
PaymentDisclosure::PaymentDisclosure(const uint256 &joinSplitPubKey, const PaymentDisclosureKey &key, const PaymentDisclosureInfo &info, const std::string &message)

View File

@@ -14,6 +14,7 @@
// For JSOutPoint
#include "wallet/wallet.h"
#include <array>
#include <cstdint>
#include <string>
@@ -38,17 +39,17 @@ struct PaymentDisclosureInfo {
uint256 joinSplitPrivKey; // primitives/transaction.h
// ed25519 - not tied to implementation e.g. libsodium, see ed25519 rfc
libzcash::PaymentAddress zaddr;
libzcash::SproutPaymentAddress zaddr;
PaymentDisclosureInfo() : version(PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL) {
}
PaymentDisclosureInfo(uint8_t v, uint256 esk, uint256 key, libzcash::PaymentAddress zaddr) : version(v), esk(esk), joinSplitPrivKey(key), zaddr(zaddr) { }
PaymentDisclosureInfo(uint8_t v, uint256 esk, uint256 key, libzcash::SproutPaymentAddress zaddr) : version(v), esk(esk), joinSplitPrivKey(key), zaddr(zaddr) { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(version);
READWRITE(esk);
READWRITE(joinSplitPrivKey);
@@ -73,19 +74,15 @@ struct PaymentDisclosurePayload {
uint8_t version; // 0 = experimental, 1 = first production version, etc.
uint256 esk; // zcash/NoteEncryption.cpp
uint256 txid; // primitives/transaction.h
#ifdef __LP64__
uint64_t js;
#else
size_t js; // Index into CTransaction.vjoinsplit
#endif
uint64_t js; // Index into CTransaction.vjoinsplit
uint8_t n; // Index into JSDescription fields of length ZC_NUM_JS_OUTPUTS
libzcash::PaymentAddress zaddr; // zcash/Address.hpp
libzcash::SproutPaymentAddress zaddr; // zcash/Address.hpp
std::string message; // parameter to RPC call
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(marker);
READWRITE(version);
READWRITE(esk);
@@ -116,18 +113,18 @@ struct PaymentDisclosurePayload {
};
struct PaymentDisclosure {
PaymentDisclosurePayload payload;
boost::array<unsigned char, 64> payloadSig;
PaymentDisclosurePayload payload;
std::array<unsigned char, 64> payloadSig;
// We use boost array because serialize doesn't like char buffer, otherwise we could do: unsigned char payloadSig[64];
PaymentDisclosure() {};
PaymentDisclosure(const PaymentDisclosurePayload payload, const boost::array<unsigned char, 64> sig) : payload(payload), payloadSig(sig) {};
PaymentDisclosure(const PaymentDisclosurePayload payload, const std::array<unsigned char, 64> sig) : payload(payload), payloadSig(sig) {};
PaymentDisclosure(const uint256& joinSplitPubKey, const PaymentDisclosureKey& key, const PaymentDisclosureInfo& info, const std::string& message);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(payload);
READWRITE(payloadSig);
}

View File

@@ -5,7 +5,7 @@
#include "paymentdisclosuredb.h"
#include "util.h"
#include "leveldbwrapper.h"
#include "dbwrapper.h"
#include <boost/filesystem.hpp>
@@ -38,7 +38,7 @@ PaymentDisclosureDB::PaymentDisclosureDB(const boost::filesystem::path& dbPath)
TryCreateDirectory(path);
options.create_if_missing = true;
leveldb::Status status = leveldb::DB::Open(options, path.string(), &db);
HandleError(status); // throws exception
dbwrapper_private::HandleError(status); // throws exception
LogPrintf("PaymentDisclosure: Opened LevelDB successfully\n");
}
@@ -57,12 +57,12 @@ bool PaymentDisclosureDB::Put(const PaymentDisclosureKey& key, const PaymentDisc
std::lock_guard<std::mutex> guard(lock_);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
ssValue.reserve(ssValue.GetSerializeSize(info));
ssValue.reserve(GetSerializeSize(ssValue, info));
ssValue << info;
leveldb::Slice slice(&ssValue[0], ssValue.size());
leveldb::Status status = db->Put(writeOptions, key.ToString(), slice);
HandleError(status);
dbwrapper_private::HandleError(status);
return true;
}
@@ -80,7 +80,7 @@ bool PaymentDisclosureDB::Get(const PaymentDisclosureKey& key, PaymentDisclosure
if (status.IsNotFound())
return false;
LogPrintf("PaymentDisclosure: LevelDB read failure: %s\n", status.ToString());
HandleError(status);
dbwrapper_private::HandleError(status);
}
try {

View File

@@ -322,14 +322,6 @@ bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& param
// H(I||V||...
crypto_generichash_blake2b_update(&state, (unsigned char*)&ss[0], ss.size());
#ifdef ENABLE_RUST
// Ensure that our Rust interactions are working in production builds. This is
// temporary and should be removed.
{
assert(librustzcash_xor(0x0f0f0f0f0f0f0f0f, 0x1111111111111111) == 0x1e1e1e1e1e1e1e1e);
}
#endif // ENABLE_RUST
bool isValid;
EhIsValidSolution(n, k, state, pblock->nSolution, isValid);

494
src/prevector.h Normal file
View File

@@ -0,0 +1,494 @@
#ifndef _BITCOIN_PREVECTOR_H_
#define _BITCOIN_PREVECTOR_H_
#include <util.h>
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <iterator>
#pragma pack(push, 1)
/** Implements a drop-in replacement for std::vector<T> which stores up to N
* elements directly (without heap allocation). The types Size and Diff are
* used to store element counts, and can be any unsigned + signed type.
*
* Storage layout is either:
* - Direct allocation:
* - Size _size: the number of used elements (between 0 and N)
* - T direct[N]: an array of N elements of type T
* (only the first _size are initialized).
* - Indirect allocation:
* - Size _size: the number of used elements plus N + 1
* - Size capacity: the number of allocated elements
* - T* indirect: a pointer to an array of capacity elements of type T
* (only the first _size are initialized).
*
* The data type T must be movable by memmove/realloc(). Once we switch to C++,
* move constructors can be used instead.
*/
template<unsigned int N, typename T, typename Size = uint32_t, typename Diff = int32_t>
class prevector {
public:
typedef Size size_type;
typedef Diff difference_type;
typedef T value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* pointer;
typedef const value_type* const_pointer;
class iterator {
T* ptr;
public:
typedef Diff difference_type;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef std::random_access_iterator_tag iterator_category;
iterator(T* ptr_) : ptr(ptr_) {}
T& operator*() const { return *ptr; }
T* operator->() const { return ptr; }
T& operator[](size_type pos) { return ptr[pos]; }
const T& operator[](size_type pos) const { return ptr[pos]; }
iterator& operator++() { ptr++; return *this; }
iterator& operator--() { ptr--; return *this; }
iterator operator++(int) { iterator copy(*this); ++(*this); return copy; }
iterator operator--(int) { iterator copy(*this); --(*this); return copy; }
difference_type friend operator-(iterator a, iterator b) { return (&(*a) - &(*b)); }
iterator operator+(size_type n) { return iterator(ptr + n); }
iterator& operator+=(size_type n) { ptr += n; return *this; }
iterator operator-(size_type n) { return iterator(ptr - n); }
iterator& operator-=(size_type n) { ptr -= n; return *this; }
bool operator==(iterator x) const { return ptr == x.ptr; }
bool operator!=(iterator x) const { return ptr != x.ptr; }
bool operator>=(iterator x) const { return ptr >= x.ptr; }
bool operator<=(iterator x) const { return ptr <= x.ptr; }
bool operator>(iterator x) const { return ptr > x.ptr; }
bool operator<(iterator x) const { return ptr < x.ptr; }
};
class reverse_iterator {
T* ptr;
public:
typedef Diff difference_type;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef std::bidirectional_iterator_tag iterator_category;
reverse_iterator(T* ptr_) : ptr(ptr_) {}
T& operator*() { return *ptr; }
const T& operator*() const { return *ptr; }
T* operator->() { return ptr; }
const T* operator->() const { return ptr; }
reverse_iterator& operator--() { ptr++; return *this; }
reverse_iterator& operator++() { ptr--; return *this; }
reverse_iterator operator++(int) { reverse_iterator copy(*this); ++(*this); return copy; }
reverse_iterator operator--(int) { reverse_iterator copy(*this); --(*this); return copy; }
bool operator==(reverse_iterator x) const { return ptr == x.ptr; }
bool operator!=(reverse_iterator x) const { return ptr != x.ptr; }
};
class const_iterator {
const T* ptr;
public:
typedef Diff difference_type;
typedef const T value_type;
typedef const T* pointer;
typedef const T& reference;
typedef std::random_access_iterator_tag iterator_category;
const_iterator(const T* ptr_) : ptr(ptr_) {}
const_iterator(iterator x) : ptr(&(*x)) {}
const T& operator*() const { return *ptr; }
const T* operator->() const { return ptr; }
const T& operator[](size_type pos) const { return ptr[pos]; }
const_iterator& operator++() { ptr++; return *this; }
const_iterator& operator--() { ptr--; return *this; }
const_iterator operator++(int) { const_iterator copy(*this); ++(*this); return copy; }
const_iterator operator--(int) { const_iterator copy(*this); --(*this); return copy; }
difference_type friend operator-(const_iterator a, const_iterator b) { return (&(*a) - &(*b)); }
const_iterator operator+(size_type n) { return const_iterator(ptr + n); }
const_iterator& operator+=(size_type n) { ptr += n; return *this; }
const_iterator operator-(size_type n) { return const_iterator(ptr - n); }
const_iterator& operator-=(size_type n) { ptr -= n; return *this; }
bool operator==(const_iterator x) const { return ptr == x.ptr; }
bool operator!=(const_iterator x) const { return ptr != x.ptr; }
bool operator>=(const_iterator x) const { return ptr >= x.ptr; }
bool operator<=(const_iterator x) const { return ptr <= x.ptr; }
bool operator>(const_iterator x) const { return ptr > x.ptr; }
bool operator<(const_iterator x) const { return ptr < x.ptr; }
};
class const_reverse_iterator {
const T* ptr;
public:
typedef Diff difference_type;
typedef const T value_type;
typedef const T* pointer;
typedef const T& reference;
typedef std::bidirectional_iterator_tag iterator_category;
const_reverse_iterator(T* ptr_) : ptr(ptr_) {}
const_reverse_iterator(reverse_iterator x) : ptr(&(*x)) {}
const T& operator*() const { return *ptr; }
const T* operator->() const { return ptr; }
const_reverse_iterator& operator--() { ptr++; return *this; }
const_reverse_iterator& operator++() { ptr--; return *this; }
const_reverse_iterator operator++(int) { const_reverse_iterator copy(*this); ++(*this); return copy; }
const_reverse_iterator operator--(int) { const_reverse_iterator copy(*this); --(*this); return copy; }
bool operator==(const_reverse_iterator x) const { return ptr == x.ptr; }
bool operator!=(const_reverse_iterator x) const { return ptr != x.ptr; }
};
private:
size_type _size;
union {
char direct[sizeof(T) * N];
struct {
size_type capacity;
char* indirect;
};
} _union;
T* direct_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.direct) + pos; }
const T* direct_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.direct) + pos; }
T* indirect_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.indirect) + pos; }
const T* indirect_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.indirect) + pos; }
bool is_direct() const { return _size <= N; }
void change_capacity(size_type new_capacity) {
if (new_capacity <= N) {
if (!is_direct()) {
T* indirect = indirect_ptr(0);
T* src = indirect;
T* dst = direct_ptr(0);
memcpy(dst, src, size() * sizeof(T));
free(indirect);
_size -= N + 1;
}
} else {
if (!is_direct()) {
/* FIXME: Because malloc/realloc here won't call new_handler if allocation fails, assert
success. These should instead use an allocator or new/delete so that handlers
are called as necessary, but performance would be slightly degraded by doing so. */
_union.indirect = static_cast<char*>(realloc(_union.indirect, ((size_t)sizeof(T)) * new_capacity));
if (!_union.indirect) { new_handler_terminate(); }
_union.capacity = new_capacity;
} else {
char* new_indirect = static_cast<char*>(malloc(((size_t)sizeof(T)) * new_capacity));
if (!new_indirect) { new_handler_terminate(); }
T* src = direct_ptr(0);
T* dst = reinterpret_cast<T*>(new_indirect);
memcpy(dst, src, size() * sizeof(T));
_union.indirect = new_indirect;
_union.capacity = new_capacity;
_size += N + 1;
}
}
}
T* item_ptr(difference_type pos) { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); }
const T* item_ptr(difference_type pos) const { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); }
public:
void assign(size_type n, const T& val) {
clear();
if (capacity() < n) {
change_capacity(n);
}
while (size() < n) {
_size++;
new(static_cast<void*>(item_ptr(size() - 1))) T(val);
}
}
template<typename InputIterator>
void assign(InputIterator first, InputIterator last) {
size_type n = last - first;
clear();
if (capacity() < n) {
change_capacity(n);
}
while (first != last) {
_size++;
new(static_cast<void*>(item_ptr(size() - 1))) T(*first);
++first;
}
}
prevector() : _size(0) {}
explicit prevector(size_type n) : _size(0) {
resize(n);
}
explicit prevector(size_type n, const T& val = T()) : _size(0) {
change_capacity(n);
while (size() < n) {
_size++;
new(static_cast<void*>(item_ptr(size() - 1))) T(val);
}
}
template<typename InputIterator>
prevector(InputIterator first, InputIterator last) : _size(0) {
size_type n = last - first;
change_capacity(n);
while (first != last) {
_size++;
new(static_cast<void*>(item_ptr(size() - 1))) T(*first);
++first;
}
}
prevector(const prevector<N, T, Size, Diff>& other) : _size(0) {
change_capacity(other.size());
const_iterator it = other.begin();
while (it != other.end()) {
_size++;
new(static_cast<void*>(item_ptr(size() - 1))) T(*it);
++it;
}
}
prevector& operator=(const prevector<N, T, Size, Diff>& other) {
if (&other == this) {
return *this;
}
resize(0);
change_capacity(other.size());
const_iterator it = other.begin();
while (it != other.end()) {
_size++;
new(static_cast<void*>(item_ptr(size() - 1))) T(*it);
++it;
}
return *this;
}
size_type size() const {
return is_direct() ? _size : _size - N - 1;
}
bool empty() const {
return size() == 0;
}
iterator begin() { return iterator(item_ptr(0)); }
const_iterator begin() const { return const_iterator(item_ptr(0)); }
iterator end() { return iterator(item_ptr(size())); }
const_iterator end() const { return const_iterator(item_ptr(size())); }
reverse_iterator rbegin() { return reverse_iterator(item_ptr(size() - 1)); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(item_ptr(size() - 1)); }
reverse_iterator rend() { return reverse_iterator(item_ptr(-1)); }
const_reverse_iterator rend() const { return const_reverse_iterator(item_ptr(-1)); }
size_t capacity() const {
if (is_direct()) {
return N;
} else {
return _union.capacity;
}
}
T& operator[](size_type pos) {
return *item_ptr(pos);
}
const T& operator[](size_type pos) const {
return *item_ptr(pos);
}
void resize(size_type new_size) {
while (size() > new_size) {
item_ptr(size() - 1)->~T();
_size--;
}
if (new_size > capacity()) {
change_capacity(new_size);
}
while (size() < new_size) {
_size++;
new(static_cast<void*>(item_ptr(size() - 1))) T();
}
}
void reserve(size_type new_capacity) {
if (new_capacity > capacity()) {
change_capacity(new_capacity);
}
}
void shrink_to_fit() {
change_capacity(size());
}
void clear() {
resize(0);
}
iterator insert(iterator pos, const T& value) {
size_type p = pos - begin();
size_type new_size = size() + 1;
if (capacity() < new_size) {
change_capacity(new_size + (new_size >> 1));
}
memmove(item_ptr(p + 1), item_ptr(p), (size() - p) * sizeof(T));
_size++;
new(static_cast<void*>(item_ptr(p))) T(value);
return iterator(item_ptr(p));
}
void insert(iterator pos, size_type count, const T& value) {
size_type p = pos - begin();
size_type new_size = size() + count;
if (capacity() < new_size) {
change_capacity(new_size + (new_size >> 1));
}
memmove(item_ptr(p + count), item_ptr(p), (size() - p) * sizeof(T));
_size += count;
for (size_type i = 0; i < count; i++) {
new(static_cast<void*>(item_ptr(p + i))) T(value);
}
}
template<typename InputIterator>
void insert(iterator pos, InputIterator first, InputIterator last) {
size_type p = pos - begin();
difference_type count = last - first;
size_type new_size = size() + count;
if (capacity() < new_size) {
change_capacity(new_size + (new_size >> 1));
}
memmove(item_ptr(p + count), item_ptr(p), (size() - p) * sizeof(T));
_size += count;
while (first != last) {
new(static_cast<void*>(item_ptr(p))) T(*first);
++p;
++first;
}
}
iterator erase(iterator pos) {
(*pos).~T();
memmove(&(*pos), &(*pos) + 1, ((char*)&(*end())) - ((char*)(1 + &(*pos))));
_size--;
return pos;
}
iterator erase(iterator first, iterator last) {
iterator p = first;
char* endp = (char*)&(*end());
while (p != last) {
(*p).~T();
_size--;
++p;
}
memmove(&(*first), &(*last), endp - ((char*)(&(*last))));
return first;
}
void push_back(const T& value) {
size_type new_size = size() + 1;
if (capacity() < new_size) {
change_capacity(new_size + (new_size >> 1));
}
new(item_ptr(size())) T(value);
_size++;
}
void pop_back() {
_size--;
}
T& front() {
return *item_ptr(0);
}
const T& front() const {
return *item_ptr(0);
}
T& back() {
return *item_ptr(size() - 1);
}
const T& back() const {
return *item_ptr(size() - 1);
}
void swap(prevector<N, T, Size, Diff>& other) {
if (_size & other._size & 1) {
std::swap(_union.capacity, other._union.capacity);
std::swap(_union.indirect, other._union.indirect);
} else {
std::swap(_union, other._union);
}
std::swap(_size, other._size);
}
~prevector() {
clear();
if (!is_direct()) {
free(_union.indirect);
_union.indirect = NULL;
}
}
bool operator==(const prevector<N, T, Size, Diff>& other) const {
if (other.size() != size()) {
return false;
}
const_iterator b1 = begin();
const_iterator b2 = other.begin();
const_iterator e1 = end();
while (b1 != e1) {
if ((*b1) != (*b2)) {
return false;
}
++b1;
++b2;
}
return true;
}
bool operator!=(const prevector<N, T, Size, Diff>& other) const {
return !(*this == other);
}
bool operator<(const prevector<N, T, Size, Diff>& other) const {
if (size() < other.size()) {
return true;
}
if (size() > other.size()) {
return false;
}
const_iterator b1 = begin();
const_iterator b2 = other.begin();
const_iterator e1 = end();
while (b1 != e1) {
if ((*b1) < (*b2)) {
return true;
}
if ((*b2) < (*b1)) {
return false;
}
++b1;
++b2;
}
return false;
}
size_t allocated_memory() const {
if (is_direct()) {
return 0;
} else {
return ((size_t)(sizeof(T))) * _union.capacity;
}
}
};
#pragma pack(pop)
#endif

View File

@@ -202,12 +202,12 @@ uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMer
std::string CBlock::ToString() const
{
std::stringstream s;
s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, hashReserved=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n",
s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, hashFinalSaplingRoot=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n",
GetHash().ToString(),
nVersion,
hashPrevBlock.ToString(),
hashMerkleRoot.ToString(),
hashReserved.ToString(),
hashFinalSaplingRoot.ToString(),
nTime, nBits, nNonce.ToString(),
vtx.size());
for (unsigned int i = 0; i < vtx.size(); i++)

View File

@@ -31,7 +31,7 @@ public:
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
uint256 hashReserved;
uint256 hashFinalSaplingRoot;
uint32_t nTime;
uint32_t nBits;
CPOSNonce nNonce;
@@ -45,12 +45,11 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
READWRITE(hashReserved);
READWRITE(hashFinalSaplingRoot);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
@@ -62,7 +61,7 @@ public:
nVersion = CBlockHeader::CURRENT_VERSION;
hashPrevBlock.SetNull();
hashMerkleRoot.SetNull();
hashReserved.SetNull();
hashFinalSaplingRoot.SetNull();
nTime = 0;
nBits = 0;
nNonce = uint256();
@@ -156,7 +155,7 @@ class CNetworkBlockHeader : public CBlockHeader
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*(CBlockHeader*)this);
READWRITE(compatVec);
}
@@ -191,7 +190,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*(CBlockHeader*)this);
READWRITE(vtx);
}
@@ -209,7 +208,7 @@ public:
block.nVersion = nVersion;
block.hashPrevBlock = hashPrevBlock;
block.hashMerkleRoot = hashMerkleRoot;
block.hashReserved = hashReserved;
block.hashFinalSaplingRoot = hashFinalSaplingRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
@@ -251,12 +250,11 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
READWRITE(hashReserved);
READWRITE(hashFinalSaplingRoot);
READWRITE(nTime);
READWRITE(nBits);
}
@@ -281,8 +279,9 @@ struct CBlockLocator
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
if (!(nType & SER_GETHASH))
inline void SerializationOp(Stream& s, Operation ser_action) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vHave);
}

View File

@@ -9,26 +9,31 @@
#include "tinyformat.h"
#include "utilstrencodings.h"
JSDescription::JSDescription(ZCJoinSplit& params,
const uint256& pubKeyHash,
const uint256& anchor,
const boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
const boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
CAmount vpub_old,
CAmount vpub_new,
bool computeProof,
uint256 *esk // payment disclosure
) : vpub_old(vpub_old), vpub_new(vpub_new), anchor(anchor)
#include "librustzcash.h"
JSDescription::JSDescription(
bool makeGrothProof,
ZCJoinSplit& params,
const uint256& joinSplitPubKey,
const uint256& anchor,
const std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
const std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
CAmount vpub_old,
CAmount vpub_new,
bool computeProof,
uint256 *esk // payment disclosure
) : vpub_old(vpub_old), vpub_new(vpub_new), anchor(anchor)
{
boost::array<libzcash::Note, ZC_NUM_JS_OUTPUTS> notes;
std::array<libzcash::SproutNote, ZC_NUM_JS_OUTPUTS> notes;
proof = params.prove(
makeGrothProof,
inputs,
outputs,
notes,
ciphertexts,
ephemeralKey,
pubKeyHash,
joinSplitPubKey,
randomSeed,
macs,
nullifiers,
@@ -42,24 +47,20 @@ JSDescription::JSDescription(ZCJoinSplit& params,
}
JSDescription JSDescription::Randomized(
ZCJoinSplit& params,
const uint256& pubKeyHash,
const uint256& anchor,
boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
#ifdef __LP64__
boost::array<uint64_t, ZC_NUM_JS_INPUTS>& inputMap,
boost::array<uint64_t, ZC_NUM_JS_OUTPUTS>& outputMap,
#else
boost::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
boost::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap,
#endif
CAmount vpub_old,
CAmount vpub_new,
bool computeProof,
uint256 *esk, // payment disclosure
std::function<int(int)> gen
)
bool makeGrothProof,
ZCJoinSplit& params,
const uint256& joinSplitPubKey,
const uint256& anchor,
std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
std::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
std::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap,
CAmount vpub_old,
CAmount vpub_new,
bool computeProof,
uint256 *esk, // payment disclosure
std::function<int(int)> gen
)
{
// Randomize the order of the inputs and outputs
inputMap = {0, 1};
@@ -71,34 +72,76 @@ JSDescription JSDescription::Randomized(
MappedShuffle(outputs.begin(), outputMap.begin(), ZC_NUM_JS_OUTPUTS, gen);
return JSDescription(
params, pubKeyHash, anchor, inputs, outputs,
makeGrothProof,
params, joinSplitPubKey, anchor, inputs, outputs,
vpub_old, vpub_new, computeProof,
esk // payment disclosure
);
}
class SproutProofVerifier : public boost::static_visitor<bool>
{
ZCJoinSplit& params;
libzcash::ProofVerifier& verifier;
const uint256& joinSplitPubKey;
const JSDescription& jsdesc;
public:
SproutProofVerifier(
ZCJoinSplit& params,
libzcash::ProofVerifier& verifier,
const uint256& joinSplitPubKey,
const JSDescription& jsdesc
) : params(params), jsdesc(jsdesc), verifier(verifier), joinSplitPubKey(joinSplitPubKey) {}
bool operator()(const libzcash::PHGRProof& proof) const
{
return params.verify(
proof,
verifier,
joinSplitPubKey,
jsdesc.randomSeed,
jsdesc.macs,
jsdesc.nullifiers,
jsdesc.commitments,
jsdesc.vpub_old,
jsdesc.vpub_new,
jsdesc.anchor
);
}
bool operator()(const libzcash::GrothProof& proof) const
{
uint256 h_sig = params.h_sig(jsdesc.randomSeed, jsdesc.nullifiers, joinSplitPubKey);
return librustzcash_sprout_verify(
proof.begin(),
jsdesc.anchor.begin(),
h_sig.begin(),
jsdesc.macs[0].begin(),
jsdesc.macs[1].begin(),
jsdesc.nullifiers[0].begin(),
jsdesc.nullifiers[1].begin(),
jsdesc.commitments[0].begin(),
jsdesc.commitments[1].begin(),
jsdesc.vpub_old,
jsdesc.vpub_new
);
}
};
bool JSDescription::Verify(
ZCJoinSplit& params,
libzcash::ProofVerifier& verifier,
const uint256& pubKeyHash
const uint256& joinSplitPubKey
) const {
return params.verify(
proof,
verifier,
pubKeyHash,
randomSeed,
macs,
nullifiers,
commitments,
vpub_old,
vpub_new,
anchor
);
auto pv = SproutProofVerifier(params, verifier, joinSplitPubKey, *this);
return boost::apply_visitor(pv, proof);
}
uint256 JSDescription::h_sig(ZCJoinSplit& params, const uint256& pubKeyHash) const
uint256 JSDescription::h_sig(ZCJoinSplit& params, const uint256& joinSplitPubKey) const
{
return params.h_sig(randomSeed, nullifiers, pubKeyHash);
return params.h_sig(randomSeed, nullifiers, joinSplitPubKey);
}
std::string COutPoint::ToString() const
@@ -106,6 +149,11 @@ std::string COutPoint::ToString() const
return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n);
}
std::string SaplingOutPoint::ToString() const
{
return strprintf("SaplingOutPoint(%s, %u)", hash.ToString().substr(0, 10), n);
}
CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn)
{
prevout = prevoutIn;
@@ -128,7 +176,7 @@ std::string CTxIn::ToString() const
if (prevout.IsNull())
str += strprintf(", coinbase %s", HexStr(scriptSig));
else
str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24));
str += strprintf(", scriptSig=%s", HexStr(scriptSig).substr(0, 24));
if (nSequence != std::numeric_limits<unsigned int>::max())
str += strprintf(", nSequence=%u", nSequence);
str += ")";
@@ -148,13 +196,15 @@ uint256 CTxOut::GetHash() const
std::string CTxOut::ToString() const
{
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30));
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
}
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::SPROUT_MIN_CURRENT_VERSION), fOverwintered(false), nVersionGroupId(0), nExpiryHeight(0), nLockTime(0) {}
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::SPROUT_MIN_CURRENT_VERSION), fOverwintered(false), nVersionGroupId(0), nExpiryHeight(0), nLockTime(0), valueBalance(0) {}
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), fOverwintered(tx.fOverwintered), nVersionGroupId(tx.nVersionGroupId), nExpiryHeight(tx.nExpiryHeight),
vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime),
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
valueBalance(tx.valueBalance), vShieldedSpend(tx.vShieldedSpend), vShieldedOutput(tx.vShieldedOutput),
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig),
bindingSig(tx.bindingSig)
{
}
@@ -169,11 +219,13 @@ void CTransaction::UpdateHash() const
*const_cast<uint256*>(&hash) = SerializeHash(*this);
}
CTransaction::CTransaction() : nVersion(CTransaction::SPROUT_MIN_CURRENT_VERSION), fOverwintered(false), nVersionGroupId(0), nExpiryHeight(0), vin(), vout(), nLockTime(0), vjoinsplit(), joinSplitPubKey(), joinSplitSig() { }
CTransaction::CTransaction() : nVersion(CTransaction::SPROUT_MIN_CURRENT_VERSION), fOverwintered(false), nVersionGroupId(0), nExpiryHeight(0), vin(), vout(), nLockTime(0), valueBalance(0), vShieldedSpend(), vShieldedOutput(), vjoinsplit(), joinSplitPubKey(), joinSplitSig(), bindingSig() { }
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), fOverwintered(tx.fOverwintered), nVersionGroupId(tx.nVersionGroupId), nExpiryHeight(tx.nExpiryHeight),
vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime),
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
valueBalance(tx.valueBalance), vShieldedSpend(tx.vShieldedSpend), vShieldedOutput(tx.vShieldedOutput),
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig),
bindingSig(tx.bindingSig)
{
UpdateHash();
}
@@ -184,11 +236,23 @@ CTransaction::CTransaction(
const CMutableTransaction &tx,
bool evilDeveloperFlag) : nVersion(tx.nVersion), fOverwintered(tx.fOverwintered), nVersionGroupId(tx.nVersionGroupId), nExpiryHeight(tx.nExpiryHeight),
vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime),
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
valueBalance(tx.valueBalance), vShieldedSpend(tx.vShieldedSpend), vShieldedOutput(tx.vShieldedOutput),
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig),
bindingSig(tx.bindingSig)
{
assert(evilDeveloperFlag);
}
CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), fOverwintered(tx.fOverwintered), nVersionGroupId(tx.nVersionGroupId),
vin(std::move(tx.vin)), vout(std::move(tx.vout)), nLockTime(tx.nLockTime), nExpiryHeight(tx.nExpiryHeight),
valueBalance(tx.valueBalance),
vShieldedSpend(std::move(tx.vShieldedSpend)), vShieldedOutput(std::move(tx.vShieldedOutput)),
vjoinsplit(std::move(tx.vjoinsplit)),
joinSplitPubKey(std::move(tx.joinSplitPubKey)), joinSplitSig(std::move(tx.joinSplitSig))
{
UpdateHash();
}
CTransaction& CTransaction::operator=(const CTransaction &tx) {
*const_cast<bool*>(&fOverwintered) = tx.fOverwintered;
*const_cast<int*>(&nVersion) = tx.nVersion;
@@ -197,9 +261,13 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) {
*const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
*const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
*const_cast<uint32_t*>(&nExpiryHeight) = tx.nExpiryHeight;
*const_cast<CAmount*>(&valueBalance) = tx.valueBalance;
*const_cast<std::vector<SpendDescription>*>(&vShieldedSpend) = tx.vShieldedSpend;
*const_cast<std::vector<OutputDescription>*>(&vShieldedOutput) = tx.vShieldedOutput;
*const_cast<std::vector<JSDescription>*>(&vjoinsplit) = tx.vjoinsplit;
*const_cast<uint256*>(&joinSplitPubKey) = tx.joinSplitPubKey;
*const_cast<joinsplit_sig_t*>(&joinSplitSig) = tx.joinSplitSig;
*const_cast<binding_sig_t*>(&bindingSig) = tx.bindingSig;
*const_cast<uint256*>(&hash) = tx.hash;
return *this;
}
@@ -214,9 +282,18 @@ CAmount CTransaction::GetValueOut() const
throw std::runtime_error("CTransaction::GetValueOut(): value out of range");
}
if (valueBalance <= 0) {
// NB: negative valueBalance "takes" money from the transparent value pool just as outputs do
nValueOut += -valueBalance;
if (!MoneyRange(-valueBalance) || !MoneyRange(nValueOut)) {
throw std::runtime_error("CTransaction::GetValueOut(): value out of range");
}
}
for (std::vector<JSDescription>::const_iterator it(vjoinsplit.begin()); it != vjoinsplit.end(); ++it)
{
// NB: vpub_old "takes" money from the value pool just as outputs do
// NB: vpub_old "takes" money from the transparent value pool just as outputs do
nValueOut += it->vpub_old;
if (!MoneyRange(it->vpub_old) || !MoneyRange(nValueOut))
@@ -225,31 +302,26 @@ CAmount CTransaction::GetValueOut() const
return nValueOut;
}
CAmount CTransaction::GetJoinSplitValueIn() const
CAmount CTransaction::GetShieldedValueIn() const
{
CAmount nValue = 0;
if (valueBalance >= 0) {
// NB: positive valueBalance "gives" money to the transparent value pool just as inputs do
nValue += valueBalance;
if (!MoneyRange(valueBalance) || !MoneyRange(nValue)) {
throw std::runtime_error("CTransaction::GetShieldedValueIn(): value out of range");
}
}
for (std::vector<JSDescription>::const_iterator it(vjoinsplit.begin()); it != vjoinsplit.end(); ++it)
{
// NB: vpub_new "gives" money to the value pool just as inputs do
// NB: vpub_new "gives" money to the transparent value pool just as inputs do
nValue += it->vpub_new;
if (!MoneyRange(it->vpub_new) || !MoneyRange(nValue))
throw std::runtime_error("CTransaction::GetJoinSplitValueIn(): value out of range");
}
return nValue;
}
CAmount CTransaction::GetJoinSplitValueOut() const
{
CAmount nValue = 0;
for (std::vector<JSDescription>::const_iterator it(vjoinsplit.begin()); it != vjoinsplit.end(); ++it)
{
// NB: vpub_new "gives" money to the value pool just as inputs do
nValue += it->vpub_old;
if (!MoneyRange(it->vpub_old) || !MoneyRange(nValue))
throw std::runtime_error("CTransaction::GetJoinSplitValueOut(): value out of range");
throw std::runtime_error("CTransaction::GetShieldedValueIn(): value out of range");
}
return nValue;
@@ -321,6 +393,19 @@ std::string CTransaction::ToString() const
vin.size(),
vout.size(),
nLockTime);
} else if (nVersion >= SAPLING_MIN_TX_VERSION) {
str += strprintf("CTransaction(hash=%s, ver=%d, fOverwintered=%d, nVersionGroupId=%08x, vin.size=%u, vout.size=%u, nLockTime=%u, nExpiryHeight=%u, valueBalance=%u, vShieldedSpend.size=%u, vShieldedOutput.size=%u)\n",
GetHash().ToString().substr(0,10),
nVersion,
fOverwintered,
nVersionGroupId,
vin.size(),
vout.size(),
nLockTime,
nExpiryHeight,
valueBalance,
vShieldedSpend.size(),
vShieldedOutput.size());
} else if (nVersion >= 3) {
str += strprintf("CTransaction(hash=%s, ver=%d, fOverwintered=%d, nVersionGroupId=%08x, vin.size=%u, vout.size=%u, nLockTime=%u, nExpiryHeight=%u)\n",
GetHash().ToString().substr(0,10),

View File

@@ -10,6 +10,7 @@
#include "random.h"
#include "script/script.h"
#include "serialize.h"
#include "streams.h"
#include "uint256.h"
#include "arith_uint256.h"
#include "consensus/consensus.h"
@@ -20,7 +21,9 @@
#include <stdint.h>
#endif
#include <boost/array.hpp>
#include <array>
#include <boost/variant.hpp>
#include "zcash/NoteEncryption.hpp"
#include "zcash/Zcash.h"
@@ -29,6 +32,159 @@
extern uint32_t ASSETCHAINS_MAGIC;
// Overwinter transaction version
static const int32_t OVERWINTER_TX_VERSION = 3;
static_assert(OVERWINTER_TX_VERSION >= OVERWINTER_MIN_TX_VERSION,
"Overwinter tx version must not be lower than minimum");
static_assert(OVERWINTER_TX_VERSION <= OVERWINTER_MAX_TX_VERSION,
"Overwinter tx version must not be higher than maximum");
// Sapling transaction version
static const int32_t SAPLING_TX_VERSION = 4;
static_assert(SAPLING_TX_VERSION >= SAPLING_MIN_TX_VERSION,
"Sapling tx version must not be lower than minimum");
static_assert(SAPLING_TX_VERSION <= SAPLING_MAX_TX_VERSION,
"Sapling tx version must not be higher than maximum");
/**
* A shielded input to a transaction. It contains data that describes a Spend transfer.
*/
class SpendDescription
{
public:
typedef std::array<unsigned char, 64> spend_auth_sig_t;
uint256 cv; //!< A value commitment to the value of the input note.
uint256 anchor; //!< A Merkle root of the Sapling note commitment tree at some block height in the past.
uint256 nullifier; //!< The nullifier of the input note.
uint256 rk; //!< The randomized public key for spendAuthSig.
libzcash::GrothProof zkproof; //!< A zero-knowledge proof using the spend circuit.
spend_auth_sig_t spendAuthSig; //!< A signature authorizing this spend.
SpendDescription() { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(cv);
READWRITE(anchor);
READWRITE(nullifier);
READWRITE(rk);
READWRITE(zkproof);
READWRITE(spendAuthSig);
}
friend bool operator==(const SpendDescription& a, const SpendDescription& b)
{
return (
a.cv == b.cv &&
a.anchor == b.anchor &&
a.nullifier == b.nullifier &&
a.rk == b.rk &&
a.zkproof == b.zkproof &&
a.spendAuthSig == b.spendAuthSig
);
}
friend bool operator!=(const SpendDescription& a, const SpendDescription& b)
{
return !(a == b);
}
};
/**
* A shielded output to a transaction. It contains data that describes an Output transfer.
*/
class OutputDescription
{
public:
uint256 cv; //!< A value commitment to the value of the output note.
uint256 cm; //!< The note commitment for the output note.
uint256 ephemeralKey; //!< A Jubjub public key.
libzcash::SaplingEncCiphertext encCiphertext; //!< A ciphertext component for the encrypted output note.
libzcash::SaplingOutCiphertext outCiphertext; //!< A ciphertext component for the encrypted output note.
libzcash::GrothProof zkproof; //!< A zero-knowledge proof using the output circuit.
OutputDescription() { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(cv);
READWRITE(cm);
READWRITE(ephemeralKey);
READWRITE(encCiphertext);
READWRITE(outCiphertext);
READWRITE(zkproof);
}
friend bool operator==(const OutputDescription& a, const OutputDescription& b)
{
return (
a.cv == b.cv &&
a.cm == b.cm &&
a.ephemeralKey == b.ephemeralKey &&
a.encCiphertext == b.encCiphertext &&
a.outCiphertext == b.outCiphertext &&
a.zkproof == b.zkproof
);
}
friend bool operator!=(const OutputDescription& a, const OutputDescription& b)
{
return !(a == b);
}
};
template <typename Stream>
class SproutProofSerializer : public boost::static_visitor<>
{
Stream& s;
bool useGroth;
public:
SproutProofSerializer(Stream& s, bool useGroth) : s(s), useGroth(useGroth) {}
void operator()(const libzcash::PHGRProof& proof) const
{
if (useGroth) {
throw std::ios_base::failure("Invalid Sprout proof for transaction format (expected GrothProof, found PHGRProof)");
}
::Serialize(s, proof);
}
void operator()(const libzcash::GrothProof& proof) const
{
if (!useGroth) {
throw std::ios_base::failure("Invalid Sprout proof for transaction format (expected PHGRProof, found GrothProof)");
}
::Serialize(s, proof);
}
};
template<typename Stream, typename T>
inline void SerReadWriteSproutProof(Stream& s, const T& proof, bool useGroth, CSerActionSerialize ser_action)
{
auto ps = SproutProofSerializer<Stream>(s, useGroth);
boost::apply_visitor(ps, proof);
}
template<typename Stream, typename T>
inline void SerReadWriteSproutProof(Stream& s, T& proof, bool useGroth, CSerActionUnserialize ser_action)
{
if (useGroth) {
libzcash::GrothProof grothProof;
::Unserialize(s, grothProof);
proof = grothProof;
} else {
libzcash::PHGRProof pghrProof;
::Unserialize(s, pghrProof);
proof = pghrProof;
}
}
class JSDescription
{
public:
@@ -47,14 +203,14 @@ public:
// are derived from the secrets placed in the note
// and the secret spend-authority key known by the
// spender.
boost::array<uint256, ZC_NUM_JS_INPUTS> nullifiers;
std::array<uint256, ZC_NUM_JS_INPUTS> nullifiers;
// Note commitments are introduced into the commitment
// tree, blinding the public about the values and
// destinations involved in the JoinSplit. The presence of
// a commitment in the note commitment tree is required
// to spend it.
boost::array<uint256, ZC_NUM_JS_OUTPUTS> commitments;
std::array<uint256, ZC_NUM_JS_OUTPUTS> commitments;
// Ephemeral key
uint256 ephemeralKey;
@@ -63,7 +219,7 @@ public:
// These contain trapdoors, values and other information
// that the recipient needs, including a memo field. It
// is encrypted using the scheme implemented in crypto/NoteEncryption.cpp
boost::array<ZCNoteEncryption::Ciphertext, ZC_NUM_JS_OUTPUTS> ciphertexts = {{ {{0}} }};
std::array<ZCNoteEncryption::Ciphertext, ZC_NUM_JS_OUTPUTS> ciphertexts = {{ {{0}} }};
// Random seed
uint256 randomSeed;
@@ -71,19 +227,21 @@ public:
// MACs
// The verification of the JoinSplit requires these MACs
// to be provided as an input.
boost::array<uint256, ZC_NUM_JS_INPUTS> macs;
std::array<uint256, ZC_NUM_JS_INPUTS> macs;
// JoinSplit proof
// This is a zk-SNARK which ensures that this JoinSplit is valid.
libzcash::ZCProof proof;
libzcash::SproutProof proof;
JSDescription(): vpub_old(0), vpub_new(0) { }
JSDescription(ZCJoinSplit& params,
const uint256& pubKeyHash,
JSDescription(
bool makeGrothProof,
ZCJoinSplit& params,
const uint256& joinSplitPubKey,
const uint256& rt,
const boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
const boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
const std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
const std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
CAmount vpub_old,
CAmount vpub_new,
bool computeProof = true, // Set to false in some tests
@@ -91,18 +249,14 @@ public:
);
static JSDescription Randomized(
bool makeGrothProof,
ZCJoinSplit& params,
const uint256& pubKeyHash,
const uint256& joinSplitPubKey,
const uint256& rt,
boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
#ifdef __LP64__
boost::array<uint64_t, ZC_NUM_JS_INPUTS>& inputMap,
boost::array<uint64_t, ZC_NUM_JS_OUTPUTS>& outputMap,
#else
boost::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
boost::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap,
#endif
std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
std::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
std::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap,
CAmount vpub_old,
CAmount vpub_new,
bool computeProof = true, // Set to false in some tests
@@ -114,16 +268,22 @@ public:
bool Verify(
ZCJoinSplit& params,
libzcash::ProofVerifier& verifier,
const uint256& pubKeyHash
const uint256& joinSplitPubKey
) const;
// Returns the calculated h_sig
uint256 h_sig(ZCJoinSplit& params, const uint256& pubKeyHash) const;
uint256 h_sig(ZCJoinSplit& params, const uint256& joinSplitPubKey) const;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
// nVersion is set by CTransaction and CMutableTransaction to
// (tx.fOverwintered << 31) | tx.nVersion
bool fOverwintered = s.GetVersion() >> 31;
int32_t txVersion = s.GetVersion() & 0x7FFFFFFF;
bool useGroth = fOverwintered && txVersion >= SAPLING_TX_VERSION;
READWRITE(vpub_old);
READWRITE(vpub_new);
READWRITE(anchor);
@@ -132,7 +292,7 @@ public:
READWRITE(ephemeralKey);
READWRITE(randomSeed);
READWRITE(macs);
READWRITE(proof);
::SerReadWriteSproutProof(s, proof, useGroth, ser_action);
READWRITE(ciphertexts);
}
@@ -158,20 +318,19 @@ public:
}
};
/** An outpoint - a combination of a transaction hash and an index n into its vout */
class COutPoint
class BaseOutPoint
{
public:
uint256 hash;
uint32_t n;
COutPoint() { SetNull(); }
COutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; }
BaseOutPoint() { SetNull(); }
BaseOutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(hash);
READWRITE(n);
}
@@ -179,21 +338,38 @@ public:
void SetNull() { hash.SetNull(); n = (uint32_t) -1; }
bool IsNull() const { return (hash.IsNull() && n == (uint32_t) -1); }
friend bool operator<(const COutPoint& a, const COutPoint& b)
friend bool operator<(const BaseOutPoint& a, const BaseOutPoint& b)
{
return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
}
friend bool operator==(const COutPoint& a, const COutPoint& b)
friend bool operator==(const BaseOutPoint& a, const BaseOutPoint& b)
{
return (a.hash == b.hash && a.n == b.n);
}
friend bool operator!=(const COutPoint& a, const COutPoint& b)
friend bool operator!=(const BaseOutPoint& a, const BaseOutPoint& b)
{
return !(a == b);
}
};
/** An outpoint - a combination of a transaction hash and an index n into its vout */
class COutPoint : public BaseOutPoint
{
public:
COutPoint() : BaseOutPoint() {};
COutPoint(uint256 hashIn, uint32_t nIn) : BaseOutPoint(hashIn, nIn) {};
std::string ToString() const;
};
/** An outpoint - a combination of a transaction hash and an index n into its sapling
* output description (vShieldedOutput) */
class SaplingOutPoint : public BaseOutPoint
{
public:
SaplingOutPoint() : BaseOutPoint() {};
SaplingOutPoint(uint256 hashIn, uint32_t nIn) : BaseOutPoint(hashIn, nIn) {};
std::string ToString() const;
};
@@ -219,9 +395,9 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(prevout);
READWRITE(scriptSig);
READWRITE(*(CScriptBase*)(&scriptSig));
READWRITE(nSequence);
}
@@ -264,9 +440,9 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(nValue);
READWRITE(scriptPubKey);
READWRITE(*(CScriptBase*)(&scriptPubKey));
}
void SetNull()
@@ -295,7 +471,7 @@ public:
if (scriptPubKey.IsUnspendable())
return 0;
size_t nSize = GetSerializeSize(SER_DISK,0)+148u;
size_t nSize = GetSerializeSize(*this, SER_DISK, 0) + 148u;
return 3*minRelayTxFee.GetFee(nSize);
}
@@ -321,6 +497,10 @@ public:
static constexpr uint32_t OVERWINTER_VERSION_GROUP_ID = 0x03C48270;
static_assert(OVERWINTER_VERSION_GROUP_ID != 0, "version group id must be non-zero as specified in ZIP 202");
// Sapling version group id
static constexpr uint32_t SAPLING_VERSION_GROUP_ID = 0x892F2085;
static_assert(SAPLING_VERSION_GROUP_ID != 0, "version group id must be non-zero as specified in ZIP 202");
struct CMutableTransaction;
/** The basic transaction that is broadcasted on the network and contained in
@@ -340,13 +520,16 @@ protected:
CTransaction(const CMutableTransaction &tx, bool evilDeveloperFlag);
public:
typedef boost::array<unsigned char, 64> joinsplit_sig_t;
typedef std::array<unsigned char, 64> joinsplit_sig_t;
typedef std::array<unsigned char, 64> binding_sig_t;
// Transactions that include a list of JoinSplits are >= version 2.
static const int32_t SPROUT_MIN_CURRENT_VERSION = 1;
static const int32_t SPROUT_MAX_CURRENT_VERSION = 2;
static const int32_t OVERWINTER_MIN_CURRENT_VERSION = 3;
static const int32_t OVERWINTER_MAX_CURRENT_VERSION = 3;
static const int32_t SAPLING_MIN_CURRENT_VERSION = 4;
static const int32_t SAPLING_MAX_CURRENT_VERSION = 4;
static_assert(SPROUT_MIN_CURRENT_VERSION >= SPROUT_MIN_TX_VERSION,
"standard rule for tx version should be consistent with network rule");
@@ -358,6 +541,13 @@ public:
OVERWINTER_MAX_CURRENT_VERSION >= OVERWINTER_MIN_CURRENT_VERSION),
"standard rule for tx version should be consistent with network rule");
static_assert(SAPLING_MIN_CURRENT_VERSION >= SAPLING_MIN_TX_VERSION,
"standard rule for tx version should be consistent with network rule");
static_assert( (SAPLING_MAX_CURRENT_VERSION <= SAPLING_MAX_TX_VERSION &&
SAPLING_MAX_CURRENT_VERSION >= SAPLING_MIN_CURRENT_VERSION),
"standard rule for tx version should be consistent with network rule");
// The local variables are made const to prevent unintended modification
// without updating the cached hash value. However, CTransaction is not
// actually immutable; deserialization and assignment are implemented,
@@ -370,61 +560,82 @@ public:
const std::vector<CTxOut> vout;
const uint32_t nLockTime;
const uint32_t nExpiryHeight;
const CAmount valueBalance;
const std::vector<SpendDescription> vShieldedSpend;
const std::vector<OutputDescription> vShieldedOutput;
const std::vector<JSDescription> vjoinsplit;
const uint256 joinSplitPubKey;
const joinsplit_sig_t joinSplitSig = {{0}};
const binding_sig_t bindingSig = {{0}};
/** Construct a CTransaction that qualifies as IsNull() */
CTransaction();
/** Convert a CMutableTransaction into a CTransaction. */
CTransaction(const CMutableTransaction &tx);
CTransaction(CMutableTransaction &&tx);
CTransaction& operator=(const CTransaction& tx);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
uint32_t header;
if (ser_action.ForRead()) {
// When deserializing, unpack the 4 byte header to extract fOverwintered and nVersion.
uint32_t header;
READWRITE(header);
*const_cast<bool*>(&fOverwintered) = header >> 31;
*const_cast<int32_t*>(&this->nVersion) = header & 0x7FFFFFFF;
} else {
uint32_t header = GetHeader();
header = GetHeader();
READWRITE(header);
}
nVersion = this->nVersion;
if (fOverwintered) {
READWRITE(*const_cast<uint32_t*>(&this->nVersionGroupId));
}
bool isOverwinterV3 = fOverwintered &&
nVersionGroupId == OVERWINTER_VERSION_GROUP_ID &&
nVersion == 3;
if (fOverwintered && !isOverwinterV3) {
bool isOverwinterV3 =
fOverwintered &&
nVersionGroupId == OVERWINTER_VERSION_GROUP_ID &&
nVersion == OVERWINTER_TX_VERSION;
bool isSaplingV4 =
fOverwintered &&
nVersionGroupId == SAPLING_VERSION_GROUP_ID &&
nVersion == SAPLING_TX_VERSION;
if (fOverwintered && !(isOverwinterV3 || isSaplingV4)) {
throw std::ios_base::failure("Unknown transaction format");
}
READWRITE(*const_cast<std::vector<CTxIn>*>(&vin));
READWRITE(*const_cast<std::vector<CTxOut>*>(&vout));
READWRITE(*const_cast<uint32_t*>(&nLockTime));
if (isOverwinterV3) {
if (isOverwinterV3 || isSaplingV4) {
READWRITE(*const_cast<uint32_t*>(&nExpiryHeight));
}
if (isSaplingV4) {
READWRITE(*const_cast<CAmount*>(&valueBalance));
READWRITE(*const_cast<std::vector<SpendDescription>*>(&vShieldedSpend));
READWRITE(*const_cast<std::vector<OutputDescription>*>(&vShieldedOutput));
}
if (nVersion >= 2) {
READWRITE(*const_cast<std::vector<JSDescription>*>(&vjoinsplit));
auto os = WithVersion(&s, static_cast<int>(header));
::SerReadWrite(os, *const_cast<std::vector<JSDescription>*>(&vjoinsplit), ser_action);
if (vjoinsplit.size() > 0) {
READWRITE(*const_cast<uint256*>(&joinSplitPubKey));
READWRITE(*const_cast<joinsplit_sig_t*>(&joinSplitSig));
}
}
if (isSaplingV4 && !(vShieldedSpend.empty() && vShieldedOutput.empty())) {
READWRITE(*const_cast<binding_sig_t*>(&bindingSig));
}
if (ser_action.ForRead())
UpdateHash();
}
template <typename Stream>
CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {}
bool IsNull() const {
return vin.empty() && vout.empty();
}
@@ -443,15 +654,24 @@ public:
return header;
}
// Return sum of txouts.
/*
* Context for the two methods below:
* As at most one of vpub_new and vpub_old is non-zero in every JoinSplit,
* we can think of a JoinSplit as an input or output according to which one
* it is (e.g. if vpub_new is non-zero the joinSplit is "giving value" to
* the outputs in the transaction). Similarly, we can think of the Sapling
* shielded part of the transaction as an input or output according to
* whether valueBalance - the sum of shielded input values minus the sum of
* shielded output values - is positive or negative.
*/
// Return sum of txouts, (negative valueBalance or zero) and JoinSplit vpub_old.
CAmount GetValueOut() const;
// GetValueIn() is a method on CCoinsViewCache, because
// inputs must be known to compute value in.
// Return sum of JoinSplit vpub_new
CAmount GetJoinSplitValueIn() const;
// Return sum of JoinSplit vpub_old
CAmount GetJoinSplitValueOut() const;
// Return sum of (positive valueBalance or zero) and JoinSplit vpub_new
CAmount GetShieldedValueIn() const;
// Compute priority, given priority of inputs and (optionally) tx size
double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
@@ -535,9 +755,13 @@ struct CMutableTransaction
std::vector<CTxOut> vout;
uint32_t nLockTime;
uint32_t nExpiryHeight;
CAmount valueBalance;
std::vector<SpendDescription> vShieldedSpend;
std::vector<OutputDescription> vShieldedOutput;
std::vector<JSDescription> vjoinsplit;
uint256 joinSplitPubKey;
CTransaction::joinsplit_sig_t joinSplitSig = {{0}};
CTransaction::binding_sig_t bindingSig = {{0}};
CMutableTransaction();
CMutableTransaction(const CTransaction& tx);
@@ -545,47 +769,65 @@ struct CMutableTransaction
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
uint32_t header;
if (ser_action.ForRead()) {
// When deserializing, unpack the 4 byte header to extract fOverwintered and nVersion.
uint32_t header;
READWRITE(header);
fOverwintered = header >> 31;
this->nVersion = header & 0x7FFFFFFF;
} else {
// When serializing v1 and v2, the 4 byte header is nVersion
uint32_t header = this->nVersion;
header = this->nVersion;
// When serializing Overwintered tx, the 4 byte header is the combination of fOverwintered and nVersion
if (fOverwintered) {
header |= 1 << 31;
}
READWRITE(header);
}
nVersion = this->nVersion;
if (fOverwintered) {
READWRITE(nVersionGroupId);
}
bool isOverwinterV3 = fOverwintered &&
nVersionGroupId == OVERWINTER_VERSION_GROUP_ID &&
nVersion == 3;
if (fOverwintered && !isOverwinterV3) {
bool isOverwinterV3 =
fOverwintered &&
nVersionGroupId == OVERWINTER_VERSION_GROUP_ID &&
nVersion == OVERWINTER_TX_VERSION;
bool isSaplingV4 =
fOverwintered &&
nVersionGroupId == SAPLING_VERSION_GROUP_ID &&
nVersion == SAPLING_TX_VERSION;
if (fOverwintered && !(isOverwinterV3 || isSaplingV4)) {
throw std::ios_base::failure("Unknown transaction format");
}
READWRITE(vin);
READWRITE(vout);
READWRITE(nLockTime);
if (isOverwinterV3) {
if (isOverwinterV3 || isSaplingV4) {
READWRITE(nExpiryHeight);
}
if (isSaplingV4) {
READWRITE(valueBalance);
READWRITE(vShieldedSpend);
READWRITE(vShieldedOutput);
}
if (nVersion >= 2) {
READWRITE(vjoinsplit);
auto os = WithVersion(&s, static_cast<int>(header));
::SerReadWrite(os, vjoinsplit, ser_action);
if (vjoinsplit.size() > 0) {
READWRITE(joinSplitPubKey);
READWRITE(joinSplitSig);
}
}
if (isSaplingV4 && !(vShieldedSpend.empty() && vShieldedOutput.empty())) {
READWRITE(bindingSig);
}
}
template <typename Stream>
CMutableTransaction(deserialize_type, Stream& s) {
Unserialize(s);
}
/** Compute the hash of this CMutableTransaction. This is computed on the

Some files were not shown because too many files have changed in this diff Show More