Skip to content
Merged
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
1 change: 1 addition & 0 deletions ci/dash/lint-tidy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ iwyu_tool.py \
"src/util/strencodings.cpp" \
"src/util/syserror.cpp" \
"src/util/url.cpp" \
"src/zmq" \
-p . "${MAKEJOBS}" \
-- -Xiwyu --cxx17ns -Xiwyu --mapping_file="${BASE_ROOT_DIR}/contrib/devtools/iwyu/bitcoin.core.imp" \
2>&1 | tee "/tmp/iwyu_ci.out"
Expand Down
2 changes: 1 addition & 1 deletion ci/lint/04_install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ if [ -z "${SKIP_PYTHON_INSTALL}" ]; then
python3 --version
fi

${CI_RETRY_EXE} pip3 install codespell==2.1.0
${CI_RETRY_EXE} pip3 install codespell==2.2.1
${CI_RETRY_EXE} pip3 install flake8==4.0.1
${CI_RETRY_EXE} pip3 install lief==0.13.1
${CI_RETRY_EXE} pip3 install mypy==0.981
Expand Down
2 changes: 2 additions & 0 deletions ci/lint/06_script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ if [ "$CIRRUS_REPO_FULL_NAME" = "dashpay/dash" ] && [ "$CIRRUS_PR" = "" ] ; then
git log HEAD~10 -1 --format='%H' > ./contrib/verify-commits/trusted-sha512-root-commit
git log HEAD~10 -1 --format='%H' > ./contrib/verify-commits/trusted-git-root
mapfile -t KEYS < contrib/verify-commits/trusted-keys
git config user.email "ci@ci.ci"
git config user.name "ci"
${CI_RETRY_EXE} gpg --keyserver hkps://keys.openpgp.org --recv-keys "${KEYS[@]}" &&
./contrib/verify-commits/verify-commits.py;
fi
17 changes: 9 additions & 8 deletions ci/test/04_install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,6 @@ if [[ $QEMU_USER_CMD == qemu-s390* ]]; then
export LC_ALL=C
fi

if [ "$CI_OS_NAME" == "macos" ]; then
sudo -H pip3 install --upgrade pip
# shellcheck disable=SC2086
IN_GETOPT_BIN="/usr/local/opt/gnu-getopt/bin/getopt" ${CI_RETRY_EXE} pip3 install --user $PIP_PACKAGES
fi

# Create folders that are mounted into the docker
mkdir -p "${CCACHE_DIR}"
mkdir -p "${PREVIOUS_RELEASES_DIR}"
Expand Down Expand Up @@ -89,9 +83,16 @@ if [[ $DOCKER_NAME_TAG == *centos* ]]; then
elif [ "$CI_USE_APT_INSTALL" != "no" ]; then
${CI_RETRY_EXE} CI_EXEC_ROOT apt-get update
${CI_RETRY_EXE} CI_EXEC_ROOT apt-get install --no-install-recommends --no-upgrade -y "$PACKAGES" "$DOCKER_PACKAGES"
if [ -n "$PIP_PACKAGES" ]; then
fi

if [ -n "$PIP_PACKAGES" ]; then
if [ "$CI_OS_NAME" == "macos" ]; then
sudo -H pip3 install --upgrade pip
# shellcheck disable=SC2086
IN_GETOPT_BIN="/usr/local/opt/gnu-getopt/bin/getopt" ${CI_RETRY_EXE} pip3 install --user $PIP_PACKAGES
else
# shellcheck disable=SC2086
${CI_RETRY_EXE} pip3 install --user $PIP_PACKAGES
${CI_RETRY_EXE} CI_EXEC pip3 install --user $PIP_PACKAGES
fi
fi

Expand Down
2 changes: 1 addition & 1 deletion doc/release-notes-empty-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Please report bugs using the issue tracker at GitHub:

If you are running an older version, shut it down. Wait until it has completely
shut down (which might take a few minutes in some cases), then run the
installer (on Windows) or just copy over `/Applications/Dash-Qt` (on Mac) or
installer (on Windows) or just copy over `/Applications/Dash-Qt` (on macOS) or
`dashd`/`dash-qt` (on Linux).

## Downgrade warning
Expand Down
5 changes: 3 additions & 2 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ BITCOIN_TESTS += \
wallet/test/availablecoins_tests.cpp \
wallet/test/init_tests.cpp \
wallet/test/ismine_tests.cpp \
wallet/test/rpc_util_tests.cpp \
wallet/test/scriptpubkeyman_tests.cpp

FUZZ_SUITE_LD_COMMON +=\
Expand All @@ -231,7 +232,8 @@ endif

FUZZ_WALLET_SRC = \
wallet/test/fuzz/coincontrol.cpp \
wallet/test/fuzz/coinselection.cpp
wallet/test/fuzz/coinselection.cpp \
wallet/test/fuzz/parse_iso8601.cpp

if USE_SQLITE
FUZZ_WALLET_SRC += \
Expand Down Expand Up @@ -331,7 +333,6 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/node_eviction.cpp \
test/fuzz/p2p_transport_serialization.cpp \
test/fuzz/parse_hd_keypath.cpp \
test/fuzz/parse_iso8601.cpp \
test/fuzz/parse_numbers.cpp \
test/fuzz/parse_script.cpp \
test/fuzz/parse_univalue.cpp \
Expand Down
2 changes: 1 addition & 1 deletion src/bench/nanobench.h
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,7 @@ class Bench {
* @brief Retrieves all benchmark results collected by the bench object so far.
*
* Each call to run() generates a Result that is stored within the Bench instance. This is mostly for advanced users who want to
* see all the nitty gritty detials.
* see all the nitty gritty details.
*
* @return All results collected so far.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/bitcoind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
if (token) { // Success
exit(EXIT_SUCCESS);
} else { // fRet = false or token read error (premature exit).
tfm::format(std::cerr, "Error during initializaton - check debug.log for details\n");
tfm::format(std::cerr, "Error during initialization - check debug.log for details\n");
exit(EXIT_FAILURE);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/index/blockfilterindex.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include <index/base.h>
#include <util/hasher.h>

static const char* const DEFAULT_BLOCKFILTERINDEX = "0";

/** Interval between compact filter checkpoints. See BIP 157. */
static constexpr int CFCHECKPT_INTERVAL = 1000;

Expand Down
2 changes: 2 additions & 0 deletions src/index/coinstatsindex.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <index/base.h>
#include <kernel/coinstats.h>

static constexpr bool DEFAULT_COINSTATSINDEX{false};

/**
* CoinStatsIndex maintains statistics on the UTXO set.
*/
Expand Down
2 changes: 2 additions & 0 deletions src/index/txindex.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#include <index/base.h>

static constexpr bool DEFAULT_TXINDEX{true};

/**
* TxIndex is used to look up transactions included in the blockchain by hash.
* The index is written to a LevelDB database and records the filesystem
Expand Down
2 changes: 1 addition & 1 deletion src/node/caches.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

#include <node/caches.h>

#include <index/txindex.h>
#include <txdb.h>
#include <util/system.h>
#include <validation.h>

namespace node {
CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes)
Expand Down
8 changes: 2 additions & 6 deletions src/node/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,13 +431,9 @@ static int UpdatePackagesForAdded(const CTxMemPool& mempool,
modtxiter mit = mapModifiedTx.find(desc);
if (mit == mapModifiedTx.end()) {
CTxMemPoolModifiedEntry modEntry(desc);
modEntry.nSizeWithAncestors -= it->GetTxSize();
modEntry.nModFeesWithAncestors -= it->GetModifiedFee();
modEntry.nSigOpCountWithAncestors -= it->GetSigOpCount();
mapModifiedTx.insert(modEntry);
} else {
mapModifiedTx.modify(mit, update_for_parent_inclusion(it));
mit = mapModifiedTx.insert(modEntry).first;
}
mapModifiedTx.modify(mit, update_for_parent_inclusion(it));
}
}
return nDescendantsUpdated;
Expand Down
2 changes: 0 additions & 2 deletions src/rpc/fees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ static RPCHelpMan estimatesmartfee()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);

CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);
const NodeContext& node = EnsureAnyNodeContext(request.context);
Expand Down Expand Up @@ -157,7 +156,6 @@ static RPCHelpMan estimaterawfee()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);

CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);

Expand Down
3 changes: 1 addition & 2 deletions src/rpc/mempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -629,8 +629,7 @@ static RPCHelpMan gettxspendingprevout()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
RPCTypeCheckArgument(request.params[0], UniValue::VARR);
const UniValue& output_params = request.params[0];
const UniValue& output_params = request.params[0].get_array();
if (output_params.empty()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, outputs are missing");
}
Expand Down
9 changes: 4 additions & 5 deletions src/rpc/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,18 +525,17 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const

static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler)
{
try
{
try {
RPCCommandExecution execution(request.strMethod);
// Execute, convert arguments to array if necessary
if (request.params.isObject()) {
return command.actor(transformNamedArguments(request, command.argNames), result, last_handler);
} else {
return command.actor(request, result, last_handler);
}
}
catch (const std::exception& e)
{
} catch (const UniValue::type_error& e) {
throw JSONRPCError(RPC_TYPE_ERROR, e.what());
} catch (const std::exception& e) {
throw JSONRPCError(RPC_MISC_ERROR, e.what());
}
}
Expand Down
45 changes: 19 additions & 26 deletions src/sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class LOCKABLE AnnotatedMixin : public PARENT
return PARENT::try_lock();
}

using UniqueLock = std::unique_lock<PARENT>;
using unique_lock = std::unique_lock<PARENT>;
#ifdef __clang__
//! For negative capabilities in the Clang Thread Safety Analysis.
//! A negative requirement uses the EXCLUSIVE_LOCKS_REQUIRED attribute, in conjunction
Expand Down Expand Up @@ -172,11 +172,13 @@ inline void AssertLockNotHeldInline(const char* name, const char* file, int line
inline void AssertLockNotHeldInline(const char* name, const char* file, int line, SharedMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); }
#define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs)

/** Wrapper around std::unique_lock style lock for Mutex. */
template <typename Mutex, typename Base = typename Mutex::UniqueLock>
class SCOPED_LOCKABLE UniqueLock : public Base
/** Wrapper around std::unique_lock style lock for MutexType. */
template <typename MutexType>
class SCOPED_LOCKABLE UniqueLock : public MutexType::unique_lock
{
private:
using Base = typename MutexType::unique_lock;

void Enter(const char* pszName, const char* pszFile, int nLine)
{
EnterCritical(pszName, pszFile, nLine, Base::mutex());
Expand All @@ -198,15 +200,15 @@ class SCOPED_LOCKABLE UniqueLock : public Base
}

public:
UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
UniqueLock(MutexType& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
{
if (fTry)
TryEnter(pszName, pszFile, nLine);
else
Enter(pszName, pszFile, nLine);
}

UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
UniqueLock(MutexType* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
{
if (!pmutexIn) return;

Expand Down Expand Up @@ -320,8 +322,6 @@ class SCOPED_LOCKABLE SharedLock : public Base

#define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock UNIQUE_NAME(revlock)(g, #g, __FILE__, __LINE__)

template<typename MutexArg>
using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>;
template<typename MutexArg>
using ReadLock = SharedLock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>;

Expand All @@ -330,28 +330,21 @@ using ReadLock = SharedLock<typename std::remove_reference<typename std::remove_
inline Mutex& MaybeCheckNotHeld(Mutex& cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; }
inline Mutex* MaybeCheckNotHeld(Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; }

// When locking a GlobalMutex, just check it is not locked in the surrounding scope
inline GlobalMutex& MaybeCheckNotHeld(GlobalMutex& cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
inline GlobalMutex* MaybeCheckNotHeld(GlobalMutex* cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }

// When locking a RecursiveMutex, it's okay to already hold the lock
// but check that it is not known to be locked in the surrounding scope anyway
inline RecursiveMutex& MaybeCheckNotHeld(RecursiveMutex& cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
inline RecursiveMutex* MaybeCheckNotHeld(RecursiveMutex* cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }

// When locking a SharedMutex, it's okay to already hold the lock
// but check that it is not known to be locked in the surrounding scope anyway
inline SharedMutex& MaybeCheckNotHeld(SharedMutex& cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
inline SharedMutex* MaybeCheckNotHeld(SharedMutex* cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
// When locking a GlobalMutex or RecursiveMutex or SharedMutex, just check it is not
// locked in the surrounding scope.
template <typename MutexType>
inline MutexType& MaybeCheckNotHeld(MutexType& m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; }
template <typename MutexType>
inline MutexType* MaybeCheckNotHeld(MutexType* m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; }

#define LOCK(cs) DebugLock<decltype(cs)> UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
#define READ_LOCK(cs) ReadLock<decltype(cs)> UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
#define LOCK2(cs1, cs2) \
DebugLock<decltype(cs1)> criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \
DebugLock<decltype(cs2)> criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
#define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true)
UniqueLock criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \
UniqueLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
#define TRY_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true)
#define TRY_READ_LOCK(cs, name) ReadLock<decltype(cs)> name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true)
#define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
#define WAIT_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)

#define ENTER_CRITICAL_SECTION(cs) \
{ \
Expand Down
4 changes: 2 additions & 2 deletions src/test/fuzz/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,8 @@ CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider, const std::option
int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min, const std::optional<int64_t>& max) noexcept
{
// Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) disables mocktime.
static const int64_t time_min{ParseISO8601DateTime("2000-01-01T00:00:01Z")};
static const int64_t time_max{ParseISO8601DateTime("2100-12-31T23:59:59Z")};
static const int64_t time_min{946684801}; // 2000-01-01T00:00:01Z
static const int64_t time_max{4133980799}; // 2100-12-31T23:59:59Z
return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(min.value_or(time_min), max.value_or(time_max));
}

Expand Down
6 changes: 1 addition & 5 deletions src/test/util_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,16 +292,12 @@ BOOST_AUTO_TEST_CASE(util_TrimString)
BOOST_CHECK_EQUAL(TrimStringView(std::string("\x05\x04\x03\x02\x01\x00", 6), std::string("\x05\x04\x03\x02\x01\x00", 6)), "");
}

BOOST_AUTO_TEST_CASE(util_FormatParseISO8601DateTime)
BOOST_AUTO_TEST_CASE(util_FormatISO8601DateTime)
{
BOOST_CHECK_EQUAL(FormatISO8601DateTime(971890963199), "32767-12-31T23:59:59Z");
BOOST_CHECK_EQUAL(FormatISO8601DateTime(971890876800), "32767-12-31T00:00:00Z");
BOOST_CHECK_EQUAL(FormatISO8601DateTime(1317425777), "2011-09-30T23:36:17Z");
BOOST_CHECK_EQUAL(FormatISO8601DateTime(0), "1970-01-01T00:00:00Z");

BOOST_CHECK_EQUAL(ParseISO8601DateTime("1970-01-01T00:00:00Z"), 0);
BOOST_CHECK_EQUAL(ParseISO8601DateTime("1960-01-01T00:00:00Z"), 0);
BOOST_CHECK_EQUAL(ParseISO8601DateTime("2011-09-30T23:36:17Z"), 1317425777);
}

BOOST_AUTO_TEST_CASE(util_FormatISO8601Date)
Expand Down
2 changes: 1 addition & 1 deletion src/test/validation_chainstatemanager_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)

//! Test LoadBlockIndex behavior when multiple chainstates are in use.
//!
//! - First, verfiy that setBlockIndexCandidates is as expected when using a single,
//! - First, verify that setBlockIndexCandidates is as expected when using a single,
//! fully-validating chainstate.
//!
//! - Then mark a region of the chain BLOCK_ASSUMED_VALID and introduce a second chainstate
Expand Down
5 changes: 5 additions & 0 deletions src/univalue/include/univalue.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ class UniValue {
public:
enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };

class type_error : public std::runtime_error
{
using std::runtime_error::runtime_error;
};

UniValue() { typ = VNULL; }
UniValue(UniValue::VType type, std::string str = {}) : typ{type}, val{std::move(str)} {}
template <typename Ref, typename T = std::remove_cv_t<std::remove_reference_t<Ref>>,
Expand Down
2 changes: 1 addition & 1 deletion src/univalue/lib/univalue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ const UniValue& UniValue::operator[](size_t index) const
void UniValue::checkType(const VType& expected) const
{
if (typ != expected) {
throw std::runtime_error{"JSON value of type " + std::string{uvTypeName(typ)} + " is not of expected type " +
throw type_error{"JSON value of type " + std::string{uvTypeName(typ)} + " is not of expected type " +
std::string{uvTypeName(expected)}};
}
}
Expand Down
16 changes: 0 additions & 16 deletions src/util/time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
#include <util/time.h>
#include <util/check.h>

#include <boost/date_time/posix_time/posix_time.hpp>

#include <atomic>
#include <chrono>
#include <ctime>
Expand Down Expand Up @@ -89,20 +87,6 @@ std::string FormatISO8601Time(int64_t nTime)
return strprintf("%02i:%02i:%02iZ", hms.hours().count(), hms.minutes().count(), hms.seconds().count());
}

int64_t ParseISO8601DateTime(const std::string& str)
{
static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);
static const std::locale loc(std::locale::classic(),
new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%SZ"));
std::istringstream iss(str);
iss.imbue(loc);
boost::posix_time::ptime ptime(boost::date_time::not_a_date_time);
iss >> ptime;
if (ptime.is_not_a_date_time() || epoch > ptime)
return 0;
return (ptime - epoch).total_seconds();
}

struct timespec MillisToTimespec(int64_t nTimeout)
{
struct timespec timeout;
Expand Down
Loading
Loading