diff --git a/src/config.h b/src/config.h index 56fbe7dfa..42769a2d4 100644 --- a/src/config.h +++ b/src/config.h @@ -1,76 +1,78 @@ // Copyright (c) 2017 Amaury SÉCHET // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_CONFIG_H #define BITCOIN_CONFIG_H #include #include -#include - #include #include #include class CChainParams; -class Config : public boost::noncopyable { +class Config { public: virtual bool SetMaxBlockSize(uint64_t maxBlockSize) = 0; virtual uint64_t GetMaxBlockSize() const = 0; virtual const CChainParams &GetChainParams() const = 0; virtual void SetCashAddrEncoding(bool) = 0; virtual bool UseCashAddrEncoding() const = 0; virtual void SetExcessUTXOCharge(Amount amt) = 0; virtual Amount GetExcessUTXOCharge() const = 0; + + Config() = default; + Config(const Config &) = delete; + Config &operator=(const Config &) = delete; }; class GlobalConfig final : public Config { public: GlobalConfig(); bool SetMaxBlockSize(uint64_t maxBlockSize) override; uint64_t GetMaxBlockSize() const override; const CChainParams &GetChainParams() const override; void SetCashAddrEncoding(bool) override; bool UseCashAddrEncoding() const override; void SetExcessUTXOCharge(Amount) override; Amount GetExcessUTXOCharge() const override; private: bool useCashAddr; Amount excessUTXOCharge; /** The largest block size this node will accept. */ uint64_t nMaxBlockSize; }; // Dummy for subclassing in unittests class DummyConfig : public Config { public: DummyConfig(); explicit DummyConfig(std::string net); explicit DummyConfig(std::unique_ptr chainParamsIn); bool SetMaxBlockSize(uint64_t maxBlockSize) override { return false; } uint64_t GetMaxBlockSize() const override { return 0; } void SetChainParams(std::string net); const CChainParams &GetChainParams() const override { return *chainParams; } void SetCashAddrEncoding(bool) override {} bool UseCashAddrEncoding() const override { return false; } void SetExcessUTXOCharge(Amount amt) override {} Amount GetExcessUTXOCharge() const override { return Amount::zero(); } private: std::unique_ptr chainParams; }; // Temporary woraround. const Config &GetConfig(); #endif // BITCOIN_CONFIG_H diff --git a/src/radix.h b/src/radix.h index a8b604443..9c7b9771a 100644 --- a/src/radix.h +++ b/src/radix.h @@ -1,285 +1,289 @@ // Copyright (c) 2019 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_RADIX_H #define BITCOIN_RADIX_H #include #include -#include - #include #include #include #include #include /** * This is a radix tree storing values identified by a unique key. * * The tree is composed of nodes (RadixNode) containing an array of * RadixElement. The key is split into chunks of a few bits that serve as an * index into that array. RadixElement is a discriminated union of either a * RadixNode* representing the next level in the tree, or a T* representing a * leaf. New RadixNode are added lazily when two leaves would go in the same * slot. * * Reads walk the tree using sequential atomic loads, and insertions are done * using CAS, which ensures both can be executed lock free. Removing any * elements from the tree can also be done using CAS, but requires waiting for * other readers before being destroyed. The tree uses RCU to track which thread * is reading the tree, which allows deletion to wait for other readers to be up * to speed before destroying anything. It is therefore crucial that the lock be * taken before reading anything in the tree. * * It is not possible to delete anything from the tree at this time. The tree * itself cannot be destroyed and will leak memory instead of cleaning up after * itself. This obviously needs to be fixed in subsequent revisions. */ -template struct RadixTree : public boost::noncopyable { +template struct RadixTree { private: static const int BITS = 4; static const int MASK = (1 << BITS) - 1; static const size_t CHILD_PER_LEVEL = 1 << BITS; typedef typename std::remove_reference().getId())>::type K; static const size_t KEY_BITS = 8 * sizeof(K); static const uint32_t TOP_LEVEL = (KEY_BITS - 1) / BITS; struct RadixElement; struct RadixNode; std::atomic root; public: RadixTree() : root(RadixElement()) {} ~RadixTree() { root.load().release(); } + RadixTree(const RadixTree &) = delete; + RadixTree &operator=(const RadixTree &) = delete; + /** * Insert a value into the tree. * Returns true if the value was inserted, false if it was already present. */ bool insert(const RCUPtr &value) { return insert(value->getId(), value); } /** * Get the value corresponding to a key. * Returns the value if found, nullptr if not. */ RCUPtr get(const K &key) { uint32_t level = TOP_LEVEL; RCULock lock; RadixElement e = root.load(); // Find a leaf. while (e.isNode()) { e = e.getNode()->get(level--, key)->load(); } T *leaf = e.getLeaf(); if (leaf == nullptr || leaf->getId() != key) { // We failed to find the proper element. return RCUPtr(); } // The leaf is non-null and the keys match. We have our guy. return RCUPtr::copy(leaf); } RCUPtr get(const K &key) const { T const *ptr = const_cast(this)->get(key).release(); return RCUPtr::acquire(ptr); } /** * Remove an element from the tree. * Returns the removed element, or nullptr if there isn't one. */ RCUPtr remove(const K &key) { uint32_t level = TOP_LEVEL; RCULock lock; std::atomic *eptr = &root; RadixElement e = eptr->load(); // Walk down the tree until we find a leaf for our node. while (e.isNode()) { Node: eptr = e.getNode()->get(level--, key); e = eptr->load(); } T *leaf = e.getLeaf(); if (leaf == nullptr || leaf->getId() != key) { // We failed to find the proper element. return RCUPtr(); } // We have the proper element, try to delete it. if (eptr->compare_exchange_strong(e, RadixElement())) { return RCUPtr::acquire(leaf); } // The element was replaced, either by a subtree or another element. if (e.isNode()) { goto Node; } // The element in the slot is not the one we are looking for. return RCUPtr(); } private: bool insert(const K &key, RCUPtr value) { uint32_t level = TOP_LEVEL; RCULock lock; std::atomic *eptr = &root; while (true) { RadixElement e = eptr->load(); // Walk down the tree until we find a leaf for our node. while (e.isNode()) { Node: eptr = e.getNode()->get(level--, key); e = eptr->load(); } // If the slot is empty, try to insert right there. if (e.getLeaf() == nullptr) { if (eptr->compare_exchange_strong(e, RadixElement(value.get()))) { value.release(); return true; } // CAS failed, we may have a node in there now. if (e.isNode()) { goto Node; } } // The element was already in the tree. const K &leafKey = e.getLeaf()->getId(); if (key == leafKey) { return false; } // There is an element there, but it isn't a subtree. We need to // convert it into a subtree and resume insertion into that subtree. auto newChild = std::make_unique(level, leafKey, e); if (eptr->compare_exchange_strong(e, RadixElement(newChild.get()))) { // We have a subtree, resume normal operations from there. newChild.release(); } else { // We failed to insert our subtree, clean it before it is freed. newChild->get(level, leafKey)->store(RadixElement()); } } } struct RadixElement { private: union { RadixNode *node; T *leaf; uintptr_t raw; }; static const uintptr_t DISCRIMINANT = 0x01; bool getDiscriminant() const { return (raw & DISCRIMINANT) != 0; } public: explicit RadixElement() noexcept : raw(DISCRIMINANT) {} explicit RadixElement(RadixNode *nodeIn) noexcept : node(nodeIn) {} explicit RadixElement(T *leafIn) noexcept : leaf(leafIn) { raw |= DISCRIMINANT; } /** * RadixElement is designed to be a dumb wrapper. This allows any * container to release what is held by the RadixElement. */ void release() { if (isNode()) { RadixNode *ptr = getNode(); RCUPtr::acquire(ptr); } else { T *ptr = getLeaf(); RCUPtr::acquire(ptr); } } /** * Node features. */ bool isNode() const { return !getDiscriminant(); } RadixNode *getNode() { assert(isNode()); return node; } const RadixNode *getNode() const { assert(isNode()); return node; } /** * Leaf features. */ bool isLeaf() const { return getDiscriminant(); } T *getLeaf() { assert(isLeaf()); return reinterpret_cast(raw & ~DISCRIMINANT); } const T *getLeaf() const { assert(isLeaf()); return const_cast(this)->getLeaf(); } }; - struct RadixNode : public boost::noncopyable { + struct RadixNode { IMPLEMENT_RCU_REFCOUNT(uint64_t); private: union { std::array, CHILD_PER_LEVEL> children; std::array non_atomic_children_DO_NOT_USE; }; public: RadixNode(uint32_t level, const K &key, RadixElement e) : non_atomic_children_DO_NOT_USE() { get(level, key)->store(e); } ~RadixNode() { for (RadixElement e : non_atomic_children_DO_NOT_USE) { e.release(); } } + RadixNode(const RadixNode &) = delete; + RadixNode &operator=(const RadixNode &) = delete; + std::atomic *get(uint32_t level, const K &key) { return &children[(key >> (level * BITS)) & MASK]; } }; // Make sure the alignment works for T and RadixElement. static_assert(alignof(T) > 1, "T's alignment must be 2 or more."); static_assert(alignof(RadixNode) > 1, "RadixNode alignment must be 2 or more."); }; #endif // BITCOIN_RADIX_H diff --git a/src/rcu.h b/src/rcu.h index f5e524758..cd375aa8e 100644 --- a/src/rcu.h +++ b/src/rcu.h @@ -1,233 +1,234 @@ // Copyright (c) 2018-2019 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_RCU_H #define BITCOIN_RCU_H -#include - #include #include #include #include #include #include #include #include class RCUInfos; class RCUReadLock; class RCUInfos { std::atomic state; std::atomic next; std::map> cleanups; // The largest revision possible means unlocked. static const uint64_t UNLOCKED = -uint64_t(1); RCUInfos(); ~RCUInfos(); void readLock() { assert(!isLocked()); state.store(revision.load()); } void readFree() { assert(isLocked()); state.store(UNLOCKED); } bool isLocked() const { return state.load() != UNLOCKED; } void registerCleanup(const std::function &f) { cleanups.emplace(++revision, f); } void synchronize(); void runCleanups(); uint64_t hasSyncedTo(uint64_t cutoff = UNLOCKED); friend class RCULock; friend struct RCUTest; static std::atomic revision; static thread_local RCUInfos infos; }; -class RCULock : public boost::noncopyable { +class RCULock { RCUInfos *infos; explicit RCULock(RCUInfos *infosIn) : infos(infosIn) { infos->readLock(); } friend class RCUInfos; public: RCULock() : RCULock(&RCUInfos::infos) {} ~RCULock() { infos->readFree(); } + RCULock(const RCULock &) = delete; + RCULock &operator=(const RCULock &) = delete; + static bool isLocked() { return RCUInfos::infos.isLocked(); } static void registerCleanup(const std::function &f) { RCUInfos::infos.registerCleanup(f); } static void synchronize() { RCUInfos::infos.synchronize(); } }; template class RCUPtr { T *ptr; // Private construction, so factories have to be used. explicit RCUPtr(T *ptrIn) : ptr(ptrIn) {} public: RCUPtr() : ptr(nullptr) {} ~RCUPtr() { if (ptr != nullptr) { ptr->release(); } } /** * Acquire ownership of some pointer. */ static RCUPtr acquire(T *&ptrIn) { RCUPtr ret(ptrIn); ptrIn = nullptr; return ret; } /** * Construct a new object that is owned by the pointer. */ template static RCUPtr make(Args &&... args) { return RCUPtr(new T(std::forward(args)...)); } /** * Construct a new RCUPtr without transferring owership. */ static RCUPtr copy(T *ptr) { if (ptr != nullptr) { ptr->acquire(); } return RCUPtr::acquire(ptr); } /** * Copy semantic. */ RCUPtr(const RCUPtr &src) : ptr(src.ptr) { if (ptr != nullptr) { ptr->acquire(); } } RCUPtr &operator=(const RCUPtr &rhs) { RCUPtr tmp(rhs); std::swap(ptr, tmp.ptr); return *this; } /** * Move semantic. */ RCUPtr(RCUPtr &&src) : RCUPtr() { std::swap(ptr, src.ptr); } RCUPtr &operator=(RCUPtr &&rhs) { std::swap(ptr, rhs.ptr); return *this; } /** * Get allows to access the undelying pointer. RCUPtr keeps ownership. */ T *get() { return ptr; } const T *get() const { return ptr; } /** * Release transfers ownership of the pointer from RCUPtr to the caller. */ T *release() { T *oldPtr = ptr; ptr = nullptr; return oldPtr; } /** * Operator overloading for convenience. */ T *operator->() { return ptr; } const T *operator->() const { return ptr; } T &operator*() { return *ptr; } const T &operator*() const { return *ptr; } explicit operator bool() const { return ptr != nullptr; } /** * Equality checks. */ friend bool operator==(const RCUPtr &lhs, const T *rhs) { return lhs.get() == rhs; } friend bool operator==(const RCUPtr &lhs, const RCUPtr &rhs) { return lhs == rhs.get(); } friend bool operator!=(const RCUPtr &lhs, const T *rhs) { return !(lhs == rhs); } friend bool operator!=(const RCUPtr &lhs, const RCUPtr &rhs) { return !(lhs == rhs); } /** * ostream support. */ friend std::ostream &operator<<(std::ostream &stream, const RCUPtr &rhs) { return stream << rhs.ptr; } }; #define IMPLEMENT_RCU_REFCOUNT(T) \ private: \ mutable std::atomic refcount{0}; \ \ void acquire() const { refcount++; } \ \ bool tryDecrement() const { \ T count = refcount.load(); \ while (count > 0) { \ if (refcount.compare_exchange_weak(count, count - 1)) { \ return true; \ } \ } \ \ return false; \ } \ \ void release() const { \ if (tryDecrement()) { \ return; \ } \ \ RCULock::registerCleanup([this] { \ if (tryDecrement()) { \ return; \ } \ \ delete this; \ }); \ } \ \ static_assert(std::is_integral::value, "T must be an integral type."); \ static_assert(std::is_unsigned::value, "T must be unsigned."); \ \ template friend class ::RCUPtr #endif // BITCOIN_RCU_H diff --git a/src/rpc/command.h b/src/rpc/command.h index bece36733..d469da83a 100644 --- a/src/rpc/command.h +++ b/src/rpc/command.h @@ -1,62 +1,63 @@ // Copyright (c) 2018-2019 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_RPC_COMMAND_H #define BITCOIN_RPC_COMMAND_H #include -#include - #include class JSONRPCRequest; /** * Base class for all RPC commands. RPCCommand should only * be inherited from directly if access to the entire request context is * necessary. For more typical cases where only request arguments are * required, see the RPCCommandWithArgsContext class. */ -class RPCCommand : public boost::noncopyable { +class RPCCommand { private: const std::string name; /* * Child classes should define dependencies as private members. * These dependencies must not be changed, or successive calls to the same * command will give unexpected behavior. */ // TODO: Parameter definitions (these will be used to generate help // messages as well) public: RPCCommand(const std::string &nameIn) : name(nameIn) {} virtual ~RPCCommand() {} + RPCCommand(const RPCCommand &) = delete; + RPCCommand &operator=(const RPCCommand &) = delete; + /** * It is recommended to override Execute(JSONRPCRequest) only if the entire * request context is required. Otherwise, use RPCCommandWithArgsContext * instead. */ virtual UniValue Execute(const JSONRPCRequest &request) const = 0; const std::string &GetName() const { return name; }; }; /** * By default, use RPCCommandWithArgsContext as the parent class for new RPC * command classes that only depend on RPC arguments. */ class RPCCommandWithArgsContext : public RPCCommand { public: RPCCommandWithArgsContext(const std::string &nameIn) : RPCCommand(nameIn) {} virtual UniValue Execute(const UniValue &args) const = 0; UniValue Execute(const JSONRPCRequest &request) const final; }; #endif // BITCOIN_RPC_COMMAND_H diff --git a/src/rpc/server.h b/src/rpc/server.h index 1e93c7080..6a9357d6a 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -1,253 +1,254 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2017-2019 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_RPC_SERVER_H #define BITCOIN_RPC_SERVER_H #include #include #include #include #include #include -#include - #include #include #include #include static const unsigned int DEFAULT_RPC_SERIALIZE_VERSION = 1; class CRPCCommand; namespace RPCServerSignals { void OnStarted(std::function slot); void OnStopped(std::function slot); } // namespace RPCServerSignals class Config; typedef std::map> RPCCommandMap; /** * Class for registering and managing all RPC calls. */ -class RPCServer : public boost::noncopyable { +class RPCServer { private: RWCollection commands; public: RPCServer() {} + RPCServer(const RPCServer &) = delete; + RPCServer &operator=(const RPCServer &) = delete; + /** * Attempts to execute an RPC command from the given request. * If no RPC command exists that matches the request, an error is returned. */ UniValue ExecuteCommand(Config &config, const JSONRPCRequest &request) const; /** * Register an RPC command. */ void RegisterCommand(std::unique_ptr command); }; /** * Query whether RPC is running */ bool IsRPCRunning(); /** Throw JSONRPCError if RPC is not running */ void RpcInterruptionPoint(); /** * Set the RPC warmup status. When this is done, all RPC calls will error out * immediately with RPC_IN_WARMUP. */ void SetRPCWarmupStatus(const std::string &newStatus); /** * Mark warmup as done. RPC calls will be processed from now on. */ void SetRPCWarmupFinished(); /** * Returns the current warmup state */ bool RPCIsInWarmup(std::string *outStatus); /** * Opaque base class for timers returned by NewTimerFunc. * This provides no methods at the moment, but makes sure that delete cleans up * the whole state. */ class RPCTimerBase { public: virtual ~RPCTimerBase() {} }; /** * RPC timer "driver". */ class RPCTimerInterface { public: virtual ~RPCTimerInterface() {} /** * Implementation name */ virtual const char *Name() = 0; /** * Factory function for timers. * RPC will call the function to create a timer that will call func in * *millis* milliseconds. * @note As the RPC mechanism is backend-neutral, it can use different * implementations of timers. * This is needed to cope with the case in which there is no HTTP server, * but only GUI RPC console, and to break the dependency of pcserver on * httprpc. */ virtual RPCTimerBase *NewTimer(std::function &func, int64_t millis) = 0; }; /** * Set the factory function for timers */ void RPCSetTimerInterface(RPCTimerInterface *iface); /** * Set the factory function for timer, but only, if unset */ void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface); /** * Unset factory function for timers */ void RPCUnsetTimerInterface(RPCTimerInterface *iface); /** * Run func nSeconds from now. * Overrides previous timer (if any). */ void RPCRunLater(const std::string &name, std::function func, int64_t nSeconds); using rpcfn_type = UniValue (*)(Config &config, const JSONRPCRequest &jsonRequest); using const_rpcfn_type = UniValue (*)(const Config &config, const JSONRPCRequest &jsonRequest); class CRPCCommand { public: //! RPC method handler reading request and assigning result. Should return //! true if request is fully handled, false if it should be passed on to //! subsequent handlers. using Actor = std::function; //! Constructor taking Actor callback supporting multiple handlers. CRPCCommand(std::string _category, std::string _name, Actor _actor, std::vector _args, intptr_t _unique_id) : category(std::move(_category)), name(std::move(_name)), actor(std::move(_actor)), argNames(std::move(_args)), unique_id(_unique_id) {} //! Simplified constructor taking plain rpcfn_type function pointer. CRPCCommand(const char *_category, const char *_name, rpcfn_type _fn, std::initializer_list _args) : CRPCCommand( _category, _name, [_fn](Config &config, const JSONRPCRequest &request, UniValue &result, bool) { result = _fn(config, request); return true; }, {_args.begin(), _args.end()}, intptr_t(_fn)) {} //! Simplified constructor taking plain const_rpcfn_type function pointer. CRPCCommand(const char *_category, const char *_name, const_rpcfn_type _fn, std::initializer_list _args) : CRPCCommand( _category, _name, [_fn](const Config &config, const JSONRPCRequest &request, UniValue &result, bool) { result = _fn(config, request); return true; }, {_args.begin(), _args.end()}, intptr_t(_fn)) {} std::string category; std::string name; Actor actor; std::vector argNames; intptr_t unique_id; }; /** * Bitcoin RPC command dispatcher. */ class CRPCTable { private: std::map> mapCommands; public: CRPCTable(); std::string help(Config &config, const std::string &name, const JSONRPCRequest &helpreq) const; /** * Execute a method. * @param request The JSONRPCRequest to execute * @returns Result of the call. * @throws an exception (UniValue) when an error happens. */ UniValue execute(Config &config, const JSONRPCRequest &request) const; /** * Returns a list of registered commands * @returns List of registered commands. */ std::vector listCommands() const; /** * Appends a CRPCCommand to the dispatch table. * * Returns false if RPC server is already running (dump concurrency * protection). * * Commands with different method names but the same unique_id will * be considered aliases, and only the first registered method name will * show up in the help text command listing. Aliased commands do not have * to have the same behavior. Server and client code can distinguish * between calls based on method name, and aliased commands can also * register different names, types, and numbers of parameters. */ bool appendCommand(const std::string &name, const CRPCCommand *pcmd); bool removeCommand(const std::string &name, const CRPCCommand *pcmd); }; bool IsDeprecatedRPCEnabled(const ArgsManager &args, const std::string &method); extern CRPCTable tableRPC; void StartRPC(); void InterruptRPC(); void StopRPC(); std::string JSONRPCExecBatch(Config &config, RPCServer &rpcServer, const JSONRPCRequest &req, const UniValue &vReq); /** * Retrieves any serialization flags requested in command line argument */ int RPCSerializationFlags(); #endif // BITCOIN_RPC_SERVER_H diff --git a/src/rwcollection.h b/src/rwcollection.h index e17ad3e6b..ca2814200 100644 --- a/src/rwcollection.h +++ b/src/rwcollection.h @@ -1,88 +1,90 @@ // Copyright (c) 2018-2019 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_RWCOLLECTION_H #define BITCOIN_RWCOLLECTION_H #include -#include #include #include #include #include #include #include -template class RWCollectionView : boost::noncopyable { +template class RWCollectionView { private: L lock; T *collection; template struct BracketType { using type = decltype(std::declval()[std::declval()]); }; public: RWCollectionView(L l, T &c) : lock(std::move(l)), collection(&c) {} RWCollectionView(RWCollectionView &&other) : lock(std::move(other.lock)), collection(other.collection) {} + RWCollectionView(const RWCollectionView &) = delete; + const RWCollectionView &operator=(const RWCollectionView) = delete; + T *operator->() { return collection; } const T *operator->() const { return collection; } /** * Iterator mechanics. */ using iterator = typename boost::range_iterator::type; iterator begin() { return std::begin(*collection); } iterator end() { return std::end(*collection); } std::reverse_iterator rbegin() { return std::rbegin(*collection); } std::reverse_iterator rend() { return std::rend(*collection); } using const_iterator = typename boost::range_iterator::type; const_iterator begin() const { return std::begin(*collection); } const_iterator end() const { return std::end(*collection); } std::reverse_iterator rbegin() const { return std::rbegin(*collection); } std::reverse_iterator rend() const { return std::rend(*collection); } /** * Forward bracket operator. */ template typename BracketType::type operator[](I &&index) { return (*collection)[std::forward(index)]; } }; template class RWCollection { private: T collection; mutable boost::shared_mutex rwmutex; public: RWCollection() : collection() {} using ReadView = RWCollectionView>; ReadView getReadView() const { return ReadView(boost::shared_lock(rwmutex), collection); } using WriteView = RWCollectionView>; WriteView getWriteView() { return WriteView(boost::unique_lock(rwmutex), collection); } }; #endif // BITCOIN_RWCOLLECTION_H diff --git a/test/lint/lint-boost-dependencies.sh b/test/lint/lint-boost-dependencies.sh index 8a89fad0b..66c2bd1ea 100755 --- a/test/lint/lint-boost-dependencies.sh +++ b/test/lint/lint-boost-dependencies.sh @@ -1,66 +1,65 @@ #!/usr/bin/env bash # # Copyright (c) 2018 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # # Guard against accidental introduction of new Boost dependencies. export LC_ALL=C EXPECTED_BOOST_INCLUDES=( boost/algorithm/string.hpp boost/algorithm/string/classification.hpp boost/algorithm/string/replace.hpp boost/algorithm/string/split.hpp boost/date_time/posix_time/posix_time.hpp boost/filesystem.hpp boost/filesystem/fstream.hpp boost/multi_index/composite_key.hpp boost/multi_index/hashed_index.hpp boost/multi_index/member.hpp boost/multi_index/ordered_index.hpp boost/multi_index/sequenced_index.hpp boost/multi_index_container.hpp - boost/noncopyable.hpp boost/preprocessor/cat.hpp boost/preprocessor/stringize.hpp boost/range/iterator.hpp boost/range/adaptor/sliced.hpp boost/signals2/connection.hpp boost/signals2/last_value.hpp boost/signals2/signal.hpp boost/test/unit_test.hpp boost/thread/condition_variable.hpp boost/thread/locks.hpp boost/thread/mutex.hpp boost/thread/shared_mutex.hpp boost/thread/thread.hpp boost/variant.hpp boost/variant/apply_visitor.hpp boost/variant/static_visitor.hpp ) for BOOST_INCLUDE in $(git grep '^#include ' | sort -u); do IS_EXPECTED_INCLUDE=0 for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do if [[ "${BOOST_INCLUDE}" == "${EXPECTED_BOOST_INCLUDE}" ]]; then IS_EXPECTED_INCLUDE=1 break fi done if [[ ${IS_EXPECTED_INCLUDE} == 0 ]]; then echo "A new Boost dependency in the form of \"${BOOST_INCLUDE}\" appears to have been introduced:" git grep "${BOOST_INCLUDE}" -- "*.cpp" "*.h" echo fi done for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do if ! git grep -q "^#include <${EXPECTED_BOOST_INCLUDE}>" -- "*.cpp" "*.h"; then echo "Good job! The Boost dependency \"${EXPECTED_BOOST_INCLUDE}\" is no longer used." echo "Please remove it from EXPECTED_BOOST_INCLUDES in $0" echo "to make sure this dependency is not accidentally reintroduced." echo fi done