merge jl777/dev; zcash upgrade, CC to fix
This commit is contained in:
127
src/Makefile.am
127
src/Makefile.am
@@ -1,6 +1,8 @@
|
||||
DIST_SUBDIRS = secp256k1 univalue cryptoconditions
|
||||
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,14 +16,16 @@ $(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)/cryptoconditions/include -I$(srcdir)/cryptoconditions/src/asn
|
||||
BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/include
|
||||
BITCOIN_INCLUDES += -I$(srcdir)/snark
|
||||
BITCOIN_INCLUDES += -I$(srcdir)/snark/libsnark
|
||||
BITCOIN_INCLUDES += -I$(srcdir)/univalue/include
|
||||
|
||||
if TARGET_WINDOWS
|
||||
@@ -40,12 +44,25 @@ LIBBITCOIN_UTIL=libbitcoin_util.a
|
||||
LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a
|
||||
LIBSECP256K1=secp256k1/libsecp256k1.la
|
||||
LIBCRYPTOCONDITIONS=cryptoconditions/cryptoconditions_core.a
|
||||
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/
|
||||
|
||||
@@ -68,6 +85,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
|
||||
@@ -99,12 +119,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 \
|
||||
@@ -126,11 +151,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 \
|
||||
@@ -149,6 +174,8 @@ BITCOIN_CORE_H = \
|
||||
net.h \
|
||||
netbase.h \
|
||||
noui.h \
|
||||
paymentdisclosure.h \
|
||||
paymentdisclosuredb.h \
|
||||
policy/fees.h \
|
||||
pow.h \
|
||||
primitives/block.h \
|
||||
@@ -191,7 +218,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 \
|
||||
@@ -210,7 +239,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 \
|
||||
@@ -221,6 +251,7 @@ libbitcoin_server_a_SOURCES = \
|
||||
bloom.cpp \
|
||||
chain.cpp \
|
||||
checkpoints.cpp \
|
||||
deprecation.cpp \
|
||||
httprpc.cpp \
|
||||
httpserver.cpp \
|
||||
init.cpp \
|
||||
@@ -232,6 +263,8 @@ libbitcoin_server_a_SOURCES = \
|
||||
miner.cpp \
|
||||
net.cpp \
|
||||
noui.cpp \
|
||||
paymentdisclosure.cpp \
|
||||
paymentdisclosuredb.cpp \
|
||||
policy/fees.cpp \
|
||||
pow.cpp \
|
||||
rest.cpp \
|
||||
@@ -254,23 +287,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 \
|
||||
@@ -280,7 +330,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 \
|
||||
@@ -312,7 +363,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 \
|
||||
@@ -320,10 +372,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 \
|
||||
@@ -345,7 +396,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 \
|
||||
@@ -370,7 +422,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) \
|
||||
@@ -381,7 +434,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
|
||||
@@ -395,6 +449,7 @@ komodod_LDADD = \
|
||||
$(LIBBITCOIN_UTIL) \
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
$(LIBZCASH) \
|
||||
$(LIBSNARK) \
|
||||
$(LIBLEVELDB) \
|
||||
$(LIBMEMENV) \
|
||||
$(LIBSECP256K1) \
|
||||
@@ -413,16 +468,19 @@ komodod_LDADD += \
|
||||
$(BDB_LIBS) \
|
||||
$(SSL_LIBS) \
|
||||
$(CRYPTO_LIBS) \
|
||||
$(MINIUPNPC_LIBS) \
|
||||
$(EVENT_PTHREADS_LIBS) \
|
||||
$(EVENT_LIBS) \
|
||||
$(LIBZCASH) \
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
$(LIBZCASH_LIBS)
|
||||
|
||||
if ENABLE_PROTON
|
||||
komodod_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
|
||||
@@ -438,13 +496,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
|
||||
@@ -458,6 +518,7 @@ komodo_tx_LDADD = \
|
||||
$(LIBBITCOIN_UTIL) \
|
||||
$(LIBSECP256K1) \
|
||||
$(LIBZCASH) \
|
||||
$(LIBSNARK) \
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
$(LIBZCASH_LIBS) \
|
||||
$(LIBCRYPTOCONDITIONS)
|
||||
@@ -482,12 +543,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 #
|
||||
@@ -500,8 +559,6 @@ libzcashconsensus_la_SOURCES = \
|
||||
crypto/sha1.cpp \
|
||||
crypto/sha256.cpp \
|
||||
crypto/sha512.cpp \
|
||||
eccryptoverify.cpp \
|
||||
ecwrapper.cpp \
|
||||
hash.cpp \
|
||||
primitives/transaction.cpp \
|
||||
pubkey.cpp \
|
||||
@@ -515,11 +572,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 \
|
||||
-I$(builddir)/cryptoconditions/src/asn \
|
||||
-I$(builddir)/cryptoconditions/src
|
||||
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
|
||||
#
|
||||
@@ -528,11 +584,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
|
||||
|
||||
@@ -542,18 +599,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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
21
src/amqp/amqpabstractnotifier.cpp
Normal file
21
src/amqp/amqpabstractnotifier.cpp
Normal 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;
|
||||
}
|
||||
43
src/amqp/amqpabstractnotifier.h
Normal file
43
src/amqp/amqpabstractnotifier.h
Normal 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
33
src/amqp/amqpconfig.h
Normal 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
|
||||
136
src/amqp/amqpnotificationinterface.cpp
Normal file
136
src/amqp/amqpnotificationinterface.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
36
src/amqp/amqpnotificationinterface.h
Normal file
36
src/amqp/amqpnotificationinterface.h
Normal 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
|
||||
177
src/amqp/amqppublishnotifier.cpp
Normal file
177
src/amqp/amqppublishnotifier.cpp
Normal 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());
|
||||
}
|
||||
56
src/amqp/amqppublishnotifier.h
Normal file
56
src/amqp/amqppublishnotifier.h
Normal 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
115
src/amqp/amqpsender.h
Normal 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
|
||||
@@ -28,7 +28,7 @@ echo $pubkey
|
||||
./komodod -pubkey=$pubkey -ac_name=BEER -ac_supply=100000000 -addnode=78.47.196.146 &
|
||||
./komodod -pubkey=$pubkey -ac_name=PIZZA -ac_supply=100000000 -addnode=78.47.196.146 &
|
||||
./komodod -pubkey=$pubkey -ac_name=NINJA -ac_supply=100000000 -addnode=78.47.196.146 &
|
||||
./komodod -pubkey=$pubkey -ac_name=OOT -ac_supply=216000000-addnode=174.138.107.226 &
|
||||
./komodod -pubkey=$pubkey -ac_name=OOT -ac_supply=216000000 -addnode=174.138.107.226 &
|
||||
#sleep $delay
|
||||
|
||||
#./komodod -pubkey=$pubkey -ac_name=USD -addnode=78.47.196.146 $1 &
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
40
src/base58.h
40
src/base58.h
@@ -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;
|
||||
|
||||
@@ -76,11 +76,16 @@ public:
|
||||
#include "komodo_cJSON.c"
|
||||
#include "komodo_notary.h"
|
||||
|
||||
void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals,int32_t KMDheight,uint32_t KMDtimestamp,uint64_t opretvalue,uint8_t *opretbuf,uint16_t opretlen,uint16_t vout)
|
||||
void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals,int32_t KMDheight,uint32_t KMDtimestamp,uint64_t opretvalue,uint8_t *opretbuf,uint16_t opretlen,uint16_t vout,uint256 MoM,int32_t MoMdepth)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint32_t komodo_heightstamp(int32_t height)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
static bool AppInitRPC(int argc, char* argv[])
|
||||
{
|
||||
//
|
||||
|
||||
@@ -81,7 +81,8 @@ CBlockIndex* CBlockIndex::GetAncestor(int height)
|
||||
|
||||
CBlockIndex* pindexWalk = this;
|
||||
int heightWalk = nHeight;
|
||||
while (heightWalk > height) {
|
||||
while ( heightWalk > height && pindexWalk != 0 )
|
||||
{
|
||||
int heightSkip = GetSkipHeight(heightWalk);
|
||||
int heightSkipPrev = GetSkipHeight(heightWalk - 1);
|
||||
if (pindexWalk->pskip != NULL &&
|
||||
|
||||
46
src/chain.h
46
src/chain.h
@@ -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;
|
||||
@@ -155,7 +177,8 @@ public:
|
||||
|
||||
//! (memory only) Sequential id assigned to distinguish order in which blocks are received.
|
||||
uint32_t nSequenceId;
|
||||
|
||||
int8_t notaryid; uint8_t pubkey33[33];
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
phashBlock = NULL;
|
||||
@@ -169,9 +192,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 +354,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 +377,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
|
||||
|
||||
@@ -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,11 +133,12 @@ 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);
|
||||
txNew.vout.resize(1);
|
||||
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
|
||||
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
|
||||
txNew.vout[0].nValue = 50 * COIN;
|
||||
txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
|
||||
genesis.vtx.push_back(txNew);
|
||||
@@ -93,6 +150,13 @@ 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"));
|
||||
@@ -119,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());
|
||||
|
||||
@@ -152,14 +201,14 @@ public:
|
||||
};
|
||||
static CMainParams mainParams;
|
||||
|
||||
void CChainParams::SetCheckpointData(Checkpoints::CCheckpointData checkpointData)
|
||||
void CChainParams::SetCheckpointData(CChainParams::CCheckpointData checkpointData)
|
||||
{
|
||||
CChainParams::checkpointData = checkpointData;
|
||||
}
|
||||
|
||||
void *chainparams_commandline(void *ptr)
|
||||
{
|
||||
Checkpoints::CCheckpointData checkpointData;
|
||||
CChainParams::CCheckpointData checkpointData;
|
||||
while ( ASSETCHAINS_PORT == 0 )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -354,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;
|
||||
@@ -403,7 +476,7 @@ public:
|
||||
fMineBlocksOnDemand = false;
|
||||
fTestnetToBeDeprecatedFieldRPC = true;
|
||||
|
||||
checkpointData = (Checkpoints::CCheckpointData) {
|
||||
checkpointData = (CCheckpointData) {
|
||||
boost::assign::map_list_of
|
||||
(0, consensus.hashGenesisBlock)
|
||||
(38000, uint256S("0x001e9a2d2e2892b88e9998cf7b079b41d59dd085423a921fe8386cecc42287b8")),
|
||||
@@ -419,7 +492,7 @@ static CTestNetParams testNetParams;
|
||||
/**
|
||||
* Regression test
|
||||
*/
|
||||
class CRegTestParams : public CTestNetParams {
|
||||
class CRegTestParams : public CChainParams {
|
||||
public:
|
||||
CRegTestParams() {
|
||||
strNetworkID = "regtest";
|
||||
@@ -431,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;
|
||||
@@ -450,7 +536,6 @@ public:
|
||||
genesis.nSolution = ParseHex("0f2a976db4c4263da10fd5d38eb1790469cf19bdb4bf93450e09a72fdff17a3454326399");
|
||||
consensus.hashGenesisBlock = genesis.GetHash();
|
||||
nDefaultPort = 17779;
|
||||
assert(consensus.hashGenesisBlock == uint256S("0x00a215b4fe36f5d2f829d43e587bf10e89e64f9f48a5b6ce18559089e8fd643d"));
|
||||
nPruneAfterHeight = 1000;
|
||||
|
||||
vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds.
|
||||
@@ -462,18 +547,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;
|
||||
|
||||
@@ -538,7 +639,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;
|
||||
}
|
||||
@@ -547,3 +648,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);
|
||||
}
|
||||
|
||||
@@ -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,8 @@ struct SeedSpec6 {
|
||||
uint16_t port;
|
||||
};
|
||||
|
||||
typedef std::map<int, uint256> MapCheckpoints;
|
||||
|
||||
|
||||
/**
|
||||
* CChainParams defines various tweakable parameters of a given instance of the
|
||||
@@ -46,17 +47,22 @@ public:
|
||||
|
||||
ZCPAYMENT_ADDRRESS,
|
||||
ZCSPENDING_KEY,
|
||||
ZCVIEWING_KEY,
|
||||
|
||||
MAX_BASE58_TYPES
|
||||
};
|
||||
struct CCheckpointData {
|
||||
MapCheckpoints mapCheckpoints;
|
||||
int64_t nTimeLastCheckpoint;
|
||||
int64_t nTransactionsLastCheckpoint;
|
||||
double fTransactionsPerDay;
|
||||
};
|
||||
|
||||
const Consensus::Params& GetConsensus() const { return consensus; }
|
||||
const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
|
||||
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;
|
||||
@@ -87,7 +93,7 @@ public:
|
||||
void SetRegTestCoinbaseMustBeProtected() { consensus.fCoinbaseMustBeProtected = true; }
|
||||
|
||||
void SetDefaultPort(uint16_t port) { nDefaultPort = port; }
|
||||
void SetCheckpointData(Checkpoints::CCheckpointData checkpointData);
|
||||
void SetCheckpointData(CCheckpointData checkpointData);
|
||||
|
||||
//void setnonce(uint32_t nonce) { memcpy(&genesis.nNonce,&nonce,sizeof(nonce)); }
|
||||
//void settimestamp(uint32_t timestamp) { genesis.nTime = timestamp; }
|
||||
@@ -118,7 +124,7 @@ protected:
|
||||
bool fRequireStandard = false;
|
||||
bool fMineBlocksOnDemand = false;
|
||||
bool fTestnetToBeDeprecatedFieldRPC = false;
|
||||
Checkpoints::CCheckpointData checkpointData;
|
||||
CCheckpointData checkpointData;
|
||||
std::vector<std::string> vFoundersRewardAddress;
|
||||
};
|
||||
|
||||
@@ -140,4 +146,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
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Checkpoints {
|
||||
* fast multicore CPU, it won't be much higher than 1.
|
||||
*/
|
||||
static const double SIGCHECK_VERIFICATION_FACTOR = 5.0;
|
||||
bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash)
|
||||
bool CheckBlock(const CChainParams::CCheckpointData& data, int nHeight, const uint256& hash)
|
||||
{
|
||||
const MapCheckpoints& checkpoints = data.mapCheckpoints;
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Checkpoints {
|
||||
}
|
||||
|
||||
//! Guess how far we are in the verification process at the given block index
|
||||
double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex *pindex, bool fSigchecks) {
|
||||
double GuessVerificationProgress(const CChainParams::CCheckpointData& data, CBlockIndex *pindex, bool fSigchecks) {
|
||||
if (pindex==NULL)
|
||||
return 0.0;
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Checkpoints {
|
||||
return fWorkBefore / (fWorkBefore + fWorkAfter);
|
||||
}
|
||||
|
||||
int GetTotalBlocksEstimate(const CCheckpointData& data)
|
||||
int GetTotalBlocksEstimate(const CChainParams::CCheckpointData& data)
|
||||
{
|
||||
const MapCheckpoints& checkpoints = data.mapCheckpoints;
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Checkpoints {
|
||||
return checkpoints.rbegin()->first;
|
||||
}
|
||||
|
||||
CBlockIndex* GetLastCheckpoint(const CCheckpointData& data)
|
||||
CBlockIndex* GetLastCheckpoint(const CChainParams::CCheckpointData& data)
|
||||
{
|
||||
const MapCheckpoints& checkpoints = data.mapCheckpoints;
|
||||
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
#define BITCOIN_CHECKPOINTS_H
|
||||
|
||||
#include "uint256.h"
|
||||
#include "chainparams.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
class CBlockIndex;
|
||||
struct CCheckpointData;
|
||||
|
||||
/**
|
||||
* Block-chain checkpoints are compiled-in sanity checks.
|
||||
@@ -17,7 +19,8 @@ class CBlockIndex;
|
||||
*/
|
||||
namespace Checkpoints
|
||||
{
|
||||
typedef std::map<int, uint256> MapCheckpoints;
|
||||
|
||||
typedef std::map<int, uint256> MapCheckpoints;
|
||||
|
||||
struct CCheckpointData {
|
||||
MapCheckpoints mapCheckpoints;
|
||||
@@ -25,15 +28,16 @@ struct CCheckpointData {
|
||||
int64_t nTransactionsLastCheckpoint;
|
||||
double fTransactionsPerDay;
|
||||
};
|
||||
bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash);
|
||||
bool CheckBlock(const CChainParams::CCheckpointData& data, int nHeight, const uint256& hash);
|
||||
|
||||
|
||||
//! Return conservative estimate of total number of blocks, 0 if unknown
|
||||
int GetTotalBlocksEstimate(const CCheckpointData& data);
|
||||
int GetTotalBlocksEstimate(const CChainParams::CCheckpointData& data);
|
||||
|
||||
//! Returns last CBlockIndex* in mapBlockIndex that is a checkpoint
|
||||
CBlockIndex* GetLastCheckpoint(const CCheckpointData& data);
|
||||
CBlockIndex* GetLastCheckpoint(const CChainParams::CCheckpointData& data);
|
||||
|
||||
double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex* pindex, bool fSigchecks = true);
|
||||
double GuessVerificationProgress(const CChainParams::CCheckpointData& data, CBlockIndex* pindex, bool fSigchecks = true);
|
||||
|
||||
} //namespace Checkpoints
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -387,7 +387,7 @@ const CScript &CCoinsViewCache::GetSpendFor(const CTxIn& input) const
|
||||
}
|
||||
|
||||
//uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
|
||||
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue);
|
||||
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight);
|
||||
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||
|
||||
CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTransaction& tx,uint32_t tiptime) const
|
||||
@@ -407,7 +407,7 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr
|
||||
if ( value >= 10*COIN )
|
||||
{
|
||||
int64_t interest; int32_t txheight; uint32_t locktime;
|
||||
interest = komodo_accrued_interest(&txheight,&locktime,tx.vin[i].prevout.hash,tx.vin[i].prevout.n,0,value);
|
||||
interest = komodo_accrued_interest(&txheight,&locktime,tx.vin[i].prevout.hash,tx.vin[i].prevout.n,0,value,(int32_t)nHeight);
|
||||
//printf("nResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nResult/COIN,(double)value/COIN,(double)interest/COIN,txheight,locktime,tiptime);
|
||||
//fprintf(stderr,"nResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nResult/COIN,(double)value/COIN,(double)interest/COIN,txheight,locktime,tiptime);
|
||||
nResult += interest;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,10 @@ struct Params {
|
||||
int nMajorityEnforceBlockUpgrade;
|
||||
int nMajorityRejectBlockOutdated;
|
||||
int nMajorityWindow;
|
||||
int fPowAllowMinDifficultyBlocks;
|
||||
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
126
src/consensus/upgrades.cpp
Normal 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
90
src/consensus/upgrades.h
Normal 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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
61
src/deprecation.cpp
Normal 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
25
src/deprecation.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
122
src/gtest/test_deprecation.cpp
Normal file
122
src/gtest/test_deprecation.cpp
Normal 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());
|
||||
}
|
||||
@@ -81,6 +81,8 @@ TEST(founders_reward_test, create_testnet_2of3multisig) {
|
||||
std::cout << s << std::endl;
|
||||
|
||||
pWallet->Flush(true);
|
||||
|
||||
ECC_Stop();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
62
src/gtest/test_httprpc.cpp
Normal file
62
src/gtest/test_httprpc.cpp
Normal 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();
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
212
src/gtest/test_paymentdisclosure.cpp
Normal file
212
src/gtest/test_paymentdisclosure.cpp
Normal 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();
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
173
src/gtest/test_upgrades.cpp
Normal 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);
|
||||
}
|
||||
152
src/gtest/test_validation.cpp
Normal file
152
src/gtest/test_validation.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,3 @@
|
||||
#include "zcash/JoinSplit.hpp"
|
||||
|
||||
ZCJoinSplit* params = ZCJoinSplit::Unopened();
|
||||
|
||||
int GenZero(int n)
|
||||
{
|
||||
return 0;
|
||||
|
||||
43
src/hash.h
43
src/hash.h
@@ -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)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
168
src/init.cpp
168
src/init.cpp
@@ -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());
|
||||
}
|
||||
|
||||
202
src/key.cpp
202
src/key.cpp
@@ -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);
|
||||
|
||||
28
src/key.h
28
src/key.h
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
@@ -31,7 +32,7 @@ using namespace std;
|
||||
|
||||
#include "komodo_interest.h"
|
||||
|
||||
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue)
|
||||
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
105
src/komodo.h
105
src/komodo.h
@@ -73,7 +73,7 @@ int32_t komodo_currentheight()
|
||||
int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char *dest)
|
||||
{
|
||||
static int32_t errs;
|
||||
int32_t func,ht,notarized_height,num,matched=0; uint256 notarized_hash,notarized_desttxid; uint8_t pubkeys[64][33];
|
||||
int32_t func,ht,notarized_height,num,matched=0,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; uint8_t pubkeys[64][33];
|
||||
if ( (func= fgetc(fp)) != EOF )
|
||||
{
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && strcmp(symbol,"KMD") == 0 )
|
||||
@@ -97,7 +97,7 @@ int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char
|
||||
}
|
||||
} else printf("illegal num.%d\n",num);
|
||||
}
|
||||
else if ( func == 'N' )
|
||||
else if ( func == 'N' || func == 'M' )
|
||||
{
|
||||
if ( fread(¬arized_height,1,sizeof(notarized_height),fp) != sizeof(notarized_height) )
|
||||
errs++;
|
||||
@@ -105,10 +105,22 @@ int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char
|
||||
errs++;
|
||||
if ( fread(¬arized_desttxid,1,sizeof(notarized_desttxid),fp) != sizeof(notarized_desttxid) )
|
||||
errs++;
|
||||
if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 && sp != 0 )
|
||||
printf("%s load[%s.%d -> %s] NOTARIZED %d %s\n",ASSETCHAINS_SYMBOL,symbol,sp->NUM_NPOINTS,dest,notarized_height,notarized_hash.ToString().c_str());
|
||||
if ( func == 'M' )
|
||||
{
|
||||
if ( fread(&MoM,1,sizeof(MoM),fp) != sizeof(MoM) )
|
||||
errs++;
|
||||
if ( fread(&MoMdepth,1,sizeof(MoMdepth),fp) != sizeof(MoMdepth) )
|
||||
errs++;
|
||||
if ( 1 && ASSETCHAINS_SYMBOL[0] != 0 && sp != 0 )
|
||||
printf("%s load[%s.%d -> %s] NOTARIZED %d %s MoM.%s %d\n",ASSETCHAINS_SYMBOL,symbol,sp->NUM_NPOINTS,dest,notarized_height,notarized_hash.ToString().c_str(),MoM.ToString().c_str(),MoMdepth);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(&MoM,0,sizeof(MoM));
|
||||
MoMdepth = 0;
|
||||
}
|
||||
//if ( matched != 0 ) global independent states -> inside *sp
|
||||
komodo_eventadd_notarized(sp,symbol,ht,dest,notarized_hash,notarized_desttxid,notarized_height);
|
||||
komodo_eventadd_notarized(sp,symbol,ht,dest,notarized_hash,notarized_desttxid,notarized_height,MoM,MoMdepth);
|
||||
}
|
||||
else if ( func == 'U' ) // deprecated
|
||||
{
|
||||
@@ -208,7 +220,7 @@ int32_t memread(void *dest,int32_t size,uint8_t *filedata,long *fposp,long datal
|
||||
int32_t komodo_parsestatefiledata(struct komodo_state *sp,uint8_t *filedata,long *fposp,long datalen,char *symbol,char *dest)
|
||||
{
|
||||
static int32_t errs;
|
||||
int32_t func= -1,ht,notarized_height,num,matched=0; uint256 notarized_hash,notarized_desttxid; uint8_t pubkeys[64][33]; long fpos = *fposp;
|
||||
int32_t func= -1,ht,notarized_height,MoMdepth,num,matched=0; uint256 MoM,notarized_hash,notarized_desttxid; uint8_t pubkeys[64][33]; long fpos = *fposp;
|
||||
if ( fpos < datalen )
|
||||
{
|
||||
func = filedata[fpos++];
|
||||
@@ -231,7 +243,7 @@ int32_t komodo_parsestatefiledata(struct komodo_state *sp,uint8_t *filedata,long
|
||||
}
|
||||
} else printf("illegal num.%d\n",num);
|
||||
}
|
||||
else if ( func == 'N' )
|
||||
else if ( func == 'N' || func == 'M' )
|
||||
{
|
||||
if ( memread(¬arized_height,sizeof(notarized_height),filedata,&fpos,datalen) != sizeof(notarized_height) )
|
||||
errs++;
|
||||
@@ -239,10 +251,21 @@ int32_t komodo_parsestatefiledata(struct komodo_state *sp,uint8_t *filedata,long
|
||||
errs++;
|
||||
if ( memread(¬arized_desttxid,sizeof(notarized_desttxid),filedata,&fpos,datalen) != sizeof(notarized_desttxid) )
|
||||
errs++;
|
||||
if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 && sp != 0 )
|
||||
printf("%s load[%s.%d -> %s] NOTARIZED %d %s\n",ASSETCHAINS_SYMBOL,symbol,sp->NUM_NPOINTS,dest,notarized_height,notarized_hash.ToString().c_str());
|
||||
//if ( matched != 0 ) global independent states -> inside *sp
|
||||
komodo_eventadd_notarized(sp,symbol,ht,dest,notarized_hash,notarized_desttxid,notarized_height);
|
||||
if ( func == 'M' )
|
||||
{
|
||||
if ( memread(&MoM,sizeof(MoM),filedata,&fpos,datalen) != sizeof(MoM) )
|
||||
errs++;
|
||||
if ( memread(&MoMdepth,sizeof(MoMdepth),filedata,&fpos,datalen) != sizeof(MoMdepth) )
|
||||
errs++;
|
||||
if ( 1 && ASSETCHAINS_SYMBOL[0] != 0 && sp != 0 )
|
||||
printf("%s load[%s.%d -> %s] NOTARIZED %d %s MoM.%s %d\n",ASSETCHAINS_SYMBOL,symbol,sp->NUM_NPOINTS,dest,notarized_height,notarized_hash.ToString().c_str(),MoM.ToString().c_str(),MoMdepth);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(&MoM,0,sizeof(MoM));
|
||||
MoMdepth = 0;
|
||||
}
|
||||
komodo_eventadd_notarized(sp,symbol,ht,dest,notarized_hash,notarized_desttxid,notarized_height,MoM,MoMdepth);
|
||||
}
|
||||
else if ( func == 'U' ) // deprecated
|
||||
{
|
||||
@@ -326,9 +349,9 @@ int32_t komodo_parsestatefiledata(struct komodo_state *sp,uint8_t *filedata,long
|
||||
return(-1);
|
||||
}
|
||||
|
||||
void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals,int32_t KMDheight,uint32_t KMDtimestamp,uint64_t opretvalue,uint8_t *opretbuf,uint16_t opretlen,uint16_t vout)
|
||||
void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals,int32_t KMDheight,uint32_t KMDtimestamp,uint64_t opretvalue,uint8_t *opretbuf,uint16_t opretlen,uint16_t vout,uint256 MoM,int32_t MoMdepth)
|
||||
{
|
||||
static FILE *fp; static int32_t errs,didinit;
|
||||
static FILE *fp; static int32_t errs,didinit; static uint256 zero;
|
||||
struct komodo_state *sp; char fname[512],symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; int32_t retval,ht,func; uint8_t num,pubkeys[64][33];
|
||||
if ( didinit == 0 )
|
||||
{
|
||||
@@ -457,7 +480,9 @@ void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotar
|
||||
//printf("ht.%d func N ht.%d errs.%d\n",height,NOTARIZED_HEIGHT,errs);
|
||||
if ( sp != 0 )
|
||||
{
|
||||
fputc('N',fp);
|
||||
if ( sp->MoMdepth > 0 && sp->MoM != zero )
|
||||
fputc('M',fp);
|
||||
else fputc('N',fp);
|
||||
if ( fwrite(&height,1,sizeof(height),fp) != sizeof(height) )
|
||||
errs++;
|
||||
if ( fwrite(&sp->NOTARIZED_HEIGHT,1,sizeof(sp->NOTARIZED_HEIGHT),fp) != sizeof(sp->NOTARIZED_HEIGHT) )
|
||||
@@ -466,7 +491,14 @@ void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotar
|
||||
errs++;
|
||||
if ( fwrite(&sp->NOTARIZED_DESTTXID,1,sizeof(sp->NOTARIZED_DESTTXID),fp) != sizeof(sp->NOTARIZED_DESTTXID) )
|
||||
errs++;
|
||||
komodo_eventadd_notarized(sp,symbol,height,dest,sp->NOTARIZED_HASH,sp->NOTARIZED_DESTTXID,sp->NOTARIZED_HEIGHT);
|
||||
if ( sp->MoMdepth > 0 && sp->MoM != zero )
|
||||
{
|
||||
if ( fwrite(&sp->MoM,1,sizeof(sp->MoM),fp) != sizeof(sp->MoM) )
|
||||
errs++;
|
||||
if ( fwrite(&sp->MoMdepth,1,sizeof(sp->MoMdepth),fp) != sizeof(sp->MoMdepth) )
|
||||
errs++;
|
||||
}
|
||||
komodo_eventadd_notarized(sp,symbol,height,dest,sp->NOTARIZED_HASH,sp->NOTARIZED_DESTTXID,sp->NOTARIZED_HEIGHT,sp->MoM,sp->MoMdepth);
|
||||
}
|
||||
}
|
||||
fflush(fp);
|
||||
@@ -537,15 +569,36 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr
|
||||
len += iguana_rwbignum(0,&scriptbuf[len],32,(uint8_t *)&kmdtxid);
|
||||
len += iguana_rwnum(0,&scriptbuf[len],sizeof(*notarizedheightp),(uint8_t *)notarizedheightp);
|
||||
len += iguana_rwbignum(0,&scriptbuf[len],32,(uint8_t *)&desttxid);
|
||||
if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && (height < sp->CURRENT_HEIGHT-1000 || komodo_verifynotarization(ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL,(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "BTC" : "KMD"),height,*notarizedheightp,kmdtxid,desttxid) == 0) )
|
||||
if ( strcmp("PIZZA",ASSETCHAINS_SYMBOL) == 0 && opretlen == 110 )
|
||||
{
|
||||
notarized = 1;
|
||||
}
|
||||
if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && (height < sp->CURRENT_HEIGHT-64 || komodo_verifynotarization(ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL,(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "BTC" : "KMD"),height,*notarizedheightp,kmdtxid,desttxid) == 0) )
|
||||
{
|
||||
int32_t nameoffset = (int32_t)strlen(ASSETCHAINS_SYMBOL) + 1;
|
||||
sp->NOTARIZED_HEIGHT = *notarizedheightp;
|
||||
sp->NOTARIZED_HASH = kmdtxid;
|
||||
sp->NOTARIZED_DESTTXID = desttxid;
|
||||
komodo_stateupdate(height,0,0,0,zero,0,0,0,0,0,0,0,0,0,0);
|
||||
len += 4;
|
||||
memset(&sp->MoM,0,sizeof(sp->MoM));
|
||||
sp->MoMdepth = 0;
|
||||
if ( len+36 <= opretlen )
|
||||
{
|
||||
len += iguana_rwbignum(0,&scriptbuf[len+nameoffset],32,(uint8_t *)&sp->MoM);
|
||||
len += iguana_rwnum(0,&scriptbuf[len+nameoffset],sizeof(sp->MoMdepth),(uint8_t *)&sp->MoMdepth);
|
||||
if ( sp->MoM == zero || sp->MoMdepth > 1440 || sp->MoMdepth < 0 )
|
||||
{
|
||||
memset(&sp->MoM,0,sizeof(sp->MoM));
|
||||
sp->MoMdepth = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("VALID %s MoM.%s [%d]\n",ASSETCHAINS_SYMBOL,sp->MoM.ToString().c_str(),sp->MoMdepth);
|
||||
}
|
||||
}
|
||||
komodo_stateupdate(height,0,0,0,zero,0,0,0,0,0,0,0,0,0,0,sp->MoM,sp->MoMdepth);
|
||||
len += nameoffset;
|
||||
if ( ASSETCHAINS_SYMBOL[0] != 0 )
|
||||
printf("[%s] ht.%d NOTARIZED.%d %s.%s %sTXID.%s lens.(%d %d)\n",ASSETCHAINS_SYMBOL,height,*notarizedheightp,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,kmdtxid.ToString().c_str(),ASSETCHAINS_SYMBOL[0]==0?"BTC":"KMD",desttxid.ToString().c_str(),opretlen,len);
|
||||
printf("[%s] ht.%d NOTARIZED.%d %s.%s %sTXID.%s lens.(%d %d) MoM.%s %d\n",ASSETCHAINS_SYMBOL,height,*notarizedheightp,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,kmdtxid.ToString().c_str(),ASSETCHAINS_SYMBOL[0]==0?"BTC":"KMD",desttxid.ToString().c_str(),opretlen,len,sp->MoM.ToString().c_str(),sp->MoMdepth);
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
{
|
||||
if ( signedfp == 0 )
|
||||
@@ -567,11 +620,11 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr
|
||||
//for (i=0; i<opretlen-len; i++)
|
||||
// printf("%02x",scriptbuf[len+i]);
|
||||
//printf(" Found extradata.[%d] %d - %d\n",opretlen-len,opretlen,len);
|
||||
komodo_stateupdate(height,0,0,0,txhash,0,0,0,0,0,0,value,&scriptbuf[len],opretlen-len+4+3+(scriptbuf[1] == 0x4d),j);
|
||||
komodo_stateupdate(height,0,0,0,txhash,0,0,0,0,0,0,value,&scriptbuf[len],opretlen-len+4+3+(scriptbuf[1] == 0x4d),j,zero,0);
|
||||
}
|
||||
}
|
||||
} else if ( height >= KOMODO_MAINNET_START )
|
||||
printf("notarized.%d %llx reject ht.%d NOTARIZED.%d prev.%d %s.%s DESTTXID.%s (%s)\n",notarized,(long long)signedmask,height,*notarizedheightp,sp->NOTARIZED_HEIGHT,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,kmdtxid.ToString().c_str(),desttxid.ToString().c_str(),(char *)&scriptbuf[len]);
|
||||
} else if ( height >= sp->CURRENT_HEIGHT-64 )//KOMODO_MAINNET_START )
|
||||
printf("notarized.%d %llx reject ht.%d NOTARIZED.%d prev.%d %s.%s DESTTXID.%s (%s) len.%d opretlen.%d\n",notarized,(long long)signedmask,height,*notarizedheightp,sp->NOTARIZED_HEIGHT,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,kmdtxid.ToString().c_str(),desttxid.ToString().c_str(),(char *)&scriptbuf[len],len,opretlen);
|
||||
}
|
||||
else if ( i == 0 && j == 1 && opretlen == 149 )
|
||||
{
|
||||
@@ -596,7 +649,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr
|
||||
}
|
||||
|
||||
if ( *isratificationp == 0 && (signedmask != 0 || (scriptbuf[len] != 'X' && scriptbuf[len] != 'A')) ) // && scriptbuf[len] != 'I')
|
||||
komodo_stateupdate(height,0,0,0,txhash,0,0,0,0,0,0,value,&scriptbuf[len],opretlen,j);
|
||||
komodo_stateupdate(height,0,0,0,txhash,0,0,0,0,0,0,value,&scriptbuf[len],opretlen,j,zero,0);
|
||||
}
|
||||
}
|
||||
return(notaryid);
|
||||
@@ -655,7 +708,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
|
||||
if ( pindex->nHeight != hwmheight )
|
||||
printf("%s hwmheight.%d vs pindex->nHeight.%d t.%u reorg.%d\n",ASSETCHAINS_SYMBOL,hwmheight,pindex->nHeight,(uint32_t)pindex->nTime,hwmheight-pindex->nHeight);
|
||||
komodo_event_rewind(sp,symbol,pindex->nHeight);
|
||||
komodo_stateupdate(pindex->nHeight,0,0,0,zero,0,0,0,0,-pindex->nHeight,pindex->nTime,0,0,0,0);
|
||||
komodo_stateupdate(pindex->nHeight,0,0,0,zero,0,0,0,0,-pindex->nHeight,pindex->nTime,0,0,0,0,zero,0);
|
||||
}
|
||||
komodo_currentheight_set(chainActive.Tip()->nHeight);
|
||||
if ( pindex != 0 )
|
||||
@@ -787,7 +840,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
|
||||
if ( ((signedmask & 1) != 0 && numvalid >= KOMODO_MINRATIFY) || bitweight(signedmask) > (numnotaries/3) )
|
||||
{
|
||||
memset(&txhash,0,sizeof(txhash));
|
||||
komodo_stateupdate(height,pubkeys,numvalid,0,txhash,0,0,0,0,0,0,0,0,0,0);
|
||||
komodo_stateupdate(height,pubkeys,numvalid,0,txhash,0,0,0,0,0,0,0,0,0,0,zero,0);
|
||||
printf("RATIFIED! >>>>>>>>>> new notaries.%d newheight.%d from height.%d\n",numvalid,(((height+KOMODO_ELECTION_GAP/2)/KOMODO_ELECTION_GAP)+1)*KOMODO_ELECTION_GAP,height);
|
||||
} else printf("signedmask.%llx numvalid.%d wt.%d numnotaries.%d\n",(long long)signedmask,numvalid,bitweight(signedmask),numnotaries);
|
||||
}
|
||||
@@ -796,7 +849,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
|
||||
if ( NOTARY_PUBKEY33[0] != 0 && ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
printf("%s ht.%d\n",ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL,height);
|
||||
if ( pindex->nHeight == hwmheight )
|
||||
komodo_stateupdate(height,0,0,0,zero,0,0,0,0,height,(uint32_t)pindex->nTime,0,0,0,0);
|
||||
komodo_stateupdate(height,0,0,0,zero,0,0,0,0,height,(uint32_t)pindex->nTime,0,0,0,0,zero,0);
|
||||
} else fprintf(stderr,"komodo_connectblock: unexpected null pindex\n");
|
||||
//KOMODO_INITDONE = (uint32_t)time(NULL);
|
||||
//fprintf(stderr,"%s end connect.%d\n",ASSETCHAINS_SYMBOL,pindex->nHeight);
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
|
||||
#include "komodo_defs.h"
|
||||
|
||||
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
|
||||
int32_t komodo_electednotary(int32_t *numnotariesp,uint8_t *pubkey33,int32_t height,uint32_t timestamp);
|
||||
|
||||
//#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr))
|
||||
|
||||
struct MemoryStruct { char *memory; size_t size; };
|
||||
@@ -414,13 +417,14 @@ int32_t komodo_verifynotarizedscript(int32_t height,uint8_t *script,int32_t len,
|
||||
printf(" notarized, ");
|
||||
for (i=0; i<32; i++)
|
||||
printf("%02x",((uint8_t *)&hash)[i]);
|
||||
printf(" opreturn from [%s] ht.%d\n",ASSETCHAINS_SYMBOL,height);
|
||||
printf(" opreturn from [%s] ht.%d MISMATCHED\n",ASSETCHAINS_SYMBOL,height);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t NOTARIZED_HEIGHT,uint256 NOTARIZED_HASH,uint256 NOTARIZED_DESTTXID)
|
||||
{
|
||||
char params[256],*jsonstr,*hexstr; uint8_t script[8192]; int32_t n,len,retval = -1; cJSON *json,*txjson,*vouts,*vout,*skey;
|
||||
char params[256],*jsonstr,*hexstr; uint8_t *script,_script[8192]; int32_t n,len,retval = -1; cJSON *json,*txjson,*vouts,*vout,*skey;
|
||||
script = _script;
|
||||
/*params[0] = '[';
|
||||
params[1] = '"';
|
||||
for (i=0; i<32; i++)
|
||||
@@ -471,9 +475,19 @@ int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t
|
||||
{
|
||||
if ( (hexstr= jstr(skey,(char *)"hex")) != 0 )
|
||||
{
|
||||
//printf("HEX.(%s)\n",hexstr);
|
||||
//printf("HEX.(%s) vs hash.%s\n",hexstr,NOTARIZED_HASH.ToString().c_str());
|
||||
len = strlen(hexstr) >> 1;
|
||||
decode_hex(script,len,hexstr);
|
||||
if ( script[1] == 0x4c )
|
||||
{
|
||||
script++;
|
||||
len--;
|
||||
}
|
||||
else if ( script[1] == 0x4d )
|
||||
{
|
||||
script += 2;
|
||||
len -= 2;
|
||||
}
|
||||
retval = komodo_verifynotarizedscript(height,script,len,NOTARIZED_HASH);
|
||||
}
|
||||
}
|
||||
@@ -574,7 +588,7 @@ void komodo_disconnect(CBlockIndex *pindex,CBlock& block)
|
||||
|
||||
int32_t komodo_is_notarytx(const CTransaction& tx)
|
||||
{
|
||||
uint8_t *ptr,crypto777[33];
|
||||
uint8_t *ptr; static uint8_t crypto777[33];
|
||||
if ( tx.vout.size() > 0 )
|
||||
{
|
||||
#ifdef KOMODO_ZCASH
|
||||
@@ -584,7 +598,8 @@ int32_t komodo_is_notarytx(const CTransaction& tx)
|
||||
#endif
|
||||
if ( ptr != 0 )
|
||||
{
|
||||
decode_hex(crypto777,33,(char *)CRYPTO777_PUBSECPSTR);
|
||||
if ( crypto777[0] == 0 )
|
||||
decode_hex(crypto777,33,(char *)CRYPTO777_PUBSECPSTR);
|
||||
if ( memcmp(ptr+1,crypto777,33) == 0 )
|
||||
{
|
||||
//printf("found notarytx\n");
|
||||
@@ -610,7 +625,7 @@ int32_t komodo_block2height(CBlock *block)
|
||||
//for (i=0; i<6; i++)
|
||||
// printf("%02x",ptr[i]);
|
||||
n = ptr[0];
|
||||
for (i=0; i<n; i++)
|
||||
for (i=0; i<n; i++) // looks strange but this works
|
||||
{
|
||||
//03bb81000101(bb 187) (81 48001) (00 12288256) <- coinbase.6 ht.12288256
|
||||
height += ((uint32_t)ptr[i+1] << (i*8));
|
||||
@@ -682,19 +697,42 @@ uint32_t komodo_heightstamp(int32_t height)
|
||||
CBlockIndex *ptr;
|
||||
if ( height > 0 && (ptr= komodo_chainactive(height)) != 0 )
|
||||
return(ptr->nTime);
|
||||
else fprintf(stderr,"komodo_heightstamp null ptr for block.%d\n",height);
|
||||
//else fprintf(stderr,"komodo_heightstamp null ptr for block.%d\n",height);
|
||||
return(0);
|
||||
}
|
||||
|
||||
void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height)
|
||||
{
|
||||
CBlock block;
|
||||
CBlock block; int32_t num,i; uint8_t pubkeys[64][33];
|
||||
//komodo_init(height);
|
||||
memset(pubkey33,0,33);
|
||||
if ( pindex != 0 )
|
||||
{
|
||||
if ( pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3 )
|
||||
{
|
||||
memcpy(pubkey33,pindex->pubkey33,33);
|
||||
return;
|
||||
}
|
||||
if ( komodo_blockload(block,pindex) == 0 )
|
||||
{
|
||||
komodo_block2pubkey33(pubkey33,block);
|
||||
if ( (pubkey33[0] == 2 || pubkey33[0] == 3) )
|
||||
{
|
||||
memcpy(pindex->pubkey33,pubkey33,33);
|
||||
if ( (num= komodo_notaries(pubkeys,(int32_t)pindex->nHeight,(uint32_t)pindex->nTime)) > 0 )
|
||||
{
|
||||
pindex->notaryid = -1;
|
||||
for (i=0; i<num; i++)
|
||||
{
|
||||
if ( memcmp(pubkeys[i],pubkey33,33) == 0 )
|
||||
{
|
||||
pindex->notaryid = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else pindex->notaryid = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -703,27 +741,28 @@ void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height)
|
||||
}
|
||||
}
|
||||
|
||||
void komodo_connectpindex(CBlockIndex *pindex)
|
||||
/*void komodo_connectpindex(CBlockIndex *pindex)
|
||||
{
|
||||
CBlock block;
|
||||
if ( komodo_blockload(block,pindex) == 0 )
|
||||
komodo_connectblock(pindex,block);
|
||||
}
|
||||
}*/
|
||||
|
||||
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
|
||||
int32_t komodo_electednotary(int32_t *numnotariesp,uint8_t *pubkey33,int32_t height,uint32_t timestamp);
|
||||
|
||||
int8_t komodo_minerid(int32_t height,uint8_t *pubkey33)
|
||||
{
|
||||
int32_t num,i,numnotaries; CBlockIndex *pindex; uint32_t timestamp=0; uint8_t _pubkey33[33],pubkeys[64][33];
|
||||
if ( pubkey33 == 0 && (pindex= chainActive[height]) != 0 )
|
||||
if ( (pindex= chainActive[height]) != 0 )
|
||||
{
|
||||
timestamp = pindex->GetBlockTime();
|
||||
if ( pubkey33 == 0 )
|
||||
if ( (pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3) )
|
||||
{
|
||||
pubkey33 = _pubkey33;
|
||||
komodo_index2pubkey33(pubkey33,pindex,height);
|
||||
if ( pubkey33 != 0 )
|
||||
memcpy(pubkey33,pindex->pubkey33,33);
|
||||
return(pindex->notaryid);
|
||||
}
|
||||
if ( pubkey33 != 0 )
|
||||
komodo_index2pubkey33(pubkey33,pindex,height);
|
||||
timestamp = pindex->GetBlockTime();
|
||||
if ( (num= komodo_notaries(pubkeys,height,timestamp)) > 0 )
|
||||
{
|
||||
for (i=0; i<num; i++)
|
||||
@@ -742,14 +781,22 @@ int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *non
|
||||
{
|
||||
if ( (pindex= komodo_chainactive(height-i)) != 0 )
|
||||
{
|
||||
komodo_index2pubkey33(pubkey33,pindex,height-i);
|
||||
for (j=0; j<33; j++)
|
||||
pubkeys[i][j] = pubkey33[j];
|
||||
if ( (mids[i]= komodo_minerid(height-i,pubkey33)) >= 0 )
|
||||
if ( pindex->notaryid >= 0 && (pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3) )
|
||||
{
|
||||
//mids[i] = *(int32_t *)pubkey33;
|
||||
memcpy(pubkeys[i],pindex->pubkey33,33);
|
||||
mids[i] = pindex->notaryid;
|
||||
(*nonzpkeysp)++;
|
||||
}
|
||||
else
|
||||
{
|
||||
komodo_index2pubkey33(pubkey33,pindex,height-i);
|
||||
memcpy(pubkeys[i],pubkey33,33);
|
||||
if ( (mids[i]= komodo_minerid(height-i,pubkey33)) >= 0 )
|
||||
{
|
||||
//mids[i] = *(int32_t *)pubkey33;
|
||||
(*nonzpkeysp)++;
|
||||
}
|
||||
}
|
||||
if ( mids[0] >= 0 && i > 0 && mids[i] == mids[0] )
|
||||
duplicate++;
|
||||
}
|
||||
@@ -759,23 +806,24 @@ int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *non
|
||||
else return(0);
|
||||
}
|
||||
|
||||
int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width)
|
||||
int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width) // deprecate
|
||||
{
|
||||
int32_t i,n=0;
|
||||
/*int32_t i,n=0;
|
||||
for (i=0; i<width; i++,n++)
|
||||
{
|
||||
if ( height-i <= 0 )
|
||||
break;
|
||||
minerids[i] = komodo_minerid(height - i,0);
|
||||
}
|
||||
return(n);
|
||||
return(n);*/
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int32_t komodo_is_special(int32_t height,uint8_t pubkey33[33],uint32_t timestamp)
|
||||
{
|
||||
int32_t i,notaryid=0,minerid,limit,nid; uint8_t _pubkey33[33];
|
||||
int32_t i,notaryid=0,minerid,limit,nid; //uint8_t _pubkey33[33];
|
||||
if ( height >= 225000 )
|
||||
komodo_chosennotary(¬aryid,height,_pubkey33,timestamp);
|
||||
komodo_chosennotary(¬aryid,height,pubkey33,timestamp);
|
||||
if ( height >= 34000 && notaryid >= 0 )
|
||||
{
|
||||
if ( height < 79693 )
|
||||
@@ -785,8 +833,8 @@ int32_t komodo_is_special(int32_t height,uint8_t pubkey33[33],uint32_t timestamp
|
||||
else limit = 66;
|
||||
for (i=1; i<limit; i++)
|
||||
{
|
||||
komodo_chosennotary(&nid,height-i,_pubkey33,timestamp);
|
||||
if ( nid == notaryid ) //komodo_minerid(height-i,_pubkey33)
|
||||
komodo_chosennotary(&nid,height-i,pubkey33,timestamp);
|
||||
if ( nid == notaryid )
|
||||
{
|
||||
if ( (0) && notaryid > 0 )
|
||||
fprintf(stderr,"ht.%d notaryid.%d already mined -i.%d nid.%d\n",height,notaryid,i,nid);
|
||||
@@ -800,9 +848,25 @@ int32_t komodo_is_special(int32_t height,uint8_t pubkey33[33],uint32_t timestamp
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t komodo_MoM(int32_t *notarized_heightp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight)
|
||||
{
|
||||
int32_t depth,notarized_ht; uint256 MoM,kmdtxid;
|
||||
depth = komodo_MoMdata(¬arized_ht,&MoM,&kmdtxid,nHeight);
|
||||
memset(MoMp,0,sizeof(*MoMp));
|
||||
memset(kmdtxidp,0,sizeof(*kmdtxidp));
|
||||
*notarized_heightp = 0;
|
||||
if ( depth > 0 && notarized_ht > 0 && nHeight > notarized_ht-depth && nHeight <= notarized_ht )
|
||||
{
|
||||
*MoMp = MoM;
|
||||
*notarized_heightp = notarized_ht;
|
||||
*kmdtxidp = kmdtxid;
|
||||
}
|
||||
return(depth);
|
||||
}
|
||||
|
||||
int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash)
|
||||
{
|
||||
int32_t notarized_height; uint256 notarized_hash,notarized_desttxid; CBlockIndex *notary; CBlockIndex *pindex;
|
||||
int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary; CBlockIndex *pindex;
|
||||
if ( (pindex= chainActive.Tip()) == 0 )
|
||||
return(-1);
|
||||
notarized_height = komodo_notarizeddata(pindex->nHeight,¬arized_hash,¬arized_desttxid);
|
||||
@@ -840,12 +904,13 @@ uint32_t komodo_interest_args(uint32_t *txheighttimep,int32_t *txheightp,uint32_
|
||||
uint32_t locktime = 0;
|
||||
if ( n < tx.vout.size() )
|
||||
{
|
||||
if ( (pindex= mapBlockIndex[hashBlock]) != 0 && (tipindex= chainActive.Tip()) != 0 )
|
||||
if ( (pindex= mapBlockIndex[hashBlock]) != 0 )
|
||||
{
|
||||
*valuep = tx.vout[n].nValue;
|
||||
*txheightp = pindex->nHeight;
|
||||
*txheighttimep = pindex->nTime;
|
||||
*tiptimep = tipindex->nTime;
|
||||
if ( *tiptimep == 0 && (tipindex= chainActive.Tip()) != 0 )
|
||||
*tiptimep = (uint32_t)tipindex->nTime;
|
||||
locktime = tx.nLockTime;
|
||||
//fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep);
|
||||
}
|
||||
@@ -854,9 +919,13 @@ uint32_t komodo_interest_args(uint32_t *txheighttimep,int32_t *txheightp,uint32_
|
||||
}
|
||||
|
||||
uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
|
||||
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue)
|
||||
|
||||
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight)
|
||||
{
|
||||
uint64_t value; uint32_t tiptime,txheighttimep;
|
||||
uint64_t value; uint32_t tiptime=0,txheighttimep; CBlockIndex *pindex;
|
||||
if ( (pindex= chainActive[tipheight]) != 0 )
|
||||
tiptime = (uint32_t)pindex->nTime;
|
||||
else fprintf(stderr,"cant find height[%d]\n",tipheight);
|
||||
if ( (*locktimep= komodo_interest_args(&txheighttimep,txheightp,&tiptime,&value,hash,n)) != 0 )
|
||||
{
|
||||
if ( (checkvalue == 0 || value == checkvalue) && (checkheight == 0 || *txheightp == checkheight) )
|
||||
@@ -891,7 +960,7 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_
|
||||
{
|
||||
if ( tx.nLockTime != 1477258935 || dispflag != 0 )
|
||||
{
|
||||
//fprintf(stderr,"komodo_validate_interest.%d reject.%d [%d] locktime %u cmp2.%u\n",dispflag,txheight,(int32_t)(tx.nLockTime - (cmptime-3600)),(uint32_t)tx.nLockTime,cmptime);
|
||||
fprintf(stderr,"komodo_validate_interest.%d reject.%d [%d] locktime %u cmp2.%u\n",dispflag,txheight,(int32_t)(tx.nLockTime - (cmptime-3600)),(uint32_t)tx.nLockTime,cmptime);
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ struct komodo_event *komodo_eventadd(struct komodo_state *sp,int32_t height,char
|
||||
return(ep);
|
||||
}
|
||||
|
||||
void komodo_eventadd_notarized(struct komodo_state *sp,char *symbol,int32_t height,char *dest,uint256 notarized_hash,uint256 notarized_desttxid,int32_t notarizedheight)
|
||||
void komodo_eventadd_notarized(struct komodo_state *sp,char *symbol,int32_t height,char *dest,uint256 notarized_hash,uint256 notarized_desttxid,int32_t notarizedheight,uint256 MoM,int32_t MoMdepth)
|
||||
{
|
||||
struct komodo_event_notarized N;
|
||||
if ( komodo_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid) != 0 )
|
||||
@@ -53,10 +53,12 @@ void komodo_eventadd_notarized(struct komodo_state *sp,char *symbol,int32_t heig
|
||||
N.blockhash = notarized_hash;
|
||||
N.desttxid = notarized_desttxid;
|
||||
N.notarizedheight = notarizedheight;
|
||||
N.MoM = MoM;
|
||||
N.MoMdepth = MoMdepth;
|
||||
strcpy(N.dest,dest);
|
||||
komodo_eventadd(sp,height,symbol,KOMODO_EVENT_NOTARIZED,(uint8_t *)&N,sizeof(N));
|
||||
if ( sp != 0 )
|
||||
komodo_notarized_update(sp,height,notarizedheight,notarized_hash,notarized_desttxid);
|
||||
komodo_notarized_update(sp,height,notarizedheight,notarized_hash,notarized_desttxid,MoM,MoMdepth);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
|
||||
#include "komodo_defs.h"
|
||||
|
||||
void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals,int32_t kheight,uint32_t ktime,uint64_t opretvalue,uint8_t *opretbuf,uint16_t opretlen,uint16_t vout);
|
||||
uint32_t komodo_heightstamp(int32_t height);
|
||||
void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals,int32_t kheight,uint32_t ktime,uint64_t opretvalue,uint8_t *opretbuf,uint16_t opretlen,uint16_t vout,uint256 MoM,int32_t MoMdepth);
|
||||
void komodo_init(int32_t height);
|
||||
int32_t komodo_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight);
|
||||
int32_t komodo_notarizeddata(int32_t nHeight,uint256 *notarized_hashp,uint256 *notarized_desttxidp);
|
||||
char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port);
|
||||
void komodo_init(int32_t height);
|
||||
|
||||
@@ -126,13 +126,13 @@ const char *Notaries_elected0[][2] =
|
||||
{ "xxspot2_XX", "03d85b221ea72ebcd25373e7961f4983d12add66a92f899deaf07bab1d8b6f5573" }
|
||||
};
|
||||
|
||||
#define KOMODO_NOTARIES_TIMESTAMP1 1600000000
|
||||
#define KOMODO_NOTARIES_HEIGHT1 ((800000 / KOMODO_ELECTION_GAP) * KOMODO_ELECTION_GAP)
|
||||
#define KOMODO_NOTARIES_TIMESTAMP1 1530921600 // 7/7/2017
|
||||
#define KOMODO_NOTARIES_HEIGHT1 ((900000 / KOMODO_ELECTION_GAP) * KOMODO_ELECTION_GAP)
|
||||
|
||||
const char *Notaries_elected1[][2] =
|
||||
{
|
||||
{ "0_jl777_testA", "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828" },
|
||||
{ "0_jl777_testB", "02ebfc784a4ba768aad88d44d1045d240d47b26e248cafaf1c5169a42d7a61d344" },
|
||||
{ "0_jl777_testA", "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828" },
|
||||
{ "0_kolo_testA", "0287aa4b73988ba26cf6565d815786caf0d2c4af704d7883d163ee89cd9977edec" },
|
||||
{ "artik_AR", "029acf1dcd9f5ff9c455f8bb717d4ae0c703e089d16cf8424619c491dff5994c90" },
|
||||
{ "artik_EU", "03f54b2c24f82632e3cdebe4568ba0acf487a80f8a89779173cdb78f74514847ce" },
|
||||
@@ -199,28 +199,52 @@ const char *Notaries_elected1[][2] =
|
||||
|
||||
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp)
|
||||
{
|
||||
static uint8_t elected_pubkeys0[64][33],elected_pubkeys1[64][33],did0,did1;
|
||||
int32_t i,htind,n; uint64_t mask = 0; struct knotary_entry *kp,*tmp;
|
||||
if ( timestamp == 0 && ASSETCHAINS_SYMBOL[0] != 0 )
|
||||
timestamp = komodo_heightstamp(height);
|
||||
if ( height >= KOMODO_NOTARIES_HARDCODED || ASSETCHAINS_SYMBOL[0] != 0 )
|
||||
{
|
||||
if ( timestamp < KOMODO_NOTARIES_TIMESTAMP1 || height < KOMODO_NOTARIES_HEIGHT1 )
|
||||
if ( (timestamp != 0 && timestamp <= KOMODO_NOTARIES_TIMESTAMP1) || height <= KOMODO_NOTARIES_HEIGHT1 )
|
||||
{
|
||||
n = (int32_t)(sizeof(Notaries_elected0)/sizeof(*Notaries_elected0));
|
||||
for (i=0; i<n; i++)
|
||||
decode_hex(pubkeys[i],33,(char *)Notaries_elected0[i][1]);
|
||||
if ( did0 == 0 )
|
||||
{
|
||||
n = (int32_t)(sizeof(Notaries_elected0)/sizeof(*Notaries_elected0));
|
||||
for (i=0; i<n; i++)
|
||||
decode_hex(elected_pubkeys0[i],33,(char *)Notaries_elected0[i][1]);
|
||||
did0 = 1;
|
||||
}
|
||||
memcpy(pubkeys,elected_pubkeys0,n * 33);
|
||||
//if ( ASSETCHAINS_SYMBOL[0] != 0 )
|
||||
//fprintf(stderr,"%s height.%d t.%u elected.%d notaries\n",ASSETCHAINS_SYMBOL,height,timestamp,n);
|
||||
}
|
||||
else // if ( timestamp < KOMODO_NOTARIES_TIMESTAMP2 || height < KOMODO_NOTARIES_HEIGHT2 )
|
||||
else //if ( (timestamp != 0 && timestamp <= KOMODO_NOTARIES_TIMESTAMP2) || height <= KOMODO_NOTARIES_HEIGHT2 )
|
||||
{
|
||||
n = (int32_t)(sizeof(Notaries_elected1)/sizeof(*Notaries_elected1));
|
||||
for (i=0; i<n; i++)
|
||||
decode_hex(pubkeys[i],33,(char *)Notaries_elected1[i][1]);
|
||||
if ( did1 == 0 )
|
||||
{
|
||||
n = (int32_t)(sizeof(Notaries_elected1)/sizeof(*Notaries_elected1));
|
||||
for (i=0; i<n; i++)
|
||||
decode_hex(elected_pubkeys1[i],33,(char *)Notaries_elected1[i][1]);
|
||||
if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 )
|
||||
fprintf(stderr,"%s height.%d t.%u elected.%d notaries2\n",ASSETCHAINS_SYMBOL,height,timestamp,n);
|
||||
did1 = 1;
|
||||
}
|
||||
memcpy(pubkeys,elected_pubkeys1,n * 33);
|
||||
}
|
||||
return(n);
|
||||
}
|
||||
htind = height / KOMODO_ELECTION_GAP;
|
||||
if ( htind >= KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP )
|
||||
htind = (KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP) - 1;
|
||||
if ( Pubkeys == 0 )
|
||||
{
|
||||
komodo_init(height);
|
||||
printf("Pubkeys.%p htind.%d vs max.%d\n",Pubkeys,htind,KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP);
|
||||
}
|
||||
pthread_mutex_lock(&komodo_mutex);
|
||||
n = Pubkeys[htind].numnotaries;
|
||||
if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 )
|
||||
fprintf(stderr,"%s height.%d t.%u genesis.%d\n",ASSETCHAINS_SYMBOL,height,timestamp,n);
|
||||
HASH_ITER(hh,Pubkeys[htind].Notaries,kp,tmp)
|
||||
{
|
||||
if ( kp->notaryid < n )
|
||||
@@ -238,11 +262,7 @@ int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestam
|
||||
|
||||
int32_t komodo_electednotary(int32_t *numnotariesp,uint8_t *pubkey33,int32_t height,uint32_t timestamp)
|
||||
{
|
||||
char pubkeystr[67]; int32_t i,n; uint8_t pubkeys[64][33];
|
||||
for (i=0; i<33; i++)
|
||||
sprintf(&pubkeystr[i*2],"%02x",pubkey33[i]);
|
||||
pubkeystr[66] = 0;
|
||||
//printf("%s vs\n",pubkeystr);
|
||||
int32_t i,n; uint8_t pubkeys[64][33];
|
||||
n = komodo_notaries(pubkeys,height,timestamp);
|
||||
*numnotariesp = n;
|
||||
for (i=0; i<n; i++)
|
||||
@@ -273,7 +293,7 @@ void komodo_notarysinit(int32_t origheight,uint8_t pubkeys[64][33],int32_t num)
|
||||
static int32_t hwmheight;
|
||||
int32_t k,i,htind,height; struct knotary_entry *kp; struct knotaries_entry N;
|
||||
if ( Pubkeys == 0 )
|
||||
Pubkeys = (struct knotaries_entry *)calloc(KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP,sizeof(*Pubkeys));
|
||||
Pubkeys = (struct knotaries_entry *)calloc(1 + (KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP),sizeof(*Pubkeys));
|
||||
memset(&N,0,sizeof(N));
|
||||
if ( origheight > 0 )
|
||||
{
|
||||
@@ -319,7 +339,6 @@ int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,
|
||||
{
|
||||
// -1 if not notary, 0 if notary, 1 if special notary
|
||||
struct knotary_entry *kp; int32_t numnotaries=0,htind,modval = -1;
|
||||
komodo_init(0);
|
||||
*notaryidp = -1;
|
||||
if ( height < 0 )//|| height >= KOMODO_MAXBLOCKS )
|
||||
{
|
||||
@@ -336,6 +355,8 @@ int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,
|
||||
}
|
||||
if ( height >= 250000 )
|
||||
return(-1);
|
||||
if ( Pubkeys == 0 )
|
||||
komodo_init(0);
|
||||
htind = height / KOMODO_ELECTION_GAP;
|
||||
if ( htind >= KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP )
|
||||
htind = (KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP) - 1;
|
||||
@@ -357,7 +378,7 @@ int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,
|
||||
return(modval);
|
||||
}
|
||||
|
||||
void komodo_notarized_update(struct komodo_state *sp,int32_t nHeight,int32_t notarized_height,uint256 notarized_hash,uint256 notarized_desttxid)
|
||||
void komodo_notarized_update(struct komodo_state *sp,int32_t nHeight,int32_t notarized_height,uint256 notarized_hash,uint256 notarized_desttxid,uint256 MoM,int32_t MoMdepth)
|
||||
{
|
||||
struct notarized_checkpoint *np;
|
||||
if ( notarized_height > nHeight )
|
||||
@@ -375,6 +396,8 @@ void komodo_notarized_update(struct komodo_state *sp,int32_t nHeight,int32_t not
|
||||
sp->NOTARIZED_HEIGHT = np->notarized_height = notarized_height;
|
||||
sp->NOTARIZED_HASH = np->notarized_hash = notarized_hash;
|
||||
sp->NOTARIZED_DESTTXID = np->notarized_desttxid = notarized_desttxid;
|
||||
sp->MoM = np->MoM = MoM;
|
||||
sp->MoMdepth = np->MoMdepth = MoMdepth;
|
||||
portable_mutex_unlock(&komodo_mutex);
|
||||
}
|
||||
|
||||
@@ -396,6 +419,30 @@ int32_t komodo_notarized_height(uint256 *hashp,uint256 *txidp)
|
||||
}
|
||||
}
|
||||
|
||||
int32_t komodo_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t height)
|
||||
{
|
||||
int32_t i; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; struct notarized_checkpoint *np = 0;
|
||||
np = 0;
|
||||
if ( (sp= komodo_stateptr(symbol,dest)) != 0 )
|
||||
{
|
||||
for (i=sp->NUM_NPOINTS-1; i>=0; i--)
|
||||
{
|
||||
np = &sp->NPOINTS[i];
|
||||
if ( np->MoMdepth > 0 && height > np->notarized_height-np->MoMdepth && height <= np->notarized_height )
|
||||
{
|
||||
*notarized_htp = np->notarized_height;
|
||||
*MoMp = np->MoM;
|
||||
*kmdtxidp = np->notarized_desttxid;
|
||||
return(np->MoMdepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
*notarized_htp = 0;
|
||||
memset(MoMp,0,sizeof(*MoMp));
|
||||
memset(kmdtxidp,0,sizeof(*kmdtxidp));
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t komodo_notarizeddata(int32_t nHeight,uint256 *notarized_hashp,uint256 *notarized_desttxidp)
|
||||
{
|
||||
struct notarized_checkpoint *np = 0; int32_t i=0,flag = 0; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp;
|
||||
@@ -457,6 +504,7 @@ void komodo_init(int32_t height)
|
||||
static int didinit; uint256 zero; int32_t k,n; uint8_t pubkeys[64][33];
|
||||
if ( 0 && height != 0 )
|
||||
printf("komodo_init ht.%d didinit.%d\n",height,didinit);
|
||||
memset(&zero,0,sizeof(zero));
|
||||
if ( didinit == 0 )
|
||||
{
|
||||
pthread_mutex_init(&komodo_mutex,NULL);
|
||||
@@ -472,10 +520,10 @@ void komodo_init(int32_t height)
|
||||
}
|
||||
komodo_notarysinit(0,pubkeys,k);
|
||||
}
|
||||
memset(&zero,0,sizeof(zero));
|
||||
//for (i=0; i<sizeof(Minerids); i++)
|
||||
// Minerids[i] = -2;
|
||||
didinit = 1;
|
||||
komodo_stateupdate(0,0,0,0,zero,0,0,0,0,0,0,0,0,0,0,zero,0);
|
||||
}
|
||||
/*else if ( 0 && height == KOMODO_MAINNET_START )
|
||||
{
|
||||
@@ -489,7 +537,6 @@ void komodo_init(int32_t height)
|
||||
printf("set MAINNET notaries.%d\n",k);
|
||||
komodo_notarysinit(KOMODO_MAINNET_START,pubkeys,k);
|
||||
}*/
|
||||
komodo_stateupdate(0,0,0,0,zero,0,0,0,0,0,0,0,0,0,0);
|
||||
}
|
||||
|
||||
/*void komodo_assetchain_pubkeys(char *jsonstr)
|
||||
|
||||
@@ -709,7 +709,7 @@ void komodo_paxpricefeed(int32_t height,uint8_t *pricefeed,int32_t opretlen)
|
||||
double KMDBTC,BTCUSD,CNYUSD; uint32_t numpvals,timestamp,pvals[128]; uint256 zero;
|
||||
numpvals = dpow_readprices(height,pricefeed,×tamp,&KMDBTC,&BTCUSD,&CNYUSD,pvals);
|
||||
memset(&zero,0,sizeof(zero));
|
||||
komodo_stateupdate(height,0,0,0,zero,0,0,pvals,numpvals,0,0,0,0,0,0);
|
||||
komodo_stateupdate(height,0,0,0,zero,0,0,pvals,numpvals,0,0,0,0,0,0,zero,0);
|
||||
if ( 0 )
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
@@ -56,7 +56,7 @@ typedef union _bits320 bits320;
|
||||
|
||||
struct komodo_kv { UT_hash_handle hh; bits256 pubkey; uint8_t *key,*value; int32_t height; uint32_t flags; uint16_t keylen,valuesize; };
|
||||
|
||||
struct komodo_event_notarized { uint256 blockhash,desttxid; int32_t notarizedheight; char dest[16]; };
|
||||
struct komodo_event_notarized { uint256 blockhash,desttxid,MoM; int32_t notarizedheight,MoMdepth; char dest[16]; };
|
||||
struct komodo_event_pubkeys { uint8_t num; uint8_t pubkeys[64][33]; };
|
||||
struct komodo_event_opreturn { uint256 txid; uint64_t value; uint16_t vout,oplen; uint8_t opret[]; };
|
||||
struct komodo_event_pricefeed { uint8_t num; uint32_t prices[35]; };
|
||||
@@ -83,12 +83,16 @@ struct pax_transaction
|
||||
|
||||
struct knotary_entry { UT_hash_handle hh; uint8_t pubkey[33],notaryid; };
|
||||
struct knotaries_entry { int32_t height,numnotaries; struct knotary_entry *Notaries; };
|
||||
struct notarized_checkpoint { uint256 notarized_hash,notarized_desttxid; int32_t nHeight,notarized_height; };
|
||||
struct notarized_checkpoint
|
||||
{
|
||||
uint256 notarized_hash,notarized_desttxid,MoM;
|
||||
int32_t nHeight,notarized_height,MoMdepth;
|
||||
};
|
||||
|
||||
struct komodo_state
|
||||
{
|
||||
uint256 NOTARIZED_HASH,NOTARIZED_DESTTXID;
|
||||
int32_t SAVEDHEIGHT,CURRENT_HEIGHT,NOTARIZED_HEIGHT;
|
||||
uint256 NOTARIZED_HASH,NOTARIZED_DESTTXID,MoM;
|
||||
int32_t SAVEDHEIGHT,CURRENT_HEIGHT,NOTARIZED_HEIGHT,MoMdepth;
|
||||
uint32_t SAVEDTIMESTAMP;
|
||||
uint64_t deposited,issued,withdrawn,approved,redeemed,shorted;
|
||||
struct notarized_checkpoint *NPOINTS; int32_t NUM_NPOINTS,last_NPOINTSi;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
870
src/main.cpp
870
src/main.cpp
File diff suppressed because it is too large
Load Diff
67
src/main.h
67
src/main.h
@@ -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,9 +45,11 @@ class CInv;
|
||||
class CScriptCheck;
|
||||
class CValidationInterface;
|
||||
class CValidationState;
|
||||
class PrecomputedTransactionData;
|
||||
|
||||
struct CNodeStateStats;
|
||||
#define DEFAULT_MEMPOOL_EXPIRY 1
|
||||
#define _COINBASE_MATURITY 100
|
||||
|
||||
/** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/
|
||||
static const unsigned int DEFAULT_BLOCK_MAX_SIZE = MAX_BLOCK_SIZE;
|
||||
@@ -57,6 +60,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 +70,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 +114,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 +313,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 +338,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 +357,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 +376,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 +399,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 +474,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 +552,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 +568,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -115,7 +112,6 @@ extern std::string NOTARY_PUBKEY;
|
||||
extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33];
|
||||
uint32_t Mining_start,Mining_height;
|
||||
int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp);
|
||||
int32_t komodo_is_special(int32_t height,uint8_t pubkey33[33],uint32_t timestamp);
|
||||
int32_t komodo_pax_opreturn(int32_t height,uint8_t *opret,int32_t maxsize);
|
||||
uint64_t komodo_paxtotal();
|
||||
int32_t komodo_baseid(char *origbase);
|
||||
@@ -189,6 +185,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 +199,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 +246,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 +278,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 +342,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 +385,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;
|
||||
@@ -525,7 +523,6 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
|
||||
//
|
||||
// Internal miner
|
||||
//
|
||||
int8_t komodo_minerid(int32_t height,uint8_t *pubkey33);
|
||||
|
||||
CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey)
|
||||
{
|
||||
@@ -550,12 +547,6 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey)
|
||||
script[34] = OP_CHECKSIG;
|
||||
//scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
|
||||
}
|
||||
if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 )
|
||||
{
|
||||
for (i=0; i<65; i++)
|
||||
fprintf(stderr,"%d ",komodo_minerid(chainActive.Tip()->nHeight-i,0));
|
||||
fprintf(stderr," minerids.special %d from ht.%d\n",komodo_is_special(chainActive.Tip()->nHeight+1,NOTARY_PUBKEY33,chainActive.Tip()->GetBlockTime()),chainActive.Tip()->nHeight);
|
||||
}
|
||||
return CreateNewBlock(scriptPubKey);
|
||||
}
|
||||
|
||||
@@ -763,7 +754,7 @@ void static BitcoinMiner()
|
||||
savebits = pblock->nBits;
|
||||
arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
|
||||
roundrobin_delay = ROUNDROBIN_DELAY;
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && notaryid >= 0 )//komodo_is_special(pindexPrev->nHeight+1,NOTARY_PUBKEY33) > 0 )
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && notaryid >= 0 )
|
||||
{
|
||||
j = 65;
|
||||
if ( (Mining_height >= 235300 && Mining_height < 236000) || (Mining_height % KOMODO_ELECTION_GAP) > 64 || (Mining_height % KOMODO_ELECTION_GAP) == 0 )
|
||||
@@ -784,12 +775,6 @@ void static BitcoinMiner()
|
||||
break;
|
||||
if ( externalflag == 0 && i != 66 )
|
||||
printf("VIOLATION at %d\n",i);
|
||||
for (i=0; i<66; i++)
|
||||
{ break;
|
||||
for (j=0; j<33; j++)
|
||||
printf("%02x",pubkeys[i][j]);
|
||||
printf(" p%d -> %d\n",i,komodo_minerid(pindexPrev->nHeight-i,pubkeys[i]));
|
||||
}
|
||||
for (j=gpucount=0; j<65; j++)
|
||||
{
|
||||
if ( mids[j] >= 0 || notaryid == 34 )
|
||||
@@ -914,7 +899,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 +985,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 +1020,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)
|
||||
{
|
||||
|
||||
198
src/net.cpp
198
src/net.cpp
@@ -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();
|
||||
|
||||
11
src/net.h
11
src/net.h
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
2
src/obj-test/.gitignore
vendored
2
src/obj-test/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
||||
63
src/paymentdisclosure.cpp
Normal file
63
src/paymentdisclosure.cpp
Normal 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
147
src/paymentdisclosure.h
Normal 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
|
||||
93
src/paymentdisclosuredb.cpp
Normal file
93
src/paymentdisclosuredb.cpp
Normal 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
42
src/paymentdisclosuredb.h
Normal 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
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -120,7 +120,6 @@ int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,
|
||||
int32_t komodo_is_special(int32_t height,uint8_t pubkey33[33],uint32_t timestamp);
|
||||
int32_t komodo_currentheight();
|
||||
CBlockIndex *komodo_chainactive(int32_t height);
|
||||
int8_t komodo_minerid(int32_t height,uint8_t *pubkey33);
|
||||
void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height);
|
||||
extern int32_t KOMODO_CHOSEN_ONE;
|
||||
extern char ASSETCHAINS_SYMBOL[];
|
||||
@@ -169,7 +168,7 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in
|
||||
// Check proof of work matches claimed amount
|
||||
if ( UintToArith256(hash) > bnTarget )
|
||||
{
|
||||
if ( (height < 235300 || height >= 236000) && KOMODO_LOADINGBLOCKS == 0 && height > 188000 )
|
||||
if ( 0 && (height < 235300 || height >= 236000) && KOMODO_LOADINGBLOCKS == 0 && height > 188000 )
|
||||
//&& )//186269, 182507&& komodo_chainactive(height) != 0 && nonzpkeys > 0
|
||||
{
|
||||
for (i=31; i>=0; i--)
|
||||
|
||||
@@ -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:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user