Skip to content

Commit b2f49bd

Browse files
committed
Integration of property based testing into Bitcoin Core
update copyright headers attempt to fix linting errors Fixing issue with make check classifying generator files as actual unit tests Wrapping gen files in ENABLE_PROPERTY_TESTS macro Make macro better
1 parent ca4510c commit b2f49bd

File tree

9 files changed

+196
-1
lines changed

9 files changed

+196
-1
lines changed

configure.ac

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,12 @@ AC_ARG_ENABLE(gui-tests,
130130
[use_gui_tests=$enableval],
131131
[use_gui_tests=$use_tests])
132132

133+
AC_ARG_WITH([rapidcheck],
134+
[AS_HELP_STRING([--with-rapidcheck],
135+
[enable RapidCheck property based tests (default is yes if librapidcheck is found)])],
136+
[use_rapidcheck=$withval],
137+
[use_rapidcheck=auto])
138+
133139
AC_ARG_ENABLE(bench,
134140
AS_HELP_STRING([--disable-bench],[do not compile benchmarks (default is to compile)]),
135141
[use_bench=$enableval],
@@ -1134,6 +1140,22 @@ AC_CHECK_DECLS([EVP_MD_CTX_new],,,[AC_INCLUDES_DEFAULT
11341140
])
11351141
CXXFLAGS="${save_CXXFLAGS}"
11361142

1143+
dnl RapidCheck Property Based Testing
1144+
1145+
enable_property_tests=no
1146+
if test "x$use_rapidcheck" = xauto; then
1147+
AC_CHECK_HEADERS([rapidcheck.h], [enable_property_tests=yes])
1148+
elif test "x$use_rapidcheck" != xno; then
1149+
enable_property_tests=yes
1150+
fi
1151+
1152+
RAPIDCHECK_LIBS=
1153+
if test "x$enable_property_tests" = xyes; then
1154+
RAPIDCHECK_LIBS=-lrapidcheck
1155+
fi
1156+
AC_SUBST(RAPIDCHECK_LIBS)
1157+
AM_CONDITIONAL([ENABLE_PROPERTY_TESTS], [test x$enable_property_tests = xyes])
1158+
11371159
dnl univalue check
11381160

11391161
need_bundled_univalue=yes

depends/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ WORK_PATH = $(BASEDIR)/work
55
BASE_CACHE ?= $(BASEDIR)/built
66
SDK_PATH ?= $(BASEDIR)/SDKs
77
NO_QT ?=
8+
RAPIDCHECK ?=
89
NO_WALLET ?=
910
NO_UPNP ?=
1011
FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources
@@ -93,13 +94,19 @@ qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) $(qt_$(host_arch
9394
wallet_packages_$(NO_WALLET) = $(wallet_packages)
9495
upnp_packages_$(NO_UPNP) = $(upnp_packages)
9596

97+
rapidcheck_packages_$(RAPIDCHECK) = $(rapidcheck_packages)
98+
9699
packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_)
97100
native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages)
98101

99102
ifneq ($(qt_packages_),)
100103
native_packages += $(qt_native_packages)
101104
endif
102105

106+
ifeq ($(rapidcheck_packages_),)
107+
packages += $(rapidcheck_packages)
108+
endif
109+
103110
all_packages = $(packages) $(native_packages)
104111

105112
meta_depends = Makefile funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk

depends/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ The following can be set when running make: make FOO=bar
6363
NO_WALLET: Don't download/build/cache libs needed to enable the wallet
6464
NO_UPNP: Don't download/build/cache packages needed for enabling upnp
6565
DEBUG: disable some optimizations and enable more runtime checking
66+
RAPIDCHECK: build rapidcheck (experimental)
6667
HOST_ID_SALT: Optional salt to use when generating host package ids
6768
BUILD_ID_SALT: Optional salt to use when generating build package ids
6869

depends/packages/packages.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ qt_packages = qrencode protobuf zlib
55

66
qt_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans
77

8+
rapidcheck_packages = rapidcheck
9+
810
qt_darwin_packages=qt
911
qt_mingw32_packages=qt
1012

depends/packages/rapidcheck.mk

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package=rapidcheck
2+
$(package)_version=10fc0cb
3+
$(package)_download_path=https://github.com/MarcoFalke/rapidcheck/archive
4+
$(package)_file_name=$(package)-$($(package)_version).tar.gz
5+
$(package)_sha256_hash=9640926223c00af45bce4c7df8b756b5458a89b2ba74cfe3e404467f13ce26df
6+
7+
define $(package)_config_cmds
8+
cmake -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true .
9+
endef
10+
11+
define $(package)_build_cmds
12+
$(MAKE) && \
13+
mkdir -p $($(package)_staging_dir)$(host_prefix)/include && \
14+
cp -a include/* $($(package)_staging_dir)$(host_prefix)/include/ && \
15+
cp -a extras/boost_test/include/rapidcheck/* $($(package)_staging_dir)$(host_prefix)/include/rapidcheck/ && \
16+
mkdir -p $($(package)_staging_dir)$(host_prefix)/lib && \
17+
cp -a librapidcheck.a $($(package)_staging_dir)$(host_prefix)/lib/
18+
endef

src/Makefile.test.include

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ TEST_SRCDIR = test
88
TEST_BINARY=test/test_bitcoin$(EXEEXT)
99

1010
JSON_TEST_FILES = \
11+
test/data/script_tests.json \
1112
test/data/base58_encode_decode.json \
1213
test/data/blockfilters.json \
1314
test/data/key_io_valid.json \
@@ -94,6 +95,15 @@ BITCOIN_TESTS =\
9495
test/validation_block_tests.cpp \
9596
test/versionbits_tests.cpp
9697

98+
if ENABLE_PROPERTY_TESTS
99+
BITCOIN_TESTS += \
100+
test/key_properties.cpp
101+
102+
BITCOIN_TEST_SUITE += \
103+
test/gen/crypto_gen.cpp \
104+
test/gen/crypto_gen.h
105+
endif
106+
97107
if ENABLE_WALLET
98108
BITCOIN_TESTS += \
99109
wallet/test/accounting_tests.cpp \
@@ -118,7 +128,7 @@ test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_C
118128
$(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
119129
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
120130

121-
test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
131+
test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(RAPIDCHECK_LIBS)
122132
test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
123133

124134
if ENABLE_ZMQ

src/test/gen/crypto_gen.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) 2018 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
#include <test/gen/crypto_gen.h>
5+
6+
#include <key.h>
7+
8+
#include <rapidcheck/gen/Arbitrary.h>
9+
#include <rapidcheck/Gen.h>
10+
#include <rapidcheck/gen/Predicate.h>
11+
#include <rapidcheck/gen/Container.h>
12+
13+
/** Generates 1 to 20 keys for OP_CHECKMULTISIG */
14+
rc::Gen<std::vector<CKey>> MultisigKeys()
15+
{
16+
return rc::gen::suchThat(rc::gen::arbitrary<std::vector<CKey>>(), [](const std::vector<CKey>& keys) {
17+
return keys.size() >= 1 && keys.size() <= 15;
18+
});
19+
};

src/test/gen/crypto_gen.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright (c) 2018 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
#ifndef BITCOIN_TEST_GEN_CRYPTO_GEN_H
5+
#define BITCOIN_TEST_GEN_CRYPTO_GEN_H
6+
7+
#include <key.h>
8+
#include <random.h>
9+
#include <uint256.h>
10+
#include <rapidcheck/gen/Arbitrary.h>
11+
#include <rapidcheck/Gen.h>
12+
#include <rapidcheck/gen/Create.h>
13+
#include <rapidcheck/gen/Numeric.h>
14+
15+
/** Generates 1 to 15 keys for OP_CHECKMULTISIG */
16+
rc::Gen<std::vector<CKey>> MultisigKeys();
17+
18+
namespace rc
19+
{
20+
/** Generator for a new CKey */
21+
template <>
22+
struct Arbitrary<CKey> {
23+
static Gen<CKey> arbitrary()
24+
{
25+
return rc::gen::map<int>([](int x) {
26+
CKey key;
27+
key.MakeNewKey(true);
28+
return key;
29+
});
30+
};
31+
};
32+
33+
/** Generator for a CPrivKey */
34+
template <>
35+
struct Arbitrary<CPrivKey> {
36+
static Gen<CPrivKey> arbitrary()
37+
{
38+
return gen::map(gen::arbitrary<CKey>(), [](const CKey& key) {
39+
return key.GetPrivKey();
40+
});
41+
};
42+
};
43+
44+
/** Generator for a new CPubKey */
45+
template <>
46+
struct Arbitrary<CPubKey> {
47+
static Gen<CPubKey> arbitrary()
48+
{
49+
return gen::map(gen::arbitrary<CKey>(), [](const CKey& key) {
50+
return key.GetPubKey();
51+
});
52+
};
53+
};
54+
/** Generates a arbitrary uint256 */
55+
template <>
56+
struct Arbitrary<uint256> {
57+
static Gen<uint256> arbitrary()
58+
{
59+
return rc::gen::just(GetRandHash());
60+
};
61+
};
62+
} //namespace rc
63+
#endif

src/test/key_properties.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright (c) 2018 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
#include <key.h>
5+
6+
#include <base58.h>
7+
#include <script/script.h>
8+
#include <uint256.h>
9+
#include <util.h>
10+
#include <utilstrencodings.h>
11+
#include <test/test_bitcoin.h>
12+
#include <string>
13+
#include <vector>
14+
15+
#include <boost/test/unit_test.hpp>
16+
#include <rapidcheck/boost_test.h>
17+
#include <rapidcheck/gen/Arbitrary.h>
18+
#include <rapidcheck/Gen.h>
19+
20+
#include <test/gen/crypto_gen.h>
21+
22+
BOOST_FIXTURE_TEST_SUITE(key_properties, BasicTestingSetup)
23+
24+
/** Check CKey uniqueness */
25+
RC_BOOST_PROP(key_uniqueness, (const CKey& key1, const CKey& key2))
26+
{
27+
RC_ASSERT(!(key1 == key2));
28+
}
29+
30+
/** Verify that a private key generates the correct public key */
31+
RC_BOOST_PROP(key_generates_correct_pubkey, (const CKey& key))
32+
{
33+
CPubKey pubKey = key.GetPubKey();
34+
RC_ASSERT(key.VerifyPubKey(pubKey));
35+
}
36+
37+
/** Create a CKey using the 'Set' function must give us the same key */
38+
RC_BOOST_PROP(key_set_symmetry, (const CKey& key))
39+
{
40+
CKey key1;
41+
key1.Set(key.begin(), key.end(), key.IsCompressed());
42+
RC_ASSERT(key1 == key);
43+
}
44+
45+
/** Create a CKey, sign a piece of data, then verify it with the public key */
46+
RC_BOOST_PROP(key_sign_symmetry, (const CKey& key, const uint256& hash))
47+
{
48+
std::vector<unsigned char> vchSig;
49+
key.Sign(hash, vchSig, 0);
50+
const CPubKey& pubKey = key.GetPubKey();
51+
RC_ASSERT(pubKey.Verify(hash, vchSig));
52+
}
53+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)