aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/net.cpp32
-rw-r--r--src/net.h14
-rw-r--r--src/rpc/net.cpp5
-rw-r--r--src/secp256k1/Makefile.am10
-rw-r--r--src/secp256k1/configure.ac17
-rw-r--r--src/secp256k1/include/secp256k1.h39
-rw-r--r--src/secp256k1/src/bench.h2
-rw-r--r--src/secp256k1/src/bench_schnorr_verify.c73
-rw-r--r--src/secp256k1/src/ecdsa_impl.h16
-rw-r--r--src/secp256k1/src/field_10x26_impl.h69
-rw-r--r--src/secp256k1/src/field_5x52_impl.h91
-rw-r--r--src/secp256k1/src/group_impl.h6
-rw-r--r--src/secp256k1/src/modules/ecdh/main_impl.h2
-rw-r--r--src/secp256k1/src/modules/ecdh/tests_impl.h30
-rwxr-xr-xsrc/secp256k1/src/modules/recovery/main_impl.h2
-rw-r--r--src/secp256k1/src/modules/recovery/tests_impl.h143
-rw-r--r--src/secp256k1/src/scalar_impl.h171
-rw-r--r--[-rwxr-xr-x]src/secp256k1/src/secp256k1.c31
-rw-r--r--src/secp256k1/src/tests.c51
-rw-r--r--src/secp256k1/src/tests_exhaustive.c143
-rw-r--r--src/secp256k1/src/util.h5
-rw-r--r--src/test/DoS_tests.cpp8
-rw-r--r--src/test/net_tests.cpp4
-rw-r--r--src/wallet/wallet.cpp8
-rwxr-xr-xtest/functional/abandonconflict.py12
-rwxr-xr-xtest/functional/assumevalid.py8
-rwxr-xr-xtest/functional/bip9-softforks.py2
-rwxr-xr-xtest/functional/bumpfee.py4
-rwxr-xr-xtest/functional/disconnect_ban.py9
-rwxr-xr-xtest/functional/forknotify.py4
-rwxr-xr-xtest/functional/fundrawtransaction.py8
-rwxr-xr-xtest/functional/import-rescan.py4
-rwxr-xr-xtest/functional/importmulti.py4
-rwxr-xr-xtest/functional/keypool.py2
-rwxr-xr-xtest/functional/listtransactions.py2
-rwxr-xr-xtest/functional/maxuploadtarget.py4
-rwxr-xr-xtest/functional/mempool_persist.py14
-rwxr-xr-xtest/functional/net.py7
-rwxr-xr-xtest/functional/p2p-segwit.py4
-rwxr-xr-xtest/functional/p2p-versionbits-warning.py8
-rwxr-xr-xtest/functional/proxy_test.py3
-rwxr-xr-xtest/functional/pruning.py16
-rwxr-xr-xtest/functional/receivedby.py2
-rwxr-xr-xtest/functional/reindex.py10
-rwxr-xr-xtest/functional/rpcbind_test.py19
-rwxr-xr-xtest/functional/smartfees.py6
-rwxr-xr-xtest/functional/test_framework/test_framework.py60
-rw-r--r--test/functional/test_framework/util.py40
-rwxr-xr-xtest/functional/wallet-accounts.py4
-rwxr-xr-xtest/functional/wallet-dump.py6
-rwxr-xr-xtest/functional/wallet-hd.py7
-rwxr-xr-xtest/functional/wallet.py20
-rwxr-xr-xtest/functional/walletbackup.py12
-rwxr-xr-xtest/functional/zapwallettxes.py10
-rwxr-xr-xtest/functional/zmq_test.py11
55 files changed, 844 insertions, 450 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 378ac99d66..14ac5618eb 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -340,6 +340,22 @@ bool CConnman::CheckIncomingNonce(uint64_t nonce)
return true;
}
+/** Get the bind address for a socket as CAddress */
+static CAddress GetBindAddress(SOCKET sock)
+{
+ CAddress addr_bind;
+ struct sockaddr_storage sockaddr_bind;
+ socklen_t sockaddr_bind_len = sizeof(sockaddr_bind);
+ if (sock != INVALID_SOCKET) {
+ if (!getsockname(sock, (struct sockaddr*)&sockaddr_bind, &sockaddr_bind_len)) {
+ addr_bind.SetSockAddr((const struct sockaddr*)&sockaddr_bind);
+ } else {
+ LogPrint(BCLog::NET, "Warning: getsockname failed\n");
+ }
+ }
+ return addr_bind;
+}
+
CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure)
{
if (pszDest == NULL) {
@@ -393,7 +409,8 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
// Add node
NodeId id = GetNewNodeId();
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
- CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false);
+ CAddress addr_bind = GetBindAddress(hSocket);
+ CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false);
pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices);
pnode->AddRef();
@@ -635,6 +652,7 @@ void CNode::copyStats(CNodeStats &stats)
stats.nodeid = this->GetId();
X(nServices);
X(addr);
+ X(addrBind);
{
LOCK(cs_filter);
X(fRelayTxes);
@@ -1036,9 +1054,11 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
int nInbound = 0;
int nMaxInbound = nMaxConnections - (nMaxOutbound + nMaxFeeler);
- if (hSocket != INVALID_SOCKET)
- if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
+ if (hSocket != INVALID_SOCKET) {
+ if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) {
LogPrintf("Warning: Unknown socket family\n");
+ }
+ }
bool whitelisted = hListenSocket.whitelisted || IsWhitelistedRange(addr);
{
@@ -1092,8 +1112,9 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
NodeId id = GetNewNodeId();
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
+ CAddress addr_bind = GetBindAddress(hSocket);
- CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, "", true);
+ CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true);
pnode->AddRef();
pnode->fWhitelisted = whitelisted;
GetNodeSignals().InitializeNode(pnode, *this);
@@ -2639,9 +2660,10 @@ int CConnman::GetBestHeight() const
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; }
-CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string& addrNameIn, bool fInboundIn) :
+CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string& addrNameIn, bool fInboundIn) :
nTimeConnected(GetSystemTimeInSeconds()),
addr(addrIn),
+ addrBind(addrBindIn),
fInbound(fInboundIn),
nKeyedNetGroup(nKeyedNetGroupIn),
addrKnown(5000, 0.001),
diff --git a/src/net.h b/src/net.h
index 7f9ec1a57b..b89c13a90d 100644
--- a/src/net.h
+++ b/src/net.h
@@ -504,8 +504,12 @@ public:
double dPingTime;
double dPingWait;
double dMinPing;
+ // Our address, as reported by the peer
std::string addrLocal;
+ // Address of this peer
CAddress addr;
+ // Bind address of our side of the connection
+ CAddress addrBind;
};
@@ -586,7 +590,10 @@ public:
std::atomic<int64_t> nLastRecv;
const int64_t nTimeConnected;
std::atomic<int64_t> nTimeOffset;
+ // Address of this peer
const CAddress addr;
+ // Bind address of our side of the connection
+ const CAddress addrBind;
std::atomic<int> nVersion;
// strSubVer is whatever byte array we read from the wire. However, this field is intended
// to be printed out, displayed to humans in various forms and so on. So we sanitize it and
@@ -676,7 +683,7 @@ public:
CAmount lastSentFeeFilter;
int64_t nextSendTimeFeeFilter;
- CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string &addrNameIn = "", bool fInboundIn = false);
+ CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn = "", bool fInboundIn = false);
~CNode();
private:
@@ -695,6 +702,7 @@ private:
mutable CCriticalSection cs_addrName;
std::string addrName;
+ // Our address, as reported by the peer
CService addrLocal;
mutable CCriticalSection cs_addrLocal;
public:
@@ -711,7 +719,7 @@ public:
return nMyStartingHeight;
}
- int GetRefCount()
+ int GetRefCount() const
{
assert(nRefCount >= 0);
return nRefCount;
@@ -723,7 +731,7 @@ public:
{
nRecvVersion = nVersionIn;
}
- int GetRecvVersion()
+ int GetRecvVersion() const
{
return nRecvVersion;
}
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index cde5ae723b..10bf99eb38 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -76,7 +76,8 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
" {\n"
" \"id\": n, (numeric) Peer index\n"
" \"addr\":\"host:port\", (string) The ip address and port of the peer\n"
- " \"addrlocal\":\"ip:port\", (string) local address\n"
+ " \"addrbind\":\"ip:port\", (string) Bind address of the connection to the peer\n"
+ " \"addrlocal\":\"ip:port\", (string) Local address as reported by the peer\n"
" \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
" \"relaytxes\":true|false, (boolean) Whether peer has asked us to relay transactions to it\n"
" \"lastsend\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n"
@@ -133,6 +134,8 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
obj.push_back(Pair("addr", stats.addrName));
if (!(stats.addrLocal.empty()))
obj.push_back(Pair("addrlocal", stats.addrLocal));
+ if (stats.addrBind.IsValid())
+ obj.push_back(Pair("addrbind", stats.addrBind.ToString()));
obj.push_back(Pair("services", strprintf("%016x", stats.nServices)));
obj.push_back(Pair("relaytxes", stats.fRelayTxes));
obj.push_back(Pair("lastsend", stats.nLastSend));
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index e5657f7f31..c071fbe275 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -93,7 +93,10 @@ TESTS =
if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
-tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
+tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
+if !ENABLE_COVERAGE
+tests_CPPFLAGS += -DVERIFY
+endif
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
tests_LDFLAGS = -static
TESTS += tests
@@ -102,7 +105,10 @@ endif
if USE_EXHAUSTIVE_TESTS
noinst_PROGRAMS += exhaustive_tests
exhaustive_tests_SOURCES = src/tests_exhaustive.c
-exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src $(SECP_INCLUDES)
+exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES)
+if !ENABLE_COVERAGE
+exhaustive_tests_CPPFLAGS += -DVERIFY
+endif
exhaustive_tests_LDADD = $(SECP_LIBS)
exhaustive_tests_LDFLAGS = -static
TESTS += exhaustive_tests
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index ec50ffe3a2..e5fcbcb4ed 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -20,7 +20,7 @@ AC_PATH_TOOL(STRIP, strip)
AX_PROG_CC_FOR_BUILD
if test "x$CFLAGS" = "x"; then
- CFLAGS="-O3 -g"
+ CFLAGS="-g"
fi
AM_PROG_CC_C_O
@@ -89,6 +89,11 @@ AC_ARG_ENABLE(benchmark,
[use_benchmark=$enableval],
[use_benchmark=no])
+AC_ARG_ENABLE(coverage,
+ AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]),
+ [enable_coverage=$enableval],
+ [enable_coverage=no])
+
AC_ARG_ENABLE(tests,
AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]),
[use_tests=$enableval],
@@ -154,6 +159,14 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
[ AC_MSG_RESULT([no])
])
+if test x"$enable_coverage" = x"yes"; then
+ AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code])
+ CFLAGS="$CFLAGS -O0 --coverage"
+ LDFLAGS="--coverage"
+else
+ CFLAGS="$CFLAGS -O3"
+fi
+
if test x"$use_ecmult_static_precomputation" != x"no"; then
save_cross_compiling=$cross_compiling
cross_compiling=no
@@ -434,6 +447,7 @@ AC_MSG_NOTICE([Using field implementation: $set_field])
AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
+AC_MSG_NOTICE([Building for coverage analysis: $enable_coverage])
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
AC_MSG_NOTICE([Using jni: $use_jni])
@@ -460,6 +474,7 @@ AC_SUBST(SECP_INCLUDES)
AC_SUBST(SECP_LIBS)
AC_SUBST(SECP_TEST_LIBS)
AC_SUBST(SECP_TEST_INCLUDES)
+AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"])
AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"])
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index f268e309d0..fc4c5cefbb 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -163,6 +163,8 @@ typedef int (*secp256k1_nonce_function)(
*
* Returns: a newly created context object.
* In: flags: which parts of the context to initialize.
+ *
+ * See also secp256k1_context_randomize.
*/
SECP256K1_API secp256k1_context* secp256k1_context_create(
unsigned int flags
@@ -485,6 +487,28 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+/** Negates a private key in place.
+ *
+ * Returns: 1 always
+ * Args: ctx: pointer to a context object
+ * In/Out: pubkey: pointer to the public key to be negated (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
+ const secp256k1_context* ctx,
+ unsigned char *seckey
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
+
+/** Negates a public key in place.
+ *
+ * Returns: 1 always
+ * Args: ctx: pointer to a context object
+ * In/Out: pubkey: pointer to the public key to be negated (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
+ const secp256k1_context* ctx,
+ secp256k1_pubkey *pubkey
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
+
/** Tweak a private key by adding tweak to it.
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
* uniformly random 32-byte arrays, or if the resulting private key
@@ -543,11 +567,24 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Updates the context randomization.
+/** Updates the context randomization to protect against side-channel leakage.
* Returns: 1: randomization successfully updated
* 0: error
* Args: ctx: pointer to a context object (cannot be NULL)
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state)
+ *
+ * While secp256k1 code is written to be constant-time no matter what secret
+ * values are, it's possible that a future compiler may output code which isn't,
+ * and also that the CPU may not emit the same radio frequencies or draw the same
+ * amount power for all values.
+ *
+ * This function provides a seed which is combined into the blinding value: that
+ * blinding value is added before each multiplication (and removed afterwards) so
+ * that it does not affect function results, but shields against attacks which
+ * rely on any input-dependent behaviour.
+ *
+ * You should call this after secp256k1_context_create or
+ * secp256k1_context_clone, and may call this repeatedly afterwards.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
secp256k1_context* ctx,
diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h
index 3a71b4aafa..d67f08a426 100644
--- a/src/secp256k1/src/bench.h
+++ b/src/secp256k1/src/bench.h
@@ -23,7 +23,7 @@ void print_number(double x) {
if (y < 0.0) {
y = -y;
}
- while (y < 100.0) {
+ while (y > 0 && y < 100.0) {
y *= 10.0;
c++;
}
diff --git a/src/secp256k1/src/bench_schnorr_verify.c b/src/secp256k1/src/bench_schnorr_verify.c
deleted file mode 100644
index 5f137dda23..0000000000
--- a/src/secp256k1/src/bench_schnorr_verify.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/**********************************************************************
- * Copyright (c) 2014 Pieter Wuille *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
- **********************************************************************/
-
-#include <stdio.h>
-#include <string.h>
-
-#include "include/secp256k1.h"
-#include "include/secp256k1_schnorr.h"
-#include "util.h"
-#include "bench.h"
-
-typedef struct {
- unsigned char key[32];
- unsigned char sig[64];
- unsigned char pubkey[33];
- size_t pubkeylen;
-} benchmark_schnorr_sig_t;
-
-typedef struct {
- secp256k1_context *ctx;
- unsigned char msg[32];
- benchmark_schnorr_sig_t sigs[64];
- int numsigs;
-} benchmark_schnorr_verify_t;
-
-static void benchmark_schnorr_init(void* arg) {
- int i, k;
- benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg;
-
- for (i = 0; i < 32; i++) {
- data->msg[i] = 1 + i;
- }
- for (k = 0; k < data->numsigs; k++) {
- secp256k1_pubkey pubkey;
- for (i = 0; i < 32; i++) {
- data->sigs[k].key[i] = 33 + i + k;
- }
- secp256k1_schnorr_sign(data->ctx, data->sigs[k].sig, data->msg, data->sigs[k].key, NULL, NULL);
- data->sigs[k].pubkeylen = 33;
- CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->sigs[k].key));
- CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->sigs[k].pubkey, &data->sigs[k].pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED));
- }
-}
-
-static void benchmark_schnorr_verify(void* arg) {
- int i;
- benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg;
-
- for (i = 0; i < 20000 / data->numsigs; i++) {
- secp256k1_pubkey pubkey;
- data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
- CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->sigs[0].pubkey, data->sigs[0].pubkeylen));
- CHECK(secp256k1_schnorr_verify(data->ctx, data->sigs[0].sig, data->msg, &pubkey) == ((i & 0xFF) == 0));
- data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
- }
-}
-
-
-
-int main(void) {
- benchmark_schnorr_verify_t data;
-
- data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
-
- data.numsigs = 1;
- run_benchmark("schnorr_verify", benchmark_schnorr_verify, benchmark_schnorr_init, NULL, &data, 10, 20000);
-
- secp256k1_context_destroy(data.ctx);
- return 0;
-}
diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h
index 9a42e519bd..453bb11880 100644
--- a/src/secp256k1/src/ecdsa_impl.h
+++ b/src/secp256k1/src/ecdsa_impl.h
@@ -225,14 +225,12 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const
#if defined(EXHAUSTIVE_TEST_ORDER)
{
secp256k1_scalar computed_r;
- int overflow = 0;
secp256k1_ge pr_ge;
secp256k1_ge_set_gej(&pr_ge, &pr);
secp256k1_fe_normalize(&pr_ge.x);
secp256k1_fe_get_b32(c, &pr_ge.x);
- secp256k1_scalar_set_b32(&computed_r, c, &overflow);
- /* we fully expect overflow */
+ secp256k1_scalar_set_b32(&computed_r, c, NULL);
return secp256k1_scalar_eq(sigr, &computed_r);
}
#else
@@ -285,14 +283,10 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
secp256k1_fe_normalize(&r.y);
secp256k1_fe_get_b32(b, &r.x);
secp256k1_scalar_set_b32(sigr, b, &overflow);
- if (secp256k1_scalar_is_zero(sigr)) {
- /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature.
- * This branch is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N.
- */
- secp256k1_gej_clear(&rp);
- secp256k1_ge_clear(&r);
- return 0;
- }
+ /* These two conditions should be checked before calling */
+ VERIFY_CHECK(!secp256k1_scalar_is_zero(sigr));
+ VERIFY_CHECK(overflow == 0);
+
if (recid) {
/* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log
* of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria.
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 7b8c079608..234c13a644 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -38,10 +38,6 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
}
VERIFY_CHECK(r == 1);
}
-#else
-static void secp256k1_fe_verify(const secp256k1_fe *a) {
- (void)a;
-}
#endif
static void secp256k1_fe_normalize(secp256k1_fe *r) {
@@ -325,17 +321,17 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
}
static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
- int i;
- r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
- r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
- for (i=0; i<32; i++) {
- int j;
- for (j=0; j<4; j++) {
- int limb = (8*i+2*j)/26;
- int shift = (8*i+2*j)%26;
- r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift;
- }
- }
+ r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24);
+ r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22);
+ r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20);
+ r->n[3] = (uint32_t)((a[22] >> 6) & 0x3) | ((uint32_t)a[21] << 2) | ((uint32_t)a[20] << 10) | ((uint32_t)a[19] << 18);
+ r->n[4] = (uint32_t)a[18] | ((uint32_t)a[17] << 8) | ((uint32_t)a[16] << 16) | ((uint32_t)(a[15] & 0x3) << 24);
+ r->n[5] = (uint32_t)((a[15] >> 2) & 0x3f) | ((uint32_t)a[14] << 6) | ((uint32_t)a[13] << 14) | ((uint32_t)(a[12] & 0xf) << 22);
+ r->n[6] = (uint32_t)((a[12] >> 4) & 0xf) | ((uint32_t)a[11] << 4) | ((uint32_t)a[10] << 12) | ((uint32_t)(a[9] & 0x3f) << 20);
+ r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18);
+ r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24);
+ r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14);
+
if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) {
return 0;
}
@@ -349,21 +345,42 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
- int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
- for (i=0; i<32; i++) {
- int j;
- int c = 0;
- for (j=0; j<4; j++) {
- int limb = (8*i+2*j)/26;
- int shift = (8*i+2*j)%26;
- c |= ((a->n[limb] >> shift) & 0x3) << (2 * j);
- }
- r[31-i] = c;
- }
+ r[0] = (a->n[9] >> 14) & 0xff;
+ r[1] = (a->n[9] >> 6) & 0xff;
+ r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3);
+ r[3] = (a->n[8] >> 16) & 0xff;
+ r[4] = (a->n[8] >> 8) & 0xff;
+ r[5] = a->n[8] & 0xff;
+ r[6] = (a->n[7] >> 18) & 0xff;
+ r[7] = (a->n[7] >> 10) & 0xff;
+ r[8] = (a->n[7] >> 2) & 0xff;
+ r[9] = ((a->n[7] & 0x3) << 6) | ((a->n[6] >> 20) & 0x3f);
+ r[10] = (a->n[6] >> 12) & 0xff;
+ r[11] = (a->n[6] >> 4) & 0xff;
+ r[12] = ((a->n[6] & 0xf) << 4) | ((a->n[5] >> 22) & 0xf);
+ r[13] = (a->n[5] >> 14) & 0xff;
+ r[14] = (a->n[5] >> 6) & 0xff;
+ r[15] = ((a->n[5] & 0x3f) << 2) | ((a->n[4] >> 24) & 0x3);
+ r[16] = (a->n[4] >> 16) & 0xff;
+ r[17] = (a->n[4] >> 8) & 0xff;
+ r[18] = a->n[4] & 0xff;
+ r[19] = (a->n[3] >> 18) & 0xff;
+ r[20] = (a->n[3] >> 10) & 0xff;
+ r[21] = (a->n[3] >> 2) & 0xff;
+ r[22] = ((a->n[3] & 0x3) << 6) | ((a->n[2] >> 20) & 0x3f);
+ r[23] = (a->n[2] >> 12) & 0xff;
+ r[24] = (a->n[2] >> 4) & 0xff;
+ r[25] = ((a->n[2] & 0xf) << 4) | ((a->n[1] >> 22) & 0xf);
+ r[26] = (a->n[1] >> 14) & 0xff;
+ r[27] = (a->n[1] >> 6) & 0xff;
+ r[28] = ((a->n[1] & 0x3f) << 2) | ((a->n[0] >> 24) & 0x3);
+ r[29] = (a->n[0] >> 16) & 0xff;
+ r[30] = (a->n[0] >> 8) & 0xff;
+ r[31] = a->n[0] & 0xff;
}
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index 7a99eb21ec..8e8b286baf 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -49,10 +49,6 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
}
VERIFY_CHECK(r == 1);
}
-#else
-static void secp256k1_fe_verify(const secp256k1_fe *a) {
- (void)a;
-}
#endif
static void secp256k1_fe_normalize(secp256k1_fe *r) {
@@ -288,16 +284,40 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
}
static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
- int i;
- r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
- for (i=0; i<32; i++) {
- int j;
- for (j=0; j<2; j++) {
- int limb = (8*i+4*j)/52;
- int shift = (8*i+4*j)%52;
- r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift;
- }
- }
+ r->n[0] = (uint64_t)a[31]
+ | ((uint64_t)a[30] << 8)
+ | ((uint64_t)a[29] << 16)
+ | ((uint64_t)a[28] << 24)
+ | ((uint64_t)a[27] << 32)
+ | ((uint64_t)a[26] << 40)
+ | ((uint64_t)(a[25] & 0xF) << 48);
+ r->n[1] = (uint64_t)((a[25] >> 4) & 0xF)
+ | ((uint64_t)a[24] << 4)
+ | ((uint64_t)a[23] << 12)
+ | ((uint64_t)a[22] << 20)
+ | ((uint64_t)a[21] << 28)
+ | ((uint64_t)a[20] << 36)
+ | ((uint64_t)a[19] << 44);
+ r->n[2] = (uint64_t)a[18]
+ | ((uint64_t)a[17] << 8)
+ | ((uint64_t)a[16] << 16)
+ | ((uint64_t)a[15] << 24)
+ | ((uint64_t)a[14] << 32)
+ | ((uint64_t)a[13] << 40)
+ | ((uint64_t)(a[12] & 0xF) << 48);
+ r->n[3] = (uint64_t)((a[12] >> 4) & 0xF)
+ | ((uint64_t)a[11] << 4)
+ | ((uint64_t)a[10] << 12)
+ | ((uint64_t)a[9] << 20)
+ | ((uint64_t)a[8] << 28)
+ | ((uint64_t)a[7] << 36)
+ | ((uint64_t)a[6] << 44);
+ r->n[4] = (uint64_t)a[5]
+ | ((uint64_t)a[4] << 8)
+ | ((uint64_t)a[3] << 16)
+ | ((uint64_t)a[2] << 24)
+ | ((uint64_t)a[1] << 32)
+ | ((uint64_t)a[0] << 40);
if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) {
return 0;
}
@@ -311,21 +331,42 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
- int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
- for (i=0; i<32; i++) {
- int j;
- int c = 0;
- for (j=0; j<2; j++) {
- int limb = (8*i+4*j)/52;
- int shift = (8*i+4*j)%52;
- c |= ((a->n[limb] >> shift) & 0xF) << (4 * j);
- }
- r[31-i] = c;
- }
+ r[0] = (a->n[4] >> 40) & 0xFF;
+ r[1] = (a->n[4] >> 32) & 0xFF;
+ r[2] = (a->n[4] >> 24) & 0xFF;
+ r[3] = (a->n[4] >> 16) & 0xFF;
+ r[4] = (a->n[4] >> 8) & 0xFF;
+ r[5] = a->n[4] & 0xFF;
+ r[6] = (a->n[3] >> 44) & 0xFF;
+ r[7] = (a->n[3] >> 36) & 0xFF;
+ r[8] = (a->n[3] >> 28) & 0xFF;
+ r[9] = (a->n[3] >> 20) & 0xFF;
+ r[10] = (a->n[3] >> 12) & 0xFF;
+ r[11] = (a->n[3] >> 4) & 0xFF;
+ r[12] = ((a->n[2] >> 48) & 0xF) | ((a->n[3] & 0xF) << 4);
+ r[13] = (a->n[2] >> 40) & 0xFF;
+ r[14] = (a->n[2] >> 32) & 0xFF;
+ r[15] = (a->n[2] >> 24) & 0xFF;
+ r[16] = (a->n[2] >> 16) & 0xFF;
+ r[17] = (a->n[2] >> 8) & 0xFF;
+ r[18] = a->n[2] & 0xFF;
+ r[19] = (a->n[1] >> 44) & 0xFF;
+ r[20] = (a->n[1] >> 36) & 0xFF;
+ r[21] = (a->n[1] >> 28) & 0xFF;
+ r[22] = (a->n[1] >> 20) & 0xFF;
+ r[23] = (a->n[1] >> 12) & 0xFF;
+ r[24] = (a->n[1] >> 4) & 0xFF;
+ r[25] = ((a->n[0] >> 48) & 0xF) | ((a->n[1] & 0xF) << 4);
+ r[26] = (a->n[0] >> 40) & 0xFF;
+ r[27] = (a->n[0] >> 32) & 0xFF;
+ r[28] = (a->n[0] >> 24) & 0xFF;
+ r[29] = (a->n[0] >> 16) & 0xFF;
+ r[30] = (a->n[0] >> 8) & 0xFF;
+ r[31] = a->n[0] & 0xFF;
}
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index 2e192b62fd..7d723532ff 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -200,12 +200,6 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
secp256k1_fe_clear(&r->z);
}
-static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
- r->infinity = 1;
- secp256k1_fe_clear(&r->x);
- secp256k1_fe_clear(&r->y);
-}
-
static void secp256k1_gej_clear(secp256k1_gej *r) {
r->infinity = 0;
secp256k1_fe_clear(&r->x);
diff --git a/src/secp256k1/src/modules/ecdh/main_impl.h b/src/secp256k1/src/modules/ecdh/main_impl.h
index c23e4f82f7..9e30fb73dd 100644
--- a/src/secp256k1/src/modules/ecdh/main_impl.h
+++ b/src/secp256k1/src/modules/ecdh/main_impl.h
@@ -16,10 +16,10 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se
secp256k1_gej res;
secp256k1_ge pt;
secp256k1_scalar s;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(result != NULL);
ARG_CHECK(point != NULL);
ARG_CHECK(scalar != NULL);
- (void)ctx;
secp256k1_pubkey_load(ctx, &pt, point);
secp256k1_scalar_set_b32(&s, scalar, &overflow);
diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h
index 7badc9033f..85a5d0a9a6 100644
--- a/src/secp256k1/src/modules/ecdh/tests_impl.h
+++ b/src/secp256k1/src/modules/ecdh/tests_impl.h
@@ -7,6 +7,35 @@
#ifndef _SECP256K1_MODULE_ECDH_TESTS_
#define _SECP256K1_MODULE_ECDH_TESTS_
+void test_ecdh_api(void) {
+ /* Setup context that just counts errors */
+ secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+ secp256k1_pubkey point;
+ unsigned char res[32];
+ unsigned char s_one[32] = { 0 };
+ int32_t ecount = 0;
+ s_one[31] = 1;
+
+ secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount);
+ CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
+
+ /* Check all NULLs are detected */
+ CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
+ CHECK(ecount == 0);
+ CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
+ CHECK(ecount == 3);
+
+ /* Cleanup */
+ secp256k1_context_destroy(tctx);
+}
+
void test_ecdh_generator_basepoint(void) {
unsigned char s_one[32] = { 0 };
secp256k1_pubkey point[2];
@@ -68,6 +97,7 @@ void test_bad_scalar(void) {
}
void run_ecdh_tests(void) {
+ test_ecdh_api();
test_ecdh_generator_basepoint();
test_bad_scalar();
}
diff --git a/src/secp256k1/src/modules/recovery/main_impl.h b/src/secp256k1/src/modules/recovery/main_impl.h
index 86f2f0cb2b..c6fbe23981 100755
--- a/src/secp256k1/src/modules/recovery/main_impl.h
+++ b/src/secp256k1/src/modules/recovery/main_impl.h
@@ -179,7 +179,7 @@ int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubk
ARG_CHECK(pubkey != NULL);
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature);
- ARG_CHECK(recid >= 0 && recid < 4);
+ VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */
secp256k1_scalar_set_b32(&m, msg32, NULL);
if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) {
secp256k1_pubkey_save(pubkey, &q);
diff --git a/src/secp256k1/src/modules/recovery/tests_impl.h b/src/secp256k1/src/modules/recovery/tests_impl.h
index 8932d5f0af..765c7dd81e 100644
--- a/src/secp256k1/src/modules/recovery/tests_impl.h
+++ b/src/secp256k1/src/modules/recovery/tests_impl.h
@@ -7,6 +7,146 @@
#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_
#define _SECP256K1_MODULE_RECOVERY_TESTS_
+static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
+ (void) msg32;
+ (void) key32;
+ (void) algo16;
+ (void) data;
+
+ /* On the first run, return 0 to force a second run */
+ if (counter == 0) {
+ memset(nonce32, 0, 32);
+ return 1;
+ }
+ /* On the second run, return an overflow to force a third run */
+ if (counter == 1) {
+ memset(nonce32, 0xff, 32);
+ return 1;
+ }
+ /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */
+ memset(nonce32, 1, 32);
+ return secp256k1_rand_bits(1);
+}
+
+void test_ecdsa_recovery_api(void) {
+ /* Setup contexts that just count errors */
+ secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+ secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+ secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
+ secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+ secp256k1_pubkey pubkey;
+ secp256k1_pubkey recpubkey;
+ secp256k1_ecdsa_signature normal_sig;
+ secp256k1_ecdsa_recoverable_signature recsig;
+ unsigned char privkey[32] = { 1 };
+ unsigned char message[32] = { 2 };
+ int32_t ecount = 0;
+ int recid = 0;
+ unsigned char sig[74];
+ unsigned char zero_privkey[32] = { 0 };
+ unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
+
+ /* Construct and verify corresponding public key. */
+ CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
+
+ /* Check bad contexts and NULLs for signing */
+ ecount = 0;
+ CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0);
+ CHECK(ecount == 4);
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0);
+ CHECK(ecount == 5);
+ /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */
+ secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL);
+ CHECK(ecount == 5);
+ /* These will all fail, but not in ARG_CHECK way */
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0);
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0);
+ /* This one will succeed. */
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
+ CHECK(ecount == 5);
+
+ /* Check signing with a goofy nonce function */
+
+ /* Check bad contexts and NULLs for recovery */
+ ecount = 0;
+ CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0);
+ CHECK(ecount == 4);
+ CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0);
+ CHECK(ecount == 5);
+
+ /* Check NULLs for conversion */
+ CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1);
+ ecount = 0;
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1);
+
+ /* Check NULLs for de/serialization */
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
+ ecount = 0;
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1);
+
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0);
+ CHECK(ecount == 4);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0);
+ CHECK(ecount == 5);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0);
+ CHECK(ecount == 6);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0);
+ CHECK(ecount == 7);
+ /* overflow in signature will fail but not affect ecount */
+ memcpy(sig, over_privkey, 32);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0);
+ CHECK(ecount == 7);
+
+ /* cleanup */
+ secp256k1_context_destroy(none);
+ secp256k1_context_destroy(sign);
+ secp256k1_context_destroy(vrfy);
+ secp256k1_context_destroy(both);
+}
+
void test_ecdsa_recovery_end_to_end(void) {
unsigned char extra[32] = {0x00};
unsigned char privkey[32];
@@ -241,6 +381,9 @@ void test_ecdsa_recovery_edge_cases(void) {
void run_recovery_tests(void) {
int i;
+ for (i = 0; i < count; i++) {
+ test_ecdsa_recovery_api();
+ }
for (i = 0; i < 64*count; i++) {
test_ecdsa_recovery_end_to_end();
}
diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h
index f5b2376407..2690d86558 100644
--- a/src/secp256k1/src/scalar_impl.h
+++ b/src/secp256k1/src/scalar_impl.h
@@ -66,88 +66,79 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
#else
secp256k1_scalar *t;
int i;
- /* First compute x ^ (2^N - 1) for some values of N. */
- secp256k1_scalar x2, x3, x4, x6, x7, x8, x15, x30, x60, x120, x127;
+ /* First compute xN as x ^ (2^N - 1) for some values of N,
+ * and uM as x ^ M for some values of M. */
+ secp256k1_scalar x2, x3, x6, x8, x14, x28, x56, x112, x126;
+ secp256k1_scalar u2, u5, u9, u11, u13;
- secp256k1_scalar_sqr(&x2, x);
- secp256k1_scalar_mul(&x2, &x2, x);
+ secp256k1_scalar_sqr(&u2, x);
+ secp256k1_scalar_mul(&x2, &u2, x);
+ secp256k1_scalar_mul(&u5, &u2, &x2);
+ secp256k1_scalar_mul(&x3, &u5, &u2);
+ secp256k1_scalar_mul(&u9, &x3, &u2);
+ secp256k1_scalar_mul(&u11, &u9, &u2);
+ secp256k1_scalar_mul(&u13, &u11, &u2);
- secp256k1_scalar_sqr(&x3, &x2);
- secp256k1_scalar_mul(&x3, &x3, x);
-
- secp256k1_scalar_sqr(&x4, &x3);
- secp256k1_scalar_mul(&x4, &x4, x);
-
- secp256k1_scalar_sqr(&x6, &x4);
+ secp256k1_scalar_sqr(&x6, &u13);
secp256k1_scalar_sqr(&x6, &x6);
- secp256k1_scalar_mul(&x6, &x6, &x2);
-
- secp256k1_scalar_sqr(&x7, &x6);
- secp256k1_scalar_mul(&x7, &x7, x);
+ secp256k1_scalar_mul(&x6, &x6, &u11);
- secp256k1_scalar_sqr(&x8, &x7);
- secp256k1_scalar_mul(&x8, &x8, x);
+ secp256k1_scalar_sqr(&x8, &x6);
+ secp256k1_scalar_sqr(&x8, &x8);
+ secp256k1_scalar_mul(&x8, &x8, &x2);
- secp256k1_scalar_sqr(&x15, &x8);
- for (i = 0; i < 6; i++) {
- secp256k1_scalar_sqr(&x15, &x15);
+ secp256k1_scalar_sqr(&x14, &x8);
+ for (i = 0; i < 5; i++) {
+ secp256k1_scalar_sqr(&x14, &x14);
}
- secp256k1_scalar_mul(&x15, &x15, &x7);
+ secp256k1_scalar_mul(&x14, &x14, &x6);
- secp256k1_scalar_sqr(&x30, &x15);
- for (i = 0; i < 14; i++) {
- secp256k1_scalar_sqr(&x30, &x30);
+ secp256k1_scalar_sqr(&x28, &x14);
+ for (i = 0; i < 13; i++) {
+ secp256k1_scalar_sqr(&x28, &x28);
}
- secp256k1_scalar_mul(&x30, &x30, &x15);
+ secp256k1_scalar_mul(&x28, &x28, &x14);
- secp256k1_scalar_sqr(&x60, &x30);
- for (i = 0; i < 29; i++) {
- secp256k1_scalar_sqr(&x60, &x60);
+ secp256k1_scalar_sqr(&x56, &x28);
+ for (i = 0; i < 27; i++) {
+ secp256k1_scalar_sqr(&x56, &x56);
}
- secp256k1_scalar_mul(&x60, &x60, &x30);
+ secp256k1_scalar_mul(&x56, &x56, &x28);
- secp256k1_scalar_sqr(&x120, &x60);
- for (i = 0; i < 59; i++) {
- secp256k1_scalar_sqr(&x120, &x120);
+ secp256k1_scalar_sqr(&x112, &x56);
+ for (i = 0; i < 55; i++) {
+ secp256k1_scalar_sqr(&x112, &x112);
}
- secp256k1_scalar_mul(&x120, &x120, &x60);
+ secp256k1_scalar_mul(&x112, &x112, &x56);
- secp256k1_scalar_sqr(&x127, &x120);
- for (i = 0; i < 6; i++) {
- secp256k1_scalar_sqr(&x127, &x127);
+ secp256k1_scalar_sqr(&x126, &x112);
+ for (i = 0; i < 13; i++) {
+ secp256k1_scalar_sqr(&x126, &x126);
}
- secp256k1_scalar_mul(&x127, &x127, &x7);
+ secp256k1_scalar_mul(&x126, &x126, &x14);
- /* Then accumulate the final result (t starts at x127). */
- t = &x127;
- for (i = 0; i < 2; i++) { /* 0 */
+ /* Then accumulate the final result (t starts at x126). */
+ t = &x126;
+ for (i = 0; i < 3; i++) {
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
+ secp256k1_scalar_mul(t, t, &u5); /* 101 */
for (i = 0; i < 4; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x3); /* 111 */
- for (i = 0; i < 2; i++) { /* 0 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 2; i++) { /* 0 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 2; i++) { /* 0 */
+ for (i = 0; i < 4; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 4; i++) { /* 0 */
+ secp256k1_scalar_mul(t, t, &u5); /* 101 */
+ for (i = 0; i < 5; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x3); /* 111 */
- for (i = 0; i < 3; i++) { /* 0 */
+ secp256k1_scalar_mul(t, t, &u11); /* 1011 */
+ for (i = 0; i < 4; i++) {
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x2); /* 11 */
+ secp256k1_scalar_mul(t, t, &u11); /* 1011 */
for (i = 0; i < 4; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
@@ -156,38 +147,26 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x3); /* 111 */
- for (i = 0; i < 4; i++) { /* 00 */
+ for (i = 0; i < 6; i++) { /* 00 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (i = 0; i < 2; i++) { /* 0 */
+ secp256k1_scalar_mul(t, t, &u13); /* 1101 */
+ for (i = 0; i < 4; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 2; i++) { /* 0 */
+ secp256k1_scalar_mul(t, t, &u5); /* 101 */
+ for (i = 0; i < 3; i++) {
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
+ secp256k1_scalar_mul(t, t, &x3); /* 111 */
for (i = 0; i < 5; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x4); /* 1111 */
- for (i = 0; i < 2; i++) { /* 0 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 3; i++) { /* 00 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 4; i++) { /* 000 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 2; i++) { /* 0 */
+ secp256k1_scalar_mul(t, t, &u9); /* 1001 */
+ for (i = 0; i < 6; i++) { /* 000 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
+ secp256k1_scalar_mul(t, t, &u5); /* 101 */
for (i = 0; i < 10; i++) { /* 0000000 */
secp256k1_scalar_sqr(t, t);
}
@@ -200,50 +179,34 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x8); /* 11111111 */
- for (i = 0; i < 2; i++) { /* 0 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 3; i++) { /* 00 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 3; i++) { /* 00 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
for (i = 0; i < 5; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x4); /* 1111 */
- for (i = 0; i < 2; i++) { /* 0 */
+ secp256k1_scalar_mul(t, t, &u9); /* 1001 */
+ for (i = 0; i < 6; i++) { /* 00 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 5; i++) { /* 000 */
+ secp256k1_scalar_mul(t, t, &u11); /* 1011 */
+ for (i = 0; i < 4; i++) {
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (i = 0; i < 4; i++) { /* 00 */
+ secp256k1_scalar_mul(t, t, &u13); /* 1101 */
+ for (i = 0; i < 5; i++) {
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (i = 0; i < 2; i++) { /* 0 */
+ for (i = 0; i < 6; i++) { /* 00 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 8; i++) { /* 000000 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (i = 0; i < 3; i++) { /* 0 */
+ secp256k1_scalar_mul(t, t, &u13); /* 1101 */
+ for (i = 0; i < 10; i++) { /* 000000 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (i = 0; i < 3; i++) { /* 00 */
+ secp256k1_scalar_mul(t, t, &u13); /* 1101 */
+ for (i = 0; i < 4; i++) {
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
+ secp256k1_scalar_mul(t, t, &u9); /* 1001 */
for (i = 0; i < 6; i++) { /* 00000 */
secp256k1_scalar_sqr(t, t);
}
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index fb8b882faa..4f8c01655b 100755..100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -424,6 +424,33 @@ int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *p
return ret;
}
+int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) {
+ secp256k1_scalar sec;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(seckey != NULL);
+
+ secp256k1_scalar_set_b32(&sec, seckey, NULL);
+ secp256k1_scalar_negate(&sec, &sec);
+ secp256k1_scalar_get_b32(seckey, &sec);
+
+ return 1;
+}
+
+int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) {
+ int ret = 0;
+ secp256k1_ge p;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(pubkey != NULL);
+
+ ret = secp256k1_pubkey_load(ctx, &p, pubkey);
+ memset(pubkey, 0, sizeof(*pubkey));
+ if (ret) {
+ secp256k1_ge_neg(&p, &p);
+ secp256k1_pubkey_save(pubkey, &p);
+ }
+ return ret;
+}
+
int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
secp256k1_scalar term;
secp256k1_scalar sec;
@@ -552,10 +579,6 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *
# include "modules/ecdh/main_impl.h"
#endif
-#ifdef ENABLE_MODULE_SCHNORR
-# include "modules/schnorr/main_impl.h"
-#endif
-
#ifdef ENABLE_MODULE_RECOVERY
# include "modules/recovery/main_impl.h"
#endif
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index 9ae7d30281..3d9bd5ebb4 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -10,6 +10,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <time.h>
@@ -135,6 +136,7 @@ void random_scalar_order(secp256k1_scalar *num) {
void run_context_tests(void) {
secp256k1_pubkey pubkey;
+ secp256k1_pubkey zero_pubkey;
secp256k1_ecdsa_signature sig;
unsigned char ctmp[32];
int32_t ecount;
@@ -149,6 +151,8 @@ void run_context_tests(void) {
secp256k1_scalar msg, key, nonce;
secp256k1_scalar sigr, sigs;
+ memset(&zero_pubkey, 0, sizeof(zero_pubkey));
+
ecount = 0;
ecount2 = 10;
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
@@ -201,12 +205,20 @@ void run_context_tests(void) {
CHECK(ecount == 2);
CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0);
CHECK(ecount2 == 13);
- CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);
+ CHECK(secp256k1_ec_pubkey_negate(vrfy, &pubkey) == 1);
CHECK(ecount == 2);
- CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0);
+ CHECK(secp256k1_ec_pubkey_negate(sign, &pubkey) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ec_pubkey_negate(sign, NULL) == 0);
+ CHECK(ecount2 == 14);
+ CHECK(secp256k1_ec_pubkey_negate(vrfy, &zero_pubkey) == 0);
CHECK(ecount == 3);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0);
+ CHECK(ecount == 4);
CHECK(secp256k1_context_randomize(sign, NULL) == 1);
- CHECK(ecount2 == 13);
+ CHECK(ecount2 == 14);
secp256k1_context_set_illegal_callback(vrfy, NULL, NULL);
secp256k1_context_set_illegal_callback(sign, NULL, NULL);
@@ -1879,9 +1891,9 @@ void test_ge(void) {
*
* When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well.
*/
- secp256k1_ge *ge = (secp256k1_ge *)malloc(sizeof(secp256k1_ge) * (1 + 4 * runs));
- secp256k1_gej *gej = (secp256k1_gej *)malloc(sizeof(secp256k1_gej) * (1 + 4 * runs));
- secp256k1_fe *zinv = (secp256k1_fe *)malloc(sizeof(secp256k1_fe) * (1 + 4 * runs));
+ secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs));
+ secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs));
+ secp256k1_fe *zinv = (secp256k1_fe *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs));
secp256k1_fe zf;
secp256k1_fe zfi2, zfi3;
@@ -1919,7 +1931,7 @@ void test_ge(void) {
/* Compute z inverses. */
{
- secp256k1_fe *zs = malloc(sizeof(secp256k1_fe) * (1 + 4 * runs));
+ secp256k1_fe *zs = checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs));
for (i = 0; i < 4 * runs + 1; i++) {
if (i == 0) {
/* The point at infinity does not have a meaningful z inverse. Any should do. */
@@ -2020,7 +2032,7 @@ void test_ge(void) {
/* Test adding all points together in random order equals infinity. */
{
secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY;
- secp256k1_gej *gej_shuffled = (secp256k1_gej *)malloc((4 * runs + 1) * sizeof(secp256k1_gej));
+ secp256k1_gej *gej_shuffled = (secp256k1_gej *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej));
for (i = 0; i < 4 * runs + 1; i++) {
gej_shuffled[i] = gej[i];
}
@@ -2041,9 +2053,9 @@ void test_ge(void) {
/* Test batch gej -> ge conversion with and without known z ratios. */
{
- secp256k1_fe *zr = (secp256k1_fe *)malloc((4 * runs + 1) * sizeof(secp256k1_fe));
- secp256k1_ge *ge_set_table = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge));
- secp256k1_ge *ge_set_all = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge));
+ secp256k1_fe *zr = (secp256k1_fe *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_fe));
+ secp256k1_ge *ge_set_table = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));
+ secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));
for (i = 0; i < 4 * runs + 1; i++) {
/* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */
if (i < 4 * runs) {
@@ -3436,6 +3448,7 @@ void test_ecdsa_end_to_end(void) {
unsigned char pubkeyc[65];
size_t pubkeyclen = 65;
secp256k1_pubkey pubkey;
+ secp256k1_pubkey pubkey_tmp;
unsigned char seckey[300];
size_t seckeylen = 300;
@@ -3457,6 +3470,13 @@ void test_ecdsa_end_to_end(void) {
memset(&pubkey, 0, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
+ /* Verify negation changes the key and changes it back */
+ memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1);
+ CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0);
+ CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1);
+ CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0);
+
/* Verify private key import and export. */
CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1));
CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1);
@@ -4383,10 +4403,6 @@ void run_ecdsa_openssl(void) {
# include "modules/ecdh/tests_impl.h"
#endif
-#ifdef ENABLE_MODULE_SCHNORR
-# include "modules/schnorr/tests_impl.h"
-#endif
-
#ifdef ENABLE_MODULE_RECOVERY
# include "modules/recovery/tests_impl.h"
#endif
@@ -4504,11 +4520,6 @@ int main(int argc, char **argv) {
run_ecdsa_openssl();
#endif
-#ifdef ENABLE_MODULE_SCHNORR
- /* Schnorr tests */
- run_schnorr_tests();
-#endif
-
#ifdef ENABLE_MODULE_RECOVERY
/* ECDSA pubkey recovery tests */
run_recovery_tests();
diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c
index bda6ee475c..b040bb0733 100644
--- a/src/secp256k1/src/tests_exhaustive.c
+++ b/src/secp256k1/src/tests_exhaustive.c
@@ -26,6 +26,11 @@
#include "secp256k1.c"
#include "testrand_impl.h"
+#ifdef ENABLE_MODULE_RECOVERY
+#include "src/modules/recovery/main_impl.h"
+#include "include/secp256k1_recovery.h"
+#endif
+
/** stolen from tests.c */
void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
CHECK(a->infinity == b->infinity);
@@ -77,7 +82,7 @@ int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned cha
* function with an increased `attempt`. So if attempt > 0 this means we
* need to change the nonce to avoid an infinite loop. */
if (attempt > 0) {
- (*idata)++;
+ *idata = (*idata + 1) % EXHAUSTIVE_TEST_ORDER;
}
secp256k1_scalar_set_int(&s, *idata);
secp256k1_scalar_get_b32(nonce32, &s);
@@ -244,6 +249,7 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou
for (i = 1; i < order; i++) { /* message */
for (j = 1; j < order; j++) { /* key */
for (k = 1; k < order; k++) { /* nonce */
+ const int starting_k = k;
secp256k1_ecdsa_signature sig;
secp256k1_scalar sk, msg, r, s, expected_r;
unsigned char sk32[32], msg32[32];
@@ -262,6 +268,11 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou
CHECK(r == expected_r);
CHECK((k * s) % order == (i + r * j) % order ||
(k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);
+
+ /* Overflow means we've tried every possible nonce */
+ if (k < starting_k) {
+ break;
+ }
}
}
}
@@ -276,6 +287,130 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou
*/
}
+#ifdef ENABLE_MODULE_RECOVERY
+void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {
+ int i, j, k;
+
+ /* Loop */
+ for (i = 1; i < order; i++) { /* message */
+ for (j = 1; j < order; j++) { /* key */
+ for (k = 1; k < order; k++) { /* nonce */
+ const int starting_k = k;
+ secp256k1_fe r_dot_y_normalized;
+ secp256k1_ecdsa_recoverable_signature rsig;
+ secp256k1_ecdsa_signature sig;
+ secp256k1_scalar sk, msg, r, s, expected_r;
+ unsigned char sk32[32], msg32[32];
+ int expected_recid;
+ int recid;
+ secp256k1_scalar_set_int(&msg, i);
+ secp256k1_scalar_set_int(&sk, j);
+ secp256k1_scalar_get_b32(sk32, &sk);
+ secp256k1_scalar_get_b32(msg32, &msg);
+
+ secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k);
+
+ /* Check directly */
+ secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig);
+ r_from_k(&expected_r, group, k);
+ CHECK(r == expected_r);
+ CHECK((k * s) % order == (i + r * j) % order ||
+ (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);
+ /* In computing the recid, there is an overflow condition that is disabled in
+ * scalar_low_impl.h `secp256k1_scalar_set_b32` because almost every r.y value
+ * will exceed the group order, and our signing code always holds out for r
+ * values that don't overflow, so with a proper overflow check the tests would
+ * loop indefinitely. */
+ r_dot_y_normalized = group[k].y;
+ secp256k1_fe_normalize(&r_dot_y_normalized);
+ /* Also the recovery id is flipped depending if we hit the low-s branch */
+ if ((k * s) % order == (i + r * j) % order) {
+ expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 1 : 0;
+ } else {
+ expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 0 : 1;
+ }
+ CHECK(recid == expected_recid);
+
+ /* Convert to a standard sig then check */
+ secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
+ secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig);
+ /* Note that we compute expected_r *after* signing -- this is important
+ * because our nonce-computing function function might change k during
+ * signing. */
+ r_from_k(&expected_r, group, k);
+ CHECK(r == expected_r);
+ CHECK((k * s) % order == (i + r * j) % order ||
+ (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);
+
+ /* Overflow means we've tried every possible nonce */
+ if (k < starting_k) {
+ break;
+ }
+ }
+ }
+ }
+}
+
+void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {
+ /* This is essentially a copy of test_exhaustive_verify, with recovery added */
+ int s, r, msg, key;
+ for (s = 1; s < order; s++) {
+ for (r = 1; r < order; r++) {
+ for (msg = 1; msg < order; msg++) {
+ for (key = 1; key < order; key++) {
+ secp256k1_ge nonconst_ge;
+ secp256k1_ecdsa_recoverable_signature rsig;
+ secp256k1_ecdsa_signature sig;
+ secp256k1_pubkey pk;
+ secp256k1_scalar sk_s, msg_s, r_s, s_s;
+ secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s;
+ int recid = 0;
+ int k, should_verify;
+ unsigned char msg32[32];
+
+ secp256k1_scalar_set_int(&s_s, s);
+ secp256k1_scalar_set_int(&r_s, r);
+ secp256k1_scalar_set_int(&msg_s, msg);
+ secp256k1_scalar_set_int(&sk_s, key);
+ secp256k1_scalar_get_b32(msg32, &msg_s);
+
+ /* Verify by hand */
+ /* Run through every k value that gives us this r and check that *one* works.
+ * Note there could be none, there could be multiple, ECDSA is weird. */
+ should_verify = 0;
+ for (k = 0; k < order; k++) {
+ secp256k1_scalar check_x_s;
+ r_from_k(&check_x_s, group, k);
+ if (r_s == check_x_s) {
+ secp256k1_scalar_set_int(&s_times_k_s, k);
+ secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s);
+ secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s);
+ secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s);
+ should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s);
+ }
+ }
+ /* nb we have a "high s" rule */
+ should_verify &= !secp256k1_scalar_is_high(&s_s);
+
+ /* We would like to try recovering the pubkey and checking that it matches,
+ * but pubkey recovery is impossible in the exhaustive tests (the reason
+ * being that there are 12 nonzero r values, 12 nonzero points, and no
+ * overlap between the sets, so there are no valid signatures). */
+
+ /* Verify by converting to a standard signature and calling verify */
+ secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid);
+ secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
+ memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge));
+ secp256k1_pubkey_save(&pk, &nonconst_ge);
+ CHECK(should_verify ==
+ secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk));
+ }
+ }
+ }
+ }
+}
+#endif
+
int main(void) {
int i;
secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER];
@@ -324,6 +459,12 @@ int main(void) {
test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER);
test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER);
+#ifdef ENABLE_MODULE_RECOVERY
+ test_exhaustive_recovery_sign(ctx, group, EXHAUSTIVE_TEST_ORDER);
+ test_exhaustive_recovery_verify(ctx, group, EXHAUSTIVE_TEST_ORDER);
+#endif
+
+ secp256k1_context_destroy(ctx);
return 0;
}
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index 4eef4ded47..4092a86c91 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -57,7 +57,10 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback *
#endif
/* Like assert(), but when VERIFY is defined, and side-effect safe. */
-#ifdef VERIFY
+#if defined(COVERAGE)
+#define VERIFY_CHECK(check)
+#define VERIFY_SETUP(stmt)
+#elif defined(VERIFY)
#define VERIFY_CHECK CHECK
#define VERIFY_SETUP(stmt) do { stmt; } while(0)
#else
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index c62e6ae838..e6b45a3b5e 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
connman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, "", true);
+ CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", true);
dummyNode1.SetSendVersion(PROTOCOL_VERSION);
GetNodeSignals().InitializeNode(&dummyNode1, *connman);
dummyNode1.nVersion = 1;
@@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
CAddress addr2(ip(0xa0b0c002), NODE_NONE);
- CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, "", true);
+ CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", true);
dummyNode2.SetSendVersion(PROTOCOL_VERSION);
GetNodeSignals().InitializeNode(&dummyNode2, *connman);
dummyNode2.nVersion = 1;
@@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
connman->ClearBanned();
ForceSetArg("-banscore", "111"); // because 11 is my favorite number
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, "", true);
+ CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, CAddress(), "", true);
dummyNode1.SetSendVersion(PROTOCOL_VERSION);
GetNodeSignals().InitializeNode(&dummyNode1, *connman);
dummyNode1.nVersion = 1;
@@ -109,7 +109,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
SetMockTime(nStartTime); // Overrides future calls to GetTime()
CAddress addr(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, "", true);
+ CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, CAddress(), "", true);
dummyNode.SetSendVersion(PROTOCOL_VERSION);
GetNodeSignals().InitializeNode(&dummyNode, *connman);
dummyNode.nVersion = 1;
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 0c7f3e5e23..66354699b2 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -175,12 +175,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
bool fInboundIn = false;
// Test that fFeeler is false by default.
- std::unique_ptr<CNode> pnode1(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, pszDest, fInboundIn));
+ std::unique_ptr<CNode> pnode1(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, fInboundIn));
BOOST_CHECK(pnode1->fInbound == false);
BOOST_CHECK(pnode1->fFeeler == false);
fInboundIn = true;
- std::unique_ptr<CNode> pnode2(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, pszDest, fInboundIn));
+ std::unique_ptr<CNode> pnode2(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, fInboundIn));
BOOST_CHECK(pnode2->fInbound == true);
BOOST_CHECK(pnode2->fFeeler == false);
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index bc98435249..78bfe02b89 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3261,9 +3261,9 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{
LOCK(cs_wallet);
- BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
+ for (const auto& walletEntry : mapWallet)
{
- CWalletTx *pcoin = &walletEntry.second;
+ const CWalletTx *pcoin = &walletEntry.second;
if (!pcoin->IsTrusted())
continue;
@@ -3301,9 +3301,9 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings()
std::set< std::set<CTxDestination> > groupings;
std::set<CTxDestination> grouping;
- BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
+ for (const auto& walletEntry : mapWallet)
{
- CWalletTx *pcoin = &walletEntry.second;
+ const CWalletTx *pcoin = &walletEntry.second;
if (pcoin->tx->vin.size() > 0)
{
diff --git a/test/functional/abandonconflict.py b/test/functional/abandonconflict.py
index 9748757641..c87c02492d 100755
--- a/test/functional/abandonconflict.py
+++ b/test/functional/abandonconflict.py
@@ -73,8 +73,8 @@ class AbandonConflictTest(BitcoinTestFramework):
# Restart the node with a higher min relay fee so the parent tx is no longer in mempool
# TODO: redo with eviction
- stop_node(self.nodes[0],0)
- self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"])
+ self.stop_node(0)
+ self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"])
# Verify txs no longer in either node's mempool
assert_equal(len(self.nodes[0].getrawmempool()), 0)
@@ -100,8 +100,8 @@ class AbandonConflictTest(BitcoinTestFramework):
balance = newbalance
# Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned
- stop_node(self.nodes[0],0)
- self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.00001"])
+ self.stop_node(0)
+ self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.00001"])
assert_equal(len(self.nodes[0].getrawmempool()), 0)
assert_equal(self.nodes[0].getbalance(), balance)
@@ -120,8 +120,8 @@ class AbandonConflictTest(BitcoinTestFramework):
balance = newbalance
# Remove using high relay fee again
- stop_node(self.nodes[0],0)
- self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"])
+ self.stop_node(0)
+ self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"])
assert_equal(len(self.nodes[0].getrawmempool()), 0)
newbalance = self.nodes[0].getbalance()
assert_equal(newbalance, balance - Decimal("24.9996"))
diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py
index 8e301c4379..9d17faac51 100755
--- a/test/functional/assumevalid.py
+++ b/test/functional/assumevalid.py
@@ -45,7 +45,7 @@ from test_framework.mininode import (CBlockHeader,
msg_headers)
from test_framework.script import (CScript, OP_TRUE)
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import (start_node, p2p_port, assert_equal)
+from test_framework.util import (p2p_port, assert_equal)
class BaseNode(NodeConnCB):
def send_header_for_blocks(self, new_blocks):
@@ -63,7 +63,7 @@ class AssumeValidTest(BitcoinTestFramework):
# Start node0. We don't start the other nodes yet since
# we need to pre-mine a block with an invalid transaction
# signature so we can pass in the block hash as assumevalid.
- self.nodes = [start_node(0, self.options.tmpdir)]
+ self.nodes = [self.start_node(0, self.options.tmpdir)]
def send_blocks_until_disconnected(self, node):
"""Keep sending blocks to the node until we're disconnected."""
@@ -162,14 +162,14 @@ class AssumeValidTest(BitcoinTestFramework):
height += 1
# Start node1 and node2 with assumevalid so they accept a block with a bad signature.
- self.nodes.append(start_node(1, self.options.tmpdir,
+ self.nodes.append(self.start_node(1, self.options.tmpdir,
["-assumevalid=" + hex(block102.sha256)]))
node1 = BaseNode() # connects to node1
connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], node1))
node1.add_connection(connections[1])
node1.wait_for_verack()
- self.nodes.append(start_node(2, self.options.tmpdir,
+ self.nodes.append(self.start_node(2, self.options.tmpdir,
["-assumevalid=" + hex(block102.sha256)]))
node2 = BaseNode() # connects to node2
connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], node2))
diff --git a/test/functional/bip9-softforks.py b/test/functional/bip9-softforks.py
index fff47fcca9..b90b0ca628 100755
--- a/test/functional/bip9-softforks.py
+++ b/test/functional/bip9-softforks.py
@@ -239,7 +239,7 @@ class BIP9SoftForksTest(ComparisonTestFramework):
# Restart all
self.test.clear_all_connections()
- stop_nodes(self.nodes)
+ self.stop_nodes()
shutil.rmtree(self.options.tmpdir + "/node0")
self.setup_chain()
self.setup_network()
diff --git a/test/functional/bumpfee.py b/test/functional/bumpfee.py
index aaed420690..d42bab6cbf 100755
--- a/test/functional/bumpfee.py
+++ b/test/functional/bumpfee.py
@@ -38,12 +38,12 @@ class BumpFeeTest(BitcoinTestFramework):
def setup_network(self, split=False):
extra_args = [["-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)]
for i in range(self.num_nodes)]
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
# Encrypt wallet for test_locked_wallet_fails test
self.nodes[1].encryptwallet(WALLET_PASSPHRASE)
bitcoind_processes[1].wait()
- self.nodes[1] = start_node(1, self.options.tmpdir, extra_args[1])
+ self.nodes[1] = self.start_node(1, self.options.tmpdir, extra_args[1])
self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
connect_nodes_bi(self.nodes, 0, 1)
diff --git a/test/functional/disconnect_ban.py b/test/functional/disconnect_ban.py
index f453fc0261..89b68aeb25 100755
--- a/test/functional/disconnect_ban.py
+++ b/test/functional/disconnect_ban.py
@@ -9,10 +9,7 @@ from test_framework.mininode import wait_until
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (assert_equal,
assert_raises_jsonrpc,
- connect_nodes_bi,
- start_node,
- stop_node,
- )
+ connect_nodes_bi)
class DisconnectBanTest(BitcoinTestFramework):
@@ -68,9 +65,9 @@ class DisconnectBanTest(BitcoinTestFramework):
self.nodes[1].setmocktime(old_time + 3)
assert_equal(len(self.nodes[1].listbanned()), 3)
- stop_node(self.nodes[1], 1)
+ self.stop_node(1)
- self.nodes[1] = start_node(1, self.options.tmpdir)
+ self.nodes[1] = self.start_node(1, self.options.tmpdir)
listAfterShutdown = self.nodes[1].listbanned()
assert_equal("127.0.0.0/24", listAfterShutdown[0]['address'])
assert_equal("127.0.0.0/32", listAfterShutdown[1]['address'])
diff --git a/test/functional/forknotify.py b/test/functional/forknotify.py
index 9db61c8350..3bcf0a6795 100755
--- a/test/functional/forknotify.py
+++ b/test/functional/forknotify.py
@@ -21,10 +21,10 @@ class ForkNotifyTest(BitcoinTestFramework):
self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
with open(self.alert_filename, 'w', encoding='utf8'):
pass # Just open then close to create zero-length file
- self.nodes.append(start_node(0, self.options.tmpdir,
+ self.nodes.append(self.start_node(0, self.options.tmpdir,
["-blockversion=2", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]))
# Node1 mines block.version=211 blocks
- self.nodes.append(start_node(1, self.options.tmpdir,
+ self.nodes.append(self.start_node(1, self.options.tmpdir,
["-blockversion=211"]))
connect_nodes(self.nodes[1], 0)
diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py
index 9ddafeb611..c41afe2b93 100755
--- a/test/functional/fundrawtransaction.py
+++ b/test/functional/fundrawtransaction.py
@@ -448,13 +448,13 @@ class RawTransactionsTest(BitcoinTestFramework):
############################################################
# locked wallet test
+ self.stop_node(0)
+ self.stop_node(2)
+ self.stop_node(3)
self.nodes[1].encryptwallet("test")
self.nodes.pop(1)
- stop_node(self.nodes[0], 0)
- stop_node(self.nodes[1], 2)
- stop_node(self.nodes[2], 3)
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir)
# This test is not meant to test fee estimation and we'd like
# to be sure all txs are sent at a consistent desired feerate
for node in self.nodes:
diff --git a/test/functional/import-rescan.py b/test/functional/import-rescan.py
index 5be095e62d..4fc5078217 100755
--- a/test/functional/import-rescan.py
+++ b/test/functional/import-rescan.py
@@ -21,7 +21,7 @@ happened previously.
from test_framework.authproxy import JSONRPCException
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import (start_nodes, connect_nodes, sync_blocks, assert_equal, set_node_times)
+from test_framework.util import (connect_nodes, sync_blocks, assert_equal, set_node_times)
import collections
import enum
@@ -121,7 +121,7 @@ class ImportRescanTest(BitcoinTestFramework):
if import_node.prune:
extra_args[i] += ["-prune=1"]
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
for i in range(1, self.num_nodes):
connect_nodes(self.nodes[i], 0)
diff --git a/test/functional/importmulti.py b/test/functional/importmulti.py
index 9e3491c428..e83e85de13 100755
--- a/test/functional/importmulti.py
+++ b/test/functional/importmulti.py
@@ -428,8 +428,8 @@ class ImportMultiTest (BitcoinTestFramework):
# restart nodes to check for proper serialization/deserialization of watch only address
- stop_nodes(self.nodes)
- self.nodes = start_nodes(2, self.options.tmpdir)
+ self.stop_nodes()
+ self.nodes = self.start_nodes(2, self.options.tmpdir)
address_assert = self.nodes[1].validateaddress(watchonly_address)
assert_equal(address_assert['iswatchonly'], True)
assert_equal(address_assert['ismine'], False)
diff --git a/test/functional/keypool.py b/test/functional/keypool.py
index c276e64c7c..f23a427d1f 100755
--- a/test/functional/keypool.py
+++ b/test/functional/keypool.py
@@ -20,7 +20,7 @@ class KeyPoolTest(BitcoinTestFramework):
nodes[0].encryptwallet('test')
bitcoind_processes[0].wait()
# Restart node 0
- nodes[0] = start_node(0, self.options.tmpdir)
+ nodes[0] = self.start_node(0, self.options.tmpdir)
# Keep creating keys
addr = nodes[0].getnewaddress()
addr_data = nodes[0].validateaddress(addr)
diff --git a/test/functional/listtransactions.py b/test/functional/listtransactions.py
index cba370d8b0..f69f1c5724 100755
--- a/test/functional/listtransactions.py
+++ b/test/functional/listtransactions.py
@@ -24,7 +24,7 @@ class ListTransactionsTest(BitcoinTestFramework):
def setup_nodes(self):
#This test requires mocktime
enable_mocktime()
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir)
def run_test(self):
# Simple send, 0 to 1:
diff --git a/test/functional/maxuploadtarget.py b/test/functional/maxuploadtarget.py
index bff1b53234..66e5bd29e6 100755
--- a/test/functional/maxuploadtarget.py
+++ b/test/functional/maxuploadtarget.py
@@ -146,8 +146,8 @@ class MaxUploadTest(BitcoinTestFramework):
#stop and start node 0 with 1MB maxuploadtarget, whitelist 127.0.0.1
self.log.info("Restarting nodes with -whitelist=127.0.0.1")
- stop_node(self.nodes[0], 0)
- self.nodes[0] = start_node(0, self.options.tmpdir, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"])
+ self.stop_node(0)
+ self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"])
#recreate/reconnect a test node
test_nodes = [TestNode()]
diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py
index 7b15476ea2..e0889fd5e9 100755
--- a/test/functional/mempool_persist.py
+++ b/test/functional/mempool_persist.py
@@ -63,27 +63,27 @@ class MempoolPersistTest(BitcoinTestFramework):
assert_equal(len(self.nodes[1].getrawmempool()), 5)
self.log.debug("Stop-start node0 and node1. Verify that node0 has the transactions in its mempool and node1 does not.")
- stop_nodes(self.nodes)
+ self.stop_nodes()
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir))
- self.nodes.append(start_node(1, self.options.tmpdir))
+ self.nodes.append(self.start_node(0, self.options.tmpdir))
+ self.nodes.append(self.start_node(1, self.options.tmpdir))
# Give bitcoind a second to reload the mempool
time.sleep(1)
assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5)
assert_equal(len(self.nodes[1].getrawmempool()), 0)
self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.")
- stop_nodes(self.nodes)
+ self.stop_nodes()
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-persistmempool=0"]))
+ self.nodes.append(self.start_node(0, self.options.tmpdir, ["-persistmempool=0"]))
# Give bitcoind a second to reload the mempool
time.sleep(1)
assert_equal(len(self.nodes[0].getrawmempool()), 0)
self.log.debug("Stop-start node0. Verify that it has the transactions in its mempool.")
- stop_nodes(self.nodes)
+ self.stop_nodes()
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir))
+ self.nodes.append(self.start_node(0, self.options.tmpdir))
assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5)
if __name__ == '__main__':
diff --git a/test/functional/net.py b/test/functional/net.py
index fb46064441..3ba3764cf9 100755
--- a/test/functional/net.py
+++ b/test/functional/net.py
@@ -29,6 +29,7 @@ class NetTest(BitcoinTestFramework):
self._test_getnettotals()
self._test_getnetworkinginfo()
self._test_getaddednodeinfo()
+ self._test_getpeerinfo()
def _test_connection_count(self):
# connect_nodes_bi connects each node to the other
@@ -88,6 +89,12 @@ class NetTest(BitcoinTestFramework):
assert_raises_jsonrpc(-24, "Node has not been added",
self.nodes[0].getaddednodeinfo, '1.1.1.1')
+ def _test_getpeerinfo(self):
+ peer_info = [x.getpeerinfo() for x in self.nodes]
+ # check both sides of bidirectional connection between nodes
+ # the address bound to on one side will be the source address for the other node
+ assert_equal(peer_info[0][0]['addrbind'], peer_info[1][0]['addr'])
+ assert_equal(peer_info[1][0]['addrbind'], peer_info[0][0]['addr'])
if __name__ == '__main__':
NetTest().main()
diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py
index 24d4d37c42..ab97596ba3 100755
--- a/test/functional/p2p-segwit.py
+++ b/test/functional/p2p-segwit.py
@@ -1495,8 +1495,8 @@ class SegWitTest(BitcoinTestFramework):
sync_blocks(self.nodes)
# Restart with the new binary
- stop_node(node, node_id)
- self.nodes[node_id] = start_node(node_id, self.options.tmpdir)
+ self.stop_node(node_id)
+ self.nodes[node_id] = self.start_node(node_id, self.options.tmpdir)
connect_nodes(self.nodes[0], node_id)
sync_blocks(self.nodes)
diff --git a/test/functional/p2p-versionbits-warning.py b/test/functional/p2p-versionbits-warning.py
index 41921fe14e..df7e8ce5c1 100755
--- a/test/functional/p2p-versionbits-warning.py
+++ b/test/functional/p2p-versionbits-warning.py
@@ -108,22 +108,22 @@ class VersionBitsWarningTest(BitcoinTestFramework):
# is cleared, and restart the node. This should move the versionbit state
# to ACTIVE.
self.nodes[0].generate(VB_PERIOD)
- stop_nodes(self.nodes)
+ self.stop_nodes()
# Empty out the alert file
with open(self.alert_filename, 'w', encoding='utf8') as _:
pass
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args)
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args)
# Connecting one block should be enough to generate an error.
self.nodes[0].generate(1)
assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getinfo()["errors"])
assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getmininginfo()["errors"])
assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getnetworkinfo()["warnings"])
- stop_nodes(self.nodes)
+ self.stop_nodes()
self.test_versionbits_in_alert_file()
# Test framework expects the node to still be running...
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args)
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args)
if __name__ == '__main__':
VersionBitsWarningTest().main()
diff --git a/test/functional/proxy_test.py b/test/functional/proxy_test.py
index 69384d9d85..ae6f843ddc 100755
--- a/test/functional/proxy_test.py
+++ b/test/functional/proxy_test.py
@@ -35,7 +35,6 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
PORT_MIN,
PORT_RANGE,
- start_nodes,
assert_equal,
)
from test_framework.netutil import test_ipv6_local
@@ -90,7 +89,7 @@ class ProxyTest(BitcoinTestFramework):
]
if self.have_ipv6:
args[3] = ['-listen', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion']
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=args)
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args=args)
def node_test(self, node, proxies, auth, test_onion=True):
rv = []
diff --git a/test/functional/pruning.py b/test/functional/pruning.py
index 7995e418c9..4c3501ad77 100755
--- a/test/functional/pruning.py
+++ b/test/functional/pruning.py
@@ -98,7 +98,7 @@ class PruneTest(BitcoinTestFramework):
# Node 2 stays connected, so it hears about the stale blocks and then reorg's when node0 reconnects
# Stopping node 0 also clears its mempool, so it doesn't have node1's transactions to accidentally mine
self.stop_node(0)
- self.nodes[0]=start_node(0, self.options.tmpdir, self.full_node_default_args, timewait=900)
+ self.nodes[0]=self.start_node(0, self.options.tmpdir, self.full_node_default_args, timewait=900)
# Mine 24 blocks in node 1
for i in range(24):
if j == 0:
@@ -126,7 +126,7 @@ class PruneTest(BitcoinTestFramework):
# Reboot node 1 to clear its mempool (hopefully make the invalidate faster)
# Lower the block max size so we don't keep mining all our big mempool transactions (from disconnected blocks)
self.stop_node(1)
- self.nodes[1]=start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
+ self.nodes[1] = self.start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
height = self.nodes[1].getblockcount()
self.log.info("Current block height: %d" % height)
@@ -149,7 +149,7 @@ class PruneTest(BitcoinTestFramework):
# Reboot node1 to clear those giant tx's from mempool
self.stop_node(1)
- self.nodes[1]=start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
+ self.nodes[1] = self.start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
self.log.info("Generating new longer chain of 300 more blocks")
self.nodes[1].generate(300)
@@ -227,13 +227,13 @@ class PruneTest(BitcoinTestFramework):
def manual_test(self, node_number, use_timestamp):
# at this point, node has 995 blocks and has not yet run in prune mode
- node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, timewait=900)
+ node = self.nodes[node_number] = self.start_node(node_number, self.options.tmpdir, timewait=900)
assert_equal(node.getblockcount(), 995)
assert_raises_jsonrpc(-1, "not in prune mode", node.pruneblockchain, 500)
self.stop_node(node_number)
# now re-start in manual pruning mode
- node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-prune=1"], timewait=900)
+ node = self.nodes[node_number] = self.start_node(node_number, self.options.tmpdir, ["-prune=1"], timewait=900)
assert_equal(node.getblockcount(), 995)
def height(index):
@@ -307,7 +307,7 @@ class PruneTest(BitcoinTestFramework):
# stop node, start back up with auto-prune at 550MB, make sure still runs
self.stop_node(node_number)
- self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-prune=550"], timewait=900)
+ self.nodes[node_number] = self.start_node(node_number, self.options.tmpdir, ["-prune=550"], timewait=900)
self.log.info("Success")
@@ -315,7 +315,7 @@ class PruneTest(BitcoinTestFramework):
# check that the pruning node's wallet is still in good shape
self.log.info("Stop and start pruning node to trigger wallet rescan")
self.stop_node(2)
- start_node(2, self.options.tmpdir, ["-prune=550"])
+ self.start_node(2, self.options.tmpdir, ["-prune=550"])
self.log.info("Success")
# check that wallet loads loads successfully when restarting a pruned node after IBD.
@@ -325,7 +325,7 @@ class PruneTest(BitcoinTestFramework):
nds = [self.nodes[0], self.nodes[5]]
sync_blocks(nds, wait=5, timeout=300)
self.stop_node(5) #stop and start to trigger rescan
- start_node(5, self.options.tmpdir, ["-prune=550"])
+ self.start_node(5, self.options.tmpdir, ["-prune=550"])
self.log.info("Success")
def run_test(self):
diff --git a/test/functional/receivedby.py b/test/functional/receivedby.py
index a1cae301c5..2cad6269ac 100755
--- a/test/functional/receivedby.py
+++ b/test/functional/receivedby.py
@@ -32,7 +32,7 @@ class ReceivedByTest(BitcoinTestFramework):
def setup_nodes(self):
#This test requires mocktime
enable_mocktime()
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir)
def run_test(self):
'''
diff --git a/test/functional/reindex.py b/test/functional/reindex.py
index 8b8c5f3e71..b446baa04d 100755
--- a/test/functional/reindex.py
+++ b/test/functional/reindex.py
@@ -10,11 +10,7 @@
"""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import (
- start_nodes,
- stop_nodes,
- assert_equal,
-)
+from test_framework.util import assert_equal
import time
class ReindexTest(BitcoinTestFramework):
@@ -27,9 +23,9 @@ class ReindexTest(BitcoinTestFramework):
def reindex(self, justchainstate=False):
self.nodes[0].generate(3)
blockcount = self.nodes[0].getblockcount()
- stop_nodes(self.nodes)
+ self.stop_nodes()
extra_args = [["-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]]
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
while self.nodes[0].getblockcount() < blockcount:
time.sleep(0.1)
assert_equal(self.nodes[0].getblockcount(), blockcount)
diff --git a/test/functional/rpcbind_test.py b/test/functional/rpcbind_test.py
index efc36481d1..5336cf2ec8 100755
--- a/test/functional/rpcbind_test.py
+++ b/test/functional/rpcbind_test.py
@@ -7,7 +7,7 @@
import socket
import sys
-from test_framework.test_framework import BitcoinTestFramework
+from test_framework.test_framework import BitcoinTestFramework, SkipTest
from test_framework.util import *
from test_framework.netutil import *
@@ -36,10 +36,10 @@ class RPCBindTest(BitcoinTestFramework):
if allow_ips:
base_args += ['-rpcallowip=' + x for x in allow_ips]
binds = ['-rpcbind='+addr for addr in addresses]
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [base_args + binds], connect_to)
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args + binds], connect_to)
pid = bitcoind_processes[0].pid
assert_equal(set(get_bind_addrs(pid)), set(expected))
- stop_nodes(self.nodes)
+ self.stop_nodes()
def run_allowip_test(self, allow_ips, rpchost, rpcport):
'''
@@ -47,17 +47,16 @@ class RPCBindTest(BitcoinTestFramework):
at a non-localhost IP.
'''
base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips]
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [base_args])
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args])
# connect to node through non-loopback interface
node = get_rpc_proxy(rpc_url(0, "%s:%d" % (rpchost, rpcport)), 0)
node.getnetworkinfo()
- stop_nodes(self.nodes)
+ self.stop_nodes()
def run_test(self):
# due to OS-specific network stats queries, this test works only on Linux
if not sys.platform.startswith('linux'):
- self.log.warning("This test can only be run on linux. Skipping test.")
- sys.exit(self.TEST_EXIT_SKIPPED)
+ raise SkipTest("This test can only be run on linux.")
# find the first non-loopback interface for testing
non_loopback_ip = None
for name,ip in all_interfaces():
@@ -65,15 +64,13 @@ class RPCBindTest(BitcoinTestFramework):
non_loopback_ip = ip
break
if non_loopback_ip is None:
- self.log.warning("This test requires at least one non-loopback IPv4 interface. Skipping test.")
- sys.exit(self.TEST_EXIT_SKIPPED)
+ raise SkipTest("This test requires at least one non-loopback IPv4 interface.")
try:
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect(("::1",1))
s.close
except OSError:
- self.log.warning("This test requires IPv6 support. Skipping test.")
- sys.exit(self.TEST_EXIT_SKIPPED)
+ raise SkipTest("This test requires IPv6 support.")
self.log.info("Using interface %s for testing" % non_loopback_ip)
diff --git a/test/functional/smartfees.py b/test/functional/smartfees.py
index 4124f8025e..482c77863f 100755
--- a/test/functional/smartfees.py
+++ b/test/functional/smartfees.py
@@ -155,7 +155,7 @@ class EstimateFeeTest(BitcoinTestFramework):
"""
self.nodes = []
# Use node0 to mine blocks for input splitting
- self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000",
+ self.nodes.append(self.start_node(0, self.options.tmpdir, ["-maxorphantx=1000",
"-whitelist=127.0.0.1"]))
self.log.info("This test is time consuming, please be patient")
@@ -191,7 +191,7 @@ class EstimateFeeTest(BitcoinTestFramework):
# Node1 mines small blocks but that are bigger than the expected transaction rate.
# NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes,
# (17k is room enough for 110 or so transactions)
- self.nodes.append(start_node(1, self.options.tmpdir,
+ self.nodes.append(self.start_node(1, self.options.tmpdir,
["-blockmaxsize=17000", "-maxorphantx=1000"]))
connect_nodes(self.nodes[1], 0)
@@ -199,7 +199,7 @@ class EstimateFeeTest(BitcoinTestFramework):
# produces too small blocks (room for only 55 or so transactions)
node2args = ["-blockmaxsize=8000", "-maxorphantx=1000"]
- self.nodes.append(start_node(2, self.options.tmpdir, node2args))
+ self.nodes.append(self.start_node(2, self.options.tmpdir, node2args))
connect_nodes(self.nodes[0], 2)
connect_nodes(self.nodes[2], 1)
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 4b5b311385..67abf35687 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -5,6 +5,7 @@
"""Base class for RPC testing."""
from collections import deque
+from enum import Enum
import logging
import optparse
import os
@@ -31,16 +32,25 @@ from .util import (
p2p_port,
rpc_url,
set_node_times,
- start_node,
- start_nodes,
- stop_node,
- stop_nodes,
+ _start_node,
+ _start_nodes,
+ _stop_node,
+ _stop_nodes,
sync_blocks,
sync_mempools,
wait_for_bitcoind_start,
)
from .authproxy import JSONRPCException
+class TestStatus(Enum):
+ PASSED = 1
+ FAILED = 2
+ SKIPPED = 3
+
+TEST_EXIT_PASSED = 0
+TEST_EXIT_FAILED = 1
+TEST_EXIT_SKIPPED = 77
+
class BitcoinTestFramework(object):
"""Base class for a bitcoin test script.
@@ -57,11 +67,6 @@ class BitcoinTestFramework(object):
This class also contains various public and private helper methods."""
# Methods to override in subclass test scripts.
-
- TEST_EXIT_PASSED = 0
- TEST_EXIT_FAILED = 1
- TEST_EXIT_SKIPPED = 77
-
def __init__(self):
self.num_nodes = 4
self.setup_clean_chain = False
@@ -91,7 +96,7 @@ class BitcoinTestFramework(object):
extra_args = None
if hasattr(self, "extra_args"):
extra_args = self.extra_args
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+ self.nodes = _start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
def run_test(self):
raise NotImplementedError
@@ -139,15 +144,18 @@ class BitcoinTestFramework(object):
self.options.tmpdir = tempfile.mkdtemp(prefix="test")
self._start_logging()
- success = False
+ success = TestStatus.FAILED
try:
self.setup_chain()
self.setup_network()
self.run_test()
- success = True
+ success = TestStatus.PASSED
except JSONRPCException as e:
self.log.exception("JSONRPC error")
+ except SkipTest as e:
+ self.log.warning("Test Skipped: %s" % e.message)
+ success = TestStatus.SKIPPED
except AssertionError as e:
self.log.exception("Assertion failed")
except KeyError as e:
@@ -159,11 +167,12 @@ class BitcoinTestFramework(object):
if not self.options.noshutdown:
self.log.info("Stopping nodes")
- self.stop_nodes()
+ if self.nodes:
+ self.stop_nodes()
else:
self.log.info("Note: bitcoinds were not stopped and may still be running")
- if not self.options.nocleanup and not self.options.noshutdown and success:
+ if not self.options.nocleanup and not self.options.noshutdown and success != TestStatus.FAILED:
self.log.info("Cleaning up")
shutil.rmtree(self.options.tmpdir)
else:
@@ -183,27 +192,31 @@ class BitcoinTestFramework(object):
except OSError:
print("Opening file %s failed." % fn)
traceback.print_exc()
- if success:
+
+ if success == TestStatus.PASSED:
self.log.info("Tests successful")
- sys.exit(self.TEST_EXIT_PASSED)
+ sys.exit(TEST_EXIT_PASSED)
+ elif success == TestStatus.SKIPPED:
+ self.log.info("Test skipped")
+ sys.exit(TEST_EXIT_SKIPPED)
else:
self.log.error("Test failed. Test logging available at %s/test_framework.log", self.options.tmpdir)
logging.shutdown()
- sys.exit(self.TEST_EXIT_FAILED)
+ sys.exit(TEST_EXIT_FAILED)
# Public helper methods. These can be accessed by the subclass test scripts.
def start_node(self, i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None):
- return start_node(i, dirname, extra_args, rpchost, timewait, binary, stderr)
+ return _start_node(i, dirname, extra_args, rpchost, timewait, binary, stderr)
def start_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
- return start_nodes(num_nodes, dirname, extra_args, rpchost, timewait, binary)
+ return _start_nodes(num_nodes, dirname, extra_args, rpchost, timewait, binary)
def stop_node(self, num_node):
- stop_node(self.nodes[num_node], num_node)
+ _stop_node(self.nodes[num_node], num_node)
def stop_nodes(self):
- stop_nodes(self.nodes)
+ _stop_nodes(self.nodes)
def split_network(self):
"""
@@ -346,6 +359,11 @@ class BitcoinTestFramework(object):
# 2 binaries: 1 test binary, 1 ref binary
# n>2 binaries: 1 test binary, n-1 ref binaries
+class SkipTest(Exception):
+ """This exception is raised to skip a test"""
+ def __init__(self, message):
+ self.message = message
+
class ComparisonTestFramework(BitcoinTestFramework):
def __init__(self):
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 2b56fe8d62..2b0f32c2b6 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -227,10 +227,11 @@ def wait_for_bitcoind_start(process, url, i):
time.sleep(0.25)
-def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None):
- """
- Start a bitcoind and return RPC connection to it
- """
+def _start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None):
+ """Start a bitcoind and return RPC connection to it
+
+ This function should only be called from within test_framework, not by individual test scripts."""
+
datadir = os.path.join(dirname, "node"+str(i))
if binary is None:
binary = os.getenv("BITCOIND", "bitcoind")
@@ -251,8 +252,8 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=
def assert_start_raises_init_error(i, dirname, extra_args=None, expected_msg=None):
with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr:
try:
- node = start_node(i, dirname, extra_args, stderr=log_stderr)
- stop_node(node, i)
+ node = _start_node(i, dirname, extra_args, stderr=log_stderr)
+ _stop_node(node, i)
except Exception as e:
assert 'bitcoind exited' in str(e) #node must have shutdown
if expected_msg is not None:
@@ -267,10 +268,11 @@ def assert_start_raises_init_error(i, dirname, extra_args=None, expected_msg=Non
assert_msg = "bitcoind should have exited with expected error " + expected_msg
raise AssertionError(assert_msg)
-def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
- """
- Start multiple bitcoinds, return RPC connections to them
- """
+def _start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
+ """Start multiple bitcoinds, return RPC connections to them
+
+ This function should only be called from within test_framework, not by individual test scripts."""
+
if extra_args is None: extra_args = [ None for _ in range(num_nodes) ]
if binary is None: binary = [ None for _ in range(num_nodes) ]
assert_equal(len(extra_args), num_nodes)
@@ -278,16 +280,20 @@ def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, timewait=None
rpcs = []
try:
for i in range(num_nodes):
- rpcs.append(start_node(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i]))
+ rpcs.append(_start_node(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i]))
except: # If one node failed to start, stop the others
- stop_nodes(rpcs)
+ _stop_nodes(rpcs)
raise
return rpcs
def log_filename(dirname, n_node, logname):
return os.path.join(dirname, "node"+str(n_node), "regtest", logname)
-def stop_node(node, i):
+def _stop_node(node, i):
+ """Stop a bitcoind test node
+
+ This function should only be called from within test_framework, not by individual test scripts."""
+
logger.debug("Stopping node %d" % i)
try:
node.stop()
@@ -297,9 +303,13 @@ def stop_node(node, i):
assert_equal(return_code, 0)
del bitcoind_processes[i]
-def stop_nodes(nodes):
+def _stop_nodes(nodes):
+ """Stop multiple bitcoind test nodes
+
+ This function should only be called from within test_framework, not by individual test scripts."""
+
for i, node in enumerate(nodes):
- stop_node(node, i)
+ _stop_node(node, i)
assert not bitcoind_processes.values() # All connections must be gone now
def set_node_times(nodes, t):
diff --git a/test/functional/wallet-accounts.py b/test/functional/wallet-accounts.py
index e6635bea1c..158aa9ae89 100755
--- a/test/functional/wallet-accounts.py
+++ b/test/functional/wallet-accounts.py
@@ -14,9 +14,7 @@ RPCs tested are:
"""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import (
- assert_equal,
-)
+from test_framework.util import assert_equal
class WalletAccountsTest(BitcoinTestFramework):
diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py
index 8876f935a4..c38a9bc996 100755
--- a/test/functional/wallet-dump.py
+++ b/test/functional/wallet-dump.py
@@ -5,7 +5,7 @@
"""Test the dumpwallet RPC."""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import (start_nodes, start_node, assert_equal, bitcoind_processes)
+from test_framework.util import (assert_equal, bitcoind_processes)
def read_dump(file_name, addrs, hd_master_addr_old):
@@ -66,7 +66,7 @@ class WalletDumpTest(BitcoinTestFramework):
# longer than the default 30 seconds due to an expensive
# CWallet::TopUpKeyPool call, and the encryptwallet RPC made later in
# the test often takes even longer.
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=60)
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=60)
def run_test (self):
tmpdir = self.options.tmpdir
@@ -93,7 +93,7 @@ class WalletDumpTest(BitcoinTestFramework):
#encrypt wallet, restart, unlock and dump
self.nodes[0].encryptwallet('test')
bitcoind_processes[0].wait()
- self.nodes[0] = start_node(0, self.options.tmpdir, self.extra_args[0])
+ self.nodes[0] = self.start_node(0, self.options.tmpdir, self.extra_args[0])
self.nodes[0].walletpassphrase('test', 10)
# Should be a no-op:
self.nodes[0].keypoolrefill()
diff --git a/test/functional/wallet-hd.py b/test/functional/wallet-hd.py
index aab3b4bc2d..e7ec72a248 100755
--- a/test/functional/wallet-hd.py
+++ b/test/functional/wallet-hd.py
@@ -6,7 +6,6 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
- start_node,
assert_equal,
connect_nodes_bi,
assert_start_raises_init_error
@@ -29,7 +28,7 @@ class WalletHDTest(BitcoinTestFramework):
# Make sure can't switch off usehd after wallet creation
self.stop_node(1)
assert_start_raises_init_error(1, self.options.tmpdir, ['-usehd=0'], 'already existing HD wallet')
- self.nodes[1] = start_node(1, self.options.tmpdir, self.extra_args[1])
+ self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1])
connect_nodes_bi(self.nodes, 0, 1)
# Make sure we use hd, keep masterkeyid
@@ -76,7 +75,7 @@ class WalletHDTest(BitcoinTestFramework):
self.stop_node(1)
os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat")
shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat")
- self.nodes[1] = start_node(1, self.options.tmpdir, self.extra_args[1])
+ self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1])
#connect_nodes_bi(self.nodes, 0, 1)
# Assert that derivation is deterministic
@@ -90,7 +89,7 @@ class WalletHDTest(BitcoinTestFramework):
# Needs rescan
self.stop_node(1)
- self.nodes[1] = start_node(1, self.options.tmpdir, self.extra_args[1] + ['-rescan'])
+ self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1] + ['-rescan'])
#connect_nodes_bi(self.nodes, 0, 1)
assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
diff --git a/test/functional/wallet.py b/test/functional/wallet.py
index efde2e005e..3e3e8fcddb 100755
--- a/test/functional/wallet.py
+++ b/test/functional/wallet.py
@@ -21,7 +21,7 @@ class WalletTest(BitcoinTestFramework):
self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)]
def setup_network(self):
- self.nodes = start_nodes(3, self.options.tmpdir, self.extra_args[:3])
+ self.nodes = self.start_nodes(3, self.options.tmpdir, self.extra_args[:3])
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
@@ -178,7 +178,7 @@ class WalletTest(BitcoinTestFramework):
txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
sync_mempools(self.nodes)
- self.nodes.append(start_node(3, self.options.tmpdir, self.extra_args[3]))
+ self.nodes.append(self.start_node(3, self.options.tmpdir, self.extra_args[3]))
connect_nodes_bi(self.nodes, 0, 3)
sync_blocks(self.nodes)
@@ -221,8 +221,8 @@ class WalletTest(BitcoinTestFramework):
assert(found)
#do some -walletbroadcast tests
- stop_nodes(self.nodes)
- self.nodes = start_nodes(3, self.options.tmpdir, [["-walletbroadcast=0"],["-walletbroadcast=0"],["-walletbroadcast=0"]])
+ self.stop_nodes()
+ self.nodes = self.start_nodes(3, self.options.tmpdir, [["-walletbroadcast=0"],["-walletbroadcast=0"],["-walletbroadcast=0"]])
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
@@ -246,8 +246,8 @@ class WalletTest(BitcoinTestFramework):
txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2)
#restart the nodes with -walletbroadcast=1
- stop_nodes(self.nodes)
- self.nodes = start_nodes(3, self.options.tmpdir)
+ self.stop_nodes()
+ self.nodes = self.start_nodes(3, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
@@ -348,9 +348,9 @@ class WalletTest(BitcoinTestFramework):
chainlimit = 6
for m in maintenance:
self.log.info("check " + m)
- stop_nodes(self.nodes)
+ self.stop_nodes()
# set lower ancestor limit for later
- self.nodes = start_nodes(3, self.options.tmpdir, [[m, "-limitancestorcount="+str(chainlimit)]] * 3)
+ self.nodes = self.start_nodes(3, self.options.tmpdir, [[m, "-limitancestorcount="+str(chainlimit)]] * 3)
while m == '-reindex' and [block_count] * 3 != [self.nodes[i].getblockcount() for i in range(3)]:
# reindex will leave rpc warm up "early"; Wait for it to finish
time.sleep(0.1)
@@ -397,8 +397,8 @@ class WalletTest(BitcoinTestFramework):
# Try with walletrejectlongchains
# Double chain limit but require combining inputs, so we pass SelectCoinsMinConf
- stop_node(self.nodes[0],0)
- self.nodes[0] = start_node(0, self.options.tmpdir, ["-walletrejectlongchains", "-limitancestorcount="+str(2*chainlimit)])
+ self.stop_node(0)
+ self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-walletrejectlongchains", "-limitancestorcount="+str(2*chainlimit)])
# wait for loadmempool
timeout = 10
diff --git a/test/functional/walletbackup.py b/test/functional/walletbackup.py
index 0492132af6..a4507182a2 100755
--- a/test/functional/walletbackup.py
+++ b/test/functional/walletbackup.py
@@ -77,18 +77,18 @@ class WalletBackupTest(BitcoinTestFramework):
# As above, this mirrors the original bash test.
def start_three(self):
- self.nodes[0] = start_node(0, self.options.tmpdir)
- self.nodes[1] = start_node(1, self.options.tmpdir)
- self.nodes[2] = start_node(2, self.options.tmpdir)
+ self.nodes[0] = self.start_node(0, self.options.tmpdir)
+ self.nodes[1] = self.start_node(1, self.options.tmpdir)
+ self.nodes[2] = self.start_node(2, self.options.tmpdir)
connect_nodes(self.nodes[0], 3)
connect_nodes(self.nodes[1], 3)
connect_nodes(self.nodes[2], 3)
connect_nodes(self.nodes[2], 0)
def stop_three(self):
- stop_node(self.nodes[0], 0)
- stop_node(self.nodes[1], 1)
- stop_node(self.nodes[2], 2)
+ self.stop_node(0)
+ self.stop_node(1)
+ self.stop_node(2)
def erase_three(self):
os.remove(self.options.tmpdir + "/node0/regtest/wallet.dat")
diff --git a/test/functional/zapwallettxes.py b/test/functional/zapwallettxes.py
index 7987edeb54..a8600e82f6 100755
--- a/test/functional/zapwallettxes.py
+++ b/test/functional/zapwallettxes.py
@@ -58,18 +58,16 @@ class ZapWalletTXesTest (BitcoinTestFramework):
assert_equal(tx3['txid'], txid3) #tx3 must be available (unconfirmed)
#restart bitcoind
- self.nodes[0].stop()
- bitcoind_processes[0].wait()
- self.nodes[0] = start_node(0,self.options.tmpdir)
+ self.stop_node(0)
+ self.nodes[0] = self.start_node(0,self.options.tmpdir)
tx3 = self.nodes[0].gettransaction(txid3)
assert_equal(tx3['txid'], txid3) #tx must be available (unconfirmed)
- self.nodes[0].stop()
- bitcoind_processes[0].wait()
+ self.stop_node(0)
#restart bitcoind with zapwallettxes
- self.nodes[0] = start_node(0,self.options.tmpdir, ["-zapwallettxes=1"])
+ self.nodes[0] = self.start_node(0,self.options.tmpdir, ["-zapwallettxes=1"])
assert_raises(JSONRPCException, self.nodes[0].gettransaction, [txid3])
#there must be a expection because the unconfirmed wallettx0 must be gone by now
diff --git a/test/functional/zmq_test.py b/test/functional/zmq_test.py
index 918e13bcd4..ce39cfefdc 100755
--- a/test/functional/zmq_test.py
+++ b/test/functional/zmq_test.py
@@ -6,9 +6,8 @@
import configparser
import os
import struct
-import sys
-from test_framework.test_framework import BitcoinTestFramework
+from test_framework.test_framework import BitcoinTestFramework, SkipTest
from test_framework.util import *
class ZMQTest (BitcoinTestFramework):
@@ -24,8 +23,7 @@ class ZMQTest (BitcoinTestFramework):
try:
import zmq
except ImportError:
- self.log.warning("python3-zmq module not available. Skipping zmq tests!")
- sys.exit(self.TEST_EXIT_SKIPPED)
+ raise SkipTest("python3-zmq module not available.")
# Check that bitcoin has been built with ZMQ enabled
config = configparser.ConfigParser()
@@ -34,15 +32,14 @@ class ZMQTest (BitcoinTestFramework):
config.read_file(open(self.options.configfile))
if not config["components"].getboolean("ENABLE_ZMQ"):
- self.log.warning("bitcoind has not been built with zmq enabled. Skipping zmq tests!")
- sys.exit(self.TEST_EXIT_SKIPPED)
+ raise SkipTest("bitcoind has not been built with zmq enabled.")
self.zmqContext = zmq.Context()
self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock")
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx")
self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % self.port)
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[
['-zmqpubhashtx=tcp://127.0.0.1:'+str(self.port), '-zmqpubhashblock=tcp://127.0.0.1:'+str(self.port)],
[],
[],