[build] autoconf adaptions for new files and targets and update dependencies
This commit is contained in:
parent
77d280acfc
commit
8e04b9dd54
|
@ -116,3 +116,6 @@ test/cache/*
|
|||
|
||||
libbitcoinconsensus.pc
|
||||
contrib/devtools/split-debug.sh
|
||||
|
||||
src/zcash/CreateJoinSplit
|
||||
src/zcash/GenerateParams
|
43
Makefile.am
43
Makefile.am
|
@ -65,7 +65,8 @@ OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \
|
|||
COVERAGE_INFO = baseline.info \
|
||||
test_bitcoin_filtered.info total_coverage.info \
|
||||
baseline_filtered.info functional_test.info functional_test_filtered.info \
|
||||
test_bitcoin_coverage.info test_bitcoin.info
|
||||
test_bitcoin_coverage.info test_bitcoin.info \
|
||||
zcash-gtest.info zcash-gtest_filtered.info zcash-gtest_coverage.info
|
||||
|
||||
dist-hook:
|
||||
-$(GIT) archive --format=tar HEAD -- src/clientversion.cpp | $(AMTAR) -C $(top_distdir) -xf -
|
||||
|
@ -187,6 +188,24 @@ test_bitcoin_filtered.info: test_bitcoin.info
|
|||
$(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@
|
||||
$(LCOV) -a $@ $(LCOV_OPTS) -o $@
|
||||
|
||||
zcash-gtest.info: baseline_filtered_combined.info
|
||||
$(MAKE) -C src/ zcash-gtest_check
|
||||
$(LCOV) -c -d $(abs_builddir)/src -t zcash-gtest -o $@
|
||||
$(LCOV) -z -d $(abs_builddir)/src
|
||||
$(LCOV) -z -d $(abs_builddir)/src/leveldb
|
||||
|
||||
zcash-gtest_filtered.info: zcash-gtest.info
|
||||
$(LCOV) -r $< "/usr/include/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
|
||||
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
|
||||
"$(abs_builddir)/src/gtest/*" \
|
||||
"$(abs_builddir)/src/test/*" \
|
||||
"$(abs_builddir)/src/wallet/gtest/*" \
|
||||
"$(abs_builddir)/src/wallet/test/*" \
|
||||
-o $@
|
||||
|
||||
functional_test.info: test_bitcoin_filtered.info
|
||||
-@TIMEOUT=15 test/functional/test_runner.py $(EXTENDED_FUNCTIONAL_TESTS)
|
||||
$(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src --t functional-tests -o $@
|
||||
|
@ -199,24 +218,34 @@ functional_test_filtered.info: functional_test.info
|
|||
test_bitcoin_coverage.info: baseline_filtered.info test_bitcoin_filtered.info
|
||||
$(LCOV) -a $(LCOV_OPTS) baseline_filtered.info -a test_bitcoin_filtered.info -o $@
|
||||
|
||||
total_coverage.info: test_bitcoin_filtered.info functional_test_filtered.info
|
||||
$(LCOV) -a $(LCOV_OPTS) baseline_filtered.info -a test_bitcoin_filtered.info -a functional_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt
|
||||
zcash-gtest_coverage.info: baseline_filtered_combined.info zcash-gtest_filtered.info
|
||||
$(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a zcash-gtest_filtered.info -o $@
|
||||
|
||||
total_coverage.info: test_bitcoin_filtered.info functional_test_filtered.info zcash-gtest_filtered.info
|
||||
$(LCOV) -a $(LCOV_OPTS) baseline_filtered.info -a test_bitcoin_filtered.info -a functional_test_filtered.info -a zcash-gtest_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt
|
||||
|
||||
test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info
|
||||
$(GENHTML) -s $(LCOV_OPTS) $< -o $(@D)
|
||||
@touch $@
|
||||
|
||||
zcash-gtest.coverage/.dirstamp: zcash-gtest_coverage.info
|
||||
$(GENHTML) -s $< -o $(@D)
|
||||
@touch $@
|
||||
|
||||
cov-zcash: zcash-gtest.coverage/.dirstamp
|
||||
|
||||
total.coverage/.dirstamp: total_coverage.info
|
||||
$(GENHTML) -s $(LCOV_OPTS) $< -o $(@D)
|
||||
@touch $@
|
||||
|
||||
cov: test_bitcoin.coverage/.dirstamp total.coverage/.dirstamp
|
||||
cov: test_bitcoin.coverage/.dirstamp cov-zcash total.coverage/.dirstamp
|
||||
|
||||
endif
|
||||
|
||||
dist_bin_SCRIPTS = zcutil/fetch-params.sh
|
||||
dist_noinst_SCRIPTS = autogen.sh
|
||||
|
||||
EXTRA_DIST = $(DIST_SHARE) test/functional/test_runner.py test/functional $(DIST_CONTRIB) $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS)
|
||||
EXTRA_DIST = $(DIST_SHARE) test/functional/test_runner.py test/functional test/zcash $(DIST_CONTRIB) $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS)
|
||||
|
||||
EXTRA_DIST += \
|
||||
test/util/bitcoin-util-test.py \
|
||||
|
@ -273,6 +302,8 @@ EXTRA_DIST += \
|
|||
test/util/rpcauth-test.py
|
||||
|
||||
CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER)
|
||||
install-exec-hook:
|
||||
mv $(DESTDIR)$(bindir)/fetch-params.sh $(DESTDIR)$(bindir)/zcash-fetch-params
|
||||
|
||||
.INTERMEDIATE: $(COVERAGE_INFO)
|
||||
|
||||
|
@ -294,6 +325,6 @@ clean-docs:
|
|||
rm -rf doc/doxygen
|
||||
|
||||
clean-local: clean-docs
|
||||
rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ test/tmp/ cache/ $(OSX_APP)
|
||||
rm -rf coverage_percent.txt test_bitcoin.coverage/ zcash-gtest.coverage/ total.coverage/ test/tmp/ cache/ $(OSX_APP)
|
||||
rm -rf test/functional/__pycache__ test/functional/test_framework/__pycache__ test/cache
|
||||
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_openmp.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_OPENMP([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro tries to find out how to compile programs that use OpenMP a
|
||||
# standard API and set of compiler directives for parallel programming
|
||||
# (see http://www-unix.mcs/)
|
||||
#
|
||||
# On success, it sets the OPENMP_CFLAGS/OPENMP_CXXFLAGS/OPENMP_F77FLAGS
|
||||
# output variable to the flag (e.g. -omp) used both to compile *and* link
|
||||
# OpenMP programs in the current language.
|
||||
#
|
||||
# NOTE: You are assumed to not only compile your program with these flags,
|
||||
# but also link it with them as well.
|
||||
#
|
||||
# If you want to compile everything with OpenMP, you should set:
|
||||
#
|
||||
# CFLAGS="$CFLAGS $OPENMP_CFLAGS"
|
||||
# #OR# CXXFLAGS="$CXXFLAGS $OPENMP_CXXFLAGS"
|
||||
# #OR# FFLAGS="$FFLAGS $OPENMP_FFLAGS"
|
||||
#
|
||||
# (depending on the selected language).
|
||||
#
|
||||
# The user can override the default choice by setting the corresponding
|
||||
# environment variable (e.g. OPENMP_CFLAGS).
|
||||
#
|
||||
# ACTION-IF-FOUND is a list of shell commands to run if an OpenMP flag is
|
||||
# found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it is
|
||||
# not found. If ACTION-IF-FOUND is not specified, the default action will
|
||||
# define HAVE_OPENMP.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
# Copyright (c) 2015 John W. Peterson <jwpeterson@gmail.com>
|
||||
# Copyright (c) 2016 Nick R. Papior <nickpapior@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 13
|
||||
|
||||
AC_DEFUN([AX_OPENMP], [
|
||||
AC_PREREQ([2.69]) dnl for _AC_LANG_PREFIX
|
||||
|
||||
AC_CACHE_CHECK([for OpenMP flag of _AC_LANG compiler], ax_cv_[]_AC_LANG_ABBREV[]_openmp, [save[]_AC_LANG_PREFIX[]FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
|
||||
ax_cv_[]_AC_LANG_ABBREV[]_openmp=unknown
|
||||
# Flags to try: -fopenmp (gcc), -mp (SGI & PGI),
|
||||
# -qopenmp (icc>=15), -openmp (icc),
|
||||
# -xopenmp (Sun), -omp (Tru64),
|
||||
# -qsmp=omp (AIX),
|
||||
# none
|
||||
ax_openmp_flags="-fopenmp -openmp -qopenmp -mp -xopenmp -omp -qsmp=omp none"
|
||||
if test "x$OPENMP_[]_AC_LANG_PREFIX[]FLAGS" != x; then
|
||||
ax_openmp_flags="$OPENMP_[]_AC_LANG_PREFIX[]FLAGS $ax_openmp_flags"
|
||||
fi
|
||||
for ax_openmp_flag in $ax_openmp_flags; do
|
||||
case $ax_openmp_flag in
|
||||
none) []_AC_LANG_PREFIX[]FLAGS=$save[]_AC_LANG_PREFIX[] ;;
|
||||
*) []_AC_LANG_PREFIX[]FLAGS="$save[]_AC_LANG_PREFIX[]FLAGS $ax_openmp_flag" ;;
|
||||
esac
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[
|
||||
@%:@include <omp.h>
|
||||
|
||||
static void
|
||||
parallel_fill(int * data, int n)
|
||||
{
|
||||
int i;
|
||||
@%:@pragma omp parallel for
|
||||
for (i = 0; i < n; ++i)
|
||||
data[i] = i;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
int arr[100000];
|
||||
omp_set_num_threads(2);
|
||||
parallel_fill(arr, 100000);
|
||||
return 0;
|
||||
}
|
||||
]])],[ax_cv_[]_AC_LANG_ABBREV[]_openmp=$ax_openmp_flag; break],[])
|
||||
done
|
||||
[]_AC_LANG_PREFIX[]FLAGS=$save[]_AC_LANG_PREFIX[]FLAGS
|
||||
])
|
||||
if test "x$ax_cv_[]_AC_LANG_ABBREV[]_openmp" = "xunknown"; then
|
||||
m4_default([$2],:)
|
||||
else
|
||||
if test "x$ax_cv_[]_AC_LANG_ABBREV[]_openmp" != "xnone"; then
|
||||
OPENMP_[]_AC_LANG_PREFIX[]FLAGS=$ax_cv_[]_AC_LANG_ABBREV[]_openmp
|
||||
fi
|
||||
m4_default([$1], [AC_DEFINE(HAVE_OPENMP,1,[Define if OpenMP is enabled])])
|
||||
fi
|
||||
])dnl AX_OPENMP
|
|
@ -2,7 +2,7 @@ dnl Copyright (c) 2013-2015 The Bitcoin Core developers
|
|||
dnl Distributed under the MIT software license, see the accompanying
|
||||
dnl file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
AC_DEFUN([BITCOIN_FIND_BDB48],[
|
||||
AC_DEFUN([BITCOIN_FIND_BDB62],[
|
||||
AC_ARG_VAR(BDB_CFLAGS, [C compiler flags for BerkeleyDB, bypasses autodetection])
|
||||
AC_ARG_VAR(BDB_LIBS, [Linker flags for BerkeleyDB, bypasses autodetection])
|
||||
|
||||
|
@ -10,9 +10,9 @@ AC_DEFUN([BITCOIN_FIND_BDB48],[
|
|||
AC_MSG_CHECKING([for Berkeley DB C++ headers])
|
||||
BDB_CPPFLAGS=
|
||||
bdbpath=X
|
||||
bdb48path=X
|
||||
bdb62path=X
|
||||
bdbdirlist=
|
||||
for _vn in 4.8 48 4 5 5.3 ''; do
|
||||
for _vn in 6.2 62 6 ''; do
|
||||
for _pfx in b lib ''; do
|
||||
bdbdirlist="$bdbdirlist ${_pfx}db${_vn}"
|
||||
done
|
||||
|
@ -22,8 +22,8 @@ AC_DEFUN([BITCOIN_FIND_BDB48],[
|
|||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <${searchpath}db_cxx.h>
|
||||
]],[[
|
||||
#if !((DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || DB_VERSION_MAJOR > 4)
|
||||
#error "failed to find bdb 4.8+"
|
||||
#if !((DB_VERSION_MAJOR == 6 && DB_VERSION_MINOR >= 2) || DB_VERSION_MAJOR > 6)
|
||||
#error "failed to find bdb 6.2+"
|
||||
#endif
|
||||
]])],[
|
||||
if test "x$bdbpath" = "xX"; then
|
||||
|
@ -35,36 +35,36 @@ AC_DEFUN([BITCOIN_FIND_BDB48],[
|
|||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <${searchpath}db_cxx.h>
|
||||
]],[[
|
||||
#if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 8)
|
||||
#error "failed to find bdb 4.8"
|
||||
#if !(DB_VERSION_MAJOR == 6 && DB_VERSION_MINOR == 2)
|
||||
#error "failed to find bdb 6.2"
|
||||
#endif
|
||||
]])],[
|
||||
bdb48path="${searchpath}"
|
||||
bdb62path="${searchpath}"
|
||||
break
|
||||
],[])
|
||||
done
|
||||
if test "x$bdbpath" = "xX"; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([libdb_cxx headers missing, ]AC_PACKAGE_NAME[ requires this library for wallet functionality (--disable-wallet to disable wallet functionality)])
|
||||
elif test "x$bdb48path" = "xX"; then
|
||||
elif test "x$bdb62path" = "xX"; then
|
||||
BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdbpath}],db_cxx)
|
||||
AC_ARG_WITH([incompatible-bdb],[AS_HELP_STRING([--with-incompatible-bdb], [allow using a bdb version other than 4.8])],[
|
||||
AC_MSG_WARN([Found Berkeley DB other than 4.8; wallets opened by this build will not be portable!])
|
||||
AC_ARG_WITH([incompatible-bdb],[AS_HELP_STRING([--with-incompatible-bdb], [allow using a bdb version other than 6.2])],[
|
||||
AC_MSG_WARN([Found Berkeley DB other than 6.2; wallets opened by this build will not be portable!])
|
||||
],[
|
||||
AC_MSG_ERROR([Found Berkeley DB other than 4.8, required for portable wallets (--with-incompatible-bdb to ignore or --disable-wallet to disable wallet functionality)])
|
||||
AC_MSG_ERROR([Found Berkeley DB other than 6.2, required for portable wallets (--with-incompatible-bdb to ignore or --disable-wallet to disable wallet functionality)])
|
||||
])
|
||||
else
|
||||
BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdb48path}],db_cxx)
|
||||
bdbpath="${bdb48path}"
|
||||
BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdb62path}],db_cxx)
|
||||
bdbpath="${bdb62path}"
|
||||
fi
|
||||
else
|
||||
BDB_CPPFLAGS=${BDB_CFLAGS}
|
||||
fi
|
||||
AC_SUBST(BDB_CPPFLAGS)
|
||||
|
||||
|
||||
if test "x$BDB_LIBS" = "x"; then
|
||||
# TODO: Ideally this could find the library version and make sure it matches the headers being used
|
||||
for searchlib in db_cxx-4.8 db_cxx db4_cxx; do
|
||||
for searchlib in db_cxx-6.2 db_cxx db6_cxx; do
|
||||
AC_CHECK_LIB([$searchlib],[main],[
|
||||
BDB_LIBS="-l${searchlib}"
|
||||
break
|
87
configure.ac
87
configure.ac
|
@ -8,6 +8,7 @@ define(_CLIENT_VERSION_IS_RELEASE, false)
|
|||
define(_COPYRIGHT_YEAR, 2018)
|
||||
define(_COPYRIGHT_HOLDERS,[The %s developers])
|
||||
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Bitcoin Core]])
|
||||
define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50)))
|
||||
AC_INIT([Bitcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/bitcoin/bitcoin/issues],[bitcoin],[https://bitcoincore.org/])
|
||||
AC_CONFIG_SRCDIR([src/validation.cpp])
|
||||
AC_CONFIG_HEADERS([src/config/bitcoin-config.h])
|
||||
|
@ -108,6 +109,12 @@ AC_ARG_ENABLE([wallet],
|
|||
[enable_wallet=$enableval],
|
||||
[enable_wallet=yes])
|
||||
|
||||
AC_ARG_ENABLE([mining],
|
||||
[AS_HELP_STRING([--enable-mining],
|
||||
[enable mining (default is yes)])],
|
||||
[enable_mining=$enableval],
|
||||
[enable_mining=yes])
|
||||
|
||||
AC_ARG_WITH([miniupnpc],
|
||||
[AS_HELP_STRING([--with-miniupnpc],
|
||||
[enable UPNP (default is yes if libminiupnpc is found)])],
|
||||
|
@ -281,6 +288,26 @@ if test x$use_sanitizers != x; then
|
|||
[AC_MSG_ERROR([linker did not accept requested flags, you are missing required libraries])])
|
||||
fi
|
||||
|
||||
if test x$use_sanitizers != x; then
|
||||
# First check if the compiler accepts flags. If an incompatible pair like
|
||||
# -fsanitize=address,thread is used here, this check will fail. This will also
|
||||
# fail if a bad argument is passed, e.g. -fsanitize=undfeined
|
||||
AX_CHECK_COMPILE_FLAG(
|
||||
[[-fsanitize=$use_sanitizers]],
|
||||
[[SANITIZER_CXXFLAGS=-fsanitize=$use_sanitizers]],
|
||||
[AC_MSG_ERROR([compiler did not accept requested flags])])
|
||||
|
||||
# Some compilers (e.g. GCC) require additional libraries like libasan,
|
||||
# libtsan, libubsan, etc. Make sure linking still works with the sanitize
|
||||
# flag. This is a separate check so we can give a better error message when
|
||||
# the sanitize flags are supported by the compiler but the actual sanitizer
|
||||
# libs are missing.
|
||||
AX_CHECK_LINK_FLAG(
|
||||
[[-fsanitize=$use_sanitizers]],
|
||||
[[SANITIZER_LDFLAGS=-fsanitize=$use_sanitizers]],
|
||||
[AC_MSG_ERROR([linker did not accept requested flags, you are missing required libraries])])
|
||||
fi
|
||||
|
||||
ERROR_CXXFLAGS=
|
||||
if test "x$enable_werror" = "xyes"; then
|
||||
if test "x$CXXFLAG_WERROR" = "x"; then
|
||||
|
@ -428,9 +455,9 @@ case $host in
|
|||
dnl add default macports paths
|
||||
CPPFLAGS="$CPPFLAGS -isystem /opt/local/include"
|
||||
LIBS="$LIBS -L/opt/local/lib"
|
||||
if test -d /opt/local/include/db48; then
|
||||
CPPFLAGS="$CPPFLAGS -I/opt/local/include/db48"
|
||||
LIBS="$LIBS -L/opt/local/lib/db48"
|
||||
if test -d /opt/local/include/db62; then
|
||||
CPPFLAGS="$CPPFLAGS -I/opt/local/include/db62"
|
||||
LIBS="$LIBS -L/opt/local/lib/db62"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@ -778,7 +805,7 @@ AC_SUBST(LIBMEMENV)
|
|||
|
||||
if test x$enable_wallet != xno; then
|
||||
dnl Check for libdb_cxx only if wallet enabled
|
||||
BITCOIN_FIND_BDB48
|
||||
BITCOIN_FIND_BDB62
|
||||
fi
|
||||
|
||||
dnl Check for libminiupnpc (optional)
|
||||
|
@ -804,7 +831,7 @@ fi
|
|||
if test x$use_boost = xyes; then
|
||||
|
||||
dnl Minimum required Boost version
|
||||
define(MINIMUM_REQUIRED_BOOST, 1.47.0)
|
||||
define(MINIMUM_REQUIRED_BOOST, 1.62)
|
||||
|
||||
dnl Check for boost libs
|
||||
AX_BOOST_BASE([MINIMUM_REQUIRED_BOOST])
|
||||
|
@ -1102,6 +1129,40 @@ AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$need_bundled_univalue = xyes])
|
|||
AC_SUBST(UNIVALUE_CFLAGS)
|
||||
AC_SUBST(UNIVALUE_LIBS)
|
||||
|
||||
# These packages don't provide pkgconfig config files across all
|
||||
# platforms, so we use older autoconf detection mechanisms:
|
||||
AC_CHECK_HEADER([gmp.h],,AC_MSG_ERROR(libgmp headers missing))
|
||||
AC_CHECK_LIB([gmp],[[__gmpn_sub_n]],GMP_LIBS=-lgmp, [AC_MSG_ERROR(libgmp missing)])
|
||||
|
||||
AC_CHECK_HEADER([gmpxx.h],,AC_MSG_ERROR(libgmpxx headers missing))
|
||||
AC_CHECK_LIB([gmpxx],[main],GMPXX_LIBS=-lgmpxx, [AC_MSG_ERROR(libgmpxx missing)])
|
||||
|
||||
RUST_LIBS="-lrustzcash"
|
||||
|
||||
dnl Check for OpenMP support
|
||||
AX_OPENMP(
|
||||
[AC_DEFINE(HAVE_OPENMP, 1, [Define if OpenMP is enabled])
|
||||
AM_CONDITIONAL([HAVE_OPENMP], [true])
|
||||
CXXFLAGS="$CXXFLAGS $OPENMP_CXXFLAGS"],
|
||||
[AC_MSG_WARN([OpenMP not supported, disabling multithreading])
|
||||
AC_DEFINE(HAVE_OPENMP, 0, [Define if OpenMP is enabled])
|
||||
AM_CONDITIONAL([HAVE_OPENMP], [false])])
|
||||
|
||||
# Gitian uses a config.site that sets depends_prefix, and then sets --prefix=/
|
||||
# build.sh just uses --prefix
|
||||
if test x$depends_prefix != x; then
|
||||
LIBSNARK_DEPINST="$depends_prefix"
|
||||
else
|
||||
LIBSNARK_DEPINST="$prefix"
|
||||
fi
|
||||
|
||||
# Additional Zcash flags
|
||||
AX_CHECK_COMPILE_FLAG([-fwrapv],[CXXFLAGS="$CXXFLAGS -fwrapv"])
|
||||
AX_CHECK_COMPILE_FLAG([-fno-strict-aliasing],[CXXFLAGS="$CXXFLAGS -fno-strict-aliasing"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wno-builtin-declaration-mismatch],[CXXFLAGS="$CXXFLAGS -Wno-builtin-declaration-mismatch"],,[[$CXXFLAG_WERROR]])
|
||||
|
||||
LIBZCASH_LIBS="-lgmp -lgmpxx $BOOST_SYSTEM_LIB -lcrypto -lsodium $RUST_LIBS"
|
||||
|
||||
BITCOIN_QT_PATH_PROGS([PROTOC], [protoc],$protoc_bin_path)
|
||||
|
||||
AC_MSG_CHECKING([whether to build bitcoind])
|
||||
|
@ -1151,6 +1212,15 @@ else
|
|||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
dnl enable mining
|
||||
AC_MSG_CHECKING([if mining should be enabled])
|
||||
if test x$enable_mining != xno; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(ENABLE_MINING, 1, [Define to 1 to enable mining functions])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
dnl enable upnp support
|
||||
AC_MSG_CHECKING([whether to build with support for UPnP])
|
||||
if test x$have_miniupnpc = xno; then
|
||||
|
@ -1244,6 +1314,7 @@ AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin])
|
|||
AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin])
|
||||
AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows])
|
||||
AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes])
|
||||
AM_CONDITIONAL([ENABLE_MINING],[test x$enable_mining = xyes])
|
||||
AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes])
|
||||
AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes])
|
||||
AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$BUILD_TEST_QT = xyes])
|
||||
|
@ -1310,6 +1381,10 @@ AC_SUBST(EVENT_PTHREADS_LIBS)
|
|||
AC_SUBST(ZMQ_LIBS)
|
||||
AC_SUBST(PROTOBUF_LIBS)
|
||||
AC_SUBST(QR_LIBS)
|
||||
AC_SUBST(GMP_LIBS)
|
||||
AC_SUBST(GMPXX_LIBS)
|
||||
AC_SUBST(LIBSNARK_DEPINST)
|
||||
AC_SUBST(LIBZCASH_LIBS)
|
||||
AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist test/config.ini])
|
||||
AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh])
|
||||
AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile])])
|
||||
|
@ -1346,7 +1421,7 @@ if test x$need_bundled_univalue = xyes; then
|
|||
fi
|
||||
|
||||
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery --disable-jni"
|
||||
AC_CONFIG_SUBDIRS([src/secp256k1])
|
||||
AC_CONFIG_SUBDIRS([src/secp256k1 src/snark])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ SDK_PATH ?= $(BASEDIR)/SDKs
|
|||
NO_QT ?=
|
||||
NO_WALLET ?=
|
||||
NO_UPNP ?=
|
||||
PRIORITY_DOWNLOAD_PATH ?= https://z.cash/depends-sources
|
||||
FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources
|
||||
|
||||
BUILD = $(shell ./config.guess)
|
||||
|
@ -16,12 +17,14 @@ BASEDIR = $(CURDIR)
|
|||
HASH_LENGTH:=11
|
||||
DOWNLOAD_CONNECT_TIMEOUT:=10
|
||||
DOWNLOAD_RETRIES:=3
|
||||
CRATE_REGISTRY:=vendored-sources
|
||||
HOST_ID_SALT ?= salt
|
||||
BUILD_ID_SALT ?= salt
|
||||
|
||||
host:=$(BUILD)
|
||||
ifneq ($(HOST),)
|
||||
host:=$(HOST)
|
||||
host_toolchain:=$(HOST)-
|
||||
endif
|
||||
|
||||
ifneq ($(DEBUG),)
|
||||
|
@ -93,7 +96,7 @@ qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) $(qt_$(host_arch
|
|||
wallet_packages_$(NO_WALLET) = $(wallet_packages)
|
||||
upnp_packages_$(NO_UPNP) = $(upnp_packages)
|
||||
|
||||
packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_)
|
||||
packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(rust_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_)
|
||||
native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages)
|
||||
|
||||
ifneq ($(qt_packages_),)
|
||||
|
@ -102,7 +105,7 @@ endif
|
|||
|
||||
all_packages = $(packages) $(native_packages)
|
||||
|
||||
meta_depends = Makefile funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk
|
||||
meta_depends = Makefile funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk cargo-checksum.sh
|
||||
|
||||
$(host_arch)_$(host_os)_native_toolchain?=$($(host_os)_native_toolchain)
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
echo "{\"files\":{$(
|
||||
find . -type f | # Get list of file paths
|
||||
grep -v $1 | # Exclude Makefile hashes
|
||||
grep -v '[.]stamp_' | # Exclude Makefile stamps
|
||||
sed 's|^[.]/||' | # Remove leading ./
|
||||
sort | # Sort (for uniformity)
|
||||
xargs $2 | # Get SHA256 hashes (assumes standard 'H(A) A' format)
|
||||
awk -v OFS='":"' '{print $2, $1}' | # 'H(A) A' -> 'A":"H(A)'
|
||||
sed 's|^|"|' | # 'A":"H(A)' -> '"A":"H(A)'
|
||||
sed 's|$|"|' | # '"A":"H(A)' -> '"A":"H(A)"'
|
||||
tr '\n' ',' | # Concatenate lines with commas
|
||||
sed 's|,$||' # Remove any trailing comma (to fit JSON spec)
|
||||
)},\"package\":\"$3\"}" > .cargo-checksum.json
|
|
@ -31,9 +31,22 @@ endef
|
|||
define fetch_file
|
||||
( test -f $$($(1)_source_dir)/$(4) || \
|
||||
( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \
|
||||
$(call fetch_file_inner,$(1),$(PRIORITY_DOWNLOAD_PATH),$(3),$(4),$(5)) || \
|
||||
$(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5))))
|
||||
endef
|
||||
|
||||
define generate_crate_checksum
|
||||
rm .gitignore && \
|
||||
$(BASEDIR)/cargo-checksum.sh "$($(1)_file_name)" "$(build_SHA256SUM)" "$($(1)_sha256_hash)"
|
||||
endef
|
||||
|
||||
define vendor_crate_source
|
||||
mkdir -p $($(1)_staging_prefix_dir)/$(CRATE_REGISTRY) && \
|
||||
cp -r $($(1)_extract_dir) $($(1)_staging_prefix_dir)/$(CRATE_REGISTRY)/$($(1)_crate_name) && \
|
||||
cd $($(1)_staging_prefix_dir)/$(CRATE_REGISTRY)/$($(1)_crate_versioned_name) && \
|
||||
rm -r `basename $($(1)_patch_dir)` .stamp_* .$($(1)_file_name).hash
|
||||
endef
|
||||
|
||||
define int_get_build_recipe_hash
|
||||
$(eval $(1)_all_file_checksums:=$(shell $(build_SHA256SUM) $(meta_depends) packages/$(1).mk $(addprefix $(PATCHES_PATH)/$(1)/,$($(1)_patches)) | cut -d" " -f1))
|
||||
$(eval $(1)_recipe_hash:=$(shell echo -n "$($(1)_all_file_checksums)" | $(build_SHA256SUM) | cut -d" " -f1))
|
||||
|
@ -47,6 +60,10 @@ $(eval $(1)_build_id_long:=$(1)-$($(1)_version)-$($(1)_recipe_hash)-$(release_ty
|
|||
$(eval $(1)_build_id:=$(shell echo -n "$($(1)_build_id_long)" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH)))
|
||||
final_build_id_long+=$($(package)_build_id_long)
|
||||
|
||||
#override platform specific files and hashes
|
||||
$(eval $(1)_file_name=$(if $($(1)_file_name_$(host_os)),$($(1)_file_name_$(host_os)),$($(1)_file_name)))
|
||||
$(eval $(1)_sha256_hash=$(if $($(1)_sha256_hash_$(host_os)),$($(1)_sha256_hash_$(host_os)),$($(1)_sha256_hash)))
|
||||
|
||||
#compute package-specific paths
|
||||
$(1)_build_subdir?=.
|
||||
$(1)_download_file?=$($(1)_file_name)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package=bdb
|
||||
$(package)_version=4.8.30
|
||||
$(package)_version=6.2.23
|
||||
$(package)_download_path=http://download.oracle.com/berkeley-db
|
||||
$(package)_file_name=db-$($(package)_version).NC.tar.gz
|
||||
$(package)_sha256_hash=12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef
|
||||
$(package)_file_name=db-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=47612c8991aa9ac2f6be721267c8d3cdccf5ac83105df8e50809daea24e95dc7
|
||||
$(package)_build_subdir=build_unix
|
||||
|
||||
define $(package)_set_vars
|
||||
|
@ -13,9 +13,8 @@ $(package)_cxxflags=-std=c++11
|
|||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
sed -i.old 's/__atomic_compare_exchange/__atomic_compare_exchange_db/' dbinc/atomic.h && \
|
||||
sed -i.old 's/atomic_init/atomic_init_db/' dbinc/atomic.h mp/mp_region.c mp/mp_mvcc.c mp/mp_fget.c mutex/mut_method.c mutex/mut_tas.c && \
|
||||
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub dist
|
||||
sed -i.old 's/__atomic_compare_exchange\\(/__atomic_compare_exchange_db(/' src/dbinc/atomic.h && \
|
||||
sed -i.old 's/atomic_init/atomic_init_db/' src/dbinc/atomic.h src/mp/mp_region.c src/mp/mp_mvcc.c src/mp/mp_fget.c src/mutex/mut_method.c src/mutex/mut_tas.c
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
|
@ -23,7 +22,7 @@ define $(package)_config_cmds
|
|||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE) libdb_cxx-4.8.a libdb-4.8.a
|
||||
$(MAKE) libdb_cxx-6.2.a libdb-6.2.a
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package=crate_libc
|
||||
$(package)_crate_name=libc
|
||||
$(package)_version=0.2.21
|
||||
$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name)
|
||||
$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate
|
||||
$(package)_sha256_hash=88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135
|
||||
$(package)_crate_versioned_name=$($(package)_crate_name)
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
$(call generate_crate_checksum,$(package))
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(call vendor_crate_source,$(package))
|
||||
endef
|
|
@ -0,0 +1,19 @@
|
|||
package=googletest
|
||||
$(package)_version=1.8.0
|
||||
$(package)_download_path=https://github.com/google/$(package)/archive/
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_download_file=release-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=58a6f4277ca2bc8565222b3bbd58a177609e9c488e8a72649359ba51450db7d8
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE) -C googlemock/make CXXFLAGS=-fPIC gmock.a && \
|
||||
$(MAKE) -C googletest/make CXXFLAGS=-fPIC gtest.a
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
mkdir -p $($(package)_staging_dir)$(host_prefix)/lib && \
|
||||
install ./googlemock/make/gmock.a $($(package)_staging_dir)$(host_prefix)/lib/libgmock.a && \
|
||||
install ./googletest/make/gtest.a $($(package)_staging_dir)$(host_prefix)/lib/libgtest.a && \
|
||||
cp -a ./googlemock/include $($(package)_staging_dir)$(host_prefix)/ && \
|
||||
cp -a ./googletest/include $($(package)_staging_dir)$(host_prefix)/
|
||||
endef
|
|
@ -0,0 +1,19 @@
|
|||
package=libgmp
|
||||
$(package)_version=6.1.1
|
||||
$(package)_download_path=https://gmplib.org/download/gmp/
|
||||
$(package)_file_name=gmp-$($(package)_version).tar.bz2
|
||||
$(package)_sha256_hash=a8109865f2893f1373b0a8ed5ff7429de8db696fc451b1036bd7bdf95bbeffd6
|
||||
$(package)_dependencies=
|
||||
$(package)_config_opts=--enable-cxx --disable-shared
|
||||
|
||||
define $(package)_config_cmds
|
||||
$($(package)_autoconf) --host=$(host) --build=$(build)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE) CPPFLAGS='-fPIC'
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install ; echo '=== staging find for $(package):' ; find $($(package)_staging_dir)
|
||||
endef
|
|
@ -0,0 +1,25 @@
|
|||
package=librustzcash
|
||||
$(package)_version=0.1
|
||||
$(package)_download_path=https://github.com/zcash/$(package)/archive/
|
||||
$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz
|
||||
$(package)_download_file=$($(package)_git_commit).tar.gz
|
||||
$(package)_sha256_hash=a5760a90d4a1045c8944204f29fa2a3cf2f800afee400f88bf89bbfe2cce1279
|
||||
$(package)_git_commit=91348647a86201a9482ad4ad68398152dc3d635e
|
||||
$(package)_dependencies=rust $(rust_crates)
|
||||
$(package)_patches=cargo.config
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
mkdir .cargo && \
|
||||
cat $($(package)_patch_dir)/cargo.config | sed 's|CRATE_REGISTRY|$(host_prefix)/$(CRATE_REGISTRY)|' > .cargo/config
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
cargo build --frozen --release
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
mkdir $($(package)_staging_dir)$(host_prefix)/lib/ && \
|
||||
mkdir $($(package)_staging_dir)$(host_prefix)/include/ && \
|
||||
cp target/release/librustzcash.a $($(package)_staging_dir)$(host_prefix)/lib/ && \
|
||||
cp include/librustzcash.h $($(package)_staging_dir)$(host_prefix)/include/
|
||||
endef
|
|
@ -0,0 +1,23 @@
|
|||
package=libsodium
|
||||
$(package)_version=1.0.15
|
||||
$(package)_download_path=https://download.libsodium.org/libsodium/releases/
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=fb6a9e879a2f674592e4328c5d9f79f082405ee4bb05cb6e679b90afe9e178f4
|
||||
$(package)_dependencies=
|
||||
$(package)_config_opts=
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
cd $($(package)_build_subdir); ./autogen.sh
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
$($(package)_autoconf) --enable-static --disable-shared
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
|
@ -0,0 +1,25 @@
|
|||
package=native_ccache
|
||||
$(package)_version=3.3.1
|
||||
$(package)_download_path=https://www.samba.org/ftp/ccache
|
||||
$(package)_file_name=ccache-$($(package)_version).tar.bz2
|
||||
$(package)_sha256_hash=cb6e4bafbb19ba0a2ec43386b123a5f92a20e1e3384c071d5d13e0cb3c84bf73
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
$($(package)_autoconf)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
|
||||
define $(package)_postprocess_cmds
|
||||
rm -rf lib include
|
||||
endef
|
|
@ -1,4 +1,10 @@
|
|||
packages:=boost openssl libevent zeromq
|
||||
rust_crates := crate_libc
|
||||
rust_packages := rust $(rust_crates) librustzcash
|
||||
proton_packages := proton
|
||||
zcash_packages := libgmp libsodium
|
||||
native_packages := native_ccache
|
||||
|
||||
packages:=boost openssl libevent zeromq $(zcash_packages) googletest
|
||||
|
||||
qt_native_packages = native_protobuf
|
||||
qt_packages = qrencode protobuf zlib
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package=rust
|
||||
$(package)_version=1.16.0
|
||||
$(package)_download_path=https://static.rust-lang.org/dist
|
||||
$(package)_file_name_linux=rust-$($(package)_version)-x86_64-unknown-linux-gnu.tar.gz
|
||||
$(package)_sha256_hash_linux=48621912c242753ba37cad5145df375eeba41c81079df46f93ffb4896542e8fd
|
||||
$(package)_file_name_darwin=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz
|
||||
$(package)_sha256_hash_darwin=2d08259ee038d3a2c77a93f1a31fc59e7a1d6d1bbfcba3dba3c8213b2e5d1926
|
||||
$(package)_file_name_mingw32=rust-mingw-$($(package)_version)-x86_64-pc-windows-gnu.tar.gz
|
||||
$(package)_sha256_hash_mingw32=4975e1f8eade1afca5dd17e71659f665f3bcc645733a545179c887543da1e27c
|
||||
|
||||
|
||||
define $(package)_stage_cmds
|
||||
./install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig
|
||||
endef
|
|
@ -0,0 +1,5 @@
|
|||
[source.crates-io]
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source.vendored-sources]
|
||||
directory = "CRATE_REGISTRY"
|
|
@ -0,0 +1,107 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
function cmd_pref() {
|
||||
if type -p "$2" > /dev/null; then
|
||||
eval "$1=$2"
|
||||
else
|
||||
eval "$1=$3"
|
||||
fi
|
||||
}
|
||||
|
||||
# If a g-prefixed version of the command exists, use it preferentially.
|
||||
function gprefix() {
|
||||
cmd_pref "$1" "g$2" "$2"
|
||||
}
|
||||
|
||||
gprefix READLINK readlink
|
||||
cd "$(dirname "$("$READLINK" -f "$0")")/.."
|
||||
|
||||
# Allow user overrides to $MAKE. Typical usage for users who need it:
|
||||
# MAKE=gmake ./zcutil/build.sh -j$(nproc)
|
||||
if [[ -z "${MAKE-}" ]]; then
|
||||
MAKE=make
|
||||
fi
|
||||
|
||||
# Allow overrides to $BUILD and $HOST for porters. Most users will not need it.
|
||||
# BUILD=i686-pc-linux-gnu ./zcutil/build.sh
|
||||
if [[ -z "${BUILD-}" ]]; then
|
||||
BUILD="$(./depends/config.guess)"
|
||||
fi
|
||||
if [[ -z "${HOST-}" ]]; then
|
||||
HOST="$BUILD"
|
||||
fi
|
||||
|
||||
# Allow override to $CC and $CXX for porters. Most users will not need it.
|
||||
if [[ -z "${CC-}" ]]; then
|
||||
CC=gcc
|
||||
fi
|
||||
if [[ -z "${CXX-}" ]]; then
|
||||
CXX=g++
|
||||
fi
|
||||
|
||||
# Allow users to set arbitary compile flags. Most users will not need this.
|
||||
if [[ -z "${CONFIGURE_FLAGS-}" ]]; then
|
||||
CONFIGURE_FLAGS=""
|
||||
fi
|
||||
|
||||
if [ "x$*" = 'x--help' ]
|
||||
then
|
||||
cat <<EOF
|
||||
Usage:
|
||||
|
||||
$0 --help
|
||||
Show this help message and exit.
|
||||
|
||||
$0 [ --enable-lcov || --disable-tests ] [ --disable-mining ] [ MAKEARGS... ]
|
||||
Build Zcash and most of its transitive dependencies from
|
||||
source. MAKEARGS are applied to both dependencies and Zcash itself.
|
||||
|
||||
If --enable-lcov is passed, Zcash is configured to add coverage
|
||||
instrumentation, thus enabling "make cov" to work.
|
||||
If --disable-tests is passed instead, the Zcash tests are not built.
|
||||
|
||||
If --disable-mining is passed, Zcash is configured to not build any mining
|
||||
code. It must be passed after the test arguments, if present.
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
set -x
|
||||
|
||||
# If --enable-lcov is the first argument, enable lcov coverage support:
|
||||
LCOV_ARG=''
|
||||
HARDENING_ARG='--enable-hardening'
|
||||
TEST_ARG=''
|
||||
if [ "x${1:-}" = 'x--enable-lcov' ]
|
||||
then
|
||||
LCOV_ARG='--enable-lcov'
|
||||
HARDENING_ARG='--disable-hardening'
|
||||
shift
|
||||
elif [ "x${1:-}" = 'x--disable-tests' ]
|
||||
then
|
||||
TEST_ARG='--enable-tests=no'
|
||||
shift
|
||||
fi
|
||||
|
||||
# If --disable-mining is the next argument, disable mining code:
|
||||
MINING_ARG=''
|
||||
if [ "x${1:-}" = 'x--disable-mining' ]
|
||||
then
|
||||
MINING_ARG='--enable-mining=no'
|
||||
shift
|
||||
fi
|
||||
|
||||
PREFIX="$(pwd)/depends/$BUILD/"
|
||||
|
||||
eval "$MAKE" --version
|
||||
eval "$CC" --version
|
||||
eval "$CXX" --version
|
||||
as --version
|
||||
ld -v
|
||||
|
||||
HOST="$HOST" BUILD="$BUILD" "$MAKE" "$@" -C ./depends/ V=1
|
||||
./autogen.sh
|
||||
CC="$CC" CXX="$CXX" ./configure --disable-wallet --prefix="${PREFIX}" --host="$HOST" --build="$BUILD" "$HARDENING_ARG" "$LCOV_ARG" "$TEST_ARG" "$MINING_ARG" $CONFIGURE_FLAGS --enable-werror CXXFLAGS='-g'
|
||||
"$MAKE" "$@" V=1
|
110
src/Makefile.am
110
src/Makefile.am
|
@ -22,6 +22,8 @@ endif
|
|||
BITCOIN_INCLUDES=-I$(builddir) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
|
||||
|
||||
BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
|
||||
BITCOIN_INCLUDES += -I$(srcdir)/snark
|
||||
BITCOIN_INCLUDES += -I$(srcdir)/snark/libsnark
|
||||
BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS)
|
||||
|
||||
LIBBITCOIN_SERVER=libbitcoin_server.a
|
||||
|
@ -32,6 +34,8 @@ LIBBITCOIN_UTIL=libbitcoin_util.a
|
|||
LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a
|
||||
LIBBITCOINQT=qt/libbitcoinqt.a
|
||||
LIBSECP256K1=secp256k1/libsecp256k1.la
|
||||
LIBSNARK=snark/libsnark.a
|
||||
LIBZCASH=libzcash.a
|
||||
|
||||
if ENABLE_ZMQ
|
||||
LIBBITCOIN_ZMQ=libbitcoin_zmq.a
|
||||
|
@ -46,6 +50,18 @@ endif
|
|||
$(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"
|
||||
|
||||
# Make is not made aware of per-object dependencies to avoid limiting building parallelization
|
||||
# But to build the less dependent modules first, we manually select their order here:
|
||||
EXTRA_LIBRARIES += \
|
||||
|
@ -56,7 +72,8 @@ EXTRA_LIBRARIES += \
|
|||
$(LIBBITCOIN_SERVER) \
|
||||
$(LIBBITCOIN_CLI) \
|
||||
$(LIBBITCOIN_WALLET) \
|
||||
$(LIBBITCOIN_ZMQ)
|
||||
$(LIBBITCOIN_ZMQ) \
|
||||
$(LIBZCASH)
|
||||
|
||||
lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS)
|
||||
|
||||
|
@ -73,11 +90,24 @@ if BUILD_BITCOIN_UTILS
|
|||
bin_PROGRAMS += bitcoin-cli bitcoin-tx
|
||||
endif
|
||||
|
||||
.PHONY: FORCE check-symbols check-security
|
||||
LIBZCASH_H = \
|
||||
zcash/IncrementalMerkleTree.hpp \
|
||||
zcash/NoteEncryption.hpp \
|
||||
zcash/Address.hpp \
|
||||
zcash/JoinSplit.hpp \
|
||||
zcash/Note.hpp \
|
||||
zcash/prf.h \
|
||||
zcash/Proof.hpp \
|
||||
zcash/util.h \
|
||||
zcash/Zcash.h
|
||||
|
||||
.PHONY: FORCE collate-libsnark check-symbols check-security
|
||||
# bitcoin core #
|
||||
BITCOIN_CORE_H = \
|
||||
addrdb.h \
|
||||
addrman.h \
|
||||
asyncrpcoperation.h \
|
||||
asyncrpcqueue.h \
|
||||
base58.h \
|
||||
bech32.h \
|
||||
bloom.h \
|
||||
|
@ -124,6 +154,8 @@ BITCOIN_CORE_H = \
|
|||
netbase.h \
|
||||
netmessagemaker.h \
|
||||
noui.h \
|
||||
paymentdisclosure.h \
|
||||
paymentdisclosuredb.h \
|
||||
policy/feerate.h \
|
||||
policy/fees.h \
|
||||
policy/policy.h \
|
||||
|
@ -168,6 +200,9 @@ BITCOIN_CORE_H = \
|
|||
validationinterface.h \
|
||||
versionbits.h \
|
||||
walletinitinterface.h \
|
||||
wallet/asyncrpcoperation_mergetoaddress.h \
|
||||
wallet/asyncrpcoperation_sendmany.h \
|
||||
wallet/asyncrpcoperation_shieldcoinbase.h \
|
||||
wallet/coincontrol.h \
|
||||
wallet/crypter.h \
|
||||
wallet/db.h \
|
||||
|
@ -182,7 +217,8 @@ BITCOIN_CORE_H = \
|
|||
zmq/zmqabstractnotifier.h \
|
||||
zmq/zmqconfig.h\
|
||||
zmq/zmqnotificationinterface.h \
|
||||
zmq/zmqpublishnotifier.h
|
||||
zmq/zmqpublishnotifier.h \
|
||||
$(LIBZCASH_H)
|
||||
|
||||
|
||||
obj/build.h: FORCE
|
||||
|
@ -197,6 +233,8 @@ libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
|||
libbitcoin_server_a_SOURCES = \
|
||||
addrdb.cpp \
|
||||
addrman.cpp \
|
||||
asyncrpcoperation.cpp \
|
||||
asyncrpcqueue.cpp \
|
||||
bloom.cpp \
|
||||
blockencodings.cpp \
|
||||
chain.cpp \
|
||||
|
@ -212,6 +250,8 @@ libbitcoin_server_a_SOURCES = \
|
|||
net.cpp \
|
||||
net_processing.cpp \
|
||||
noui.cpp \
|
||||
paymentdisclosure.cpp \
|
||||
paymentdisclosuredb.cpp \
|
||||
policy/fees.cpp \
|
||||
policy/policy.cpp \
|
||||
policy/rbf.cpp \
|
||||
|
@ -250,11 +290,17 @@ libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
|
|||
libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libbitcoin_wallet_a_SOURCES = \
|
||||
interfaces/wallet.cpp \
|
||||
wallet/asyncrpcoperation_mergetoaddress.cpp \
|
||||
wallet/asyncrpcoperation_sendmany.cpp \
|
||||
wallet/asyncrpcoperation_shieldcoinbase.cpp \
|
||||
wallet/crypter.cpp \
|
||||
wallet/db.cpp \
|
||||
wallet/feebumper.cpp \
|
||||
wallet/fees.cpp \
|
||||
wallet/init.cpp \
|
||||
paymentdisclosure.cpp \
|
||||
paymentdisclosuredb.cpp \
|
||||
wallet/rpcdisclosure.cpp \
|
||||
wallet/rpcdump.cpp \
|
||||
wallet/rpcwallet.cpp \
|
||||
wallet/wallet.cpp \
|
||||
|
@ -272,6 +318,9 @@ crypto_libbitcoin_crypto_a_SOURCES = \
|
|||
crypto/chacha20.h \
|
||||
crypto/chacha20.cpp \
|
||||
crypto/common.h \
|
||||
crypto/equihash.cpp \
|
||||
crypto/equihash.h \
|
||||
crypto/equihash.tcc \
|
||||
crypto/hmac_sha256.cpp \
|
||||
crypto/hmac_sha256.h \
|
||||
crypto/hmac_sha512.cpp \
|
||||
|
@ -289,6 +338,18 @@ if USE_ASM
|
|||
crypto_libbitcoin_crypto_a_SOURCES += crypto/sha256_sse4.cpp
|
||||
endif
|
||||
|
||||
if ENABLE_MINING
|
||||
EQUIHASH_TROMP_SOURCES = \
|
||||
pow/tromp/equi_miner.h \
|
||||
pow/tromp/equi.h \
|
||||
pow/tromp/osx_barrier.h
|
||||
|
||||
crypto_libbitcoin_crypto_a_CPPFLAGS += \
|
||||
-DEQUIHASH_TROMP_ATOMIC
|
||||
crypto_libbitcoin_crypto_a_SOURCES += \
|
||||
${EQUIHASH_TROMP_SOURCES}
|
||||
endif
|
||||
|
||||
# consensus: shared between all executables that validate any consensus rules.
|
||||
libbitcoin_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
|
||||
libbitcoin_consensus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
|
@ -321,6 +382,7 @@ libbitcoin_consensus_a_SOURCES = \
|
|||
tinyformat.h \
|
||||
uint256.cpp \
|
||||
uint256.h \
|
||||
uint252.h \
|
||||
utilstrencodings.cpp \
|
||||
utilstrencodings.h \
|
||||
version.h
|
||||
|
@ -411,6 +473,9 @@ bitcoind_LDADD = \
|
|||
$(LIBBITCOIN_ZMQ) \
|
||||
$(LIBBITCOIN_CONSENSUS) \
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
$(LIBZCASH) \
|
||||
$(LIBSNARK) \
|
||||
$(LIBZCASH_LIBS) \
|
||||
$(LIBLEVELDB) \
|
||||
$(LIBLEVELDB_SSE42) \
|
||||
$(LIBMEMENV) \
|
||||
|
@ -432,7 +497,10 @@ bitcoin_cli_LDADD = \
|
|||
$(LIBBITCOIN_CLI) \
|
||||
$(LIBUNIVALUE) \
|
||||
$(LIBBITCOIN_UTIL) \
|
||||
$(LIBBITCOIN_CRYPTO)
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
$(LIBZCASH) \
|
||||
$(LIBSNARK) \
|
||||
$(LIBZCASH_LIBS)
|
||||
|
||||
bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS)
|
||||
#
|
||||
|
@ -453,11 +521,39 @@ bitcoin_tx_LDADD = \
|
|||
$(LIBBITCOIN_UTIL) \
|
||||
$(LIBBITCOIN_CONSENSUS) \
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
$(LIBSECP256K1)
|
||||
$(LIBSECP256K1) \
|
||||
$(LIBZCASH) \
|
||||
$(LIBSNARK) \
|
||||
$(LIBZCASH_LIBS)
|
||||
|
||||
bitcoin_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
|
||||
#
|
||||
|
||||
# zcash protocol primitives #
|
||||
libzcash_a_SOURCES = \
|
||||
zcash/IncrementalMerkleTree.cpp \
|
||||
zcash/NoteEncryption.cpp \
|
||||
zcash/Address.cpp \
|
||||
zcash/JoinSplit.cpp \
|
||||
zcash/Proof.cpp \
|
||||
zcash/Note.cpp \
|
||||
zcash/prf.cpp \
|
||||
zcash/util.cpp \
|
||||
zcash/circuit/commitment.tcc \
|
||||
zcash/circuit/gadget.tcc \
|
||||
zcash/circuit/merkle.tcc \
|
||||
zcash/circuit/note.tcc \
|
||||
zcash/circuit/prfs.tcc \
|
||||
zcash/circuit/utils.tcc
|
||||
|
||||
libzcash_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS $(HARDENED_CPPFLAGS) $(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_LIBADD = $(SAN_LDFLAGS) $(HARDENED_LDFLAGS)
|
||||
|
||||
libzcash_a_CPPFLAGS += -DMONTGOMERY_OUTPUT
|
||||
|
||||
# bitcoinconsensus library #
|
||||
if BUILD_BITCOIN_LIBS
|
||||
include_HEADERS = script/bitcoinconsensus.h
|
||||
|
@ -509,6 +605,7 @@ $(top_srcdir)/$(subdir)/config/bitcoin-config.h.in: $(am__configure_deps)
|
|||
|
||||
clean-local:
|
||||
-$(MAKE) -C secp256k1 clean
|
||||
-$(MAKE) -C snark clean
|
||||
-$(MAKE) -C univalue clean
|
||||
-rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno
|
||||
-rm -f config.h
|
||||
|
@ -541,6 +638,7 @@ endif
|
|||
|
||||
if ENABLE_TESTS
|
||||
include Makefile.test.include
|
||||
include Makefile.gtest.include
|
||||
endif
|
||||
|
||||
if ENABLE_BENCH
|
||||
|
@ -554,3 +652,5 @@ endif
|
|||
if ENABLE_QT_TESTS
|
||||
include Makefile.qttest.include
|
||||
endif
|
||||
|
||||
include Makefile.zcash.include
|
||||
|
|
|
@ -52,7 +52,7 @@ if ENABLE_WALLET
|
|||
bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp
|
||||
endif
|
||||
|
||||
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
|
||||
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(LIBZCASH) $(LIBSNARK) $(LIBZCASH_LIBS)
|
||||
bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
||||
|
||||
CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES)
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
TESTS += zcash-gtest
|
||||
noinst_PROGRAMS += zcash-gtest
|
||||
|
||||
# tool for generating our public parameters.
|
||||
# test_checktransaction.cpp MUST be before
|
||||
# any test that calls SelectParams().
|
||||
zcash_gtest_SOURCES = \
|
||||
gtest/main.cpp \
|
||||
gtest/utils.cpp \
|
||||
gtest/test_checktransaction.cpp \
|
||||
gtest/json_test_vectors.cpp \
|
||||
gtest/json_test_vectors.h \
|
||||
gtest/test_foundersreward.cpp
|
||||
# These tests are order-dependent, because they
|
||||
# depend on global state (see #1539)
|
||||
if ENABLE_WALLET
|
||||
zcash_gtest_SOURCES += \
|
||||
wallet/gtest/test_wallet_zkeys.cpp
|
||||
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 \
|
||||
gtest/test_mempool.cpp \
|
||||
gtest/test_merkletree.cpp \
|
||||
gtest/test_metrics.cpp \
|
||||
gtest/test_miner.cpp \
|
||||
gtest/test_pow.cpp \
|
||||
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
|
||||
|
||||
zcash_gtest_CPPFLAGS = $(AM_CPPFLAGS) -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES)
|
||||
zcash_gtest_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
|
||||
zcash_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
|
||||
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1)
|
||||
if ENABLE_ZMQ
|
||||
zcash_gtest_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
|
||||
endif
|
||||
if ENABLE_WALLET
|
||||
zcash_gtest_LDADD += $(LIBBITCOIN_WALLET)
|
||||
endif
|
||||
|
||||
zcash_gtest_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(LIBZCASH) $(LIBSNARK) $(LIBZCASH_LIBS)
|
||||
|
||||
zcash_gtest_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
|
||||
|
||||
zcash-gtest_check: zcash-gtest FORCE
|
||||
./zcash-gtest
|
||||
|
||||
zcash-gtest-expected-failures: zcash-gtest FORCE
|
||||
./zcash-gtest --gtest_filter=*DISABLED_* --gtest_also_run_disabled_tests
|
|
@ -357,7 +357,7 @@ if ENABLE_WALLET
|
|||
BITCOIN_QT_CPP += $(BITCOIN_QT_WALLET_CPP)
|
||||
endif
|
||||
|
||||
RES_IMAGES =
|
||||
RES_IMAGES =
|
||||
|
||||
RES_MOVIES = $(wildcard $(srcdir)/qt/res/movies/spinner-*.png)
|
||||
|
||||
|
@ -410,7 +410,7 @@ qt_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
|
|||
endif
|
||||
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
|
||||
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
|
||||
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
|
||||
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(LIBZCASH) $(LIBSNARK) $(LIBZCASH_LIBS)
|
||||
qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
||||
qt_bitcoin_qt_LIBTOOLFLAGS = $(AM_LIBTOOLFLAGS) --tag CXX
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ endif
|
|||
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \
|
||||
$(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
|
||||
$(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
|
||||
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
|
||||
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(LIBZCASH) $(LIBSNARK) $(LIBZCASH_LIBS)
|
||||
qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
||||
qt_test_test_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ BITCOIN_TESTS =\
|
|||
test/crypto_tests.cpp \
|
||||
test/cuckoocache_tests.cpp \
|
||||
test/DoS_tests.cpp \
|
||||
test/equihash_tests.cpp \
|
||||
test/getarg_tests.cpp \
|
||||
test/hash_tests.cpp \
|
||||
test/key_io_tests.cpp \
|
||||
|
@ -113,7 +114,7 @@ test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_C
|
|||
$(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
|
||||
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
|
||||
test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
|
||||
test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBZCASH) $(LIBSNARK) $(LIBZCASH_LIBS)
|
||||
test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
|
||||
|
||||
if ENABLE_ZMQ
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
noinst_PROGRAMS += \
|
||||
zcash/GenerateParams \
|
||||
zcash/CreateJoinSplit
|
||||
|
||||
# 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) \
|
||||
$(LIBZCASH_LIBS)
|
|
@ -0,0 +1,14 @@
|
|||
#include "json_test_vectors.h"
|
||||
|
||||
UniValue
|
||||
read_json(const std::string& jsondata)
|
||||
{
|
||||
UniValue v;
|
||||
|
||||
if (!(v.read(jsondata) && v.isArray()))
|
||||
{
|
||||
ADD_FAILURE();
|
||||
return UniValue(UniValue::VARR);
|
||||
}
|
||||
return v.get_array();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "utilstrencodings.h"
|
||||
#include "version.h"
|
||||
#include "serialize.h"
|
||||
#include "streams.h"
|
||||
|
||||
#include <univalue.h>
|
||||
|
||||
UniValue
|
||||
read_json(const std::string& jsondata);
|
||||
|
||||
// #define PRINT_JSON 1
|
||||
|
||||
template<typename T>
|
||||
void expect_deser_same(const T& expected)
|
||||
{
|
||||
CDataStream ss1(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss1 << expected;
|
||||
|
||||
auto serialized_size = ss1.size();
|
||||
|
||||
T object;
|
||||
ss1 >> object;
|
||||
|
||||
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss2 << object;
|
||||
|
||||
ASSERT_TRUE(serialized_size == ss2.size());
|
||||
ASSERT_TRUE(memcmp(&*ss1.begin(), &*ss2.begin(), serialized_size) == 0);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
void expect_test_vector(T& v, const U& expected)
|
||||
{
|
||||
expect_deser_same(expected);
|
||||
|
||||
CDataStream ss1(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss1 << expected;
|
||||
|
||||
#ifdef PRINT_JSON
|
||||
std::cout << "\t\"" ;
|
||||
std::cout << HexStr(ss1.begin(), ss1.end()) << "\",\n";
|
||||
#else
|
||||
std::string raw = v.get_str();
|
||||
CDataStream ss2(ParseHex(raw), SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
ASSERT_TRUE(ss1.size() == ss2.size());
|
||||
ASSERT_TRUE(memcmp(&*ss1.begin(), &*ss2.begin(), ss1.size()) == 0);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#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>
|
||||
|
||||
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::InitGoogleMock(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "primitives/block.h"
|
||||
|
||||
|
||||
TEST(block_tests, header_size_is_expected) {
|
||||
// Dummy header with an empty Equihash solution.
|
||||
CBlockHeader header;
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << header;
|
||||
|
||||
ASSERT_EQ(ss.size(), CBlockHeader::HEADER_SIZE);
|
||||
}
|
|
@ -0,0 +1,233 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include "consensus/validation.h"
|
||||
#include "main.h"
|
||||
#include "zcash/Proof.hpp"
|
||||
|
||||
class MockCValidationState : public CValidationState {
|
||||
public:
|
||||
MOCK_METHOD5(DoS, bool(int level, bool ret,
|
||||
unsigned char chRejectCodeIn, std::string strRejectReasonIn,
|
||||
bool corruptionIn));
|
||||
MOCK_METHOD3(Invalid, bool(bool ret,
|
||||
unsigned char _chRejectCode, std::string _strRejectReason));
|
||||
MOCK_METHOD1(Error, bool(std::string strRejectReasonIn));
|
||||
MOCK_CONST_METHOD0(IsValid, bool());
|
||||
MOCK_CONST_METHOD0(IsInvalid, bool());
|
||||
MOCK_CONST_METHOD0(IsError, bool());
|
||||
MOCK_CONST_METHOD1(IsInvalid, bool(int &nDoSOut));
|
||||
MOCK_CONST_METHOD0(CorruptionPossible, bool());
|
||||
MOCK_CONST_METHOD0(GetRejectCode, unsigned char());
|
||||
MOCK_CONST_METHOD0(GetRejectReason, std::string());
|
||||
};
|
||||
|
||||
TEST(CheckBlock, VersionTooLow) {
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
|
||||
CBlock block;
|
||||
block.nVersion = 1;
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "version-too-low", false)).Times(1);
|
||||
EXPECT_FALSE(CheckBlock(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);
|
||||
|
||||
// Create a block with no height in scriptSig
|
||||
CMutableTransaction mtx;
|
||||
mtx.vin.resize(1);
|
||||
mtx.vin[0].prevout.SetNull();
|
||||
mtx.vin[0].scriptSig = CScript() << OP_0;
|
||||
mtx.vout.resize(1);
|
||||
mtx.vout[0].scriptPubKey = CScript() << OP_TRUE;
|
||||
mtx.vout[0].nValue = 0;
|
||||
CTransaction tx {mtx};
|
||||
CBlock block;
|
||||
block.vtx.push_back(tx);
|
||||
|
||||
// Treating block as genesis should pass
|
||||
MockCValidationState state;
|
||||
EXPECT_TRUE(ContextualCheckBlock(block, state, NULL));
|
||||
|
||||
// Treating block as non-genesis should fail
|
||||
mtx.vout.push_back(CTxOut(GetBlockSubsidy(1, Params().GetConsensus())/5, Params().GetFoundersRewardScriptAtHeight(1)));
|
||||
CTransaction tx2 {mtx};
|
||||
block.vtx[0] = tx2;
|
||||
CBlock prev;
|
||||
CBlockIndex indexPrev {prev};
|
||||
indexPrev.nHeight = 0;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-cb-height", false)).Times(1);
|
||||
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
|
||||
|
||||
// Setting to an incorrect height should fail
|
||||
mtx.vin[0].scriptSig = CScript() << 2 << OP_0;
|
||||
CTransaction tx3 {mtx};
|
||||
block.vtx[0] = tx3;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-cb-height", false)).Times(1);
|
||||
EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev));
|
||||
|
||||
// After correcting the scriptSig, should pass
|
||||
mtx.vin[0].scriptSig = CScript() << 1 << OP_0;
|
||||
CTransaction tx4 {mtx};
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,774 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <sodium.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "consensus/validation.h"
|
||||
|
||||
TEST(checktransaction_tests, check_vpub_not_both_nonzero) {
|
||||
CMutableTransaction tx;
|
||||
tx.nVersion = 2;
|
||||
|
||||
{
|
||||
// Ensure that values within the joinsplit are well-formed.
|
||||
CMutableTransaction newTx(tx);
|
||||
CValidationState state;
|
||||
|
||||
newTx.vjoinsplit.push_back(JSDescription());
|
||||
|
||||
JSDescription *jsdesc = &newTx.vjoinsplit[0];
|
||||
jsdesc->vpub_old = 1;
|
||||
jsdesc->vpub_new = 1;
|
||||
|
||||
EXPECT_FALSE(CheckTransactionWithoutProofVerification(newTx, state));
|
||||
EXPECT_EQ(state.GetRejectReason(), "bad-txns-vpubs-both-nonzero");
|
||||
}
|
||||
}
|
||||
|
||||
class MockCValidationState : public CValidationState {
|
||||
public:
|
||||
MOCK_METHOD5(DoS, bool(int level, bool ret,
|
||||
unsigned char chRejectCodeIn, std::string strRejectReasonIn,
|
||||
bool corruptionIn));
|
||||
MOCK_METHOD3(Invalid, bool(bool ret,
|
||||
unsigned char _chRejectCode, std::string _strRejectReason));
|
||||
MOCK_METHOD1(Error, bool(std::string strRejectReasonIn));
|
||||
MOCK_CONST_METHOD0(IsValid, bool());
|
||||
MOCK_CONST_METHOD0(IsInvalid, bool());
|
||||
MOCK_CONST_METHOD0(IsError, bool());
|
||||
MOCK_CONST_METHOD1(IsInvalid, bool(int &nDoSOut));
|
||||
MOCK_CONST_METHOD0(CorruptionPossible, bool());
|
||||
MOCK_CONST_METHOD0(GetRejectCode, unsigned char());
|
||||
MOCK_CONST_METHOD0(GetRejectReason, std::string());
|
||||
};
|
||||
|
||||
|
||||
CMutableTransaction GetValidTransaction() {
|
||||
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||
|
||||
CMutableTransaction mtx;
|
||||
mtx.vin.resize(2);
|
||||
mtx.vin[0].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
|
||||
mtx.vin[0].prevout.n = 0;
|
||||
mtx.vin[1].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
|
||||
mtx.vin[1].prevout.n = 0;
|
||||
mtx.vout.resize(2);
|
||||
// mtx.vout[0].scriptPubKey =
|
||||
mtx.vout[0].nValue = 0;
|
||||
mtx.vout[1].nValue = 0;
|
||||
mtx.vjoinsplit.resize(2);
|
||||
mtx.vjoinsplit[0].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
||||
mtx.vjoinsplit[0].nullifiers.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
|
||||
mtx.vjoinsplit[1].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
|
||||
mtx.vjoinsplit[1].nullifiers.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000003");
|
||||
|
||||
|
||||
// Generate an ephemeral keypair.
|
||||
uint256 joinSplitPubKey;
|
||||
unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
|
||||
crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
|
||||
mtx.joinSplitPubKey = joinSplitPubKey;
|
||||
|
||||
// Compute the correct hSig.
|
||||
// TODO: #966.
|
||||
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
||||
// Empty output script.
|
||||
CScript scriptCode;
|
||||
CTransaction signTx(mtx);
|
||||
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
|
||||
if (dataToBeSigned == one) {
|
||||
throw std::runtime_error("SignatureHash failed");
|
||||
}
|
||||
|
||||
// Add the signature
|
||||
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
|
||||
dataToBeSigned.begin(), 32,
|
||||
joinSplitPrivKey
|
||||
) == 0);
|
||||
return mtx;
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, valid_transaction) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
CTransaction tx(mtx);
|
||||
MockCValidationState state;
|
||||
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, BadVersionTooLow) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.nVersion = 0;
|
||||
|
||||
CTransaction tx(mtx);
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-version-too-low", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_vin_empty) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vjoinsplit.resize(0);
|
||||
mtx.vin.resize(0);
|
||||
|
||||
CTransaction tx(mtx);
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_vout_empty) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vjoinsplit.resize(0);
|
||||
mtx.vout.resize(0);
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_oversize) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
|
||||
mtx.vin[0].scriptSig = CScript();
|
||||
std::vector<unsigned char> vchData(520);
|
||||
for (unsigned int i = 0; i < 190; ++i)
|
||||
mtx.vin[0].scriptSig << vchData << OP_DROP;
|
||||
mtx.vin[0].scriptSig << OP_1;
|
||||
|
||||
{
|
||||
// Transaction is just under the limit...
|
||||
CTransaction tx(mtx);
|
||||
CValidationState state;
|
||||
ASSERT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
|
||||
}
|
||||
|
||||
// Not anymore!
|
||||
mtx.vin[1].scriptSig << vchData << OP_DROP;
|
||||
mtx.vin[1].scriptSig << OP_1;
|
||||
|
||||
{
|
||||
CTransaction tx(mtx);
|
||||
ASSERT_EQ(::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION), 100202);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-oversize", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_vout_negative) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vout[0].nValue = -1;
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_vout_toolarge) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vout[0].nValue = MAX_MONEY + 1;
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_txouttotal_toolarge_outputs) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vout[0].nValue = MAX_MONEY;
|
||||
mtx.vout[1].nValue = 1;
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_txouttotal_toolarge_joinsplit) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vout[0].nValue = 1;
|
||||
mtx.vjoinsplit[0].vpub_old = MAX_MONEY;
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_txintotal_toolarge_joinsplit) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vjoinsplit[0].vpub_new = MAX_MONEY - 1;
|
||||
mtx.vjoinsplit[1].vpub_new = MAX_MONEY - 1;
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-txintotal-toolarge", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_vpub_old_negative) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vjoinsplit[0].vpub_old = -1;
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-vpub_old-negative", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_vpub_new_negative) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vjoinsplit[0].vpub_new = -1;
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-vpub_new-negative", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_vpub_old_toolarge) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vjoinsplit[0].vpub_old = MAX_MONEY + 1;
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-vpub_old-toolarge", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_vpub_new_toolarge) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vjoinsplit[0].vpub_new = MAX_MONEY + 1;
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-vpub_new-toolarge", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_vpubs_both_nonzero) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vjoinsplit[0].vpub_old = 1;
|
||||
mtx.vjoinsplit[0].vpub_new = 1;
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-vpubs-both-nonzero", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_inputs_duplicate) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vin[1].prevout.hash = mtx.vin[0].prevout.hash;
|
||||
mtx.vin[1].prevout.n = mtx.vin[0].prevout.n;
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_joinsplits_nullifiers_duplicate_same_joinsplit) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vjoinsplit[0].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
||||
mtx.vjoinsplit[0].nullifiers.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-joinsplits-nullifiers-duplicate", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_joinsplits_nullifiers_duplicate_different_joinsplit) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vjoinsplit[0].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
||||
mtx.vjoinsplit[1].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-joinsplits-nullifiers-duplicate", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_cb_has_joinsplits) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
// Make it a coinbase.
|
||||
mtx.vin.resize(1);
|
||||
mtx.vin[0].prevout.SetNull();
|
||||
|
||||
mtx.vjoinsplit.resize(1);
|
||||
|
||||
CTransaction tx(mtx);
|
||||
EXPECT_TRUE(tx.IsCoinBase());
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-cb-has-joinsplits", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_cb_empty_scriptsig) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
// Make it a coinbase.
|
||||
mtx.vin.resize(1);
|
||||
mtx.vin[0].prevout.SetNull();
|
||||
|
||||
mtx.vjoinsplit.resize(0);
|
||||
|
||||
CTransaction tx(mtx);
|
||||
EXPECT_TRUE(tx.IsCoinBase());
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-cb-length", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
TEST(checktransaction_tests, bad_txns_prevout_null) {
|
||||
CMutableTransaction mtx = GetValidTransaction();
|
||||
mtx.vin[1].prevout.SetNull();
|
||||
|
||||
CTransaction tx(mtx);
|
||||
EXPECT_FALSE(tx.IsCoinBase());
|
||||
|
||||
MockCValidationState state;
|
||||
EXPECT_CALL(state, DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null", false)).Times(1);
|
||||
CheckTransactionWithoutProofVerification(tx, state);
|
||||
}
|
||||
|
||||
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);
|
||||
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(ContextualCheckTransaction(tx, state, 0, 100));
|
||||
}
|
||||
|
||||
// Copied from libsodium/crypto_sign/ed25519/ref10/open.c
|
||||
static const unsigned char L[32] =
|
||||
{ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
|
||||
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 };
|
||||
|
||||
// Add L to S, which starts at mtx.joinSplitSig[32].
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < 32; i++) {
|
||||
s = mtx.joinSplitSig[32 + i] + L[i] + (s >> 8);
|
||||
mtx.joinSplitSig[32 + i] = s & 0xff;
|
||||
}
|
||||
|
||||
CTransaction tx(mtx);
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "uint256.h"
|
||||
|
||||
#include "zcash/util.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#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 "zcash/IncrementalMerkleTree.hpp"
|
||||
|
||||
using namespace libsnark;
|
||||
using namespace libzcash;
|
||||
|
||||
#include "zcash/circuit/utils.tcc"
|
||||
#include "zcash/circuit/merkle.tcc"
|
||||
|
||||
template<typename FieldT>
|
||||
void test_value_equals(uint64_t i) {
|
||||
protoboard<FieldT> pb;
|
||||
pb_variable_array<FieldT> num;
|
||||
num.allocate(pb, 64, "");
|
||||
num.fill_with_bits(pb, uint64_to_bool_vector(i));
|
||||
pb.add_r1cs_constraint(r1cs_constraint<FieldT>(
|
||||
packed_addition(num),
|
||||
FieldT::one(),
|
||||
FieldT::one() * i
|
||||
), "");
|
||||
ASSERT_TRUE(pb.is_satisfied());
|
||||
}
|
||||
|
||||
TEST(circuit, values)
|
||||
{
|
||||
typedef Fr<default_r1cs_ppzksnark_pp> FieldT;
|
||||
test_value_equals<FieldT>(0);
|
||||
test_value_equals<FieldT>(1);
|
||||
test_value_equals<FieldT>(3);
|
||||
test_value_equals<FieldT>(5391);
|
||||
test_value_equals<FieldT>(883128374);
|
||||
test_value_equals<FieldT>(173419028459);
|
||||
test_value_equals<FieldT>(2205843009213693953);
|
||||
}
|
||||
|
||||
TEST(circuit, endianness)
|
||||
{
|
||||
std::vector<unsigned char> before = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63
|
||||
};
|
||||
auto result = swap_endianness_u64(before);
|
||||
|
||||
std::vector<unsigned char> after = {
|
||||
56, 57, 58, 59, 60, 61, 62, 63,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7
|
||||
};
|
||||
|
||||
EXPECT_EQ(after, result);
|
||||
|
||||
std::vector<unsigned char> bad = {0, 1, 2, 3};
|
||||
|
||||
ASSERT_THROW(swap_endianness_u64(bad), std::length_error);
|
||||
}
|
||||
|
||||
template<typename FieldT>
|
||||
bool test_merkle_gadget(
|
||||
bool enforce_a,
|
||||
bool enforce_b,
|
||||
bool write_root_first
|
||||
)
|
||||
{
|
||||
protoboard<FieldT> pb;
|
||||
digest_variable<FieldT> root(pb, 256, "root");
|
||||
pb.set_input_sizes(256);
|
||||
|
||||
digest_variable<FieldT> commitment1(pb, 256, "commitment1");
|
||||
digest_variable<FieldT> commitment2(pb, 256, "commitment2");
|
||||
|
||||
pb_variable<FieldT> commitment1_read;
|
||||
commitment1_read.allocate(pb);
|
||||
pb_variable<FieldT> commitment2_read;
|
||||
commitment2_read.allocate(pb);
|
||||
|
||||
merkle_tree_gadget<FieldT> mgadget1(pb, commitment1, root, commitment1_read);
|
||||
merkle_tree_gadget<FieldT> mgadget2(pb, commitment2, root, commitment2_read);
|
||||
|
||||
commitment1.generate_r1cs_constraints();
|
||||
commitment2.generate_r1cs_constraints();
|
||||
root.generate_r1cs_constraints();
|
||||
mgadget1.generate_r1cs_constraints();
|
||||
mgadget2.generate_r1cs_constraints();
|
||||
|
||||
ZCIncrementalMerkleTree tree;
|
||||
uint256 commitment1_data = uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c");
|
||||
uint256 commitment2_data = uint256S("59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7");
|
||||
tree.append(commitment1_data);
|
||||
auto wit1 = tree.witness();
|
||||
tree.append(commitment2_data);
|
||||
wit1.append(commitment2_data);
|
||||
auto wit2 = tree.witness();
|
||||
auto expected_root = tree.root();
|
||||
tree.append(uint256S("3e243c8798678570bb8d42616c23a536af44be15c4eef073490c2a44ae5f32c3"));
|
||||
auto unexpected_root = tree.root();
|
||||
tree.append(uint256S("26d9b20c7f1c3d2528bbcd43cd63344b0afd3b6a0a8ebd37ec51cba34907bec7"));
|
||||
auto badwit1 = tree.witness();
|
||||
tree.append(uint256S("02c2467c9cd15e0d150f74cd636505ed675b0b71b66a719f6f52fdb49a5937bb"));
|
||||
auto badwit2 = tree.witness();
|
||||
|
||||
// Perform the test
|
||||
|
||||
pb.val(commitment1_read) = enforce_a ? FieldT::one() : FieldT::zero();
|
||||
pb.val(commitment2_read) = enforce_b ? FieldT::one() : FieldT::zero();
|
||||
|
||||
commitment1.bits.fill_with_bits(pb, uint256_to_bool_vector(commitment1_data));
|
||||
commitment2.bits.fill_with_bits(pb, uint256_to_bool_vector(commitment2_data));
|
||||
|
||||
if (write_root_first) {
|
||||
root.bits.fill_with_bits(pb, uint256_to_bool_vector(expected_root));
|
||||
}
|
||||
|
||||
mgadget1.generate_r1cs_witness(wit1.path());
|
||||
mgadget2.generate_r1cs_witness(wit2.path());
|
||||
|
||||
// Overwrite with our expected root
|
||||
root.bits.fill_with_bits(pb, uint256_to_bool_vector(expected_root));
|
||||
|
||||
return pb.is_satisfied();
|
||||
}
|
||||
|
||||
TEST(circuit, merkle_tree_gadget_weirdness)
|
||||
{
|
||||
/*
|
||||
The merkle tree gadget takes a leaf in the merkle tree (the Note commitment),
|
||||
a merkle tree authentication path, and a root (anchor). It also takes a parameter
|
||||
called read_success, which is used to determine if the commitment actually needs to
|
||||
appear in the tree.
|
||||
|
||||
If two input notes use the same root (which our protocol does) then if `read_success`
|
||||
is disabled on the first note but enabled on the second note (i.e., the first note
|
||||
has value of zero and second note has nonzero value) then there is an edge case in
|
||||
the witnessing behavior. The first witness will accidentally constrain the root to
|
||||
equal null (the default value of the anchor) and the second witness will actually
|
||||
copy the bits, violating the constraint system.
|
||||
|
||||
Notice that this edge case is not in the constraint system but in the witnessing
|
||||
behavior.
|
||||
*/
|
||||
|
||||
typedef Fr<default_r1cs_ppzksnark_pp> FieldT;
|
||||
|
||||
// Test the normal case
|
||||
ASSERT_TRUE(test_merkle_gadget<FieldT>(true, true, false));
|
||||
ASSERT_TRUE(test_merkle_gadget<FieldT>(true, true, true));
|
||||
|
||||
// Test the case where the first commitment is enforced but the second isn't
|
||||
// Works because the first read is performed before the second one
|
||||
ASSERT_TRUE(test_merkle_gadget<FieldT>(true, false, false));
|
||||
ASSERT_TRUE(test_merkle_gadget<FieldT>(true, false, true));
|
||||
|
||||
// Test the case where the first commitment isn't enforced but the second is
|
||||
// Doesn't work because the first multipacker witnesses the existing root (which
|
||||
// is null)
|
||||
ASSERT_TRUE(!test_merkle_gadget<FieldT>(false, true, false));
|
||||
|
||||
// Test the last again, except this time write the root first.
|
||||
ASSERT_TRUE(test_merkle_gadget<FieldT>(false, true, true));
|
||||
}
|
|
@ -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());
|
||||
}
|
|
@ -0,0 +1,291 @@
|
|||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config/bitcoin-config.h"
|
||||
#endif
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include "crypto/equihash.h"
|
||||
#include "uint256.h"
|
||||
|
||||
void TestExpandAndCompress(const std::string &scope, size_t bit_len, size_t byte_pad,
|
||||
std::vector<unsigned char> compact,
|
||||
std::vector<unsigned char> expanded)
|
||||
{
|
||||
SCOPED_TRACE(scope);
|
||||
|
||||
std::vector<unsigned char> out(expanded.size());
|
||||
ExpandArray(compact.data(), compact.size(),
|
||||
out.data(), out.size(), bit_len, byte_pad);
|
||||
EXPECT_EQ(expanded, out);
|
||||
|
||||
out.resize(compact.size());
|
||||
CompressArray(expanded.data(), expanded.size(),
|
||||
out.data(), out.size(), bit_len, byte_pad);
|
||||
EXPECT_EQ(compact, out);
|
||||
}
|
||||
|
||||
TEST(equihash_tests, expand_and_contract_arrays) {
|
||||
TestExpandAndCompress("8 11-bit chunks, all-ones", 11, 0,
|
||||
ParseHex("ffffffffffffffffffffff"),
|
||||
ParseHex("07ff07ff07ff07ff07ff07ff07ff07ff"));
|
||||
TestExpandAndCompress("8 21-bit chunks, alternating 1s and 0s", 21, 0,
|
||||
ParseHex("aaaaad55556aaaab55555aaaaad55556aaaab55555"),
|
||||
ParseHex("155555155555155555155555155555155555155555155555"));
|
||||
TestExpandAndCompress("8 21-bit chunks, based on example in the spec", 21, 0,
|
||||
ParseHex("000220000a7ffffe00123022b38226ac19bdf23456"),
|
||||
ParseHex("0000440000291fffff0001230045670089ab00cdef123456"));
|
||||
TestExpandAndCompress("16 14-bit chunks, alternating 11s and 00s", 14, 0,
|
||||
ParseHex("cccf333cccf333cccf333cccf333cccf333cccf333cccf333cccf333"),
|
||||
ParseHex("3333333333333333333333333333333333333333333333333333333333333333"));
|
||||
|
||||
TestExpandAndCompress("8 11-bit chunks, all-ones, 2-byte padding", 11, 2,
|
||||
ParseHex("ffffffffffffffffffffff"),
|
||||
ParseHex("000007ff000007ff000007ff000007ff000007ff000007ff000007ff000007ff"));
|
||||
}
|
||||
|
||||
void TestMinimalSolnRepr(const std::string &scope, size_t cBitLen,
|
||||
std::vector<eh_index> indices,
|
||||
std::vector<unsigned char> minimal)
|
||||
{
|
||||
SCOPED_TRACE(scope);
|
||||
|
||||
EXPECT_EQ(indices, GetIndicesFromMinimal(minimal, cBitLen));
|
||||
EXPECT_EQ(minimal, GetMinimalFromIndices(indices, cBitLen));
|
||||
}
|
||||
|
||||
TEST(equihash_tests, minimal_solution_representation) {
|
||||
TestMinimalSolnRepr("Test 1", 20,
|
||||
{1, 1, 1, 1, 1, 1, 1, 1},
|
||||
ParseHex("000008000040000200001000008000040000200001"));
|
||||
TestMinimalSolnRepr("Test 2", 20,
|
||||
{2097151, 2097151, 2097151, 2097151,
|
||||
2097151, 2097151, 2097151, 2097151},
|
||||
ParseHex("ffffffffffffffffffffffffffffffffffffffffff"));
|
||||
TestMinimalSolnRepr("Test 3", 20,
|
||||
{131071, 128, 131071, 128, 131071, 128, 131071, 128},
|
||||
ParseHex("0ffff8002003fffe000800ffff8002003fffe00080"));
|
||||
TestMinimalSolnRepr("Test 4", 20,
|
||||
{68, 41, 2097151, 1233, 665, 1023, 1, 1048575},
|
||||
ParseHex("000220000a7ffffe004d10014c800ffc00002fffff"));
|
||||
}
|
||||
|
||||
TEST(equihash_tests, is_probably_duplicate) {
|
||||
std::shared_ptr<eh_trunc> p1 (new eh_trunc[4] {0, 1, 2, 3}, std::default_delete<eh_trunc[]>());
|
||||
std::shared_ptr<eh_trunc> p2 (new eh_trunc[4] {0, 1, 1, 3}, std::default_delete<eh_trunc[]>());
|
||||
std::shared_ptr<eh_trunc> p3 (new eh_trunc[4] {3, 1, 1, 3}, std::default_delete<eh_trunc[]>());
|
||||
|
||||
ASSERT_FALSE(IsProbablyDuplicate<4>(p1, 4));
|
||||
ASSERT_FALSE(IsProbablyDuplicate<4>(p2, 4));
|
||||
ASSERT_TRUE(IsProbablyDuplicate<4>(p3, 4));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MINING
|
||||
TEST(equihash_tests, check_basic_solver_cancelled) {
|
||||
Equihash<48,5> Eh48_5;
|
||||
crypto_generichash_blake2b_state state;
|
||||
Eh48_5.InitialiseState(state);
|
||||
uint256 V = uint256S("0x00");
|
||||
crypto_generichash_blake2b_update(&state, V.begin(), V.size());
|
||||
|
||||
{
|
||||
ASSERT_NO_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == ListGeneration;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == ListSorting;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == ListColliding;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == RoundEnd;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == FinalSorting;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == FinalColliding;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_NO_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == PartialGeneration;
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_NO_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == PartialSorting;
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_NO_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == PartialSubtreeEnd;
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_NO_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == PartialIndexEnd;
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_NO_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == PartialEnd;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(equihash_tests, check_optimised_solver_cancelled) {
|
||||
Equihash<48,5> Eh48_5;
|
||||
crypto_generichash_blake2b_state state;
|
||||
Eh48_5.InitialiseState(state);
|
||||
uint256 V = uint256S("0x00");
|
||||
crypto_generichash_blake2b_update(&state, V.begin(), V.size());
|
||||
|
||||
{
|
||||
ASSERT_NO_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == ListGeneration;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == ListSorting;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == ListColliding;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == RoundEnd;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == FinalSorting;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == FinalColliding;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == PartialGeneration;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == PartialSorting;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == PartialSubtreeEnd;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == PartialIndexEnd;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) {
|
||||
return false;
|
||||
}, [](EhSolverCancelCheck pos) {
|
||||
return pos == PartialEnd;
|
||||
}), EhSolverCancelledException);
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_MINING
|
|
@ -0,0 +1,195 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "utilmoneystr.h"
|
||||
#include "chainparams.h"
|
||||
#include "utilstrencodings.h"
|
||||
#include "zcash/Address.hpp"
|
||||
#include "wallet/wallet.h"
|
||||
#include "amount.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "util.h"
|
||||
|
||||
// To run tests:
|
||||
// ./zcash-gtest --gtest_filter="founders_reward_test.*"
|
||||
|
||||
//
|
||||
// Enable this test to generate and print 48 testnet 2-of-3 multisig addresses.
|
||||
// The output can be copied into chainparams.cpp.
|
||||
// The temporary wallet file can be renamed as wallet.dat and used for testing with zcashd.
|
||||
//
|
||||
#if 0
|
||||
TEST(founders_reward_test, create_testnet_2of3multisig) {
|
||||
ECC_Start();
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
boost::filesystem::create_directories(pathTemp);
|
||||
mapArgs["-datadir"] = pathTemp.string();
|
||||
bool fFirstRun;
|
||||
auto pWallet = std::make_shared<CWallet>("wallet.dat");
|
||||
ASSERT_EQ(DB_LOAD_OK, pWallet->LoadWallet(fFirstRun));
|
||||
pWallet->TopUpKeyPool();
|
||||
std::cout << "Test wallet and logs saved in folder: " << pathTemp.native() << std::endl;
|
||||
|
||||
int numKeys = 48;
|
||||
std::vector<CPubKey> pubkeys;
|
||||
pubkeys.resize(3);
|
||||
CPubKey newKey;
|
||||
std::vector<std::string> addresses;
|
||||
for (int i = 0; i < numKeys; i++) {
|
||||
ASSERT_TRUE(pWallet->GetKeyFromPool(newKey));
|
||||
pubkeys[0] = newKey;
|
||||
pWallet->SetAddressBook(newKey.GetID(), "", "receive");
|
||||
|
||||
ASSERT_TRUE(pWallet->GetKeyFromPool(newKey));
|
||||
pubkeys[1] = newKey;
|
||||
pWallet->SetAddressBook(newKey.GetID(), "", "receive");
|
||||
|
||||
ASSERT_TRUE(pWallet->GetKeyFromPool(newKey));
|
||||
pubkeys[2] = newKey;
|
||||
pWallet->SetAddressBook(newKey.GetID(), "", "receive");
|
||||
|
||||
CScript result = GetScriptForMultisig(2, pubkeys);
|
||||
ASSERT_FALSE(result.size() > MAX_SCRIPT_ELEMENT_SIZE);
|
||||
CScriptID innerID(result);
|
||||
pWallet->AddCScript(result);
|
||||
pWallet->SetAddressBook(innerID, "", "receive");
|
||||
|
||||
std::string address = CBitcoinAddress(innerID).ToString();
|
||||
addresses.push_back(address);
|
||||
}
|
||||
|
||||
// Print out the addresses, 4 on each line.
|
||||
std::string s = "vFoundersRewardAddress = {\n";
|
||||
int i=0;
|
||||
int colsPerRow = 4;
|
||||
ASSERT_TRUE(numKeys % colsPerRow == 0);
|
||||
int numRows = numKeys/colsPerRow;
|
||||
for (int row=0; row<numRows; row++) {
|
||||
s += " ";
|
||||
for (int col=0; col<colsPerRow; col++) {
|
||||
s += "\"" + addresses[i++] + "\", ";
|
||||
}
|
||||
s += "\n";
|
||||
}
|
||||
s += " };";
|
||||
std::cout << s << std::endl;
|
||||
|
||||
pWallet->Flush(true);
|
||||
|
||||
ECC_Stop();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Utility method to check the number of unique addresses from height 1 to maxHeight
|
||||
void checkNumberOfUniqueAddresses(int nUnique) {
|
||||
int maxHeight = Params().GetConsensus().GetLastFoundersRewardBlockHeight();
|
||||
std::set<std::string> addresses;
|
||||
for (int i = 1; i <= maxHeight; i++) {
|
||||
addresses.insert(Params().GetFoundersRewardAddressAtHeight(i));
|
||||
}
|
||||
ASSERT_TRUE(addresses.size() == nUnique);
|
||||
}
|
||||
|
||||
|
||||
TEST(founders_reward_test, general) {
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
|
||||
CChainParams params = Params();
|
||||
|
||||
// Fourth testnet reward:
|
||||
// address = t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy
|
||||
// script.ToString() = OP_HASH160 55d64928e69829d9376c776550b6cc710d427153 OP_EQUAL
|
||||
// HexStr(script) = a91455d64928e69829d9376c776550b6cc710d42715387
|
||||
EXPECT_EQ(params.GetFoundersRewardScriptAtHeight(1), ParseHex("a914ef775f1f997f122a062fff1a2d7443abd1f9c64287"));
|
||||
EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(1), "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi");
|
||||
EXPECT_EQ(params.GetFoundersRewardScriptAtHeight(53126), ParseHex("a914ac67f4c072668138d88a86ff21b27207b283212f87"));
|
||||
EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(53126), "t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2");
|
||||
EXPECT_EQ(params.GetFoundersRewardScriptAtHeight(53127), ParseHex("a91455d64928e69829d9376c776550b6cc710d42715387"));
|
||||
EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(53127), "t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy");
|
||||
|
||||
int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight();
|
||||
|
||||
// If the block height parameter is out of bounds, there is an assert.
|
||||
EXPECT_DEATH(params.GetFoundersRewardScriptAtHeight(0), "nHeight");
|
||||
EXPECT_DEATH(params.GetFoundersRewardScriptAtHeight(maxHeight+1), "nHeight");
|
||||
EXPECT_DEATH(params.GetFoundersRewardAddressAtHeight(0), "nHeight");
|
||||
EXPECT_DEATH(params.GetFoundersRewardAddressAtHeight(maxHeight+1), "nHeight");
|
||||
}
|
||||
|
||||
|
||||
#define NUM_MAINNET_FOUNDER_ADDRESSES 48
|
||||
|
||||
TEST(founders_reward_test, mainnet) {
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
checkNumberOfUniqueAddresses(NUM_MAINNET_FOUNDER_ADDRESSES);
|
||||
}
|
||||
|
||||
|
||||
#define NUM_TESTNET_FOUNDER_ADDRESSES 48
|
||||
|
||||
TEST(founders_reward_test, testnet) {
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
checkNumberOfUniqueAddresses(NUM_TESTNET_FOUNDER_ADDRESSES);
|
||||
}
|
||||
|
||||
|
||||
#define NUM_REGTEST_FOUNDER_ADDRESSES 1
|
||||
|
||||
TEST(founders_reward_test, regtest) {
|
||||
SelectParams(CBaseChainParams::REGTEST);
|
||||
checkNumberOfUniqueAddresses(NUM_REGTEST_FOUNDER_ADDRESSES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Test that 10% founders reward is fully rewarded after the first halving and slow start shift.
|
||||
// On Mainnet, this would be 2,100,000 ZEC after 850,000 blocks (840,000 + 10,000).
|
||||
TEST(founders_reward_test, slow_start_subsidy) {
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
CChainParams params = Params();
|
||||
|
||||
int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight();
|
||||
CAmount totalSubsidy = 0;
|
||||
for (int nHeight = 1; nHeight <= maxHeight; nHeight++) {
|
||||
CAmount nSubsidy = GetBlockSubsidy(nHeight, params.GetConsensus()) / 5;
|
||||
totalSubsidy += nSubsidy;
|
||||
}
|
||||
|
||||
ASSERT_TRUE(totalSubsidy == MAX_MONEY/10.0);
|
||||
}
|
||||
|
||||
|
||||
// For use with mainnet and testnet which each have 48 addresses.
|
||||
// Verify the number of rewards each individual address receives.
|
||||
void verifyNumberOfRewards() {
|
||||
CChainParams params = Params();
|
||||
int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight();
|
||||
std::multiset<std::string> ms;
|
||||
for (int nHeight = 1; nHeight <= maxHeight; nHeight++) {
|
||||
ms.insert(params.GetFoundersRewardAddressAtHeight(nHeight));
|
||||
}
|
||||
|
||||
ASSERT_TRUE(ms.count(params.GetFoundersRewardAddressAtIndex(0)) == 17708);
|
||||
for (int i = 1; i <= 46; i++) {
|
||||
ASSERT_TRUE(ms.count(params.GetFoundersRewardAddressAtIndex(i)) == 17709);
|
||||
}
|
||||
ASSERT_TRUE(ms.count(params.GetFoundersRewardAddressAtIndex(47)) == 17677);
|
||||
}
|
||||
|
||||
// Verify the number of rewards going to each mainnet address
|
||||
TEST(founders_reward_test, per_address_reward_mainnet) {
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
verifyNumberOfRewards();
|
||||
}
|
||||
|
||||
// Verify the number of rewards going to each testnet address
|
||||
TEST(founders_reward_test, per_address_reward_testnet) {
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
verifyNumberOfRewards();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,549 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "zcash/prf.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "zcash/JoinSplit.hpp"
|
||||
#include "zcash/Note.hpp"
|
||||
#include "zcash/NoteEncryption.hpp"
|
||||
#include "zcash/IncrementalMerkleTree.hpp"
|
||||
|
||||
using namespace libzcash;
|
||||
|
||||
extern ZCJoinSplit* params;
|
||||
|
||||
void test_full_api(ZCJoinSplit* js)
|
||||
{
|
||||
// Create verification context.
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
|
||||
// The recipient's information.
|
||||
SpendingKey recipient_key = SpendingKey::random();
|
||||
PaymentAddress recipient_addr = recipient_key.address();
|
||||
|
||||
// Create the commitment tree
|
||||
ZCIncrementalMerkleTree tree;
|
||||
|
||||
// Set up a JoinSplit description
|
||||
uint256 ephemeralKey;
|
||||
uint256 randomSeed;
|
||||
uint64_t vpub_old = 10;
|
||||
uint64_t vpub_new = 0;
|
||||
uint256 pubKeyHash = random_uint256();
|
||||
boost::array<uint256, 2> macs;
|
||||
boost::array<uint256, 2> nullifiers;
|
||||
boost::array<uint256, 2> commitments;
|
||||
uint256 rt = tree.root();
|
||||
boost::array<ZCNoteEncryption::Ciphertext, 2> ciphertexts;
|
||||
ZCProof proof;
|
||||
|
||||
{
|
||||
boost::array<JSInput, 2> inputs = {
|
||||
JSInput(), // dummy input
|
||||
JSInput() // dummy input
|
||||
};
|
||||
|
||||
boost::array<JSOutput, 2> outputs = {
|
||||
JSOutput(recipient_addr, 10),
|
||||
JSOutput() // dummy output
|
||||
};
|
||||
|
||||
boost::array<Note, 2> output_notes;
|
||||
|
||||
// Perform the proof
|
||||
proof = js->prove(
|
||||
inputs,
|
||||
outputs,
|
||||
output_notes,
|
||||
ciphertexts,
|
||||
ephemeralKey,
|
||||
pubKeyHash,
|
||||
randomSeed,
|
||||
macs,
|
||||
nullifiers,
|
||||
commitments,
|
||||
vpub_old,
|
||||
vpub_new,
|
||||
rt
|
||||
);
|
||||
}
|
||||
|
||||
// Verify the transaction:
|
||||
ASSERT_TRUE(js->verify(
|
||||
proof,
|
||||
verifier,
|
||||
pubKeyHash,
|
||||
randomSeed,
|
||||
macs,
|
||||
nullifiers,
|
||||
commitments,
|
||||
vpub_old,
|
||||
vpub_new,
|
||||
rt
|
||||
));
|
||||
|
||||
// Recipient should decrypt
|
||||
// Now the recipient should spend the money again
|
||||
auto h_sig = js->h_sig(randomSeed, nullifiers, pubKeyHash);
|
||||
ZCNoteDecryption decryptor(recipient_key.receiving_key());
|
||||
|
||||
auto note_pt = NotePlaintext::decrypt(
|
||||
decryptor,
|
||||
ciphertexts[0],
|
||||
ephemeralKey,
|
||||
h_sig,
|
||||
0
|
||||
);
|
||||
|
||||
auto decrypted_note = note_pt.note(recipient_addr);
|
||||
|
||||
ASSERT_TRUE(decrypted_note.value == 10);
|
||||
|
||||
// Insert the commitments from the last tx into the tree
|
||||
tree.append(commitments[0]);
|
||||
auto witness_recipient = tree.witness();
|
||||
tree.append(commitments[1]);
|
||||
witness_recipient.append(commitments[1]);
|
||||
vpub_old = 0;
|
||||
vpub_new = 1;
|
||||
rt = tree.root();
|
||||
pubKeyHash = random_uint256();
|
||||
|
||||
{
|
||||
boost::array<JSInput, 2> inputs = {
|
||||
JSInput(), // dummy input
|
||||
JSInput(witness_recipient, decrypted_note, recipient_key)
|
||||
};
|
||||
|
||||
SpendingKey second_recipient = SpendingKey::random();
|
||||
PaymentAddress second_addr = second_recipient.address();
|
||||
|
||||
boost::array<JSOutput, 2> outputs = {
|
||||
JSOutput(second_addr, 9),
|
||||
JSOutput() // dummy output
|
||||
};
|
||||
|
||||
boost::array<Note, 2> output_notes;
|
||||
|
||||
// Perform the proof
|
||||
proof = js->prove(
|
||||
inputs,
|
||||
outputs,
|
||||
output_notes,
|
||||
ciphertexts,
|
||||
ephemeralKey,
|
||||
pubKeyHash,
|
||||
randomSeed,
|
||||
macs,
|
||||
nullifiers,
|
||||
commitments,
|
||||
vpub_old,
|
||||
vpub_new,
|
||||
rt
|
||||
);
|
||||
}
|
||||
|
||||
// Verify the transaction:
|
||||
ASSERT_TRUE(js->verify(
|
||||
proof,
|
||||
verifier,
|
||||
pubKeyHash,
|
||||
randomSeed,
|
||||
macs,
|
||||
nullifiers,
|
||||
commitments,
|
||||
vpub_old,
|
||||
vpub_new,
|
||||
rt
|
||||
));
|
||||
}
|
||||
|
||||
// Invokes the API (but does not compute a proof)
|
||||
// to test exceptions
|
||||
void invokeAPI(
|
||||
ZCJoinSplit* js,
|
||||
const boost::array<JSInput, 2>& inputs,
|
||||
const boost::array<JSOutput, 2>& outputs,
|
||||
uint64_t vpub_old,
|
||||
uint64_t vpub_new,
|
||||
const uint256& rt
|
||||
) {
|
||||
uint256 ephemeralKey;
|
||||
uint256 randomSeed;
|
||||
uint256 pubKeyHash = random_uint256();
|
||||
boost::array<uint256, 2> macs;
|
||||
boost::array<uint256, 2> nullifiers;
|
||||
boost::array<uint256, 2> commitments;
|
||||
boost::array<ZCNoteEncryption::Ciphertext, 2> ciphertexts;
|
||||
|
||||
boost::array<Note, 2> output_notes;
|
||||
|
||||
ZCProof proof = js->prove(
|
||||
inputs,
|
||||
outputs,
|
||||
output_notes,
|
||||
ciphertexts,
|
||||
ephemeralKey,
|
||||
pubKeyHash,
|
||||
randomSeed,
|
||||
macs,
|
||||
nullifiers,
|
||||
commitments,
|
||||
vpub_old,
|
||||
vpub_new,
|
||||
rt,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
void invokeAPIFailure(
|
||||
ZCJoinSplit* js,
|
||||
const boost::array<JSInput, 2>& inputs,
|
||||
const boost::array<JSOutput, 2>& outputs,
|
||||
uint64_t vpub_old,
|
||||
uint64_t vpub_new,
|
||||
const uint256& rt,
|
||||
std::string reason
|
||||
)
|
||||
{
|
||||
try {
|
||||
invokeAPI(js, inputs, outputs, vpub_old, vpub_new, rt);
|
||||
FAIL() << "It worked, when it shouldn't have!";
|
||||
} catch(std::invalid_argument const & err) {
|
||||
EXPECT_EQ(err.what(), reason);
|
||||
} catch(...) {
|
||||
FAIL() << "Expected invalid_argument exception.";
|
||||
}
|
||||
}
|
||||
|
||||
TEST(joinsplit, h_sig)
|
||||
{
|
||||
/*
|
||||
// by Taylor Hornby
|
||||
|
||||
import pyblake2
|
||||
import binascii
|
||||
|
||||
def hSig(randomSeed, nf1, nf2, pubKeyHash):
|
||||
return pyblake2.blake2b(
|
||||
data=(randomSeed + nf1 + nf2 + pubKeyHash),
|
||||
digest_size=32,
|
||||
person=b"ZcashComputehSig"
|
||||
).digest()
|
||||
|
||||
INCREASING = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
|
||||
|
||||
TEST_VECTORS = [
|
||||
[b"a" * 32, b"b" * 32, b"c" * 32, b"d" * 32],
|
||||
[b"\x00" * 32, b"\x00" * 32, b"\x00" * 32, b"\x00" * 32],
|
||||
[b"\xFF" * 32, b"\xFF" * 32, b"\xFF" * 32, b"\xFF" * 32],
|
||||
[INCREASING, INCREASING, INCREASING, INCREASING]
|
||||
]
|
||||
|
||||
for test_input in TEST_VECTORS:
|
||||
print "---"
|
||||
print "\"" + binascii.hexlify(test_input[0][::-1]) + "\""
|
||||
print "\"" + binascii.hexlify(test_input[1][::-1]) + "\""
|
||||
print "\"" + binascii.hexlify(test_input[2][::-1]) + "\""
|
||||
print "\"" + binascii.hexlify(test_input[3][::-1]) + "\""
|
||||
print "\"" + binascii.hexlify(hSig(test_input[0], test_input[1], test_input[2], test_input[3])[::-1]) + "\""
|
||||
*/
|
||||
|
||||
std::vector<std::vector<std::string>> tests = {
|
||||
{
|
||||
"6161616161616161616161616161616161616161616161616161616161616161",
|
||||
"6262626262626262626262626262626262626262626262626262626262626262",
|
||||
"6363636363636363636363636363636363636363636363636363636363636363",
|
||||
"6464646464646464646464646464646464646464646464646464646464646464",
|
||||
"a8cba69f1fa329c055756b4af900f8a00b61e44f4cb8a1824ceb58b90a5b8113"
|
||||
},
|
||||
{
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"697322276b5dd93b12fb1fcbd2144b2960f24c73aac6c6a0811447be1e7f1e19"
|
||||
},
|
||||
{
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"4961048919f0ca79d49c9378c36a91a8767060001f4212fe6f7d426f3ccf9f32"
|
||||
},
|
||||
{
|
||||
"1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100",
|
||||
"1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100",
|
||||
"1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100",
|
||||
"1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100",
|
||||
"b61110ec162693bc3d9ca7fb0eec3afd2e278e2f41394b3ff11d7cb761ad4b27"
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_FOREACH(std::vector<std::string>& v, tests) {
|
||||
auto expected = ZCJoinSplit::h_sig(
|
||||
uint256S(v[0]),
|
||||
{uint256S(v[1]), uint256S(v[2])},
|
||||
uint256S(v[3])
|
||||
);
|
||||
|
||||
EXPECT_EQ(expected, uint256S(v[4]));
|
||||
}
|
||||
}
|
||||
|
||||
void increment_note_witnesses(
|
||||
const uint256& element,
|
||||
std::vector<ZCIncrementalWitness>& witnesses,
|
||||
ZCIncrementalMerkleTree& tree
|
||||
)
|
||||
{
|
||||
tree.append(element);
|
||||
for (ZCIncrementalWitness& w : witnesses) {
|
||||
w.append(element);
|
||||
}
|
||||
witnesses.push_back(tree.witness());
|
||||
}
|
||||
|
||||
TEST(joinsplit, full_api_test)
|
||||
{
|
||||
{
|
||||
std::vector<ZCIncrementalWitness> witnesses;
|
||||
ZCIncrementalMerkleTree tree;
|
||||
increment_note_witnesses(uint256(), witnesses, tree);
|
||||
SpendingKey sk = SpendingKey::random();
|
||||
PaymentAddress addr = sk.address();
|
||||
Note note1(addr.a_pk, 100, random_uint256(), random_uint256());
|
||||
increment_note_witnesses(note1.cm(), witnesses, tree);
|
||||
Note note2(addr.a_pk, 100, random_uint256(), random_uint256());
|
||||
increment_note_witnesses(note2.cm(), witnesses, tree);
|
||||
Note note3(addr.a_pk, 2100000000000001, random_uint256(), random_uint256());
|
||||
increment_note_witnesses(note3.cm(), witnesses, tree);
|
||||
Note note4(addr.a_pk, 1900000000000000, random_uint256(), random_uint256());
|
||||
increment_note_witnesses(note4.cm(), witnesses, tree);
|
||||
Note note5(addr.a_pk, 1900000000000000, random_uint256(), random_uint256());
|
||||
increment_note_witnesses(note5.cm(), witnesses, tree);
|
||||
|
||||
// Should work
|
||||
invokeAPI(params,
|
||||
{
|
||||
JSInput(),
|
||||
JSInput()
|
||||
},
|
||||
{
|
||||
JSOutput(),
|
||||
JSOutput()
|
||||
},
|
||||
0,
|
||||
0,
|
||||
tree.root());
|
||||
|
||||
// lhs > MAX_MONEY
|
||||
invokeAPIFailure(params,
|
||||
{
|
||||
JSInput(),
|
||||
JSInput()
|
||||
},
|
||||
{
|
||||
JSOutput(),
|
||||
JSOutput()
|
||||
},
|
||||
2100000000000001,
|
||||
0,
|
||||
tree.root(),
|
||||
"nonsensical vpub_old value");
|
||||
|
||||
// rhs > MAX_MONEY
|
||||
invokeAPIFailure(params,
|
||||
{
|
||||
JSInput(),
|
||||
JSInput()
|
||||
},
|
||||
{
|
||||
JSOutput(),
|
||||
JSOutput()
|
||||
},
|
||||
0,
|
||||
2100000000000001,
|
||||
tree.root(),
|
||||
"nonsensical vpub_new value");
|
||||
|
||||
// input witness for the wrong element
|
||||
invokeAPIFailure(params,
|
||||
{
|
||||
JSInput(witnesses[0], note1, sk),
|
||||
JSInput()
|
||||
},
|
||||
{
|
||||
JSOutput(),
|
||||
JSOutput()
|
||||
},
|
||||
0,
|
||||
100,
|
||||
tree.root(),
|
||||
"witness of wrong element for joinsplit input");
|
||||
|
||||
// input witness doesn't match up with
|
||||
// real root
|
||||
invokeAPIFailure(params,
|
||||
{
|
||||
JSInput(witnesses[1], note1, sk),
|
||||
JSInput()
|
||||
},
|
||||
{
|
||||
JSOutput(),
|
||||
JSOutput()
|
||||
},
|
||||
0,
|
||||
100,
|
||||
uint256(),
|
||||
"joinsplit not anchored to the correct root");
|
||||
|
||||
// input is in the tree now! this should work
|
||||
invokeAPI(params,
|
||||
{
|
||||
JSInput(witnesses[1], note1, sk),
|
||||
JSInput()
|
||||
},
|
||||
{
|
||||
JSOutput(),
|
||||
JSOutput()
|
||||
},
|
||||
0,
|
||||
100,
|
||||
tree.root());
|
||||
|
||||
// Wrong secret key
|
||||
invokeAPIFailure(params,
|
||||
{
|
||||
JSInput(witnesses[1], note1, SpendingKey::random()),
|
||||
JSInput()
|
||||
},
|
||||
{
|
||||
JSOutput(),
|
||||
JSOutput()
|
||||
},
|
||||
0,
|
||||
0,
|
||||
tree.root(),
|
||||
"input note not authorized to spend with given key");
|
||||
|
||||
// Absurd input value
|
||||
invokeAPIFailure(params,
|
||||
{
|
||||
JSInput(witnesses[3], note3, sk),
|
||||
JSInput()
|
||||
},
|
||||
{
|
||||
JSOutput(),
|
||||
JSOutput()
|
||||
},
|
||||
0,
|
||||
0,
|
||||
tree.root(),
|
||||
"nonsensical input note value");
|
||||
|
||||
// Absurd total input value
|
||||
invokeAPIFailure(params,
|
||||
{
|
||||
JSInput(witnesses[4], note4, sk),
|
||||
JSInput(witnesses[5], note5, sk)
|
||||
},
|
||||
{
|
||||
JSOutput(),
|
||||
JSOutput()
|
||||
},
|
||||
0,
|
||||
0,
|
||||
tree.root(),
|
||||
"nonsensical left hand size of joinsplit balance");
|
||||
|
||||
// Absurd output value
|
||||
invokeAPIFailure(params,
|
||||
{
|
||||
JSInput(),
|
||||
JSInput()
|
||||
},
|
||||
{
|
||||
JSOutput(addr, 2100000000000001),
|
||||
JSOutput()
|
||||
},
|
||||
0,
|
||||
0,
|
||||
tree.root(),
|
||||
"nonsensical output value");
|
||||
|
||||
// Absurd total output value
|
||||
invokeAPIFailure(params,
|
||||
{
|
||||
JSInput(),
|
||||
JSInput()
|
||||
},
|
||||
{
|
||||
JSOutput(addr, 1900000000000000),
|
||||
JSOutput(addr, 1900000000000000)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
tree.root(),
|
||||
"nonsensical right hand side of joinsplit balance");
|
||||
|
||||
// Absurd total output value
|
||||
invokeAPIFailure(params,
|
||||
{
|
||||
JSInput(),
|
||||
JSInput()
|
||||
},
|
||||
{
|
||||
JSOutput(addr, 1900000000000000),
|
||||
JSOutput()
|
||||
},
|
||||
0,
|
||||
0,
|
||||
tree.root(),
|
||||
"invalid joinsplit balance");
|
||||
}
|
||||
|
||||
test_full_api(params);
|
||||
}
|
||||
|
||||
TEST(joinsplit, note_plaintexts)
|
||||
{
|
||||
uint252 a_sk = uint252(uint256S("f6da8716682d600f74fc16bd0187faad6a26b4aa4c24d5c055b216d94516840e"));
|
||||
uint256 a_pk = PRF_addr_a_pk(a_sk);
|
||||
uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk);
|
||||
uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc);
|
||||
PaymentAddress addr_pk(a_pk, pk_enc);
|
||||
|
||||
uint256 h_sig;
|
||||
|
||||
ZCNoteEncryption encryptor(h_sig);
|
||||
uint256 epk = encryptor.get_epk();
|
||||
|
||||
Note note(a_pk,
|
||||
1945813,
|
||||
random_uint256(),
|
||||
random_uint256()
|
||||
);
|
||||
|
||||
boost::array<unsigned char, ZC_MEMO_SIZE> memo;
|
||||
|
||||
NotePlaintext note_pt(note, memo);
|
||||
|
||||
ZCNoteEncryption::Ciphertext ct = note_pt.encrypt(encryptor, pk_enc);
|
||||
|
||||
ZCNoteDecryption decryptor(sk_enc);
|
||||
|
||||
auto decrypted = NotePlaintext::decrypt(decryptor, ct, epk, h_sig, 0);
|
||||
auto decrypted_note = decrypted.note(addr_pk);
|
||||
|
||||
ASSERT_TRUE(decrypted_note.a_pk == note.a_pk);
|
||||
ASSERT_TRUE(decrypted_note.rho == note.rho);
|
||||
ASSERT_TRUE(decrypted_note.r == note.r);
|
||||
ASSERT_TRUE(decrypted_note.value == note.value);
|
||||
|
||||
ASSERT_TRUE(decrypted.memo == note_pt.memo);
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "keystore.h"
|
||||
#include "random.h"
|
||||
#ifdef ENABLE_WALLET
|
||||
#include "wallet/crypter.h"
|
||||
#endif
|
||||
#include "zcash/Address.hpp"
|
||||
|
||||
TEST(keystore_tests, store_and_retrieve_spending_key) {
|
||||
CBasicKeyStore keyStore;
|
||||
libzcash::SpendingKey skOut;
|
||||
|
||||
std::set<libzcash::PaymentAddress> addrs;
|
||||
keyStore.GetPaymentAddresses(addrs);
|
||||
EXPECT_EQ(0, addrs.size());
|
||||
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
auto addr = sk.address();
|
||||
|
||||
// Sanity-check: we can't get a key we haven't added
|
||||
EXPECT_FALSE(keyStore.HaveSpendingKey(addr));
|
||||
EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut));
|
||||
|
||||
keyStore.AddSpendingKey(sk);
|
||||
EXPECT_TRUE(keyStore.HaveSpendingKey(addr));
|
||||
EXPECT_TRUE(keyStore.GetSpendingKey(addr, skOut));
|
||||
EXPECT_EQ(sk, skOut);
|
||||
|
||||
keyStore.GetPaymentAddresses(addrs);
|
||||
EXPECT_EQ(1, addrs.size());
|
||||
EXPECT_EQ(1, addrs.count(addr));
|
||||
}
|
||||
|
||||
TEST(keystore_tests, store_and_retrieve_note_decryptor) {
|
||||
CBasicKeyStore keyStore;
|
||||
ZCNoteDecryption decOut;
|
||||
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
auto addr = sk.address();
|
||||
|
||||
EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut));
|
||||
|
||||
keyStore.AddSpendingKey(sk);
|
||||
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
|
||||
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
|
||||
}
|
||||
|
||||
TEST(keystore_tests, StoreAndRetrieveViewingKey) {
|
||||
CBasicKeyStore keyStore;
|
||||
libzcash::ViewingKey vkOut;
|
||||
libzcash::SpendingKey skOut;
|
||||
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
|
||||
class TestCCryptoKeyStore : public CCryptoKeyStore
|
||||
{
|
||||
public:
|
||||
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn) { return CCryptoKeyStore::EncryptKeys(vMasterKeyIn); }
|
||||
bool Unlock(const CKeyingMaterial& vMasterKeyIn) { return CCryptoKeyStore::Unlock(vMasterKeyIn); }
|
||||
};
|
||||
|
||||
TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) {
|
||||
TestCCryptoKeyStore keyStore;
|
||||
uint256 r {GetRandHash()};
|
||||
CKeyingMaterial vMasterKey (r.begin(), r.end());
|
||||
libzcash::SpendingKey keyOut;
|
||||
ZCNoteDecryption decOut;
|
||||
std::set<libzcash::PaymentAddress> addrs;
|
||||
|
||||
// 1) Test adding a key to an unencrypted key store, then encrypting it
|
||||
auto sk = libzcash::SpendingKey::random();
|
||||
auto addr = sk.address();
|
||||
EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut));
|
||||
|
||||
keyStore.AddSpendingKey(sk);
|
||||
ASSERT_TRUE(keyStore.HaveSpendingKey(addr));
|
||||
ASSERT_TRUE(keyStore.GetSpendingKey(addr, keyOut));
|
||||
ASSERT_EQ(sk, keyOut);
|
||||
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut));
|
||||
EXPECT_EQ(ZCNoteDecryption(sk.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.receiving_key()), decOut);
|
||||
|
||||
// Unlocking with a random key should fail
|
||||
uint256 r2 {GetRandHash()};
|
||||
CKeyingMaterial vRandomKey (r2.begin(), r2.end());
|
||||
EXPECT_FALSE(keyStore.Unlock(vRandomKey));
|
||||
|
||||
// Unlocking with a slightly-modified vMasterKey should fail
|
||||
CKeyingMaterial vModifiedKey (r.begin(), r.end());
|
||||
vModifiedKey[0] += 1;
|
||||
EXPECT_FALSE(keyStore.Unlock(vModifiedKey));
|
||||
|
||||
// Unlocking with vMasterKey should succeed
|
||||
ASSERT_TRUE(keyStore.Unlock(vMasterKey));
|
||||
ASSERT_TRUE(keyStore.GetSpendingKey(addr, keyOut));
|
||||
ASSERT_EQ(sk, keyOut);
|
||||
|
||||
keyStore.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(1, addrs.size());
|
||||
ASSERT_EQ(1, addrs.count(addr));
|
||||
|
||||
// 2) Test adding a spending key to an already-encrypted key store
|
||||
auto sk2 = libzcash::SpendingKey::random();
|
||||
auto addr2 = sk2.address();
|
||||
EXPECT_FALSE(keyStore.GetNoteDecryptor(addr2, decOut));
|
||||
|
||||
keyStore.AddSpendingKey(sk2);
|
||||
ASSERT_TRUE(keyStore.HaveSpendingKey(addr2));
|
||||
ASSERT_TRUE(keyStore.GetSpendingKey(addr2, keyOut));
|
||||
ASSERT_EQ(sk2, keyOut);
|
||||
EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut));
|
||||
EXPECT_EQ(ZCNoteDecryption(sk2.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.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.receiving_key()), decOut);
|
||||
|
||||
keyStore.GetPaymentAddresses(addrs);
|
||||
ASSERT_EQ(2, addrs.size());
|
||||
ASSERT_EQ(1, addrs.count(addr));
|
||||
ASSERT_EQ(1, addrs.count(addr2));
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,44 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "zcash/util.h"
|
||||
|
||||
TEST(libzcash_utils, convertBytesVectorToVector)
|
||||
{
|
||||
std::vector<unsigned char> bytes = {0x00, 0x01, 0x03, 0x12, 0xFF};
|
||||
std::vector<bool> expected_bits = {
|
||||
// 0x00
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
// 0x01
|
||||
0, 0, 0, 0, 0, 0, 0, 1,
|
||||
// 0x03
|
||||
0, 0, 0, 0, 0, 0, 1, 1,
|
||||
// 0x12
|
||||
0, 0, 0, 1, 0, 0, 1, 0,
|
||||
// 0xFF
|
||||
1, 1, 1, 1, 1, 1, 1, 1
|
||||
};
|
||||
ASSERT_TRUE(convertBytesVectorToVector(bytes) == expected_bits);
|
||||
}
|
||||
|
||||
TEST(libzcash_utils, convertVectorToInt)
|
||||
{
|
||||
ASSERT_TRUE(convertVectorToInt({0}) == 0);
|
||||
ASSERT_TRUE(convertVectorToInt({1}) == 1);
|
||||
ASSERT_TRUE(convertVectorToInt({0,1}) == 1);
|
||||
ASSERT_TRUE(convertVectorToInt({1,0}) == 2);
|
||||
ASSERT_TRUE(convertVectorToInt({1,1}) == 3);
|
||||
ASSERT_TRUE(convertVectorToInt({1,0,0}) == 4);
|
||||
ASSERT_TRUE(convertVectorToInt({1,0,1}) == 5);
|
||||
ASSERT_TRUE(convertVectorToInt({1,1,0}) == 6);
|
||||
|
||||
ASSERT_THROW(convertVectorToInt(std::vector<bool>(100)), std::length_error);
|
||||
|
||||
{
|
||||
std::vector<bool> v(63, 1);
|
||||
ASSERT_TRUE(convertVectorToInt(v) == 0x7fffffffffffffff);
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<bool> v(64, 1);
|
||||
ASSERT_TRUE(convertVectorToInt(v) == 0xffffffffffffffff);
|
||||
}
|
||||
}
|
|
@ -0,0 +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), ""), "");
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "test/data/merkle_roots.json.h"
|
||||
#include "test/data/merkle_roots_empty.json.h"
|
||||
#include "test/data/merkle_serialization.json.h"
|
||||
#include "test/data/merkle_witness_serialization.json.h"
|
||||
#include "test/data/merkle_path.json.h"
|
||||
#include "test/data/merkle_commitments.json.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "utilstrencodings.h"
|
||||
#include "version.h"
|
||||
#include "serialize.h"
|
||||
#include "streams.h"
|
||||
|
||||
#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 <boost/foreach.hpp>
|
||||
|
||||
#include "json_test_vectors.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace libsnark;
|
||||
|
||||
template<>
|
||||
void expect_deser_same(const ZCTestingIncrementalWitness& expected)
|
||||
{
|
||||
// Cannot check this; IncrementalWitness cannot be
|
||||
// deserialized because it can only be constructed by
|
||||
// IncrementalMerkleTree, and it does not yet have a
|
||||
// canonical serialized representation.
|
||||
}
|
||||
|
||||
template<>
|
||||
void expect_deser_same(const libzcash::MerklePath& expected)
|
||||
{
|
||||
// This deserialization check is pointless for MerklePath,
|
||||
// since we only serialize it to check it against test
|
||||
// vectors. See `expect_test_vector` for that. Also,
|
||||
// it doesn't seem that vector<bool> can be properly
|
||||
// deserialized by Bitcoin's serialization code.
|
||||
}
|
||||
|
||||
template<typename A, typename B, typename C>
|
||||
void expect_ser_test_vector(B& b, const C& c, const A& tree) {
|
||||
expect_test_vector<B, C>(b, c);
|
||||
}
|
||||
|
||||
template<typename Tree, typename Witness>
|
||||
void test_tree(
|
||||
UniValue commitment_tests,
|
||||
UniValue root_tests,
|
||||
UniValue ser_tests,
|
||||
UniValue witness_ser_tests,
|
||||
UniValue path_tests
|
||||
)
|
||||
{
|
||||
size_t witness_ser_i = 0;
|
||||
size_t path_i = 0;
|
||||
|
||||
Tree tree;
|
||||
|
||||
// The root of the tree at this point is expected to be the root of the
|
||||
// empty tree.
|
||||
ASSERT_TRUE(tree.root() == Tree::empty_root());
|
||||
|
||||
// The tree doesn't have a 'last' element added since it's blank.
|
||||
ASSERT_THROW(tree.last(), std::runtime_error);
|
||||
|
||||
// The tree is empty.
|
||||
ASSERT_TRUE(tree.size() == 0);
|
||||
|
||||
// We need to witness at every single point in the tree, so
|
||||
// that the consistency of the tree and the merkle paths can
|
||||
// be checked.
|
||||
vector<Witness> witnesses;
|
||||
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
uint256 test_commitment = uint256S(commitment_tests[i].get_str());
|
||||
|
||||
// Witness here
|
||||
witnesses.push_back(tree.witness());
|
||||
|
||||
// Now append a commitment to the tree
|
||||
tree.append(test_commitment);
|
||||
|
||||
// Size incremented by one.
|
||||
ASSERT_TRUE(tree.size() == i+1);
|
||||
|
||||
// Last element added to the tree was `test_commitment`
|
||||
ASSERT_TRUE(tree.last() == test_commitment);
|
||||
|
||||
// Check tree root consistency
|
||||
expect_test_vector(root_tests[i], tree.root());
|
||||
|
||||
// Check serialization of tree
|
||||
expect_ser_test_vector(ser_tests[i], tree, tree);
|
||||
|
||||
bool first = true; // The first witness can never form a path
|
||||
BOOST_FOREACH(Witness& wit, witnesses)
|
||||
{
|
||||
// Append the same commitment to all the witnesses
|
||||
wit.append(test_commitment);
|
||||
|
||||
if (first) {
|
||||
ASSERT_THROW(wit.path(), std::runtime_error);
|
||||
ASSERT_THROW(wit.element(), std::runtime_error);
|
||||
} else {
|
||||
auto path = wit.path();
|
||||
|
||||
{
|
||||
expect_test_vector(path_tests[path_i++], path);
|
||||
|
||||
typedef Fr<default_r1cs_ppzksnark_pp> FieldT;
|
||||
|
||||
protoboard<FieldT> pb;
|
||||
pb_variable_array<FieldT> positions;
|
||||
digest_variable<FieldT> commitment(pb, 256, "commitment");
|
||||
digest_variable<FieldT> root(pb, 256, "root");
|
||||
positions.allocate(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "pos");
|
||||
merkle_authentication_path_variable<FieldT, sha256_two_to_one_hash_gadget<FieldT>> authvars(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "auth");
|
||||
merkle_tree_check_read_gadget<FieldT, sha256_two_to_one_hash_gadget<FieldT>> auth(
|
||||
pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, positions, commitment, root, authvars, ONE, "path"
|
||||
);
|
||||
commitment.generate_r1cs_constraints();
|
||||
root.generate_r1cs_constraints();
|
||||
authvars.generate_r1cs_constraints();
|
||||
auth.generate_r1cs_constraints();
|
||||
|
||||
std::vector<bool> commitment_bv;
|
||||
{
|
||||
uint256 witnessed_commitment = wit.element();
|
||||
std::vector<unsigned char> commitment_v(witnessed_commitment.begin(), witnessed_commitment.end());
|
||||
commitment_bv = convertBytesVectorToVector(commitment_v);
|
||||
}
|
||||
|
||||
size_t path_index = convertVectorToInt(path.index);
|
||||
|
||||
commitment.bits.fill_with_bits(pb, bit_vector(commitment_bv));
|
||||
positions.fill_with_bits_of_ulong(pb, path_index);
|
||||
|
||||
authvars.generate_r1cs_witness(path_index, path.authentication_path);
|
||||
auth.generate_r1cs_witness();
|
||||
|
||||
std::vector<bool> root_bv;
|
||||
{
|
||||
uint256 witroot = wit.root();
|
||||
std::vector<unsigned char> root_v(witroot.begin(), witroot.end());
|
||||
root_bv = convertBytesVectorToVector(root_v);
|
||||
}
|
||||
|
||||
root.bits.fill_with_bits(pb, bit_vector(root_bv));
|
||||
|
||||
ASSERT_TRUE(pb.is_satisfied());
|
||||
|
||||
root_bv[0] = !root_bv[0];
|
||||
root.bits.fill_with_bits(pb, bit_vector(root_bv));
|
||||
|
||||
ASSERT_TRUE(!pb.is_satisfied());
|
||||
}
|
||||
}
|
||||
|
||||
// Check witness serialization
|
||||
expect_ser_test_vector(witness_ser_tests[witness_ser_i++], wit, tree);
|
||||
|
||||
ASSERT_TRUE(wit.root() == tree.root());
|
||||
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Tree should be full now
|
||||
ASSERT_THROW(tree.append(uint256()), std::runtime_error);
|
||||
|
||||
BOOST_FOREACH(Witness& wit, witnesses)
|
||||
{
|
||||
ASSERT_THROW(wit.append(uint256()), std::runtime_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define MAKE_STRING(x) std::string((x), (x)+sizeof(x))
|
||||
|
||||
TEST(merkletree, vectors) {
|
||||
UniValue root_tests = read_json(MAKE_STRING(json_tests::merkle_roots));
|
||||
UniValue ser_tests = read_json(MAKE_STRING(json_tests::merkle_serialization));
|
||||
UniValue witness_ser_tests = read_json(MAKE_STRING(json_tests::merkle_witness_serialization));
|
||||
UniValue path_tests = read_json(MAKE_STRING(json_tests::merkle_path));
|
||||
UniValue commitment_tests = read_json(MAKE_STRING(json_tests::merkle_commitments));
|
||||
|
||||
test_tree<ZCTestingIncrementalMerkleTree, ZCTestingIncrementalWitness>(commitment_tests, root_tests, ser_tests, witness_ser_tests, path_tests);
|
||||
}
|
||||
|
||||
TEST(merkletree, emptyroots) {
|
||||
UniValue empty_roots = read_json(MAKE_STRING(json_tests::merkle_roots_empty));
|
||||
|
||||
libzcash::EmptyMerkleRoots<64, libzcash::SHA256Compress> emptyroots;
|
||||
|
||||
for (size_t depth = 0; depth <= 64; depth++) {
|
||||
expect_test_vector(empty_roots[depth], emptyroots.empty_root(depth));
|
||||
}
|
||||
|
||||
// Double check that we're testing (at least) all the empty roots we'll use.
|
||||
ASSERT_TRUE(INCREMENTAL_MERKLE_TREE_DEPTH <= 64);
|
||||
}
|
||||
|
||||
TEST(merkletree, emptyroot) {
|
||||
// This literal is the depth-20 empty tree root with the bytes reversed to
|
||||
// account for the fact that uint256S() loads a big-endian representation of
|
||||
// an integer which converted to little-endian internally.
|
||||
uint256 expected = uint256S("59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7");
|
||||
|
||||
ASSERT_TRUE(ZCIncrementalMerkleTree::empty_root() == expected);
|
||||
}
|
||||
|
||||
TEST(merkletree, deserializeInvalid) {
|
||||
// attempt to deserialize a small tree from a serialized large tree
|
||||
// (exceeds depth well-formedness check)
|
||||
ZCIncrementalMerkleTree newTree;
|
||||
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c"));
|
||||
}
|
||||
|
||||
newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c"));
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << newTree;
|
||||
|
||||
ZCTestingIncrementalMerkleTree newTreeSmall;
|
||||
ASSERT_THROW({ss >> newTreeSmall;}, std::ios_base::failure);
|
||||
}
|
||||
|
||||
TEST(merkletree, deserializeInvalid2) {
|
||||
// the most ancestral parent is empty
|
||||
CDataStream ss(
|
||||
ParseHex("0155b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3000100"),
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION
|
||||
);
|
||||
|
||||
ZCIncrementalMerkleTree tree;
|
||||
ASSERT_THROW(ss >> tree, std::ios_base::failure);
|
||||
}
|
||||
|
||||
TEST(merkletree, deserializeInvalid3) {
|
||||
// left doesn't exist but right does
|
||||
CDataStream ss(
|
||||
ParseHex("000155b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e300"),
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION
|
||||
);
|
||||
|
||||
ZCIncrementalMerkleTree tree;
|
||||
ASSERT_THROW(ss >> tree, std::ios_base::failure);
|
||||
}
|
||||
|
||||
TEST(merkletree, deserializeInvalid4) {
|
||||
// left doesn't exist but a parent does
|
||||
CDataStream ss(
|
||||
ParseHex("000001018695873d63ec0bceeadb5bf4ccc6723ac803c1826fc7cfb34fc76180305ae27d"),
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION
|
||||
);
|
||||
|
||||
ZCIncrementalMerkleTree tree;
|
||||
ASSERT_THROW(ss >> tree, std::ios_base::failure);
|
||||
}
|
||||
|
||||
TEST(merkletree, testZeroElements) {
|
||||
for (int start = 0; start < 20; start++) {
|
||||
ZCIncrementalMerkleTree newTree;
|
||||
|
||||
ASSERT_TRUE(newTree.root() == ZCIncrementalMerkleTree::empty_root());
|
||||
|
||||
for (int i = start; i > 0; i--) {
|
||||
newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c"));
|
||||
}
|
||||
|
||||
uint256 oldroot = newTree.root();
|
||||
|
||||
// At this point, appending tons of null objects to the tree
|
||||
// should preserve its root.
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
newTree.append(uint256());
|
||||
}
|
||||
|
||||
ASSERT_TRUE(newTree.root() == oldroot);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "metrics.h"
|
||||
#include "utiltime.h"
|
||||
|
||||
|
||||
TEST(Metrics, AtomicTimer) {
|
||||
AtomicTimer t;
|
||||
SetMockTime(100);
|
||||
|
||||
EXPECT_FALSE(t.running());
|
||||
|
||||
t.start();
|
||||
EXPECT_TRUE(t.running());
|
||||
|
||||
t.start();
|
||||
EXPECT_TRUE(t.running());
|
||||
|
||||
t.stop();
|
||||
EXPECT_TRUE(t.running());
|
||||
|
||||
t.stop();
|
||||
EXPECT_FALSE(t.running());
|
||||
|
||||
// Additional calls to stop() are ignored.
|
||||
t.stop();
|
||||
EXPECT_FALSE(t.running());
|
||||
|
||||
t.start();
|
||||
EXPECT_TRUE(t.running());
|
||||
|
||||
AtomicCounter c;
|
||||
EXPECT_EQ(0, t.rate(c));
|
||||
|
||||
c.increment();
|
||||
EXPECT_EQ(0, t.rate(c));
|
||||
|
||||
SetMockTime(101);
|
||||
EXPECT_EQ(1, t.rate(c));
|
||||
|
||||
c.decrement();
|
||||
EXPECT_EQ(0, t.rate(c));
|
||||
|
||||
SetMockTime(102);
|
||||
EXPECT_EQ(0, t.rate(c));
|
||||
|
||||
c.increment();
|
||||
EXPECT_EQ(0.5, t.rate(c));
|
||||
|
||||
t.stop();
|
||||
EXPECT_FALSE(t.running());
|
||||
EXPECT_EQ(0.5, t.rate(c));
|
||||
}
|
||||
|
||||
TEST(Metrics, GetLocalSolPS) {
|
||||
SetMockTime(100);
|
||||
miningTimer.start();
|
||||
|
||||
// No time has passed
|
||||
EXPECT_EQ(0, GetLocalSolPS());
|
||||
|
||||
// Increment time
|
||||
SetMockTime(101);
|
||||
EXPECT_EQ(0, GetLocalSolPS());
|
||||
|
||||
// Increment solutions
|
||||
solutionTargetChecks.increment();
|
||||
EXPECT_EQ(1, GetLocalSolPS());
|
||||
|
||||
// Increment time
|
||||
SetMockTime(102);
|
||||
EXPECT_EQ(0.5, GetLocalSolPS());
|
||||
|
||||
// Increment solutions
|
||||
solutionTargetChecks.increment();
|
||||
solutionTargetChecks.increment();
|
||||
EXPECT_EQ(1.5, GetLocalSolPS());
|
||||
|
||||
// Stop timing
|
||||
miningTimer.stop();
|
||||
EXPECT_EQ(1.5, GetLocalSolPS());
|
||||
|
||||
// Increment time
|
||||
SetMockTime(103);
|
||||
EXPECT_EQ(1.5, GetLocalSolPS());
|
||||
|
||||
// Start timing again
|
||||
miningTimer.start();
|
||||
EXPECT_EQ(1.5, GetLocalSolPS());
|
||||
|
||||
// Increment time
|
||||
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));
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "chainparams.h"
|
||||
#include "key.h"
|
||||
#include "miner.h"
|
||||
#include "util.h"
|
||||
#ifdef ENABLE_WALLET
|
||||
#include "wallet/wallet.h"
|
||||
#endif
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
using ::testing::Return;
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
class MockReserveKey : public CReserveKey {
|
||||
public:
|
||||
MockReserveKey() : CReserveKey(nullptr) { }
|
||||
|
||||
MOCK_METHOD1(GetReservedKey, bool(CPubKey &pubkey));
|
||||
};
|
||||
#endif
|
||||
|
||||
TEST(Miner, GetMinerScriptPubKey) {
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
|
||||
boost::optional<CScript> scriptPubKey;
|
||||
#ifdef ENABLE_WALLET
|
||||
MockReserveKey reservekey;
|
||||
EXPECT_CALL(reservekey, GetReservedKey(::testing::_))
|
||||
.WillRepeatedly(Return(false));
|
||||
#endif
|
||||
|
||||
// No miner address set
|
||||
#ifdef ENABLE_WALLET
|
||||
scriptPubKey = GetMinerScriptPubKey(reservekey);
|
||||
#else
|
||||
scriptPubKey = GetMinerScriptPubKey();
|
||||
#endif
|
||||
EXPECT_FALSE((bool) scriptPubKey);
|
||||
|
||||
mapArgs["-mineraddress"] = "notAnAddress";
|
||||
#ifdef ENABLE_WALLET
|
||||
scriptPubKey = GetMinerScriptPubKey(reservekey);
|
||||
#else
|
||||
scriptPubKey = GetMinerScriptPubKey();
|
||||
#endif
|
||||
EXPECT_FALSE((bool) scriptPubKey);
|
||||
|
||||
// Partial address
|
||||
mapArgs["-mineraddress"] = "t1T8yaLVhNqxA5KJcmiqq";
|
||||
#ifdef ENABLE_WALLET
|
||||
scriptPubKey = GetMinerScriptPubKey(reservekey);
|
||||
#else
|
||||
scriptPubKey = GetMinerScriptPubKey();
|
||||
#endif
|
||||
EXPECT_FALSE((bool) scriptPubKey);
|
||||
|
||||
// Typo in address
|
||||
mapArgs["-mineraddress"] = "t1TByaLVhNqxA5KJcmiqqFN88e8DNp2PBfF";
|
||||
#ifdef ENABLE_WALLET
|
||||
scriptPubKey = GetMinerScriptPubKey(reservekey);
|
||||
#else
|
||||
scriptPubKey = GetMinerScriptPubKey();
|
||||
#endif
|
||||
EXPECT_FALSE((bool) scriptPubKey);
|
||||
|
||||
// Set up expected scriptPubKey for t1T8yaLVhNqxA5KJcmiqqFN88e8DNp2PBfF
|
||||
CKeyID keyID;
|
||||
keyID.SetHex("eb88f1c65b39a823479ac9c7db2f4a865960a165");
|
||||
CScript expectedScriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
|
||||
// Valid address
|
||||
mapArgs["-mineraddress"] = "t1T8yaLVhNqxA5KJcmiqqFN88e8DNp2PBfF";
|
||||
#ifdef ENABLE_WALLET
|
||||
scriptPubKey = GetMinerScriptPubKey(reservekey);
|
||||
#else
|
||||
scriptPubKey = GetMinerScriptPubKey();
|
||||
#endif
|
||||
EXPECT_TRUE((bool) scriptPubKey);
|
||||
EXPECT_EQ(expectedScriptPubKey, *scriptPubKey);
|
||||
|
||||
// Valid address with leading whitespace
|
||||
mapArgs["-mineraddress"] = " t1T8yaLVhNqxA5KJcmiqqFN88e8DNp2PBfF";
|
||||
#ifdef ENABLE_WALLET
|
||||
scriptPubKey = GetMinerScriptPubKey(reservekey);
|
||||
#else
|
||||
scriptPubKey = GetMinerScriptPubKey();
|
||||
#endif
|
||||
EXPECT_TRUE((bool) scriptPubKey);
|
||||
EXPECT_EQ(expectedScriptPubKey, *scriptPubKey);
|
||||
|
||||
// Valid address with trailing whitespace
|
||||
mapArgs["-mineraddress"] = "t1T8yaLVhNqxA5KJcmiqqFN88e8DNp2PBfF ";
|
||||
#ifdef ENABLE_WALLET
|
||||
scriptPubKey = GetMinerScriptPubKey(reservekey);
|
||||
#else
|
||||
scriptPubKey = GetMinerScriptPubKey();
|
||||
#endif
|
||||
EXPECT_TRUE((bool) scriptPubKey);
|
||||
EXPECT_EQ(expectedScriptPubKey, *scriptPubKey);
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "sodium.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "zcash/NoteEncryption.hpp"
|
||||
#include "zcash/prf.h"
|
||||
#include "crypto/sha256.h"
|
||||
|
||||
class TestNoteDecryption : public ZCNoteDecryption {
|
||||
public:
|
||||
TestNoteDecryption(uint256 sk_enc) : ZCNoteDecryption(sk_enc) {}
|
||||
|
||||
void change_pk_enc(uint256 to) {
|
||||
pk_enc = to;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(noteencryption, api)
|
||||
{
|
||||
uint256 sk_enc = ZCNoteEncryption::generate_privkey(uint252(uint256S("21035d60bc1983e37950ce4803418a8fb33ea68d5b937ca382ecbae7564d6a07")));
|
||||
uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc);
|
||||
|
||||
ZCNoteEncryption b = ZCNoteEncryption(uint256());
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
{
|
||||
ZCNoteEncryption c = ZCNoteEncryption(uint256());
|
||||
|
||||
ASSERT_TRUE(b.get_epk() != c.get_epk());
|
||||
}
|
||||
|
||||
boost::array<unsigned char, ZC_NOTEPLAINTEXT_SIZE> message;
|
||||
for (size_t i = 0; i < ZC_NOTEPLAINTEXT_SIZE; i++) {
|
||||
// Fill the message with dummy data
|
||||
message[i] = (unsigned char) i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 255; i++) {
|
||||
auto ciphertext = b.encrypt(pk_enc, message);
|
||||
|
||||
{
|
||||
ZCNoteDecryption decrypter(sk_enc);
|
||||
|
||||
// Test decryption
|
||||
auto plaintext = decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i);
|
||||
ASSERT_TRUE(plaintext == message);
|
||||
|
||||
// Test wrong nonce
|
||||
ASSERT_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256(), (i == 0) ? 1 : (i - 1)),
|
||||
libzcash::note_decryption_failed);
|
||||
|
||||
// Test wrong ephemeral key
|
||||
{
|
||||
ZCNoteEncryption c = ZCNoteEncryption(uint256());
|
||||
|
||||
ASSERT_THROW(decrypter.decrypt(ciphertext, c.get_epk(), uint256(), i),
|
||||
libzcash::note_decryption_failed);
|
||||
}
|
||||
|
||||
// Test wrong seed
|
||||
ASSERT_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256S("11035d60bc1983e37950ce4803418a8fb33ea68d5b937ca382ecbae7564d6a77"), i),
|
||||
libzcash::note_decryption_failed);
|
||||
|
||||
// Test corrupted ciphertext
|
||||
ciphertext[10] ^= 0xff;
|
||||
ASSERT_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i),
|
||||
libzcash::note_decryption_failed);
|
||||
ciphertext[10] ^= 0xff;
|
||||
}
|
||||
|
||||
{
|
||||
// Test wrong private key
|
||||
uint256 sk_enc_2 = ZCNoteEncryption::generate_privkey(uint252());
|
||||
ZCNoteDecryption decrypter(sk_enc_2);
|
||||
|
||||
ASSERT_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i),
|
||||
libzcash::note_decryption_failed);
|
||||
}
|
||||
|
||||
{
|
||||
TestNoteDecryption decrypter(sk_enc);
|
||||
|
||||
// Test decryption
|
||||
auto plaintext = decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i);
|
||||
ASSERT_TRUE(plaintext == message);
|
||||
|
||||
// Test wrong public key (test of KDF)
|
||||
decrypter.change_pk_enc(uint256());
|
||||
ASSERT_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i),
|
||||
libzcash::note_decryption_failed);
|
||||
}
|
||||
}
|
||||
|
||||
// Nonce space should run out here
|
||||
try {
|
||||
b.encrypt(pk_enc, message);
|
||||
FAIL() << "Expected std::logic_error";
|
||||
}
|
||||
catch(std::logic_error const & err) {
|
||||
EXPECT_EQ(err.what(), std::string("no additional nonce space for KDF"));
|
||||
}
|
||||
catch(...) {
|
||||
FAIL() << "Expected std::logic_error";
|
||||
}
|
||||
}
|
||||
|
||||
uint256 test_prf(
|
||||
unsigned char distinguisher,
|
||||
uint252 seed_x,
|
||||
uint256 y
|
||||
) {
|
||||
uint256 x = seed_x.inner();
|
||||
*x.begin() &= 0x0f;
|
||||
*x.begin() |= distinguisher;
|
||||
CSHA256 hasher;
|
||||
hasher.Write(x.begin(), 32);
|
||||
hasher.Write(y.begin(), 32);
|
||||
|
||||
uint256 ret;
|
||||
hasher.FinalizeNoPadding(ret.begin());
|
||||
return ret;
|
||||
}
|
||||
|
||||
TEST(noteencryption, prf_addr)
|
||||
{
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
uint252 a_sk = libzcash::random_uint252();
|
||||
uint256 rest;
|
||||
ASSERT_TRUE(
|
||||
test_prf(0xc0, a_sk, rest) == PRF_addr_a_pk(a_sk)
|
||||
);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
uint252 a_sk = libzcash::random_uint252();
|
||||
uint256 rest;
|
||||
*rest.begin() = 0x01;
|
||||
ASSERT_TRUE(
|
||||
test_prf(0xc0, a_sk, rest) == PRF_addr_sk_enc(a_sk)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(noteencryption, prf_nf)
|
||||
{
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
uint252 a_sk = libzcash::random_uint252();
|
||||
uint256 rho = libzcash::random_uint256();
|
||||
ASSERT_TRUE(
|
||||
test_prf(0xe0, a_sk, rho) == PRF_nf(a_sk, rho)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(noteencryption, prf_pk)
|
||||
{
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
uint252 a_sk = libzcash::random_uint252();
|
||||
uint256 h_sig = libzcash::random_uint256();
|
||||
ASSERT_TRUE(
|
||||
test_prf(0x00, a_sk, h_sig) == PRF_pk(a_sk, 0, h_sig)
|
||||
);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
uint252 a_sk = libzcash::random_uint252();
|
||||
uint256 h_sig = libzcash::random_uint256();
|
||||
ASSERT_TRUE(
|
||||
test_prf(0x40, a_sk, h_sig) == PRF_pk(a_sk, 1, h_sig)
|
||||
);
|
||||
}
|
||||
|
||||
uint252 dummy_a;
|
||||
uint256 dummy_b;
|
||||
ASSERT_THROW(PRF_pk(dummy_a, 2, dummy_b), std::domain_error);
|
||||
}
|
||||
|
||||
TEST(noteencryption, prf_rho)
|
||||
{
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
uint252 phi = libzcash::random_uint252();
|
||||
uint256 h_sig = libzcash::random_uint256();
|
||||
ASSERT_TRUE(
|
||||
test_prf(0x20, phi, h_sig) == PRF_rho(phi, 0, h_sig)
|
||||
);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
uint252 phi = libzcash::random_uint252();
|
||||
uint256 h_sig = libzcash::random_uint256();
|
||||
ASSERT_TRUE(
|
||||
test_prf(0x60, phi, h_sig) == PRF_rho(phi, 1, h_sig)
|
||||
);
|
||||
}
|
||||
|
||||
uint252 dummy_a;
|
||||
uint256 dummy_b;
|
||||
ASSERT_THROW(PRF_rho(dummy_a, 2, dummy_b), std::domain_error);
|
||||
}
|
||||
|
||||
TEST(noteencryption, uint252)
|
||||
{
|
||||
ASSERT_THROW(uint252(uint256S("f6da8716682d600f74fc16bd0187faad6a26b4aa4c24d5c055b216d94516847e")), std::domain_error);
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "chain.h"
|
||||
#include "chainparams.h"
|
||||
#include "pow.h"
|
||||
#include "random.h"
|
||||
|
||||
TEST(PoW, DifficultyAveraging) {
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
const Consensus::Params& params = Params().GetConsensus();
|
||||
size_t lastBlk = 2*params.nPowAveragingWindow;
|
||||
size_t firstBlk = lastBlk - params.nPowAveragingWindow;
|
||||
|
||||
// Start with blocks evenly-spaced and equal difficulty
|
||||
std::vector<CBlockIndex> blocks(lastBlk+1);
|
||||
for (int i = 0; i <= lastBlk; i++) {
|
||||
blocks[i].pprev = i ? &blocks[i - 1] : nullptr;
|
||||
blocks[i].nHeight = i;
|
||||
blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing;
|
||||
blocks[i].nBits = 0x1e7fffff; /* target 0x007fffff000... */
|
||||
blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0);
|
||||
}
|
||||
|
||||
// Result should be the same as if last difficulty was used
|
||||
arith_uint256 bnAvg;
|
||||
bnAvg.SetCompact(blocks[lastBlk].nBits);
|
||||
EXPECT_EQ(CalculateNextWorkRequired(bnAvg,
|
||||
blocks[lastBlk].GetMedianTimePast(),
|
||||
blocks[firstBlk].GetMedianTimePast(),
|
||||
params),
|
||||
GetNextWorkRequired(&blocks[lastBlk], nullptr, params));
|
||||
// Result should be unchanged, modulo integer division precision loss
|
||||
arith_uint256 bnRes;
|
||||
bnRes.SetCompact(0x1e7fffff);
|
||||
bnRes /= params.AveragingWindowTimespan();
|
||||
bnRes *= params.AveragingWindowTimespan();
|
||||
EXPECT_EQ(bnRes.GetCompact(), GetNextWorkRequired(&blocks[lastBlk], nullptr, params));
|
||||
|
||||
// Randomise the final block time (plus 1 to ensure it is always different)
|
||||
blocks[lastBlk].nTime += GetRand(params.nPowTargetSpacing/2) + 1;
|
||||
|
||||
// Result should be the same as if last difficulty was used
|
||||
bnAvg.SetCompact(blocks[lastBlk].nBits);
|
||||
EXPECT_EQ(CalculateNextWorkRequired(bnAvg,
|
||||
blocks[lastBlk].GetMedianTimePast(),
|
||||
blocks[firstBlk].GetMedianTimePast(),
|
||||
params),
|
||||
GetNextWorkRequired(&blocks[lastBlk], nullptr, params));
|
||||
// Result should not be unchanged
|
||||
EXPECT_NE(0x1e7fffff, GetNextWorkRequired(&blocks[lastBlk], nullptr, params));
|
||||
|
||||
// Change the final block difficulty
|
||||
blocks[lastBlk].nBits = 0x1e0fffff;
|
||||
|
||||
// Result should not be the same as if last difficulty was used
|
||||
bnAvg.SetCompact(blocks[lastBlk].nBits);
|
||||
EXPECT_NE(CalculateNextWorkRequired(bnAvg,
|
||||
blocks[lastBlk].GetMedianTimePast(),
|
||||
blocks[firstBlk].GetMedianTimePast(),
|
||||
params),
|
||||
GetNextWorkRequired(&blocks[lastBlk], nullptr, params));
|
||||
|
||||
// Result should be the same as if the average difficulty was used
|
||||
arith_uint256 average = UintToArith256(uint256S("0000796968696969696969696969696969696969696969696969696969696969"));
|
||||
EXPECT_EQ(CalculateNextWorkRequired(average,
|
||||
blocks[lastBlk].GetMedianTimePast(),
|
||||
blocks[firstBlk].GetMedianTimePast(),
|
||||
params),
|
||||
GetNextWorkRequired(&blocks[lastBlk], nullptr, params));
|
||||
}
|
|
@ -0,0 +1,702 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "zcash/Proof.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#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;
|
||||
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp curve_pp;
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp::G1_type curve_G1;
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp::G2_type curve_G2;
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp::GT_type curve_GT;
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp::Fp_type curve_Fr;
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp::Fq_type curve_Fq;
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp::Fqe_type curve_Fq2;
|
||||
|
||||
#include "streams.h"
|
||||
#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
|
||||
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * curve_G2::random_element() == curve_G2::zero());
|
||||
|
||||
// but that doesn't mean all elements that satisfy the curve equation are in G2...
|
||||
curve_G2 p = curve_G2::one();
|
||||
|
||||
while (1) {
|
||||
// This will construct an order r(2q-r) point with high probability
|
||||
p.X = curve_Fq2::random_element();
|
||||
try {
|
||||
p.Y = ((p.X.squared() * p.X) + libsnark::alt_bn128_twist_coeff_b).sqrt();
|
||||
break;
|
||||
} catch(...) {}
|
||||
}
|
||||
|
||||
ASSERT_TRUE(p.is_well_formed()); // it's on the curve
|
||||
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * p != curve_G2::zero()); // but not the order r subgroup..
|
||||
|
||||
{
|
||||
// libsnark unfortunately doesn't check, and the pairing will complete
|
||||
auto e = curve_Fr("149");
|
||||
auto a = curve_pp::reduced_pairing(curve_G1::one(), p);
|
||||
auto b = curve_pp::reduced_pairing(e * curve_G1::one(), p);
|
||||
|
||||
// though it will not preserve bilinearity
|
||||
ASSERT_TRUE((a^e) != b);
|
||||
}
|
||||
|
||||
{
|
||||
// so, our decompression API should not allow you to decompress G2 elements of that form!
|
||||
CompressedG2 badp(p);
|
||||
try {
|
||||
auto newp = badp.to_libsnark_g2<curve_G2>();
|
||||
FAIL() << "Expected std::runtime_error";
|
||||
} catch (std::runtime_error const & err) {
|
||||
EXPECT_EQ(err.what(), std::string("point is not in G2"));
|
||||
} catch(...) {
|
||||
FAIL() << "Expected std::runtime_error";
|
||||
}
|
||||
}
|
||||
|
||||
// educational purposes: showing that E'(Fp2) is of order r(2q-r),
|
||||
// by multiplying our random point in E' by (2q-r) = (q + q - r) to
|
||||
// get an element in G2
|
||||
{
|
||||
auto p1 = libsnark::alt_bn128_modulus_q * p;
|
||||
p1 = p1 + p1;
|
||||
p1 = p1 - (libsnark::alt_bn128_modulus_r * p);
|
||||
|
||||
ASSERT_TRUE(p1.is_well_formed());
|
||||
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * p1 == curve_G2::zero());
|
||||
|
||||
CompressedG2 goodp(p1);
|
||||
auto newp = goodp.to_libsnark_g2<curve_G2>();
|
||||
|
||||
ASSERT_TRUE(newp == p1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, sqrt_zero)
|
||||
{
|
||||
ASSERT_TRUE(curve_Fq::zero() == curve_Fq::zero().sqrt());
|
||||
ASSERT_TRUE(curve_Fq2::zero() == curve_Fq2::zero().sqrt());
|
||||
}
|
||||
|
||||
TEST(proofs, sqrt_fq)
|
||||
{
|
||||
// Poor man's PRNG
|
||||
curve_Fq acc = curve_Fq("348957923485290374852379485") ^ 1000;
|
||||
|
||||
size_t quadratic_residues = 0;
|
||||
size_t quadratic_nonresidues = 0;
|
||||
|
||||
for (size_t i = 1; i < 1000; i++) {
|
||||
try {
|
||||
acc += curve_Fq("45634563456") ^ i;
|
||||
|
||||
curve_Fq x = acc.sqrt();
|
||||
ASSERT_TRUE((x*x) == acc);
|
||||
quadratic_residues += 1;
|
||||
} catch (std::runtime_error &e) {
|
||||
quadratic_nonresidues += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Half of all nonzero elements in Fp are quadratic residues
|
||||
ASSERT_TRUE(quadratic_residues == 511);
|
||||
ASSERT_TRUE(quadratic_nonresidues == 488);
|
||||
|
||||
for (size_t i = 0; i < 1000; i++) {
|
||||
curve_Fq x = curve_Fq::random_element();
|
||||
curve_Fq x2 = x * x;
|
||||
|
||||
ASSERT_TRUE((x2.sqrt() == x) || (x2.sqrt() == -x));
|
||||
}
|
||||
|
||||
// Test vectors
|
||||
ASSERT_TRUE(
|
||||
curve_Fq("5204065062716160319596273903996315000119019512886596366359652578430118331601")
|
||||
==
|
||||
curve_Fq("348579348568").sqrt()
|
||||
);
|
||||
ASSERT_THROW(curve_Fq("348579348569").sqrt(), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST(proofs, sqrt_fq2)
|
||||
{
|
||||
curve_Fq2 acc = curve_Fq2(
|
||||
curve_Fq("3456293840592348059238409578239048769348760238476029347885092384059238459834") ^ 1000,
|
||||
curve_Fq("2394578084760439457823945729347502374590283479582739485723945729384759823745") ^ 1000
|
||||
);
|
||||
|
||||
size_t quadratic_residues = 0;
|
||||
size_t quadratic_nonresidues = 0;
|
||||
|
||||
for (size_t i = 1; i < 1000; i++) {
|
||||
try {
|
||||
acc = acc + curve_Fq2(
|
||||
curve_Fq("5204065062716160319596273903996315000119019512886596366359652578430118331601") ^ i,
|
||||
curve_Fq("348957923485290374852379485348957923485290374852379485348957923485290374852") ^ i
|
||||
);
|
||||
|
||||
curve_Fq2 x = acc.sqrt();
|
||||
ASSERT_TRUE((x*x) == acc);
|
||||
quadratic_residues += 1;
|
||||
} catch (std::runtime_error &e) {
|
||||
quadratic_nonresidues += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Half of all nonzero elements in Fp^k are quadratic residues as long
|
||||
// as p != 2
|
||||
ASSERT_TRUE(quadratic_residues == 505);
|
||||
ASSERT_TRUE(quadratic_nonresidues == 494);
|
||||
|
||||
for (size_t i = 0; i < 1000; i++) {
|
||||
curve_Fq2 x = curve_Fq2::random_element();
|
||||
curve_Fq2 x2 = x * x;
|
||||
|
||||
ASSERT_TRUE((x2.sqrt() == x) || (x2.sqrt() == -x));
|
||||
}
|
||||
|
||||
// Test vectors
|
||||
ASSERT_THROW(curve_Fq2(
|
||||
curve_Fq("2"),
|
||||
curve_Fq("1")
|
||||
).sqrt(), std::runtime_error);
|
||||
|
||||
ASSERT_THROW(curve_Fq2(
|
||||
curve_Fq("3345897230485723946872934576923485762803457692345760237495682347502347589473"),
|
||||
curve_Fq("1234912378405347958234756902345768290345762348957605678245967234857634857676")
|
||||
).sqrt(), std::runtime_error);
|
||||
|
||||
curve_Fq2 x = curve_Fq2(
|
||||
curve_Fq("12844195307879678418043983815760255909500142247603239203345049921980497041944"),
|
||||
curve_Fq("7476417578426924565731404322659619974551724117137577781074613937423560117731")
|
||||
);
|
||||
|
||||
curve_Fq2 nx = -x;
|
||||
|
||||
curve_Fq2 x2 = curve_Fq2(
|
||||
curve_Fq("3345897230485723946872934576923485762803457692345760237495682347502347589474"),
|
||||
curve_Fq("1234912378405347958234756902345768290345762348957605678245967234857634857676")
|
||||
);
|
||||
|
||||
ASSERT_TRUE(x == x2.sqrt());
|
||||
ASSERT_TRUE(nx == -x2.sqrt());
|
||||
ASSERT_TRUE(x*x == x2);
|
||||
ASSERT_TRUE(nx*nx == x2);
|
||||
}
|
||||
|
||||
TEST(proofs, size_is_expected)
|
||||
{
|
||||
ZCProof p;
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << p;
|
||||
|
||||
ASSERT_EQ(ss.size(), 296);
|
||||
}
|
||||
|
||||
TEST(proofs, fq_serializes_properly)
|
||||
{
|
||||
for (size_t i = 0; i < 1000; i++) {
|
||||
curve_Fq e = curve_Fq::random_element();
|
||||
|
||||
Fq e2(e);
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << e2;
|
||||
|
||||
Fq e3;
|
||||
ss >> e3;
|
||||
|
||||
curve_Fq e4 = e3.to_libsnark_fq<curve_Fq>();
|
||||
|
||||
ASSERT_TRUE(e == e4);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, fq2_serializes_properly)
|
||||
{
|
||||
for (size_t i = 0; i < 1000; i++) {
|
||||
curve_Fq2 e = curve_Fq2::random_element();
|
||||
|
||||
Fq2 e2(e);
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << e2;
|
||||
|
||||
Fq2 e3;
|
||||
ss >> e3;
|
||||
|
||||
curve_Fq2 e4 = e3.to_libsnark_fq2<curve_Fq2>();
|
||||
|
||||
ASSERT_TRUE(e == e4);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T deserialize_tv(std::string s)
|
||||
{
|
||||
T e;
|
||||
CDataStream ss(ParseHex(s), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> e;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
curve_Fq deserialize_fq(std::string s)
|
||||
{
|
||||
return deserialize_tv<Fq>(s).to_libsnark_fq<curve_Fq>();
|
||||
}
|
||||
|
||||
curve_Fq2 deserialize_fq2(std::string s)
|
||||
{
|
||||
return deserialize_tv<Fq2>(s).to_libsnark_fq2<curve_Fq2>();
|
||||
}
|
||||
|
||||
TEST(proofs, fq_valid)
|
||||
{
|
||||
curve_Fq e = deserialize_fq("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46");
|
||||
|
||||
ASSERT_TRUE(e == curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"));
|
||||
ASSERT_TRUE(e != curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208581"));
|
||||
|
||||
curve_Fq e2 = deserialize_fq("30644e72e131a029b75045b68181585d97816a916871ca8d3c208c16d87cfd46");
|
||||
|
||||
ASSERT_TRUE(e2 == curve_Fq("21888242871839275222221885816603420866962577604863418715751138068690288573766"));
|
||||
}
|
||||
|
||||
TEST(proofs, fq_invalid)
|
||||
{
|
||||
// Should not be able to deserialize the modulus
|
||||
ASSERT_THROW(
|
||||
deserialize_fq("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"),
|
||||
std::logic_error
|
||||
);
|
||||
|
||||
// Should not be able to deserialize the modulus plus one
|
||||
ASSERT_THROW(
|
||||
deserialize_fq("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd48"),
|
||||
std::logic_error
|
||||
);
|
||||
|
||||
// Should not be able to deserialize a ridiculously out of bound int
|
||||
ASSERT_THROW(
|
||||
deserialize_fq("ff644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46"),
|
||||
std::logic_error
|
||||
);
|
||||
}
|
||||
|
||||
TEST(proofs, fq2_valid)
|
||||
{
|
||||
// (q - 1) * q + q
|
||||
curve_Fq2 e = deserialize_fq2("0925c4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b0");
|
||||
ASSERT_TRUE(e.c0 == curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"));
|
||||
ASSERT_TRUE(e.c1 == curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"));
|
||||
|
||||
curve_Fq2 e2 = deserialize_fq2("000000000000000000000000000000000000000000000000010245be1c91e3186bbbe1c430a93fcfc5aada4ab10c3492f70eea97a91c7b29554db55acffa34d2");
|
||||
ASSERT_TRUE(e2.c0 == curve_Fq("238769481237490823"));
|
||||
ASSERT_TRUE(e2.c1 == curve_Fq("384579238459723485"));
|
||||
|
||||
curve_Fq2 e3 = deserialize_fq2("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
|
||||
ASSERT_TRUE(e3.c0 == curve_Fq("0"));
|
||||
ASSERT_TRUE(e3.c1 == curve_Fq("0"));
|
||||
|
||||
curve_Fq2 e4 = deserialize_fq2("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001");
|
||||
ASSERT_TRUE(e4.c0 == curve_Fq("1"));
|
||||
ASSERT_TRUE(e4.c1 == curve_Fq("0"));
|
||||
}
|
||||
|
||||
TEST(proofs, fq2_invalid)
|
||||
{
|
||||
// (q - 1) * q + q is invalid
|
||||
ASSERT_THROW(
|
||||
deserialize_fq2("0925c4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b1"),
|
||||
std::logic_error
|
||||
);
|
||||
|
||||
// q * q + (q - 1) is invalid
|
||||
ASSERT_THROW(
|
||||
deserialize_fq2("0925c4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d34cced085b43e2f202a05e52ef18233a3d8371be725c8b8e7774e4b8ffda66f7"),
|
||||
std::logic_error
|
||||
);
|
||||
|
||||
// Ridiculously out of bounds
|
||||
ASSERT_THROW(
|
||||
deserialize_fq2("0fffc4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b0"),
|
||||
std::logic_error
|
||||
);
|
||||
ASSERT_THROW(
|
||||
deserialize_fq2("ffffffff763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b0"),
|
||||
std::logic_error
|
||||
);
|
||||
}
|
||||
|
||||
TEST(proofs, g1_serializes_properly)
|
||||
{
|
||||
// Cannot serialize zero
|
||||
{
|
||||
ASSERT_THROW({CompressedG1 g = CompressedG1(curve_G1::zero());}, std::domain_error);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 1000; i++) {
|
||||
curve_G1 e = curve_G1::random_element();
|
||||
|
||||
CompressedG1 e2(e);
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << e2;
|
||||
|
||||
CompressedG1 e3;
|
||||
ss >> e3;
|
||||
|
||||
ASSERT_TRUE(e2 == e3);
|
||||
|
||||
curve_G1 e4 = e3.to_libsnark_g1<curve_G1>();
|
||||
|
||||
ASSERT_TRUE(e == e4);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, g2_serializes_properly)
|
||||
{
|
||||
// Cannot serialize zero
|
||||
{
|
||||
ASSERT_THROW({CompressedG2 g = CompressedG2(curve_G2::zero());}, std::domain_error);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 1000; i++) {
|
||||
curve_G2 e = curve_G2::random_element();
|
||||
|
||||
CompressedG2 e2(e);
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << e2;
|
||||
|
||||
CompressedG2 e3;
|
||||
ss >> e3;
|
||||
|
||||
ASSERT_TRUE(e2 == e3);
|
||||
|
||||
curve_G2 e4 = e3.to_libsnark_g2<curve_G2>();
|
||||
|
||||
ASSERT_TRUE(e == e4);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, zksnark_serializes_properly)
|
||||
{
|
||||
auto example = libsnark::generate_r1cs_example_with_field_input<curve_Fr>(250, 4);
|
||||
example.constraint_system.swap_AB_if_beneficial();
|
||||
auto kp = libsnark::r1cs_ppzksnark_generator<curve_pp>(example.constraint_system);
|
||||
auto vkprecomp = libsnark::r1cs_ppzksnark_verifier_process_vk(kp.vk);
|
||||
|
||||
for (size_t i = 0; i < 20; i++) {
|
||||
auto badproof = ZCProof::random_invalid();
|
||||
auto proof = badproof.to_libsnark_proof<libsnark::r1cs_ppzksnark_proof<curve_pp>>();
|
||||
|
||||
auto verifierEnabled = ProofVerifier::Strict();
|
||||
auto verifierDisabled = ProofVerifier::Disabled();
|
||||
// This verifier should catch the bad proof
|
||||
ASSERT_FALSE(verifierEnabled.check(
|
||||
kp.vk,
|
||||
vkprecomp,
|
||||
example.primary_input,
|
||||
proof
|
||||
));
|
||||
// This verifier won't!
|
||||
ASSERT_TRUE(verifierDisabled.check(
|
||||
kp.vk,
|
||||
vkprecomp,
|
||||
example.primary_input,
|
||||
proof
|
||||
));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 20; i++) {
|
||||
auto proof = libsnark::r1cs_ppzksnark_prover<curve_pp>(
|
||||
kp.pk,
|
||||
example.primary_input,
|
||||
example.auxiliary_input,
|
||||
example.constraint_system
|
||||
);
|
||||
|
||||
{
|
||||
auto verifierEnabled = ProofVerifier::Strict();
|
||||
auto verifierDisabled = ProofVerifier::Disabled();
|
||||
ASSERT_TRUE(verifierEnabled.check(
|
||||
kp.vk,
|
||||
vkprecomp,
|
||||
example.primary_input,
|
||||
proof
|
||||
));
|
||||
ASSERT_TRUE(verifierDisabled.check(
|
||||
kp.vk,
|
||||
vkprecomp,
|
||||
example.primary_input,
|
||||
proof
|
||||
));
|
||||
}
|
||||
|
||||
ASSERT_TRUE(libsnark::r1cs_ppzksnark_verifier_strong_IC<curve_pp>(
|
||||
kp.vk,
|
||||
example.primary_input,
|
||||
proof
|
||||
));
|
||||
|
||||
ZCProof compressed_proof_0(proof);
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << compressed_proof_0;
|
||||
|
||||
ZCProof compressed_proof_1;
|
||||
ss >> compressed_proof_1;
|
||||
|
||||
ASSERT_TRUE(compressed_proof_0 == compressed_proof_1);
|
||||
|
||||
auto newproof = compressed_proof_1.to_libsnark_proof<libsnark::r1cs_ppzksnark_proof<curve_pp>>();
|
||||
|
||||
ASSERT_TRUE(proof == newproof);
|
||||
ASSERT_TRUE(libsnark::r1cs_ppzksnark_verifier_strong_IC<curve_pp>(
|
||||
kp.vk,
|
||||
example.primary_input,
|
||||
newproof
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, g1_deserialization)
|
||||
{
|
||||
CompressedG1 g;
|
||||
curve_G1 expected;
|
||||
|
||||
// Valid G1 element.
|
||||
{
|
||||
CDataStream ss(ParseHex("0230644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
expected.X = curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582");
|
||||
expected.Y = curve_Fq("3969792565221544645472939191694882283483352126195956956354061729942568608776");
|
||||
expected.Z = curve_Fq::one();
|
||||
|
||||
ASSERT_TRUE(g.to_libsnark_g1<curve_G1>() == expected);
|
||||
}
|
||||
|
||||
// Its negation.
|
||||
{
|
||||
CDataStream ss(ParseHex("0330644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
expected.X = curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582");
|
||||
expected.Y = curve_Fq("3969792565221544645472939191694882283483352126195956956354061729942568608776");
|
||||
expected.Z = curve_Fq::one();
|
||||
|
||||
ASSERT_TRUE(g.to_libsnark_g1<curve_G1>() == -expected);
|
||||
}
|
||||
|
||||
// Invalid leading bytes
|
||||
{
|
||||
CDataStream ss(ParseHex("ff30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
ASSERT_THROW(ss >> g, std::ios_base::failure);
|
||||
}
|
||||
|
||||
// Invalid point
|
||||
{
|
||||
CDataStream ss(ParseHex("0208c6d2adffacbc8438f09f321874ea66e2fcc29f8dcfec2caefa21ec8c96a77c"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
ASSERT_THROW(g.to_libsnark_g1<curve_G1>(), std::runtime_error);
|
||||
}
|
||||
|
||||
// Point with out of bounds Fq
|
||||
{
|
||||
CDataStream ss(ParseHex("02ffc6d2adffacbc8438f09f321874ea66e2fcc29f8dcfec2caefa21ec8c96a77c"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
ASSERT_THROW(g.to_libsnark_g1<curve_G1>(), std::logic_error);
|
||||
}
|
||||
|
||||
// Randomly produce valid G1 representations and fail/succeed to
|
||||
// turn them into G1 points based on whether they are valid.
|
||||
for (size_t i = 0; i < 5000; i++) {
|
||||
curve_Fq e = curve_Fq::random_element();
|
||||
CDataStream ss(ParseHex("02"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << Fq(e);
|
||||
CompressedG1 g;
|
||||
ss >> g;
|
||||
|
||||
try {
|
||||
curve_G1 g_real = g.to_libsnark_g1<curve_G1>();
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, g2_deserialization)
|
||||
{
|
||||
CompressedG2 g;
|
||||
curve_G2 expected = curve_G2::random_element();
|
||||
|
||||
// Valid G2 point
|
||||
{
|
||||
CDataStream ss(ParseHex("0a023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
expected.X = curve_Fq2(
|
||||
curve_Fq("5923585509243758863255447226263146374209884951848029582715967108651637186684"),
|
||||
curve_Fq("5336385337059958111259504403491065820971993066694750945459110579338490853570")
|
||||
);
|
||||
expected.Y = curve_Fq2(
|
||||
curve_Fq("10374495865873200088116930399159835104695426846400310764827677226300185211748"),
|
||||
curve_Fq("5256529835065685814318509161957442385362539991735248614869838648137856366932")
|
||||
);
|
||||
expected.Z = curve_Fq2::one();
|
||||
|
||||
ASSERT_TRUE(g.to_libsnark_g2<curve_G2>() == expected);
|
||||
}
|
||||
|
||||
// Its negation
|
||||
{
|
||||
CDataStream ss(ParseHex("0b023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
expected.X = curve_Fq2(
|
||||
curve_Fq("5923585509243758863255447226263146374209884951848029582715967108651637186684"),
|
||||
curve_Fq("5336385337059958111259504403491065820971993066694750945459110579338490853570")
|
||||
);
|
||||
expected.Y = curve_Fq2(
|
||||
curve_Fq("10374495865873200088116930399159835104695426846400310764827677226300185211748"),
|
||||
curve_Fq("5256529835065685814318509161957442385362539991735248614869838648137856366932")
|
||||
);
|
||||
expected.Z = curve_Fq2::one();
|
||||
|
||||
ASSERT_TRUE(g.to_libsnark_g2<curve_G2>() == -expected);
|
||||
}
|
||||
|
||||
// Invalid leading bytes
|
||||
{
|
||||
CDataStream ss(ParseHex("ff023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
ASSERT_THROW(ss >> g, std::ios_base::failure);
|
||||
}
|
||||
|
||||
|
||||
// Invalid point
|
||||
{
|
||||
CDataStream ss(ParseHex("0b023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984b"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
ASSERT_THROW(g.to_libsnark_g2<curve_G2>(), std::runtime_error);
|
||||
}
|
||||
|
||||
// Point with out of bounds Fq2
|
||||
{
|
||||
CDataStream ss(ParseHex("0a0f3aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
ASSERT_THROW(g.to_libsnark_g2<curve_G2>(), std::logic_error);
|
||||
}
|
||||
|
||||
// Randomly produce valid G2 representations and fail/succeed to
|
||||
// turn them into G2 points based on whether they are valid.
|
||||
for (size_t i = 0; i < 5000; i++) {
|
||||
curve_Fq2 e = curve_Fq2::random_element();
|
||||
CDataStream ss(ParseHex("0a"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << Fq2(e);
|
||||
CompressedG2 g;
|
||||
ss >> g;
|
||||
|
||||
try {
|
||||
curve_G2 g_real = g.to_libsnark_g2<curve_G2>();
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "json_test_vectors.h"
|
||||
#include "test/data/g1_compressed.json.h"
|
||||
|
||||
TEST(proofs, g1_test_vectors)
|
||||
{
|
||||
UniValue v = read_json(std::string(json_tests::g1_compressed, json_tests::g1_compressed + sizeof(json_tests::g1_compressed)));
|
||||
|
||||
curve_G1 e = curve_Fr("34958239045823") * curve_G1::one();
|
||||
for (size_t i = 0; i < 10000; i++) {
|
||||
e = (curve_Fr("34958239045823") ^ i) * e;
|
||||
auto expected = CompressedG1(e);
|
||||
|
||||
expect_test_vector(v[i], expected);
|
||||
ASSERT_TRUE(expected.to_libsnark_g1<curve_G1>() == e);
|
||||
}
|
||||
}
|
||||
|
||||
#include "test/data/g2_compressed.json.h"
|
||||
|
||||
TEST(proofs, g2_test_vectors)
|
||||
{
|
||||
UniValue v = read_json(std::string(json_tests::g2_compressed, json_tests::g2_compressed + sizeof(json_tests::g2_compressed)));
|
||||
|
||||
curve_G2 e = curve_Fr("34958239045823") * curve_G2::one();
|
||||
for (size_t i = 0; i < 10000; i++) {
|
||||
e = (curve_Fr("34958239045823") ^ i) * e;
|
||||
auto expected = CompressedG2(e);
|
||||
|
||||
expect_test_vector(v[i], expected);
|
||||
ASSERT_TRUE(expected.to_libsnark_g2<curve_G2>() == e);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "random.h"
|
||||
|
||||
extern int GenZero(int n);
|
||||
extern int GenMax(int n);
|
||||
|
||||
TEST(Random, MappedShuffle) {
|
||||
std::vector<int> a {8, 4, 6, 3, 5};
|
||||
std::vector<int> m {0, 1, 2, 3, 4};
|
||||
|
||||
auto a1 = a;
|
||||
auto m1 = m;
|
||||
MappedShuffle(a1.begin(), m1.begin(), a1.size(), GenZero);
|
||||
std::vector<int> ea1 {4, 6, 3, 5, 8};
|
||||
std::vector<int> em1 {1, 2, 3, 4, 0};
|
||||
EXPECT_EQ(ea1, a1);
|
||||
EXPECT_EQ(em1, m1);
|
||||
|
||||
auto a2 = a;
|
||||
auto m2 = m;
|
||||
MappedShuffle(a2.begin(), m2.begin(), a2.size(), GenMax);
|
||||
std::vector<int> ea2 {8, 4, 6, 3, 5};
|
||||
std::vector<int> em2 {0, 1, 2, 3, 4};
|
||||
EXPECT_EQ(ea2, a2);
|
||||
EXPECT_EQ(em2, m2);
|
||||
|
||||
auto a3 = a;
|
||||
auto m3 = m;
|
||||
MappedShuffle(a3.begin(), m3.begin(), a3.size(), GenIdentity);
|
||||
std::vector<int> ea3 {8, 4, 6, 3, 5};
|
||||
std::vector<int> em3 {0, 1, 2, 3, 4};
|
||||
EXPECT_EQ(ea3, a3);
|
||||
EXPECT_EQ(em3, m3);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <univalue.h>
|
||||
|
||||
#include "chain.h"
|
||||
#include "chainparams.h"
|
||||
#include "clientversion.h"
|
||||
#include "primitives/block.h"
|
||||
#include "rpcserver.h"
|
||||
#include "streams.h"
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
extern UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false);
|
||||
|
||||
TEST(rpc, check_blockToJSON_returns_minified_solution) {
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
|
||||
// Testnet block 006a87f9f91c1f51c7549e2c8965c0fd4fe8c212798f932efc54dc7bccbec780
|
||||
// Height 1391
|
||||
CDataStream ss(ParseHex("0400000077be515306e347c6856686d83a229169140a2f7e17281c8319ecf00c49bb6f00994ca400914d6733295faf4e0063998e75a18aae7d39b5244d88d082c13145070000000000000000000000000000000000000000000000000000000000000000ae71c25700737b1f010090f8a62f53105d6b6f173d242fbbf54b0c1024a64520f0020e47fe710000fd4005009f44ff7505d789b964d6817734b8ce1377d456255994370d06e59ac99bd5791b6ad174a66fd71c70e60cfc7fd88243ffe06f80b1ad181625f210779c745524629448e25348a5fce4f346a1735e60fdf53e144c0157dbc47c700a21a236f1efb7ee75f65b8d9d9e29026cfd09048233175202b211b9a49de4ab46f1cac71b6ea57a686377bd612378746e70c61a659c9cd683269e9c2a5cbc1d19f1149345302bbd0a1e62bf4bab01e9caeea789a1519441a61b146de35a4cc75dbdf01029127e311ad5073e7e96397f47226a7df9df66b2086b70756db013bbaeb068260157014b2602fc7dc71336e1439c887d2742d9730b4e79b08ec7839c3e2a037ae1565d04e05e351bb3531e5ef42cf7b71ca1482a9205245dd41f4db0f71644f8bdb88e845558537c03834c06ac83f336651e54e2edfc12e15ea9b7ea2c074e6155654d44c4d3bd90d9511050e9ad87d170db01448e5be6f45419cd86008978db5e3ceab79890234f992648d69bf1053855387db646ccdee5575c65f81dd0f670b016d9f9a84707d91f77b862f697b8bb08365ba71fbe6bfa47af39155a75ebdcb1e5d69f59c40c9e3a64988c1ec26f7f5159eef5c244d504a9e46125948ecc389c2ec3028ac4ff39ffd66e7743970819272b21e0c2df75b308bc62896873952147e57ed79446db4cdb5a563e76ec4c25899d41128afb9a5f8fc8063621efb7a58b9dd666d30c73e318cdcf3393bfec200e160f500e645f7baac263db99fa4a7c1cb4fea219fc512193102034d379f244c21a81821301b8d47c90247713a3e902c762d7bafa6cdb744eeb6d3b50dd175599d02b6e9f5bbda59366e04862aa765135968426e7ac0116de7351940dc57c0ae451d63f667e39891bc81e09e6c76f6f8a7582f7447c6f5945f717b0e52a7e3dd0c6db4061362123cc53fd8ede4abed4865201dc4d8eb4e5d48baa565183b69a5304a44c0600bb24dcaeee9d95ceebd27c1b0a33e0b46f23797d7d7907300b2bb7d62ef2fc5aa139250c73930c621bb5f41fc235534ee8014dfaddd5245aeb01198420ba7b5c076545329c94d54fa725a8e807579f5f0cc9d98170598023268f5930893620190275e6b3c6f5181e36310a9a475208316911d78f917d724c5946c553b7ec042c563c540114b6b78bd4c6e808ee391a4a9d93e127032983c5b3708037b14aa604cfb034e7c8b0ffdd6936446fe80216178506a87402653a373926eeff66e704daf992a0a9a5c3ad80566c0339be9e5b8e35b3b3226b2f7767e20d992ea6c3d6e322eca37b0c7f7e60060802f5abcc1975841365cadbdc3867063addfc803766ae525375ecddee61f9df9ffcd20343c83ab82b0e91de039c59cb435c8d3159cc338b4901f40c9b5c27043bcf2bd5fa9b685b65c9ba5a1e11a51dd3f773051560341f9ec81d05bf259e2d4b7161f896fbb6812cfc924a32120b7367d5e40439e267adda6a1315bb0d6200ce6a503174c8d2a638ea6fd6b1f486d68db11bdca63c4f4a725d1ab6231ea875484e70b27d293c05803386924f283d4c12bb953474d92b7dd43d2d97193bd96281ebb63fa075d2f9ecd310c70ee1d97b5330bd8fb5791c5943ecf084e5f2c83915acac57519c46b166136068d6f9ec0dd598616e32c591128ce13705a283ca39d5b211409600e07b3713113374d9700207a45394eac5b3b7afc9b1b2bad7d89fd3f35f6b2413ce615ee7869b3569009403b96fdacdb32ef0a7e5229e2b666d51e95bdfb009b892e88bde70621a9b6509f068781392df4bdbc5723bb15071993f0d9a11575af5ff6ef85eaea39bc86805b35d8beee91b779354147f2d85304b8b49d053e7444fdd3deb9d16de331f2552af5b3be7766bb8f3f6a78c62148efb231f22680101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05026f050101ffffffff02b03f250400000000232103885e6a80a5702046eb76c4702921b75858fc633df3cddff827cf7b3602e45cbdacec4f09010000000017a9146708e6670db0b950dac68031025cc5b63213a4918700000000"), SER_DISK, CLIENT_VERSION);
|
||||
CBlock block;
|
||||
ss >> block;
|
||||
|
||||
CBlockIndex index {block};
|
||||
index.nHeight = 1391;
|
||||
|
||||
UniValue obj = blockToJSON(block, &index);
|
||||
EXPECT_EQ("009f44ff7505d789b964d6817734b8ce1377d456255994370d06e59ac99bd5791b6ad174a66fd71c70e60cfc7fd88243ffe06f80b1ad181625f210779c745524629448e25348a5fce4f346a1735e60fdf53e144c0157dbc47c700a21a236f1efb7ee75f65b8d9d9e29026cfd09048233175202b211b9a49de4ab46f1cac71b6ea57a686377bd612378746e70c61a659c9cd683269e9c2a5cbc1d19f1149345302bbd0a1e62bf4bab01e9caeea789a1519441a61b146de35a4cc75dbdf01029127e311ad5073e7e96397f47226a7df9df66b2086b70756db013bbaeb068260157014b2602fc7dc71336e1439c887d2742d9730b4e79b08ec7839c3e2a037ae1565d04e05e351bb3531e5ef42cf7b71ca1482a9205245dd41f4db0f71644f8bdb88e845558537c03834c06ac83f336651e54e2edfc12e15ea9b7ea2c074e6155654d44c4d3bd90d9511050e9ad87d170db01448e5be6f45419cd86008978db5e3ceab79890234f992648d69bf1053855387db646ccdee5575c65f81dd0f670b016d9f9a84707d91f77b862f697b8bb08365ba71fbe6bfa47af39155a75ebdcb1e5d69f59c40c9e3a64988c1ec26f7f5159eef5c244d504a9e46125948ecc389c2ec3028ac4ff39ffd66e7743970819272b21e0c2df75b308bc62896873952147e57ed79446db4cdb5a563e76ec4c25899d41128afb9a5f8fc8063621efb7a58b9dd666d30c73e318cdcf3393bfec200e160f500e645f7baac263db99fa4a7c1cb4fea219fc512193102034d379f244c21a81821301b8d47c90247713a3e902c762d7bafa6cdb744eeb6d3b50dd175599d02b6e9f5bbda59366e04862aa765135968426e7ac0116de7351940dc57c0ae451d63f667e39891bc81e09e6c76f6f8a7582f7447c6f5945f717b0e52a7e3dd0c6db4061362123cc53fd8ede4abed4865201dc4d8eb4e5d48baa565183b69a5304a44c0600bb24dcaeee9d95ceebd27c1b0a33e0b46f23797d7d7907300b2bb7d62ef2fc5aa139250c73930c621bb5f41fc235534ee8014dfaddd5245aeb01198420ba7b5c076545329c94d54fa725a8e807579f5f0cc9d98170598023268f5930893620190275e6b3c6f5181e36310a9a475208316911d78f917d724c5946c553b7ec042c563c540114b6b78bd4c6e808ee391a4a9d93e127032983c5b3708037b14aa604cfb034e7c8b0ffdd6936446fe80216178506a87402653a373926eeff66e704daf992a0a9a5c3ad80566c0339be9e5b8e35b3b3226b2f7767e20d992ea6c3d6e322eca37b0c7f7e60060802f5abcc1975841365cadbdc3867063addfc803766ae525375ecddee61f9df9ffcd20343c83ab82b0e91de039c59cb435c8d3159cc338b4901f40c9b5c27043bcf2bd5fa9b685b65c9ba5a1e11a51dd3f773051560341f9ec81d05bf259e2d4b7161f896fbb6812cfc924a32120b7367d5e40439e267adda6a1315bb0d6200ce6a503174c8d2a638ea6fd6b1f486d68db11bdca63c4f4a725d1ab6231ea875484e70b27d293c05803386924f283d4c12bb953474d92b7dd43d2d97193bd96281ebb63fa075d2f9ecd310c70ee1d97b5330bd8fb5791c5943ecf084e5f2c83915acac57519c46b166136068d6f9ec0dd598616e32c591128ce13705a283ca39d5b211409600e07b3713113374d9700207a45394eac5b3b7afc9b1b2bad7d89fd3f35f6b2413ce615ee7869b3569009403b96fdacdb32ef0a7e5229e2b666d51e95bdfb009b892e88bde70621a9b6509f068781392df4bdbc5723bb15071993f0d9a11575af5ff6ef85eaea39bc86805b35d8beee91b779354147f2d85304b8b49d053e7444fdd3deb9d16de331f2552af5b3be7766bb8f3f6a78c62148efb231f2268", find_value(obj, "solution").get_str());
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(tautologies, seven_eq_seven) {
|
||||
ASSERT_EQ(7, 7);
|
||||
}
|
||||
|
||||
TEST(tautologies, DISABLED_ObviousFailure)
|
||||
{
|
||||
FAIL() << "This is expected";
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "primitives/transaction.h"
|
||||
#include "zcash/Note.hpp"
|
||||
#include "zcash/Address.hpp"
|
||||
|
||||
extern ZCJoinSplit* params;
|
||||
extern int GenZero(int n);
|
||||
extern int GenMax(int n);
|
||||
|
||||
TEST(Transaction, JSDescriptionRandomized) {
|
||||
// construct a merkle tree
|
||||
ZCIncrementalMerkleTree merkleTree;
|
||||
|
||||
libzcash::SpendingKey k = libzcash::SpendingKey::random();
|
||||
libzcash::PaymentAddress addr = k.address();
|
||||
|
||||
libzcash::Note note(addr.a_pk, 100, uint256(), uint256());
|
||||
|
||||
// commitment from coin
|
||||
uint256 commitment = note.cm();
|
||||
|
||||
// insert commitment into the merkle tree
|
||||
merkleTree.append(commitment);
|
||||
|
||||
// compute the merkle root we will be working with
|
||||
uint256 rt = merkleTree.root();
|
||||
|
||||
auto witness = merkleTree.witness();
|
||||
|
||||
// create JSDescription
|
||||
uint256 pubKeyHash;
|
||||
boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> inputs = {
|
||||
libzcash::JSInput(witness, note, k),
|
||||
libzcash::JSInput() // dummy input of zero value
|
||||
};
|
||||
boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS> outputs = {
|
||||
libzcash::JSOutput(addr, 50),
|
||||
libzcash::JSOutput(addr, 50)
|
||||
};
|
||||
boost::array<size_t, ZC_NUM_JS_INPUTS> inputMap;
|
||||
boost::array<size_t, ZC_NUM_JS_OUTPUTS> outputMap;
|
||||
|
||||
{
|
||||
auto jsdesc = JSDescription::Randomized(
|
||||
*params, pubKeyHash, rt,
|
||||
inputs, outputs,
|
||||
inputMap, outputMap,
|
||||
0, 0, false);
|
||||
|
||||
std::set<size_t> inputSet(inputMap.begin(), inputMap.end());
|
||||
std::set<size_t> expectedInputSet {0, 1};
|
||||
EXPECT_EQ(expectedInputSet, inputSet);
|
||||
|
||||
std::set<size_t> outputSet(outputMap.begin(), outputMap.end());
|
||||
std::set<size_t> expectedOutputSet {0, 1};
|
||||
EXPECT_EQ(expectedOutputSet, outputSet);
|
||||
}
|
||||
|
||||
{
|
||||
auto jsdesc = JSDescription::Randomized(
|
||||
*params, pubKeyHash, rt,
|
||||
inputs, outputs,
|
||||
inputMap, outputMap,
|
||||
0, 0, false, nullptr, GenZero);
|
||||
|
||||
boost::array<size_t, ZC_NUM_JS_INPUTS> expectedInputMap {1, 0};
|
||||
boost::array<size_t, ZC_NUM_JS_OUTPUTS> expectedOutputMap {1, 0};
|
||||
EXPECT_EQ(expectedInputMap, inputMap);
|
||||
EXPECT_EQ(expectedOutputMap, outputMap);
|
||||
}
|
||||
|
||||
{
|
||||
auto jsdesc = JSDescription::Randomized(
|
||||
*params, pubKeyHash, rt,
|
||||
inputs, outputs,
|
||||
inputMap, outputMap,
|
||||
0, 0, false, nullptr, GenMax);
|
||||
|
||||
boost::array<size_t, ZC_NUM_JS_INPUTS> expectedInputMap {0, 1};
|
||||
boost::array<size_t, ZC_NUM_JS_OUTPUTS> expectedOutputMap {0, 1};
|
||||
EXPECT_EQ(expectedInputMap, inputMap);
|
||||
EXPECT_EQ(expectedOutputMap, outputMap);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "primitives/transaction.h"
|
||||
#include "clientversion.h"
|
||||
#include "serialize.h"
|
||||
#include "streams.h"
|
||||
#include "uint256.h"
|
||||
#include "util.h"
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
/*
|
||||
Test that removing #1144 succeeded by verifying the hash of a transaction is over the entire serialized form.
|
||||
*/
|
||||
TEST(txid_tests, check_txid_and_hash_are_same) {
|
||||
// Random zcash transaction aacaa62d40fcdd9192ed35ea9df31660ccf7f6c60566530faaa444fb5d0d410e
|
||||
CTransaction tx;
|
||||
CDataStream stream(ParseHex("01000000015ad78be5497476bbf84869d8156761ca850b6e82e48ad1315069a3726516a3d1010000006b483045022100ba5e90204e83c5f961b67c6232c1cc6c360afd36d43fcfae0de7af2e75f4cda7022012fec415a12048dbb70511fda6195b090b56735232281dc1144409833a092edc012102c322382e17c9ed4f47183f219cc5dd7853f939fb8eebae3c943622e0abf8d5e5feffffff0280969800000000001976a91430271a250e92135ce0db0783ebb63aaeb58e47f988acd694693a000000001976a9145f0d00adba6489150808feb4108d7be582cbb2e188ac0a000000"), SER_DISK, CLIENT_VERSION);
|
||||
stream >> tx;
|
||||
|
||||
uint256 hash = uint256S("aacaa62d40fcdd9192ed35ea9df31660ccf7f6c60566530faaa444fb5d0d410e");
|
||||
ASSERT_TRUE(hash == tx.GetHash());
|
||||
}
|
||||
|
||||
TEST(txid_tests, check_txid_and_hash_are_same_coinbase) {
|
||||
// Random zcash coinbase transaction 6041357de59ba64959d1b60f93de24dfe5ea1e26ed9e8a73d35b225a1845bad5
|
||||
CTransaction tx;
|
||||
CDataStream stream(ParseHex("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03530101ffffffff02f049020000000000232102f2df427fd4f76552ed0e86b17da8cf9b07754ea23ddc05799410a4a3a5d806ccac7c9200000000000017a9146708e6670db0b950dac68031025cc5b63213a4918700000000"), SER_DISK, CLIENT_VERSION);
|
||||
stream >> tx;
|
||||
|
||||
ASSERT_TRUE(tx.IsCoinBase());
|
||||
|
||||
uint256 hash = uint256S("6041357de59ba64959d1b60f93de24dfe5ea1e26ed9e8a73d35b225a1845bad5");
|
||||
ASSERT_TRUE(hash == tx.GetHash());
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
int GenZero(int n)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GenMax(int n)
|
||||
{
|
||||
return n-1;
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
#********************************************************************************
|
||||
# Makefile for the libsnark library.
|
||||
#********************************************************************************
|
||||
#* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
#* and contributors (see AUTHORS).
|
||||
#* @copyright MIT license (see LICENSE file)
|
||||
#*******************************************************************************/
|
||||
|
||||
# To override these, use "make OPTFLAGS=..." etc.
|
||||
CURVE = BN128
|
||||
OPTFLAGS = -O2 -march=native -mtune=native
|
||||
FEATUREFLAGS = -DUSE_ASM -DMONTGOMERY_OUTPUT
|
||||
|
||||
# Initialize this using "CXXFLAGS=... make". The makefile appends to that.
|
||||
CXXFLAGS += -std=c++11 -Wall -Wextra -Wno-unused-parameter -Wno-comment -Wfatal-errors $(OPTFLAGS) $(FEATUREFLAGS) -DCURVE_$(CURVE)
|
||||
|
||||
DEPSRC = depsrc
|
||||
DEPINST = depinst
|
||||
|
||||
CXXFLAGS += -I$(DEPINST)/include -Ilibsnark
|
||||
LDFLAGS += -L$(DEPINST)/lib -Wl,-rpath,$(DEPINST)/lib
|
||||
LDLIBS += -lgmpxx -lgmp -lboost_program_options -lsodium
|
||||
# List of .a files to include within libsnark.a and libsnark.so:
|
||||
AR_LIBS =
|
||||
# List of library files to install:
|
||||
INSTALL_LIBS = $(LIB_FILE)
|
||||
# Sentinel file to check existence of this directory (since directories don't work as a Make dependency):
|
||||
DEPINST_EXISTS = $(DEPINST)/.exists
|
||||
|
||||
ifneq ($(NO_GTEST),1)
|
||||
# Compile GTest from sourcecode if we can (e.g., Ubuntu). Otherwise use precompiled one (e.g., Fedora).
|
||||
# See https://github.com/google/googletest/blob/master/googletest/docs/FAQ.md#why-is-it-not-recommended-to-install-a-pre-compiled-copy-of-google-test-for-example-into-usrlocal
|
||||
ifneq ($(NO_COMPILE_LIBGTEST),1)
|
||||
GTESTDIR=/usr/src/gtest
|
||||
COMPILE_LIBGTEST = $(shell test -d $(GTESTDIR) && echo -n 1)
|
||||
endif
|
||||
GTEST_LDLIBS += -lgtest -lpthread
|
||||
endif
|
||||
|
||||
ifneq ($(NO_SUPERCOP),1)
|
||||
SUPERCOP_LDLIBS += -lsupercop
|
||||
INSTALL_LIBS += depinst/lib/libsupercop.a
|
||||
# Would have been nicer to roll supercop into libsnark.a ("AR_LIBS += $(DEPINST)/lib/libsupercop.a"), but it doesn't support position-independent code (libsnark issue #20).
|
||||
endif
|
||||
|
||||
LIB_SRCS = \
|
||||
libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp \
|
||||
libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp \
|
||||
libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp \
|
||||
libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp \
|
||||
libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp \
|
||||
libsnark/common/profiling.cpp \
|
||||
libsnark/common/utils.cpp \
|
||||
libsnark/gadgetlib1/constraint_profiling.cpp \
|
||||
|
||||
ifeq ($(CURVE),BN128)
|
||||
LIB_SRCS += \
|
||||
libsnark/algebra/curves/bn128/bn128_g1.cpp \
|
||||
libsnark/algebra/curves/bn128/bn128_g2.cpp \
|
||||
libsnark/algebra/curves/bn128/bn128_gt.cpp \
|
||||
libsnark/algebra/curves/bn128/bn128_init.cpp \
|
||||
libsnark/algebra/curves/bn128/bn128_pairing.cpp \
|
||||
libsnark/algebra/curves/bn128/bn128_pp.cpp
|
||||
|
||||
CXXFLAGS += -DBN_SUPPORT_SNARK
|
||||
AR_LIBS += $(DEPINST)/lib/libzm.a
|
||||
endif
|
||||
|
||||
# FIXME: most of these are broken due to removed code.
|
||||
DISABLED_EXECUTABLES = \
|
||||
libsnark/common/routing_algorithms/profiling/profile_routing_algorithms \
|
||||
libsnark/common/routing_algorithms/tests/test_routing_algorithms \
|
||||
libsnark/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram \
|
||||
libsnark/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget \
|
||||
libsnark/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets \
|
||||
libsnark/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget \
|
||||
libsnark/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget \
|
||||
libsnark/reductions/ram_to_r1cs/examples/demo_arithmetization \
|
||||
libsnark/relations/arithmetic_programs/ssp/tests/test_ssp \
|
||||
libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd \
|
||||
libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd \
|
||||
libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd \
|
||||
libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd \
|
||||
libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark \
|
||||
libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark \
|
||||
libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark \
|
||||
libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark \
|
||||
libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark \
|
||||
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark \
|
||||
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator \
|
||||
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover \
|
||||
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier \
|
||||
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark \
|
||||
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark \
|
||||
libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark \
|
||||
libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark \
|
||||
libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark \
|
||||
libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark \
|
||||
libsnark/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark \
|
||||
libsnark/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark
|
||||
|
||||
EXECUTABLES =
|
||||
|
||||
EXECUTABLES_WITH_GTEST =
|
||||
|
||||
EXECUTABLES_WITH_SUPERCOP = \
|
||||
libsnark/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark
|
||||
|
||||
GTEST_TESTS = libsnark/gtests
|
||||
|
||||
GTEST_SRCS = \
|
||||
libsnark/algebra/curves/tests/test_bilinearity.cpp \
|
||||
libsnark/algebra/curves/tests/test_groups.cpp \
|
||||
libsnark/algebra/fields/tests/test_bigint.cpp \
|
||||
libsnark/algebra/fields/tests/test_fields.cpp \
|
||||
libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp \
|
||||
libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp \
|
||||
libsnark/relations/arithmetic_programs/qap/tests/test_qap.cpp \
|
||||
libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp \
|
||||
libsnark/gtests.cpp
|
||||
|
||||
DOCS = README.html
|
||||
|
||||
LIBSNARK_A = libsnark.a
|
||||
|
||||
# For documentation of the following options, see README.md .
|
||||
|
||||
ifeq ($(NO_PROCPS),1)
|
||||
CXXFLAGS += -DNO_PROCPS
|
||||
else
|
||||
LDLIBS += -lprocps
|
||||
endif
|
||||
|
||||
ifeq ($(LOWMEM),1)
|
||||
CXXFLAGS += -DLOWMEM
|
||||
endif
|
||||
|
||||
ifeq ($(PROFILE_OP_COUNTS),1)
|
||||
STATIC = 1
|
||||
CXXFLAGS += -DPROFILE_OP_COUNTS
|
||||
endif
|
||||
|
||||
ifeq ($(STATIC),1)
|
||||
CXXFLAGS += -static -DSTATIC
|
||||
else
|
||||
CXXFLAGS += -fPIC
|
||||
endif
|
||||
|
||||
ifeq ($(MULTICORE),1)
|
||||
CXXFLAGS += -DMULTICORE -fopenmp
|
||||
endif
|
||||
|
||||
ifeq ($(CPPDEBUG),1)
|
||||
CXXFLAGS += -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC
|
||||
DEBUG = 1
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CXXFLAGS += -DDEBUG -ggdb3
|
||||
endif
|
||||
|
||||
ifeq ($(PERFORMANCE),1)
|
||||
OPTFLAGS = -O3 -march=native -mtune=native
|
||||
CXXFLAGS += -DNDEBUG
|
||||
# Enable link-time optimization:
|
||||
CXXFLAGS += -flto -fuse-linker-plugin
|
||||
LDFLAGS += -flto
|
||||
endif
|
||||
|
||||
LIB_OBJS =$(patsubst %.cpp,%.o,$(LIB_SRCS))
|
||||
EXEC_OBJS =$(patsubst %,%.o,$(EXECUTABLES) $(EXECUTABLES_WITH_GTEST) $(EXECUTABLES_WITH_SUPERCOP))
|
||||
GTEST_OBJS =$(patsubst %.cpp,%.o,$(GTEST_SRCS))
|
||||
|
||||
all: \
|
||||
$(if $(NO_GTEST),,$(EXECUTABLES_WITH_GTEST) $(GTEST_TESTS)) \
|
||||
$(if $(NO_SUPERCOP),,$(EXECUTABLES_WITH_SUPERCOP)) \
|
||||
$(EXECUTABLES) \
|
||||
$(if $(NO_DOCS),,doc)
|
||||
|
||||
doc: $(DOCS)
|
||||
|
||||
$(DEPINST_EXISTS):
|
||||
# Create placeholder directories for installed dependencies. Some make settings (including the default) require actually running ./prepare-depends.sh to populate this directory.
|
||||
mkdir -p $(DEPINST)/lib $(DEPINST)/include
|
||||
touch $@
|
||||
|
||||
# In order to detect changes to #include dependencies. -MMD below generates a .d file for each .o file. Include the .d file.
|
||||
-include $(patsubst %.o,%.d, $(LIB_OBJS) $(GTEST_OBJS) $(EXEC_OBJS) )
|
||||
|
||||
$(LIB_OBJS) $(if $(NO_GTEST),,$(GTEST_OBJS)) $(EXEC_OBJS): %.o: %.cpp
|
||||
$(CXX) -o $@ $< -c -MMD $(CXXFLAGS)
|
||||
|
||||
LIBGTEST_A = $(DEPINST)/lib/libgtest.a
|
||||
|
||||
$(LIBGTEST_A): $(GTESTDIR)/libsnark/gtest-all.cc $(DEPINST_EXISTS)
|
||||
$(CXX) -o $(DEPINST)/lib/gtest-all.o -I $(GTESTDIR) -c -isystem $(GTESTDIR)/include $< $(CXXFLAGS)
|
||||
$(AR) -rv $(LIBGTEST_A) $(DEPINST)/lib/gtest-all.o
|
||||
|
||||
# libsnark.a will contains all of our relevant object files, and we also mash in the .a files of relevant dependencies built by ./prepare-depends.sh
|
||||
$(LIBSNARK_A): $(LIB_OBJS) $(AR_LIBS)
|
||||
$(AR) q $(LIBSNARK_A) $(LIB_OBJS)
|
||||
if [ -n "$(AR_LIBS)" ]; then mkdir -p tmp-ar; cd tmp-ar; for AR_LIB in $(AR_LIBS); do $(AR) x $$AR_LIB; done; $(AR) qc $(LIBSNARK_A) tmp-ar/*; cd ..; rm -r tmp-ar; fi;
|
||||
$(AR) s $(LIBSNARK_A)
|
||||
|
||||
libsnark.so: $(LIBSNARK_A) $(DEPINST_EXISTS)
|
||||
$(CXX) -o $@ --shared -Wl,--whole-archive $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) -Wl,--no-whole-archive $(LDLIBS)
|
||||
|
||||
libsnark/gadgetlib2/tests/gadgetlib2_test: \
|
||||
libsnark/gadgetlib2/tests/adapters_UTEST.cpp \
|
||||
libsnark/gadgetlib2/tests/constraint_UTEST.cpp \
|
||||
libsnark/gadgetlib2/tests/gadget_UTEST.cpp \
|
||||
libsnark/gadgetlib2/tests/integration_UTEST.cpp \
|
||||
libsnark/gadgetlib2/tests/protoboard_UTEST.cpp \
|
||||
libsnark/gadgetlib2/tests/variable_UTEST.cpp
|
||||
|
||||
$(EXECUTABLES): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS)
|
||||
$(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS)
|
||||
|
||||
$(EXECUTABLES_WITH_GTEST): %: %.o $(LIBSNARK_A) $(if $(COMPILE_LIBGTEST),$(LIBGTEST_A)) $(DEPINST_EXISTS)
|
||||
$(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(GTEST_LDLIBS) $(LDLIBS)
|
||||
|
||||
$(EXECUTABLES_WITH_SUPERCOP): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS)
|
||||
$(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(SUPERCOP_LDLIBS) $(LDLIBS)
|
||||
|
||||
$(GTEST_TESTS): %: $(GTEST_OBJS) $(LIBSNARK_A) $(if $(COMPILE_LIBGTEST),$(LIBGTEST_A)) $(DEPINST_EXISTS)
|
||||
$(CXX) -o $@ $(GTEST_OBJS) $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(GTEST_LDLIBS) $(LDLIBS)
|
||||
|
||||
|
||||
ifeq ($(STATIC),1)
|
||||
LIB_FILE = $(LIBSNARK_A)
|
||||
else
|
||||
LIB_FILE = libsnark.so
|
||||
endif
|
||||
|
||||
lib: $(LIB_FILE)
|
||||
|
||||
$(DOCS): %.html: %.md
|
||||
markdown_py -f $@ $^ -x toc -x extra --noisy
|
||||
# TODO: Would be nice to enable "-x smartypants" but Ubuntu 12.04 doesn't support that.
|
||||
# TODO: switch to redcarpet, to produce same output as GitHub's processing of README.md. But what about TOC?
|
||||
|
||||
ifeq ($(PREFIX),)
|
||||
install:
|
||||
$(error Please provide PREFIX. E.g. make install PREFIX=/usr)
|
||||
else
|
||||
HEADERS_SRC=$(shell find libsnark -name '*.hpp' -o -name '*.tcc')
|
||||
HEADERS_DEST=$(patsubst libsnark/%,$(PREFIX)/include/libsnark/%,$(HEADERS_SRC))
|
||||
|
||||
$(HEADERS_DEST): $(PREFIX)/include/libsnark/%: libsnark/%
|
||||
mkdir -p $(shell dirname $@)
|
||||
cp $< $@
|
||||
|
||||
install: $(INSTALL_LIBS) $(HEADERS_DEST) $(DEPINST_EXISTS)
|
||||
mkdir -p $(PREFIX)/lib
|
||||
cp -v $(INSTALL_LIBS) $(PREFIX)/lib/
|
||||
ifneq ($(NO_COPY_DEPINST),1)
|
||||
cp -rv $(DEPINST)/include $(PREFIX)
|
||||
endif
|
||||
endif
|
||||
|
||||
check: $(GTEST_TESTS)
|
||||
$(GTEST_TESTS)
|
||||
|
||||
doxy:
|
||||
doxygen doxygen.conf
|
||||
|
||||
# Clean generated files, except locally-compiled dependencies
|
||||
clean:
|
||||
$(RM) \
|
||||
$(LIB_OBJS) $(GTEST_OBJS) $(EXEC_OBJS) \
|
||||
$(EXECUTABLES) $(EXECUTABLES_WITH_GTEST) $(EXECUTABLES_WITH_SUPERCOP) $(GTEST_TESTS) \
|
||||
$(DOCS) \
|
||||
${patsubst %.o,%.d,${LIB_OBJS} ${GTEST_OBJS} ${EXEC_OBJS}} \
|
||||
libsnark.so $(LIBSNARK_A) \
|
||||
$(RM) -fr doxygen/ \
|
||||
$(RM) $(LIBGTEST_A) $(DEPINST)/lib/gtest-all.o
|
||||
|
||||
# Clean all, including locally-compiled dependencies
|
||||
clean-all: clean
|
||||
$(RM) -fr $(DEPSRC) $(DEPINST)
|
||||
|
||||
.PHONY: all clean clean-all doc doxy lib install
|
Loading…
Reference in New Issue