merge jl777/dev; zcash upgrade, CC to fix

This commit is contained in:
Scott Sadler
2018-03-26 20:07:32 -03:00
617 changed files with 56209 additions and 10078 deletions

View File

@@ -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

View File

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

View File

@@ -99,20 +99,25 @@ BITCOIN_TESTS += \
endif
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
test_test_bitcoin_CPPFLAGS = -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
endif
test_test_bitcoin_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBZCASH) $(LIBZCASH_LIBS)
test_test_bitcoin_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(LIBZCASH) $(LIBSNARK) $(LIBZCASH_LIBS)
test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
if ENABLE_ZMQ
test_test_bitcoin_LDADD += $(ZMQ_LIBS)
endif
if ENABLE_PROTON
test_test_bitcoin_LDADD += $(PROTON_LIBS)
endif
nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
$(BITCOIN_TESTS): $(GENERATED_TEST_FILES)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

@@ -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 &

View File

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

View File

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

View File

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

View File

@@ -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[])
{
//

View File

@@ -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 &&

View File

@@ -16,6 +16,8 @@
#include <boost/foreach.hpp>
static const int SPROUT_VALUE_VERSION = 1001400;
struct CDiskBlockPos
{
int nFile;
@@ -92,8 +94,14 @@ enum BlockStatus: uint32_t {
BLOCK_FAILED_VALID = 32, //! stage after last reached validness failed
BLOCK_FAILED_CHILD = 64, //! descends from failed block
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,
BLOCK_ACTIVATES_UPGRADE = 128, //! block activates a network upgrade
};
//! Short-hand for the highest consensus validity we implement.
//! Blocks with this validity are assumed to satisfy all consensus rules.
static const BlockStatus BLOCK_VALID_CONSENSUS = BLOCK_VALID_SCRIPTS;
/** The block chain is a tree shaped structure starting with the
* genesis block at the root, with each block potentially having multiple
* candidates to be the next block. A blockindex may have multiple pprev pointing
@@ -138,12 +146,26 @@ public:
//! Verification status of this block. See enum BlockStatus
unsigned int nStatus;
//! Branch ID corresponding to the consensus rules used to validate this block.
//! Only cached if block validity is BLOCK_VALID_CONSENSUS.
//! Persisted at each activation height, memory-only for intervening blocks.
boost::optional<uint32_t> nCachedBranchId;
//! The anchor for the tree state up to the start of this block
uint256 hashAnchor;
//! (memory only) The anchor for the tree state up to the end of this block
uint256 hashAnchorEnd;
//! Change in value held by the Sprout circuit over this block.
//! Will be boost::none for older blocks on old nodes until a reindex has taken place.
boost::optional<CAmount> nSproutValue;
//! (memory only) Total value held by the Sprout circuit up to and including this block.
//! Will be boost::none for on old nodes until a reindex has taken place.
//! Will be boost::none if nChainTx is zero.
boost::optional<CAmount> nChainSproutValue;
//! block header
int nVersion;
uint256 hashMerkleRoot;
@@ -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

View File

@@ -15,10 +15,56 @@
#include "base58.h"
using namespace std;
#include "chainparamsseeds.h"
static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, const uint256& nNonce, const std::vector<unsigned char>& nSolution, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
// To create a genesis block for a new chain which is Overwintered:
// txNew.nVersion = 3
// txNew.fOverwintered = true
// txNew.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID
// txNew.nExpiryHeight = <default value>
CMutableTransaction txNew;
txNew.nVersion = 1;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 520617983 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
txNew.vout[0].nValue = genesisReward;
txNew.vout[0].scriptPubKey = genesisOutputScript;
CBlock genesis;
genesis.nTime = nTime;
genesis.nBits = nBits;
genesis.nNonce = nNonce;
genesis.nSolution = nSolution;
genesis.nVersion = nVersion;
genesis.vtx.push_back(txNew);
genesis.hashPrevBlock.SetNull();
genesis.hashMerkleRoot = genesis.BuildMerkleTree();
return genesis;
}
/**
* Build the genesis block. Note that the output of its generation
* transaction cannot be spent since it did not originally exist in the
* database (and is in any case of zero value).
*
* >>> from pyblake2 import blake2s
* >>> 'Zcash' + blake2s(b'The Economist 2016-10-29 Known unknown: Another crypto-currency is born. BTC#436254 0000000000000000044f321997f336d2908cf8c8d6893e88dbf067e2d949487d ETH#2521903 483039a6b6bd8bd05f0584f9a078d075e454925eb71c1f13eaff59b405a721bb DJIA close on 27 Oct 2016: 18,169.68').hexdigest()
*
* CBlock(hash=00040fe8, ver=4, hashPrevBlock=00000000000000, hashMerkleRoot=c4eaa5, nTime=1477641360, nBits=1f07ffff, nNonce=4695, vtx=1)
* CTransaction(hash=c4eaa5, ver=1, vin.size=1, vout.size=1, nLockTime=0)
* CTxIn(COutPoint(000000, -1), coinbase 04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334)
* CTxOut(nValue=0.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
* vMerkleTree: c4eaa5
*/
static CBlock CreateGenesisBlock(uint32_t nTime, const uint256& nNonce, const std::vector<unsigned char>& nSolution, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
const char* pszTimestamp = "Zcash0b9c4eef8b7cc417ee5001e3500984b6fea35683a7cac141a043c42064835d34";
const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nSolution, nBits, nVersion, genesisReward);
}
/**
* Main network
*/
@@ -59,6 +105,16 @@ public:
consensus.nPowMaxAdjustUp = 16; // 16% adjustment up
consensus.nPowTargetSpacing = 1 * 60;
consensus.fPowAllowMinDifficultyBlocks = true; //false;
consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002;
consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight =
Consensus::NetworkUpgrade::ALWAYS_ACTIVE;
consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nProtocolVersion = 170002;
consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170004;
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
/**
* The message start string is designed to be unlikely to occur in normal data.
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
@@ -77,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);
}

View File

@@ -7,7 +7,6 @@
#define BITCOIN_CHAINPARAMS_H
#include "chainparamsbase.h"
#include "checkpoints.h"
#include "consensus/params.h"
#include "primitives/block.h"
#include "protocol.h"
@@ -26,6 +25,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

View File

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

View File

@@ -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;

View File

@@ -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

View File

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

View File

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

View File

@@ -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);
}

View File

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

View File

@@ -9,7 +9,11 @@
/** The minimum allowed block version (network rule) */
static const int32_t MIN_BLOCK_VERSION = 4;
/** The minimum allowed transaction version (network rule) */
static const int32_t MIN_TX_VERSION = 1;
static const int32_t SPROUT_MIN_TX_VERSION = 1;
/** The minimum allowed transaction version (network rule) */
static const int32_t OVERWINTER_MIN_TX_VERSION = 3;
/** The maximum allowed transaction version (network rule) */
static const int32_t OVERWINTER_MAX_TX_VERSION = 3;
/** The maximum allowed size for a serialized block, in bytes (network rule) */
static const unsigned int MAX_BLOCK_SIZE = 2000000;
/** The maximum allowed number of signature check operations in a block (network rule) */
@@ -18,6 +22,8 @@ static const unsigned int MAX_BLOCK_SIGOPS = 20000;
static const unsigned int MAX_TX_SIZE = 100000;
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
extern int COINBASE_MATURITY;
/** The minimum value which is invalid for expiry height, used by CTransaction and CMutableTransaction */
static constexpr uint32_t TX_EXPIRY_HEIGHT_THRESHOLD = 500000000;
/** Flags for LockTime() */
enum {

View File

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

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

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

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

View File

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

View File

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

61
src/deprecation.cpp Normal file
View File

@@ -0,0 +1,61 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "deprecation.h"
#include "clientversion.h"
#include "init.h"
#include "ui_interface.h"
#include "util.h"
#include "chainparams.h"
static const std::string CLIENT_VERSION_STR = FormatVersion(CLIENT_VERSION);
void EnforceNodeDeprecation(int nHeight, bool forceLogging) {
// Do not enforce deprecation in regtest or on testnet
std::string networkID = Params().NetworkIDString();
if (networkID != "main") return;
int blocksToDeprecation = DEPRECATION_HEIGHT - nHeight;
bool disableDeprecation = (GetArg("-disabledeprecation", "") == CLIENT_VERSION_STR);
if (blocksToDeprecation <= 0) {
// In order to ensure we only log once per process when deprecation is
// disabled (to avoid log spam), we only need to log in two cases:
// - The deprecating block just arrived
// - This can be triggered more than once if a block chain reorg
// occurs, but that's an irregular event that won't cause spam.
// - The node is starting
if (blocksToDeprecation == 0 || forceLogging) {
auto msg = strprintf(_("This version has been deprecated as of block height %d."),
DEPRECATION_HEIGHT) + " " +
_("You should upgrade to the latest version of Zcash.");
if (!disableDeprecation) {
msg += " " + strprintf(_("To disable deprecation for this version, set %s%s."),
"-disabledeprecation=", CLIENT_VERSION_STR);
}
LogPrintf("*** %s\n", msg);
uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR);
}
if (!disableDeprecation) {
StartShutdown();
}
} else if (blocksToDeprecation == DEPRECATION_WARN_LIMIT ||
(blocksToDeprecation < DEPRECATION_WARN_LIMIT && forceLogging)) {
std::string msg;
if (disableDeprecation) {
msg = strprintf(_("This version will be deprecated at block height %d."),
DEPRECATION_HEIGHT) + " " +
_("You should upgrade to the latest version of Zcash.");
} else {
msg = strprintf(_("This version will be deprecated at block height %d, and will automatically shut down."),
DEPRECATION_HEIGHT) + " " +
_("You should upgrade to the latest version of Zcash.") + " " +
strprintf(_("To disable deprecation for this version, set %s%s."),
"-disabledeprecation=", CLIENT_VERSION_STR);
}
LogPrintf("*** %s\n", msg);
uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_WARNING);
}
}

25
src/deprecation.h Normal file
View File

@@ -0,0 +1,25 @@
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef ZCASH_DEPRECATION_H
#define ZCASH_DEPRECATION_H
// Deprecation policy:
// * Shut down 16 weeks' worth of blocks after the estimated release block height.
// * A warning is shown during the 2 weeks' worth of blocks prior to shut down.
static const int APPROX_RELEASE_HEIGHT = 800000;
static const int WEEKS_UNTIL_DEPRECATION = 52;
static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24);
// Number of blocks before deprecation to warn users
static const int DEPRECATION_WARN_LIMIT = 60 * 24 * 60; // 2 months
/**
* Checks whether the node is deprecated based on the current block height, and
* shuts down the node with an error if so (and deprecation is not disabled for
* the current client version).
*/
void EnforceNodeDeprecation(int nHeight, bool forceLogging=false);
#endif // ZCASH_DEPRECATION_H

View File

@@ -1,68 +0,0 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "eccryptoverify.h"
namespace {
int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char *c2, size_t c2len) {
while (c1len > c2len) {
if (*c1)
return 1;
c1++;
c1len--;
}
while (c2len > c1len) {
if (*c2)
return -1;
c2++;
c2len--;
}
while (c1len > 0) {
if (*c1 > *c2)
return 1;
if (*c2 > *c1)
return -1;
c1++;
c2++;
c1len--;
}
return 0;
}
/** Order of secp256k1's generator minus 1. */
const unsigned char vchMaxModOrder[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
};
/** Half of the order of secp256k1's generator minus 1. */
const unsigned char vchMaxModHalfOrder[32] = {
0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x5D,0x57,0x6E,0x73,0x57,0xA4,0x50,0x1D,
0xDF,0xE9,0x2F,0x46,0x68,0x1B,0x20,0xA0
};
const unsigned char vchZero[1] = {0};
} // anon namespace
namespace eccrypto {
bool Check(const unsigned char *vch) {
return vch &&
CompareBigEndian(vch, 32, vchZero, 0) > 0 &&
CompareBigEndian(vch, 32, vchMaxModOrder, 32) <= 0;
}
bool CheckSignatureElement(const unsigned char *vch, int len, bool half) {
return vch &&
CompareBigEndian(vch, len, vchZero, 0) > 0 &&
CompareBigEndian(vch, len, half ? vchMaxModHalfOrder : vchMaxModOrder, 32) <= 0;
}
} // namespace eccrypto

View File

@@ -1,21 +0,0 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_ECCRYPTOVERIFY_H
#define BITCOIN_ECCRYPTOVERIFY_H
#include <vector>
#include <cstdlib>
class uint256;
namespace eccrypto {
bool Check(const unsigned char *vch);
bool CheckSignatureElement(const unsigned char *vch, int len, bool half);
} // eccrypto namespace
#endif // BITCOIN_ECCRYPTOVERIFY_H

View File

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

View File

@@ -1,40 +0,0 @@
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_ECWRAPPER_H
#define BITCOIN_ECWRAPPER_H
#include <cstddef>
#include <vector>
#include <openssl/ec.h>
class uint256;
/** RAII Wrapper around OpenSSL's EC_KEY */
class CECKey {
private:
EC_KEY *pkey;
public:
CECKey();
~CECKey();
void GetPubKey(std::vector<unsigned char>& pubkey, bool fCompressed);
bool SetPubKey(const unsigned char* pubkey, size_t size);
bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig);
/**
* reconstruct public key from a compact signature
* This is only slightly more CPU intensive than just verifying it.
* If this function succeeds, the recovered public key is guaranteed to be valid
* (the signature is a valid signature of the given data for that key)
*/
bool Recover(const uint256 &hash, const unsigned char *p64, int rec);
bool TweakPublic(const unsigned char vchTweak[32]);
static bool SanityCheck();
};
#endif // BITCOIN_ECWRAPPER_H

View File

@@ -1,15 +1,30 @@
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "crypto/common.h"
#include "pubkey.h"
#include "zcash/JoinSplit.hpp"
#include "util.h"
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
struct ECCryptoClosure
{
ECCVerifyHandle handle;
};
ECCryptoClosure instance_of_eccryptoclosure;
ZCJoinSplit* params;
int main(int argc, char **argv) {
assert(init_and_check_sodium() != -1);
libsnark::default_r1cs_ppzksnark_pp::init_public_params();
libsnark::inhibit_profiling_info = true;
libsnark::inhibit_profiling_counters = true;
boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key";
boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key";
params = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string());
testing::InitGoogleTest(&argc, argv);
testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -33,6 +33,40 @@ TEST(CheckBlock, VersionTooLow) {
EXPECT_FALSE(CheckBlock(0,0,block, state, verifier, false, false));
}
// Test that a Sprout tx with negative version is still rejected
// by CheckBlock under Sprout consensus rules.
TEST(CheckBlock, BlockSproutRejectsBadVersion) {
SelectParams(CBaseChainParams::MAIN);
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
mtx.vout.push_back(CTxOut(
GetBlockSubsidy(1, Params().GetConsensus())/5,
Params().GetFoundersRewardScriptAtHeight(1)));
mtx.fOverwintered = false;
mtx.nVersion = -1;
mtx.nVersionGroupId = 0;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
auto verifier = libzcash::ProofVerifier::Strict();
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-version-too-low", false)).Times(1);
EXPECT_FALSE(CheckBlock(block, state, verifier, false, false));
}
TEST(ContextualCheckBlock, BadCoinbaseHeight) {
SelectParams(CBaseChainParams::MAIN);
@@ -75,3 +109,125 @@ TEST(ContextualCheckBlock, BadCoinbaseHeight) {
block.vtx[0] = tx4;
EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev));
}
// Test that a block evaluated under Sprout rules cannot contain Overwinter transactions.
// This test assumes that mainnet Overwinter activation is at least height 2.
TEST(ContextualCheckBlock, BlockSproutRulesRejectOverwinterTx) {
SelectParams(CBaseChainParams::MAIN);
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1);
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
}
// Test block evaluated under Sprout rules will accept Sprout transactions
TEST(ContextualCheckBlock, BlockSproutRulesAcceptSproutTx) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
mtx.vout.push_back(CTxOut(
GetBlockSubsidy(1, Params().GetConsensus())/5,
Params().GetFoundersRewardScriptAtHeight(1)));
mtx.fOverwintered = false;
mtx.nVersion = 1;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev));
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Test block evaluated under Overwinter rules will accept Overwinter transactions
TEST(ContextualCheckBlock, BlockOverwinterRulesAcceptOverwinterTx) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
mtx.vout.push_back(CTxOut(
GetBlockSubsidy(1, Params().GetConsensus())/5,
Params().GetFoundersRewardScriptAtHeight(1)));
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev));
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}
// Test block evaluated under Overwinter rules will reject Sprout transactions
TEST(ContextualCheckBlock, BlockOverwinterRulesRejectSproutTx) {
SelectParams(CBaseChainParams::REGTEST);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1);
CMutableTransaction mtx;
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
mtx.vout[0].nValue = 0;
mtx.nVersion = 2;
CTransaction tx {mtx};
CBlock block;
block.vtx.push_back(tx);
MockCValidationState state;
CBlockIndex indexPrev {Params().GenesisBlock()};
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-active", false)).Times(1);
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
// Revert to default
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -55,12 +55,19 @@ public:
virtual bool HaveSpendingKey(const libzcash::PaymentAddress &address) const =0;
virtual bool GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey& skOut) const =0;
virtual void GetPaymentAddresses(std::set<libzcash::PaymentAddress> &setAddress) const =0;
//! Support for viewing keys
virtual bool AddViewingKey(const libzcash::ViewingKey &vk) =0;
virtual bool RemoveViewingKey(const libzcash::ViewingKey &vk) =0;
virtual bool HaveViewingKey(const libzcash::PaymentAddress &address) const =0;
virtual bool GetViewingKey(const libzcash::PaymentAddress &address, libzcash::ViewingKey& vkOut) const =0;
};
typedef std::map<CKeyID, CKey> KeyMap;
typedef std::map<CScriptID, CScript > ScriptMap;
typedef std::set<CScript> WatchOnlySet;
typedef std::map<libzcash::PaymentAddress, libzcash::SpendingKey> SpendingKeyMap;
typedef std::map<libzcash::PaymentAddress, libzcash::ViewingKey> ViewingKeyMap;
typedef std::map<libzcash::PaymentAddress, ZCNoteDecryption> NoteDecryptorMap;
/** Basic key store, that keeps keys in an address->secret map */
@@ -71,6 +78,7 @@ protected:
ScriptMap mapScripts;
WatchOnlySet setWatchOnly;
SpendingKeyMap mapSpendingKeys;
ViewingKeyMap mapViewingKeys;
NoteDecryptorMap mapNoteDecryptors;
public:
@@ -166,8 +174,19 @@ public:
setAddress.insert((*mi).first);
mi++;
}
ViewingKeyMap::const_iterator mvi = mapViewingKeys.begin();
while (mvi != mapViewingKeys.end())
{
setAddress.insert((*mvi).first);
mvi++;
}
}
}
virtual bool AddViewingKey(const libzcash::ViewingKey &vk);
virtual bool RemoveViewingKey(const libzcash::ViewingKey &vk);
virtual bool HaveViewingKey(const libzcash::PaymentAddress &address) const;
virtual bool GetViewingKey(const libzcash::PaymentAddress &address, libzcash::ViewingKey& vkOut) const;
};
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;

View File

@@ -6,6 +6,7 @@
#include "clientversion.h"
#include "coins.h"
#include "consensus/consensus.h"
#include "consensus/upgrades.h"
#include "core_io.h"
#include "keystore.h"
#include "primitives/transaction.h"
@@ -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);

View File

@@ -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(&notarized_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(&notarized_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(&notarized_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(&notarized_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);

View File

@@ -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(&notaryid,height,_pubkey33,timestamp);
komodo_chosennotary(&notaryid,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(&notarized_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,&notarized_hash,&notarized_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);
}

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -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,&timestamp,&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;

View File

@@ -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;

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -15,6 +15,7 @@
#include "chainparams.h"
#include "coins.h"
#include "consensus/consensus.h"
#include "consensus/upgrades.h"
#include "net.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
@@ -44,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

View File

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

View File

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

View File

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

View File

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

View File

@@ -12,6 +12,7 @@
#include "base58.h"
#include "chainparams.h"
#include "consensus/consensus.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#ifdef ENABLE_MINING
#include "crypto/equihash.h"
@@ -100,10 +101,6 @@ public:
void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
// Updating time can change work required on testnet:
if (consensusParams.fPowAllowMinDifficultyBlocks)
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
}
#include "komodo_defs.h"
@@ -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)
{

View File

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

View File

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

View File

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

View File

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

View File

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

63
src/paymentdisclosure.cpp Normal file
View File

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

147
src/paymentdisclosure.h Normal file
View File

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

View File

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

42
src/paymentdisclosuredb.h Normal file
View File

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

View File

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

View File

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

View File

@@ -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--)

View File

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

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