Merge remote-tracking branch 'zcash/master' into rebase2

# Conflicts:
#	.travis.yml
#	Makefile.am
#	README.md
#	configure.ac
#	depends/Makefile
#	depends/builders/darwin.mk
#	depends/funcs.mk
#	depends/hosts/darwin.mk
#	depends/packages/googlemock.mk
#	depends/packages/googletest.mk
#	depends/packages/libsnark.mk
#	depends/packages/libsodium.mk
#	depends/packages/packages.mk
#	depends/packages/rust.mk
#	src/Makefile.am
#	src/Makefile.gtest.include
#	src/chainparams.cpp
#	src/chainparams.h
#	src/checkpoints.h
#	src/clientversion.h
#	src/coins.cpp
#	src/consensus/consensus.h
#	src/gtest/test_mempool.cpp
#	src/httprpc.cpp
#	src/init.cpp
#	src/komodo-tx.cpp
#	src/main.cpp
#	src/miner.cpp
#	src/policy/fees.cpp
#	src/policy/fees.h
#	src/rpcmining.cpp
#	src/rpcrawtransaction.cpp
#	src/rpcserver.cpp
#	src/test/policyestimator_tests.cpp
#	src/test/rpc_wallet_tests.cpp
#	src/test/transaction_tests.cpp
#	src/txdb.cpp
#	src/txmempool.cpp
#	src/wallet/asyncrpcoperation_sendmany.cpp
#	src/wallet/rpcwallet.cpp
#	src/wallet/wallet.cpp
#	src/wallet/wallet.h
#	src/zcash/CreateJoinSplit.cpp
#	zcutil/build.sh
This commit is contained in:
jl777
2018-03-25 18:44:38 +03:00
603 changed files with 55577 additions and 9837 deletions

View File

@@ -1,6 +1,8 @@
DIST_SUBDIRS = secp256k1 univalue
AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS)
AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(SAN_LDFLAGS) $(HARDENED_LDFLAGS)
AM_CXXFLAGS = $(SAN_CXXFLAGS) $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS)
AM_CPPFLAGS = $(HARDENED_CPPFLAGS)
if EMBEDDED_LEVELDB
LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include
@@ -14,13 +16,15 @@ $(LIBLEVELDB): $(LIBMEMENV)
$(LIBLEVELDB) $(LIBMEMENV):
@echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \
CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \
OPT="$(CXXFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS"
OPT="$(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS"
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$(srcdir)/secp256k1/include
BITCOIN_INCLUDES += -I$(srcdir)/snark
BITCOIN_INCLUDES += -I$(srcdir)/snark/libsnark
BITCOIN_INCLUDES += -I$(srcdir)/univalue/include
if TARGET_WINDOWS
@@ -38,12 +42,25 @@ LIBBITCOIN_CLI=libbitcoin_cli.a
LIBBITCOIN_UTIL=libbitcoin_util.a
LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a
LIBSECP256K1=secp256k1/libsecp256k1.la
LIBSNARK=snark/libsnark.a
LIBUNIVALUE=univalue/libunivalue.la
LIBZCASH=libzcash.a -lcurl
$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*)
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F)
LIBSNARK_CXXFLAGS = -fPIC -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
$(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"
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"
$(LIBUNIVALUE): $(wildcard univalue/lib/*)
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue/
@@ -63,6 +80,9 @@ endif
if ENABLE_ZMQ
EXTRA_LIBRARIES += libbitcoin_zmq.a
endif
if ENABLE_PROTON
EXTRA_LIBRARIES += libbitcoin_proton.a
endif
if BUILD_BITCOIN_LIBS
lib_LTLIBRARIES = libzcashconsensus.la
@@ -94,12 +114,17 @@ LIBZCASH_H = \
zcash/util.h \
zcash/Zcash.h
.PHONY: FORCE check-symbols check-security
.PHONY: FORCE collate-libsnark check-symbols check-security
# bitcoin core #
BITCOIN_CORE_H = \
addrman.h \
alert.h \
amount.h \
amqp/amqpabstractnotifier.h \
amqp/amqpconfig.h \
amqp/amqpnotificationinterface.h \
amqp/amqppublishnotifier.h \
amqp/amqpsender.h \
arith_uint256.h \
asyncrpcoperation.h \
asyncrpcqueue.h \
@@ -121,11 +146,11 @@ BITCOIN_CORE_H = \
compressor.h \
consensus/consensus.h \
consensus/params.h \
consensus/upgrades.h \
consensus/validation.h \
core_io.h \
core_memusage.h \
eccryptoverify.h \
ecwrapper.h \
deprecation.h \
hash.h \
httprpc.h \
httpserver.h \
@@ -143,6 +168,8 @@ BITCOIN_CORE_H = \
net.h \
netbase.h \
noui.h \
paymentdisclosure.h \
paymentdisclosuredb.h \
policy/fees.h \
pow.h \
primitives/block.h \
@@ -185,7 +212,9 @@ BITCOIN_CORE_H = \
utiltime.h \
validationinterface.h \
version.h \
wallet/asyncrpcoperation_mergetoaddress.h \
wallet/asyncrpcoperation_sendmany.h \
wallet/asyncrpcoperation_shieldcoinbase.h \
wallet/crypter.h \
wallet/db.h \
wallet/wallet.h \
@@ -204,7 +233,8 @@ obj/build.h: FORCE
libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
# server: zcashd
libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
sendalert.cpp \
addrman.cpp \
@@ -215,6 +245,7 @@ libbitcoin_server_a_SOURCES = \
bloom.cpp \
chain.cpp \
checkpoints.cpp \
deprecation.cpp \
httprpc.cpp \
httpserver.cpp \
init.cpp \
@@ -225,6 +256,8 @@ libbitcoin_server_a_SOURCES = \
miner.cpp \
net.cpp \
noui.cpp \
paymentdisclosure.cpp \
paymentdisclosuredb.cpp \
policy/fees.cpp \
pow.cpp \
rest.cpp \
@@ -247,23 +280,40 @@ 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 = \
zmq/zmqabstractnotifier.cpp \
zmq/zmqnotificationinterface.cpp \
zmq/zmqpublishnotifier.cpp
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 = \
amqp/amqpabstractnotifier.cpp \
amqp/amqpnotificationinterface.cpp \
amqp/amqppublishnotifier.cpp
endif
# wallet: zcashd, but only linked when wallet enabled
libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES)
libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_wallet_a_SOURCES = \
utiltest.cpp \
utiltest.h \
zcbenchmarks.cpp \
zcbenchmarks.h \
wallet/asyncrpcoperation_mergetoaddress.cpp \
wallet/asyncrpcoperation_sendmany.cpp \
wallet/asyncrpcoperation_shieldcoinbase.cpp \
wallet/crypter.cpp \
wallet/db.cpp \
paymentdisclosure.cpp \
paymentdisclosuredb.cpp \
wallet/rpcdisclosure.cpp \
wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
wallet/wallet.cpp \
@@ -273,7 +323,8 @@ libbitcoin_wallet_a_SOURCES = \
$(LIBZCASH_H)
# crypto primitives library
crypto_libbitcoin_crypto_a_CPPFLAGS = $(BITCOIN_CONFIG_INCLUDES)
crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES)
crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
crypto_libbitcoin_crypto_a_SOURCES = \
crypto/common.h \
crypto/equihash.cpp \
@@ -305,7 +356,8 @@ crypto_libbitcoin_crypto_a_SOURCES += \
endif
# common: shared between zcashd and non-server tools
libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES)
libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_common_a_SOURCES = \
amount.cpp \
arith_uint256.cpp \
@@ -313,10 +365,9 @@ libbitcoin_common_a_SOURCES = \
chainparams.cpp \
coins.cpp \
compressor.cpp \
consensus/upgrades.cpp \
core_read.cpp \
core_write.cpp \
eccryptoverify.cpp \
ecwrapper.cpp \
hash.cpp \
key.cpp \
keystore.cpp \
@@ -337,7 +388,8 @@ libbitcoin_common_a_SOURCES = \
# util: shared between all executables.
# This library *must* be included to make sure that the glibc
# backward-compatibility objects and their sanity checks are linked.
libbitcoin_util_a_CPPFLAGS = $(BITCOIN_INCLUDES)
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 \
@@ -362,7 +414,8 @@ libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp
endif
# cli: zcash-cli
libbitcoin_cli_a_CPPFLAGS = $(BITCOIN_INCLUDES)
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) \
@@ -373,7 +426,8 @@ nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h
# bitcoind binary #
komodod_SOURCES = bitcoind.cpp
komodod_CPPFLAGS = $(BITCOIN_INCLUDES)
komodod_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
komodod_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
komodod_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
if TARGET_WINDOWS
@@ -387,6 +441,7 @@ komodod_LDADD = \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZCASH) \
$(LIBSNARK) \
$(LIBLEVELDB) \
$(LIBMEMENV) \
$(LIBSECP256K1)
@@ -404,16 +459,19 @@ komodod_LDADD += \
$(BDB_LIBS) \
$(SSL_LIBS) \
$(CRYPTO_LIBS) \
$(MINIUPNPC_LIBS) \
$(EVENT_PTHREADS_LIBS) \
$(EVENT_LIBS) \
$(LIBZCASH) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZCASH_LIBS)
if ENABLE_PROTON
zcashd_LDADD += $(LIBBITCOIN_PROTON) $(PROTON_LIBS)
endif
# bitcoin-cli binary #
komodo_cli_SOURCES = bitcoin-cli.cpp
komodo_cli_CPPFLAGS = $(BITCOIN_INCLUDES) $(EVENT_CFLAGS)
komodo_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS)
komodo_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
komodo_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
if TARGET_WINDOWS
@@ -429,13 +487,15 @@ komodo_cli_LDADD = \
$(CRYPTO_LIBS) \
$(EVENT_LIBS) \
$(LIBZCASH) \
$(LIBSNARK) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZCASH_LIBS)
#
# zcash-tx binary #
komodo_tx_SOURCES = komodo-tx.cpp
komodo_tx_CPPFLAGS = $(BITCOIN_INCLUDES)
komodo_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
komodo_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
komodo_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
if TARGET_WINDOWS
@@ -449,6 +509,7 @@ komodo_tx_LDADD = \
$(LIBBITCOIN_UTIL) \
$(LIBSECP256K1) \
$(LIBZCASH) \
$(LIBSNARK) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZCASH_LIBS)
@@ -472,12 +533,10 @@ libzcash_a_SOURCES = \
zcash/circuit/prfs.tcc \
zcash/circuit/utils.tcc
libzcash_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS $(HARDENED_CPPFLAGS) -pipe -O1 -g -Wstack-protector -fstack-protector-all -fPIE -fvisibility=hidden -DSTATIC $(BITCOIN_INCLUDES)
libzcash_a_CXXFLAGS = $(HARDENED_CXXFLAGS) -fwrapv -fno-strict-aliasing
#libzcash_a_LDFLAGS = $(HARDENED_LDFLAGS)
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 = $(SAN_CXXFLAGS) $(HARDENED_CXXFLAGS) -fwrapv -fno-strict-aliasing
libzcash_a_LDFLAGS = $(SAN_LDFLAGS) $(HARDENED_LDFLAGS)
libzcash_a_CPPFLAGS += -DMONTGOMERY_OUTPUT
# zcashconsensus library #
@@ -490,8 +549,6 @@ libzcashconsensus_la_SOURCES = \
crypto/sha1.cpp \
crypto/sha256.cpp \
crypto/sha512.cpp \
eccryptoverify.cpp \
ecwrapper.cpp \
hash.cpp \
primitives/transaction.cpp \
pubkey.cpp \
@@ -505,9 +562,10 @@ if GLIBC_BACK_COMPAT
libzcashconsensus_la_SOURCES += compat/glibc_compat.cpp
endif
libzcashconsensus_la_LDFLAGS = -no-undefined $(RELDFLAGS)
libzcashconsensus_la_LIBADD = $(CRYPTO_LIBS)
libzcashconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCOIN_INTERNAL
libzcashconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS)
libzcashconsensus_la_LIBADD = $(LIBSECP256K1)
libzcashconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL
libzcashconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
endif
#
@@ -516,11 +574,12 @@ CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno */*.gcno wal
DISTCLEANFILES = obj/build.h
EXTRA_DIST = leveldb
EXTRA_DIST = leveldb snark
clean-local:
-$(MAKE) -C leveldb clean
-$(MAKE) -C secp256k1 clean
-$(MAKE) -C snark clean
rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno
-rm -f config.h
@@ -530,18 +589,18 @@ clean-local:
.mm.o:
$(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o $@ $<
$(CPPFLAGS) $(AM_CXXFLAGS) $(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) -c -o $@ $<
check-symbols: $(bin_PROGRAMS)
if GLIBC_BACK_COMPAT
@echo "Checking glibc back compat of [$(bin_PROGRAMS)]..."
$(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py < $(bin_PROGRAMS)
$(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)
endif
check-security: $(bin_PROGRAMS)
if HARDEN
@echo "Checking binary security of [$(bin_PROGRAMS)]..."
$(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS)
$(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py $(bin_PROGRAMS)
endif
%.pb.cc %.pb.h: %.proto

View File

@@ -19,7 +19,9 @@ zcash_gtest_SOURCES += \
endif
zcash_gtest_SOURCES += \
gtest/test_tautology.cpp \
gtest/test_deprecation.cpp \
gtest/test_equihash.cpp \
gtest/test_httprpc.cpp \
gtest/test_joinsplit.cpp \
gtest/test_keystore.cpp \
gtest/test_noteencryption.cpp \
@@ -31,17 +33,21 @@ zcash_gtest_SOURCES += \
gtest/test_random.cpp \
gtest/test_rpc.cpp \
gtest/test_transaction.cpp \
gtest/test_upgrades.cpp \
gtest/test_validation.cpp \
gtest/test_circuit.cpp \
gtest/test_txid.cpp \
gtest/test_libzcash_utils.cpp \
gtest/test_proofs.cpp \
gtest/test_paymentdisclosure.cpp \
gtest/test_checkblock.cpp
if ENABLE_WALLET
zcash_gtest_SOURCES += \
wallet/gtest/test_wallet.cpp
endif
komodo_gtest_CPPFLAGS = -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC
komodo_gtest_CPPFLAGS = $(AM_CPPFLAGS) -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES)
komodo_gtest_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
komodo_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1)
@@ -52,7 +58,14 @@ if ENABLE_WALLET
komodo_gtest_LDADD += $(LIBBITCOIN_WALLET)
endif
komodo_gtest_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(LIBZCASH) $(LIBZCASH_LIBS)
komodo_gtest_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(LIBZCASH) $(LIBSNARK) $(LIBZCASH_LIBS)
if ENABLE_PROTON
komodo_gtest_LDADD += $(LIBBITCOIN_PROTON) $(PROTON_LIBS)
endif
komodo_gtest_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
komodo_gtest_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static

View File

@@ -99,20 +99,25 @@ BITCOIN_TESTS += \
endif
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
test_test_bitcoin_CPPFLAGS = -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
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_PTHREADS_LIBS) $(EVENT_LIBS)
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
endif
test_test_bitcoin_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBZCASH) $(LIBZCASH_LIBS)
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
if ENABLE_ZMQ
test_test_bitcoin_LDADD += $(ZMQ_LIBS)
endif
if ENABLE_PROTON
test_test_bitcoin_LDADD += $(PROTON_LIBS)
endif
nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
$(BITCOIN_TESTS): $(GENERATED_TEST_FILES)

View File

@@ -4,18 +4,24 @@ noinst_PROGRAMS += \
# tool for generating our public parameters
zcash_GenerateParams_SOURCES = zcash/GenerateParams.cpp
zcash_GenerateParams_CPPFLAGS = $(AM_CPPFLAGS)
zcash_GenerateParams_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
zcash_GenerateParams_LDADD = \
$(BOOST_LIBS) \
$(LIBZCASH) \
$(LIBSNARK) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZCASH_LIBS)
# tool for profiling the creation of joinsplits
zcash_CreateJoinSplit_SOURCES = zcash/CreateJoinSplit.cpp
zcash_CreateJoinSplit_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
zcash_CreateJoinSplit_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
zcash_CreateJoinSplit_LDADD = \
$(LIBBITCOIN_COMMON) \
$(LIBZCASH) \
$(LIBSNARK) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(BOOST_LIBS) \

View File

@@ -234,7 +234,7 @@ protected:
//! Select an address to connect to, if newOnly is set to true, only the new table is selected from.
CAddrInfo Select_(bool newOnly);
//! Wraps GetRandInt to allow tests to override RandomInt and make it determinismistic.
//! Wraps GetRandInt to allow tests to override RandomInt and make it deterministic.
virtual int RandomInt(int nMax);
#ifdef DEBUG_ADDRMAN

View File

@@ -7,6 +7,8 @@
#include "tinyformat.h"
const std::string CURRENCY_UNIT = "ZEC";
CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nSize)
{
if (nSize > 0)
@@ -27,5 +29,5 @@ CAmount CFeeRate::GetFee(size_t nSize) const
std::string CFeeRate::ToString() const
{
return strprintf("%d.%08d BTC/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN);
return strprintf("%d.%08d %s/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN, CURRENCY_UNIT);
}

View File

@@ -16,6 +16,8 @@ typedef int64_t CAmount;
static const CAmount COIN = 100000000;
static const CAmount CENT = 1000000;
extern const std::string CURRENCY_UNIT;
/** No amount larger than this (in satoshi) is valid.
*
* Note that this constant is *not* the total money supply, which in Bitcoin

View File

@@ -0,0 +1,21 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "amqpabstractnotifier.h"
#include "util.h"
AMQPAbstractNotifier::~AMQPAbstractNotifier()
{
}
bool AMQPAbstractNotifier::NotifyBlock(const CBlockIndex * /*CBlockIndex*/)
{
return true;
}
bool AMQPAbstractNotifier::NotifyTransaction(const CTransaction &/*transaction*/)
{
return true;
}

View File

@@ -0,0 +1,43 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef ZCASH_AMQP_AMQPABSTRACTNOTIFIER_H
#define ZCASH_AMQP_AMQPABSTRACTNOTIFIER_H
#include "amqpconfig.h"
class CBlockIndex;
class AMQPAbstractNotifier;
typedef AMQPAbstractNotifier* (*AMQPNotifierFactory)();
class AMQPAbstractNotifier
{
public:
AMQPAbstractNotifier() { }
virtual ~AMQPAbstractNotifier();
template <typename T>
static AMQPAbstractNotifier* Create()
{
return new T();
}
std::string GetType() const { return type; }
void SetType(const std::string &t) { type = t; }
std::string GetAddress() const { return address; }
void SetAddress(const std::string &a) { address = a; }
virtual bool Initialize() = 0;
virtual void Shutdown() = 0;
virtual bool NotifyBlock(const CBlockIndex *pindex);
virtual bool NotifyTransaction(const CTransaction &transaction);
protected:
std::string type;
std::string address;
};
#endif // ZCASH_AMQP_AMQPABSTRACTNOTIFIER_H

33
src/amqp/amqpconfig.h Normal file
View File

@@ -0,0 +1,33 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef ZCASH_AMQP_AMQPCONFIG_H
#define ZCASH_AMQP_AMQPCONFIG_H
#if defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
#endif
#include <stdarg.h>
#include <string>
#if ENABLE_PROTON
#include <proton/connection.hpp>
#include <proton/connection_options.hpp>
#include <proton/container.hpp>
#include <proton/default_container.hpp>
#include <proton/message.hpp>
#include <proton/message_id.hpp>
#include <proton/messaging_handler.hpp>
#include <proton/thread_safe.hpp>
#include <proton/tracker.hpp>
#include <proton/transport.hpp>
#include <proton/types.hpp>
#include <proton/url.hpp>
#endif
#include "primitives/block.h"
#include "primitives/transaction.h"
#endif // ZCASH_AMQP_AMQPCONFIG_H

View File

@@ -0,0 +1,136 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "amqpnotificationinterface.h"
#include "amqppublishnotifier.h"
#include "version.h"
#include "main.h"
#include "streams.h"
#include "util.h"
// AMQP 1.0 Support
//
// The boost::signals2 signals and slot system is thread safe, so CValidationInterface listeners
// can be invoked from any thread.
//
// Currently signals are fired from main.cpp so the callbacks should be invoked on the same thread.
// It should be safe to share objects responsible for sending, as they should not be run concurrently
// across different threads.
//
// Developers should be mindful of where notifications are fired to avoid potential race conditions.
// For example, different signals targeting the same address could be fired from different threads
// in different parts of the system around the same time.
//
// Like the ZMQ notification interface, if a notifier fails to send a message, the notifier is shut down.
//
AMQPNotificationInterface::AMQPNotificationInterface()
{
}
AMQPNotificationInterface::~AMQPNotificationInterface()
{
Shutdown();
for (std::list<AMQPAbstractNotifier*>::iterator i = notifiers.begin(); i != notifiers.end(); ++i) {
delete *i;
}
}
AMQPNotificationInterface* AMQPNotificationInterface::CreateWithArguments(const std::map<std::string, std::string> &args)
{
AMQPNotificationInterface* notificationInterface = nullptr;
std::map<std::string, AMQPNotifierFactory> factories;
std::list<AMQPAbstractNotifier*> notifiers;
factories["pubhashblock"] = AMQPAbstractNotifier::Create<AMQPPublishHashBlockNotifier>;
factories["pubhashtx"] = AMQPAbstractNotifier::Create<AMQPPublishHashTransactionNotifier>;
factories["pubrawblock"] = AMQPAbstractNotifier::Create<AMQPPublishRawBlockNotifier>;
factories["pubrawtx"] = AMQPAbstractNotifier::Create<AMQPPublishRawTransactionNotifier>;
for (std::map<std::string, AMQPNotifierFactory>::const_iterator i=factories.begin(); i!=factories.end(); ++i) {
std::map<std::string, std::string>::const_iterator j = args.find("-amqp" + i->first);
if (j!=args.end()) {
AMQPNotifierFactory factory = i->second;
std::string address = j->second;
AMQPAbstractNotifier *notifier = factory();
notifier->SetType(i->first);
notifier->SetAddress(address);
notifiers.push_back(notifier);
}
}
if (!notifiers.empty()) {
notificationInterface = new AMQPNotificationInterface();
notificationInterface->notifiers = notifiers;
if (!notificationInterface->Initialize()) {
delete notificationInterface;
notificationInterface = nullptr;
}
}
return notificationInterface;
}
// Called at startup to conditionally set up
bool AMQPNotificationInterface::Initialize()
{
LogPrint("amqp", "amqp: Initialize notification interface\n");
std::list<AMQPAbstractNotifier*>::iterator i = notifiers.begin();
for (; i != notifiers.end(); ++i) {
AMQPAbstractNotifier *notifier = *i;
if (notifier->Initialize()) {
LogPrint("amqp", "amqp: Notifier %s ready (address = %s)\n", notifier->GetType(), notifier->GetAddress());
} else {
LogPrint("amqp", "amqp: Notifier %s failed (address = %s)\n", notifier->GetType(), notifier->GetAddress());
break;
}
}
if (i != notifiers.end()) {
return false;
}
return true;
}
// Called during shutdown sequence
void AMQPNotificationInterface::Shutdown()
{
LogPrint("amqp", "amqp: Shutdown notification interface\n");
for (std::list<AMQPAbstractNotifier*>::iterator i = notifiers.begin(); i != notifiers.end(); ++i) {
AMQPAbstractNotifier *notifier = *i;
notifier->Shutdown();
}
}
void AMQPNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindex)
{
for (std::list<AMQPAbstractNotifier*>::iterator i = notifiers.begin(); i != notifiers.end(); ) {
AMQPAbstractNotifier *notifier = *i;
if (notifier->NotifyBlock(pindex)) {
i++;
} else {
notifier->Shutdown();
i = notifiers.erase(i);
}
}
}
void AMQPNotificationInterface::SyncTransaction(const CTransaction &tx, const CBlock *pblock)
{
for (std::list<AMQPAbstractNotifier*>::iterator i = notifiers.begin(); i != notifiers.end(); ) {
AMQPAbstractNotifier *notifier = *i;
if (notifier->NotifyTransaction(tx)) {
i++;
} else {
notifier->Shutdown();
i = notifiers.erase(i);
}
}
}

View File

@@ -0,0 +1,36 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef ZCASH_AMQP_AMQPNOTIFICATIONINTERFACE_H
#define ZCASH_AMQP_AMQPNOTIFICATIONINTERFACE_H
#include "validationinterface.h"
#include <string>
#include <map>
class CBlockIndex;
class AMQPAbstractNotifier;
class AMQPNotificationInterface : public CValidationInterface
{
public:
virtual ~AMQPNotificationInterface();
static AMQPNotificationInterface* CreateWithArguments(const std::map<std::string, std::string> &args);
protected:
bool Initialize();
void Shutdown();
// CValidationInterface
void SyncTransaction(const CTransaction &tx, const CBlock *pblock);
void UpdatedBlockTip(const CBlockIndex *pindex);
private:
AMQPNotificationInterface();
std::list<AMQPAbstractNotifier*> notifiers;
};
#endif // ZCASH_AMQP_AMQPNOTIFICATIONINTERFACE_H

View File

@@ -0,0 +1,177 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "amqppublishnotifier.h"
#include "main.h"
#include "util.h"
#include "amqpsender.h"
#include <memory>
#include <thread>
static std::multimap<std::string, AMQPAbstractPublishNotifier*> mapPublishNotifiers;
static const char *MSG_HASHBLOCK = "hashblock";
static const char *MSG_HASHTX = "hashtx";
static const char *MSG_RAWBLOCK = "rawblock";
static const char *MSG_RAWTX = "rawtx";
// Invoke this method from a new thread to run the proton container event loop.
void AMQPAbstractPublishNotifier::SpawnProtonContainer()
{
try {
proton::default_container(*handler_).run();
}
catch (const proton::error_condition &e) {
LogPrint("amqp", "amqp: container error: %s\n", e.what());
}
catch (const std::runtime_error &e) {
LogPrint("amqp", "amqp: runtime error: %s\n", e.what());
}
catch (const std::exception &e) {
LogPrint("amqp", "amqp: exception: %s\n", e.what());
}
catch (...) {
LogPrint("amqp", "amqp: unknown error\n");
}
handler_->terminate();
}
bool AMQPAbstractPublishNotifier::Initialize()
{
std::multimap<std::string, AMQPAbstractPublishNotifier*>::iterator i = mapPublishNotifiers.find(address);
if (i == mapPublishNotifiers.end()) {
try {
handler_ = std::make_shared<AMQPSender>(address);
thread_ = std::make_shared<std::thread>(&AMQPAbstractPublishNotifier::SpawnProtonContainer, this);
}
catch (std::exception &e) {
LogPrint("amqp", "amqp: initialization error: %s\n", e.what());
return false;
}
mapPublishNotifiers.insert(std::make_pair(address, this));
} else {
// copy the shared ptrs to the message handler and the thread where the proton container is running
handler_ = i->second->handler_;
thread_ = i->second->thread_;
mapPublishNotifiers.insert(std::make_pair(address, this));
}
return true;
}
void AMQPAbstractPublishNotifier::Shutdown()
{
LogPrint("amqp", "amqp: Shutdown notifier %s at %s\n", GetType(), GetAddress());
int count = mapPublishNotifiers.count(address);
// remove this notifier from the list of publishers using this address
typedef std::multimap<std::string, AMQPAbstractPublishNotifier*>::iterator iterator;
std::pair<iterator, iterator> iterpair = mapPublishNotifiers.equal_range(address);
for (iterator it = iterpair.first; it != iterpair.second; ++it) {
if (it->second == this) {
mapPublishNotifiers.erase(it);
break;
}
}
// terminate the connection if this is the last publisher using this address
if (count == 1) {
handler_->terminate();
if (thread_.get() != nullptr) {
if (thread_->joinable()) {
thread_->join();
}
}
}
}
bool AMQPAbstractPublishNotifier::SendMessage(const char *command, const void* data, size_t size)
{
try {
proton::binary content;
const char *p = (const char *)data;
content.assign(p, p + size);
proton::message message(content);
message.subject(std::string(command));
proton::message::property_map & props = message.properties();
props.put("x-opt-sequence-number", sequence_);
handler_->publish(message);
} catch (proton::error_condition &e) {
LogPrint("amqp", "amqp: error : %s\n", e.what());
return false;
}
catch (const std::runtime_error &e) {
LogPrint("amqp", "amqp: runtime error: %s\n", e.what());
return false;
}
catch (const std::exception &e) {
LogPrint("amqp", "amqp: exception: %s\n", e.what());
return false;
}
catch (...) {
LogPrint("amqp", "amqp: unknown error\n");
return false;
}
sequence_++;
return true;
}
bool AMQPPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
{
uint256 hash = pindex->GetBlockHash();
LogPrint("amqp", "amqp: Publish hashblock %s\n", hash.GetHex());
char data[32];
for (unsigned int i = 0; i < 32; i++)
data[31 - i] = hash.begin()[i];
return SendMessage(MSG_HASHBLOCK, data, 32);
}
bool AMQPPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
{
uint256 hash = transaction.GetHash();
LogPrint("amqp", "amqp: Publish hashtx %s\n", hash.GetHex());
char data[32];
for (unsigned int i = 0; i < 32; i++)
data[31 - i] = hash.begin()[i];
return SendMessage(MSG_HASHTX, data, 32);
}
bool AMQPPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
{
LogPrint("amqp", "amqp: Publish rawblock %s\n", pindex->GetBlockHash().GetHex());
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
{
LOCK(cs_main);
CBlock block;
if(!ReadBlockFromDisk(block, pindex)) {
LogPrint("amqp", "amqp: Can't read block from disk");
return false;
}
ss << block;
}
return SendMessage(MSG_RAWBLOCK, &(*ss.begin()), ss.size());
}
bool AMQPPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
{
uint256 hash = transaction.GetHash();
LogPrint("amqp", "amqp: Publish rawtx %s\n", hash.GetHex());
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << transaction;
return SendMessage(MSG_RAWTX, &(*ss.begin()), ss.size());
}

View File

@@ -0,0 +1,56 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef ZCASH_AMQP_AMQPPUBLISHNOTIFIER_H
#define ZCASH_AMQP_AMQPPUBLISHNOTIFIER_H
#include "amqpabstractnotifier.h"
#include "amqpconfig.h"
#include "amqpsender.h"
#include <memory>
#include <thread>
class CBlockIndex;
class AMQPAbstractPublishNotifier : public AMQPAbstractNotifier
{
private:
uint64_t sequence_; // memory only, per notifier instance: upcounting message sequence number
std::shared_ptr<std::thread> thread_; // proton container thread, may be shared between notifiers
std::shared_ptr<AMQPSender> handler_; // proton container message handler, may be shared between notifiers
public:
bool SendMessage(const char *command, const void* data, size_t size);
bool Initialize();
void Shutdown();
void SpawnProtonContainer();
};
class AMQPPublishHashBlockNotifier : public AMQPAbstractPublishNotifier
{
public:
bool NotifyBlock(const CBlockIndex *pindex);
};
class AMQPPublishHashTransactionNotifier : public AMQPAbstractPublishNotifier
{
public:
bool NotifyTransaction(const CTransaction &transaction);
};
class AMQPPublishRawBlockNotifier : public AMQPAbstractPublishNotifier
{
public:
bool NotifyBlock(const CBlockIndex *pindex);
};
class AMQPPublishRawTransactionNotifier : public AMQPAbstractPublishNotifier
{
public:
bool NotifyTransaction(const CTransaction &transaction);
};
#endif // ZCASH_AMQP_AMQPPUBLISHNOTIFIER_H

115
src/amqp/amqpsender.h Normal file
View File

@@ -0,0 +1,115 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef ZCASH_AMQP_AMQPSENDER_H
#define ZCASH_AMQP_AMQPSENDER_H
#include "amqpconfig.h"
#include <deque>
#include <memory>
#include <future>
#include <iostream>
class AMQPSender : public proton::messaging_handler {
private:
std::deque<proton::message> messages_;
proton::url url_;
proton::connection conn_;
proton::sender sender_;
std::mutex lock_;
std::atomic<bool> terminated_ = {false};
public:
AMQPSender(const std::string& url) : url_(url) {}
// Callback to initialize the container when run() is invoked
void on_container_start(proton::container& c) override {
proton::duration t(10000); // milliseconds
proton::connection_options opts = proton::connection_options().idle_timeout(t);
conn_ = c.connect(url_, opts);
sender_ = conn_.open_sender(url_.path());
}
// Remote end signals when the local end can send (i.e. has credit)
void on_sendable(proton::sender &s) override {
dispatch();
}
// Publish message by adding to queue and trying to dispatch it
void publish(const proton::message &m) {
add_message(m);
dispatch();
}
// Add message to queue
void add_message(const proton::message &m) {
std::lock_guard<std::mutex> guard(lock_);
messages_.push_back(m);
}
// Send messages in queue
void dispatch() {
std::lock_guard<std::mutex> guard(lock_);
if (isTerminated()) {
throw std::runtime_error("amqp connection was terminated");
}
if (!conn_.active()) {
throw std::runtime_error("amqp connection is not active");
}
while (messages_.size() > 0) {
if (sender_.credit()) {
const proton::message& m = messages_.front();
sender_.send(m);
messages_.pop_front();
} else {
break;
}
}
}
// Close connection to remote end. Container event-loop, by default, will auto-stop.
void terminate() {
std::lock_guard<std::mutex> guard(lock_);
conn_.close();
terminated_.store(true);
}
bool isTerminated() const {
return terminated_.load();
}
void on_transport_error(proton::transport &t) override {
t.connection().close();
throw t.error();
}
void on_connection_error(proton::connection &c) override {
c.close();
throw c.error();
}
void on_session_error(proton::session &s) override {
s.connection().close();
throw s.error();
}
void on_receiver_error(proton::receiver &r) override {
r.connection().close();
throw r.error();
}
void on_sender_error(proton::sender &s) override {
s.connection().close();
throw s.error();
}
};
#endif //ZCASH_AMQP_AMQPSENDER_H

View File

@@ -24,7 +24,7 @@ using namespace std;
*
* To subclass AsyncRPCOperation, implement the main() method.
* Update the operation status as work is underway and completes.
* If main() can be interrupted, inmplement the cancel() method.
* If main() can be interrupted, implement the cancel() method.
*/
typedef std::string AsyncRPCOperationId;

View File

@@ -323,67 +323,60 @@ bool CBitcoinSecret::SetString(const std::string& strSecret)
return SetString(strSecret.c_str());
}
bool CZCPaymentAddress::Set(const libzcash::PaymentAddress& addr)
template<class DATA_TYPE, CChainParams::Base58Type PREFIX, size_t SER_SIZE>
bool CZCEncoding<DATA_TYPE, PREFIX, SER_SIZE>::Set(const DATA_TYPE& addr)
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << addr;
std::vector<unsigned char> addrSerialized(ss.begin(), ss.end());
assert(addrSerialized.size() == libzcash::SerializedPaymentAddressSize);
SetData(Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS), &addrSerialized[0], libzcash::SerializedPaymentAddressSize);
assert(addrSerialized.size() == SER_SIZE);
SetData(Params().Base58Prefix(PREFIX), &addrSerialized[0], SER_SIZE);
return true;
}
libzcash::PaymentAddress CZCPaymentAddress::Get() const
template<class DATA_TYPE, CChainParams::Base58Type PREFIX, size_t SER_SIZE>
DATA_TYPE CZCEncoding<DATA_TYPE, PREFIX, SER_SIZE>::Get() const
{
if (vchData.size() != libzcash::SerializedPaymentAddressSize) {
if (vchData.size() != SER_SIZE) {
throw std::runtime_error(
"payment address is invalid"
PrependName(" is invalid")
);
}
if (vchVersion != Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS)) {
if (vchVersion != Params().Base58Prefix(PREFIX)) {
throw std::runtime_error(
"payment address is for wrong network type"
PrependName(" is for wrong network type")
);
}
std::vector<unsigned char> serialized(vchData.begin(), vchData.end());
CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
libzcash::PaymentAddress ret;
DATA_TYPE ret;
ss >> ret;
return ret;
}
bool CZCSpendingKey::Set(const libzcash::SpendingKey& addr)
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << addr;
std::vector<unsigned char> addrSerialized(ss.begin(), ss.end());
assert(addrSerialized.size() == libzcash::SerializedSpendingKeySize);
SetData(Params().Base58Prefix(CChainParams::ZCSPENDING_KEY), &addrSerialized[0], libzcash::SerializedSpendingKeySize);
return true;
}
// 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;
libzcash::SpendingKey CZCSpendingKey::Get() const
{
if (vchData.size() != libzcash::SerializedSpendingKeySize) {
throw std::runtime_error(
"spending key is invalid"
);
}
if (vchVersion != Params().Base58Prefix(CChainParams::ZCSPENDING_KEY)) {
throw std::runtime_error(
"spending key is for wrong network type"
);
}
std::vector<unsigned char> serialized(vchData.begin(), vchData.end());
CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
libzcash::SpendingKey ret;
ss >> ret;
return ret;
}
// 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

@@ -96,26 +96,48 @@ public:
bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; }
};
class CZCPaymentAddress : public CBase58Data {
template<class DATA_TYPE, CChainParams::Base58Type PREFIX, size_t SER_SIZE>
class CZCEncoding : public CBase58Data {
protected:
virtual std::string PrependName(const std::string& s) const = 0;
public:
bool Set(const DATA_TYPE& addr);
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:
bool Set(const libzcash::PaymentAddress& addr);
CZCPaymentAddress() {}
CZCPaymentAddress(const std::string& strAddress) { SetString(strAddress.c_str(), 2); }
CZCPaymentAddress(const libzcash::PaymentAddress& addr) { Set(addr); }
libzcash::PaymentAddress Get() const;
};
class CZCSpendingKey : public CBase58Data {
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:
bool Set(const libzcash::SpendingKey& addr);
CZCSpendingKey() {}
CZCSpendingKey(const std::string& strAddress) { SetString(strAddress.c_str(), 2); }
CZCSpendingKey(const libzcash::SpendingKey& addr) { Set(addr); }
libzcash::SpendingKey Get() const;
};
/** base58-encoded Bitcoin addresses.
@@ -172,7 +194,7 @@ public:
K GetKey() {
K ret;
if (vchData.size() == Size) {
//if base58 encouded data not holds a ext key, return a !IsValid() key
//if base58 encoded data not holds a ext key, return a !IsValid() key
ret.Decode(&vchData[0]);
}
return ret;

View File

@@ -16,6 +16,8 @@
#include <boost/foreach.hpp>
static const int SPROUT_VALUE_VERSION = 1001400;
struct CDiskBlockPos
{
int nFile;
@@ -92,8 +94,14 @@ enum BlockStatus: uint32_t {
BLOCK_FAILED_VALID = 32, //! stage after last reached validness failed
BLOCK_FAILED_CHILD = 64, //! descends from failed block
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,
BLOCK_ACTIVATES_UPGRADE = 128, //! block activates a network upgrade
};
//! Short-hand for the highest consensus validity we implement.
//! Blocks with this validity are assumed to satisfy all consensus rules.
static const BlockStatus BLOCK_VALID_CONSENSUS = BLOCK_VALID_SCRIPTS;
/** The block chain is a tree shaped structure starting with the
* genesis block at the root, with each block potentially having multiple
* candidates to be the next block. A blockindex may have multiple pprev pointing
@@ -138,12 +146,26 @@ public:
//! Verification status of this block. See enum BlockStatus
unsigned int nStatus;
//! Branch ID corresponding to the consensus rules used to validate this block.
//! Only cached if block validity is BLOCK_VALID_CONSENSUS.
//! Persisted at each activation height, memory-only for intervening blocks.
boost::optional<uint32_t> nCachedBranchId;
//! The anchor for the tree state up to the start of this block
uint256 hashAnchor;
//! (memory only) The anchor for the tree state up to the end of this block
uint256 hashAnchorEnd;
//! 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.
boost::optional<CAmount> nSproutValue;
//! (memory only) Total value held by the Sprout circuit up to and including this block.
//! Will be boost::none for on old nodes until a reindex has taken place.
//! Will be boost::none if nChainTx is zero.
boost::optional<CAmount> nChainSproutValue;
//! block header
int nVersion;
uint256 hashMerkleRoot;
@@ -169,9 +191,12 @@ public:
nTx = 0;
nChainTx = 0;
nStatus = 0;
nCachedBranchId = boost::none;
hashAnchor = uint256();
hashAnchorEnd = uint256();
nSequenceId = 0;
nSproutValue = boost::none;
nChainSproutValue = boost::none;
nVersion = 0;
hashMerkleRoot = uint256();
@@ -328,6 +353,18 @@ public:
READWRITE(VARINT(nDataPos));
if (nStatus & BLOCK_HAVE_UNDO)
READWRITE(VARINT(nUndoPos));
if (nStatus & BLOCK_ACTIVATES_UPGRADE) {
if (ser_action.ForRead()) {
uint32_t branchId;
READWRITE(branchId);
nCachedBranchId = branchId;
} else {
// nCachedBranchId must always be set if BLOCK_ACTIVATES_UPGRADE is set.
assert(nCachedBranchId);
uint32_t branchId = *nCachedBranchId;
READWRITE(branchId);
}
}
READWRITE(hashAnchor);
// block header
@@ -339,6 +376,12 @@ public:
READWRITE(nBits);
READWRITE(nNonce);
READWRITE(nSolution);
// Only read/write nSproutValue if the client version used to create
// this index was storing them.
if ((nType & SER_DISK) && (nVersion >= SPROUT_VALUE_VERSION)) {
READWRITE(nSproutValue);
}
}
uint256 GetBlockHash() const

View File

@@ -15,10 +15,56 @@
#include "base58.h"
using namespace std;
#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.fOverwintered = true
// txNew.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID
// txNew.nExpiryHeight = <default value>
CMutableTransaction txNew;
txNew.nVersion = 1;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 520617983 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
txNew.vout[0].nValue = genesisReward;
txNew.vout[0].scriptPubKey = genesisOutputScript;
CBlock genesis;
genesis.nTime = nTime;
genesis.nBits = nBits;
genesis.nNonce = nNonce;
genesis.nSolution = nSolution;
genesis.nVersion = nVersion;
genesis.vtx.push_back(txNew);
genesis.hashPrevBlock.SetNull();
genesis.hashMerkleRoot = genesis.BuildMerkleTree();
return genesis;
}
/**
* Build the genesis block. Note that the output of its generation
* transaction cannot be spent since it did not originally exist in the
* database (and is in any case of zero value).
*
* >>> from pyblake2 import blake2s
* >>> 'Zcash' + blake2s(b'The Economist 2016-10-29 Known unknown: Another crypto-currency is born. BTC#436254 0000000000000000044f321997f336d2908cf8c8d6893e88dbf067e2d949487d ETH#2521903 483039a6b6bd8bd05f0584f9a078d075e454925eb71c1f13eaff59b405a721bb DJIA close on 27 Oct 2016: 18,169.68').hexdigest()
*
* CBlock(hash=00040fe8, ver=4, hashPrevBlock=00000000000000, hashMerkleRoot=c4eaa5, nTime=1477641360, nBits=1f07ffff, nNonce=4695, vtx=1)
* CTransaction(hash=c4eaa5, ver=1, vin.size=1, vout.size=1, nLockTime=0)
* CTxIn(COutPoint(000000, -1), coinbase 04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334)
* CTxOut(nValue=0.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
* vMerkleTree: c4eaa5
*/
static CBlock CreateGenesisBlock(uint32_t nTime, const uint256& nNonce, const std::vector<unsigned char>& nSolution, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
const char* pszTimestamp = "Zcash0b9c4eef8b7cc417ee5001e3500984b6fea35683a7cac141a043c42064835d34";
const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nSolution, nBits, nVersion, genesisReward);
}
/**
* Main network
*/
@@ -59,6 +105,16 @@ public:
consensus.nPowMaxAdjustUp = 16; // 16% adjustment up
consensus.nPowTargetSpacing = 1 * 60;
consensus.fPowAllowMinDifficultyBlocks = true; //false;
consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002;
consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight =
Consensus::NetworkUpgrade::ALWAYS_ACTIVE;
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;
/**
* The message start string is designed to be unlikely to occur in normal data.
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
@@ -77,6 +133,7 @@ public:
BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K));
nEquihashN = N;
nEquihashK = K;
const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
CMutableTransaction txNew;
txNew.vin.resize(1);
@@ -93,11 +150,19 @@ public:
genesis.nNonce = uint256S("0x000000000000000000000000000000000000000000000000000000000000000b");
genesis.nSolution = ParseHex("000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2");
/*genesis = CreateGenesisBlock(
1477641360,
uint256S("0x0000000000000000000000000000000000000000000000000000000000001257"),
ParseHex("000a889f00854b8665cd555f4656f68179d31ccadc1b1f7fb0952726313b16941da348284d67add4686121d4e3d930160c1348d8191c25f12b267a6a9c131b5031cbf8af1f79c9d513076a216ec87ed045fa966e01214ed83ca02dc1797270a454720d3206ac7d931a0a680c5c5e099057592570ca9bdf6058343958b31901fce1a15a4f38fd347750912e14004c73dfe588b903b6c03166582eeaf30529b14072a7b3079e3a684601b9b3024054201f7440b0ee9eb1a7120ff43f713735494aa27b1f8bab60d7f398bca14f6abb2adbf29b04099121438a7974b078a11635b594e9170f1086140b4173822dd697894483e1c6b4e8b8dcd5cb12ca4903bc61e108871d4d915a9093c18ac9b02b6716ce1013ca2c1174e319c1a570215bc9ab5f7564765f7be20524dc3fdf8aa356fd94d445e05ab165ad8bb4a0db096c097618c81098f91443c719416d39837af6de85015dca0de89462b1d8386758b2cf8a99e00953b308032ae44c35e05eb71842922eb69797f68813b59caf266cb6c213569ae3280505421a7e3a0a37fdf8e2ea354fc5422816655394a9454bac542a9298f176e211020d63dee6852c40de02267e2fc9d5e1ff2ad9309506f02a1a71a0501b16d0d36f70cdfd8de78116c0c506ee0b8ddfdeb561acadf31746b5a9dd32c21930884397fb1682164cb565cc14e089d66635a32618f7eb05fe05082b8a3fae620571660a6b89886eac53dec109d7cbb6930ca698a168f301a950be152da1be2b9e07516995e20baceebecb5579d7cdbc16d09f3a50cb3c7dffe33f26686d4ff3f8946ee6475e98cf7b3cf9062b6966e838f865ff3de5fb064a37a21da7bb8dfd2501a29e184f207caaba364f36f2329a77515dcb710e29ffbf73e2bbd773fab1f9a6b005567affff605c132e4e4dd69f36bd201005458cfbd2c658701eb2a700251cefd886b1e674ae816d3f719bac64be649c172ba27a4fd55947d95d53ba4cbc73de97b8af5ed4840b659370c556e7376457f51e5ebb66018849923db82c1c9a819f173cccdb8f3324b239609a300018d0fb094adf5bd7cbb3834c69e6d0b3798065c525b20f040e965e1a161af78ff7561cd874f5f1b75aa0bc77f720589e1b810f831eac5073e6dd46d00a2793f70f7427f0f798f2f53a67e615e65d356e66fe40609a958a05edb4c175bcc383ea0530e67ddbe479a898943c6e3074c6fcc252d6014de3a3d292b03f0d88d312fe221be7be7e3c59d07fa0f2f4029e364f1f355c5d01fa53770d0cd76d82bf7e60f6903bc1beb772e6fde4a70be51d9c7e03c8d6d8dfb361a234ba47c470fe630820bbd920715621b9fbedb49fcee165ead0875e6c2b1af16f50b5d6140cc981122fcbcf7c5a4e3772b3661b628e08380abc545957e59f634705b1bbde2f0b4e055a5ec5676d859be77e20962b645e051a880fddb0180b4555789e1f9344a436a84dc5579e2553f1e5fb0a599c137be36cabbed0319831fea3fddf94ddc7971e4bcf02cdc93294a9aab3e3b13e3b058235b4f4ec06ba4ceaa49d675b4ba80716f3bc6976b1fbf9c8bf1f3e3a4dc1cd83ef9cf816667fb94f1e923ff63fef072e6a19321e4812f96cb0ffa864da50ad74deb76917a336f31dce03ed5f0303aad5e6a83634f9fcc371096f8288b8f02ddded5ff1bb9d49331e4a84dbe1543164438fde9ad71dab024779dcdde0b6602b5ae0a6265c14b94edd83b37403f4b78fcd2ed555b596402c28ee81d87a909c4e8722b30c71ecdd861b05f61f8b1231795c76adba2fdefa451b283a5d527955b9f3de1b9828e7b2e74123dd47062ddcc09b05e7fa13cb2212a6fdbc65d7e852cec463ec6fd929f5b8483cf3052113b13dac91b69f49d1b7d1aec01c4a68e41ce157"),
0x1f07ffff, 4, 0);*/
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256S("0x027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71"));
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
vFixedSeeds.clear();
vSeeds.clear();
vSeeds.push_back(CDNSSeedData("komodoplatform.com", "seeds.komodoplatform.com")); // @kolo
vSeeds.push_back(CDNSSeedData("komodo.mewhub.com", "seeds.komodo.mewhub.com")); // @kolo
// TODO: set up bootstrapping for mainnet
@@ -118,21 +183,6 @@ public:
fRequireStandard = true;
fMineBlocksOnDemand = false;
fTestnetToBeDeprecatedFieldRPC = false;
/*
checkpointData = (Checkpoints::CCheckpointData)
{
boost::assign::map_list_of
(0, consensus.hashGenesisBlock),
//(2500, uint256S("0x0e6a3d5a46eba97c4e7618d66a39f115729e1176433c98481124c2bf733aa54e"))
//(15000, uint256S("0x00f0bd236790e903321a2d22f85bd6bf8a505f6ef4eddb20458a65d37e14d142")),
//(100000, uint256S("0x0f02eb1f3a4b89df9909fec81a4bd7d023e32e24e1f5262d9fc2cc36a715be6f")),
1481120910, // * UNIX timestamp of last checkpoint block
110415, // * total number of transactions between genesis and last checkpoint
// (the tx=... number in the SetBestChain debug.log lines)
2777 // * estimated number of transactions per day after checkpoint
// total number of tx / (checkpoint block height / (24 * 24))
};
*/
// LogPrintf(">>>>>>>> ac_name = %u\n",GetArg("-ac_name","").c_str());
@@ -353,25 +403,49 @@ void *chainparams_commandline(void *ptr)
/**
* Testnet (v3)
*/
class CTestNetParams : public CMainParams {
class CTestNetParams : public CChainParams {
public:
CTestNetParams() {
strNetworkID = "test";
strCurrencyUnits = "TAZ";
consensus.fCoinbaseMustBeProtected = true;
consensus.nSubsidySlowStartInterval = 20000;
consensus.nSubsidyHalvingInterval = 840000;
consensus.nMajorityEnforceBlockUpgrade = 51;
consensus.nMajorityRejectBlockOutdated = 75;
consensus.nMajorityWindow = 400;
consensus.powLimit = uint256S("07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowAveragingWindow = 17;
assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
vAlertPubKey = ParseHex("00");
nDefaultPort = 17770;
nMinerThreads = 0;
consensus.nPowMaxAdjustDown = 32; // 32% adjustment down
consensus.nPowMaxAdjustUp = 16; // 16% adjustment up
consensus.nPowTargetSpacing = 2.5 * 60;
consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002;
consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight =
Consensus::NetworkUpgrade::ALWAYS_ACTIVE;
consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nProtocolVersion = 170002;
consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170003;
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 207500;
consensus.fPowAllowMinDifficultyBlocks = true;
pchMessageStart[0] = 0x5A;
pchMessageStart[1] = 0x1F;
pchMessageStart[2] = 0x7E;
pchMessageStart[3] = 0x62;
vAlertPubKey = ParseHex("00");
nDefaultPort = 17770;
nMinerThreads = 0;
vAlertPubKey = ParseHex("020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9");
nMaxTipAge = 24 * 60 * 60;
nPruneAfterHeight = 1000;
const size_t N = 200, K = 9;
BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K));
nEquihashN = N;
nEquihashK = K;
//! Modify the testnet genesis block so the timestamp is valid for a later start.
genesis.nTime = 1296688602;
@@ -402,7 +476,7 @@ public:
fMineBlocksOnDemand = false;
fTestnetToBeDeprecatedFieldRPC = true;
checkpointData = (Checkpoints::CCheckpointData) {
checkpointData = (CCheckpointData) {
boost::assign::map_list_of
(0, consensus.hashGenesisBlock)
(38000, uint256S("0x001e9a2d2e2892b88e9998cf7b079b41d59dd085423a921fe8386cecc42287b8")),
@@ -418,7 +492,7 @@ static CTestNetParams testNetParams;
/**
* Regression test
*/
class CRegTestParams : public CTestNetParams {
class CRegTestParams : public CChainParams {
public:
CRegTestParams() {
strNetworkID = "regtest";
@@ -430,15 +504,28 @@ public:
consensus.nMajorityRejectBlockOutdated = 950;
consensus.nMajorityWindow = 1000;
consensus.powLimit = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f");
consensus.nPowAveragingWindow = 17;
assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down
consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up
consensus.nPowTargetSpacing = 2.5 * 60;
consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002;
consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight =
Consensus::NetworkUpgrade::ALWAYS_ACTIVE;
consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nProtocolVersion = 170002;
consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170003;
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
pchMessageStart[0] = 0xaa;
pchMessageStart[1] = 0x8e;
pchMessageStart[2] = 0xf3;
pchMessageStart[3] = 0xf5;
nMinerThreads = 1;
nMaxTipAge = 24 * 60 * 60;
nPruneAfterHeight = 1000;
const size_t N = 48, K = 5;
BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K));
nEquihashN = N;
@@ -461,18 +548,34 @@ public:
fMineBlocksOnDemand = true;
fTestnetToBeDeprecatedFieldRPC = false;
checkpointData = (Checkpoints::CCheckpointData){
checkpointData = (CCheckpointData){
boost::assign::map_list_of
( 0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")),
0,
0,
0
};
// These prefixes are the same as the testnet prefixes
base58Prefixes[PUBKEY_ADDRESS] = {0x1D,0x25};
base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBA};
base58Prefixes[SECRET_KEY] = {0xEF};
// do not rely on these BIP32 prefixes; they are not specified and may change
base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x35,0x87,0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04,0x35,0x83,0x94};
base58Prefixes[ZCPAYMENT_ADDRRESS] = {0x16,0xB6};
base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C};
base58Prefixes[ZCSPENDING_KEY] = {0xAC,0x08};
// Founders reward script expects a vector of 2-of-3 multisig addresses
vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" };
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight());
}
void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivationHeight)
{
assert(idx > Consensus::BASE_SPROUT && idx < Consensus::MAX_NETWORK_UPGRADES);
consensus.vUpgrades[idx].nActivationHeight = nActivationHeight;
}
};
static CRegTestParams regTestParams;
@@ -537,7 +640,7 @@ CScript CChainParams::GetFoundersRewardScriptAtHeight(int nHeight) const {
CBitcoinAddress address(GetFoundersRewardAddressAtHeight(nHeight).c_str());
assert(address.IsValid());
assert(address.IsScript());
CScriptID scriptID = get<CScriptID>(address.Get()); // Get() returns a boost variant
CScriptID scriptID = boost::get<CScriptID>(address.Get()); // Get() returns a boost variant
CScript script = CScript() << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
return script;
}
@@ -546,3 +649,8 @@ std::string CChainParams::GetFoundersRewardAddressAtIndex(int i) const {
assert(i >= 0 && i < vFoundersRewardAddress.size());
return vFoundersRewardAddress[i];
}
void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivationHeight)
{
regTestParams.UpdateNetworkUpgradeParameters(idx, nActivationHeight);
}

View File

@@ -7,7 +7,6 @@
#define BITCOIN_CHAINPARAMS_H
#include "chainparamsbase.h"
#include "checkpoints.h"
#include "consensus/params.h"
#include "primitives/block.h"
#include "protocol.h"
@@ -26,6 +25,14 @@ struct SeedSpec6 {
uint16_t port;
};
typedef std::map<int, uint256> MapCheckpoints;
struct CCheckpointData {
MapCheckpoints mapCheckpoints;
int64_t nTimeLastCheckpoint;
int64_t nTransactionsLastCheckpoint;
double fTransactionsPerDay;
};
/**
* CChainParams defines various tweakable parameters of a given instance of the
@@ -46,6 +53,7 @@ public:
ZCPAYMENT_ADDRRESS,
ZCSPENDING_KEY,
ZCVIEWING_KEY,
MAX_BASE58_TYPES
};
@@ -55,8 +63,6 @@ public:
const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
int GetDefaultPort() const { return nDefaultPort; }
/** Used if GenerateBitcoins is called with a negative number of threads */
int DefaultMinerThreads() const { return nMinerThreads; }
const CBlock& GenesisBlock() const { return genesis; }
/** Make miner wait to have peers to avoid wasting work */
bool MiningRequiresPeers() const { return fMiningRequiresPeers; }
@@ -78,7 +84,7 @@ public:
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
const Checkpoints::CCheckpointData& Checkpoints() const { return checkpointData; }
const CCheckpointData& Checkpoints() const { return checkpointData; }
/** Return the founder's reward address and script for a given block height */
std::string GetFoundersRewardAddressAtHeight(int height) const;
CScript GetFoundersRewardScriptAtHeight(int height) const;
@@ -103,6 +109,7 @@ protected:
//! Raw pub key bytes for the broadcast alert signing key.
std::vector<unsigned char> vAlertPubKey;
int nMinerThreads = 0;
int nDefaultPort = 0;
long nMaxTipAge = 0;
uint64_t nPruneAfterHeight = 0;
unsigned int nEquihashN = 0;
@@ -118,7 +125,7 @@ protected:
bool fRequireStandard = false;
bool fMineBlocksOnDemand = false;
bool fTestnetToBeDeprecatedFieldRPC = false;
Checkpoints::CCheckpointData checkpointData;
CCheckpointData checkpointData;
std::vector<std::string> vFoundersRewardAddress;
};
@@ -140,4 +147,9 @@ void SelectParams(CBaseChainParams::Network network);
*/
bool SelectParamsFromCommandLine();
/**
* Allows modifying the network upgrade regtest parameters.
*/
void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivationHeight);
#endif // BITCOIN_CHAINPARAMS_H

View File

@@ -25,7 +25,7 @@ static CBaseMainParams mainParams;
/**
* Testnet (v3)
*/
class CBaseTestNetParams : public CBaseMainParams
class CBaseTestNetParams : public CBaseChainParams
{
public:
CBaseTestNetParams()
@@ -39,11 +39,12 @@ static CBaseTestNetParams testNetParams;
/*
* Regression test
*/
class CBaseRegTestParams : public CBaseTestNetParams
class CBaseRegTestParams : public CBaseChainParams
{
public:
CBaseRegTestParams()
{
nRPCPort = 18232;
strDataDir = "regtest";
}
};

View File

@@ -10,6 +10,7 @@
#include <map>
class CBlockIndex;
struct CCheckpointData;
/**
* Block-chain checkpoints are compiled-in sanity checks.
@@ -17,7 +18,8 @@ class CBlockIndex;
*/
namespace Checkpoints
{
typedef std::map<int, uint256> MapCheckpoints;
typedef std::map<int, uint256> MapCheckpoints;
struct CCheckpointData {
MapCheckpoints mapCheckpoints;
@@ -27,6 +29,7 @@ struct CCheckpointData {
};
bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash);
//! Return conservative estimate of total number of blocks, 0 if unknown
int GetTotalBlocksEstimate(const CCheckpointData& data);

View File

@@ -100,7 +100,7 @@ const std::string CLIENT_NAME("MagicBean");
const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
const std::string CLIENT_DATE(BUILD_DATE);
static std::string FormatVersion(int nVersion)
std::string FormatVersion(int nVersion)
{
if (nVersion % 100 < 25)
return strprintf("%d.%d.%d-beta%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100, (nVersion % 100)+1);

View File

@@ -17,7 +17,7 @@
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 1
#define CLIENT_VERSION_MINOR 0
#define CLIENT_VERSION_REVISION 8
#define CLIENT_VERSION_REVISION 15
#define CLIENT_VERSION_BUILD 52
//! Set to true for release, false for prerelease or test build
@@ -63,6 +63,7 @@ extern const std::string CLIENT_BUILD;
extern const std::string CLIENT_DATE;
std::string FormatVersion(int nVersion);
std::string FormatFullVersion();
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments);

View File

@@ -473,8 +473,6 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
{
if (tx.IsCoinBase())
return 0.0;
//CAmount nTotalIn = 0;
// Joinsplits do not reveal any information about the value or age of a note, so we
// cannot apply the priority algorithm used for transparent utxos. Instead, we just
// use the maximum priority whenever a transaction contains any JoinSplits.
@@ -493,34 +491,9 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
if (!coins->IsAvailable(txin.prevout.n)) continue;
if (coins->nHeight < nHeight) {
dResult += coins->vout[txin.prevout.n].nValue * (nHeight-coins->nHeight);
//nTotalIn += coins->vout[txin.prevout.n].nValue;
}
}
// If a transaction contains a joinsplit, we boost the priority of the transaction.
// Joinsplits do not reveal any information about the value or age of a note, so we
// cannot apply the priority algorithm used for transparent utxos. Instead, we pick a
// very large number and multiply it by the transaction's fee per 1000 bytes of data.
// One trillion, 1000000000000, is equivalent to 1 ZEC utxo * 10000 blocks (~17 days).
/*if (tx.vjoinsplit.size() > 0) {
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
nTotalIn += tx.GetJoinSplitValueIn();
CAmount fee = nTotalIn - tx.GetValueOut();
CFeeRate feeRate(fee, nTxSize);
CAmount feePerK = feeRate.GetFeePerK();
if (feePerK == 0) {
feePerK = 1;
}
dResult += 1000000000000 * double(feePerK);
// We cast feePerK from int64_t to double because if feePerK is a large number, say
// close to MAX_MONEY, the multiplication operation will result in an integer overflow.
// The variable dResult should never overflow since a 64-bit double in C++ is typically
// a double-precision floating-point number as specified by IEE 754, with a maximum
// value DBL_MAX of 1.79769e+308.
}*/
return tx.ComputePriority(dResult);
}

View File

@@ -171,7 +171,7 @@ public:
nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion);
// spentness bitmask
nSize += nMaskSize;
// txouts themself
// txouts
for (unsigned int i = 0; i < vout.size(); i++)
if (!vout[i].IsNull())
nSize += ::GetSerializeSize(CTxOutCompressor(REF(vout[i])), nType, nVersion);

View File

@@ -9,7 +9,11 @@
/** The minimum allowed block version (network rule) */
static const int32_t MIN_BLOCK_VERSION = 4;
/** The minimum allowed transaction version (network rule) */
static const int32_t MIN_TX_VERSION = 1;
static const int32_t SPROUT_MIN_TX_VERSION = 1;
/** The minimum allowed transaction version (network rule) */
static const int32_t OVERWINTER_MIN_TX_VERSION = 3;
/** The maximum allowed transaction version (network rule) */
static const int32_t OVERWINTER_MAX_TX_VERSION = 3;
/** 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) */
@@ -18,6 +22,8 @@ static const unsigned int MAX_BLOCK_SIGOPS = 20000;
static const unsigned int MAX_TX_SIZE = 100000;
/** 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 */
static constexpr uint32_t TX_EXPIRY_HEIGHT_THRESHOLD = 500000000;
/** Flags for LockTime() */
enum {

View File

@@ -9,6 +9,54 @@
#include "uint256.h"
namespace Consensus {
/**
* Index into Params.vUpgrades and NetworkUpgradeInfo
*
* Being array indices, these MUST be numbered consecutively.
*
* The order of these indices MUST match the order of the upgrades on-chain, as
* several functions depend on the enum being sorted.
*/
enum UpgradeIndex {
// Sprout must be first
BASE_SPROUT,
UPGRADE_TESTDUMMY,
UPGRADE_OVERWINTER,
// NOTE: Also add new upgrades to NetworkUpgradeInfo in upgrades.cpp
MAX_NETWORK_UPGRADES
};
struct NetworkUpgrade {
/**
* The first protocol version which will understand the new consensus rules
*/
int nProtocolVersion;
/**
* Height of the first block for which the new consensus rules will be active
*/
int nActivationHeight;
/**
* Special value for nActivationHeight indicating that the upgrade is always active.
* This is useful for testing, as it means tests don't need to deal with the activation
* process (namely, faking a chain of somewhat-arbitrary length).
*
* New blockchains that want to enable upgrade rules from the beginning can also use
* this value. However, additional care must be taken to ensure the genesis block
* satisfies the enabled rules.
*/
static constexpr int ALWAYS_ACTIVE = 0;
/**
* Special value for nActivationHeight indicating that the upgrade will never activate.
* This is useful when adding upgrade code that has a testnet activation height, but
* should remain disabled on mainnet.
*/
static constexpr int NO_ACTIVATION_HEIGHT = -1;
};
/**
* Parameters that influence chain consensus.
*/
@@ -39,9 +87,9 @@ struct Params {
int nMajorityEnforceBlockUpgrade;
int nMajorityRejectBlockOutdated;
int nMajorityWindow;
NetworkUpgrade vUpgrades[MAX_NETWORK_UPGRADES];
/** Proof of work parameters */
uint256 powLimit;
bool fPowAllowMinDifficultyBlocks;
int64_t nPowAveragingWindow;
int64_t nPowMaxAdjustDown;
int64_t nPowMaxAdjustUp;

126
src/consensus/upgrades.cpp Normal file
View File

@@ -0,0 +1,126 @@
// Copyright (c) 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 "consensus/upgrades.h"
/**
* General information about each network upgrade.
* Ordered by Consensus::UpgradeIndex.
*/
const struct NUInfo NetworkUpgradeInfo[Consensus::MAX_NETWORK_UPGRADES] = {
{
/*.nBranchId =*/ 0,
/*.strName =*/ "Sprout",
/*.strInfo =*/ "The Zcash network at launch",
},
{
/*.nBranchId =*/ 0x74736554,
/*.strName =*/ "Test dummy",
/*.strInfo =*/ "Test dummy info",
},
{
/*.nBranchId =*/ 0x5ba81b19,
/*.strName =*/ "Overwinter",
/*.strInfo =*/ "See https://z.cash/upgrade/overwinter.html for details.",
}
};
const uint32_t SPROUT_BRANCH_ID = NetworkUpgradeInfo[Consensus::BASE_SPROUT].nBranchId;
UpgradeState NetworkUpgradeState(
int nHeight,
const Consensus::Params& params,
Consensus::UpgradeIndex idx)
{
assert(nHeight >= 0);
assert(idx >= Consensus::BASE_SPROUT && idx < Consensus::MAX_NETWORK_UPGRADES);
auto nActivationHeight = params.vUpgrades[idx].nActivationHeight;
if (nActivationHeight == Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) {
return UPGRADE_DISABLED;
} else if (nHeight >= nActivationHeight) {
// From ZIP 200:
//
// ACTIVATION_HEIGHT
// The non-zero block height at which the network upgrade rules will come
// into effect, and be enforced as part of the blockchain consensus.
//
// For removal of ambiguity, the block at height ACTIVATION_HEIGHT - 1 is
// subject to the pre-upgrade consensus rules, and would be the last common
// block in the event of a persistent pre-upgrade branch.
return UPGRADE_ACTIVE;
} else {
return UPGRADE_PENDING;
}
}
bool NetworkUpgradeActive(
int nHeight,
const Consensus::Params& params,
Consensus::UpgradeIndex idx)
{
return NetworkUpgradeState(nHeight, params, idx) == UPGRADE_ACTIVE;
}
int CurrentEpoch(int nHeight, const Consensus::Params& params) {
for (auto idxInt = Consensus::MAX_NETWORK_UPGRADES - 1; idxInt >= Consensus::BASE_SPROUT; idxInt--) {
if (NetworkUpgradeActive(nHeight, params, Consensus::UpgradeIndex(idxInt))) {
return idxInt;
}
}
}
uint32_t CurrentEpochBranchId(int nHeight, const Consensus::Params& params) {
return NetworkUpgradeInfo[CurrentEpoch(nHeight, params)].nBranchId;
}
bool IsActivationHeight(
int nHeight,
const Consensus::Params& params,
Consensus::UpgradeIndex idx)
{
assert(idx >= Consensus::BASE_SPROUT && idx < Consensus::MAX_NETWORK_UPGRADES);
// Don't count Sprout as an activation height
if (idx == Consensus::BASE_SPROUT) {
return false;
}
return nHeight >= 0 && nHeight == params.vUpgrades[idx].nActivationHeight;
}
bool IsActivationHeightForAnyUpgrade(
int nHeight,
const Consensus::Params& params)
{
if (nHeight < 0) {
return false;
}
// Don't count Sprout as an activation height
for (int idx = Consensus::BASE_SPROUT + 1; idx < Consensus::MAX_NETWORK_UPGRADES; idx++) {
if (nHeight == params.vUpgrades[idx].nActivationHeight)
return true;
}
return false;
}
boost::optional<int> NextActivationHeight(
int nHeight,
const Consensus::Params& params)
{
if (nHeight < 0) {
return boost::none;
}
// Don't count Sprout as an activation height
for (auto idx = Consensus::BASE_SPROUT + 1; idx < Consensus::MAX_NETWORK_UPGRADES; idx++) {
if (NetworkUpgradeState(nHeight, params, Consensus::UpgradeIndex(idx)) == UPGRADE_PENDING) {
return params.vUpgrades[idx].nActivationHeight;
}
}
return boost::none;
}

90
src/consensus/upgrades.h Normal file
View File

@@ -0,0 +1,90 @@
// Copyright (c) 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 ZCASH_CONSENSUS_UPGRADES_H
#define ZCASH_CONSENSUS_UPGRADES_H
#include "consensus/params.h"
#include <boost/optional.hpp>
enum UpgradeState {
UPGRADE_DISABLED,
UPGRADE_PENDING,
UPGRADE_ACTIVE
};
struct NUInfo {
/** Branch ID (a random non-zero 32-bit value) */
uint32_t nBranchId;
/** User-facing name for the upgrade */
std::string strName;
/** User-facing information string about the upgrade */
std::string strInfo;
};
extern const struct NUInfo NetworkUpgradeInfo[];
// Consensus branch id to identify pre-overwinter (Sprout) consensus rules.
extern const uint32_t SPROUT_BRANCH_ID;
/**
* Checks the state of a given network upgrade based on block height.
* Caller must check that the height is >= 0 (and handle unknown heights).
*/
UpgradeState NetworkUpgradeState(
int nHeight,
const Consensus::Params& params,
Consensus::UpgradeIndex idx);
/**
* Returns true if the given network upgrade is active as of the given block
* height. Caller must check that the height is >= 0 (and handle unknown
* heights).
*/
bool NetworkUpgradeActive(
int nHeight,
const Consensus::Params& params,
Consensus::UpgradeIndex idx);
/**
* Returns the index of the most recent upgrade as of the given block height
* (corresponding to the current "epoch"). Consensus::BASE_SPROUT is the
* default value if no upgrades are active. Caller must check that the height
* is >= 0 (and handle unknown heights).
*/
int CurrentEpoch(int nHeight, const Consensus::Params& params);
/**
* Returns the branch ID of the most recent upgrade as of the given block height
* (corresponding to the current "epoch"), or 0 if no upgrades are active.
* Caller must check that the height is >= 0 (and handle unknown heights).
*/
uint32_t CurrentEpochBranchId(int nHeight, const Consensus::Params& params);
/**
* Returns true if the given block height is the activation height for the given
* upgrade.
*/
bool IsActivationHeight(
int nHeight,
const Consensus::Params& params,
Consensus::UpgradeIndex upgrade);
/**
* Returns true if the given block height is the activation height for any upgrade.
*/
bool IsActivationHeightForAnyUpgrade(
int nHeight,
const Consensus::Params& params);
/**
* Returns the activation height for the next upgrade after the given block height,
* or boost::none if there are no more known upgrades.
*/
boost::optional<int> NextActivationHeight(
int nHeight,
const Consensus::Params& params);
#endif // ZCASH_CONSENSUS_UPGRADES_H

View File

@@ -16,7 +16,7 @@
#include "compat/endian.h"
#if defined(NDEBUG)
# error "Bitcoin cannot be compiled without assertions."
# error "Zcash cannot be compiled without assertions."
#endif
uint16_t static inline ReadLE16(const unsigned char* ptr)

View File

@@ -16,6 +16,7 @@
#include "config/bitcoin-config.h"
#endif
#include "compat/endian.h"
#include "crypto/equihash.h"
#include "util.h"
#ifndef __linux__

61
src/deprecation.cpp Normal file
View File

@@ -0,0 +1,61 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "deprecation.h"
#include "clientversion.h"
#include "init.h"
#include "ui_interface.h"
#include "util.h"
#include "chainparams.h"
static const std::string CLIENT_VERSION_STR = FormatVersion(CLIENT_VERSION);
void EnforceNodeDeprecation(int nHeight, bool forceLogging) {
// Do not enforce deprecation in regtest or on testnet
std::string networkID = Params().NetworkIDString();
if (networkID != "main") 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:
// - The deprecating block just arrived
// - This can be triggered more than once if a block chain reorg
// 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."),
DEPRECATION_HEIGHT) + " " +
_("You should upgrade to the latest version of Zcash.");
if (!disableDeprecation) {
msg += " " + strprintf(_("To disable deprecation for this version, set %s%s."),
"-disabledeprecation=", CLIENT_VERSION_STR);
}
LogPrintf("*** %s\n", msg);
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."),
DEPRECATION_HEIGHT) + " " +
_("You should upgrade to the latest version of Zcash.");
} 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 Zcash.") + " " +
strprintf(_("To disable deprecation for this version, set %s%s."),
"-disabledeprecation=", CLIENT_VERSION_STR);
}
LogPrintf("*** %s\n", msg);
uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_WARNING);
}
}

25
src/deprecation.h Normal file
View File

@@ -0,0 +1,25 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef ZCASH_DEPRECATION_H
#define ZCASH_DEPRECATION_H
// Deprecation policy:
// * Shut down 16 weeks' worth of blocks after the estimated release block height.
// * A warning is shown during the 2 weeks' worth of blocks prior to shut down.
static const int APPROX_RELEASE_HEIGHT = 800000;
static const int WEEKS_UNTIL_DEPRECATION = 52;
static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24);
// Number of blocks before deprecation to warn users
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).
*/
void EnforceNodeDeprecation(int nHeight, bool forceLogging=false);
#endif // ZCASH_DEPRECATION_H

View File

@@ -1,68 +0,0 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-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.
#include "eccryptoverify.h"
namespace {
int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char *c2, size_t c2len) {
while (c1len > c2len) {
if (*c1)
return 1;
c1++;
c1len--;
}
while (c2len > c1len) {
if (*c2)
return -1;
c2++;
c2len--;
}
while (c1len > 0) {
if (*c1 > *c2)
return 1;
if (*c2 > *c1)
return -1;
c1++;
c2++;
c1len--;
}
return 0;
}
/** Order of secp256k1's generator minus 1. */
const unsigned char vchMaxModOrder[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
};
/** Half of the order of secp256k1's generator minus 1. */
const unsigned char vchMaxModHalfOrder[32] = {
0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x5D,0x57,0x6E,0x73,0x57,0xA4,0x50,0x1D,
0xDF,0xE9,0x2F,0x46,0x68,0x1B,0x20,0xA0
};
const unsigned char vchZero[1] = {0};
} // anon namespace
namespace eccrypto {
bool Check(const unsigned char *vch) {
return vch &&
CompareBigEndian(vch, 32, vchZero, 0) > 0 &&
CompareBigEndian(vch, 32, vchMaxModOrder, 32) <= 0;
}
bool CheckSignatureElement(const unsigned char *vch, int len, bool half) {
return vch &&
CompareBigEndian(vch, len, vchZero, 0) > 0 &&
CompareBigEndian(vch, len, half ? vchMaxModHalfOrder : vchMaxModOrder, 32) <= 0;
}
} // namespace eccrypto

View File

@@ -1,21 +0,0 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-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_ECCRYPTOVERIFY_H
#define BITCOIN_ECCRYPTOVERIFY_H
#include <vector>
#include <cstdlib>
class uint256;
namespace eccrypto {
bool Check(const unsigned char *vch);
bool CheckSignatureElement(const unsigned char *vch, int len, bool half);
} // eccrypto namespace
#endif // BITCOIN_ECCRYPTOVERIFY_H

View File

@@ -1,223 +0,0 @@
// Copyright (c) 2009-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.
#include "ecwrapper.h"
#include "serialize.h"
#include "uint256.h"
#include <openssl/bn.h>
#include <openssl/obj_mac.h>
namespace {
class ecgroup_order
{
public:
static const EC_GROUP* get()
{
static const ecgroup_order wrapper;
return wrapper.pgroup;
}
private:
ecgroup_order()
: pgroup(EC_GROUP_new_by_curve_name(NID_secp256k1))
{
}
~ecgroup_order()
{
EC_GROUP_free(pgroup);
}
EC_GROUP* pgroup;
};
/**
* Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
* recid selects which key is recovered
* if check is non-zero, additional checks are performed
*/
int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
{
if (!eckey) return 0;
int ret = 0;
BN_CTX *ctx = NULL;
BIGNUM *x = NULL;
BIGNUM *e = NULL;
BIGNUM *order = NULL;
BIGNUM *sor = NULL;
BIGNUM *eor = NULL;
BIGNUM *field = NULL;
EC_POINT *R = NULL;
EC_POINT *O = NULL;
EC_POINT *Q = NULL;
BIGNUM *rr = NULL;
BIGNUM *zero = NULL;
int n = 0;
int i = recid / 2;
const BIGNUM *sig_r, *sig_s;
ECDSA_SIG_get0(ecsig, &sig_r, &sig_s);
const EC_GROUP *group = EC_KEY_get0_group(eckey);
if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
BN_CTX_start(ctx);
order = BN_CTX_get(ctx);
if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
x = BN_CTX_get(ctx);
if (!BN_copy(x, order)) { ret=-1; goto err; }
if (!BN_mul_word(x, i)) { ret=-1; goto err; }
if (!BN_add(x, x, sig_r)) { ret=-1; goto err; }
field = BN_CTX_get(ctx);
if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
if (check)
{
if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
}
if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
n = EC_GROUP_get_degree(group);
e = BN_CTX_get(ctx);
if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
zero = BN_CTX_get(ctx);
if (!BN_zero(zero)) { ret=-1; goto err; }
if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
rr = BN_CTX_get(ctx);
if (!BN_mod_inverse(rr, sig_r, order, ctx)) { ret=-1; goto err; }
sor = BN_CTX_get(ctx);
if (!BN_mod_mul(sor, sig_s, rr, order, ctx)) { ret=-1; goto err; }
eor = BN_CTX_get(ctx);
if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }
ret = 1;
err:
if (ctx) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
if (R != NULL) EC_POINT_free(R);
if (O != NULL) EC_POINT_free(O);
if (Q != NULL) EC_POINT_free(Q);
return ret;
}
} // anon namespace
CECKey::CECKey() {
pkey = EC_KEY_new();
assert(pkey != NULL);
int result = EC_KEY_set_group(pkey, ecgroup_order::get());
assert(result);
}
CECKey::~CECKey() {
EC_KEY_free(pkey);
}
void CECKey::GetPubKey(std::vector<unsigned char> &pubkey, bool fCompressed) {
EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
int nSize = i2o_ECPublicKey(pkey, NULL);
assert(nSize);
assert(nSize <= 65);
pubkey.clear();
pubkey.resize(nSize);
unsigned char *pbegin(begin_ptr(pubkey));
int nSize2 = i2o_ECPublicKey(pkey, &pbegin);
assert(nSize == nSize2);
}
bool CECKey::SetPubKey(const unsigned char* pubkey, size_t size) {
return o2i_ECPublicKey(&pkey, &pubkey, size) != NULL;
}
bool CECKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
if (vchSig.empty())
return false;
// New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first.
unsigned char *norm_der = NULL;
ECDSA_SIG *norm_sig = ECDSA_SIG_new();
const unsigned char* sigptr = &vchSig[0];
assert(norm_sig);
if (d2i_ECDSA_SIG(&norm_sig, &sigptr, vchSig.size()) == NULL)
{
/* As of OpenSSL 1.0.0p d2i_ECDSA_SIG frees and nulls the pointer on
* error. But OpenSSL's own use of this function redundantly frees the
* result. As ECDSA_SIG_free(NULL) is a no-op, and in the absence of a
* clear contract for the function behaving the same way is more
* conservative.
*/
ECDSA_SIG_free(norm_sig);
return false;
}
int derlen = i2d_ECDSA_SIG(norm_sig, &norm_der);
ECDSA_SIG_free(norm_sig);
if (derlen <= 0)
return false;
// -1 = error, 0 = bad sig, 1 = good
bool ret = ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), norm_der, derlen, pkey) == 1;
OPENSSL_free(norm_der);
return ret;
}
bool CECKey::Recover(const uint256 &hash, const unsigned char *p64, int rec)
{
if (rec<0 || rec>=3)
return false;
ECDSA_SIG *sig = ECDSA_SIG_new();
BIGNUM *sig_r = BN_bin2bn(&p64[0], 32, nullptr);
BIGNUM *sig_s = BN_bin2bn(&p64[32], 32, nullptr);
assert(sig && sig_r && sig_s);
bool ret = ECDSA_SIG_set0(sig, sig_r, sig_s);
assert(ret);
ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
ECDSA_SIG_free(sig);
return ret;
}
bool CECKey::TweakPublic(const unsigned char vchTweak[32]) {
bool ret = true;
BN_CTX *ctx = BN_CTX_new();
BN_CTX_start(ctx);
BIGNUM *bnTweak = BN_CTX_get(ctx);
BIGNUM *bnOrder = BN_CTX_get(ctx);
BIGNUM *bnOne = BN_CTX_get(ctx);
const EC_GROUP *group = EC_KEY_get0_group(pkey);
EC_GROUP_get_order(group, bnOrder, ctx); // what a grossly inefficient way to get the (constant) group order...
BN_bin2bn(vchTweak, 32, bnTweak);
if (BN_cmp(bnTweak, bnOrder) >= 0)
ret = false; // extremely unlikely
EC_POINT *point = EC_POINT_dup(EC_KEY_get0_public_key(pkey), group);
BN_one(bnOne);
EC_POINT_mul(group, point, bnTweak, point, bnOne, ctx);
if (EC_POINT_is_at_infinity(group, point))
ret = false; // ridiculously unlikely
EC_KEY_set_public_key(pkey, point);
EC_POINT_free(point);
BN_CTX_end(ctx);
BN_CTX_free(ctx);
return ret;
}
bool CECKey::SanityCheck()
{
const EC_GROUP *pgroup = ecgroup_order::get();
if(pgroup == NULL)
return false;
// TODO Is there more EC functionality that could be missing?
return true;
}

View File

@@ -1,40 +0,0 @@
// Copyright (c) 2009-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_ECWRAPPER_H
#define BITCOIN_ECWRAPPER_H
#include <cstddef>
#include <vector>
#include <openssl/ec.h>
class uint256;
/** RAII Wrapper around OpenSSL's EC_KEY */
class CECKey {
private:
EC_KEY *pkey;
public:
CECKey();
~CECKey();
void GetPubKey(std::vector<unsigned char>& pubkey, bool fCompressed);
bool SetPubKey(const unsigned char* pubkey, size_t size);
bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig);
/**
* reconstruct public key from a compact signature
* This is only slightly more CPU intensive than just verifying it.
* If this function succeeds, the recovered public key is guaranteed to be valid
* (the signature is a valid signature of the given data for that key)
*/
bool Recover(const uint256 &hash, const unsigned char *p64, int rec);
bool TweakPublic(const unsigned char vchTweak[32]);
static bool SanityCheck();
};
#endif // BITCOIN_ECWRAPPER_H

View File

@@ -1,15 +1,30 @@
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "crypto/common.h"
#include "pubkey.h"
#include "zcash/JoinSplit.hpp"
#include "util.h"
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
struct ECCryptoClosure
{
ECCVerifyHandle handle;
};
ECCryptoClosure instance_of_eccryptoclosure;
ZCJoinSplit* params;
int main(int argc, char **argv) {
assert(init_and_check_sodium() != -1);
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());
testing::InitGoogleTest(&argc, argv);
testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -33,6 +33,40 @@ TEST(CheckBlock, VersionTooLow) {
EXPECT_FALSE(CheckBlock(0,0,block, state, verifier, false, false));
}
// Test that a Sprout tx with negative version is still rejected
// by CheckBlock under Sprout consensus rules.
TEST(CheckBlock, BlockSproutRejectsBadVersion) {
SelectParams(CBaseChainParams::MAIN);
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)));
mtx.fOverwintered = false;
mtx.nVersion = -1;
mtx.nVersionGroupId = 0;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
auto verifier = libzcash::ProofVerifier::Strict();
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-version-too-low", false)).Times(1);
EXPECT_FALSE(CheckBlock(block, state, verifier, false, false));
}
TEST(ContextualCheckBlock, BadCoinbaseHeight) {
SelectParams(CBaseChainParams::MAIN);
@@ -75,3 +109,125 @@ TEST(ContextualCheckBlock, BadCoinbaseHeight) {
block.vtx[0] = tx4;
EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev));
}
// Test that a block evaluated under Sprout rules cannot contain Overwinter transactions.
// This test assumes that mainnet Overwinter activation is at least height 2.
TEST(ContextualCheckBlock, BlockSproutRulesRejectOverwinterTx) {
SelectParams(CBaseChainParams::MAIN);
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)));
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);
}
// Test block evaluated under Overwinter rules will accept Overwinter transactions
TEST(ContextualCheckBlock, 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)));
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_TRUE(ContextualCheckBlock(block, state, &indexPrev));
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Test block evaluated under Overwinter rules will reject Sprout transactions
TEST(ContextualCheckBlock, BlockOverwinterRulesRejectSproutTx) {
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.nVersion = 2;
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-active", false)).Times(1);
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}

View File

@@ -45,6 +45,8 @@ public:
CMutableTransaction GetValidTransaction() {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CMutableTransaction mtx;
mtx.vin.resize(2);
mtx.vin[0].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
@@ -74,7 +76,7 @@ CMutableTransaction GetValidTransaction() {
// Empty output script.
CScript scriptCode;
CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
if (dataToBeSigned == one) {
throw std::runtime_error("SignatureHash failed");
}
@@ -352,23 +354,27 @@ TEST(checktransaction_tests, bad_txns_prevout_null) {
}
TEST(checktransaction_tests, bad_txns_invalid_joinsplit_signature) {
SelectParams(CBaseChainParams::REGTEST);
CMutableTransaction mtx = GetValidTransaction();
mtx.joinSplitSig[0] += 1;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
ContextualCheckTransaction(tx, state, 0, 100);
}
TEST(checktransaction_tests, non_canonical_ed25519_signature) {
SelectParams(CBaseChainParams::REGTEST);
CMutableTransaction mtx = GetValidTransaction();
// Check that the signature is valid before we add L
{
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
EXPECT_TRUE(ContextualCheckTransaction(tx, state, 0, 100));
}
// Copied from libsodium/crypto_sign/ed25519/ref10/open.c
@@ -389,5 +395,380 @@ TEST(checktransaction_tests, non_canonical_ed25519_signature) {
MockCValidationState state;
EXPECT_CALL(state, DoS(100, 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.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 20;
// Check constructor with overwinter fields
CTransaction tx(mtx);
EXPECT_EQ(tx.nVersion, mtx.nVersion);
EXPECT_EQ(tx.fOverwintered, mtx.fOverwintered);
EXPECT_EQ(tx.nVersionGroupId, mtx.nVersionGroupId);
EXPECT_EQ(tx.nExpiryHeight, mtx.nExpiryHeight);
// Check constructor of mutable transaction struct
CMutableTransaction mtx2(tx);
EXPECT_EQ(mtx2.nVersion, mtx.nVersion);
EXPECT_EQ(mtx2.fOverwintered, mtx.fOverwintered);
EXPECT_EQ(mtx2.nVersionGroupId, mtx.nVersionGroupId);
EXPECT_EQ(mtx2.nExpiryHeight, mtx.nExpiryHeight);
EXPECT_TRUE(mtx2.GetHash() == mtx.GetHash());
// Check assignment of overwinter fields
CTransaction tx2 = tx;
EXPECT_EQ(tx2.nVersion, mtx.nVersion);
EXPECT_EQ(tx2.fOverwintered, mtx.fOverwintered);
EXPECT_EQ(tx2.nVersionGroupId, mtx.nVersionGroupId);
EXPECT_EQ(tx2.nExpiryHeight, mtx.nExpiryHeight);
EXPECT_TRUE(tx2 == tx);
}
TEST(checktransaction_tests, OverwinterSerialization) {
CMutableTransaction mtx;
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 99;
// Check round-trip serialization and deserialization from mtx to tx.
{
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
ss << mtx;
CTransaction tx;
ss >> tx;
EXPECT_EQ(mtx.nVersion, tx.nVersion);
EXPECT_EQ(mtx.fOverwintered, tx.fOverwintered);
EXPECT_EQ(mtx.nVersionGroupId, tx.nVersionGroupId);
EXPECT_EQ(mtx.nExpiryHeight, tx.nExpiryHeight);
EXPECT_EQ(mtx.GetHash(), CMutableTransaction(tx).GetHash());
EXPECT_EQ(tx.GetHash(), CTransaction(mtx).GetHash());
}
// Also check mtx to mtx
{
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
ss << mtx;
CMutableTransaction mtx2;
ss >> mtx2;
EXPECT_EQ(mtx.nVersion, mtx2.nVersion);
EXPECT_EQ(mtx.fOverwintered, mtx2.fOverwintered);
EXPECT_EQ(mtx.nVersionGroupId, mtx2.nVersionGroupId);
EXPECT_EQ(mtx.nExpiryHeight, mtx2.nExpiryHeight);
EXPECT_EQ(mtx.GetHash(), mtx2.GetHash());
}
// Also check tx to tx
{
CTransaction tx(mtx);
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
ss << tx;
CTransaction tx2;
ss >> tx2;
EXPECT_EQ(tx.nVersion, tx2.nVersion);
EXPECT_EQ(tx.fOverwintered, tx2.fOverwintered);
EXPECT_EQ(tx.nVersionGroupId, tx2.nVersionGroupId);
EXPECT_EQ(tx.nExpiryHeight, tx2.nExpiryHeight);
EXPECT_EQ(mtx.GetHash(), CMutableTransaction(tx).GetHash());
EXPECT_EQ(tx.GetHash(), tx2.GetHash());
}
}
TEST(checktransaction_tests, OverwinterDefaultValues) {
// Check default values (this will fail when defaults change; test should then be updated)
CTransaction tx;
EXPECT_EQ(tx.nVersion, 1);
EXPECT_EQ(tx.fOverwintered, false);
EXPECT_EQ(tx.nVersionGroupId, 0);
EXPECT_EQ(tx.nExpiryHeight, 0);
}
// A valid v3 transaction with no joinsplits
TEST(checktransaction_tests, OverwinterValidTx) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
}
TEST(checktransaction_tests, OverwinterExpiryHeight) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
{
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
}
{
mtx.nExpiryHeight = TX_EXPIRY_HEIGHT_THRESHOLD - 1;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
}
{
mtx.nExpiryHeight = TX_EXPIRY_HEIGHT_THRESHOLD;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-tx-expiry-height-too-high", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
{
mtx.nExpiryHeight = std::numeric_limits<uint32_t>::max();
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-tx-expiry-height-too-high", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
}
// Test that a Sprout tx with a negative version number is detected
// given the new Overwinter logic
TEST(checktransaction_tests, SproutTxVersionTooLow) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = false;
mtx.nVersion = -1;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-version-too-low", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
// Subclass of CTransaction which doesn't call UpdateHash when constructing
// from a CMutableTransaction. This enables us to create a CTransaction
// with bad values which normally trigger an exception during construction.
class UNSAFE_CTransaction : public CTransaction {
public:
UNSAFE_CTransaction(const CMutableTransaction &tx) : CTransaction(tx, true) {}
};
// Test bad Overwinter version number in CheckTransactionWithoutProofVerification
TEST(checktransaction_tests, OverwinterVersionNumberLow) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = OVERWINTER_MIN_TX_VERSION - 1;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
UNSAFE_CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-tx-overwinter-version-too-low", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
// Test bad Overwinter version number in ContextualCheckTransaction
TEST(checktransaction_tests, OverwinterVersionNumberHigh) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = OVERWINTER_MAX_TX_VERSION + 1;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
UNSAFE_CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-tx-overwinter-version-too-high", false)).Times(1);
ContextualCheckTransaction(tx, state, 1, 100);
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Test bad Overwinter version group id
TEST(checktransaction_tests, OverwinterBadVersionGroupId) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0);
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nExpiryHeight = 0;
mtx.nVersionGroupId = 0x12345678;
UNSAFE_CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-tx-version-group-id", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
// This tests an Overwinter transaction checked against Sprout
TEST(checktransaction_tests, OverwinterNotActive) {
SelectParams(CBaseChainParams::TESTNET);
CMutableTransaction mtx = GetValidTransaction();
mtx.fOverwintered = true;
mtx.nVersion = 3;
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);
ContextualCheckTransaction(tx, state, 1, 100);
}
// This tests a transaction without the fOverwintered flag set, against the Overwinter consensus rule set.
TEST(checktransaction_tests, OverwinterFlagNotSet) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
CMutableTransaction mtx = GetValidTransaction();
mtx.fOverwintered = false;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-flag-not-set", false)).Times(1);
ContextualCheckTransaction(tx, state, 1, 100);
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Overwinter (NU0) does not allow soft fork to version 4 Overwintered tx.
TEST(checktransaction_tests, OverwinterInvalidSoftForkVersion) {
CMutableTransaction mtx = GetValidTransaction();
mtx.fOverwintered = true;
mtx.nVersion = 4; // This is not allowed
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
try {
ss << mtx;
FAIL() << "Expected std::ios_base::failure 'Unknown transaction format'";
}
catch(std::ios_base::failure & err) {
EXPECT_THAT(err.what(), testing::HasSubstr(std::string("Unknown transaction format")));
}
catch(...) {
FAIL() << "Expected std::ios_base::failure 'Unknown transaction format', got some other exception";
}
}
// Test CreateNewContextualCMutableTransaction sets default values based on height
TEST(checktransaction_tests, OverwinteredContextualCreateTx) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& consensusParams = Params().GetConsensus();
int activationHeight = 5;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, activationHeight);
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(
consensusParams, activationHeight - 1);
EXPECT_EQ(mtx.nVersion, 1);
EXPECT_EQ(mtx.fOverwintered, false);
EXPECT_EQ(mtx.nVersionGroupId, 0);
EXPECT_EQ(mtx.nExpiryHeight, 0);
}
// Overwinter activates
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(
consensusParams, activationHeight );
EXPECT_EQ(mtx.nVersion, 3);
EXPECT_EQ(mtx.fOverwintered, true);
EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID);
EXPECT_EQ(mtx.nExpiryHeight, 0);
}
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Test a v1 transaction which has a malformed header, perhaps modified in-flight
TEST(checktransaction_tests, BadTxReceivedOverNetwork)
{
// First four bytes <01 00 00 00> have been modified to be <FC FF FF FF> (-4 as an int32)
std::string goodPrefix = "01000000";
std::string badPrefix = "fcffffff";
std::string hexTx = "0176c6541939b95f8d8b7779a77a0863b2a0267e281a050148326f0ea07c3608fb000000006a47304402207c68117a6263486281af0cc5d3bee6db565b6dce19ffacc4cb361906eece82f8022007f604382dee2c1fde41c4e6e7c1ae36cfa28b5b27350c4bfaa27f555529eace01210307ff9bef60f2ac4ceb1169a9f7d2c773d6c7f4ab6699e1e5ebc2e0c6d291c733feffffff02c0d45407000000001976a9145eaaf6718517ec8a291c6e64b16183292e7011f788ac5ef44534000000001976a91485e12fb9967c96759eae1c6b1e9c07ce977b638788acbe000000";
// Good v1 tx
{
std::vector<unsigned char> txData(ParseHex(goodPrefix + hexTx ));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx;
ssData >> tx;
EXPECT_EQ(tx.nVersion, 1);
EXPECT_EQ(tx.fOverwintered, false);
}
// Good v1 mutable tx
{
std::vector<unsigned char> txData(ParseHex(goodPrefix + hexTx ));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
CMutableTransaction mtx;
ssData >> mtx;
EXPECT_EQ(mtx.nVersion, 1);
}
// Bad tx
{
std::vector<unsigned char> txData(ParseHex(badPrefix + hexTx ));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
try {
CTransaction tx;
ssData >> tx;
FAIL() << "Expected std::ios_base::failure 'Unknown transaction format'";
}
catch(std::ios_base::failure & err) {
EXPECT_THAT(err.what(), testing::HasSubstr(std::string("Unknown transaction format")));
}
catch(...) {
FAIL() << "Expected std::ios_base::failure 'Unknown transaction format', got some other exception";
}
}
// Bad mutable tx
{
std::vector<unsigned char> txData(ParseHex(badPrefix + hexTx ));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
try {
CMutableTransaction mtx;
ssData >> mtx;
FAIL() << "Expected std::ios_base::failure 'Unknown transaction format'";
}
catch(std::ios_base::failure & err) {
EXPECT_THAT(err.what(), testing::HasSubstr(std::string("Unknown transaction format")));
}
catch(...) {
FAIL() << "Expected std::ios_base::failure 'Unknown transaction format', got some other exception";
}
}
}

View File

@@ -7,10 +7,11 @@
#include <boost/format.hpp>
#include <boost/optional.hpp>
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp"
#include "libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp"
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include <libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp>
#include <libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp>
#include "zcash/IncrementalMerkleTree.hpp"
using namespace libsnark;

View File

@@ -0,0 +1,122 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "clientversion.h"
#include "deprecation.h"
#include "init.h"
#include "ui_interface.h"
#include "util.h"
#include "chainparams.h"
using ::testing::StrictMock;
static const std::string CLIENT_VERSION_STR = FormatVersion(CLIENT_VERSION);
extern std::atomic<bool> fRequestShutdown;
class MockUIInterface {
public:
MOCK_METHOD3(ThreadSafeMessageBox, bool(const std::string& message,
const std::string& caption,
unsigned int style));
};
static bool ThreadSafeMessageBox(MockUIInterface *mock,
const std::string& message,
const std::string& caption,
unsigned int style)
{
return mock->ThreadSafeMessageBox(message, caption, style);
}
class DeprecationTest : public ::testing::Test {
protected:
virtual void SetUp() {
uiInterface.ThreadSafeMessageBox.disconnect_all_slots();
uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, &mock_, _1, _2, _3));
SelectParams(CBaseChainParams::MAIN);
}
virtual void TearDown() {
fRequestShutdown = false;
mapArgs.clear();
}
StrictMock<MockUIInterface> mock_;
};
TEST_F(DeprecationTest, NonDeprecatedNodeKeepsRunning) {
EXPECT_FALSE(ShutdownRequested());
EnforceNodeDeprecation(DEPRECATION_HEIGHT - DEPRECATION_WARN_LIMIT - 1);
EXPECT_FALSE(ShutdownRequested());
}
TEST_F(DeprecationTest, NodeNearDeprecationIsWarned) {
EXPECT_FALSE(ShutdownRequested());
EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_WARNING));
EnforceNodeDeprecation(DEPRECATION_HEIGHT - DEPRECATION_WARN_LIMIT);
EXPECT_FALSE(ShutdownRequested());
}
TEST_F(DeprecationTest, NodeNearDeprecationWarningIsNotDuplicated) {
EXPECT_FALSE(ShutdownRequested());
EnforceNodeDeprecation(DEPRECATION_HEIGHT - DEPRECATION_WARN_LIMIT + 1);
EXPECT_FALSE(ShutdownRequested());
}
TEST_F(DeprecationTest, NodeNearDeprecationWarningIsRepeatedOnStartup) {
EXPECT_FALSE(ShutdownRequested());
EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_WARNING));
EnforceNodeDeprecation(DEPRECATION_HEIGHT - DEPRECATION_WARN_LIMIT + 1, true);
EXPECT_FALSE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeShutsDown) {
EXPECT_FALSE(ShutdownRequested());
EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_ERROR));
EnforceNodeDeprecation(DEPRECATION_HEIGHT);
EXPECT_TRUE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeErrorIsNotDuplicated) {
EXPECT_FALSE(ShutdownRequested());
EnforceNodeDeprecation(DEPRECATION_HEIGHT + 1);
EXPECT_TRUE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeErrorIsRepeatedOnStartup) {
EXPECT_FALSE(ShutdownRequested());
EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_ERROR));
EnforceNodeDeprecation(DEPRECATION_HEIGHT + 1, true);
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());
EnforceNodeDeprecation(DEPRECATION_HEIGHT+1);
EXPECT_FALSE(ShutdownRequested());
}
TEST_F(DeprecationTest, DeprecatedNodeIgnoredOnTestnet) {
SelectParams(CBaseChainParams::TESTNET);
EXPECT_FALSE(ShutdownRequested());
EnforceNodeDeprecation(DEPRECATION_HEIGHT+1);
EXPECT_FALSE(ShutdownRequested());
}

View File

@@ -81,6 +81,8 @@ TEST(founders_reward_test, create_testnet_2of3multisig) {
std::cout << s << std::endl;
pWallet->Flush(true);
ECC_Stop();
}
#endif

View File

@@ -0,0 +1,62 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "httprpc.cpp"
#include "httpserver.h"
using ::testing::Return;
class MockHTTPRequest : public HTTPRequest {
public:
MOCK_METHOD0(GetPeer, CService());
MOCK_METHOD0(GetRequestMethod, HTTPRequest::RequestMethod());
MOCK_METHOD1(GetHeader, std::pair<bool, std::string>(const std::string& hdr));
MOCK_METHOD2(WriteHeader, void(const std::string& hdr, const std::string& value));
MOCK_METHOD2(WriteReply, void(int nStatus, const std::string& strReply));
MockHTTPRequest() : HTTPRequest(nullptr) {}
void CleanUp() {
// So the parent destructor doesn't try to send a reply
replySent = true;
}
};
TEST(HTTPRPC, FailsOnGET) {
MockHTTPRequest req;
EXPECT_CALL(req, GetRequestMethod())
.WillRepeatedly(Return(HTTPRequest::GET));
EXPECT_CALL(req, WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests"))
.Times(1);
EXPECT_FALSE(HTTPReq_JSONRPC(&req, ""));
req.CleanUp();
}
TEST(HTTPRPC, FailsWithoutAuthHeader) {
MockHTTPRequest req;
EXPECT_CALL(req, GetRequestMethod())
.WillRepeatedly(Return(HTTPRequest::POST));
EXPECT_CALL(req, GetHeader("authorization"))
.WillRepeatedly(Return(std::make_pair(false, "")));
EXPECT_CALL(req, WriteHeader("WWW-Authenticate", "Basic realm=\"jsonrpc\""))
.Times(1);
EXPECT_CALL(req, WriteReply(HTTP_UNAUTHORIZED, ""))
.Times(1);
EXPECT_FALSE(HTTPReq_JSONRPC(&req, ""));
req.CleanUp();
}
TEST(HTTPRPC, FailsWithBadAuth) {
MockHTTPRequest req;
EXPECT_CALL(req, GetRequestMethod())
.WillRepeatedly(Return(HTTPRequest::POST));
EXPECT_CALL(req, GetHeader("authorization"))
.WillRepeatedly(Return(std::make_pair(true, "Basic spam:eggs")));
EXPECT_CALL(req, GetPeer())
.WillRepeatedly(Return(CService("127.0.0.1:1337")));
EXPECT_CALL(req, WriteHeader("WWW-Authenticate", "Basic realm=\"jsonrpc\""))
.Times(1);
EXPECT_CALL(req, WriteReply(HTTP_UNAUTHORIZED, ""))
.Times(1);
EXPECT_FALSE(HTTPReq_JSONRPC(&req, ""));
req.CleanUp();
}

View File

@@ -5,6 +5,7 @@
#include <boost/foreach.hpp>
#include "zcash/prf.h"
#include "util.h"
#include "zcash/JoinSplit.hpp"
#include "zcash/Note.hpp"
@@ -13,6 +14,8 @@
using namespace libzcash;
extern ZCJoinSplit* params;
void test_full_api(ZCJoinSplit* js)
{
// Create verification context.
@@ -86,7 +89,7 @@ void test_full_api(ZCJoinSplit* js)
// Recipient should decrypt
// Now the recipient should spend the money again
auto h_sig = js->h_sig(randomSeed, nullifiers, pubKeyHash);
ZCNoteDecryption decryptor(recipient_key.viewing_key());
ZCNoteDecryption decryptor(recipient_key.receiving_key());
auto note_pt = NotePlaintext::decrypt(
decryptor,
@@ -219,8 +222,6 @@ void invokeAPIFailure(
TEST(joinsplit, h_sig)
{
auto js = ZCJoinSplit::Unopened();
/*
// by Taylor Hornby
@@ -284,7 +285,7 @@ for test_input in TEST_VECTORS:
};
BOOST_FOREACH(std::vector<std::string>& v, tests) {
auto expected = js->h_sig(
auto expected = ZCJoinSplit::h_sig(
uint256S(v[0]),
{uint256S(v[1]), uint256S(v[2])},
uint256S(v[3])
@@ -292,8 +293,6 @@ for test_input in TEST_VECTORS:
EXPECT_EQ(expected, uint256S(v[4]));
}
delete js;
}
void increment_note_witnesses(
@@ -311,8 +310,6 @@ void increment_note_witnesses(
TEST(joinsplit, full_api_test)
{
auto js = ZCJoinSplit::Generate();
{
std::vector<ZCIncrementalWitness> witnesses;
ZCIncrementalMerkleTree tree;
@@ -331,7 +328,7 @@ TEST(joinsplit, full_api_test)
increment_note_witnesses(note5.cm(), witnesses, tree);
// Should work
invokeAPI(js,
invokeAPI(params,
{
JSInput(),
JSInput()
@@ -345,7 +342,7 @@ TEST(joinsplit, full_api_test)
tree.root());
// lhs > MAX_MONEY
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@@ -360,7 +357,7 @@ TEST(joinsplit, full_api_test)
"nonsensical vpub_old value");
// rhs > MAX_MONEY
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@@ -375,7 +372,7 @@ TEST(joinsplit, full_api_test)
"nonsensical vpub_new value");
// input witness for the wrong element
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[0], note1, sk),
JSInput()
@@ -391,7 +388,7 @@ TEST(joinsplit, full_api_test)
// input witness doesn't match up with
// real root
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[1], note1, sk),
JSInput()
@@ -406,7 +403,7 @@ TEST(joinsplit, full_api_test)
"joinsplit not anchored to the correct root");
// input is in the tree now! this should work
invokeAPI(js,
invokeAPI(params,
{
JSInput(witnesses[1], note1, sk),
JSInput()
@@ -420,7 +417,7 @@ TEST(joinsplit, full_api_test)
tree.root());
// Wrong secret key
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[1], note1, SpendingKey::random()),
JSInput()
@@ -435,7 +432,7 @@ TEST(joinsplit, full_api_test)
"input note not authorized to spend with given key");
// Absurd input value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[3], note3, sk),
JSInput()
@@ -450,7 +447,7 @@ TEST(joinsplit, full_api_test)
"nonsensical input note value");
// Absurd total input value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[4], note4, sk),
JSInput(witnesses[5], note5, sk)
@@ -465,7 +462,7 @@ TEST(joinsplit, full_api_test)
"nonsensical left hand size of joinsplit balance");
// Absurd output value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@@ -480,7 +477,7 @@ TEST(joinsplit, full_api_test)
"nonsensical output value");
// Absurd total output value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@@ -495,7 +492,7 @@ TEST(joinsplit, full_api_test)
"nonsensical right hand side of joinsplit balance");
// Absurd total output value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@@ -510,22 +507,7 @@ TEST(joinsplit, full_api_test)
"invalid joinsplit balance");
}
test_full_api(js);
js->saveProvingKey("./zcashTest.pk");
js->saveVerifyingKey("./zcashTest.vk");
delete js;
js = ZCJoinSplit::Unopened();
js->setProvingKeyPath("./zcashTest.pk");
js->loadProvingKey();
js->loadVerifyingKey("./zcashTest.vk");
test_full_api(js);
delete js;
test_full_api(params);
}
TEST(joinsplit, note_plaintexts)

View File

@@ -43,7 +43,64 @@ TEST(keystore_tests, store_and_retrieve_note_decryptor) {
keyStore.AddSpendingKey(sk);
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut);
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
}
TEST(keystore_tests, StoreAndRetrieveViewingKey) {
CBasicKeyStore keyStore;
libzcash::ViewingKey vkOut;
libzcash::SpendingKey skOut;
ZCNoteDecryption decOut;
auto sk = libzcash::SpendingKey::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));
// 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.GetNoteDecryptor(addr, decOut));
// and we can't find it in our list of addresses
std::set<libzcash::PaymentAddress> addresses;
keyStore.GetPaymentAddresses(addresses);
EXPECT_FALSE(addresses.count(addr));
keyStore.AddViewingKey(vk);
EXPECT_TRUE(keyStore.HaveViewingKey(addr));
EXPECT_TRUE(keyStore.GetViewingKey(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));
// ... but we should have a decryptor
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
// ... and we should find it in our list of addresses
addresses.clear();
keyStore.GetPaymentAddresses(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));
addresses.clear();
keyStore.GetPaymentAddresses(addresses);
EXPECT_FALSE(addresses.count(addr));
// We still have a decryptor because those are cached in memory
// (and also we only remove viewing keys when adding a spending key)
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
}
#ifdef ENABLE_WALLET
@@ -72,13 +129,13 @@ TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) {
ASSERT_TRUE(keyStore.GetSpendingKey(addr, keyOut));
ASSERT_EQ(sk, keyOut);
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut);
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
ASSERT_TRUE(keyStore.EncryptKeys(vMasterKey));
ASSERT_TRUE(keyStore.HaveSpendingKey(addr));
ASSERT_FALSE(keyStore.GetSpendingKey(addr, keyOut));
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut);
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
// Unlocking with a random key should fail
uint256 r2 {GetRandHash()};
@@ -109,19 +166,19 @@ TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) {
ASSERT_TRUE(keyStore.GetSpendingKey(addr2, keyOut));
ASSERT_EQ(sk2, keyOut);
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
EXPECT_EQ(ZCNoteDecryption(sk2.viewing_key()), decOut);
EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut);
ASSERT_TRUE(keyStore.Lock());
ASSERT_TRUE(keyStore.HaveSpendingKey(addr2));
ASSERT_FALSE(keyStore.GetSpendingKey(addr2, keyOut));
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
EXPECT_EQ(ZCNoteDecryption(sk2.viewing_key()), decOut);
EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut);
ASSERT_TRUE(keyStore.Unlock(vMasterKey));
ASSERT_TRUE(keyStore.GetSpendingKey(addr2, keyOut));
ASSERT_EQ(sk2, keyOut);
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
EXPECT_EQ(ZCNoteDecryption(sk2.viewing_key()), decOut);
EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut);
keyStore.GetPaymentAddresses(addrs);
ASSERT_EQ(2, addrs.size());

View File

@@ -1,89 +1,263 @@
#include <gtest/gtest.h>
#include <gtest/gtest-spi.h>
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "main.h"
#include "primitives/transaction.h"
#include "txmempool.h"
#include "policy/fees.h"
#include "util.h"
// Implementation is in test_checktransaction.cpp
extern CMutableTransaction GetValidTransaction();
// Fake the input of transaction 5295156213414ed77f6e538e7e8ebe14492156906b9fe995b242477818789364
// - 532639cc6bebed47c1c69ae36dd498c68a012e74ad12729adbd3dbb56f8f3f4a, 0
class FakeCoinsViewDB : public CCoinsView {
public:
FakeCoinsViewDB() {}
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf) const {
return false;
}
bool GetCoins(const uint256 &txid, CCoins &coins) const {
CTxOut txOut;
txOut.nValue = 4288035;
CCoins newCoins;
newCoins.vout.resize(2);
newCoins.vout[0] = txOut;
newCoins.nHeight = 92045;
coins.swap(newCoins);
return true;
}
bool HaveCoins(const uint256 &txid) const {
return true;
}
uint256 GetBestBlock() const {
uint256 a;
return a;
}
uint256 GetBestAnchor() const {
uint256 a;
return a;
}
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) {
return false;
}
bool GetStats(CCoinsStats &stats) const {
return false;
}
};
TEST(Mempool, PriorityStatsDoNotCrash) {
// Test for security issue 2017-04-11.a
// https://z.cash/blog/security-announcement-2017-04-12.html
// Trigger transaction in block 92046
std::string triggerTx = "02000000014a3f8f6fb5dbd3db9a7212ad742e018ac698d46de39ac6c147edeb6bcc392653000000006b483045022100da0514afd80d3bbd0743458efe3b2abd18f727b4268b124c3885094c26ea09cd02207d37d7934ec90618fc5a345cb2a6d1755d8b1a432ea1df517a85e36628449196012103e9b41072e9d2cbe04e6b22a6ac4862ec3f5a76b3823b071ded0dfd5455a0803fffffffff000000000001236e4100000000000000000000000000cf592f6776810cf9fb961d80e683f5529a6b34894b00446c396022512a02dc2e96918294bffdc988a2627d9b12a9f3176b671e286fc62e3c7441cf35ea5e03d561bd5817ca5827cb2761f88dde280a6da5281af2cc69053816f31abd2170722f72c258c7c6b865c97ff8ae53b697f3b77c239a73e1d0296c2c73d21c3b50059d82866cf9f6e2f5dbbf9b4de9caa3cf836080373311978e1f1b1150ce564336ebf0fd502c2e783ff23252fba4efbb110c28c4fbe31efb6a67bc24c0ad8fd8346c5c9ed1791b555b3e43a309aa8d855a294847368ebdf30365d4dfa9b25dd8ed7adf272ecc08f4756fb9d93b8e20d45548dd4aeab6abb76a2081b6e36a9af9d38ebae378df422f40589769c07a3c12e5da253330314cbc4beaa863fac7ab10055d0310089a44c45179a39b2c4e210cec2e053f54983d744abed49f66959f45785ea90325a310fba15f946e245a0e64caec303f2a3e1d457e3e3ca5d892956c1a93b05e0b0373cf862d7bbb5908148b475c03eec96c9b9ecc7d2d78716d2c2e8ccf96175b25738dfb5b0d356a7e30604ee014c6be1db5e43af0fa6ad3f4e917a9f84b4d6f030cad0ffe0738e1effe570b0552b407ca9c26023b74b99f431cc28b79116f717703158404e343b1b47a0556f593441dc64758930f19e84d5ee468fd9a7958c6c63503054f60680f7147e88bf6da65415450230ef7437481023fc5d94872d5aa18bf3b0212b4c0d938e6c84debb8a4e65f99970c59193873a72b2440f19a652073abd960021bfef4e1e52b8f353c6e517bb97053afd4c8035defc27c3fd16faba5bc924a4179f69cfdcdb82253b5f6472a99d4b78ad2c6c18c45ed4dda5bf2adc019c99b55702f4e7b3fcaeb6f3b84ad411d36e901cba9d49ac1d6b916aa88794fb23501aeb0c585cbc2bed952846f41a03bd5c74dfe004e7ac21f7a20d32b009ccf6f70b3e577d25c679421225522b6290d5fa00a5d9a02b97a62aab60e040a03efa946d87c5e65dbf10d66df5b0834c262c31c23f3c2643451e614695003fb3a95bf21444bebb45cdcb8169245e34a76f754c89c3a90f36598a71ef4645eef4c82f1fb322536097fcf0cbe061e80ae887dbb88d8ed910be9ef18b8794930addab1a140b16c4b50f93926b1e5df03ee6e4b5ec6d7f0ed49fbbae50330ae94c5ae9182f4b58870022e423e7d80adccdb90680f7a7fe11a4ed4fe005a0af2d22bf9e7d1bef7caf4f37f5777e4aa6c9b9ea44f5973575c20fb3482fe357c19fc0c20594f492f5694e3e8eb3599e968fd23b5bdd6c4bf5aee1374b38aafe59dd5af83011e642a9427b5ff03e7a4cce92ee201a0fac0acb69d6ad3b7e4c26dfefaa53a737889e759c4b5695c1a7fd5d988e531acf66dae5067f252a25a102d92916b2d84c730645e15a78d3dce1c787634f6f7323cb949a5b6ad004e208cb8c6b734761629c13b9974dc80b082f83357f3bc703d835acbbf72aba225ffe69396c151d2646fac9bd1acc184dd047ebfaadc6b60a9185ce80c7bc8ac5dbb2219cbc0d35af91673b95d28335f0ee2774b8084871d54ca8eab3a285e4b4adf3f34b4263d67474bb5de2e1e37aa7a4ecbd5b49575caaa9e7208c2b9871946b11f2c54cd1ca7660dff44cf206e7da46ab57dd49ec0aa06ded7980f1557cc7c84023690b4df77f26d6b4eff7553b9a8628c28e8e5c38c6170bc61af0969b072586fa740f68ab33c0f62d0507cc8fe41c680b2f077e49cc2691048006311b46cd5ed18e63089f11c115b797ed5fbcd86836a4da2ab90a00745077f2f13bc9e390fc2f92b941d4fb70a3f098548953566141670317fc17e0ba81e98b8a94919992fb008c5480f4018f3a1ea673fe94a6ba3363656a944855d7c799ccb73d95d4ed6ce04c26f79c4cf79f883f0f810519f28eabe8cf6d833f24227f5074763c7b80f1431e5463cc07eff2f1d6cbfaf0411d38e62528a39b093ed7b51fa8c1008e5c1ce4bf39e67b1703554cefef44b71457bfddf43d23a54fa0145fa0e716d02a5304d85345a2b4ebf98c5010d0df468c8cbfc2db22083b0f5a74d4324ee74b46daa5ab70f2575ef5390e6aa2acb8d3b3eb2065e8c06fd6276aca283f5850e7a8b4da37455430df55621e4af59bb355ba2db0ac6cae6ceed2f538ec8c928ee895bd190fd9c1dff4956bad27d567023bc847dd64d83bac399f8d10248a077c9b2f50d5dda4789e09eae4ed8609da085b6370f6529f3c7b8b13442f9a1cc93565734a81c38c6360235ba23ddf87d1b44413c24b363552a322b01d88d1cae6c5ccd88f8cef15776035934fd24adce913282983d9b55181b382ed61242fb4a5e459c3cad8d38626ef8ccdccb9899d5962dec3f3cc2422f109d902e764186cf166ed88c383f428f195dd5fec4f781bcd2308dec66927f41c9e06369c6806ed8ec9a59c096b29b2a74dc85f4f7cd77a23650c0662b5c2602ef5e41cdc13d16074500aac461f823e3bba7178bcffa000db4ffc9b1618395824ffbee1cad1d9c138a20e0b8bbea2d9a07fade932f81c3daf2d64c4991daf4a1b8b531f9b958a252c6c38cd463342aef3e03e3dae3370581d6cddf5af3ef1585780cf83db1909a1daca156018cd2f7483e53a5fccda49640de60b24523617c7ae84ec5fa987ba8a108";
CTransaction tx;
ASSERT_TRUE(DecodeHexTx(tx, triggerTx));
ASSERT_EQ(tx.GetHash().GetHex(), "5295156213414ed77f6e538e7e8ebe14492156906b9fe995b242477818789364");
// Fake its inputs
FakeCoinsViewDB fakeDB;
CCoinsViewCache view(&fakeDB);
CTxMemPool testPool(CFeeRate(0));
// Values taken from core dump (parameters of entry)
CAmount nFees = 0;
int64_t nTime = 0x58e5fed9;
unsigned int nHeight = 92045;
double dPriority = view.GetPriority(tx, nHeight);
CTxMemPoolEntry entry(tx, nFees, nTime, dPriority, nHeight, true, false, SPROUT_BRANCH_ID);
// Check it does not crash (ie. the death test fails)
EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(testPool.addUnchecked(tx.GetHash(), entry), ""), "");
// Fake the input of transaction 5295156213414ed77f6e538e7e8ebe14492156906b9fe995b242477818789364
// - 532639cc6bebed47c1c69ae36dd498c68a012e74ad12729adbd3dbb56f8f3f4a, 0
class FakeCoinsViewDB : public CCoinsView {
public:
FakeCoinsViewDB() {}
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf) const {
return false;
}
bool GetCoins(const uint256 &txid, CCoins &coins) const {
CTxOut txOut;
txOut.nValue = 4288035;
CCoins newCoins;
newCoins.vout.resize(2);
newCoins.vout[0] = txOut;
newCoins.nHeight = 92045;
coins.swap(newCoins);
return true;
}
bool HaveCoins(const uint256 &txid) const {
return true;
}
uint256 GetBestBlock() const {
uint256 a;
return a;
}
uint256 GetBestAnchor() const {
uint256 a;
return a;
}
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) {
return false;
}
bool GetStats(CCoinsStats &stats) const {
return false;
}
};
TEST(Mempool, PriorityStatsDoNotCrash) {
// Test for security issue 2017-04-11.a
// https://z.cash/blog/security-announcement-2017-04-12.html
// Trigger transaction in block 92046
std::string triggerTx = "02000000014a3f8f6fb5dbd3db9a7212ad742e018ac698d46de39ac6c147edeb6bcc392653000000006b483045022100da0514afd80d3bbd0743458efe3b2abd18f727b4268b124c3885094c26ea09cd02207d37d7934ec90618fc5a345cb2a6d1755d8b1a432ea1df517a85e36628449196012103e9b41072e9d2cbe04e6b22a6ac4862ec3f5a76b3823b071ded0dfd5455a0803fffffffff000000000001236e4100000000000000000000000000cf592f6776810cf9fb961d80e683f5529a6b34894b00446c396022512a02dc2e96918294bffdc988a2627d9b12a9f3176b671e286fc62e3c7441cf35ea5e03d561bd5817ca5827cb2761f88dde280a6da5281af2cc69053816f31abd2170722f72c258c7c6b865c97ff8ae53b697f3b77c239a73e1d0296c2c73d21c3b50059d82866cf9f6e2f5dbbf9b4de9caa3cf836080373311978e1f1b1150ce564336ebf0fd502c2e783ff23252fba4efbb110c28c4fbe31efb6a67bc24c0ad8fd8346c5c9ed1791b555b3e43a309aa8d855a294847368ebdf30365d4dfa9b25dd8ed7adf272ecc08f4756fb9d93b8e20d45548dd4aeab6abb76a2081b6e36a9af9d38ebae378df422f40589769c07a3c12e5da253330314cbc4beaa863fac7ab10055d0310089a44c45179a39b2c4e210cec2e053f54983d744abed49f66959f45785ea90325a310fba15f946e245a0e64caec303f2a3e1d457e3e3ca5d892956c1a93b05e0b0373cf862d7bbb5908148b475c03eec96c9b9ecc7d2d78716d2c2e8ccf96175b25738dfb5b0d356a7e30604ee014c6be1db5e43af0fa6ad3f4e917a9f84b4d6f030cad0ffe0738e1effe570b0552b407ca9c26023b74b99f431cc28b79116f717703158404e343b1b47a0556f593441dc64758930f19e84d5ee468fd9a7958c6c63503054f60680f7147e88bf6da65415450230ef7437481023fc5d94872d5aa18bf3b0212b4c0d938e6c84debb8a4e65f99970c59193873a72b2440f19a652073abd960021bfef4e1e52b8f353c6e517bb97053afd4c8035defc27c3fd16faba5bc924a4179f69cfdcdb82253b5f6472a99d4b78ad2c6c18c45ed4dda5bf2adc019c99b55702f4e7b3fcaeb6f3b84ad411d36e901cba9d49ac1d6b916aa88794fb23501aeb0c585cbc2bed952846f41a03bd5c74dfe004e7ac21f7a20d32b009ccf6f70b3e577d25c679421225522b6290d5fa00a5d9a02b97a62aab60e040a03efa946d87c5e65dbf10d66df5b0834c262c31c23f3c2643451e614695003fb3a95bf21444bebb45cdcb8169245e34a76f754c89c3a90f36598a71ef4645eef4c82f1fb322536097fcf0cbe061e80ae887dbb88d8ed910be9ef18b8794930addab1a140b16c4b50f93926b1e5df03ee6e4b5ec6d7f0ed49fbbae50330ae94c5ae9182f4b58870022e423e7d80adccdb90680f7a7fe11a4ed4fe005a0af2d22bf9e7d1bef7caf4f37f5777e4aa6c9b9ea44f5973575c20fb3482fe357c19fc0c20594f492f5694e3e8eb3599e968fd23b5bdd6c4bf5aee1374b38aafe59dd5af83011e642a9427b5ff03e7a4cce92ee201a0fac0acb69d6ad3b7e4c26dfefaa53a737889e759c4b5695c1a7fd5d988e531acf66dae5067f252a25a102d92916b2d84c730645e15a78d3dce1c787634f6f7323cb949a5b6ad004e208cb8c6b734761629c13b9974dc80b082f83357f3bc703d835acbbf72aba225ffe69396c151d2646fac9bd1acc184dd047ebfaadc6b60a9185ce80c7bc8ac5dbb2219cbc0d35af91673b95d28335f0ee2774b8084871d54ca8eab3a285e4b4adf3f34b4263d67474bb5de2e1e37aa7a4ecbd5b49575caaa9e7208c2b9871946b11f2c54cd1ca7660dff44cf206e7da46ab57dd49ec0aa06ded7980f1557cc7c84023690b4df77f26d6b4eff7553b9a8628c28e8e5c38c6170bc61af0969b072586fa740f68ab33c0f62d0507cc8fe41c680b2f077e49cc2691048006311b46cd5ed18e63089f11c115b797ed5fbcd86836a4da2ab90a00745077f2f13bc9e390fc2f92b941d4fb70a3f098548953566141670317fc17e0ba81e98b8a94919992fb008c5480f4018f3a1ea673fe94a6ba3363656a944855d7c799ccb73d95d4ed6ce04c26f79c4cf79f883f0f810519f28eabe8cf6d833f24227f5074763c7b80f1431e5463cc07eff2f1d6cbfaf0411d38e62528a39b093ed7b51fa8c1008e5c1ce4bf39e67b1703554cefef44b71457bfddf43d23a54fa0145fa0e716d02a5304d85345a2b4ebf98c5010d0df468c8cbfc2db22083b0f5a74d4324ee74b46daa5ab70f2575ef5390e6aa2acb8d3b3eb2065e8c06fd6276aca283f5850e7a8b4da37455430df55621e4af59bb355ba2db0ac6cae6ceed2f538ec8c928ee895bd190fd9c1dff4956bad27d567023bc847dd64d83bac399f8d10248a077c9b2f50d5dda4789e09eae4ed8609da085b6370f6529f3c7b8b13442f9a1cc93565734a81c38c6360235ba23ddf87d1b44413c24b363552a322b01d88d1cae6c5ccd88f8cef15776035934fd24adce913282983d9b55181b382ed61242fb4a5e459c3cad8d38626ef8ccdccb9899d5962dec3f3cc2422f109d902e764186cf166ed88c383f428f195dd5fec4f781bcd2308dec66927f41c9e06369c6806ed8ec9a59c096b29b2a74dc85f4f7cd77a23650c0662b5c2602ef5e41cdc13d16074500aac461f823e3bba7178bcffa000db4ffc9b1618395824ffbee1cad1d9c138a20e0b8bbea2d9a07fade932f81c3daf2d64c4991daf4a1b8b531f9b958a252c6c38cd463342aef3e03e3dae3370581d6cddf5af3ef1585780cf83db1909a1daca156018cd2f7483e53a5fccda49640de60b24523617c7ae84ec5fa987ba8a108";
CTransaction tx;
ASSERT_TRUE(DecodeHexTx(tx, triggerTx));
ASSERT_EQ(tx.GetHash().GetHex(), "5295156213414ed77f6e538e7e8ebe14492156906b9fe995b242477818789364");
// Fake its inputs
FakeCoinsViewDB fakeDB;
CCoinsViewCache view(&fakeDB);
CTxMemPool testPool(CFeeRate(0));
// Values taken from core dump (parameters of entry)
CAmount nFees = 0;
int64_t nTime = 0x58e5fed9;
unsigned int nHeight = 92045;
double dPriority = view.GetPriority(tx, nHeight);
CTxMemPoolEntry entry(tx, nFees, nTime, dPriority, nHeight, true);
// Check it does not crash (ie. the death test fails)
EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(testPool.addUnchecked(tx.GetHash(), entry), ""), "");
EXPECT_EQ(dPriority, MAX_PRIORITY);
}
TEST(Mempool, TxInputLimit) {
SelectParams(CBaseChainParams::TESTNET);
CTxMemPool pool(::minRelayTxFee);
bool missingInputs;
// Create an obviously-invalid transaction
// We intentionally set tx.nVersion = 0 to reliably trigger an error, as
// it's the first check that occurs after the -mempooltxinputlimit check,
// and it means that we don't have to mock out a lot of global state.
CMutableTransaction mtx;
mtx.nVersion = 0;
mtx.vin.resize(10);
// Check it fails as expected
CValidationState state1;
CTransaction tx1(mtx);
EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs));
EXPECT_EQ(state1.GetRejectReason(), "bad-txns-version-too-low");
// Set a limit
mapArgs["-mempooltxinputlimit"] = "10";
// Check it still fails as expected
CValidationState state2;
EXPECT_FALSE(AcceptToMemoryPool(pool, state2, tx1, false, &missingInputs));
EXPECT_EQ(state2.GetRejectReason(), "bad-txns-version-too-low");
// Resize the transaction
mtx.vin.resize(11);
// Check it now fails due to exceeding the limit
CValidationState state3;
CTransaction tx3(mtx);
EXPECT_FALSE(AcceptToMemoryPool(pool, state3, tx3, false, &missingInputs));
// The -mempooltxinputlimit check doesn't set a reason
EXPECT_EQ(state3.GetRejectReason(), "");
// Clear the limit
mapArgs.erase("-mempooltxinputlimit");
// 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");
}
// Valid overwinter v3 format tx gets rejected because overwinter hasn't activated yet.
TEST(Mempool, OverwinterNotActiveYet) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
CTxMemPool pool(::minRelayTxFee);
bool missingInputs;
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0); // no joinsplits
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
mtx.nExpiryHeight = 0;
CValidationState state1;
CTransaction tx1(mtx);
EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs));
EXPECT_EQ(state1.GetRejectReason(), "tx-overwinter-not-active");
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Sprout transaction version 3 when Overwinter is not active:
// 1. pass CheckTransaction (and CheckTransactionWithoutProofVerification)
// 2. pass ContextualCheckTransaction
// 3. fail IsStandardTx
TEST(Mempool, SproutV3TxFailsAsExpected) {
SelectParams(CBaseChainParams::TESTNET);
CTxMemPool pool(::minRelayTxFee);
bool missingInputs;
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0); // no joinsplits
mtx.fOverwintered = false;
mtx.nVersion = 3;
CValidationState state1;
CTransaction tx1(mtx);
EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs));
EXPECT_EQ(state1.GetRejectReason(), "version");
}
// Sprout transaction version 3 when Overwinter is always active:
// 1. pass CheckTransaction (and CheckTransactionWithoutProofVerification)
// 2. fails ContextualCheckTransaction
TEST(Mempool, SproutV3TxWhenOverwinterActive) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
CTxMemPool pool(::minRelayTxFee);
bool missingInputs;
CMutableTransaction mtx = GetValidTransaction();
mtx.vjoinsplit.resize(0); // no joinsplits
mtx.fOverwintered = false;
mtx.nVersion = 3;
CValidationState state1;
CTransaction tx1(mtx);
EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs));
EXPECT_EQ(state1.GetRejectReason(), "tx-overwinter-flag-not-set");
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Sprout transaction with negative version, rejected by the mempool in CheckTransaction
// under Sprout consensus rules, should still be rejected under Overwinter consensus rules.
// 1. fails CheckTransaction (specifically CheckTransactionWithoutProofVerification)
TEST(Mempool, SproutNegativeVersionTxWhenOverwinterActive) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
CTxMemPool pool(::minRelayTxFee);
bool missingInputs;
CMutableTransaction mtx = GetValidTransaction();
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).
// 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
// to not setting fOverwintered and not masking off the most significant bit of the header field.
// The resulting Sprout tx with nVersion -3 should be rejected by the Overwinter node's mempool.
{
mtx.nVersion = -3;
EXPECT_EQ(mtx.nVersion, static_cast<int32_t>(0xfffffffd));
CTransaction tx1(mtx);
EXPECT_EQ(tx1.nVersion, -3);
CValidationState state1;
EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs));
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).
// 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.
{
mtx.nVersion = static_cast<int32_t>((1 << 31) | 3);
EXPECT_EQ(mtx.nVersion, static_cast<int32_t>(0x80000003));
CTransaction tx1(mtx);
EXPECT_EQ(tx1.nVersion, -2147483645);
CValidationState state1;
EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs));
EXPECT_EQ(state1.GetRejectReason(), "bad-txns-version-too-low");
}
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}

View File

@@ -19,10 +19,10 @@
#include "zcash/IncrementalMerkleTree.hpp"
#include "zcash/util.h"
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp"
#include "libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp"
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include <libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp>
#include <libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp>
#include <boost/foreach.hpp>

View File

@@ -92,3 +92,44 @@ TEST(Metrics, GetLocalSolPS) {
SetMockTime(104);
EXPECT_EQ(1, GetLocalSolPS());
}
TEST(Metrics, EstimateNetHeightInner) {
// Ensure that the (rounded) current height is returned if the tip is current
SetMockTime(15000);
EXPECT_EQ(100, EstimateNetHeightInner(100, 14100, 50, 7500, 0, 150));
SetMockTime(15150);
EXPECT_EQ(100, EstimateNetHeightInner(101, 14250, 50, 7500, 0, 150));
// Ensure that correct estimates are returned if the tip is in the past
SetMockTime(15300); // Tip is 2 blocks behind
EXPECT_EQ(100, EstimateNetHeightInner(100, 14100, 50, 7500, 0, 150));
SetMockTime(15900); // Tip is 6 blocks behind
EXPECT_EQ(110, EstimateNetHeightInner(100, 14100, 50, 7500, 0, 150));
// Check estimates during resync
SetMockTime(15000);
EXPECT_EQ(100, EstimateNetHeightInner( 0, 0, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner( 7, 600, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner( 8, 600, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(10, 750, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(11, 900, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(20, 2100, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(49, 6450, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(50, 6600, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(51, 6750, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(55, 7350, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(56, 7500, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(57, 7650, 50, 7500, 0, 150));
EXPECT_EQ(100, EstimateNetHeightInner(75, 10350, 50, 7500, 0, 150));
// More complex calculations:
SetMockTime(20000);
// - Checkpoint spacing: 200
// -> Average spacing: 175
// -> estimated height: 127 -> 130
EXPECT_EQ(130, EstimateNetHeightInner(100, 14100, 50, 5250, 0, 150));
// - Checkpoint spacing: 50
// -> Average spacing: 100
// -> estimated height: 153 -> 150
EXPECT_EQ(150, EstimateNetHeightInner(100, 14100, 50, 12000, 0, 150));
}

View File

@@ -0,0 +1,212 @@
#include <gtest/gtest.h>
#include "main.h"
#include "utilmoneystr.h"
#include "chainparams.h"
#include "utilstrencodings.h"
#include "zcash/Address.hpp"
#include "wallet/wallet.h"
#include "amount.h"
#include <memory>
#include <string>
#include <set>
#include <vector>
#include <boost/filesystem.hpp>
#include <iostream>
#include "util.h"
#include "paymentdisclosure.h"
#include "paymentdisclosuredb.h"
#include "sodium.h"
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
using namespace std;
/*
To run tests:
./zcash-gtest --gtest_filter="paymentdisclosure.*"
Note: As an experimental feature, writing your own tests may require option flags to be set.
mapArgs["-experimentalfeatures"] = true;
mapArgs["-paymentdisclosure"] = true;
*/
#define NUM_TRIES 10000
#define DUMP_DATABASE_TO_STDOUT false
static boost::uuids::random_generator uuidgen;
static uint256 random_uint256()
{
uint256 ret;
randombytes_buf(ret.begin(), 32);
return ret;
}
// Subclass of PaymentDisclosureDB to add debugging methods
class PaymentDisclosureDBTest : public PaymentDisclosureDB {
public:
PaymentDisclosureDBTest(const boost::filesystem::path& dbPath) : PaymentDisclosureDB(dbPath) {}
void DebugDumpAllStdout() {
ASSERT_NE(db, nullptr);
std::lock_guard<std::mutex> guard(lock_);
// Iterate over each item in the database and print them
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
cout << it->key().ToString() << " : ";
// << it->value().ToString() << endl;
try {
std::string strValue = it->value().ToString();
PaymentDisclosureInfo info;
CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
ssValue >> info;
cout << info.ToString() << std::endl;
} catch (const std::exception& e) {
cout << e.what() << std::endl;
}
}
if (false == it->status().ok()) {
cerr << "An error was found iterating over the database" << endl;
cerr << it->status().ToString() << endl;
}
delete it;
}
};
// This test creates random payment disclosure blobs and checks that they can be
// 1. inserted and retrieved from a database
// 2. serialized and deserialized without corruption
// 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;
PaymentDisclosureDBTest mydb(pathTemp);
for (int i=0; i<NUM_TRIES; i++) {
// Generate an ephemeral keypair for joinsplit sig.
uint256 joinSplitPubKey;
unsigned char buffer[crypto_sign_SECRETKEYBYTES] = {0};
crypto_sign_keypair(joinSplitPubKey.begin(), &buffer[0]);
// First 32 bytes contain private key, second 32 bytes contain public key.
ASSERT_EQ(0, memcmp(joinSplitPubKey.begin(), &buffer[0]+32, 32));
std::vector<unsigned char> vch(&buffer[0], &buffer[0] + 32);
uint256 joinSplitPrivKey = uint256(vch);
// Create payment disclosure key and info data to store in test database
size_t js = random_uint256().GetCheapHash() % std::numeric_limits<size_t>::max();
uint8_t n = random_uint256().GetCheapHash() % std::numeric_limits<uint8_t>::max();
PaymentDisclosureKey key { random_uint256(), js, n};
PaymentDisclosureInfo info;
info.esk = random_uint256();
info.joinSplitPrivKey = joinSplitPrivKey;
info.zaddr = libzcash::SpendingKey::random().address();
ASSERT_TRUE(mydb.Put(key, info));
// Retrieve info from test database into new local variable and test it matches
PaymentDisclosureInfo info2;
ASSERT_TRUE(mydb.Get(key, info2));
ASSERT_EQ(info, info2);
// Modify this local variable and confirm it no longer matches
info2.esk = random_uint256();
info2.joinSplitPrivKey = random_uint256();
info2.zaddr = libzcash::SpendingKey::random().address();
ASSERT_NE(info, info2);
// Using the payment info object, let's create a dummy payload
PaymentDisclosurePayload payload;
payload.version = PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL;
payload.esk = info.esk;
payload.txid = key.hash;
payload.js = key.js;
payload.n = key.n;
payload.message = "random-" + boost::uuids::to_string(uuidgen()); // random message
payload.zaddr = info.zaddr;
// Serialize and hash the payload to generate a signature
uint256 dataToBeSigned = SerializeHash(payload, SER_GETHASH, 0);
// Compute the payload signature
unsigned char payloadSig[64];
if (!(crypto_sign_detached(&payloadSig[0], NULL,
dataToBeSigned.begin(), 32,
&buffer[0] // buffer containing both private and public key required
) == 0))
{
throw std::runtime_error("crypto_sign_detached failed");
}
// Sanity check
if (!(crypto_sign_verify_detached(&payloadSig[0],
dataToBeSigned.begin(), 32,
joinSplitPubKey.begin()
) == 0))
{
throw std::runtime_error("crypto_sign_verify_detached failed");
}
// Convert signature buffer to boost array
boost::array<unsigned char, 64> arrayPayloadSig;
memcpy(arrayPayloadSig.data(), &payloadSig[0], 64);
// Payment disclosure blob to pass around
PaymentDisclosure pd = {payload, arrayPayloadSig};
// Test payment disclosure constructors
PaymentDisclosure pd2(payload, arrayPayloadSig);
ASSERT_EQ(pd, pd2);
PaymentDisclosure pd3(joinSplitPubKey, key, info, payload.message);
ASSERT_EQ(pd, pd3);
// Verify serialization and deserialization works
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << pd;
std::string ssHexString = HexStr(ss.begin(), ss.end());
PaymentDisclosure pdTmp;
CDataStream ssTmp(ParseHex(ssHexString), SER_NETWORK, PROTOCOL_VERSION);
ssTmp >> pdTmp;
ASSERT_EQ(pd, pdTmp);
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
ss2 << pdTmp;
std::string ss2HexString = HexStr(ss2.begin(), ss2.end());
ASSERT_EQ(ssHexString, ss2HexString);
// Verify marker
ASSERT_EQ(pd.payload.marker, PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES);
ASSERT_EQ(pdTmp.payload.marker, PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES);
ASSERT_EQ(0, ssHexString.find("706462ff")); // Little endian encoding of PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES value
// Sanity check
PaymentDisclosure pdDummy;
ASSERT_NE(pd, pdDummy);
}
#if DUMP_DATABASE_TO_STDOUT == true
mydb.DebugDumpAllStdout();
#endif
ECC_Stop();
}

View File

@@ -3,10 +3,9 @@
#include <iostream>
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp"
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
using namespace libzcash;
@@ -22,6 +21,51 @@ typedef libsnark::default_r1cs_ppzksnark_pp::Fqe_type curve_Fq2;
#include "version.h"
#include "utilstrencodings.h"
TEST(proofs, g1_pairing_at_infinity)
{
for (size_t i = 0; i < 100; i++) {
auto r1 = curve_G1::random_element();
auto r2 = curve_G2::random_element();
ASSERT_TRUE(
curve_pp::reduced_pairing(curve_G1::zero(), r2) ==
curve_GT::one()
);
ASSERT_TRUE(
curve_pp::final_exponentiation(
curve_pp::double_miller_loop(
curve_pp::precompute_G1(curve_G1::zero()),
curve_pp::precompute_G2(r2),
curve_pp::precompute_G1(curve_G1::zero()),
curve_pp::precompute_G2(r2)
)
) ==
curve_GT::one()
);
ASSERT_TRUE(
curve_pp::final_exponentiation(
curve_pp::double_miller_loop(
curve_pp::precompute_G1(r1),
curve_pp::precompute_G2(r2),
curve_pp::precompute_G1(curve_G1::zero()),
curve_pp::precompute_G2(r2)
)
) ==
curve_pp::reduced_pairing(r1, r2)
);
ASSERT_TRUE(
curve_pp::final_exponentiation(
curve_pp::double_miller_loop(
curve_pp::precompute_G1(curve_G1::zero()),
curve_pp::precompute_G2(r2),
curve_pp::precompute_G1(r1),
curve_pp::precompute_G2(r2)
)
) ==
curve_pp::reduced_pairing(r1, r2)
);
}
}
TEST(proofs, g2_subgroup_check)
{
// all G2 elements are order r

View File

@@ -77,7 +77,7 @@ TEST(Transaction, JSDescriptionRandomized) {
*params, pubKeyHash, rt,
inputs, outputs,
inputMap, outputMap,
0, 0, false, GenZero);
0, 0, false, nullptr, GenZero);
#ifdef __LP64__ // required for building on MacOS
boost::array<uint64_t, ZC_NUM_JS_INPUTS> expectedInputMap {1, 0};
@@ -95,7 +95,7 @@ TEST(Transaction, JSDescriptionRandomized) {
*params, pubKeyHash, rt,
inputs, outputs,
inputMap, outputMap,
0, 0, false, GenMax);
0, 0, false, nullptr, GenMax);
#ifdef __LP64__ // required for building on MacOS
boost::array<uint64_t, ZC_NUM_JS_INPUTS> expectedInputMap {0, 1};

173
src/gtest/test_upgrades.cpp Normal file
View File

@@ -0,0 +1,173 @@
#include <gtest/gtest.h>
#include "chainparams.h"
#include "consensus/upgrades.h"
#include <boost/optional.hpp>
class UpgradesTest : public ::testing::Test {
protected:
virtual void SetUp() {
}
virtual void TearDown() {
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
};
TEST_F(UpgradesTest, NetworkUpgradeState) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& params = Params().GetConsensus();
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
EXPECT_EQ(
NetworkUpgradeState(0, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_DISABLED);
EXPECT_EQ(
NetworkUpgradeState(1000000, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_DISABLED);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
EXPECT_EQ(
NetworkUpgradeState(0, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_ACTIVE);
EXPECT_EQ(
NetworkUpgradeState(1000000, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_ACTIVE);
int nActivationHeight = 100;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight);
EXPECT_EQ(
NetworkUpgradeState(0, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_PENDING);
EXPECT_EQ(
NetworkUpgradeState(nActivationHeight - 1, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_PENDING);
EXPECT_EQ(
NetworkUpgradeState(nActivationHeight, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_ACTIVE);
EXPECT_EQ(
NetworkUpgradeState(1000000, params, Consensus::UPGRADE_TESTDUMMY),
UPGRADE_ACTIVE);
}
TEST_F(UpgradesTest, CurrentEpoch) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& params = Params().GetConsensus();
auto nBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_TESTDUMMY].nBranchId;
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
EXPECT_EQ(CurrentEpoch(0, params), Consensus::BASE_SPROUT);
EXPECT_EQ(CurrentEpochBranchId(0, params), 0);
EXPECT_EQ(CurrentEpoch(1000000, params), Consensus::BASE_SPROUT);
EXPECT_EQ(CurrentEpochBranchId(1000000, params), 0);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
EXPECT_EQ(CurrentEpoch(0, params), Consensus::UPGRADE_TESTDUMMY);
EXPECT_EQ(CurrentEpochBranchId(0, params), nBranchId);
EXPECT_EQ(CurrentEpoch(1000000, params), Consensus::UPGRADE_TESTDUMMY);
EXPECT_EQ(CurrentEpochBranchId(1000000, params), nBranchId);
int nActivationHeight = 100;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight);
EXPECT_EQ(CurrentEpoch(0, params), Consensus::BASE_SPROUT);
EXPECT_EQ(CurrentEpochBranchId(0, params), 0);
EXPECT_EQ(CurrentEpoch(nActivationHeight - 1, params), Consensus::BASE_SPROUT);
EXPECT_EQ(CurrentEpochBranchId(nActivationHeight - 1, params), 0);
EXPECT_EQ(CurrentEpoch(nActivationHeight, params), Consensus::UPGRADE_TESTDUMMY);
EXPECT_EQ(CurrentEpochBranchId(nActivationHeight, params), nBranchId);
EXPECT_EQ(CurrentEpoch(1000000, params), Consensus::UPGRADE_TESTDUMMY);
EXPECT_EQ(CurrentEpochBranchId(1000000, params), nBranchId);
}
TEST_F(UpgradesTest, IsActivationHeight) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& params = Params().GetConsensus();
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
EXPECT_FALSE(IsActivationHeight(-1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(0, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(1000000, params, Consensus::UPGRADE_TESTDUMMY));
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
EXPECT_FALSE(IsActivationHeight(-1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_TRUE(IsActivationHeight(0, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(1000000, params, Consensus::UPGRADE_TESTDUMMY));
int nActivationHeight = 100;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight);
EXPECT_FALSE(IsActivationHeight(-1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(0, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(nActivationHeight - 1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_TRUE(IsActivationHeight(nActivationHeight, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(nActivationHeight + 1, params, Consensus::UPGRADE_TESTDUMMY));
EXPECT_FALSE(IsActivationHeight(1000000, params, Consensus::UPGRADE_TESTDUMMY));
}
TEST_F(UpgradesTest, IsActivationHeightForAnyUpgrade) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& params = Params().GetConsensus();
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(-1, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(0, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params));
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(-1, params));
EXPECT_TRUE(IsActivationHeightForAnyUpgrade(0, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params));
int nActivationHeight = 100;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight);
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(-1, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(0, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(nActivationHeight - 1, params));
EXPECT_TRUE(IsActivationHeightForAnyUpgrade(nActivationHeight, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(nActivationHeight + 1, params));
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params));
}
TEST_F(UpgradesTest, NextActivationHeight) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& params = Params().GetConsensus();
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
EXPECT_EQ(NextActivationHeight(-1, params), boost::none);
EXPECT_EQ(NextActivationHeight(0, params), boost::none);
EXPECT_EQ(NextActivationHeight(1, params), boost::none);
EXPECT_EQ(NextActivationHeight(1000000, params), boost::none);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
EXPECT_EQ(NextActivationHeight(-1, params), boost::none);
EXPECT_EQ(NextActivationHeight(0, params), boost::none);
EXPECT_EQ(NextActivationHeight(1, params), boost::none);
EXPECT_EQ(NextActivationHeight(1000000, params), boost::none);
int nActivationHeight = 100;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight);
EXPECT_EQ(NextActivationHeight(-1, params), boost::none);
EXPECT_EQ(NextActivationHeight(0, params), nActivationHeight);
EXPECT_EQ(NextActivationHeight(1, params), nActivationHeight);
EXPECT_EQ(NextActivationHeight(nActivationHeight - 1, params), nActivationHeight);
EXPECT_EQ(NextActivationHeight(nActivationHeight, params), boost::none);
EXPECT_EQ(NextActivationHeight(nActivationHeight + 1, params), boost::none);
EXPECT_EQ(NextActivationHeight(1000000, params), boost::none);
}

View File

@@ -0,0 +1,152 @@
#include <gtest/gtest.h>
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#include "main.h"
#include "utiltest.h"
extern ZCJoinSplit* params;
extern bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos);
void ExpectOptionalAmount(CAmount expected, boost::optional<CAmount> actual) {
EXPECT_TRUE((bool)actual);
if (actual) {
EXPECT_EQ(expected, *actual);
}
}
// Fake an empty view
class FakeCoinsViewDB : public CCoinsView {
public:
FakeCoinsViewDB() {}
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf) const {
return false;
}
bool GetCoins(const uint256 &txid, CCoins &coins) const {
return false;
}
bool HaveCoins(const uint256 &txid) const {
return false;
}
uint256 GetBestBlock() const {
uint256 a;
return a;
}
uint256 GetBestAnchor() const {
uint256 a;
return a;
}
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) {
return false;
}
bool GetStats(CCoinsStats &stats) const {
return false;
}
};
TEST(Validation, ContextualCheckInputsPassesWithCoinbase) {
// Create fake coinbase transaction
CMutableTransaction mtx;
mtx.vin.resize(1);
CTransaction tx(mtx);
ASSERT_TRUE(tx.IsCoinBase());
// Fake an empty view
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));
}
TEST(Validation, ReceivedBlockTransactions) {
auto sk = libzcash::SpendingKey::random();
// Create a fake genesis block
CBlock block1;
block1.vtx.push_back(GetValidReceive(*params, sk, 5, true));
block1.hashMerkleRoot = block1.BuildMerkleTree();
CBlockIndex fakeIndex1 {block1};
// Create a fake child block
CBlock block2;
block2.hashPrevBlock = block1.GetHash();
block2.vtx.push_back(GetValidReceive(*params, sk, 10, true));
block2.hashMerkleRoot = block2.BuildMerkleTree();
CBlockIndex fakeIndex2 {block2};
fakeIndex2.pprev = &fakeIndex1;
CDiskBlockPos pos1;
CDiskBlockPos pos2;
// Set initial state of indices
ASSERT_TRUE(fakeIndex1.RaiseValidity(BLOCK_VALID_TREE));
ASSERT_TRUE(fakeIndex2.RaiseValidity(BLOCK_VALID_TREE));
EXPECT_TRUE(fakeIndex1.IsValid(BLOCK_VALID_TREE));
EXPECT_TRUE(fakeIndex2.IsValid(BLOCK_VALID_TREE));
EXPECT_FALSE(fakeIndex1.IsValid(BLOCK_VALID_TRANSACTIONS));
EXPECT_FALSE(fakeIndex2.IsValid(BLOCK_VALID_TRANSACTIONS));
// Sprout pool values should not be set
EXPECT_FALSE((bool)fakeIndex1.nSproutValue);
EXPECT_FALSE((bool)fakeIndex1.nChainSproutValue);
EXPECT_FALSE((bool)fakeIndex2.nSproutValue);
EXPECT_FALSE((bool)fakeIndex2.nChainSproutValue);
// Mark the second block's transactions as received first
CValidationState state;
EXPECT_TRUE(ReceivedBlockTransactions(block2, state, &fakeIndex2, pos2));
EXPECT_FALSE(fakeIndex1.IsValid(BLOCK_VALID_TRANSACTIONS));
EXPECT_TRUE(fakeIndex2.IsValid(BLOCK_VALID_TRANSACTIONS));
// Sprout pool value delta should now be set for the second block,
// but not any chain totals
EXPECT_FALSE((bool)fakeIndex1.nSproutValue);
EXPECT_FALSE((bool)fakeIndex1.nChainSproutValue);
{
SCOPED_TRACE("ExpectOptionalAmount call");
ExpectOptionalAmount(20, fakeIndex2.nSproutValue);
}
EXPECT_FALSE((bool)fakeIndex2.nChainSproutValue);
// Now mark the first block's transactions as received
EXPECT_TRUE(ReceivedBlockTransactions(block1, state, &fakeIndex1, pos1));
EXPECT_TRUE(fakeIndex1.IsValid(BLOCK_VALID_TRANSACTIONS));
EXPECT_TRUE(fakeIndex2.IsValid(BLOCK_VALID_TRANSACTIONS));
// Sprout pool values should now be set for both blocks
{
SCOPED_TRACE("ExpectOptionalAmount call");
ExpectOptionalAmount(10, fakeIndex1.nSproutValue);
}
{
SCOPED_TRACE("ExpectOptionalAmount call");
ExpectOptionalAmount(10, fakeIndex1.nChainSproutValue);
}
{
SCOPED_TRACE("ExpectOptionalAmount call");
ExpectOptionalAmount(20, fakeIndex2.nSproutValue);
}
{
SCOPED_TRACE("ExpectOptionalAmount call");
ExpectOptionalAmount(30, fakeIndex2.nChainSproutValue);
}
}

View File

@@ -1,7 +1,3 @@
#include "zcash/JoinSplit.hpp"
ZCJoinSplit* params = ZCJoinSplit::Unopened();
int GenZero(int n)
{
return 0;

View File

@@ -12,6 +12,8 @@
#include "uint256.h"
#include "version.h"
#include "sodium.h"
#include <vector>
typedef uint256 ChainCode;
@@ -150,6 +152,47 @@ public:
}
};
/** A writer stream (for serialization) that computes a 256-bit BLAKE2b hash. */
class CBLAKE2bWriter
{
private:
crypto_generichash_blake2b_state state;
public:
int nType;
int nVersion;
CBLAKE2bWriter(int nTypeIn, int nVersionIn, const unsigned char* personal) : nType(nTypeIn), nVersion(nVersionIn) {
assert(crypto_generichash_blake2b_init_salt_personal(
&state,
NULL, 0, // No key.
32,
NULL, // No salt.
personal) == 0);
}
CBLAKE2bWriter& write(const char *pch, size_t size) {
crypto_generichash_blake2b_update(&state, (const unsigned char*)pch, size);
return (*this);
}
// invalidates the object
uint256 GetHash() {
uint256 result;
crypto_generichash_blake2b_final(&state, (unsigned char*)&result, 32);
return result;
}
template<typename T>
CBLAKE2bWriter& operator<<(const T& obj) {
// Serialize to this stream
::Serialize(*this, obj, nType, nVersion);
return (*this);
}
};
/** Compute the 256-bit hash of an object's serialization. */
template<typename T>
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)

View File

@@ -17,7 +17,7 @@
static const char *WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\"";
/** Simple one-shot callback timer to be used by the RPC mechanism to e.g.
* re-lock the wellet.
* re-lock the wallet.
*/
class HTTPRPCTimer : public RPCTimerBase
{

View File

@@ -72,13 +72,35 @@ private:
std::deque<WorkItem*> queue;
bool running;
size_t maxDepth;
int numThreads;
/** RAII object to keep track of number of running worker threads */
class ThreadCounter
{
public:
WorkQueue &wq;
ThreadCounter(WorkQueue &w): wq(w)
{
boost::lock_guard<boost::mutex> lock(wq.cs);
wq.numThreads += 1;
}
~ThreadCounter()
{
boost::lock_guard<boost::mutex> lock(wq.cs);
wq.numThreads -= 1;
wq.cond.notify_all();
}
};
public:
WorkQueue(size_t maxDepth) : running(true),
maxDepth(maxDepth)
maxDepth(maxDepth),
numThreads(0)
{
}
/* Precondition: worker threads have all stopped */
/*( Precondition: worker threads have all stopped
* (call WaitExit)
*/
~WorkQueue()
{
while (!queue.empty()) {
@@ -100,6 +122,7 @@ public:
/** Thread function */
void Run()
{
ThreadCounter count(*this);
while (running) {
WorkItem* i = 0;
{
@@ -122,6 +145,13 @@ public:
running = false;
cond.notify_all();
}
/** Wait for worker threads to exit */
void WaitExit()
{
boost::unique_lock<boost::mutex> lock(cs);
while (numThreads > 0)
cond.wait(lock);
}
/** Return current depth of queue */
size_t Depth()
@@ -155,6 +185,8 @@ static std::vector<CSubNet> rpc_allow_subnets;
static WorkQueue<HTTPClosure>* workQueue = 0;
//! Handlers for (sub)paths
std::vector<HTTPPathHandler> pathHandlers;
//! Bound listening sockets
std::vector<evhttp_bound_socket *> boundSockets;
/** Check if a network address is allowed to access the HTTP server */
static bool ClientAllowed(const CNetAddr& netaddr)
@@ -264,10 +296,17 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
}
}
/** Callback to reject HTTP requests after shutdown. */
static void http_reject_request_cb(struct evhttp_request* req, void*)
{
LogPrint("http", "Rejecting request while shutting down\n");
evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
}
/** Event dispatcher thread */
static void ThreadHTTP(struct event_base* base, struct evhttp* http)
{
RenameThread("bitcoin-http");
RenameThread("zcash-http");
LogPrint("http", "Entering http event loop\n");
event_base_dispatch(base);
// Event loop will be interrupted by InterruptHTTPServer()
@@ -278,7 +317,6 @@ static void ThreadHTTP(struct event_base* base, struct evhttp* http)
static bool HTTPBindAddresses(struct evhttp* http)
{
int defaultPort = GetArg("-rpcport", BaseParams().RPCPort());
int nBound = 0;
std::vector<std::pair<std::string, uint16_t> > endpoints;
// Determine what addresses to bind to
@@ -304,19 +342,20 @@ static bool HTTPBindAddresses(struct evhttp* http)
// Bind addresses
for (std::vector<std::pair<std::string, uint16_t> >::iterator i = endpoints.begin(); i != endpoints.end(); ++i) {
LogPrint("http", "Binding RPC on address %s port %i\n", i->first, i->second);
if (evhttp_bind_socket(http, i->first.empty() ? NULL : i->first.c_str(), i->second) == 0) {
nBound += 1;
evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? NULL : i->first.c_str(), i->second);
if (bind_handle) {
boundSockets.push_back(bind_handle);
} else {
LogPrintf("Binding RPC on address %s port %i failed.\n", i->first, i->second);
}
}
return nBound > 0;
return !boundSockets.empty();
}
/** Simple wrapper to set thread name and run work queue */
static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue)
{
RenameThread("bitcoin-httpworker");
RenameThread("zcash-httpworker");
queue->Run();
}
@@ -399,23 +438,33 @@ bool InitHTTPServer()
return true;
}
bool StartHTTPServer(boost::thread_group& threadGroup)
boost::thread threadHTTP;
bool StartHTTPServer()
{
LogPrint("http", "Starting HTTP server\n");
int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
threadGroup.create_thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP));
threadHTTP = boost::thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP));
for (int i = 0; i < rpcThreads; i++)
threadGroup.create_thread(boost::bind(&HTTPWorkQueueRun, workQueue));
for (int i = 0; i < rpcThreads; i++) {
boost::thread rpc_worker(HTTPWorkQueueRun, workQueue);
rpc_worker.detach();
}
return true;
}
void InterruptHTTPServer()
{
LogPrint("http", "Interrupting HTTP server\n");
if (eventBase)
event_base_loopbreak(eventBase);
if (eventHTTP) {
// Unlisten sockets
BOOST_FOREACH (evhttp_bound_socket *socket, boundSockets) {
evhttp_del_accept_socket(eventHTTP, socket);
}
// Reject requests on current connections
evhttp_set_gencb(eventHTTP, http_reject_request_cb, NULL);
}
if (workQueue)
workQueue->Interrupt();
}
@@ -423,7 +472,27 @@ void InterruptHTTPServer()
void StopHTTPServer()
{
LogPrint("http", "Stopping HTTP server\n");
delete workQueue;
if (workQueue) {
LogPrint("http", "Waiting for HTTP worker threads to exit\n");
workQueue->WaitExit();
delete workQueue;
}
if (eventBase) {
LogPrint("http", "Waiting for HTTP event thread to exit\n");
// Exit the event loop as soon as there are no active events.
event_base_loopexit(eventBase, nullptr);
// Give event loop a few seconds to exit (to send back last RPC responses), then break it
// Before this was solved with event_base_loopexit, but that didn't work as expected in
// at least libevent 2.0.21 and always introduced a delay. In libevent
// master that appears to be solved, so in the future that solution
// could be used again (if desirable).
// (see discussion in https://github.com/bitcoin/bitcoin/pull/6990)
if (!threadHTTP.try_join_for(boost::chrono::milliseconds(2000))) {
LogPrintf("HTTP event loop did not exit within allotted time, sending loopbreak\n");
event_base_loopbreak(eventBase);
threadHTTP.join();
}
}
if (eventHTTP) {
evhttp_free(eventHTTP);
eventHTTP = 0;
@@ -432,6 +501,7 @@ void StopHTTPServer()
event_base_free(eventBase);
eventBase = 0;
}
LogPrint("http", "Stopped HTTP server\n");
}
struct event_base* EventBase()

View File

@@ -28,7 +28,7 @@ bool InitHTTPServer();
* This is separate from InitHTTPServer to give users race-condition-free time
* to register their handlers between InitHTTPServer and StartHTTPServer.
*/
bool StartHTTPServer(boost::thread_group& threadGroup);
bool StartHTTPServer();
/** Interrupt HTTP server threads */
void InterruptHTTPServer();
/** Stop HTTP server */
@@ -56,11 +56,14 @@ class HTTPRequest
{
private:
struct evhttp_request* req;
// For test access
protected:
bool replySent;
public:
HTTPRequest(struct evhttp_request* req);
~HTTPRequest();
virtual ~HTTPRequest();
enum RequestMethod {
UNKNOWN,
@@ -76,17 +79,17 @@ public:
/** Get CService (address:ip) for the origin of the http request.
*/
CService GetPeer();
virtual CService GetPeer();
/** Get request method.
*/
RequestMethod GetRequestMethod();
virtual RequestMethod GetRequestMethod();
/**
* Get the request header specified by hdr, or an empty string.
* Return an pair (isPresent,string).
*/
std::pair<bool, std::string> GetHeader(const std::string& hdr);
virtual std::pair<bool, std::string> GetHeader(const std::string& hdr);
/**
* Read request body.
@@ -101,7 +104,7 @@ public:
*
* @note call this before calling WriteErrorReply or Reply.
*/
void WriteHeader(const std::string& hdr, const std::string& value);
virtual void WriteHeader(const std::string& hdr, const std::string& value);
/**
* Write HTTP reply.
@@ -111,7 +114,7 @@ public:
* @note Can be called only once. As this will give the request back to the
* main thread, do not call any other HTTPRequest methods after calling this.
*/
void WriteReply(int nStatus, const std::string& strReply = "");
virtual void WriteReply(int nStatus, const std::string& strReply = "");
};
/** Event handler closure.

View File

@@ -16,6 +16,7 @@
#endif
#include "checkpoints.h"
#include "compat/sanity.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#include "httpserver.h"
#include "httprpc.h"
@@ -44,8 +45,10 @@
#include <signal.h>
#endif
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
#include <boost/function.hpp>
@@ -53,12 +56,16 @@
#include <boost/thread.hpp>
#include <openssl/crypto.h>
#include "libsnark/common/profiling.hpp"
#include <libsnark/common/profiling.hpp>
#if ENABLE_ZMQ
#include "zmq/zmqnotificationinterface.h"
#endif
#if ENABLE_PROTON
#include "amqp/amqpnotificationinterface.h"
#endif
using namespace std;
extern void ThreadSendAlert();
@@ -74,7 +81,11 @@ bool fFeeEstimatesInitialized = false;
static CZMQNotificationInterface* pzmqNotificationInterface = NULL;
#endif
#ifdef _WIN32
#if ENABLE_PROTON
static AMQPNotificationInterface* pAMQPNotificationInterface = NULL;
#endif
#ifdef WIN32
// Win32 LevelDB doesn't use file descriptors, and the ones used for
// accessing block files don't count towards the fd_set size limit
// anyway.
@@ -153,6 +164,7 @@ public:
static CCoinsViewDB *pcoinsdbview = NULL;
static CCoinsViewErrorCatcher *pcoinscatcher = NULL;
static boost::scoped_ptr<ECCVerifyHandle> globalVerifyHandle;
void Interrupt(boost::thread_group& threadGroup)
{
@@ -236,7 +248,15 @@ void Shutdown()
}
#endif
#ifndef _WIN32
#if ENABLE_PROTON
if (pAMQPNotificationInterface) {
UnregisterValidationInterface(pAMQPNotificationInterface);
delete pAMQPNotificationInterface;
pAMQPNotificationInterface = NULL;
}
#endif
#ifndef WIN32
try {
boost::filesystem::remove(GetPidFile());
} catch (const boost::filesystem::filesystem_error& e) {
@@ -250,6 +270,7 @@ void Shutdown()
#endif
delete pzcashParams;
pzcashParams = NULL;
globalVerifyHandle.reset();
ECC_Stop();
LogPrintf("%s: done\n", __func__);
}
@@ -311,7 +332,7 @@ std::string HelpMessage(HelpMessageMode mode)
const bool showDebug = GetBoolArg("-help-debug", false);
// When adding new options to the categories, please keep and ensure alphabetical ordering.
// Do not translate _(...) -help-debug options, Many technical terms, and only a very small audience, so is unnecessary stress to translators
// Do not translate _(...) -help-debug options, many technical terms, and only a very small audience, so is unnecessary stress to translators
string strUsage = HelpMessageGroup(_("Options:"));
strUsage += HelpMessageOpt("-?", _("This help message"));
@@ -328,10 +349,13 @@ 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("-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
@@ -372,13 +396,6 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-timeout=<n>", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT));
strUsage += HelpMessageOpt("-torcontrol=<ip>:<port>", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL));
strUsage += HelpMessageOpt("-torpassword=<pass>", _("Tor control port password (default: empty)"));
#ifdef USE_UPNP
#if USE_UPNP
strUsage += HelpMessageOpt("-upnp", _("Use UPnP to map the listening port (default: 1 when listening and no -proxy)"));
#else
strUsage += HelpMessageOpt("-upnp", strprintf(_("Use UPnP to map the listening port (default: %u)"), 0));
#endif
#endif
strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6"));
strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
@@ -388,16 +405,18 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), 100));
if (showDebug)
strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf("Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s)",
FormatMoney(CWallet::minTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in BTC/kB) to add to transactions you send (default: %s)"), FormatMoney(payTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-rescan", _("Rescan the blockchain for missing wallet transactions") + " " + _("on startup"));
strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)",
CURRENCY_UNIT, FormatMoney(CWallet::minTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions") + " " + _("on startup"));
strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup"));
strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0));
strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), 1));
strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)"),
FormatMoney(maxTxFee)));
strUsage += HelpMessageOpt("-txexpirydelta", strprintf(_("Set the number of blocks after which a transaction that has not been mined will become invalid (default: %u)"), DEFAULT_TX_EXPIRY_DELTA));
strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)"),
CURRENCY_UNIT, FormatMoney(maxTxFee)));
strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format") + " " + _("on startup"));
strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat"));
strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), true));
@@ -414,6 +433,14 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-zmqpubrawtx=<address>", _("Enable publish raw transaction in <address>"));
#endif
#if ENABLE_PROTON
strUsage += HelpMessageGroup(_("AMQP 1.0 notification options:"));
strUsage += HelpMessageOpt("-amqppubhashblock=<address>", _("Enable publish hash block in <address>"));
strUsage += HelpMessageOpt("-amqppubhashtx=<address>", _("Enable publish hash transaction in <address>"));
strUsage += HelpMessageOpt("-amqppubrawblock=<address>", _("Enable publish raw block in <address>"));
strUsage += HelpMessageOpt("-amqppubrawtx=<address>", _("Enable publish raw transaction in <address>"));
#endif
strUsage += HelpMessageGroup(_("Debugging/Testing options:"));
if (showDebug)
{
@@ -425,6 +452,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", "Randomly fuzz 1 of every <n> network messages");
strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", 1));
strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0));
strUsage += HelpMessageOpt("-nuparams=hexBranchId:activationHeight", "Use given activation height for specified network upgrade (regtest-only)");
}
string debugCategories = "addrman, alert, bench, coindb, db, estimatefee, http, libevent, lock, mempool, net, partitioncheck, pow, proxy, prune, "
"rand, reindex, rpc, selectcoins, tor, zmq, zrpc, zrpcunsafe (implies zrpc)"; // Don't translate these
@@ -440,7 +468,8 @@ std::string HelpMessage(HelpMessageMode mode)
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("-minrelaytxfee=<amt>", strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK())));
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())));
strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of debug.log file"));
if (showDebug)
{
@@ -638,8 +667,7 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
bool InitSanityCheck(void)
{
if(!ECC_InitSanityCheck()) {
InitError("OpenSSL appears to lack support for elliptic curve cryptography. For more "
"information, visit https://en.bitcoin.it/wiki/OpenSSL_and_EC_Libraries");
InitError("Elliptic curve cryptography sanity check failure. Aborting.");
return false;
}
if (!glibc_sanity_test() || !glibcxx_sanity_test())
@@ -668,18 +696,14 @@ static void ZC_LoadParams()
return;
}
pzcashParams = ZCJoinSplit::Unopened();
LogPrintf("Loading verifying key from %s\n", vk_path.string().c_str());
gettimeofday(&tv_start, 0);
pzcashParams->loadVerifyingKey(vk_path.string());
pzcashParams = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string());
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);
pzcashParams->setProvingKeyPath(pk_path.string());
}
bool AppInitServers(boost::thread_group& threadGroup)
@@ -694,7 +718,7 @@ bool AppInitServers(boost::thread_group& threadGroup)
return false;
if (GetBoolArg("-rest", false) && !StartREST())
return false;
if (!StartHTTPServer(threadGroup))
if (!StartHTTPServer())
return false;
return true;
}
@@ -773,6 +797,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (mapArgs.count("-developerencryptwallet")) {
return InitError(_("Wallet encryption requires -experimentalfeatures."));
}
else if (mapArgs.count("-paymentdisclosure")) {
return InitError(_("Payment disclosure requires -experimentalfeatures."));
} else if (mapArgs.count("-zmergetoaddress")) {
return InitError(_("RPC method z_mergetoaddress requires -experimentalfeatures."));
}
}
// Set this early so that parameter interactions go to console
@@ -806,19 +835,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// to protect privacy, do not listen by default if a default proxy server is specified
if (SoftSetBoolArg("-listen", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__);
// to protect privacy, do not use UPNP when a proxy is set. The user may still specify -listen=1
// to listen locally, so don't rely on this happening through -listen below.
if (SoftSetBoolArg("-upnp", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__);
// to protect privacy, do not discover addresses by default
if (SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -discover=0\n", __func__);
}
if (!GetBoolArg("-listen", DEFAULT_LISTEN)) {
// do not map ports or try to retrieve public IP when not listening (pointless)
if (SoftSetBoolArg("-upnp", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__);
// do not try to retrieve public IP when not listening (pointless)
if (SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__);
if (SoftSetBoolArg("-listenonion", false))
@@ -899,14 +922,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
InitWarning(_("Warning: Unsupported argument -benchmark ignored, use -debug=bench."));
// Checkmempool and checkblockindex default to true in regtest mode
mempool.setSanityCheck(GetBoolArg("-checkmempool", chainparams.DefaultConsistencyChecks()));
int ratio = std::min<int>(std::max<int>(GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
if (ratio != 0) {
mempool.setSanityCheck(1.0 / ratio);
}
fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
fCheckpointsEnabled = GetBoolArg("-checkpoints", true);
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
if (nScriptCheckThreads <= 0)
nScriptCheckThreads += boost::thread::hardware_concurrency();
nScriptCheckThreads += GetNumCores();
if (nScriptCheckThreads <= 1)
nScriptCheckThreads = 0;
else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)
@@ -989,6 +1015,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
expiryDelta = GetArg("-txexpirydelta", DEFAULT_TX_EXPIRY_DELTA);
bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", true);
fSendFreeTransactions = GetBoolArg("-sendfreetransactions", false);
@@ -1014,6 +1041,49 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
#endif
// Default value of 0 for mempooltxinputlimit means no limit is applied
if (mapArgs.count("-mempooltxinputlimit")) {
int64_t limit = GetArg("-mempooltxinputlimit", 0);
if (limit < 0) {
return InitError(_("Mempool limit on transparent inputs to a transaction cannot be negative"));
} else if (limit > 0) {
LogPrintf("Mempool configured to reject transactions with greater than %lld transparent inputs\n", limit);
}
}
if (!mapMultiArgs["-nuparams"].empty()) {
// Allow overriding network upgrade parameters for testing
if (Params().NetworkIDString() != "regtest") {
return InitError("Network upgrade parameters may only be overridden on regtest.");
}
const vector<string>& deployments = mapMultiArgs["-nuparams"];
for (auto i : deployments) {
std::vector<std::string> vDeploymentParams;
boost::split(vDeploymentParams, i, boost::is_any_of(":"));
if (vDeploymentParams.size() != 2) {
return InitError("Network upgrade parameters malformed, expecting hexBranchId:activationHeight");
}
int nActivationHeight;
if (!ParseInt32(vDeploymentParams[1], &nActivationHeight)) {
return InitError(strprintf("Invalid nActivationHeight (%s)", vDeploymentParams[1]));
}
bool found = false;
// Exclude Sprout from upgrades
for (auto i = Consensus::BASE_SPROUT + 1; i < Consensus::MAX_NETWORK_UPGRADES; ++i)
{
if (vDeploymentParams[0].compare(HexInt(NetworkUpgradeInfo[i].nBranchId)) == 0) {
UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex(i), nActivationHeight);
found = true;
LogPrintf("Setting network upgrade activation parameters for %s to height=%d\n", vDeploymentParams[0], nActivationHeight);
break;
}
}
if (!found) {
return InitError(strprintf("Invalid network upgrade (%s)", vDeploymentParams[0]));
}
}
}
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
// Initialize libsodium
@@ -1023,6 +1093,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Initialize elliptic curve code
ECC_Start();
globalVerifyHandle.reset(new ECCVerifyHandle());
// Sanity check
if (!InitSanityCheck())
@@ -1245,6 +1316,21 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
#endif
#if ENABLE_PROTON
pAMQPNotificationInterface = AMQPNotificationInterface::CreateWithArguments(mapArgs);
if (pAMQPNotificationInterface) {
// AMQP support is currently an experimental feature, so fail if user configured AMQP notifications
// without enabling experimental features.
if (!fExperimentalMode) {
return InitError(_("AMQP support requires -experimentalfeatures."));
}
RegisterValidationInterface(pAMQPNotificationInterface);
}
#endif
// ********************************************************* Step 7: load block chain
fReindex = GetBoolArg("-reindex", false);
@@ -1349,6 +1435,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
break;
}
if (!fReindex) {
uiInterface.InitMessage(_("Rewinding blocks if needed..."));
if (!RewindBlockIndex(chainparams)) {
strLoadError = _("Unable to rewind the database to a pre-upgrade state. You will need to redownload the blockchain");
break;
}
}
uiInterface.InitMessage(_("Verifying blocks..."));
if (fHavePruned && GetArg("-checkblocks", 288) > MIN_BLOCKS_TO_KEEP) {
LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n",
@@ -1449,10 +1543,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
InitWarning(msg);
}
else if (nLoadWalletRet == DB_TOO_NEW)
strErrors << _("Error loading wallet.dat: Wallet requires newer version of Bitcoin Core") << "\n";
strErrors << _("Error loading wallet.dat: Wallet requires newer version of Zcash") << "\n";
else if (nLoadWalletRet == DB_NEED_REWRITE)
{
strErrors << _("Wallet needed to be rewritten: restart Bitcoin Core to complete") << "\n";
strErrors << _("Wallet needed to be rewritten: restart Zcash to complete") << "\n";
LogPrintf("%s", strErrors.str());
return InitError(strErrors.str());
}

View File

@@ -1,4 +1,5 @@
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,17 +8,152 @@
#include "arith_uint256.h"
#include "crypto/common.h"
#include "crypto/hmac_sha512.h"
#include "eccryptoverify.h"
#include "pubkey.h"
#include "random.h"
#include <secp256k1.h>
#include "ecwrapper.h"
#include <secp256k1_recovery.h>
static secp256k1_context_t* secp256k1_context = NULL;
static secp256k1_context* secp256k1_context_sign = NULL;
/** These functions are taken from the libsecp256k1 distribution and are very ugly. */
/**
* This parses a format loosely based on a DER encoding of the ECPrivateKey type from
* section C.4 of SEC 1 <http://www.secg.org/sec1-v2.pdf>, with the following caveats:
*
* * The octet-length of the SEQUENCE must be encoded as 1 or 2 octets. It is not
* required to be encoded as one octet if it is less than 256, as DER would require.
* * The octet-length of the SEQUENCE must not be greater than the remaining
* length of the key encoding, but need not match it (i.e. the encoding may contain
* junk after the encoded SEQUENCE).
* * The privateKey OCTET STRING is zero-filled on the left to 32 octets.
* * Anything after the encoding of the privateKey OCTET STRING is ignored, whether
* or not it is validly encoded DER.
*
* out32 must point to an output buffer of length at least 32 bytes.
*/
static int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) {
const unsigned char *end = privkey + privkeylen;
memset(out32, 0, 32);
/* sequence header */
if (end - privkey < 1 || *privkey != 0x30u) {
return 0;
}
privkey++;
/* sequence length constructor */
if (end - privkey < 1 || !(*privkey & 0x80u)) {
return 0;
}
size_t lenb = *privkey & ~0x80u; privkey++;
if (lenb < 1 || lenb > 2) {
return 0;
}
if (end - privkey < lenb) {
return 0;
}
/* sequence length */
size_t len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0u);
privkey += lenb;
if (end - privkey < len) {
return 0;
}
/* sequence element 0: version number (=1) */
if (end - privkey < 3 || privkey[0] != 0x02u || privkey[1] != 0x01u || privkey[2] != 0x01u) {
return 0;
}
privkey += 3;
/* sequence element 1: octet string, up to 32 bytes */
if (end - privkey < 2 || privkey[0] != 0x04u) {
return 0;
}
size_t oslen = privkey[1];
privkey += 2;
if (oslen > 32 || end - privkey < oslen) {
return 0;
}
memcpy(out32 + (32 - oslen), privkey, oslen);
if (!secp256k1_ec_seckey_verify(ctx, out32)) {
memset(out32, 0, 32);
return 0;
}
return 1;
}
/**
* This serializes to a DER encoding of the ECPrivateKey type from section C.4 of SEC 1
* <http://www.secg.org/sec1-v2.pdf>. The optional parameters and publicKey fields are
* included.
*
* privkey must point to an output buffer of length at least CKey::PRIVATE_KEY_SIZE bytes.
* privkeylen must initially be set to the size of the privkey buffer. Upon return it
* will be set to the number of bytes used in the buffer.
* key32 must point to a 32-byte raw private key.
*/
static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) {
assert(*privkeylen >= CKey::PRIVATE_KEY_SIZE);
secp256k1_pubkey pubkey;
size_t pubkeylen = 0;
if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) {
*privkeylen = 0;
return 0;
}
if (compressed) {
static const unsigned char begin[] = {
0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20
};
static const unsigned char middle[] = {
0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00
};
unsigned char *ptr = privkey;
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
memcpy(ptr, key32, 32); ptr += 32;
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
pubkeylen = CPubKey::COMPRESSED_PUBLIC_KEY_SIZE;
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED);
ptr += pubkeylen;
*privkeylen = ptr - privkey;
assert(*privkeylen == CKey::COMPRESSED_PRIVATE_KEY_SIZE);
} else {
static const unsigned char begin[] = {
0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
};
static const unsigned char middle[] = {
0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11,
0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10,
0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00
};
unsigned char *ptr = privkey;
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
memcpy(ptr, key32, 32); ptr += 32;
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
pubkeylen = CPubKey::PUBLIC_KEY_SIZE;
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
ptr += pubkeylen;
*privkeylen = ptr - privkey;
assert(*privkeylen == CKey::PRIVATE_KEY_SIZE);
}
return 1;
}
bool CKey::Check(const unsigned char *vch) {
return eccrypto::Check(vch);
return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch);
}
void CKey::MakeNewKey(bool fCompressedIn) {
@@ -29,7 +165,7 @@ void CKey::MakeNewKey(bool fCompressedIn) {
}
bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size()))
if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size()))
return false;
fCompressed = fCompressedIn;
fValid = true;
@@ -39,10 +175,11 @@ bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
CPrivKey CKey::GetPrivKey() const {
assert(fValid);
CPrivKey privkey;
int privkeylen, ret;
privkey.resize(279);
privkeylen = 279;
ret = secp256k1_ec_privkey_export(secp256k1_context, begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed);
int ret;
size_t privkeylen;
privkey.resize(PRIVATE_KEY_SIZE);
privkeylen = PRIVATE_KEY_SIZE;
ret = ec_privkey_export_der(secp256k1_context_sign, (unsigned char*)&privkey[0], &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
assert(ret);
privkey.resize(privkeylen);
return privkey;
@@ -50,11 +187,13 @@ CPrivKey CKey::GetPrivKey() const {
CPubKey CKey::GetPubKey() const {
assert(fValid);
secp256k1_pubkey pubkey;
size_t clen = CPubKey::PUBLIC_KEY_SIZE;
CPubKey result;
int clen = 65;
int ret = secp256k1_ec_pubkey_create(secp256k1_context, (unsigned char*)result.begin(), &clen, begin(), fCompressed);
assert((int)result.size() == clen);
int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin());
assert(ret);
secp256k1_ec_pubkey_serialize(secp256k1_context_sign, (unsigned char*)result.begin(), &clen, &pubkey, fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
assert(result.size() == clen);
assert(result.IsValid());
return result;
}
@@ -62,12 +201,14 @@ CPubKey CKey::GetPubKey() const {
bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_t test_case) const {
if (!fValid)
return false;
vchSig.resize(72);
int nSigLen = 72;
vchSig.resize(CPubKey::SIGNATURE_SIZE);
size_t nSigLen = CPubKey::SIGNATURE_SIZE;
unsigned char extra_entropy[32] = {0};
WriteLE32(extra_entropy, test_case);
int ret = secp256k1_ecdsa_sign(secp256k1_context, hash.begin(), (unsigned char*)&vchSig[0], &nSigLen, begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL);
secp256k1_ecdsa_signature sig;
int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL);
assert(ret);
secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, (unsigned char*)&vchSig[0], &nSigLen, &sig);
vchSig.resize(nSigLen);
return true;
}
@@ -77,7 +218,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const {
return false;
}
unsigned char rnd[8];
std::string str = "Bitcoin key verification\n";
std::string str = "Zcash key verification\n";
GetRandBytes(rnd, sizeof(rnd));
uint256 hash;
CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize(hash.begin());
@@ -89,9 +230,12 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const {
bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
if (!fValid)
return false;
vchSig.resize(65);
vchSig.resize(CPubKey::COMPACT_SIGNATURE_SIZE);
int rec = -1;
int ret = secp256k1_ecdsa_sign_compact(secp256k1_context, hash.begin(), &vchSig[1], begin(), secp256k1_nonce_function_rfc6979, NULL, &rec);
secp256k1_ecdsa_recoverable_signature sig;
int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, NULL);
assert(ret);
secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, (unsigned char*)&vchSig[1], &rec, &sig);
assert(ret);
assert(rec != -1);
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
@@ -99,7 +243,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
}
bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size()))
if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size()))
return false;
fCompressed = vchPubKey.IsCompressed();
fValid = true;
@@ -117,15 +261,15 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
LockObject(out);
if ((nChild >> 31) == 0) {
CPubKey pubkey = GetPubKey();
assert(pubkey.begin() + 33 == pubkey.end());
assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, out);
} else {
assert(begin() + 32 == end());
assert(size() == 32);
BIP32Hash(cc, nChild, 0, begin(), out);
}
memcpy(ccChild.begin(), out+32, 32);
memcpy((unsigned char*)keyChild.begin(), begin(), 32);
bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context, (unsigned char*)keyChild.begin(), out);
bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), out);
UnlockObject(out);
keyChild.fCompressed = true;
keyChild.fValid = ret;
@@ -183,20 +327,16 @@ void CExtKey::Decode(const unsigned char code[74]) {
}
bool ECC_InitSanityCheck() {
if (!CECKey::SanityCheck()) {
return false;
}
CKey key;
key.MakeNewKey(true);
CPubKey pubkey = key.GetPubKey();
return key.VerifyPubKey(pubkey);
}
void ECC_Start() {
assert(secp256k1_context == NULL);
assert(secp256k1_context_sign == NULL);
secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
assert(ctx != NULL);
{
@@ -209,12 +349,12 @@ void ECC_Start() {
UnlockObject(seed);
}
secp256k1_context = ctx;
secp256k1_context_sign = ctx;
}
void ECC_Stop() {
secp256k1_context_t *ctx = secp256k1_context;
secp256k1_context = NULL;
secp256k1_context *ctx = secp256k1_context_sign;
secp256k1_context_sign = NULL;
if (ctx) {
secp256k1_context_destroy(ctx);

View File

@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,25 +16,30 @@
#include <vector>
/**
* secp256k1:
* const unsigned int PRIVATE_KEY_SIZE = 279;
* const unsigned int PUBLIC_KEY_SIZE = 65;
* const unsigned int SIGNATURE_SIZE = 72;
*
* see www.keylength.com
* script supports up to 75 for single byte push
*/
/**
* secure_allocator is defined in allocators.h
* CPrivKey is a serialized private key, with all parameters included (279 bytes)
* CPrivKey is a serialized private key, with all parameters included
* (PRIVATE_KEY_SIZE bytes)
*/
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
/** An encapsulated private key. */
class CKey
{
public:
/**
* secp256k1:
*/
static const unsigned int PRIVATE_KEY_SIZE = 279;
static const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214;
/**
* see www.keylength.com
* script supports up to 75 for single byte push
*/
static_assert(
PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE,
"COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE");
private:
//! Whether this private key is valid. We check for correctness when modifying the key
//! data, so fValid should always correspond to the actual state.

View File

@@ -89,6 +89,40 @@ bool CBasicKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk)
LOCK(cs_SpendingKeyStore);
auto address = sk.address();
mapSpendingKeys[address] = sk;
mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(sk.viewing_key())));
mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(sk.receiving_key())));
return true;
}
bool CBasicKeyStore::AddViewingKey(const libzcash::ViewingKey &vk)
{
LOCK(cs_SpendingKeyStore);
auto address = vk.address();
mapViewingKeys[address] = vk;
mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(vk.sk_enc)));
return true;
}
bool CBasicKeyStore::RemoveViewingKey(const libzcash::ViewingKey &vk)
{
LOCK(cs_SpendingKeyStore);
mapViewingKeys.erase(vk.address());
return true;
}
bool CBasicKeyStore::HaveViewingKey(const libzcash::PaymentAddress &address) const
{
LOCK(cs_SpendingKeyStore);
return mapViewingKeys.count(address) > 0;
}
bool CBasicKeyStore::GetViewingKey(const libzcash::PaymentAddress &address,
libzcash::ViewingKey &vkOut) const
{
LOCK(cs_SpendingKeyStore);
ViewingKeyMap::const_iterator mi = mapViewingKeys.find(address);
if (mi != mapViewingKeys.end()) {
vkOut = mi->second;
return true;
}
return false;
}

View File

@@ -55,12 +55,19 @@ public:
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;
//! 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;
};
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;
/** Basic key store, that keeps keys in an address->secret map */
@@ -71,6 +78,7 @@ protected:
ScriptMap mapScripts;
WatchOnlySet setWatchOnly;
SpendingKeyMap mapSpendingKeys;
ViewingKeyMap mapViewingKeys;
NoteDecryptorMap mapNoteDecryptors;
public:
@@ -166,8 +174,19 @@ public:
setAddress.insert((*mi).first);
mi++;
}
ViewingKeyMap::const_iterator mvi = mapViewingKeys.begin();
while (mvi != mapViewingKeys.end())
{
setAddress.insert((*mvi).first);
mvi++;
}
}
}
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;
};
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;

View File

@@ -6,6 +6,7 @@
#include "clientversion.h"
#include "coins.h"
#include "consensus/consensus.h"
#include "consensus/upgrades.h"
#include "core_io.h"
#include "keystore.h"
#include "primitives/transaction.h"
@@ -83,7 +84,7 @@ static bool AppInitRawTx(int argc, char* argv[])
strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT", _("Add raw script output to TX"));
strUsage += HelpMessageOpt("sign=SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " +
strUsage += HelpMessageOpt("sign=HEIGHT:SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " +
_("This command requires JSON registers:") +
_("prevtxs=JSON object") + ", " +
_("privatekeys=JSON object") + ". " +
@@ -170,12 +171,21 @@ static void RegisterLoad(const string& strInput)
static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal)
{
int64_t newVersion = atoi64(cmdVal);
if (newVersion < CTransaction::MIN_CURRENT_VERSION || newVersion > CTransaction::MAX_CURRENT_VERSION)
if (newVersion < CTransaction::SPROUT_MIN_CURRENT_VERSION || newVersion > CTransaction::SPROUT_MAX_CURRENT_VERSION)
throw runtime_error("Invalid TX version requested");
tx.nVersion = (int) newVersion;
}
static void MutateTxExpiry(CMutableTransaction& tx, const string& cmdVal)
{
int64_t newExpiry = atoi64(cmdVal);
if (newExpiry >= TX_EXPIRY_HEIGHT_THRESHOLD) {
throw runtime_error("Invalid TX expiry requested");
}
tx.nExpiryHeight = (int) newExpiry;
}
static void MutateTxLocktime(CMutableTransaction& tx, const string& cmdVal)
{
int64_t newLocktime = atoi64(cmdVal);
@@ -335,11 +345,39 @@ vector<unsigned char> ParseHexUO(map<string,UniValue>& o, string strKey)
return ParseHexUV(o[strKey], strKey);
}
static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
static CAmount AmountFromValue(const UniValue& value)
{
int nHashType = SIGHASH_ALL;
if (!value.isNum() && !value.isStr())
throw runtime_error("Amount is not a number or string");
CAmount amount;
if (!ParseFixedPoint(value.getValStr(), 8, &amount))
throw runtime_error("Invalid amount");
if (!MoneyRange(amount))
throw runtime_error("Amount out of range");
return amount;
}
static void MutateTxSign(CMutableTransaction& tx, const 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");
// extract and validate HEIGHT
string strHeight = strInput.substr(0, pos);
int nHeight = atoi(strHeight);
if (nHeight <= 0) {
throw 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);
}
if (flagStr.size() > 0)
if (!findSighashFlags(nHashType, flagStr))
throw runtime_error("unknown sighash flag/sign option");
@@ -407,7 +445,10 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
if ((unsigned int)nOut >= coins->vout.size())
coins->vout.resize(nOut+1);
coins->vout[nOut].scriptPubKey = scriptPubKey;
coins->vout[nOut].nValue = 0; // we don't know the actual output value
coins->vout[nOut].nValue = 0;
if (prevOut.exists("amount")) {
coins->vout[nOut].nValue = AmountFromValue(prevOut["amount"]);
}
}
// if redeemScript given and private keys given,
@@ -426,6 +467,9 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
// Grab the consensus branch ID for the given height
auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus());
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i];
@@ -435,17 +479,19 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
continue;
}
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
const CAmount& amount = coins->vout[txin.prevout.n].nValue;
txin.scriptSig.clear();
SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size()))
SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId);
// ... and merge in other signatures:
BOOST_FOREACH(const CTransaction& txv, txVariants) {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
}
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i)))
BOOST_FOREACH(const CTransaction& txv, txVariants)
sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId);
UpdateTransaction(mergedTx, i, sigdata);
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount), consensusBranchId))
fComplete = false;
}
@@ -459,9 +505,15 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
class Secp256k1Init
{
ECCVerifyHandle globalVerifyHandle;
public:
Secp256k1Init() { ECC_Start(); }
~Secp256k1Init() { ECC_Stop(); }
Secp256k1Init() {
ECC_Start();
}
~Secp256k1Init() {
ECC_Stop();
}
};
static void MutateTx(CMutableTransaction& tx, const string& command,
@@ -473,6 +525,8 @@ static void MutateTx(CMutableTransaction& tx, const string& command,
MutateTxVersion(tx, commandVal);
else if (command == "locktime")
MutateTxLocktime(tx, commandVal);
else if (command == "expiry")
MutateTxExpiry(tx, commandVal);
else if (command == "delin")
MutateTxDelInput(tx, commandVal);

View File

@@ -13,7 +13,7 @@
#include <leveldb/filter_policy.h>
#include <memenv.h>
void HandleError(const leveldb::Status& status) throw(leveldb_error)
void HandleError(const leveldb::Status& status)
{
if (status.ok())
return;
@@ -81,7 +81,7 @@ CLevelDBWrapper::~CLevelDBWrapper()
options.env = NULL;
}
bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) throw(leveldb_error)
bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync)
{
leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
HandleError(status);

View File

@@ -22,7 +22,7 @@ public:
leveldb_error(const std::string& msg) : std::runtime_error(msg) {}
};
void HandleError(const leveldb::Status& status) throw(leveldb_error);
void HandleError(const leveldb::Status& status);
/** Batch of changes queued to be written to a CLevelDBWrapper */
class CLevelDBBatch
@@ -90,7 +90,7 @@ public:
~CLevelDBWrapper();
template <typename K, typename V>
bool Read(const K& key, V& value) const throw(leveldb_error)
bool Read(const K& key, V& value) const
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(ssKey.GetSerializeSize(key));
@@ -115,7 +115,7 @@ public:
}
template <typename K, typename V>
bool Write(const K& key, const V& value, bool fSync = false) throw(leveldb_error)
bool Write(const K& key, const V& value, bool fSync = false)
{
CLevelDBBatch batch;
batch.Write(key, value);
@@ -123,7 +123,7 @@ public:
}
template <typename K>
bool Exists(const K& key) const throw(leveldb_error)
bool Exists(const K& key) const
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(ssKey.GetSerializeSize(key));
@@ -142,14 +142,14 @@ public:
}
template <typename K>
bool Erase(const K& key, bool fSync = false) throw(leveldb_error)
bool Erase(const K& key, bool fSync = false)
{
CLevelDBBatch batch;
batch.Erase(key);
return WriteBatch(batch, fSync);
}
bool WriteBatch(CLevelDBBatch& batch, bool fSync = false) throw(leveldb_error);
bool WriteBatch(CLevelDBBatch& batch, bool fSync = false);
// not available for LevelDB; provide for compatibility with BDB
bool Flush()
@@ -157,7 +157,7 @@ public:
return true;
}
bool Sync() throw(leveldb_error)
bool Sync()
{
CLevelDBBatch batch;
return WriteBatch(batch, true);

File diff suppressed because it is too large Load Diff

View File

@@ -15,6 +15,7 @@
#include "chainparams.h"
#include "coins.h"
#include "consensus/consensus.h"
#include "consensus/upgrades.h"
#include "net.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
@@ -44,6 +45,7 @@ class CInv;
class CScriptCheck;
class CValidationInterface;
class CValidationState;
class PrecomputedTransactionData;
struct CNodeStateStats;
#define DEFAULT_MEMPOOL_EXPIRY 1
@@ -57,6 +59,8 @@ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = DEFAULT_BLOCK_MAX_SIZE /
static const bool DEFAULT_ALERTS = true;
/** Minimum alert priority for enabling safe mode. */
static const int ALERT_PRIORITY_SAFE_MODE = 4000;
/** Maximum reorg length we will accept before we shut down and alert the user. */
static const unsigned int MAX_REORG_LENGTH = COINBASE_MATURITY - 1;
/** Maximum number of signature check operations in an IsStandard() P2SH script */
static const unsigned int MAX_P2SH_SIGOPS = 15;
/** The maximum number of sigops we're willing to relay/mine in a single tx */
@@ -65,6 +69,8 @@ static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5;
static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 100;
/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */
static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;
/** Default for -txexpirydelta, in number of blocks */
static const unsigned int DEFAULT_TX_EXPIRY_DELTA = 20;
/** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
@@ -107,6 +113,7 @@ struct BlockHasher
size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); }
};
extern unsigned int expiryDelta;
extern CScript COINBASE_FLAGS;
extern CCriticalSection cs_main;
extern CTxMemPool mempool;
@@ -305,7 +312,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
* @return True if all inputs (scriptSigs) use only standard transaction forms
*/
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId);
/**
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
@@ -330,11 +337,17 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma
* instead of being performed inline.
*/
bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams,
unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata,
const Consensus::Params& consensusParams, uint32_t consensusBranchId,
std::vector<CScriptCheck> *pvChecks = NULL);
/** Check a transaction contextually against a set of consensus rules */
bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, int nHeight, int dosLevel);
/** Apply the effects of this transaction on the UTXO set represented by view */
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight);
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
/** Transaction validation functions */
/** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state, libzcash::ProofVerifier& verifier);
@@ -343,7 +356,18 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
/** Check for standard transaction types
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
*/
bool IsStandardTx(const CTransaction& tx, std::string& reason);
bool IsStandardTx(const CTransaction& tx, std::string& reason, int nHeight = 0);
namespace Consensus {
/**
* Check whether all inputs of this transaction are valid (no double spends and amounts)
* This does not modify the UTXO set. This does not check scripts and sigs.
* Preconditions: tx.IsCoinBase() is false.
*/
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams);
} // namespace Consensus
/**
* Check if transaction is final and can be included in a block with the
@@ -351,6 +375,12 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason);
*/
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime);
/**
* Check if transaction is expired and can be included in a block with the
* specified height. Consensus critical.
*/
bool IsExpiredTx(const CTransaction &tx, int nBlockHeight);
/**
* Check if transaction will be final in the next block to be created.
*
@@ -368,27 +398,33 @@ class CScriptCheck
{
private:
CScript scriptPubKey;
CAmount amount;
const CTransaction *ptxTo;
unsigned int nIn;
unsigned int nFlags;
bool cacheStore;
uint32_t consensusBranchId;
ScriptError error;
PrecomputedTransactionData *txdata;
public:
CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) :
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey),
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) { }
CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), consensusBranchId(0), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, uint32_t consensusBranchIdIn, PrecomputedTransactionData* txdataIn) :
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), amount(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue),
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), consensusBranchId(consensusBranchIdIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
bool operator()();
void swap(CScriptCheck &check) {
scriptPubKey.swap(check.scriptPubKey);
std::swap(ptxTo, check.ptxTo);
std::swap(amount, check.amount);
std::swap(nIn, check.nIn);
std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore);
std::swap(consensusBranchId, check.consensusBranchId);
std::swap(error, check.error);
std::swap(txdata, check.txdata);
}
ScriptError GetScriptError() const { return error; }
@@ -437,6 +473,13 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
/**
* 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.
*/
bool RewindBlockIndex(const CChainParams& params);
class CBlockFileInfo
{
public:
@@ -508,7 +551,7 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex);
/** Remove invalidity status from a block and its descendants. */
bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex);
/** The currently-connected chain of blocks. */
/** The currently-connected chain of blocks (protected by cs_main). */
extern CChain chainActive;
/** Global variable that points to the active CCoinsView (protected by cs_main) */
@@ -524,8 +567,7 @@ extern CBlockTreeDB *pblocktree;
*/
int GetSpendHeight(const CCoinsViewCache& inputs);
namespace Consensus {
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams);
}
/** Return a CMutableTransaction with contextual default values based on set of consensus rules at height */
CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight);
#endif // BITCOIN_MAIN_H

View File

@@ -62,12 +62,12 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, const std::set<uint256>& txids)
uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid) {
if (height == 0) {
// hash at height 0 is the txids themself
// hash at height 0 is the txid itself
return vTxid[pos];
} else {
// calculate left hash
uint256 left = CalcHash(height-1, pos*2, vTxid), right;
// calculate right hash if not beyond the end of the array - copy left hash otherwise1
// calculate right hash if not beyond the end of the array - copy left hash otherwise
if (pos*2+1 < CalcTreeWidth(height-1))
right = CalcHash(height-1, pos*2+1, vTxid);
else

View File

@@ -67,7 +67,7 @@ protected:
return (nTransactions+(1 << height)-1) >> height;
}
/** calculate the hash of a node in the merkle tree (at leaf level: the txid's themselves) */
/** calculate the hash of a node in the merkle tree (at leaf level: the txid itself) */
uint256 CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid);
/** recursive function that traverses tree nodes, storing the data as bits and hashes */

View File

@@ -5,11 +5,13 @@
#include "metrics.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "main.h"
#include "ui_interface.h"
#include "util.h"
#include "utiltime.h"
#include "utilmoneystr.h"
#include "utilstrencodings.h"
#include <boost/thread.hpp>
#include <boost/thread/synchronized_value.hpp>
@@ -50,6 +52,12 @@ bool AtomicTimer::running()
return threads > 0;
}
uint64_t AtomicTimer::threadCount()
{
std::unique_lock<std::mutex> lock(mtx);
return threads;
}
double AtomicTimer::rate(const AtomicCounter& count)
{
std::unique_lock<std::mutex> lock(mtx);
@@ -101,6 +109,36 @@ double GetLocalSolPS()
return miningTimer.rate(solutionTargetChecks);
}
int EstimateNetHeightInner(int height, int64_t tipmediantime,
int heightLastCheckpoint, int64_t timeLastCheckpoint,
int64_t genesisTime, int64_t targetSpacing)
{
// We average the target spacing with the observed spacing to the last
// checkpoint (either from below or above depending on the current height),
// and use that to estimate the current network height.
int medianHeight = height > CBlockIndex::nMedianTimeSpan ?
height - (1 + ((CBlockIndex::nMedianTimeSpan - 1) / 2)) :
height / 2;
double checkpointSpacing = medianHeight > heightLastCheckpoint ?
(double (tipmediantime - timeLastCheckpoint)) / (medianHeight - heightLastCheckpoint) :
(double (timeLastCheckpoint - genesisTime)) / heightLastCheckpoint;
double averageSpacing = (targetSpacing + checkpointSpacing) / 2;
int netheight = medianHeight + ((GetTime() - tipmediantime) / averageSpacing);
// Round to nearest ten to reduce noise
return ((netheight + 5) / 10) * 10;
}
int EstimateNetHeight(int height, int64_t tipmediantime, CChainParams chainParams)
{
auto checkpointData = chainParams.Checkpoints();
return EstimateNetHeightInner(
height, tipmediantime,
Checkpoints::GetTotalBlocksEstimate(checkpointData),
checkpointData.nTimeLastCheckpoint,
chainParams.GenesisBlock().nTime,
chainParams.GetConsensus().nPowTargetSpacing);
}
void TriggerRefresh()
{
*nNextRefresh = GetTime();
@@ -167,17 +205,25 @@ int printStats(bool mining)
int lines = 4;
int height;
int64_t tipmediantime;
size_t connections;
int64_t netsolps;
{
LOCK2(cs_main, cs_vNodes);
height = chainActive.Height();
tipmediantime = chainActive.Tip()->GetMedianTimePast();
connections = vNodes.size();
netsolps = GetNetworkHashPS(120, -1);
}
auto localsolps = GetLocalSolPS();
std::cout << " " << _("Block height") << " | " << height << std::endl;
if (IsInitialBlockDownload()) {
int netheight = EstimateNetHeight(height, tipmediantime, Params());
int downloadPercent = height * 100 / netheight;
std::cout << " " << _("Downloading blocks") << " | " << height << " / ~" << netheight << " (" << downloadPercent << "%)" << std::endl;
} else {
std::cout << " " << _("Block height") << " | " << height << std::endl;
}
std::cout << " " << _("Connections") << " | " << connections << std::endl;
std::cout << " " << _("Network solution rate") << " | " << netsolps << " Sol/s" << std::endl;
if (mining && miningTimer.running()) {
@@ -196,15 +242,8 @@ int printMiningStatus(bool mining)
int lines = 1;
if (mining) {
int nThreads = GetArg("-genproclimit", 1);
if (nThreads < 0) {
// In regtest threads defaults to 1
if (Params().DefaultMinerThreads())
nThreads = Params().DefaultMinerThreads();
else
nThreads = boost::thread::hardware_concurrency();
}
if (miningTimer.running()) {
auto nThreads = miningTimer.threadCount();
if (nThreads > 0) {
std::cout << strprintf(_("You are mining with the %s solver on %d threads."),
GetArg("-equihashsolver", "default"), nThreads) << std::endl;
} else {
@@ -339,20 +378,19 @@ int printMessageBox(size_t cols)
int lines = 2 + u->size();
std::cout << _("Messages:") << std::endl;
for (auto it = u->cbegin(); it != u->cend(); ++it) {
std::cout << *it << std::endl;
auto msg = FormatParagraph(*it, cols, 2);
std::cout << "- " << msg << std::endl;
// Handle newlines and wrapped lines
size_t i = 0;
size_t j = 0;
while (j < it->size()) {
i = it->find('\n', j);
while (j < msg.size()) {
i = msg.find('\n', j);
if (i == std::string::npos) {
i = it->size();
i = msg.size();
} else {
// Newline
lines++;
}
// Wrapped lines
lines += ((i-j) / cols);
j = i + 1;
}
}

View File

@@ -49,6 +49,8 @@ public:
bool running();
uint64_t threadCount();
double rate(const AtomicCounter& count);
};
@@ -61,6 +63,9 @@ void TrackMinedBlock(uint256 hash);
void MarkStartTime();
double GetLocalSolPS();
int EstimateNetHeightInner(int height, int64_t tipmediantime,
int heightLastCheckpoint, int64_t timeLastCheckpoint,
int64_t genesisTime, int64_t targetSpacing);
void TriggerRefresh();

View File

@@ -12,6 +12,7 @@
#include "base58.h"
#include "chainparams.h"
#include "consensus/consensus.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#ifdef ENABLE_MINING
#include "crypto/equihash.h"
@@ -100,10 +101,6 @@ public:
void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
// Updating time can change work required on testnet:
if (consensusParams.fPowAllowMinDifficultyBlocks)
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
}
#include "komodo_defs.h"
@@ -189,6 +186,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
LOCK2(cs_main, mempool.cs);
CBlockIndex* pindexPrev = chainActive.Tip();
const int nHeight = pindexPrev->nHeight + 1;
uint32_t consensusBranchId = CurrentEpochBranchId(nHeight, chainparams.GetConsensus());
pblock->nTime = GetAdjustedTime();
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
CCoinsViewCache view(pcoinsTip);
@@ -202,16 +200,16 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
// This vector will be sorted into a priority queue:
vector<TxPriority> vecPriority;
vecPriority.reserve(mempool.mapTx.size());
for (map<uint256, CTxMemPoolEntry>::iterator mi = mempool.mapTx.begin();
for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
mi != mempool.mapTx.end(); ++mi)
{
const CTransaction& tx = mi->second.GetTx();
const CTransaction& tx = mi->GetTx();
int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
? nMedianTimePast
: pblock->GetBlockTime();
if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, nLockTimeCutoff))
if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, nLockTimeCutoff) || IsExpiredTx(tx, nHeight))
continue;
if ( komodo_validate_interest(tx,nHeight,(uint32_t)pblock->nTime,2) < 0 )
{
@@ -249,7 +247,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
}
mapDependers[txin.prevout.hash].push_back(porphan);
porphan->setDependsOn.insert(txin.prevout.hash);
nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue;
nTotalIn += mempool.mapTx.find(txin.prevout.hash)->GetTx().vout[txin.prevout.n].nValue;
continue;
}
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
@@ -281,7 +279,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
porphan->feeRate = feeRate;
}
else
vecPriority.push_back(TxPriority(dPriority, feeRate, &mi->second.GetTx()));
vecPriority.push_back(TxPriority(dPriority, feeRate, &(mi->GetTx())));
}
// Collect transactions into block
@@ -345,10 +343,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
// policy here, but we still have to ensure that the block we
// create only contains transactions that are valid in new blocks.
CValidationState state;
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus()))
PrecomputedTransactionData txdata(tx);
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
continue;
UpdateCoins(tx, state, view, nHeight);
UpdateCoins(tx, view, nHeight);
// Added
pblock->vtx.push_back(tx);
@@ -387,13 +386,13 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize);
// Create coinbase tx
CMutableTransaction txNew;
//txNew.nLockTime = (uint32_t)time(NULL) - 60;
CMutableTransaction txNew = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight);
txNew.vin.resize(1);
txNew.vin[0].prevout.SetNull();
txNew.vout.resize(1);
txNew.vout[0].scriptPubKey = scriptPubKeyIn;
txNew.vout[0].nValue = GetBlockSubsidy(nHeight,chainparams.GetConsensus());
txNew.nExpiryHeight = 0;
// Add fees
txNew.vout[0].nValue += nFees;
txNew.vin[0].scriptSig = CScript() << nHeight << OP_0;
@@ -914,7 +913,7 @@ void static BitcoinMiner()
equi eq(1);
eq.setstate(&curr_state);
// Intialization done, start algo driver.
// Initialization done, start algo driver.
eq.digit0(0);
eq.xfull = eq.bfull = eq.hfull = 0;
eq.showbsizes(0);
@@ -1000,18 +999,12 @@ void static BitcoinMiner()
// Update nNonce and nTime
pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1);
pblock->nBits = savebits;
//UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks)
{
// Changing pblock->nTime can change work required on testnet:
hashTarget.SetCompact(pblock->nBits);
}
/*CValidationState tmpstate;
if ( !TestBlockValidity(tmpstate, *pblock, pindexPrev, false, false))
{
fprintf(stderr,"formerly valid mining block became invalid, likely due to tx expiration\n");
break;
}*/
}
}
}
@@ -1041,13 +1034,8 @@ void GenerateBitcoins(bool fGenerate, int nThreads)
{
static boost::thread_group* minerThreads = NULL;
if (nThreads < 0) {
// In regtest threads defaults to 1
if (Params().DefaultMinerThreads())
nThreads = Params().DefaultMinerThreads();
else
nThreads = boost::thread::hardware_concurrency();
}
if (nThreads < 0)
nThreads = GetNumCores();
if (minerThreads != NULL)
{

View File

@@ -7,6 +7,7 @@
#include "config/bitcoin-config.h"
#endif
#include "main.h"
#include "net.h"
#include "addrman.h"
@@ -23,13 +24,6 @@
#include <fcntl.h>
#endif
#ifdef USE_UPNP
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/miniwget.h>
#include <miniupnpc/upnpcommands.h>
#include <miniupnpc/upnperrors.h>
#endif
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
@@ -542,24 +536,22 @@ void CNode::AddWhitelistedRange(const CSubNet &subnet) {
vWhitelistedRange.push_back(subnet);
}
#undef X
#define X(name) stats.name = name
void CNode::copyStats(CNodeStats &stats)
{
stats.nodeid = this->GetId();
X(nServices);
X(nLastSend);
X(nLastRecv);
X(nTimeConnected);
X(nTimeOffset);
X(addrName);
X(nVersion);
X(cleanSubVer);
X(fInbound);
X(nStartingHeight);
X(nSendBytes);
X(nRecvBytes);
X(fWhitelisted);
stats.nServices = nServices;
stats.nLastSend = nLastSend;
stats.nLastRecv = nLastRecv;
stats.nTimeConnected = nTimeConnected;
stats.nTimeOffset = nTimeOffset;
stats.addrName = addrName;
stats.nVersion = nVersion;
stats.cleanSubVer = cleanSubVer;
stats.fInbound = fInbound;
stats.nStartingHeight = nStartingHeight;
stats.nSendBytes = nSendBytes;
stats.nRecvBytes = nRecvBytes;
stats.fWhitelisted = fWhitelisted;
// It is common for nodes with good ping times to suddenly become lagged,
// due to a new block arriving or other large transfer.
@@ -579,7 +571,6 @@ void CNode::copyStats(CNodeStats &stats)
// Leave string empty if addrLocal invalid (not filled in yet)
stats.addrLocal = addrLocal.IsValid() ? addrLocal.ToString() : "";
}
#undef X
// requires LOCK(cs_vRecvMsg)
bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
@@ -820,6 +811,34 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
// Protect connections with certain characteristics
// Check version of eviction candidates and prioritize nodes which do not support network upgrade.
std::vector<CNodeRef> vTmpEvictionCandidates;
int height;
{
LOCK(cs_main);
height = chainActive.Height();
}
const Consensus::Params& params = Params().GetConsensus();
int nActivationHeight = params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight;
if (nActivationHeight > 0 &&
height < nActivationHeight &&
height >= nActivationHeight - NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD)
{
// 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) {
vTmpEvictionCandidates.push_back(node);
}
}
// Prioritize these nodes by replacing eviction set with them
if (vTmpEvictionCandidates.size() > 0) {
vEvictionCandidates = vTmpEvictionCandidates;
}
}
// Deterministically select 4 peers to protect by netgroup.
// An attacker cannot predict which netgroups will be protected.
static CompareNetGroupKeyed comparerNetGroupKeyed;
@@ -1053,7 +1072,7 @@ void ThreadSocketHandler()
// happens when optimistic write failed, we choose to first drain the
// write buffer in this case before receiving more. This avoids
// needlessly queueing received data, if the remote peer is not themselves
// receiving data. This means properly utilizing TCP flow control signalling.
// receiving data. This means properly utilizing TCP flow control signaling.
// * Otherwise, if there is no (complete) message in the receive buffer,
// or there is space left in the buffer, select() for receiving data.
// * (if neither of the above applies, there is certainly one message
@@ -1216,131 +1235,6 @@ void ThreadSocketHandler()
}
#ifdef USE_UPNP
void ThreadMapPort()
{
std::string port = strprintf("%u", GetListenPort());
const char * multicastif = 0;
const char * minissdpdpath = 0;
struct UPNPDev * devlist = 0;
char lanaddr[64];
#ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */
devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0);
#elif MINIUPNPC_API_VERSION < 14
/* miniupnpc 1.6 */
int error = 0;
devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
#else
/* miniupnpc 1.9.20150730 */
int error = 0;
devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error);
#endif
struct UPNPUrls urls;
struct IGDdatas data;
int r;
r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
if (r == 1)
{
if (fDiscover) {
char externalIPAddress[40];
r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
if(r != UPNPCOMMAND_SUCCESS)
LogPrintf("UPnP: GetExternalIPAddress() returned %d\n", r);
else
{
if(externalIPAddress[0])
{
LogPrintf("UPnP: ExternalIPAddress = %s\n", externalIPAddress);
AddLocal(CNetAddr(externalIPAddress), LOCAL_UPNP);
}
else
LogPrintf("UPnP: GetExternalIPAddress failed.\n");
}
}
string strDesc = "Bitcoin " + FormatFullVersion();
try {
while (true) {
#ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */
r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0);
#else
/* miniupnpc 1.6 */
r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0");
#endif
if(r!=UPNPCOMMAND_SUCCESS)
LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
port, port, lanaddr, r, strupnperror(r));
else
LogPrintf("UPnP Port Mapping successful.\n");;
MilliSleep(20*60*1000); // Refresh every 20 minutes
}
}
catch (const boost::thread_interrupted&)
{
r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0);
LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r);
freeUPNPDevlist(devlist); devlist = 0;
FreeUPNPUrls(&urls);
throw;
}
} else {
LogPrintf("No valid UPnP IGDs found\n");
freeUPNPDevlist(devlist); devlist = 0;
if (r != 0)
FreeUPNPUrls(&urls);
}
}
void MapPort(bool fUseUPnP)
{
static boost::thread* upnp_thread = NULL;
if (fUseUPnP)
{
if (upnp_thread) {
upnp_thread->interrupt();
upnp_thread->join();
delete upnp_thread;
}
upnp_thread = new boost::thread(boost::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort));
}
else if (upnp_thread) {
upnp_thread->interrupt();
upnp_thread->join();
delete upnp_thread;
upnp_thread = NULL;
}
}
#else
void MapPort(bool)
{
// Intentionally left blank.
}
#endif
void ThreadDNSAddressSeed()
{
// goal: only query DNS seeds if address need is acute
@@ -1769,7 +1663,7 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste
{
int nErr = WSAGetLastError();
if (nErr == WSAEADDRINUSE)
strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin Core is probably already running."), addrBind.ToString());
strError = strprintf(_("Unable to bind to %s on this computer. Zcash is probably already running."), addrBind.ToString());
else
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
LogPrintf("%s\n", strError);
@@ -1880,9 +1774,6 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
else
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "dnsseed", &ThreadDNSAddressSeed));
// Map ports with UPnP
MapPort(GetBoolArg("-upnp", DEFAULT_UPNP));
// Send and receive from sockets, accept connections
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "net", &ThreadSocketHandler));
@@ -1902,7 +1793,6 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
bool StopNode()
{
LogPrintf("StopNode()\n");
MapPort(false);
if (semOutbound)
for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
semOutbound->post();

View File

@@ -51,18 +51,14 @@ static const unsigned int MAX_ADDR_TO_SEND = 1000;
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 2 * 1024 * 1024;
/** -listen default */
static const bool DEFAULT_LISTEN = true;
/** -upnp default */
#ifdef USE_UPNP
static const bool DEFAULT_UPNP = USE_UPNP;
#else
static const bool DEFAULT_UPNP = false;
#endif
/** The maximum number of entries in mapAskFor */
static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ;
/** The maximum number of entries in setAskFor (larger due to getdata latency)*/
static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ;
/** The maximum number of peer connections to maintain. */
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
/** The period before a network upgrade activates, where connections to upgrading peers are preferred (in blocks). */
static const int NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD = 24 * 24 * 3;
unsigned int ReceiveFloodSize();
unsigned int SendBufferSize();
@@ -75,7 +71,6 @@ CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL);
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler);
@@ -118,7 +113,7 @@ enum
LOCAL_NONE, // unknown
LOCAL_IF, // address a local interface listens on
LOCAL_BIND, // address explicit bound to
LOCAL_UPNP, // address reported by UPnP
LOCAL_UPNP, // unused (was: address reported by UPnP)
LOCAL_MANUAL, // address explicitly specified (-externalip=)
LOCAL_MAX

View File

@@ -146,7 +146,7 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
return false;
do {
// Should set the timeout limit to a resonable value to avoid
// Should set the timeout limit to a reasonable value to avoid
// generating unnecessary checking call during the polling loop,
// while it can still response to stop request quick enough.
// 2 seconds looks fine in our situation.

View File

@@ -61,7 +61,7 @@ class CNetAddr
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor)
bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
bool IsRFC2544() const; // IPv4 inter-network communcations (192.18.0.0/15)
bool IsRFC2544() const; // IPv4 inter-network communications (192.18.0.0/15)
bool IsRFC6598() const; // IPv4 ISP-level NAT (100.64.0.0/10)
bool IsRFC5737() const; // IPv4 documentation addresses (192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24)
bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32)

View File

@@ -1,2 +0,0 @@
*
!.gitignore

63
src/paymentdisclosure.cpp Normal file
View File

@@ -0,0 +1,63 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "paymentdisclosure.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());
}
std::string PaymentDisclosure::ToString() const {
std::string s = HexStr(payloadSig.begin(), payloadSig.end());
return strprintf("PaymentDisclosure(payload=%s, payloadSig=%s)", payload.ToString(), s);
}
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);
}
PaymentDisclosure::PaymentDisclosure(const uint256 &joinSplitPubKey, const PaymentDisclosureKey &key, const PaymentDisclosureInfo &info, const std::string &message)
{
// Populate payload member variable
payload.version = info.version; // experimental = 0, production = 1 etc.
payload.esk = info.esk;
payload.txid = key.hash;
payload.js = key.js;
payload.n = key.n;
payload.zaddr = info.zaddr;
payload.message = message;
// Serialize and hash the payload to generate a signature
uint256 dataToBeSigned = SerializeHash(payload, SER_GETHASH, 0);
LogPrint("paymentdisclosure", "Payment Disclosure: signing raw payload = %s\n", dataToBeSigned.ToString());
// Prepare buffer to store ed25519 key pair in libsodium-compatible format
unsigned char bufferKeyPair[64];
memcpy(&bufferKeyPair[0], info.joinSplitPrivKey.begin(), 32);
memcpy(&bufferKeyPair[32], joinSplitPubKey.begin(), 32);
// Compute payload signature member variable
if (!(crypto_sign_detached(payloadSig.data(), NULL,
dataToBeSigned.begin(), 32,
&bufferKeyPair[0]
) == 0))
{
throw std::runtime_error("crypto_sign_detached failed");
}
// Sanity check
if (!(crypto_sign_verify_detached(payloadSig.data(),
dataToBeSigned.begin(), 32,
joinSplitPubKey.begin()) == 0))
{
throw std::runtime_error("crypto_sign_verify_detached failed");
}
std::string sigString = HexStr(payloadSig.data(), payloadSig.data() + payloadSig.size());
LogPrint("paymentdisclosure", "Payment Disclosure: signature = %s\n", sigString);
}

147
src/paymentdisclosure.h Normal file
View File

@@ -0,0 +1,147 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef ZCASH_PAYMENTDISCLOSURE_H
#define ZCASH_PAYMENTDISCLOSURE_H
#include "uint256.h"
#include "clientversion.h"
#include "serialize.h"
#include "streams.h"
#include "version.h"
// For JSOutPoint
#include "wallet/wallet.h"
#include <cstdint>
#include <string>
// Ensure that the two different protocol messages, payment disclosure blobs and transactions,
// which are signed with the same key, joinSplitPrivKey, have disjoint encodings such that an
// encoding from one context will be rejected in the other. We know that the set of valid
// transaction versions is currently ({1..INT32_MAX}) so we will use a negative value for
// payment disclosure of -10328976 which in hex is 0xFF626470. Serialization is in little endian
// format, so a payment disclosure hex string begins 706462FF, which in ISO-8859-1 is "pdbÿ".
#define PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES -10328976
#define PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL 0
#define PAYMENT_DISCLOSURE_BLOB_STRING_PREFIX "zpd:"
typedef JSOutPoint PaymentDisclosureKey;
struct PaymentDisclosureInfo {
uint8_t version; // 0 = experimental, 1 = first production version, etc.
uint256 esk; // zcash/NoteEncryption.cpp
uint256 joinSplitPrivKey; // primitives/transaction.h
// ed25519 - not tied to implementation e.g. libsodium, see ed25519 rfc
libzcash::PaymentAddress 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) { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(version);
READWRITE(esk);
READWRITE(joinSplitPrivKey);
READWRITE(zaddr);
}
std::string ToString() const;
friend bool operator==(const PaymentDisclosureInfo& a, const PaymentDisclosureInfo& b) {
return (a.version == b.version && a.esk == b.esk && a.joinSplitPrivKey == b.joinSplitPrivKey && a.zaddr == b.zaddr);
}
friend bool operator!=(const PaymentDisclosureInfo& a, const PaymentDisclosureInfo& b) {
return !(a == b);
}
};
struct PaymentDisclosurePayload {
int32_t marker = PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES; // to be disjoint from transaction encoding
uint8_t version; // 0 = experimental, 1 = first production version, etc.
uint256 esk; // zcash/NoteEncryption.cpp
uint256 txid; // primitives/transaction.h
size_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
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) {
READWRITE(marker);
READWRITE(version);
READWRITE(esk);
READWRITE(txid);
READWRITE(js);
READWRITE(n);
READWRITE(zaddr);
READWRITE(message);
}
std::string ToString() const;
friend bool operator==(const PaymentDisclosurePayload& a, const PaymentDisclosurePayload& b) {
return (
a.version == b.version &&
a.esk == b.esk &&
a.txid == b.txid &&
a.js == b.js &&
a.n == b.n &&
a.zaddr == b.zaddr &&
a.message == b.message
);
}
friend bool operator!=(const PaymentDisclosurePayload& a, const PaymentDisclosurePayload& b) {
return !(a == b);
}
};
struct PaymentDisclosure {
PaymentDisclosurePayload payload;
boost::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 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) {
READWRITE(payload);
READWRITE(payloadSig);
}
std::string ToString() const;
friend bool operator==(const PaymentDisclosure& a, const PaymentDisclosure& b) {
return (a.payload == b.payload && a.payloadSig == b.payloadSig);
}
friend bool operator!=(const PaymentDisclosure& a, const PaymentDisclosure& b) {
return !(a == b);
}
};
typedef std::pair<PaymentDisclosureKey, PaymentDisclosureInfo> PaymentDisclosureKeyInfo;
#endif // ZCASH_PAYMENTDISCLOSURE_H

View File

@@ -0,0 +1,93 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "paymentdisclosuredb.h"
#include "util.h"
#include "leveldbwrapper.h"
#include <boost/filesystem.hpp>
using namespace std;
static boost::filesystem::path emptyPath;
/**
* Static method to return the shared/default payment disclosure database.
*/
shared_ptr<PaymentDisclosureDB> PaymentDisclosureDB::sharedInstance() {
// Thread-safe in C++11 and gcc 4.3
static shared_ptr<PaymentDisclosureDB> ptr = std::make_shared<PaymentDisclosureDB>();
return ptr;
}
// C++11 delegated constructor
PaymentDisclosureDB::PaymentDisclosureDB() : PaymentDisclosureDB(emptyPath) {
}
PaymentDisclosureDB::PaymentDisclosureDB(const boost::filesystem::path& dbPath) {
boost::filesystem::path path(dbPath);
if (path.empty()) {
path = GetDataDir() / "paymentdisclosure";
LogPrintf("PaymentDisclosure: using default path for database: %s\n", path.string());
} else {
LogPrintf("PaymentDisclosure: using custom path for database: %s\n", path.string());
}
TryCreateDirectory(path);
options.create_if_missing = true;
leveldb::Status status = leveldb::DB::Open(options, path.string(), &db);
HandleError(status); // throws exception
LogPrintf("PaymentDisclosure: Opened LevelDB successfully\n");
}
PaymentDisclosureDB::~PaymentDisclosureDB() {
if (db != nullptr) {
delete db;
}
}
bool PaymentDisclosureDB::Put(const PaymentDisclosureKey& key, const PaymentDisclosureInfo& info)
{
if (db == nullptr) {
return false;
}
std::lock_guard<std::mutex> guard(lock_);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
ssValue.reserve(ssValue.GetSerializeSize(info));
ssValue << info;
leveldb::Slice slice(&ssValue[0], ssValue.size());
leveldb::Status status = db->Put(writeOptions, key.ToString(), slice);
HandleError(status);
return true;
}
bool PaymentDisclosureDB::Get(const PaymentDisclosureKey& key, PaymentDisclosureInfo& info)
{
if (db == nullptr) {
return false;
}
std::lock_guard<std::mutex> guard(lock_);
std::string strValue;
leveldb::Status status = db->Get(readOptions, key.ToString(), &strValue);
if (!status.ok()) {
if (status.IsNotFound())
return false;
LogPrintf("PaymentDisclosure: LevelDB read failure: %s\n", status.ToString());
HandleError(status);
}
try {
CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
ssValue >> info;
} catch (const std::exception&) {
return false;
}
return true;
}

42
src/paymentdisclosuredb.h Normal file
View File

@@ -0,0 +1,42 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef ZCASH_PAYMENTDISCLOSUREDB_H
#define ZCASH_PAYMENTDISCLOSUREDB_H
#include "paymentdisclosure.h"
#include <cstdint>
#include <string>
#include <mutex>
#include <future>
#include <memory>
#include <boost/optional.hpp>
#include <leveldb/db.h>
class PaymentDisclosureDB
{
protected:
leveldb::DB* db = nullptr;
leveldb::Options options;
leveldb::ReadOptions readOptions;
leveldb::WriteOptions writeOptions;
mutable std::mutex lock_;
public:
static std::shared_ptr<PaymentDisclosureDB> sharedInstance();
PaymentDisclosureDB();
PaymentDisclosureDB(const boost::filesystem::path& dbPath);
~PaymentDisclosureDB();
bool Put(const PaymentDisclosureKey& key, const PaymentDisclosureInfo& info);
bool Get(const PaymentDisclosureKey& key, PaymentDisclosureInfo& info);
};
#endif // ZCASH_PAYMENTDISCLOSUREDB_H

View File

@@ -16,14 +16,12 @@ void TxConfirmStats::Initialize(std::vector<double>& defaultBuckets,
{
decay = _decay;
dataTypeString = _dataTypeString;
//for (unsigned int i = 0; i < defaultBuckets.size(); i++) {
// buckets.push_back(defaultBuckets[i]);
// bucketMap[defaultBuckets[i]] = i;
buckets.insert(buckets.end(), defaultBuckets.begin(), defaultBuckets.end());
buckets.push_back(std::numeric_limits<double>::infinity());
for (unsigned int i = 0; i < buckets.size(); i++) {
bucketMap[buckets[i]] = i;
}
confAvg.resize(maxConfirms);
curBlockConf.resize(maxConfirms);
unconfTxs.resize(maxConfirms);
@@ -57,7 +55,6 @@ unsigned int TxConfirmStats::FindBucketIndex(double val)
{
extern char ASSETCHAINS_SYMBOL[];
auto it = bucketMap.lower_bound(val);
//assert(it != bucketMap.end());
if ( it != bucketMap.end() )
{
static uint32_t counter;
@@ -72,7 +69,6 @@ void TxConfirmStats::Record(int blocksToConfirm, double val)
// blocksToConfirm is 1-based
if (blocksToConfirm < 1)
return;
//unsigned int bucketindex = bucketMap.lower_bound(val)->second;
unsigned int bucketindex = FindBucketIndex(val);
for (size_t i = blocksToConfirm; i <= curBlockConf.size(); i++) {
curBlockConf[i - 1][bucketindex]++;
@@ -264,7 +260,6 @@ void TxConfirmStats::Read(CAutoFile& filein)
unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
{
//unsigned int bucketindex = bucketMap.lower_bound(val)->second;
unsigned int bucketindex = FindBucketIndex(val);
unsigned int blockIndex = nBlockHeight % unconfTxs.size();
unconfTxs[blockIndex][bucketindex]++;
@@ -325,7 +320,6 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee)
for (double bucketBoundary = minTrackedFee.GetFeePerK(); bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) {
vfeelist.push_back(bucketBoundary);
}
//vfeelist.push_back(INF_FEERATE);
feeStats.Initialize(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY, "FeeRate");
minTrackedPriority = AllowFreeThreshold() < MIN_PRIORITY ? MIN_PRIORITY : AllowFreeThreshold();
@@ -333,7 +327,6 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee)
for (double bucketBoundary = minTrackedPriority; bucketBoundary <= MAX_PRIORITY; bucketBoundary *= PRI_SPACING) {
vprilist.push_back(bucketBoundary);
}
//vprilist.push_back(INF_PRIORITY);
priStats.Initialize(vprilist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY, "Priority");
feeUnlikely = CFeeRate(0);

View File

@@ -28,7 +28,7 @@ class CTxMemPoolEntry;
* included in blocks before transactions of lower fee/priority. So for
* example if you wanted to know what fee you should put on a transaction to
* be included in a block within the next 5 blocks, you would start by looking
* at the bucket with with the highest fee transactions and verifying that a
* at the bucket with the highest fee transactions and verifying that a
* sufficiently high percentage of them were confirmed within 5 blocks and
* then you would look at the next highest fee bucket, and so on, stopping at
* the last bucket to pass the test. The average fee of transactions in this
@@ -71,7 +71,7 @@ static const double DEFAULT_DECAY = .998;
/**
* We will instantiate two instances of this class, one to track transactions
* that were included in a block due to fee, and one for tx's included due to
* that were included in a block due to fee, and one for txs included due to
* priority. We will lump transactions into a bucket according to their approximate
* fee or priority and then track how long it took for those txs to be included
* in a block. There is always a bucket into which any given double value
@@ -100,7 +100,7 @@ private:
// and calcuate the totals for the current block to update the moving averages
std::vector<std::vector<int> > curBlockConf; // curBlockConf[Y][X]
// Sum the total priority/fee of all tx's in each bucket
// Sum the total priority/fee of all txs in each bucket
// Track the historical moving average of this total over blocks
std::vector<double> avg;
// and calculate the total for the current block to update the moving average
@@ -214,7 +214,7 @@ static const double FEE_SPACING = 1.1;
static const double PRI_SPACING = 2;
/**
* We want to be able to estimate fees or priorities that are needed on tx's to be included in
* We want to be able to estimate fees or priorities that are needed on txs to be included in
* a certain number of blocks. Every time a block is added to the best chain, this class records
* stats on the transactions included in that block
*/

View File

@@ -3,7 +3,7 @@
// Fix N, K, such that n = N/(k+1) is integer
// Fix M = 2^{n+1} hashes each of length N bits,
// H_0, ... , H_{M-1}, generated fom (n+1)-bit indices.
// H_0, ... , H_{M-1}, generated from (n+1)-bit indices.
// Problem: find binary tree on 2^K distinct indices,
// for which the exclusive-or of leaf hashes is all 0s.
// Additionally, it should satisfy the Wagner conditions:

View File

@@ -16,13 +16,12 @@ JSDescription::JSDescription(ZCJoinSplit& params,
const boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
CAmount vpub_old,
CAmount vpub_new,
bool computeProof) : vpub_old(vpub_old), vpub_new(vpub_new), anchor(anchor)
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;
if (computeProof) {
params.loadProvingKey();
}
proof = params.prove(
inputs,
outputs,
@@ -37,7 +36,8 @@ JSDescription::JSDescription(ZCJoinSplit& params,
vpub_old,
vpub_new,
anchor,
computeProof
computeProof,
esk // payment disclosure
);
}
@@ -57,7 +57,9 @@ JSDescription JSDescription::Randomized(
CAmount vpub_old,
CAmount vpub_new,
bool computeProof,
std::function<int(int)> gen)
uint256 *esk, // payment disclosure
std::function<int(int)> gen
)
{
// Randomize the order of the inputs and outputs
inputMap = {0, 1};
@@ -70,7 +72,9 @@ JSDescription JSDescription::Randomized(
return JSDescription(
params, pubKeyHash, anchor, inputs, outputs,
vpub_old, vpub_new, computeProof);
vpub_old, vpub_new, computeProof,
esk // payment disclosure
);
}
bool JSDescription::Verify(
@@ -147,8 +151,9 @@ std::string CTxOut::ToString() const
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30));
}
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::MIN_CURRENT_VERSION), nLockTime(0) {}
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime),
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::SPROUT_MIN_CURRENT_VERSION), fOverwintered(false), nVersionGroupId(0), nExpiryHeight(0), nLockTime(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)
{
@@ -164,19 +169,34 @@ void CTransaction::UpdateHash() const
*const_cast<uint256*>(&hash) = SerializeHash(*this);
}
CTransaction::CTransaction() : nVersion(CTransaction::MIN_CURRENT_VERSION), 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), vjoinsplit(), joinSplitPubKey(), joinSplitSig() { }
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), vjoinsplit(tx.vjoinsplit),
joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
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)
{
UpdateHash();
}
// Protected constructor which only derived classes can call.
// For developer testing only.
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)
{
assert(evilDeveloperFlag);
}
CTransaction& CTransaction::operator=(const CTransaction &tx) {
*const_cast<bool*>(&fOverwintered) = tx.fOverwintered;
*const_cast<int*>(&nVersion) = tx.nVersion;
*const_cast<uint32_t*>(&nVersionGroupId) = tx.nVersionGroupId;
*const_cast<std::vector<CTxIn>*>(&vin) = tx.vin;
*const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
*const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
*const_cast<uint32_t*>(&nExpiryHeight) = tx.nExpiryHeight;
*const_cast<std::vector<JSDescription>*>(&vjoinsplit) = tx.vjoinsplit;
*const_cast<uint256*>(&joinSplitPubKey) = tx.joinSplitPubKey;
*const_cast<joinsplit_sig_t*>(&joinSplitSig) = tx.joinSplitSig;
@@ -249,12 +269,24 @@ unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const
std::string CTransaction::ToString() const
{
std::string str;
str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n",
GetHash().ToString().substr(0,10),
nVersion,
vin.size(),
vout.size(),
nLockTime);
if (!fOverwintered) {
str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n",
GetHash().ToString().substr(0,10),
nVersion,
vin.size(),
vout.size(),
nLockTime);
} 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),
nVersion,
fOverwintered,
nVersionGroupId,
vin.size(),
vout.size(),
nLockTime,
nExpiryHeight);
}
for (unsigned int i = 0; i < vin.size(); i++)
str += " " + vin[i].ToString() + "\n";
for (unsigned int i = 0; i < vout.size(); i++)

View File

@@ -81,7 +81,8 @@ public:
const boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
CAmount vpub_old,
CAmount vpub_new,
bool computeProof = true // Set to false in some tests
bool computeProof = true, // Set to false in some tests
uint256 *esk = nullptr // payment disclosure
);
static JSDescription Randomized(
@@ -100,6 +101,7 @@ public:
CAmount vpub_old,
CAmount vpub_new,
bool computeProof = true, // Set to false in some tests
uint256 *esk = nullptr, // payment disclosure
std::function<int(int)> gen = GetRandInt
);
@@ -310,6 +312,10 @@ public:
std::string ToString() const;
};
// Overwinter version group id
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");
struct CMutableTransaction;
/** The basic transaction that is broadcasted on the network and contained in
@@ -322,14 +328,29 @@ private:
const uint256 hash;
void UpdateHash() const;
protected:
/** Developer testing only. Set evilDeveloperFlag to true.
* Convert a CMutableTransaction into a CTransaction without invoking UpdateHash()
*/
CTransaction(const CMutableTransaction &tx, bool evilDeveloperFlag);
public:
typedef boost::array<unsigned char, 64> joinsplit_sig_t;
// Transactions that include a list of JoinSplits are version 2.
static const int32_t MIN_CURRENT_VERSION = 1;
static const int32_t MAX_CURRENT_VERSION = 2;
// 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_assert(MIN_CURRENT_VERSION >= MIN_TX_VERSION,
static_assert(SPROUT_MIN_CURRENT_VERSION >= SPROUT_MIN_TX_VERSION,
"standard rule for tx version should be consistent with network rule");
static_assert(OVERWINTER_MIN_CURRENT_VERSION >= OVERWINTER_MIN_TX_VERSION,
"standard rule for tx version should be consistent with network rule");
static_assert( (OVERWINTER_MAX_CURRENT_VERSION <= OVERWINTER_MAX_TX_VERSION &&
OVERWINTER_MAX_CURRENT_VERSION >= OVERWINTER_MIN_CURRENT_VERSION),
"standard rule for tx version should be consistent with network rule");
// The local variables are made const to prevent unintended modification
@@ -337,10 +358,13 @@ public:
// actually immutable; deserialization and assignment are implemented,
// and bypass the constness. This is safe, as they update the entire
// structure, including the hash.
const bool fOverwintered;
const int32_t nVersion;
const uint32_t nVersionGroupId;
const std::vector<CTxIn> vin;
const std::vector<CTxOut> vout;
const uint32_t nLockTime;
const uint32_t nExpiryHeight;
const std::vector<JSDescription> vjoinsplit;
const uint256 joinSplitPubKey;
const joinsplit_sig_t joinSplitSig = {{0}};
@@ -357,11 +381,34 @@ public:
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(*const_cast<int32_t*>(&this->nVersion));
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();
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) {
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) {
READWRITE(*const_cast<uint32_t*>(&nExpiryHeight));
}
if (nVersion >= 2) {
READWRITE(*const_cast<std::vector<JSDescription>*>(&vjoinsplit));
if (vjoinsplit.size() > 0) {
@@ -381,6 +428,16 @@ public:
return hash;
}
uint32_t GetHeader() const {
// When serializing v1 and v2, the 4 byte header is nVersion
uint32_t header = this->nVersion;
// When serializing Overwintered tx, the 4 byte header is the combination of fOverwintered and nVersion
if (fOverwintered) {
header |= 1 << 31;
}
return header;
}
// Return sum of txouts.
CAmount GetValueOut() const;
// GetValueIn() is a method on CCoinsViewCache, because
@@ -416,10 +473,13 @@ public:
/** A mutable version of CTransaction. */
struct CMutableTransaction
{
bool fOverwintered;
int32_t nVersion;
uint32_t nVersionGroupId;
std::vector<CTxIn> vin;
std::vector<CTxOut> vout;
uint32_t nLockTime;
uint32_t nExpiryHeight;
std::vector<JSDescription> vjoinsplit;
uint256 joinSplitPubKey;
CTransaction::joinsplit_sig_t joinSplitSig = {{0}};
@@ -431,11 +491,39 @@ struct CMutableTransaction
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(this->nVersion);
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;
// 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) {
throw std::ios_base::failure("Unknown transaction format");
}
READWRITE(vin);
READWRITE(vout);
READWRITE(nLockTime);
if (isOverwinterV3) {
READWRITE(nExpiryHeight);
}
if (nVersion >= 2) {
READWRITE(vjoinsplit);
if (vjoinsplit.size() > 0) {

View File

@@ -71,10 +71,6 @@ enum {
// set by all Bitcoin Core nodes, and is unset by SPV clients or other peers that just want
// network services but don't provide them.
NODE_NETWORK = (1 << 0),
// NODE_GETUTXO means the node is capable of responding to the getutxo protocol request.
// Bitcoin Core does not support this but a patch set called Bitcoin XT does.
// See BIP 64 for details on how this is implemented.
NODE_GETUTXO = (1 << 1),
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
// isn't getting used, or one not being used much, and notify the

View File

@@ -1,73 +1,101 @@
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "pubkey.h"
#include "eccryptoverify.h"
#include <secp256k1.h>
#include <secp256k1_recovery.h>
namespace
{
/* Global secp256k1_context object used for verification. */
secp256k1_context* secp256k1_context_verify = NULL;
}
#include "ecwrapper.h"
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
if (!IsValid())
return false;
CECKey key;
if (!key.SetPubKey(begin(), size()))
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
return false;
if (!key.Verify(hash, vchSig))
}
if (vchSig.size() == 0) {
return false;
return true;
}
/* Zcash, unlike Bitcoin, has always enforced strict DER signatures. */
if (!secp256k1_ecdsa_signature_parse_der(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {
return false;
}
/* libsecp256k1's ECDSA verification requires lower-S signatures, which have
* not historically been enforced in Bitcoin or Zcash, so normalize them first. */
secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, &sig, &sig);
return secp256k1_ecdsa_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey);
}
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
if (vchSig.size() != 65)
if (vchSig.size() != COMPACT_SIGNATURE_SIZE)
return false;
int recid = (vchSig[0] - 27) & 3;
bool fComp = ((vchSig[0] - 27) & 4) != 0;
CECKey key;
if (!key.Recover(hash, &vchSig[1], recid))
secp256k1_pubkey pubkey;
secp256k1_ecdsa_recoverable_signature sig;
if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_verify, &sig, &vchSig[1], recid)) {
return false;
std::vector<unsigned char> pubkey;
key.GetPubKey(pubkey, fComp);
Set(pubkey.begin(), pubkey.end());
}
if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) {
return false;
}
unsigned char pub[PUBLIC_KEY_SIZE];
size_t publen = PUBLIC_KEY_SIZE;
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
Set(pub, pub + publen);
return true;
}
bool CPubKey::IsFullyValid() const {
if (!IsValid())
return false;
CECKey key;
if (!key.SetPubKey(begin(), size()))
return false;
return true;
secp256k1_pubkey pubkey;
return secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size());
}
bool CPubKey::Decompress() {
if (!IsValid())
return false;
CECKey key;
if (!key.SetPubKey(begin(), size()))
secp256k1_pubkey pubkey;
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
return false;
std::vector<unsigned char> pubkey;
key.GetPubKey(pubkey, false);
Set(pubkey.begin(), pubkey.end());
}
unsigned char pub[PUBLIC_KEY_SIZE];
size_t publen = PUBLIC_KEY_SIZE;
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
Set(pub, pub + publen);
return true;
}
bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {
assert(IsValid());
assert((nChild >> 31) == 0);
assert(begin() + 33 == end());
assert(size() == COMPRESSED_PUBLIC_KEY_SIZE);
unsigned char out[64];
BIP32Hash(cc, nChild, *begin(), begin()+1, out);
memcpy(ccChild.begin(), out+32, 32);
CECKey key;
bool ret = key.SetPubKey(begin(), size());
ret &= key.TweakPublic(out);
std::vector<unsigned char> pubkey;
key.GetPubKey(pubkey, true);
pubkeyChild.Set(pubkey.begin(), pubkey.end());
return ret;
secp256k1_pubkey pubkey;
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
return false;
}
if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) {
return false;
}
unsigned char pub[COMPRESSED_PUBLIC_KEY_SIZE];
size_t publen = COMPRESSED_PUBLIC_KEY_SIZE;
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED);
pubkeyChild.Set(pub, pub + publen);
return true;
}
void CExtPubKey::Encode(unsigned char code[74]) const {
@@ -76,8 +104,8 @@ void CExtPubKey::Encode(unsigned char code[74]) const {
code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF;
memcpy(code+9, chaincode.begin(), 32);
assert(pubkey.size() == 33);
memcpy(code+41, pubkey.begin(), 33);
assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
}
void CExtPubKey::Decode(const unsigned char code[74]) {
@@ -95,3 +123,35 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const {
out.nChild = nChild;
return pubkey.Derive(out.pubkey, out.chaincode, nChild, chaincode);
}
/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {
secp256k1_ecdsa_signature sig;
/* Zcash, unlike Bitcoin, has always enforced strict DER signatures. */
if (!secp256k1_ecdsa_signature_parse_der(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {
return false;
}
return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, NULL, &sig));
}
/* static */ int ECCVerifyHandle::refcount = 0;
ECCVerifyHandle::ECCVerifyHandle()
{
if (refcount == 0) {
assert(secp256k1_context_verify == NULL);
secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
assert(secp256k1_context_verify != NULL);
}
refcount++;
}
ECCVerifyHandle::~ECCVerifyHandle()
{
refcount--;
if (refcount == 0) {
assert(secp256k1_context_verify != NULL);
secp256k1_context_destroy(secp256k1_context_verify);
secp256k1_context_verify = NULL;
}
}

View File

@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,16 +14,6 @@
#include <stdexcept>
#include <vector>
/**
* secp256k1:
* const unsigned int PRIVATE_KEY_SIZE = 279;
* const unsigned int PUBLIC_KEY_SIZE = 65;
* const unsigned int SIGNATURE_SIZE = 72;
*
* see www.keylength.com
* script supports up to 75 for single byte push
*/
/** A reference to a CKey: the Hash160 of its serialized public key */
class CKeyID : public uint160
{
@@ -36,21 +27,37 @@ typedef uint256 ChainCode;
/** An encapsulated public key. */
class CPubKey
{
public:
/**
* secp256k1:
*/
static const unsigned int PUBLIC_KEY_SIZE = 65;
static const unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33;
static const unsigned int SIGNATURE_SIZE = 72;
static const unsigned int COMPACT_SIGNATURE_SIZE = 65;
/**
* see www.keylength.com
* script supports up to 75 for single byte push
*/
static_assert(
PUBLIC_KEY_SIZE >= COMPRESSED_PUBLIC_KEY_SIZE,
"COMPRESSED_PUBLIC_KEY_SIZE is larger than PUBLIC_KEY_SIZE");
private:
/**
* Just store the serialized data.
* Its length can very cheaply be computed from the first byte.
*/
unsigned char vch[65];
unsigned char vch[PUBLIC_KEY_SIZE];
//! Compute the length of a pubkey with a given first byte.
unsigned int static GetLen(unsigned char chHeader)
{
if (chHeader == 2 || chHeader == 3)
return 33;
return COMPRESSED_PUBLIC_KEY_SIZE;
if (chHeader == 4 || chHeader == 6 || chHeader == 7)
return 65;
return PUBLIC_KEY_SIZE;
return 0;
}
@@ -129,7 +136,7 @@ public:
void Unserialize(Stream& s, int nType, int nVersion)
{
unsigned int len = ::ReadCompactSize(s);
if (len <= 65) {
if (len <= PUBLIC_KEY_SIZE) {
s.read((char*)vch, len);
} else {
// invalid pubkey, skip available data
@@ -168,7 +175,7 @@ public:
//! Check whether this is a compressed public key.
bool IsCompressed() const
{
return size() == 33;
return size() == COMPRESSED_PUBLIC_KEY_SIZE;
}
/**
@@ -177,6 +184,11 @@ public:
*/
bool Verify(const uint256& hash, const std::vector<unsigned char>& vchSig) const;
/**
* Check whether a signature is normalized (lower-S).
*/
static bool CheckLowS(const std::vector<unsigned char>& vchSig);
//! Recover a public key from a compact signature.
bool RecoverCompact(const uint256& hash, const std::vector<unsigned char>& vchSig);
@@ -205,4 +217,15 @@ struct CExtPubKey {
bool Derive(CExtPubKey& out, unsigned int nChild) const;
};
/** Users of this module must hold an ECCVerifyHandle. The constructor and
* destructor of these are not allowed to run in parallel, though. */
class ECCVerifyHandle
{
static int refcount;
public:
ECCVerifyHandle();
~ECCVerifyHandle();
};
#endif // BITCOIN_PUBKEY_H

View File

@@ -405,7 +405,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
boost::split(uriParts, strUriParams, boost::is_any_of("/"));
}
// throw exception in case of a empty request
// throw exception in case of an empty request
std::string strRequestMutable = req->ReadBody();
if (strRequestMutable.length() == 0 && uriParts.size() == 0)
return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
@@ -485,7 +485,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS)
return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
// check spentness and form a bitmap (as well as a JSON capable human-readble string representation)
// check spentness and form a bitmap (as well as a JSON capable human-readable string representation)
vector<unsigned char> bitmap;
vector<CCoin> outs;
std::string bitmapStringRepresentation;

View File

@@ -15,10 +15,12 @@ public:
explicit reverse_lock(Lock& lock) : lock(lock) {
lock.unlock();
lock.swap(templock);
}
~reverse_lock() noexcept(false) {
lock.lock();
~reverse_lock() {
templock.lock();
templock.swap(lock);
}
private:
@@ -26,6 +28,7 @@ private:
reverse_lock& operator=(reverse_lock const&);
Lock& lock;
Lock templock;
};
#endif // BITCOIN_REVERSELOCK_H

View File

@@ -3,6 +3,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "amount.h"
#include "chain.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "consensus/validation.h"
#include "main.h"
@@ -74,6 +77,25 @@ double GetNetworkDifficulty(const CBlockIndex* blockindex)
return GetDifficultyINTERNAL(blockindex, true);
}
static UniValue ValuePoolDesc(
const std::string &name,
const boost::optional<CAmount> chainValue,
const boost::optional<CAmount> valueDelta)
{
UniValue rv(UniValue::VOBJ);
rv.push_back(Pair("id", name));
rv.push_back(Pair("monitored", (bool)chainValue));
if (chainValue) {
rv.push_back(Pair("chainValue", ValueFromAmount(*chainValue)));
rv.push_back(Pair("chainValueZat", *chainValue));
}
if (valueDelta) {
rv.push_back(Pair("valueDelta", ValueFromAmount(*valueDelta)));
rv.push_back(Pair("valueDeltaZat", *valueDelta));
}
return rv;
}
UniValue blockheaderToJSON(const CBlockIndex* blockindex)
{
UniValue result(UniValue::VOBJ);
@@ -135,6 +157,10 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
result.push_back(Pair("anchor", blockindex->hashAnchorEnd.GetHex()));
UniValue valuePools(UniValue::VARR);
valuePools.push_back(ValuePoolDesc("sprout", blockindex->nChainSproutValue, blockindex->nSproutValue));
result.push_back(Pair("valuePools", valuePools));
if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
CBlockIndex *pnext = chainActive.Next(blockindex);
@@ -148,7 +174,7 @@ UniValue getblockcount(const UniValue& params, bool fHelp)
if (fHelp || params.size() != 0)
throw runtime_error(
"getblockcount\n"
"\nReturns the number of blocks in the longest block chain.\n"
"\nReturns the number of blocks in the best valid block chain.\n"
"\nResult:\n"
"n (numeric) The current block count\n"
"\nExamples:\n"
@@ -200,10 +226,9 @@ UniValue mempoolToJSON(bool fVerbose = false)
{
LOCK(mempool.cs);
UniValue o(UniValue::VOBJ);
BOOST_FOREACH(const PAIRTYPE(uint256, CTxMemPoolEntry)& entry, mempool.mapTx)
BOOST_FOREACH(const CTxMemPoolEntry& e, mempool.mapTx)
{
const uint256& hash = entry.first;
const CTxMemPoolEntry& e = entry.second;
const uint256& hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
info.push_back(Pair("size", (int)e.GetTxSize()));
info.push_back(Pair("fee", ValueFromAmount(e.GetFee())));
@@ -260,7 +285,7 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
"{ (json object)\n"
" \"transactionid\" : { (json object)\n"
" \"size\" : n, (numeric) transaction size in bytes\n"
" \"fee\" : n, (numeric) transaction fee in bitcoins\n"
" \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n"
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
" \"height\" : n, (numeric) block height when transaction entered pool\n"
" \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"
@@ -829,24 +854,24 @@ UniValue gettxout(const UniValue& params, bool fHelp)
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
"2. n (numeric, required) vout value\n"
"3. includemempool (boolean, optional) Whether to included the mem pool\n"
"3. includemempool (boolean, optional) Whether to include the mempool\n"
"\nResult:\n"
"{\n"
" \"bestblock\" : \"hash\", (string) the block hash\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
" \"value\" : x.xxx, (numeric) The transaction value in btc\n"
" \"value\" : x.xxx, (numeric) The transaction value in " + CURRENCY_UNIT + "\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"code\", (string) \n"
" \"hex\" : \"hex\", (string) \n"
" \"reqSigs\" : n, (numeric) Number of required signatures\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n"
" \"addresses\" : [ (array of string) array of bitcoin addresses\n"
" \"bitcoinaddress\" (string) bitcoin address\n"
" \"addresses\" : [ (array of string) array of Zcash addresses\n"
" \"zcashaddress\" (string) Zcash address\n"
" ,...\n"
" ]\n"
" },\n"
" \"version\" : n, (numeric) The version\n"
" \"coinbase\" : true|false (boolean) Coinbase or not\n"
" \"version\" : n, (numeric) The version\n"
" \"coinbase\" : true|false (boolean) Coinbase or not\n"
"}\n"
"\nExamples:\n"
@@ -960,12 +985,45 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex*
return rv;
}
static UniValue NetworkUpgradeDesc(const Consensus::Params& consensusParams, Consensus::UpgradeIndex idx, int height)
{
UniValue rv(UniValue::VOBJ);
auto upgrade = NetworkUpgradeInfo[idx];
rv.push_back(Pair("name", upgrade.strName));
rv.push_back(Pair("activationheight", consensusParams.vUpgrades[idx].nActivationHeight));
switch (NetworkUpgradeState(height, consensusParams, idx)) {
case UPGRADE_DISABLED: rv.push_back(Pair("status", "disabled")); break;
case UPGRADE_PENDING: rv.push_back(Pair("status", "pending")); break;
case UPGRADE_ACTIVE: rv.push_back(Pair("status", "active")); break;
}
rv.push_back(Pair("info", upgrade.strInfo));
return rv;
}
void NetworkUpgradeDescPushBack(
UniValue& networkUpgrades,
const Consensus::Params& consensusParams,
Consensus::UpgradeIndex idx,
int height)
{
// Network upgrades with an activation height of NO_ACTIVATION_HEIGHT are
// hidden. This is used when network upgrade implementations are merged
// without specifying the activation height.
if (consensusParams.vUpgrades[idx].nActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) {
networkUpgrades.push_back(Pair(
HexInt(NetworkUpgradeInfo[idx].nBranchId),
NetworkUpgradeDesc(consensusParams, idx, height)));
}
}
UniValue getblockchaininfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getblockchaininfo\n"
"Returns an object containing various state info regarding block chain processing.\n"
"\nNote that when the chain tip is at the last block before a network upgrade activation,\n"
"consensus.chaintip != consensus.nextblock.\n"
"\nResult:\n"
"{\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
@@ -988,7 +1046,19 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
" },\n"
" \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
" }, ...\n"
" ]\n"
" ],\n"
" \"upgrades\": { (object) status of network upgrades\n"
" \"xxxx\" : { (string) branch ID of the upgrade\n"
" \"name\": \"xxxx\", (string) name of upgrade\n"
" \"activationheight\": xxxxxx, (numeric) block height of activation\n"
" \"status\": \"xxxx\", (string) status of upgrade\n"
" \"info\": \"xxxx\", (string) additional information about upgrade\n"
" }, ...\n"
" },\n"
" \"consensus\": { (object) branch IDs of the current and upcoming consensus rules\n"
" \"chaintip\": \"xxxxxxxx\", (string) branch ID used to validate the current chain tip\n"
" \"nextblock\": \"xxxxxxxx\" (string) branch ID that the next block will be validated under\n"
" }\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getblockchaininfo", "")
@@ -1015,14 +1085,29 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("commitments", tree.size()));
#endif
const Consensus::Params& consensusParams = Params().GetConsensus();
CBlockIndex* tip = chainActive.Tip();
UniValue valuePools(UniValue::VARR);
valuePools.push_back(ValuePoolDesc("sprout", tip->nChainSproutValue, boost::none));
obj.push_back(Pair("valuePools", valuePools));
const Consensus::Params& consensusParams = Params().GetConsensus();
UniValue softforks(UniValue::VARR);
softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
obj.push_back(Pair("softforks", softforks));
UniValue upgrades(UniValue::VOBJ);
for (int i = Consensus::UPGRADE_OVERWINTER; i < Consensus::MAX_NETWORK_UPGRADES; i++) {
NetworkUpgradeDescPushBack(upgrades, consensusParams, Consensus::UpgradeIndex(i), tip->nHeight);
}
obj.push_back(Pair("upgrades", upgrades));
UniValue consensus(UniValue::VOBJ);
consensus.push_back(Pair("chaintip", HexInt(CurrentEpochBranchId(tip->nHeight, consensusParams))));
consensus.push_back(Pair("nextblock", HexInt(CurrentEpochBranchId(tip->nHeight + 1, consensusParams))));
obj.push_back(Pair("consensus", consensus));
if (fPruneMode)
{
CBlockIndex *block = chainActive.Tip();

View File

@@ -103,12 +103,21 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "zcbenchmark", 1 },
{ "zcbenchmark", 2 },
{ "getblocksubsidy", 0},
{ "z_listreceivedbyaddress", 1},
{ "z_listaddresses", 0},
{ "z_listreceivedbyaddress", 1},
{ "z_getbalance", 1},
{ "z_gettotalbalance", 0},
{ "z_gettotalbalance", 1},
{ "z_gettotalbalance", 2},
{ "z_mergetoaddress", 0},
{ "z_mergetoaddress", 2},
{ "z_mergetoaddress", 3},
{ "z_mergetoaddress", 4},
{ "z_sendmany", 1},
{ "z_sendmany", 2},
{ "z_sendmany", 3},
{ "z_shieldcoinbase", 2},
{ "z_shieldcoinbase", 3},
{ "z_getoperationstatus", 0},
{ "z_getoperationresult", 0},
{ "z_importkey", 1 },
@@ -121,6 +130,9 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "kvsearch", 1 },
{ "kvupdate", 4 },
{ "z_importkey", 2 },
{ "z_importviewingkey", 2 },
{ "z_getpaymentdisclosure", 1},
{ "z_getpaymentdisclosure", 2}
};
class CRPCConvertTable

View File

@@ -65,7 +65,7 @@ UniValue getinfo(const UniValue& params, bool fHelp)
" \"version\": xxxxx, (numeric) the server version\n"
" \"protocolversion\": xxxxx, (numeric) the protocol version\n"
" \"walletversion\": xxxxx, (numeric) the wallet version\n"
" \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n"
" \"balance\": xxxxxxx, (numeric) the total Zcash balance of the wallet\n"
" \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
" \"connections\": xxxxx, (numeric) the number of connections\n"
@@ -75,8 +75,8 @@ UniValue getinfo(const UniValue& params, bool fHelp)
" \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
" \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
" \"paytxfee\": x.xxxx, (numeric) the transaction fee set in btc/kb\n"
" \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n"
" \"paytxfee\": x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n"
" \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n"
" \"errors\": \"...\" (string) any error messages\n"
"}\n"
"\nExamples:\n"
@@ -249,14 +249,14 @@ UniValue validateaddress(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"validateaddress \"bitcoinaddress\"\n"
"\nReturn information about the given bitcoin address.\n"
"validateaddress \"zcashaddress\"\n"
"\nReturn information about the given Zcash address.\n"
"\nArguments:\n"
"1. \"bitcoinaddress\" (string, required) The bitcoin address to validate\n"
"1. \"zcashaddress\" (string, required) The Zcash address to validate\n"
"\nResult:\n"
"{\n"
" \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
" \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n"
" \"address\" : \"zcashaddress\", (string) The Zcash address validated\n"
" \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n"
" \"ismine\" : true|false, (boolean) If the address is yours or not\n"
" \"isscript\" : true|false, (boolean) If the key is a script\n"
@@ -321,7 +321,8 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp)
"}\n"
"\nExamples:\n"
+ HelpExampleCli("validateaddress", "\"zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL\"")
+ HelpExampleCli("z_validateaddress", "\"zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL\"")
+ HelpExampleRpc("z_validateaddress", "\"zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL\"")
);
@@ -439,9 +440,9 @@ UniValue createmultisig(const UniValue& params, bool fHelp)
"\nArguments:\n"
"1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
"2. \"keys\" (string, required) A json array of keys which are bitcoin addresses or hex-encoded public keys\n"
"2. \"keys\" (string, required) A json array of keys which are Zcash addresses or hex-encoded public keys\n"
" [\n"
" \"key\" (string) bitcoin address or hex-encoded public key\n"
" \"key\" (string) Zcash address or hex-encoded public key\n"
" ,...\n"
" ]\n"
@@ -453,9 +454,9 @@ UniValue createmultisig(const UniValue& params, bool fHelp)
"\nExamples:\n"
"\nCreate a multisig address from 2 addresses\n"
+ HelpExampleCli("createmultisig", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
+ HelpExampleCli("createmultisig", "2 \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
+ HelpExampleRpc("createmultisig", "2, \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
;
throw runtime_error(msg);
}
@@ -476,10 +477,10 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 3)
throw runtime_error(
"verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n"
"verifymessage \"zcashaddress\" \"signature\" \"message\"\n"
"\nVerify a signed message\n"
"\nArguments:\n"
"1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the signature.\n"
"1. \"zcashaddress\" (string, required) The Zcash address to use for the signature.\n"
"2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
"3. \"message\" (string, required) The message that was signed.\n"
"\nResult:\n"
@@ -488,11 +489,11 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
"\nUnlock the wallet for 30 seconds\n"
+ HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
"\nCreate the signature\n"
+ HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
+ HelpExampleCli("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"my message\"") +
"\nVerify the signature\n"
+ HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
+ HelpExampleCli("verifymessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"signature\" \"my message\"") +
"\nAs json rpc\n"
+ HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
+ HelpExampleRpc("verifymessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"signature\", \"my message\"")
);
LOCK(cs_main);

View File

@@ -13,6 +13,7 @@
#include "timedata.h"
#include "util.h"
#include "version.h"
#include "deprecation.h"
#include <boost/foreach.hpp>
@@ -141,7 +142,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("pingwait", stats.dPingWait));
obj.push_back(Pair("version", stats.nVersion));
// Use the sanitized form of subver here, to avoid tricksy remote peers from
// corrupting or modifiying the JSON output by putting special characters in
// corrupting or modifying the JSON output by putting special characters in
// their ver message.
obj.push_back(Pair("subver", stats.cleanSubVer));
obj.push_back(Pair("inbound", stats.fInbound));
@@ -285,7 +286,7 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
" \"connected\" : true|false, (boolean) If connected\n"
" \"addresses\" : [\n"
" {\n"
" \"address\" : \"192.168.0.201:8233\", (string) The bitcoin server host and port\n"
" \"address\" : \"192.168.0.201:8233\", (string) The Zcash server host and port\n"
" \"connected\" : \"outbound\" (string) connection, inbound or outbound\n"
" }\n"
" ,...\n"
@@ -428,6 +429,33 @@ static UniValue GetNetworksInfo()
return networks;
}
UniValue getdeprecationinfo(const UniValue& params, bool fHelp)
{
const CChainParams& chainparams = Params();
if (fHelp || params.size() != 0 || chainparams.NetworkIDString() != "main")
throw runtime_error(
"getdeprecationinfo\n"
"Returns an object containing current version and deprecation block height. Applicable only on mainnet.\n"
"\nResult:\n"
"{\n"
" \"version\": xxxxx, (numeric) the server version\n"
" \"subversion\": \"/MagicBean:x.y.z[-v]/\", (string) the server subversion string\n"
" \"deprecationheight\": xxxxx, (numeric) the block height at which this version will deprecate and shut down (unless -disabledeprecation is set)\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getdeprecationinfo", "")
+ HelpExampleRpc("getdeprecationinfo", "")
);
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("subversion",
FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>())));
obj.push_back(Pair("deprecationheight", DEPRECATION_HEIGHT));
return obj;
}
UniValue getnetworkinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -451,7 +479,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
" }\n"
" ,...\n"
" ],\n"
" \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n"
" \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n"
" \"localaddresses\": [ (array) list of local addresses\n"
" {\n"
" \"address\": \"xxxx\", (string) network address\n"

View File

@@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "init.h"
@@ -117,8 +118,15 @@ uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uin
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
{
entry.push_back(Pair("txid", tx.GetHash().GetHex()));
entry.push_back(Pair("overwintered", tx.fOverwintered));
entry.push_back(Pair("version", tx.nVersion));
if (tx.fOverwintered) {
entry.push_back(Pair("versiongroupid", HexInt(tx.nVersionGroupId)));
}
entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
if (tx.fOverwintered) {
entry.push_back(Pair("expiryheight", (int64_t)tx.nExpiryHeight));
}
UniValue vin(UniValue::VARR);
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
UniValue in(UniValue::VOBJ);
@@ -144,14 +152,12 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
const CTxOut& txout = tx.vout[i];
UniValue out(UniValue::VOBJ);
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
if ( pindex != 0 && tx.nLockTime != 0 && (tipindex= chainActive.Tip()) != 0 )
if ( pindex != 0 && tx.nLockTime > 500000000 && (tipindex= chainActive.Tip()) != 0 )
{
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
interest = komodo_interest(pindex->nHeight,txout.nValue,tx.nLockTime,tipindex->nTime);
if ( 0 && strcmp("REVS",ASSETCHAINS_SYMBOL) == 0 )
fprintf(stderr,"TxtoJSON interest %llu %.8f (%d %llu %u %u)\n",(long long)interest,(double)interest/COIN,(int32_t)pindex->nHeight,(long long)txout.nValue,(uint32_t)tx.nLockTime,(int32_t)tipindex->nTime);
out.push_back(Pair("interest", ValueFromAmount(interest)));
}
out.push_back(Pair("valueZat", txout.nValue));
out.push_back(Pair("n", (int64_t)i));
UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
@@ -204,6 +210,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
" \"txid\" : \"id\", (string) The transaction id (same as provided)\n"
" \"version\" : n, (numeric) The version\n"
" \"locktime\" : ttt, (numeric) The lock time\n"
" \"expiryheight\" : ttt, (numeric, optional) The block height after which the transaction expires\n"
" \"vin\" : [ (array of json objects)\n"
" {\n"
" \"txid\": \"id\", (string) The transaction id\n"
@@ -218,7 +225,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
" ],\n"
" \"vout\" : [ (array of json objects)\n"
" {\n"
" \"value\" : x.xxx, (numeric) The value in btc\n"
" \"value\" : x.xxx, (numeric) The value in " + CURRENCY_UNIT + "\n"
" \"n\" : n, (numeric) index\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"asm\", (string) the asm\n"
@@ -226,7 +233,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
" \"reqSigs\" : n, (numeric) The required sigs\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n"
" \"addresses\" : [ (json array of string)\n"
" \"bitcoinaddress\" (string) bitcoin address\n"
" \"zcashaddress\" (string) Zcash address\n"
" ,...\n"
" ]\n"
" }\n"
@@ -235,8 +242,8 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
" ],\n"
" \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n"
" {\n"
" \"vpub_old\" : x.xxx, (numeric) public input value in ZEC\n"
" \"vpub_new\" : x.xxx, (numeric) public output value in ZEC\n"
" \"vpub_old\" : x.xxx, (numeric) public input value in " + CURRENCY_UNIT + "\n"
" \"vpub_new\" : x.xxx, (numeric) public output value in " + CURRENCY_UNIT + "\n"
" \"anchor\" : \"hex\", (string) the anchor\n"
" \"nullifiers\" : [ (json array of string)\n"
" \"hex\" (string) input note nullifier\n"
@@ -481,7 +488,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
" ]\n"
"2. \"addresses\" (string, required) a json object with addresses as keys and amounts as values\n"
" {\n"
" \"address\": x.xxx (numeric, required) The key is the bitcoin address, the value is the btc amount\n"
" \"address\": x.xxx (numeric, required) The key is the Zcash address, the value is the " + CURRENCY_UNIT + " amount\n"
" ,...\n"
" }\n"
@@ -499,7 +506,16 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
UniValue inputs = params[0].get_array();
UniValue sendTo = params[1].get_obj();
CMutableTransaction rawTx;
int nextBlockHeight = chainActive.Height() + 1;
CMutableTransaction rawTx = CreateNewContextualCMutableTransaction(
Params().GetConsensus(), nextBlockHeight);
if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
rawTx.nExpiryHeight = nextBlockHeight + expiryDelta;
if (rawTx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD){
throw JSONRPCError(RPC_INVALID_PARAMETER, "nExpiryHeight must be less than TX_EXPIRY_HEIGHT_THRESHOLD.");
}
}
for (size_t idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
@@ -523,7 +539,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
BOOST_FOREACH(const string& name_, addrList) {
CBitcoinAddress address(name_);
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_);
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+name_);
if (setAddress.count(address))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
@@ -552,8 +568,11 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp)
"\nResult:\n"
"{\n"
" \"txid\" : \"id\", (string) The transaction id\n"
" \"overwintered\" : bool (boolean) The Overwintered flag\n"
" \"version\" : n, (numeric) The version\n"
" \"versiongroupid\": \"hex\" (string, optional) The version group id (Overwintered txs)\n"
" \"locktime\" : ttt, (numeric) The lock time\n"
" \"expiryheight\" : n, (numeric, optional) Last valid block height for mining transaction (Overwintered txs)\n"
" \"vin\" : [ (array of json objects)\n"
" {\n"
" \"txid\": \"id\", (string) The transaction id\n"
@@ -568,7 +587,7 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp)
" ],\n"
" \"vout\" : [ (array of json objects)\n"
" {\n"
" \"value\" : x.xxx, (numeric) The value in btc\n"
" \"value\" : x.xxx, (numeric) The value in " + CURRENCY_UNIT + "\n"
" \"n\" : n, (numeric) index\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"asm\", (string) the asm\n"
@@ -576,7 +595,7 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp)
" \"reqSigs\" : n, (numeric) The required sigs\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n"
" \"addresses\" : [ (json array of string)\n"
" \"12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) bitcoin address\n"
" \"t12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) zcash address\n"
" ,...\n"
" ]\n"
" }\n"
@@ -585,8 +604,8 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp)
" ],\n"
" \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n"
" {\n"
" \"vpub_old\" : x.xxx, (numeric) public input value in ZEC\n"
" \"vpub_new\" : x.xxx, (numeric) public output value in ZEC\n"
" \"vpub_old\" : x.xxx, (numeric) public input value in " + CURRENCY_UNIT + "\n"
" \"vpub_new\" : x.xxx, (numeric) public output value in " + CURRENCY_UNIT + "\n"
" \"anchor\" : \"hex\", (string) the anchor\n"
" \"nullifiers\" : [ (json array of string)\n"
" \"hex\" (string) input note nullifier\n"
@@ -646,7 +665,7 @@ UniValue decodescript(const UniValue& params, bool fHelp)
" \"type\":\"type\", (string) The output type\n"
" \"reqSigs\": n, (numeric) The required signatures\n"
" \"addresses\": [ (json array of string)\n"
" \"address\" (string) bitcoin address\n"
" \"address\" (string) Zcash address\n"
" ,...\n"
" ],\n"
" \"p2sh\",\"address\" (string) script address\n"
@@ -707,7 +726,8 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
" \"txid\":\"id\", (string, required) The transaction id\n"
" \"vout\":n, (numeric, required) The output number\n"
" \"scriptPubKey\": \"hex\", (string, required) script key\n"
" \"redeemScript\": \"hex\" (string, required for P2SH) redeem script\n"
" \"redeemScript\": \"hex\", (string, required for P2SH) redeem script\n"
" \"amount\": value (numeric, required) The amount spent\n"
" }\n"
" ,...\n"
" ]\n"
@@ -845,7 +865,10 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
if ((unsigned int)nOut >= coins->vout.size())
coins->vout.resize(nOut+1);
coins->vout[nOut].scriptPubKey = scriptPubKey;
coins->vout[nOut].nValue = 0; // we don't know the actual output value
coins->vout[nOut].nValue = 0;
if (prevOut.exists("amount")) {
coins->vout[nOut].nValue = AmountFromValue(find_value(prevOut, "amount"));
}
}
// if redeemScript given and not using the local wallet (private keys
@@ -888,9 +911,15 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
// Grab the current consensus branch ID
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
// Script verification errors
UniValue vErrors(UniValue::VARR);
// Use CTransaction for the constant parts of the
// transaction to avoid rehashing.
const CTransaction txConst(mergedTx);
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i];
@@ -900,18 +929,22 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
continue;
}
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
const CAmount& amount = coins->vout[txin.prevout.n].nValue;
txin.scriptSig.clear();
SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size()))
SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId);
// ... and merge in other signatures:
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId);
}
UpdateTransaction(mergedTx, i, sigdata);
ScriptError serror = SCRIPT_ERR_OK;
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i), &serror)) {
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), consensusBranchId, &serror)) {
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
}
}

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