Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 4 additions & 32 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,9 @@ AC_ARG_WITH([qrencode],

AC_ARG_ENABLE([hardening],
[AS_HELP_STRING([--disable-hardening],
[do not attempt to harden the resulting executables (default is to harden when possible)])],
[do not attempt to harden the resulting executables (default is to harden)])],
[use_hardening=$enableval],
[use_hardening=auto])
[use_hardening=yes])

AC_ARG_ENABLE([reduce-exports],
[AS_HELP_STRING([--enable-reduce-exports],
Expand Down Expand Up @@ -306,13 +306,6 @@ AC_ARG_WITH([sanitizers],
[comma separated list of extra sanitizers to build with (default is none enabled)])],
[use_sanitizers=$withval])

dnl Enable gprof profiling
AC_ARG_ENABLE([gprof],
[AS_HELP_STRING([--enable-gprof],
[use gprof profiling compiler flags (default is no)])],
[enable_gprof=$enableval],
[enable_gprof=no])

dnl Turn warnings into errors
AC_ARG_ENABLE([werror],
[AS_HELP_STRING([--enable-werror],
Expand Down Expand Up @@ -1044,30 +1037,12 @@ if test "$ac_cv_sys_large_files" != "" &&
CORE_CPPFLAGS="$CORE_CPPFLAGS -D_LARGE_FILES=$ac_cv_sys_large_files"
fi

if test "$enable_gprof" = "yes"; then
dnl -pg is incompatible with -pie. Since hardening and profiling together doesn't make sense,
dnl we simply make them mutually exclusive here. Additionally, hardened toolchains may force
dnl -pie by default, in which case it needs to be turned off with -no-pie.

if test "$use_hardening" = "yes"; then
AC_MSG_ERROR([gprof profiling is not compatible with hardening. Reconfigure with --disable-hardening or --disable-gprof])
fi
use_hardening=no
AX_CHECK_COMPILE_FLAG([-pg],[GPROF_CXXFLAGS="-pg"],
[AC_MSG_ERROR([gprof profiling requested but not available])], [$CXXFLAG_WERROR])

AX_CHECK_LINK_FLAG([-no-pie], [GPROF_LDFLAGS="-no-pie"])
AX_CHECK_LINK_FLAG([-pg], [GPROF_LDFLAGS="$GPROF_LDFLAGS -pg"],
[AC_MSG_ERROR([gprof profiling requested but not available])], [$GPROF_LDFLAGS])
fi

if test "$TARGET_OS" != "windows"; then
dnl All windows code is PIC, forcing it on just adds useless compile warnings
AX_CHECK_COMPILE_FLAG([-fPIC], [PIC_FLAGS="-fPIC"])
fi

if test "$use_hardening" != "no"; then
use_hardening=yes
AX_CHECK_COMPILE_FLAG([-Wstack-protector], [HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -Wstack-protector"])
AX_CHECK_COMPILE_FLAG([-fstack-protector-all], [HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fstack-protector-all"])

Expand Down Expand Up @@ -2009,8 +1984,6 @@ AC_SUBST(DEBUG_CXXFLAGS)
AC_SUBST(WARN_CXXFLAGS)
AC_SUBST(NOWARN_CXXFLAGS)
AC_SUBST(ERROR_CXXFLAGS)
AC_SUBST(GPROF_CXXFLAGS)
AC_SUBST(GPROF_LDFLAGS)
AC_SUBST(HARDENED_CXXFLAGS)
AC_SUBST(HARDENED_CPPFLAGS)
AC_SUBST(HARDENED_LDFLAGS)
Expand Down Expand Up @@ -2131,7 +2104,6 @@ echo " debug enabled = $enable_debug"
echo " stacktraces = $enable_stacktraces"
echo " crash hooks = $enable_crashhooks"
echo " miner enabled = $enable_miner"
echo " gprof enabled = $enable_gprof"
echo " werror = $enable_werror"
echo
echo " target os = $host_os"
Expand All @@ -2141,8 +2113,8 @@ echo " CC = $CC"
echo " CFLAGS = $DEBUG_CFLAGS $PTHREAD_CFLAGS $BACKTRACE_FLAGS $CFLAGS"
echo " CPPFLAGS = $DEBUG_CPPFLAGS $HARDENED_CPPFLAGS $CORE_CPPFLAGS $CPPFLAGS"
echo " CXX = $CXX"
echo " CXXFLAGS = $DEBUG_CXXFLAGS $HARDENED_CXXFLAGS $WARN_CXXFLAGS $NOWARN_CXXFLAGS $ERROR_CXXFLAGS $GPROF_CXXFLAGS $CORE_CXXFLAGS $BACKTRACE_FLAGS $CXXFLAGS"
echo " LDFLAGS = $PTHREAD_LIBS $HARDENED_LDFLAGS $GPROF_LDFLAGS $CORE_LDFLAGS $BACKTRACE_LDFLAGS $LDFLAGS"
echo " CXXFLAGS = $DEBUG_CXXFLAGS $HARDENED_CXXFLAGS $WARN_CXXFLAGS $NOWARN_CXXFLAGS $ERROR_CXXFLAGS $CORE_CXXFLAGS $BACKTRACE_FLAGS $CXXFLAGS"
echo " LDFLAGS = $PTHREAD_LIBS $HARDENED_LDFLAGS $CORE_LDFLAGS $BACKTRACE_LDFLAGS $LDFLAGS"
echo " AR = $AR"
echo " ARFLAGS = $ARFLAGS"
echo
5 changes: 0 additions & 5 deletions doc/developer-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ Developer Notes
- [Development tips and tricks](#development-tips-and-tricks)
- [Compiling for debugging](#compiling-for-debugging)
- [Show sources in debugging](#show-sources-in-debugging)
- [Compiling for gprof profiling](#compiling-for-gprof-profiling)
- [`debug.log`](#debuglog)
- [Devnet, testnet, and regtest modes](#devnet-testnet-and-regtest-modes)
- [DEBUG_LOCKORDER](#debug_lockorder)
Expand Down Expand Up @@ -385,10 +384,6 @@ ln -s /path/to/project/root/src src

3. Use `debugedit` to modify debug information in the binary.

### Compiling for gprof profiling

Run configure with the `--enable-gprof` option, then make.

### `debug.log`

If the code is behaving strangely, take a look in the `debug.log` file in the data directory;
Expand Down
4 changes: 2 additions & 2 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ print-%: FORCE

DIST_SUBDIRS = secp256k1

AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS) $(CORE_LDFLAGS) $(BACKTRACE_LDFLAGS)
AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(SANITIZER_LDFLAGS) $(CORE_LDFLAGS) $(BACKTRACE_LDFLAGS)
AM_CFLAGS = $(DEBUG_CFLAGS) $(BACKTRACE_FLAGS)
AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS) $(CORE_CXXFLAGS) $(BACKTRACE_FLAGS)
AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) $(SANITIZER_CXXFLAGS) $(CORE_CXXFLAGS) $(BACKTRACE_FLAGS)
AM_OBJCXXFLAGS = $(AM_CXXFLAGS)
AM_CPPFLAGS = $(DEBUG_CPPFLAGS) $(HARDENED_CPPFLAGS) $(CORE_CPPFLAGS)
AM_LIBTOOLFLAGS = --preserve-dup-deps
Expand Down
56 changes: 31 additions & 25 deletions src/bech32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ namespace

typedef std::vector<uint8_t> data;

/** The Bech32 and Bech32m checksum size */
constexpr size_t CHECKSUM_SIZE = 6;

/** The Bech32 and Bech32m character set for encoding. */
const char* CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";

Expand Down Expand Up @@ -133,18 +136,18 @@ inline unsigned char LowerCase(unsigned char c)
return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c;
}

/** Expand a HRP for use in checksum computation. */
data ExpandHRP(const std::string& hrp)
std::vector<unsigned char> PreparePolynomialCoefficients(const std::string& hrp, const data& values)
{
data ret;
ret.reserve(hrp.size() + 90);
ret.resize(hrp.size() * 2 + 1);
for (size_t i = 0; i < hrp.size(); ++i) {
unsigned char c = hrp[i];
ret[i] = c >> 5;
ret[i + hrp.size() + 1] = c & 0x1f;
}
ret[hrp.size()] = 0;
ret.reserve(hrp.size() + 1 + hrp.size() + values.size() + CHECKSUM_SIZE);

/** Expand a HRP for use in checksum computation. */
for (size_t i = 0; i < hrp.size(); ++i) ret.push_back(hrp[i] >> 5);
ret.push_back(0);
for (size_t i = 0; i < hrp.size(); ++i) ret.push_back(hrp[i] & 0x1f);

ret.insert(ret.end(), values.begin(), values.end());

return ret;
}

Expand All @@ -156,7 +159,8 @@ Encoding VerifyChecksum(const std::string& hrp, const data& values)
// list of values would result in a new valid list. For that reason, Bech32 requires the
// resulting checksum to be 1 instead. In Bech32m, this constant was amended. See
// https://gist.github.com/sipa/14c248c288c3880a3b191f978a34508e for details.
const uint32_t check = PolyMod(Cat(ExpandHRP(hrp), values));
auto enc = PreparePolynomialCoefficients(hrp, values);
const uint32_t check = PolyMod(enc);
if (check == EncodingConstant(Encoding::BECH32)) return Encoding::BECH32;
if (check == EncodingConstant(Encoding::BECH32M)) return Encoding::BECH32M;
return Encoding::INVALID;
Expand All @@ -165,11 +169,11 @@ Encoding VerifyChecksum(const std::string& hrp, const data& values)
/** Create a checksum. */
data CreateChecksum(Encoding encoding, const std::string& hrp, const data& values)
{
data enc = Cat(ExpandHRP(hrp), values);
enc.resize(enc.size() + 6); // Append 6 zeroes
auto enc = PreparePolynomialCoefficients(hrp, values);
enc.insert(enc.end(), CHECKSUM_SIZE, 0x00);
uint32_t mod = PolyMod(enc) ^ EncodingConstant(encoding); // Determine what to XOR into those 6 zeroes.
data ret(6);
for (size_t i = 0; i < 6; ++i) {
data ret(CHECKSUM_SIZE);
for (size_t i = 0; i < CHECKSUM_SIZE; ++i) {
// Convert the 5-bit groups in mod to checksum values.
ret[i] = (mod >> (5 * (5 - i))) & 31;
}
Expand All @@ -184,18 +188,18 @@ std::string Encode(Encoding encoding, const std::string& hrp, const data& values
// to return a lowercase Bech32/Bech32m string, but if given an uppercase HRP, the
// result will always be invalid.
for (const char& c : hrp) assert(c < 'A' || c > 'Z');
data checksum = CreateChecksum(encoding, hrp, values);
data combined = Cat(values, checksum);
std::string ret = hrp + '1';
ret.reserve(ret.size() + combined.size());
for (const auto c : combined) {
ret += CHARSET[c];
}

std::string ret;
ret.reserve(hrp.size() + 1 + values.size() + CHECKSUM_SIZE);
ret += hrp;
ret += '1';
for (const uint8_t& i : values) ret += CHARSET[i];
for (const uint8_t& i : CreateChecksum(encoding, hrp, values)) ret += CHARSET[i];
return ret;
}

/** Decode a Bech32 or Bech32m string. */
DecodeResult Decode(const std::string& str) {
DecodeResult Decode(const std::string& str, CharLimit limit) {
bool lower = false, upper = false;
for (size_t i = 0; i < str.size(); ++i) {
unsigned char c = str[i];
Expand All @@ -205,7 +209,8 @@ DecodeResult Decode(const std::string& str) {
}
if (lower && upper) return {};
size_t pos = str.rfind('1');
if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
if (str.size() > limit) return {};
if (pos == str.npos || pos == 0 || pos + CHECKSUM_SIZE >= str.size()) {
return {};
}
data values(str.size() - 1 - pos);
Expand All @@ -219,12 +224,13 @@ DecodeResult Decode(const std::string& str) {
values[i] = rev;
}
std::string hrp;
hrp.reserve(pos);
for (size_t i = 0; i < pos; ++i) {
hrp += LowerCase(str[i]);
}
Encoding result = VerifyChecksum(hrp, values);
if (result == Encoding::INVALID) return {};
return {result, std::move(hrp), data(values.begin(), values.end() - 6)};
return {result, std::move(hrp), data(values.begin(), values.end() - CHECKSUM_SIZE)};
}

} // namespace bech32
10 changes: 9 additions & 1 deletion src/bech32.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ enum class Encoding {
BECH32M, //!< Bech32m encoding as defined in BIP350
};

/** Character limits for Bech32(m) encoded strings. Character limits are how we provide error location guarantees.
* These values should never exceed 2^31 - 1 (max value for a 32-bit int), since there are places where we may need to
* convert the CharLimit::VALUE to an int. In practice, this should never happen since this CharLimit applies to an address encoding
* and we would never encode an address with such a massive value */
enum CharLimit : size_t {
BECH32 = 90, //!< BIP173/350 imposed character limit for Bech32(m) encoded addresses. This guarantees finding up to 4 errors.
};

/** Encode a Bech32 or Bech32m string. If hrp contains uppercase characters, this will cause an
* assertion error. Encoding must be one of BECH32 or BECH32M. */
std::string Encode(Encoding encoding, const std::string& hrp, const std::vector<uint8_t>& values);
Expand All @@ -42,7 +50,7 @@ struct DecodeResult
};

/** Decode a Bech32 or Bech32m string. */
DecodeResult Decode(const std::string& str);
DecodeResult Decode(const std::string& str, CharLimit limit = CharLimit::BECH32);

} // namespace bech32

Expand Down
1 change: 1 addition & 0 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3288,6 +3288,7 @@ CBlockIndex* CChainState::FindMostWorkChain()
while (pindexTest != pindexFailed) {
if (fFailedChain) {
pindexFailed->nStatus |= BLOCK_FAILED_CHILD;
m_blockman.m_dirty_blockindex.insert(pindexFailed);
} else if (fConflictingChain) {
// We don't need data for conflciting blocks
pindexFailed->nStatus |= BLOCK_CONFLICT_CHAINLOCK;
Expand Down
2 changes: 1 addition & 1 deletion test/functional/feature_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def check_clean_start():

for terminate_line in lines_to_terminate_after:
self.log.info(f"Starting node and will exit after line {terminate_line}")
with node.wait_for_debug_log([terminate_line]):
with node.busy_wait_for_debug_log([terminate_line]):
node.start(extra_args=['-txindex=1', '-blockfilterindex=1', '-coinstatsindex=1'])
self.log.debug("Terminating node after terminate line was found")
sigterm_node()
Expand Down
3 changes: 3 additions & 0 deletions test/functional/rpc_rawtransaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,13 +436,16 @@ def raw_multisig_transaction_legacy_tests(self):
rawTxPartialSigned2 = self.nodes[2].signrawtransactionwithwallet(rawTx2, inputs)
self.log.debug(rawTxPartialSigned2)
assert_equal(rawTxPartialSigned2['complete'], False) # node2 only has one key, can't comp. sign the tx
assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].combinerawtransaction, [rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex'] + "00"])
assert_raises_rpc_error(-22, "Missing transactions", self.nodes[0].combinerawtransaction, [])
rawTxComb = self.nodes[2].combinerawtransaction([rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']])
self.log.debug(rawTxComb)
self.nodes[2].sendrawtransaction(rawTxComb)
rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb)
self.sync_all()
self.generate(self.nodes[0], 1)
assert_equal(self.nodes[0].getbalance(), bal + Decimal('500.00000000') + Decimal('2.19000000')) # block reward + tx
assert_raises_rpc_error(-25, "Input not found or already spent", self.nodes[0].combinerawtransaction, [rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']])


if __name__ == '__main__':
Expand Down
2 changes: 1 addition & 1 deletion test/functional/test_framework/test_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ def assert_debug_log(self, expected_msgs, unexpected_msgs=None, timeout=2):
self._raise_assertion_error('Expected messages "{}" does not partially match log:\n\n{}\n\n'.format(str(expected_msgs), print_log))

@contextlib.contextmanager
def wait_for_debug_log(self, expected_msgs, timeout=60):
def busy_wait_for_debug_log(self, expected_msgs, timeout=60):
"""
Block until we see a particular debug log message fragment or until we exceed the timeout.
Return:
Expand Down
Loading