diff --git a/.gitmodules b/.gitmodules index 14ad7b178..2ff5eb9c0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ -[submodule "secp256k1/upstream"] - path = secp256k1/upstream - url = https://github.com/cryptonomex/secp256k1-zkp.git [submodule "include/fc/crypto/webauthn_json"] path = include/fc/crypto/webauthn_json url = https://github.com/Tencent/rapidjson/ +[submodule "secp256k1/secp256k1"] + path = secp256k1/secp256k1 + url = https://github.com/bitcoin-core/secp256k1 diff --git a/CMakeLists.txt b/CMakeLists.txt index b21fd6cea..5408c3d88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,10 @@ elseif(NOT CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD_REQUIRED ON) endif() +# Suppress warnings on 3rdParty Library +add_definitions( -w ) add_subdirectory( secp256k1 ) +remove_definitions( -w ) IF( ECC_IMPL STREQUAL openssl ) SET( ECC_REST src/crypto/elliptic_impl_pub.cpp ) @@ -72,8 +75,7 @@ set( fc_sources src/log/log_message.cpp src/log/logger.cpp src/log/appender.cpp - src/log/console_appender.cpp - src/log/gelf_appender.cpp + src/log/console_appender.cpp src/log/dmlog_appender.cpp src/log/logger_config.cpp src/crypto/_digest_common.cpp @@ -111,6 +113,8 @@ set( fc_sources src/network/http/http_client.cpp src/compress/smaz.cpp src/compress/zlib.cpp + src/log/gelf_appender.cpp + src/log/zipkin.cpp ) file( GLOB_RECURSE fc_headers ${CMAKE_CURRENT_SOURCE_DIR} *.hpp *.h ) diff --git a/CMakeModules/FindGMP.cmake b/CMakeModules/FindGMP.cmake index b6a402d0b..3aaa4b36d 100644 --- a/CMakeModules/FindGMP.cmake +++ b/CMakeModules/FindGMP.cmake @@ -1,3 +1,5 @@ +# This module's inputs: +# GMP_STATIC - static link GMP # This module defines: # GMP_FOUND - system has GMP lib # GMP_INCLUDE_DIR - the GMP include directory @@ -32,7 +34,11 @@ else() ) set(PREVIOUS_CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES}") - set(CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_SHARED_LIBRARY_SUFFIX}") + if(GMP_STATIC) + set(CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_STATIC_LIBRARY_SUFFIX}") + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_SHARED_LIBRARY_SUFFIX}") + endif() find_library(GMP_LIBRARIES NAMES gmp HINTS ENV GMP_LIB_DIR diff --git a/include/fc/array.hpp b/include/fc/array.hpp index 38f31cbd5..d37b8bf65 100644 --- a/include/fc/array.hpp +++ b/include/fc/array.hpp @@ -116,7 +116,7 @@ namespace fc { memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } else - memset( &bi, char(0), sizeof(bi) ); + memset( bi.data, char(0), sizeof(bi.data) ); } diff --git a/include/fc/crypto/common.hpp b/include/fc/crypto/common.hpp index aa63d808d..2be0f4dc3 100644 --- a/include/fc/crypto/common.hpp +++ b/include/fc/crypto/common.hpp @@ -72,8 +72,8 @@ namespace fc { namespace crypto { * @return */ template - struct base58_str_parser, Prefixes> { - static fc::static_variant apply(const std::string& base58str) { + struct base58_str_parser, Prefixes> { + static std::variant apply(const std::string& base58str) { const auto pivot = base58str.find('_'); FC_ASSERT(pivot != std::string::npos, "No delimiter in data, cannot determine suite type: ${str}", ("str", base58str)); @@ -81,7 +81,7 @@ namespace fc { namespace crypto { auto data_str = base58str.substr(pivot + 1); FC_ASSERT(!data_str.empty(), "Data only has suite type prefix: ${str}", ("str", base58str)); - return base58_str_parser_impl, Prefixes, 0, Ts...>::apply(prefix_str, data_str); + return base58_str_parser_impl, Prefixes, 0, Ts...>::apply(prefix_str, data_str); } }; @@ -92,7 +92,7 @@ namespace fc { namespace crypto { template< typename KeyType > std::string operator()( const KeyType& key ) const { using data_type = typename KeyType::data_type; - constexpr int position = Storage::template position(); + constexpr int position = fc::get_index(); constexpr bool is_default = position == DefaultPosition; checksummed_data wrapper; @@ -122,15 +122,15 @@ namespace fc { namespace crypto { }; template - struct eq_comparator> { - using variant_type = fc::static_variant; + struct eq_comparator> { + using variant_type = std::variant; struct visitor : public fc::visitor { visitor(const variant_type &b) : _b(b) {} template bool operator()(const KeyType &a) const { - const auto &b = _b.template get(); + const auto &b = std::template get(_b); return eq_comparator::apply(a,b); } @@ -138,7 +138,7 @@ namespace fc { namespace crypto { }; static bool apply(const variant_type& a, const variant_type& b) { - return a.which() == b.which() && a.visit(visitor(b)); + return a.index() == b.index() && std::visit(visitor(b), a); } }; @@ -150,15 +150,15 @@ namespace fc { namespace crypto { }; template - struct less_comparator> { - using variant_type = fc::static_variant; + struct less_comparator> { + using variant_type = std::variant; struct visitor : public fc::visitor { visitor(const variant_type &b) : _b(b) {} template bool operator()(const KeyType &a) const { - const auto &b = _b.template get(); + const auto &b = std::template get(_b); return less_comparator::apply(a,b); } @@ -166,7 +166,7 @@ namespace fc { namespace crypto { }; static bool apply(const variant_type& a, const variant_type& b) { - return a.which() < b.which() || (a.which() == b.which() && a.visit(visitor(b))); + return a.index() < b.index() || (a.index() == b.index() && std::visit(visitor(b), a)); } }; diff --git a/include/fc/crypto/elliptic.hpp b/include/fc/crypto/elliptic.hpp index 26128682b..c16e645a4 100644 --- a/include/fc/crypto/elliptic.hpp +++ b/include/fc/crypto/elliptic.hpp @@ -24,7 +24,6 @@ namespace fc { typedef fc::array public_key_point_data; ///< the full non-compressed version of the ECC point typedef fc::array signature; typedef fc::array compact_signature; - typedef std::vector range_proof_type; typedef fc::array extended_key_data; typedef fc::sha256 blinded_hash; typedef fc::sha256 blind_signature; @@ -53,11 +52,6 @@ namespace fc { public_key child( const fc::sha256& offset )const; bool valid()const; - /** Computes new pubkey = generator * offset + old pubkey ?! */ -// public_key mult( const fc::sha256& offset )const; - /** Computes new pubkey = regenerate(offset).pubkey + old pubkey - * = offset * G + 1 * old pubkey ?! */ - public_key add( const fc::sha256& offset )const; public_key( public_key&& pk ); public_key& operator=( public_key&& pk ); @@ -150,39 +144,6 @@ namespace fc { fc::fwd my; }; - struct range_proof_info - { - int exp; - int mantissa; - uint64_t min_value; - uint64_t max_value; - }; - - commitment_type blind( const blind_factor_type& blind, uint64_t value ); - blind_factor_type blind_sum( const std::vector& blinds, uint32_t non_neg ); - /** verifies taht commnits + neg_commits + excess == 0 */ - bool verify_sum( const std::vector& commits, const std::vector& neg_commits, int64_t excess ); - bool verify_range( uint64_t& min_val, uint64_t& max_val, const commitment_type& commit, const range_proof_type& proof ); - - range_proof_type range_proof_sign( uint64_t min_value, - const commitment_type& commit, - const blind_factor_type& commit_blind, - const blind_factor_type& nonce, - int8_t base10_exp, - uint8_t min_bits, - uint64_t actual_value - ); - - bool verify_range_proof_rewind( blind_factor_type& blind_out, - uint64_t& value_out, - string& message_out, - const blind_factor_type& nonce, - uint64_t& min_val, - uint64_t& max_val, - commitment_type commit, - const range_proof_type& proof ); - range_proof_info range_get_info( const range_proof_type& proof ); - /** * Shims */ @@ -273,7 +234,6 @@ namespace fc { FC_REFLECT_TYPENAME( fc::ecc::private_key ) FC_REFLECT_TYPENAME( fc::ecc::public_key ) -FC_REFLECT( fc::ecc::range_proof_info, (exp)(mantissa)(min_value)(max_value) ) FC_REFLECT_DERIVED( fc::ecc::public_key_shim, (fc::crypto::shim), BOOST_PP_SEQ_NIL ) FC_REFLECT_DERIVED( fc::ecc::signature_shim, (fc::crypto::shim), BOOST_PP_SEQ_NIL ) FC_REFLECT_DERIVED( fc::ecc::private_key_shim, (fc::crypto::shim), BOOST_PP_SEQ_NIL ) diff --git a/include/fc/crypto/elliptic_r1.hpp b/include/fc/crypto/elliptic_r1.hpp index 16dddde89..1ada2a9d6 100644 --- a/include/fc/crypto/elliptic_r1.hpp +++ b/include/fc/crypto/elliptic_r1.hpp @@ -37,7 +37,6 @@ namespace fc { ~public_key(); bool verify( const fc::sha256& digest, const signature& sig ); public_key_data serialize()const; - public_key_point_data serialize_ecc_point()const; operator public_key_data()const { return serialize(); } diff --git a/include/fc/crypto/private_key.hpp b/include/fc/crypto/private_key.hpp index d986abca4..505bf3d3d 100644 --- a/include/fc/crypto/private_key.hpp +++ b/include/fc/crypto/private_key.hpp @@ -19,7 +19,7 @@ namespace fc { namespace crypto { class private_key { public: - using storage_type = static_variant; + using storage_type = std::variant; private_key() = default; private_key( private_key&& ) = default; diff --git a/include/fc/crypto/public_key.hpp b/include/fc/crypto/public_key.hpp index b881259aa..bee8215c8 100644 --- a/include/fc/crypto/public_key.hpp +++ b/include/fc/crypto/public_key.hpp @@ -21,7 +21,7 @@ namespace fc { namespace crypto { class public_key { public: - using storage_type = static_variant; + using storage_type = std::variant; public_key() = default; public_key( public_key&& ) = default; diff --git a/include/fc/crypto/sha1.hpp b/include/fc/crypto/sha1.hpp index 32fc2e49c..d8938f27a 100644 --- a/include/fc/crypto/sha1.hpp +++ b/include/fc/crypto/sha1.hpp @@ -13,7 +13,8 @@ class sha1 string str()const; operator string()const; - char* data()const; + char* data(); + const char* data()const; size_t data_size()const { return 20; } static sha1 hash( const char* d, uint32_t dlen ); diff --git a/include/fc/crypto/sha224.hpp b/include/fc/crypto/sha224.hpp index a6212082f..749fabc1d 100644 --- a/include/fc/crypto/sha224.hpp +++ b/include/fc/crypto/sha224.hpp @@ -16,7 +16,8 @@ class sha224 string str()const; operator string()const; - char* data()const; + char* data(); + const char* data()const; size_t data_size()const { return 224 / 8; } static sha224 hash( const char* d, uint32_t dlen ); diff --git a/include/fc/crypto/sha256.hpp b/include/fc/crypto/sha256.hpp index bef0fea68..96c6796b0 100644 --- a/include/fc/crypto/sha256.hpp +++ b/include/fc/crypto/sha256.hpp @@ -4,6 +4,8 @@ #include #include +#include + namespace fc { @@ -17,8 +19,9 @@ class sha256 string str()const; operator string()const; - char* data()const; - size_t data_size()const { return 256 / 8; } + const char* data()const; + char* data(); + size_t data_size() const { return 256 / 8; } static sha256 hash( const char* d, uint32_t dlen ); static sha256 hash( const string& ); diff --git a/include/fc/crypto/sha512.hpp b/include/fc/crypto/sha512.hpp index ef10887c5..c2d7f96d8 100644 --- a/include/fc/crypto/sha512.hpp +++ b/include/fc/crypto/sha512.hpp @@ -14,7 +14,8 @@ class sha512 string str()const; operator string()const; - char* data()const; + char* data(); + const char* data()const; size_t data_size()const { return 512 / 8; } static sha512 hash( const char* d, uint32_t dlen ); diff --git a/include/fc/crypto/signature.hpp b/include/fc/crypto/signature.hpp index 53a2a2fae..a4405193c 100644 --- a/include/fc/crypto/signature.hpp +++ b/include/fc/crypto/signature.hpp @@ -19,7 +19,7 @@ namespace fc { namespace crypto { class signature { public: - using storage_type = static_variant; + using storage_type = std::variant; signature() = default; signature( signature&& ) = default; diff --git a/include/fc/exception/exception.hpp b/include/fc/exception/exception.hpp index 83ebb338e..8ed209a43 100644 --- a/include/fc/exception/exception.hpp +++ b/include/fc/exception/exception.hpp @@ -4,7 +4,6 @@ * @brief Defines exception's used by fc */ #include -#include #include #include #include @@ -55,7 +54,7 @@ namespace fc * @see FC_RETHROW_EXCEPTION * @see FC_RETHROW_EXCEPTIONS */ - class exception + class exception : public std::exception { public: static constexpr fc::microseconds format_time_limit = fc::milliseconds( 10 ); // limit time spent formatting exceptions @@ -84,7 +83,7 @@ namespace fc const char* name()const throw(); int64_t code()const throw(); - virtual const char* what()const throw(); + const char* what()const noexcept override; /** * @return a reference to log messages that have @@ -139,7 +138,7 @@ namespace fc void from_variant( const variant& e, exception& ll ); typedef std::shared_ptr exception_ptr; - typedef optional oexception; + typedef std::optional oexception; /** @@ -187,6 +186,8 @@ namespace fc std::exception_ptr get_inner_exception()const; + static std_exception_wrapper from_current_exception(const std::exception& e); + virtual NO_RETURN void dynamic_rethrow_exception()const; virtual std::shared_ptr dynamic_copy_exception()const; private: @@ -476,10 +477,8 @@ namespace fc wdump( __VA_ARGS__ ); \ } -#define FC_LOG_AND_DROP( ... ) \ - catch( const boost::interprocess::bad_alloc& ) {\ - throw;\ - } catch( fc::exception& er ) { \ +#define FC_LOG_AND_DROP_ALL( ... ) \ + catch( fc::exception& er ) { \ wlog( "${details}", ("details",er.to_detail_string()) ); \ } catch( const std::exception& e ) { \ fc::std_exception_wrapper sew( \ @@ -496,6 +495,12 @@ namespace fc } +#define FC_LOG_AND_DROP( ... ) \ + catch( const boost::interprocess::bad_alloc& ) {\ + throw;\ + } FC_LOG_AND_DROP_ALL(__VA_ARGS__) + + /** * @def FC_RETHROW_EXCEPTIONS(LOG_LEVEL,FORMAT,...) * @brief Catchs all exception's, std::exceptions, and ... and rethrows them after diff --git a/include/fc/filesystem.hpp b/include/fc/filesystem.hpp index 7484f2a5a..389c61082 100644 --- a/include/fc/filesystem.hpp +++ b/include/fc/filesystem.hpp @@ -4,7 +4,6 @@ #include #include -#include #include namespace boost { @@ -81,6 +80,7 @@ namespace fc { bool is_relative()const; bool is_absolute()const; + bool empty() const; static char separator_char; @@ -194,13 +194,13 @@ namespace fc { { public: inline ~temp_file_base() { remove(); } - inline operator bool() const { return _path.valid(); } - inline bool operator!() const { return !_path; } + inline operator bool() const { return _path.has_value(); } + inline bool operator!() const { return !_path.has_value(); } const fc::path& path() const; void remove(); void release(); protected: - typedef fc::optional path_t; + typedef std::optional path_t; inline temp_file_base(const path_t& path) : _path(path) {} inline temp_file_base(path_t&& path) : _path(std::move(path)) {} path_t _path; diff --git a/include/fc/fwd.hpp b/include/fc/fwd.hpp index ccf0828e5..0aabe43a8 100644 --- a/include/fc/fwd.hpp +++ b/include/fc/fwd.hpp @@ -10,9 +10,8 @@ namespace fc { template class fwd { public: - template fwd( U&& u ); - template fwd( U&& u, V&& v ); - template fwd( U&& u, V&& v, X&&, Y&& ); + template + fwd( U&&... u ); fwd(); fwd( const fwd& f ); diff --git a/include/fc/fwd_impl.hpp b/include/fc/fwd_impl.hpp index 639085abe..af2b23fdd 100644 --- a/include/fc/fwd_impl.hpp +++ b/include/fc/fwd_impl.hpp @@ -58,25 +58,11 @@ namespace fc { void check_size() { static_assert( (ProvidedSize >= RequiredSize), "Failed to reserve enough space in fc::fwd" ); } template - template - fwd::fwd( U&& u ) { - check_size(); - new (this) T( fc::forward(u) ); - } - - template - template - fwd::fwd( U&& u, V&& v ) { + template + fwd::fwd( U&&... u ) { check_size(); - new (this) T( fc::forward(u), fc::forward(v) ); + new (this) T( fc::forward(u)... ); } - template - template - fwd::fwd( U&& u, V&& v, X&& x, Y&& y ) { - check_size(); - new (this) T( fc::forward(u), fc::forward(v), fc::forward(x), fc::forward(y) ); - } - template fwd::fwd() { diff --git a/include/fc/io/bio_device_adaptor.hpp b/include/fc/io/bio_device_adaptor.hpp new file mode 100644 index 000000000..609fe3671 --- /dev/null +++ b/include/fc/io/bio_device_adaptor.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +namespace fc { + +namespace bio = boost::iostreams; + +template +struct device_adaptor { + STREAM& strm; + + typedef char char_type; + typedef Category category; + size_t write(const char* data, size_t n) { return strm.write(data, n), n; } + size_t read(char* data, size_t n) { return strm.read(data, n), n; } +}; + +template +device_adaptor to_sink(STREAM& strm) { + return device_adaptor{strm}; +} + +template +device_adaptor to_source(STREAM& strm) { + return device_adaptor{strm}; +} + +template +device_adaptor to_seekable(STREAM& strm) { + return device_adaptor{strm}; +} +} // namespace fc \ No newline at end of file diff --git a/include/fc/io/cfile.hpp b/include/fc/io/cfile.hpp index 72adf331c..74723a144 100644 --- a/include/fc/io/cfile.hpp +++ b/include/fc/io/cfile.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include #include +#include #ifndef _WIN32 #define FC_FOPEN(p, m) fopen(p, m) @@ -76,6 +78,13 @@ class cfile { } } + void skip( long loc) { + if( 0 != fseek( _file.get(), loc, SEEK_CUR ) ) { + throw std::ios_base::failure( "cfile: " + _file_path.generic_string() + + " unable to SEEK_CUR to: " + std::to_string(loc) ); + } + } + void read( char* d, size_t n ) { size_t result = fread( d, 1, n, _file.get() ); if( result != n ) { @@ -113,6 +122,17 @@ class cfile { } } + bool eof() const { return feof(_file.get()) != 0; } + + int getc() { + int ret = fgetc(_file.get()); + if (ret == EOF) { + throw std::ios_base::failure( "cfile: " + _file_path.generic_string() + + " unable to read 1 byte"); + } + return ret; + } + void close() { _file.reset(); _open = false; @@ -159,6 +179,27 @@ inline cfile_datastream cfile::create_datastream() { return cfile_datastream(*this); } +/* + * @brief datastream adapter that adapts cfile for use with fc pack + * + * This class supports pack functionality but not unpack. + */ +template <> +class datastream : public fc::cfile { + public: + using fc::cfile::cfile; + + bool seekp(size_t pos) { return this->seek(pos), true; } + + bool get(char& c) { + c = this->getc(); + return true; + } + + fc::cfile& storage() { return *this; } + const fc::cfile& storage() const { return *this; } +}; + } // namespace fc diff --git a/include/fc/io/datastream.hpp b/include/fc/io/datastream.hpp index 1ac171e1e..7306f0622 100644 --- a/include/fc/io/datastream.hpp +++ b/include/fc/io/datastream.hpp @@ -1,7 +1,9 @@ #pragma once #include +#include #include #include +#include #include @@ -12,15 +14,18 @@ namespace detail NO_RETURN void throw_datastream_range_error( const char* file, size_t len, int64_t over ); } +template +class datastream; + /** - * The purpose of this datastream is to provide a fast, effecient, means + * The purpose of this datastream is to provide a fast, efficient, means * of calculating the amount of data "about to be written" and then * writing it. This means having two modes of operation, "test run" where * you call the entire pack sequence calculating the size, and then * actually packing it after doing a single allocation. */ template -class datastream { +class datastream || std::is_same_v>> { public: datastream( T start, size_t s ) :_start(start),_pos(start),_end(start+s){}; @@ -37,7 +42,7 @@ class datastream { } inline bool write( const char* d, size_t s ) { - if( _end - _pos >= (int32_t)s ) { + if( size_t(_end - _pos) >= (size_t)s ) { memcpy( _pos, d, s ); _pos += s; return true; @@ -77,7 +82,7 @@ class datastream { }; template<> -class datastream { +class datastream { public: datastream( size_t init_size = 0):_size(init_size){}; inline bool skip( size_t s ) { _size += s; return true; } @@ -91,6 +96,86 @@ class datastream { size_t _size; }; +template +class datastream>> { + private: + Streambuf buf; + + public: + template + datastream(Args&&... args) + : buf(std::forward(args)...) {} + + size_t read(char* data, size_t n) { return buf.sgetn(data, n); } + size_t write(const char* data, size_t n) { return buf.sputn(data, n); } + size_t tellp() { return this->pubseekoff(0, std::ios::cur); } + bool skip(size_t p) { this->pubseekoff(p, std::ios::cur); return true; } + bool get(char& c) { + c = buf.sbumpc(); + return true; + } + bool seekp(size_t off) { + buf.pubseekoff(off, std::ios::beg); + return true; + } + bool remaining() { return buf.in_avail(); } + + Streambuf& storage() { return buf; } + const Streambuf& storage() const { return buf; } +}; + +template +class datastream, Container> || + std::is_same_v, Container>)>> { + private: + Container _container; + size_t cur; + + public: + template + datastream(Args&&... args) + : _container(std::forward(args)...) + , cur(0) {} + + size_t read(char* s, size_t n) { + if (cur + n > _container.size()) { + FC_THROW_EXCEPTION(out_of_range_exception, + "read datastream> of length ${len} over by ${over}", + ("len", _container.size())("over", _container.size() - n)); + } + std::copy_n(_container.begin() + cur, n, s); + cur += n; + return n; + } + + size_t write(const char* s, size_t n) { + _container.resize(std::max(cur + n, _container.size())); + std::copy_n(s, n, _container.begin() + cur); + cur += n; + return n; + } + + bool seekp(size_t off) { + cur = off; + return true; + } + + size_t tellp() const { return cur; } + bool skip(size_t p) { cur += p; return true; } + + bool get(char& c) { + this->read(&c, 1); + return true; + } + + size_t remaining() const { return _container.size() - cur; } + + Container& storage() { return _container; } + const Container& storage() const { return _container; } +}; + + + template inline datastream& operator<<(datastream& ds, const __int128& d) { ds.write( (const char*)&d, sizeof(d) ); diff --git a/include/fc/io/json.hpp b/include/fc/io/json.hpp index 686e8a518..cdae756c5 100644 --- a/include/fc/io/json.hpp +++ b/include/fc/io/json.hpp @@ -31,15 +31,9 @@ namespace fc stringify_large_ints_and_doubles = 0, legacy_generator = 1 }; - using yield_function_t = fc::optional_delegate; + using yield_function_t = fc::optional_delegate; static constexpr uint64_t max_length_limit = std::numeric_limits::max(); - static constexpr size_t escape_string_yeild_check_count = 128; - static ostream& to_stream( ostream& out, const fc::string&, const yield_function_t& yield ); - static ostream& to_stream( ostream& out, const variant& v, const yield_function_t& yield, const output_formatting format = output_formatting::stringify_large_ints_and_doubles ); - static ostream& to_stream( ostream& out, const variants& v, const yield_function_t& yield, const output_formatting format = output_formatting::stringify_large_ints_and_doubles ); - static ostream& to_stream( ostream& out, const variant_object& v, const yield_function_t& yield, const output_formatting format = output_formatting::stringify_large_ints_and_doubles ); - static ostream& to_stream( ostream& out, const variant& v, const fc::time_point& deadline, const output_formatting format = output_formatting::stringify_large_ints_and_doubles, const uint64_t max_len = max_length_limit ); - + static constexpr size_t escape_string_yield_check_count = 128; static variant from_string( const string& utf8_str, const parse_type ptype = parse_type::legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); static variants variants_from_string( const string& utf8_str, const parse_type ptype = parse_type::legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); static string to_string( const variant& v, const yield_function_t& yield, const output_formatting format = output_formatting::stringify_large_ints_and_doubles); @@ -65,9 +59,9 @@ namespace fc template static string to_string( const T& v, const fc::time_point& deadline, const output_formatting format = output_formatting::stringify_large_ints_and_doubles, const uint64_t max_len = max_length_limit ) { - const auto yield = [&](std::ostream& os) { + const auto yield = [&](size_t s) { FC_CHECK_DEADLINE(deadline); - FC_ASSERT(os.tellp() <= max_len); + FC_ASSERT(s <= max_len); }; return to_string( variant(v), yield, format ); } @@ -75,9 +69,9 @@ namespace fc template static string to_pretty_string( const T& v, const fc::time_point& deadline = fc::time_point::maximum(), const output_formatting format = output_formatting::stringify_large_ints_and_doubles, const uint64_t max_len = max_length_limit ) { - const auto yield = [&](std::ostream& os) { + const auto yield = [&](size_t s) { FC_CHECK_DEADLINE(deadline); - FC_ASSERT( os.tellp() <= max_len ); + FC_ASSERT( s <= max_len ); }; return to_pretty_string( variant(v), yield, format ); } @@ -89,7 +83,8 @@ namespace fc } }; - void escape_string( const string& str, std::ostream& os, const json::yield_function_t& yield ); + std::string escape_string( const std::string_view& str, const json::yield_function_t& yield, bool escape_control_chars = true ); + } // fc #undef DEFAULT_MAX_RECURSION_DEPTH diff --git a/include/fc/io/raw.hpp b/include/fc/io/raw.hpp index 00bd74985..62fb508b4 100644 --- a/include/fc/io/raw.hpp +++ b/include/fc/io/raw.hpp @@ -3,17 +3,18 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include #include +#include #include #include @@ -27,11 +28,12 @@ namespace fc { namespace bip = boost::interprocess; using shared_string = bip::basic_string< char, std::char_traits< char >, bip::allocator >; - using namespace boost::multiprecision; template - using UInt = number >; + using UInt = boost::multiprecision::number< + boost::multiprecision::cpp_int_backend >; template - using Int = number >; + using Int = boost::multiprecision::number< + boost::multiprecision::cpp_int_backend >; template void pack( Stream& s, const UInt<256>& n ); template void unpack( Stream& s, UInt<256>& n ); template void pack( Stream& s, const Int<256>& n ); @@ -267,13 +269,13 @@ namespace fc { // optional template - void pack( Stream& s, const fc::optional& v ) { - fc::raw::pack( s, bool(!!v) ); - if( !!v ) fc::raw::pack( s, *v ); + void pack( Stream& s, const std::optional& v ) { + fc::raw::pack( s, v.has_value() ); + if( v ) fc::raw::pack( s, *v ); } template - void unpack( Stream& s, fc::optional& v ) + void unpack( Stream& s, std::optional& v ) { try { bool b; fc::raw::unpack( s, b ); if( b ) { v = T(); fc::raw::unpack( s, *v ); } @@ -583,6 +585,26 @@ namespace fc { } } + template + inline void pack( Stream& s, const std::list& value ) { + FC_ASSERT( value.size() <= MAX_NUM_ARRAY_ELEMENTS ); + fc::raw::pack( s, unsigned_int((uint32_t)value.size()) ); + for( const auto& i : value ) { + fc::raw::pack( s, i ); + } + } + + template + inline void unpack( Stream& s, std::list& value ) { + unsigned_int size; fc::raw::unpack( s, size ); + FC_ASSERT( size.value <= MAX_NUM_ARRAY_ELEMENTS ); + while( size.value-- ) { + T i; + fc::raw::unpack( s, i ); + value.emplace_back( std::move( i ) ); + } + } + template inline void pack( Stream& s, const std::set& value ) { FC_ASSERT( value.size() <= MAX_NUM_ARRAY_ELEMENTS ); @@ -746,18 +768,18 @@ namespace fc { template - void pack( Stream& s, const static_variant& sv ) + void pack( Stream& s, const std::variant& sv ) { - fc::raw::pack( s, unsigned_int(sv.which()) ); - sv.visit( pack_static_variant(s) ); + fc::raw::pack( s, unsigned_int(sv.index()) ); + std::visit( pack_static_variant(s), sv ); } - template void unpack( Stream& s, static_variant& sv ) + template void unpack( Stream& s, std::variant& sv ) { unsigned_int w; fc::raw::unpack( s, w ); - sv.set_which(w.value); - sv.visit( unpack_static_variant(s) ); + fc::from_index(sv, w.value); + std::visit( unpack_static_variant(s), sv ); } diff --git a/include/fc/io/raw_fwd.hpp b/include/fc/io/raw_fwd.hpp index cb334cc67..60acfc724 100644 --- a/include/fc/io/raw_fwd.hpp +++ b/include/fc/io/raw_fwd.hpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace fc { class time_point; @@ -17,8 +18,7 @@ namespace fc { class variant; class variant_object; class path; - template class static_variant; - + template class enum_type; namespace ip { class endpoint; } @@ -47,8 +47,8 @@ namespace fc { template inline void pack( Stream& s, const std::unordered_set& value ); template inline void unpack( Stream& s, std::unordered_set& value ); - template void pack( Stream& s, const static_variant& sv ); - template void unpack( Stream& s, static_variant& sv ); + template void pack( Stream& s, const std::variant& sv ); + template void unpack( Stream& s, std::variant& sv ); template inline void pack( Stream& s, const std::deque& value ); template inline void unpack( Stream& s, std::deque& value ); @@ -83,9 +83,9 @@ namespace fc { template inline void unpack( Stream& s, ip::endpoint& v ); - template void unpack( Stream& s, fc::optional& v ); + template void unpack( Stream& s, std::optional& v ); template void unpack( Stream& s, const T& v ); - template void pack( Stream& s, const fc::optional& v ); + template void pack( Stream& s, const std::optional& v ); template void pack( Stream& s, const safe& v ); template void unpack( Stream& s, fc::safe& v ); diff --git a/include/fc/io/raw_variant.hpp b/include/fc/io/raw_variant.hpp index e80f39011..925040062 100644 --- a/include/fc/io/raw_variant.hpp +++ b/include/fc/io/raw_variant.hpp @@ -119,6 +119,7 @@ namespace fc { namespace raw { blob val; raw::unpack(s,val); v = fc::move(val); + return; } default: FC_THROW_EXCEPTION( parse_error_exception, "Unknown Variant Type ${t}", ("t", t) ); diff --git a/include/fc/log/logger_config.hpp b/include/fc/log/logger_config.hpp index ffcb2f978..04de647d5 100644 --- a/include/fc/log/logger_config.hpp +++ b/include/fc/log/logger_config.hpp @@ -28,11 +28,11 @@ namespace fc { string name; ostring parent; /// if not set, then parents level is used. - fc::optional level; + std::optional level; bool enabled; /// if any appenders are sepecified, then parent's appenders are not set. bool additivity; - std::vector appenders; + std::vector appenders; }; struct logging_config { diff --git a/include/fc/log/trace.hpp b/include/fc/log/trace.hpp new file mode 100644 index 000000000..31010e6f7 --- /dev/null +++ b/include/fc/log/trace.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include +#include +#include + +/// @param trace_str const char* identifier for trace +/// @return implementation defined type RAII object that submits trace on exit of scope +inline ::std::optional<::fc::zipkin_span> fc_create_trace(const char* trace_str) { + return ::fc::zipkin_config::is_enabled() + ? ::std::optional<::fc::zipkin_span>(::std::in_place, ::fc::zipkin_config::get_next_unique_id(), + (trace_str), 0, 0) + : ::std::optional<::fc::zipkin_span>{}; +} + +/// @param trace_str const char* identifier for trace +/// @param trace_id fc::sha256 id to use +/// @return implementation defined type RAII object that submits trace on exit of scope +inline ::std::optional<::fc::zipkin_span> fc_create_trace_with_id(const char* trace_str, const fc::sha256& trace_id) { + return ::fc::zipkin_config::is_enabled() + ? ::std::optional<::fc::zipkin_span>(::std::in_place, ::fc::zipkin_span::to_id(trace_id), (trace_str), 0 , 0) + : ::std::optional<::fc::zipkin_span>{}; +} + +/// @param condition create the trace only when the condition is true +/// @param trace_str const char* identifier for trace +/// @param trace_id fc::sha256 id to use +/// @return implementation defined type RAII object that submits trace on exit of scope +inline ::std::optional<::fc::zipkin_span> fc_create_trace_with_id_if(bool condition, const char* trace_str, const fc::sha256& trace_id) { + return (condition && ::fc::zipkin_config::is_enabled()) + ? ::std::optional<::fc::zipkin_span>(::std::in_place, ::fc::zipkin_span::to_id(trace_id), (trace_str), ::fc::zipkin_span::to_id(trace_id) , 0) + : ::std::optional<::fc::zipkin_span>{}; +} + +inline ::std::optional<::fc::zipkin_span> fc_create_span_with_id(const char* span_str, uint64_t id, const fc::sha256& trace_id) { + auto tid = ::fc::zipkin_span::to_id(trace_id); + return ::fc::zipkin_config::is_enabled() + ? ::std::optional<::fc::zipkin_span>(::std::in_place, id, span_str, tid, tid) + : ::std::optional<::fc::zipkin_span>{}; +} + +inline ::std::optional<::fc::zipkin_span> fc_create_trace_with_start_time(const char* trace_str, fc::time_point start) { + return ::fc::zipkin_config::is_enabled() + ? ::std::optional<::fc::zipkin_span>(::std::in_place, trace_str, start) + : ::std::optional<::fc::zipkin_span>{}; +} + +/// @param trace variable returned from fc_create_trace +/// @param span_str const char* indentifier +/// @return implementation defined type RAII object that submits span on exit of scope +inline ::std::optional<::fc::zipkin_span> fc_create_span(const ::std::optional<::fc::zipkin_span>& trace, + const char* span_str) { + return ((trace) && ::fc::zipkin_config::is_enabled()) ? (trace)->create_span((span_str)) + : ::std::optional<::fc::zipkin_span>{}; +} + +/// @param trace_token variable returned from trace.get_token() +/// @param span_str const char* indentifier +/// @return implementation defined type RAII object that submits span on exit of scope +inline ::std::optional<::fc::zipkin_span> fc_create_span_from_token(fc::zipkin_span::token trace_token, + const char* span_str) { + return ((trace_token) && ::fc::zipkin_config::is_enabled()) + ? ::fc::zipkin_span::create_span_from_token((trace_token), (span_str)) + : ::std::optional<::fc::zipkin_span>{}; +} + +/// @param span variable returned from fc_create_span +/// @param tag_key_str string key +/// @param tag_value string value +template +inline void fc_add_tag(::std::optional<::fc::zipkin_span>& span, const char* tag_key_str, Value&& value) { + if ((span) && ::fc::zipkin_config::is_enabled()) + (span)->add_tag((tag_key_str), std::forward(value)); +} + +inline fc::zipkin_span::token fc_get_token(const ::std::optional<::fc::zipkin_span>& span) { + return (span && ::fc::zipkin_config::is_enabled()) ? span->get_token() : fc::zipkin_span::token(0, 0); +} + + +#define fc_trace_log( TRACE_OR_SPAN, FORMAT, ... ) \ + FC_MULTILINE_MACRO_BEGIN \ + if( (fc::logger::get(DEFAULT_LOGGER)).is_enabled( fc::log_level::info ) ) \ + (fc::logger::get(DEFAULT_LOGGER)).log( FC_LOG_MESSAGE( info, FORMAT " traceID=${_the_trace_id_}", ("_the_trace_id_", TRACE_OR_SPAN->trace_id_string()) __VA_ARGS__ ) ); \ + FC_MULTILINE_MACRO_END + diff --git a/include/fc/log/zipkin.hpp b/include/fc/log/zipkin.hpp new file mode 100644 index 000000000..3af878547 --- /dev/null +++ b/include/fc/log/zipkin.hpp @@ -0,0 +1,195 @@ +#pragma once + +#include +#include +#include + +namespace fc { +/// Active Object that sends zipkin messages in JSON format +/// https://zipkin.io/zipkin-api/ +/// +/// Span contains following data +/// uint64_t traceId - unique id for trace, all children spans shared same id +/// std::string name - logical operation, should have low cardinality +/// uint64_t parentId - The parent span id, or absent if root span +/// uint64_t id - unique id for this span +/// int64_t timestamp - epoch microseconds of start of span +/// int64_t duration - microseconds of span +/// +/// Enable zipkin by calling zipkin_config::init() from main thread on startup. +/// Use macros defined in trace.hpp. + +class zipkin; + +class sha256; + +class zipkin_config { +public: + /// Thread safe only if init() called from main thread before spawning of any threads + static bool is_enabled() { return get_zipkin_() != nullptr; } + + /// Not thread safe, call from main thread before spawning any threads that might use zipkin. + /// @param url the url endpoint of zipkin server. e.g. http://127.0.0.1:9411/api/v2/spans + /// @param service_name the service name to include in each zipkin span + /// @param timeout_us the timeout in microseconds for each http call + /// (9 consecutive failures and zipkin is disabled, SIGHUP will reset the failure counter and re-enable zipkin) + /// @param retry_interval_us the interval in microseconds for connecting to zipkin + /// @param wait_time_seconds the initial wait time in seconds for connecting to zipkin, an exception is thrown when the connection is not established within the wait time. + static void init( const std::string& url, const std::string& service_name, uint32_t timeout_us, uint32_t retry_interval_us, uint32_t wait_time_seconds = 0 ); + + /// Thread safe only if init() called from main thread before spawning of any threads + /// @throw assert_exception if called before init() + static zipkin& get_zipkin(); + + /// Thread safe only if init() called from main thread before spawning of any threads + /// @throw assert_exception if called before init() + static void shutdown(); + + /// Starts with a random id and increments on each call, will not return 0 + static uint64_t get_next_unique_id(); + + /// Signal safe + static void handle_sighup(); + +private: + /// Provide access to initialized zipkin endpoint + /// Thread safe as long as init() called correctly + /// @return nullptr if init() not called + static zipkin* get_zipkin_() { return get().zip.get(); }; + + static zipkin_config& get(); + +private: + std::unique_ptr zip; +}; + +struct zipkin_span { + explicit zipkin_span( std::string name, uint64_t trace_id, uint64_t parent_id ) + : data( std::move( name ), trace_id, parent_id ) {} + + explicit zipkin_span( uint64_t id, std::string name, uint64_t trace_id, uint64_t parent_id ) + : data( id, std::move( name ), trace_id, parent_id ) {} + + explicit zipkin_span( std::string name, fc::time_point start ) + : data( std::move( name ), start ) {} + + zipkin_span( const zipkin_span& ) = delete; + zipkin_span& operator=( const zipkin_span& ) = delete; + zipkin_span& operator=( zipkin_span&& ) = delete; + + zipkin_span( zipkin_span&& rhs ) noexcept + : data( std::move( rhs.data ) ) { + rhs.data.id = 0; + } + + ~zipkin_span(); + + void add_tag( const std::string& key, const std::string& var ) { + // zipkin tags are required to be strings + data.tags( key, var ); + } + + void add_tag( const std::string& key, const char* var ) { + // zipkin tags are required to be strings + data.tags( key, var ); + } + + void add_tag( const std::string& key, bool v ) { + // zipkin tags are required to be strings + data.tags( key, v ? "true" : "false" ); + } + + template + std::enable_if_t>, void> + add_tag( const std::string& key, T&& var ) { + data.tags( key, std::to_string( std::forward( var ) ) ); + } + + template + std::enable_if_t>, void> + add_tag( const std::string& key, T&& var ) { + data.tags( key, (std::string) var ); + } + + struct token { + friend zipkin_span; + friend struct zipkin_trace; + friend struct optional_trace; + constexpr explicit operator bool() const noexcept { return id != 0; } + token( uint64_t id, uint64_t trace_id ) + : id( id ), trace_id( trace_id ) {} + private: + uint64_t id; + uint64_t trace_id; + }; + + token get_token() const { return token{data.id, data.trace_id }; }; + + static uint64_t to_id( const fc::sha256& id ); + + struct span_data { + explicit span_data( std::string name, uint64_t trace_id, uint64_t parent_id ) + : id( zipkin_config::get_next_unique_id() ), trace_id( trace_id ), parent_id( parent_id ), + start( time_point::now() ), name( std::move( name ) ) {} + + explicit span_data( uint64_t id, std::string name, uint64_t trace_id, uint64_t parent_id ) + : id( id ), trace_id( trace_id == 0 ? id : trace_id ), parent_id( parent_id ), start( time_point::now() ), name( std::move( name ) ) {} + + explicit span_data( std::string name, fc::time_point start) + : id( zipkin_config::get_next_unique_id() ), trace_id( zipkin_config::get_next_unique_id() ), parent_id( 0 ), + start( start), name( std::move( name ) ) {} + + span_data( const span_data& ) = delete; + span_data& operator=( const span_data& ) = delete; + span_data& operator=( span_data&& ) = delete; + span_data( span_data&& rhs ) = default; + + uint64_t id; + const uint64_t trace_id; + const uint64_t parent_id; + const fc::time_point start; + fc::time_point stop; + std::string name; + fc::mutable_variant_object tags; + }; + + [[nodiscard]] std::optional create_span( std::string name ) const { + return create_span_from_token(get_token(), std::move(name)); + } + + [[nodiscard]] static std::optional + create_span_from_token( zipkin_span::token token, std::string name ) { + return zipkin_span{std::move( name ), token.trace_id, token.id}; + } + + std::string trace_id_string() const; + + span_data data; +}; + +class zipkin { +public: + zipkin( const std::string& url, const std::string& service_name, uint32_t timeout_us, uint32_t retry_interval_us , uint32_t wait_time_seconds ); + + /// finishes logging all queued up spans + ~zipkin() = default; + + /// Starts with a random id and increments on each call, will not return 0 + uint64_t get_next_unique_id(); + + // finish logging all queued up spans, not restartable + void shutdown(); + + // Logs zipkin json via http on separate thread + void log( zipkin_span::span_data&& span ); + + // Post http request to the boost asio queue + void post_request(zipkin_span::span_data&& span); + +private: + class impl; + std::unique_ptr my; +}; + +} // namespace fc + diff --git a/include/fc/network/http/http_client.hpp b/include/fc/network/http/http_client.hpp index 47a38f434..84dd5891d 100644 --- a/include/fc/network/http/http_client.hpp +++ b/include/fc/network/http/http_client.hpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace fc { @@ -17,13 +18,21 @@ class http_client { http_client(); ~http_client(); - variant post_sync(const url& dest, const variant& payload, const time_point& deadline = time_point::maximum()); - - template - variant post_sync(const url& dest, const T& payload, const time_point& deadline = time_point::maximum()) { - variant payload_v; - to_variant(payload, payload_v); - return post_sync(dest, payload_v, deadline); + variant + post_sync(const url &dest, const variant &payload, + const time_point &deadline = time_point::maximum(), + json::output_formatting formatting = + json::output_formatting::stringify_large_ints_and_doubles); + + template + variant + post_sync(const url &dest, const T &payload, + const time_point &deadline = time_point::maximum(), + json::output_formatting formatting = + json::output_formatting::stringify_large_ints_and_doubles) { + variant payload_v; + to_variant(payload, payload_v); + return post_sync(dest, payload_v, deadline, formatting); } void add_cert(const std::string& cert_pem_string); diff --git a/include/fc/network/url.hpp b/include/fc/network/url.hpp index 09007073e..c9cd47ce8 100644 --- a/include/fc/network/url.hpp +++ b/include/fc/network/url.hpp @@ -1,6 +1,5 @@ #pragma once #include -#include #include #include #include @@ -8,9 +7,9 @@ namespace fc { - typedef fc::optional ostring; - typedef fc::optional opath; - typedef fc::optional ovariant_object; + typedef std::optional ostring; + typedef std::optional opath; + typedef std::optional ovariant_object; namespace detail { class url_impl; } @@ -28,7 +27,7 @@ namespace fc { url( const url& c ); url( url&& c ); url( const string& proto, const ostring& host, const ostring& user, const ostring& pass, - const opath& path, const ostring& query, const ovariant_object& args, const fc::optional& port); + const opath& path, const ostring& query, const ovariant_object& args, const std::optional& port); ~url(); url& operator=( const url& c ); @@ -49,7 +48,7 @@ namespace fc { opath path()const; ostring query()const; ovariant_object args()const; - fc::optional port()const; + std::optional port()const; private: friend class mutable_url; diff --git a/include/fc/optional.hpp b/include/fc/optional.hpp deleted file mode 100644 index 520bbde41..000000000 --- a/include/fc/optional.hpp +++ /dev/null @@ -1,276 +0,0 @@ -#pragma once -#include -#include - - -namespace fc { -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable:4521) /* multiple copy ctors */ -# pragma warning(disable:4522) /* multiple assignment operators */ -#endif - bool assert_optional(bool is_valid ); // defined in exception.cpp - - /** - * @brief provides stack-based nullable value similar to boost::optional - * - * Simply including boost::optional adds 35,000 lines to each object file, using - * fc::optional adds less than 400. - */ - template - class optional - { - public: - typedef T value_type; - typedef typename std::aligned_storage::type storage_type; - - optional():_valid(false){} - ~optional(){ reset(); } - - optional( optional& o ) - :_valid(false) - { - if( o._valid ) new (ptr()) T( *o ); - _valid = o._valid; - } - - optional( const optional& o ) - :_valid(false) - { - if( o._valid ) new (ptr()) T( *o ); - _valid = o._valid; - } - - optional( optional&& o ) - :_valid(false) - { - if( o._valid ) new (ptr()) T( fc::move(*o) ); - _valid = o._valid; - o.reset(); - } - - template - optional( const optional& o ) - :_valid(false) - { - if( o._valid ) new (ptr()) T( *o ); - _valid = o._valid; - } - - template - optional( optional& o ) - :_valid(false) - { - if( o._valid ) - { - new (ptr()) T( *o ); - } - _valid = o._valid; - } - - template - optional( optional&& o ) - :_valid(false) - { - if( o._valid ) new (ptr()) T( fc::move(*o) ); - _valid = o._valid; - o.reset(); - } - - template - optional( U&& u ) - :_valid(true) - { - new ((char*)ptr()) T( fc::forward(u) ); - } - - template - optional& operator=( U&& u ) - { - reset(); - new (ptr()) T( fc::forward(u) ); - _valid = true; - return *this; - } - - template - void emplace(Args&& ... args) { - if (_valid) { - reset(); - } - - new ((char*)ptr()) T( fc::forward(args)... ); - _valid = true; - } - - template - optional& operator=( optional& o ) { - if (this != &o) { - if( _valid && o._valid ) { - ref() = *o; - } else if( !_valid && o._valid ) { - new (ptr()) T( *o ); - _valid = true; - } else if (_valid) { - reset(); - } - } - return *this; - } - template - optional& operator=( const optional& o ) { - if (this != &o) { - if( _valid && o._valid ) { - ref() = *o; - } else if( !_valid && o._valid ) { - new (ptr()) T( *o ); - _valid = true; - } else if (_valid) { - reset(); - } - } - return *this; - } - - optional& operator=( optional& o ) { - if (this != &o) { - if( _valid && o._valid ) { - ref() = *o; - } else if( !_valid && o._valid ) { - new (ptr()) T( *o ); - _valid = true; - } else if (_valid) { - reset(); - } - } - return *this; - } - - optional& operator=( const optional& o ) { - if (this != &o) { - if( _valid && o._valid ) { - ref() = *o; - } else if( !_valid && o._valid ) { - new (ptr()) T( *o ); - _valid = true; - } else if (_valid) { - reset(); - } - } - return *this; - } - - template - optional& operator=( optional&& o ) - { - if (this != &o) - { - if( _valid && o._valid ) - { - ref() = fc::move(*o); - o.reset(); - } else if ( !_valid && o._valid ) { - *this = fc::move(*o); - } else if (_valid) { - reset(); - } - } - return *this; - } - - optional& operator=( optional&& o ) - { - if (this != &o) - { - if( _valid && o._valid ) - { - ref() = fc::move(*o); - o.reset(); - } else if ( !_valid && o._valid ) { - *this = fc::move(*o); - } else if (_valid) { - reset(); - } - } - return *this; - } - - bool valid()const { return _valid; } - bool operator!()const { return !_valid; } - - // this operation is not safe and can result in unintential - // casts and comparisons, use valid() or !! - explicit operator bool()const { return _valid; } - - T& operator*() { assert(_valid); return ref(); } - const T& operator*()const { assert(_valid); return ref(); } - - T* operator->() - { - assert(_valid); - return ptr(); - } - const T* operator->()const - { - assert(_valid); - return ptr(); - } - - optional& operator=(std::nullptr_t) - { - reset(); - return *this; - } - - friend bool operator < ( const optional a, optional b ) - { - if( a.valid() && b.valid() ) return *a < *b; - return a.valid() < b.valid(); - } - friend bool operator == ( const optional a, optional b ) - { - if( a.valid() && b.valid() ) return *a == *b; - return a.valid() == b.valid(); - } - - void reset() - { - if( _valid ) - { - ref().~T(); // cal destructor - } - _valid = false; - } - private: - template friend class optional; - T& ref() { return *ptr(); } - const T& ref()const { return *ptr(); } - T* ptr() { return reinterpret_cast(&_value); } - const T* ptr()const { return reinterpret_cast(&_value); } - - bool _valid; - storage_type _value; - }; - - template - bool operator == ( const optional& left, const optional& right ) { - return (!left == !right) || (!!left && *left == *right); - } - template - bool operator == ( const optional& left, const U& u ) { - return !!left && *left == u; - } - template - bool operator != ( const optional& left, const optional& right ) { - return (!left != !right) || (!!left && *left != *right); - } - template - bool operator != ( const optional& left, const U& u ) { - return !left || *left != u; - } - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -} // namespace fc diff --git a/include/fc/reflect/typename.hpp b/include/fc/reflect/typename.hpp index d96cfd9b2..889c8fefa 100644 --- a/include/fc/reflect/typename.hpp +++ b/include/fc/reflect/typename.hpp @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -58,7 +57,7 @@ namespace fc { return n.c_str(); } }; - template struct get_typename> + template struct get_typename> { static const char* name() { static std::string n = std::string("optional<") + get_typename::name() + ">"; diff --git a/include/fc/reflect/variant.hpp b/include/fc/reflect/variant.hpp index f26f73cbe..15b4e309b 100644 --- a/include/fc/reflect/variant.hpp +++ b/include/fc/reflect/variant.hpp @@ -25,9 +25,9 @@ namespace fc private: template - void add( mutable_variant_object& vo, const char* name, const optional& v )const + void add( mutable_variant_object& vo, const char* name, const std::optional& v )const { - if( v.valid() ) + if( v ) vo(name,*v); } template diff --git a/include/fc/rpc/api_connection.hpp b/include/fc/rpc/api_connection.hpp index c2268ea72..d0ca7c12f 100644 --- a/include/fc/rpc/api_connection.hpp +++ b/include/fc/rpc/api_connection.hpp @@ -1,6 +1,5 @@ #pragma once #include -#include #include #include #include @@ -8,7 +7,6 @@ #include #include #include -//#include namespace fc { class api_connection; @@ -174,7 +172,7 @@ namespace fc { std::function to_generic( const std::function(Args...)>& f )const; template - std::function to_generic( const std::function>(Args...)>& f )const; + std::function to_generic( const std::function>(Args...)>& f )const; template std::function to_generic( const std::function& f )const; @@ -393,7 +391,7 @@ namespace fc { } template std::function generic_api::api_visitor::to_generic( - const std::function>(Args...)>& f )const + const std::function>(Args...)>& f )const { auto api_con = _api_con; auto gapi = &_api; diff --git a/include/fc/rpc/binary_api_connection.hpp b/include/fc/rpc/binary_api_connection.hpp index 9c9ce2f7d..4e389f515 100644 --- a/include/fc/rpc/binary_api_connection.hpp +++ b/include/fc/rpc/binary_api_connection.hpp @@ -1,7 +1,6 @@ #pragma once #include #include -#include #include #include #include @@ -9,7 +8,6 @@ #include #include #include -//#include namespace fc { class binary_api_connection; @@ -178,7 +176,7 @@ namespace fc { std::function to_generic( const std::function(Args...)>& f )const; template - std::function to_generic( const std::function>(Args...)>& f )const; + std::function to_generic( const std::function>(Args...)>& f )const; template std::function to_generic( const std::function& f )const; @@ -401,7 +399,7 @@ namespace fc { } template std::function generic_api::api_visitor::to_generic( - const std::function>(Args...)>& f )const + const std::function>(Args...)>& f )const { auto api_con = _api_con; auto gapi = &api; diff --git a/include/fc/rpc/json_connection.hpp b/include/fc/rpc/json_connection.hpp deleted file mode 100644 index 04cd041b0..000000000 --- a/include/fc/rpc/json_connection.hpp +++ /dev/null @@ -1,315 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -namespace fc { namespace rpc { - - namespace detail { class json_connection_impl; } - - /** - * @brief Implements JSON-RPC 2.0 over a set of io streams - * - * Each JSON RPC message is expected to be on its own line, violators - * will be prosecuted to the fullest extent of the law. - */ - class json_connection - { - public: - typedef std::function method; - typedef std::function named_param_method; - - json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out ); - ~json_connection(); - - /** - * Starts processing messages from input - */ - future exec(); - - bool is_open(); - void close(); - - void set_on_disconnected_callback(std::function callback); - - logger get_logger()const; - void set_logger( const logger& l ); - - /** - * @name server interface - * - * Adding methods to the interface allows the remote side - * to call them. - */ - ///@{ - void add_method( const fc::string& name, method ); - void add_named_param_method( const fc::string& name, named_param_method ); - void remove_method( const fc::string& name ); - //@} - - /** - * @name client interface - */ - ///@{ - void notice( const fc::string& method ); - void notice( const fc::string& method, const variants& args ); - void notice( const fc::string& method, const variant_object& named_args ); - - /// args will be handled as named params - future async_call( const fc::string& method, - const variant_object& args ); - - future async_call( const fc::string& method, mutable_variant_object args ); - - /// Sending in an array of variants will be handled as positional arguments - future async_call( const fc::string& method, - const variants& args ); - - future async_call( const fc::string& method ); - - future async_call( const fc::string& method, - const variant& a1 ); - - future async_call( const fc::string& method, - const variant& a1, - const variant& a2 ); - - future async_call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3 ); - - future async_call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4 ); - - future async_call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5 ); - - future async_call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - const variant& a6 ); - - future async_call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - const variant& a6, - const variant& a7 - ); - - future async_call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - const variant& a6, - const variant& a7, - const variant& a8 - ); - future async_call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - const variant& a6, - const variant& a7, - const variant& a8, - const variant& a9 - ); - future async_call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - const variant& a6, - const variant& a7, - const variant& a8, - const variant& a9, - const variant& a10 - ); - - template - Result call( const fc::string& method, - const variants& args, - microseconds timeout = microseconds::maximum()) - { - return async_call( method, args ).wait(timeout).as(); - } - - template - Result call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - microseconds timeout = microseconds::maximum()) - { - return async_call( method, a1, a2, a3 ).wait(timeout).as(); - } - - template - Result call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - microseconds timeout = microseconds::maximum()) - { - return async_call( method, a1, a2, a3, a4).wait(timeout).as(); - } - - template - Result call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - microseconds timeout = microseconds::maximum()) - { - return async_call( method, a1, a2, a3, a4, a5).wait(timeout).as(); - } - - template - Result call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - const variant& a6, - microseconds timeout = microseconds::maximum()) - { - return async_call( method, a1, a2, a3, a4, a5, a6).wait(timeout).as(); - } - template - Result call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - const variant& a6, - const variant& a7, - microseconds timeout = microseconds::maximum()) - { - return async_call( method, a1, a2, a3, a4, a5, a6, a7).wait(timeout).as(); - } - - template - Result call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - const variant& a6, - const variant& a7, - const variant& a8, - microseconds timeout = microseconds::maximum()) - { - return async_call( method, a1, a2, a3, a4, a5, a6, a7, a8).wait(timeout).as(); - } - - template - Result call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - const variant& a6, - const variant& a7, - const variant& a8, - const variant& a9, - microseconds timeout = microseconds::maximum()) - { - return async_call( method, a1, a2, a3, a4, a5, a6, a7, a8, a9).wait(timeout).as(); - } - - template - Result call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - const variant& a6, - const variant& a7, - const variant& a8, - const variant& a9, - const variant& a10, - microseconds timeout = microseconds::maximum()) - { - return async_call( method, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10).wait(timeout).as(); - } - - template - Result call( const fc::string& method, - const variant& a1, - const variant& a2, - microseconds timeout = microseconds::maximum()) - { - return async_call( method, a1, a2 ).wait(timeout).as(); - } - - template - Result call( const fc::string& method, - const variant& a1, - microseconds timeout = microseconds::maximum()) - { - return async_call( method, a1 ).wait(timeout).as(); - } - - template - Result call( const fc::string& method, - variant_object a1, - microseconds timeout = microseconds::maximum()) - { - return async_call( method, fc::move(a1) ).wait(timeout).as(); - } - template - Result call( const fc::string& method, - mutable_variant_object a1, - microseconds timeout = microseconds::maximum()) - { - return async_call( method, variant_object( fc::move(a1) ) ).wait(timeout).as(); - } - - - template - Result call( const fc::string& method, microseconds timeout = microseconds::maximum() ) - { - return async_call( method ).wait(timeout).as(); - } - - /// Sending in a variant_object will be issued as named parameters - variant call( const fc::string& method, const variant_object& named_args ); - ///@} - - private: - std::unique_ptr my; - }; - typedef std::shared_ptr json_connection_ptr; - -}} // fc::rpc - - - diff --git a/include/fc/rpc/variant_connection.hpp b/include/fc/rpc/variant_connection.hpp index 93cb29b1e..04d2cdf8d 100644 --- a/include/fc/rpc/variant_connection.hpp +++ b/include/fc/rpc/variant_connection.hpp @@ -53,67 +53,67 @@ namespace fc { namespace rpc { void notice( const fc::string& method, const variant_object& named_args ); /// args will be handled as named params - future async_call( const fc::string& method, - const variant_object& args ); + future async_call( const fc::string& method, + const variant_object& args ); - future async_call( const fc::string& method, mutable_variant_object args ); + future async_call( const fc::string& method, mutable_variant_object args ); /// Sending in an array of variants will be handled as positional arguments - future async_call( const fc::string& method, - const variants& args ); + future async_call( const fc::string& method, + const variants& args ); - future async_call( const fc::string& method ); + future async_call( const fc::string& method ); - future async_call( const fc::string& method, - const variant& a1 ); + future async_call( const fc::string& method, + const fc::variant& a1 ); - future async_call( const fc::string& method, - const variant& a1, - const variant& a2 ); + future async_call( const fc::string& method, + const fc::variant& a1, + const fc::variant& a2 ); - future async_call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3 ); + future async_call( const fc::string& method, + const fc::variant& a1, + const fc::variant& a2, + const fc::variant& a3 ); template Result call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - microseconds timeout = microseconds::maximum()) + const fc::variant& a1, + const fc::variant& a2, + const fc::variant& a3, + microseconds timeout = microseconds::maximum()) { return async_call( method, a1, a2, a3 ).wait(timeout).as(); } template Result call( const fc::string& method, - const variant& a1, - const variant& a2, - microseconds timeout = microseconds::maximum()) + const fc::variant& a1, + const fc::variant& a2, + microseconds timeout = microseconds::maximum()) { return async_call( method, a1, a2 ).wait(timeout).as(); } template Result call( const fc::string& method, - const variant& a1, - microseconds timeout = microseconds::maximum()) + const fc::variant& a1, + microseconds timeout = microseconds::maximum()) { return async_call( method, a1 ).wait(timeout).as(); } template Result call( const fc::string& method, - variant_object a1, - microseconds timeout = microseconds::maximum()) + variant_object a1, + microseconds timeout = microseconds::maximum()) { return async_call( method, fc::move(a1) ).wait(timeout).as(); } template Result call( const fc::string& method, - mutable_variant_object a1, - microseconds timeout = microseconds::maximum()) + mutable_variant_object a1, + microseconds timeout = microseconds::maximum()) { return async_call( method, variant_object( fc::move(a1) ) ).wait(timeout).as(); } diff --git a/include/fc/rpc/variant_stream.hpp b/include/fc/rpc/variant_stream.hpp index 585b776b0..9c9bc2e42 100644 --- a/include/fc/rpc/variant_stream.hpp +++ b/include/fc/rpc/variant_stream.hpp @@ -28,7 +28,7 @@ namespace fc int64_t wait(); // wait for variants to be posted private: - std::vector _variants; + std::vector _variants; uint64_t _read_pos; uint64_t _write_pos; }; diff --git a/include/fc/static_variant.hpp b/include/fc/static_variant.hpp index b7d047bda..d9731490d 100644 --- a/include/fc/static_variant.hpp +++ b/include/fc/static_variant.hpp @@ -1,600 +1,93 @@ -/** This source adapted from https://github.com/kmicklas/variadic-static_variant - * - * Copyright (C) 2013 Kenneth Micklas - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **/ #pragma once #include #include +#include #include #include +#include namespace fc { -// Implementation details, the user should not import this: -namespace impl { - -template -struct storage_ops; - -template -struct position; - -template -struct type_at; - -template -struct type_info; - -template< typename Visitor, typename ...Ts> -struct const_result_type_info; - -template< typename Visitor, typename ...Ts> -struct result_type_info; - -template< typename Visitor, typename ...Ts> -struct rvalue_ref_result_type_info; +template +struct visitor {}; -template -struct copy_construct +template +void from_index(variant& v, int index) { - StaticVariant& sv; - copy_construct( StaticVariant& s ):sv(s){} - template - void operator()( const T& v )const - { - sv.init(v); - } -}; - -template -struct move_construct + if constexpr(i >= std::variant_size_v) + { + FC_THROW_EXCEPTION(fc::assert_exception, "Provided index out of range for variant."); + } + else if (index == 0) + { + auto value = variant(std::in_place_index); + v = std::move(value); + } + else + { + from_index(v, index - 1); + } +} + +template +constexpr std::size_t get_index() { - StaticVariant& sv; - move_construct( StaticVariant& s ):sv(s){} - template - void operator()( T& v )const - { - sv.init( std::move(v) ); - } -}; - -template -struct storage_ops { - static void del(int n, void *data) {} - static void con(int n, void *data) {} - - template - static R apply(int n, void *data, visitor&& v) {} - - template - static R apply(int n, const void *data, visitor&& v) {} - - template - static R apply_rvalue_ref(int n, void *data, visitor&& v) {} - - template class Op> - static R apply_binary_operator(int n, const void *lhs, const void *rhs) {} -}; - -template -struct storage_ops { - static void del(int n, void *data) { - if(n == N) reinterpret_cast(data)->~T(); - else storage_ops::del(n, data); - } - static void con(int n, void *data) { - if(n == N) new(reinterpret_cast(data)) T(); - else storage_ops::con(n, data); - } - - template - static R apply(int n, void *data, visitor&& v) { - if(n == N) return v(*reinterpret_cast(data)); - else return storage_ops::apply(n, data, std::forward(v)); - } - - template - static R apply(int n, const void *data, visitor&& v) { - if(n == N) return v(*reinterpret_cast(data)); - else return storage_ops::apply(n, data, std::forward(v)); - } - - template - static R apply_rvalue_ref(int n, void *data, visitor&& v) { - if(n == N) return v(std::move(*reinterpret_cast(data))); - else return storage_ops::apply(n, data, std::forward(v)); - } - - template class Op> - static R apply_binary_operator(int n, const void *lhs, const void *rhs) { - if (n == N) return Op()(*reinterpret_cast(lhs), *reinterpret_cast(rhs)); - else return storage_ops::template apply_binary_operator(n, lhs, rhs); - } -}; - -template -struct storage_ops { - static void del(int n, void *data) { - FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid."); - } - static void con(int n, void *data) { - FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." ); - } - - template - static R apply(int n, void *data, visitor&& v) { - FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." ); - } - template - static R apply(int n, const void *data, visitor&& v) { - FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." ); - } - - template - static R apply_rvalue_ref(int n, void *data, visitor&& v) { - FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." ); - } - - template class Op> - static R apply_binary_operator(int n, const void *lhs, const void *rhs) { - FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." ); - } -}; - -template -using storage_ops_auto = storage_ops::result_type, N, Ts...>; - -template -using storage_ops_const_auto = storage_ops::result_type, N, Ts...>; - -template -using storage_ops_revalue_ref_auto = storage_ops::result_type, N, Ts...>; - -template -struct position { - static const int pos = -1; -}; - -template -struct position { - static const int pos = 0; -}; - -template -struct position { - static const int pos = position::pos != -1 ? position::pos + 1 : -1; -}; - -template -struct type_at<0, T, Ts...> { - using type = T; -}; - -template -struct type_at { - using type = typename type_at::type; -}; - -template class Op, typename T> -std::is_convertible, const T&, const T&>, bool> can_invoke_operator_test(int); - -template class Op, typename T> -std::false_type can_invoke_operator_test(...); - -template class Op, typename T> -using can_invoke_operator = decltype(can_invoke_operator_test(0)); - -template -struct type_info { - static const bool no_reference_types = false; - static const bool no_duplicates = position::pos == -1 && type_info::no_duplicates; - static const size_t size = type_info::size > sizeof(T&) ? type_info::size : sizeof(T&); - static const size_t count = 1 + type_info::count; - - static const bool has_equal_to = can_invoke_operator>::value && type_info::has_equal_to; - static const bool has_not_equal_to = can_invoke_operator>::value && type_info::has_not_equal_to; - static const bool has_less = can_invoke_operator>::value && type_info::has_less; - static const bool has_less_equal = can_invoke_operator>::value && type_info::has_less_equal; - static const bool has_greater = can_invoke_operator>::value && type_info::has_greater; - static const bool has_greater_equal = can_invoke_operator>::value && type_info::has_greater_equal; -}; - -template -struct type_info { - static const bool no_reference_types = type_info::no_reference_types; - static const bool no_duplicates = position::pos == -1 && type_info::no_duplicates; - static const size_t size = type_info::size > sizeof(T) ? type_info::size : sizeof(T&); - static const size_t count = 1 + type_info::count; - - static const bool has_equal_to = can_invoke_operator::value && type_info::has_equal_to; - static const bool has_not_equal_to = can_invoke_operator::value && type_info::has_not_equal_to; - static const bool has_less = can_invoke_operator::value && type_info::has_less; - static const bool has_less_equal = can_invoke_operator::value && type_info::has_less_equal; - static const bool has_greater = can_invoke_operator::value && type_info::has_greater; - static const bool has_greater_equal = can_invoke_operator::value && type_info::has_greater_equal; -}; - -template<> -struct type_info<> { - static const bool no_reference_types = true; - static const bool no_duplicates = true; - static const size_t count = 0; - static const size_t size = 0; - static const bool has_equal_to = true; - static const bool has_not_equal_to = true; - static const bool has_less = true; - static const bool has_less_equal = true; - static const bool has_greater = true; - static const bool has_greater_equal = true; -}; - -template -struct const_result_type_info { - using result_type = decltype(std::declval>()(std::declval())); -}; - -template -struct const_result_type_info { - using result_type = typename const_result_type_info::result_type; - - static_assert( - std::is_same_v::result_type >, - "Varying result types are not supported from visitors" - ); -}; - -template -struct result_type_info { - using result_type = decltype(std::declval>()(std::declval())); -}; - - -template -struct result_type_info { - using result_type = typename result_type_info::result_type; - - static_assert( - std::is_same_v::result_type >, - "Varying result types are not supported from visitors" - ); -}; - -template -struct rvalue_ref_result_type_info { - using result_type = decltype(std::declval>()(std::declval())); -}; - -template -struct rvalue_ref_result_type_info { - using result_type = typename rvalue_ref_result_type_info::result_type; + if constexpr (index == std::variant_size_v) + { + return index; + } + else if constexpr (std::is_same_v, T>) + { + return index; + } + else + { + return get_index(); + } +} + +struct from_static_variant +{ + variant& var; + from_static_variant( variant& dv ):var(dv){} - static_assert( - std::is_same_v::result_type >, - "Varying result types are not supported from visitors" - ); + template void operator()( const T& v )const + { + to_variant( v, var ); + } }; +struct to_static_variant +{ + const variant& var; + to_static_variant( const variant& dv ):var(dv){} -} // namespace impl - -template -class static_variant { - using type_info = impl::type_info; - static_assert(type_info::no_reference_types, "Reference types are not permitted in static_variant."); - static_assert(type_info::no_duplicates, "static_variant type arguments contain duplicate types."); - - alignas(Types...) char storage[impl::type_info::size]; - int _tag; - - template - void init(X&& x) { - _tag = impl::position, Types...>::pos; - new(storage) std::decay_t( std::forward(x) ); - } - - template - friend struct impl::copy_construct; - template - friend struct impl::move_construct; -public: - template - struct tag - { - static_assert( - impl::position::pos != -1, - "Type not in static_variant." - ); - static const int value = impl::position::pos; - }; - - static_variant() - { - _tag = 0; - impl::storage_ops::con(0, storage); - } - - template - static_variant( const static_variant& cpy ) - { - cpy.visit( impl::copy_construct(*this) ); - } - - static_variant( const static_variant& cpy ) - { - cpy.visit( impl::copy_construct(*this) ); - } - - static_variant( static_variant& cpy ) - : static_variant( const_cast(cpy) ) - {} - - static_variant( static_variant&& mv ) - { - mv.visit( impl::move_construct(*this) ); - } - - template - static_variant(X&& v) { - static_assert( - impl::position, Types...>::pos != -1, - "Type not in static_variant." - ); - init(std::forward(v)); - } - - ~static_variant() { - impl::storage_ops::del(_tag, storage); - } - - - template - static_variant& operator=(const X& v) { - static_assert( - impl::position::pos != -1, - "Type not in static_variant." - ); - this->~static_variant(); - init(v); - return *this; - } - static_variant& operator=( const static_variant& v ) - { - if( this == &v ) return *this; - this->~static_variant(); - v.visit( impl::copy_construct(*this) ); - return *this; - } - static_variant& operator=( static_variant&& v ) - { - if( this == &v ) return *this; - this->~static_variant(); - v.visit( impl::move_construct(*this) ); - return *this; - } - - template - friend std::enable_if_t operator == ( const static_variant& a, const static_variant& b ) - { - if (a.which() != b.which()) { - return false; - } - - return impl::storage_ops::template apply_binary_operator(a._tag, a.storage, b.storage); - } - - template - friend std::enable_if_t operator != ( const static_variant& a, const static_variant& b ) - { - if (a.which() != b.which()) { - return true; - } - - return impl::storage_ops::template apply_binary_operator(a._tag, a.storage, b.storage); - } - - template - friend std::enable_if_t operator < ( const static_variant& a, const static_variant& b ) - { - if (a.which() > b.which()) { - return false; - } - - if (a.which() < b.which()) { - return true; - } - - return impl::storage_ops::template apply_binary_operator(a._tag, a.storage, b.storage); - } - - template - friend std::enable_if_t operator <= ( const static_variant& a, const static_variant& b ) - { - if (a.which() > b.which()) { - return false; - } - - if (a.which() < b.which()) { - return true; - } - - return impl::storage_ops::template apply_binary_operator(a._tag, a.storage, b.storage); - } - - template - friend std::enable_if_t operator > ( const static_variant& a, const static_variant& b ) - { - if (a.which() < b.which()) { - return false; - } - - if (a.which() > b.which()) { - return true; - } - - return impl::storage_ops::template apply_binary_operator(a._tag, a.storage, b.storage); - } - - template - friend std::enable_if_t operator >= ( const static_variant& a, const static_variant& b ) - { - if (a.which() < b.which()) { - return false; - } - - if (a.which() > b.which()) { - return true; - } - - return impl::storage_ops::template apply_binary_operator(a._tag, a.storage, b.storage); - } - - template - X& get() & { - static_assert( - impl::position::pos != -1, - "Type not in static_variant." - ); - if(_tag == impl::position::pos) { - void* tmp(storage); - return *reinterpret_cast(tmp); - } else { - FC_THROW_EXCEPTION( fc::assert_exception, "static_variant does not contain a value of type ${t}", ("t",fc::get_typename::name()) ); - // std::string("static_variant does not contain value of type ") + typeid(X).name() - // ); - } - } - template - const X& get() const & { - static_assert( - impl::position::pos != -1, - "Type not in static_variant." - ); - if(_tag == impl::position::pos) { - const void* tmp(storage); - return *reinterpret_cast(tmp); - } else { - FC_THROW_EXCEPTION( fc::assert_exception, "static_variant does not contain a value of type ${t}", ("t",fc::get_typename::name()) ); - } - } - template - X&& get() && { - static_assert( - impl::position::pos != -1, - "Type not in static_variant." - ); - if(_tag == impl::position::pos) { - void* tmp(storage); - return std::move(*reinterpret_cast(tmp)); - } else { - FC_THROW_EXCEPTION( fc::assert_exception, "static_variant does not contain a value of type ${t}", ("t",fc::get_typename::name()) ); - } - } - template - auto visit(visitor&& v) & { - return impl::storage_ops_auto::apply(_tag, storage, std::forward(v)); - } - - - template - auto visit(visitor&& v) const & { - return impl::storage_ops_const_auto::apply(_tag, storage, std::forward(v)); - } - - template - auto visit(visitor&& v) && { - return impl::storage_ops_revalue_ref_auto::apply_rvalue_ref(_tag, storage, std::forward(v)); - } - - template - auto visit(visitor&& v) & { - return impl::storage_ops::apply(_tag, storage, std::forward(v)); - } - - - template - auto visit(visitor&& v) const & { - return impl::storage_ops::apply(_tag, storage, std::forward(v)); - } - - template - auto visit(visitor&& v) && { - return impl::storage_ops::apply_rvalue_ref(_tag, storage, std::forward(v)); - } - - static uint32_t count() { return type_info::count; } - void set_which( uint32_t w ) { - FC_ASSERT( w < count() ); - this->~static_variant(); - try { - _tag = w; - impl::storage_ops::con(_tag, storage); - } catch ( ... ) { - _tag = 0; - impl::storage_ops::con(_tag, storage); - } - } - - int which() const {return _tag;} - - template - bool contains() const { return which() == tag::value; } - - template - static constexpr int position() { return impl::position::pos; } - - template = 1> - using type_at = typename impl::type_at::type; -}; - -template -struct visitor { + template void operator()( T& v )const + { + from_variant( var, v ); + } }; - struct from_static_variant - { - variant& var; - from_static_variant( variant& dv ):var(dv){} - - template void operator()( const T& v )const - { - to_variant( v, var ); - } - }; - - struct to_static_variant - { - const variant& var; - to_static_variant( const variant& dv ):var(dv){} - - template void operator()( T& v )const - { - from_variant( var, v ); - } - }; - - - template void to_variant( const fc::static_variant& s, fc::variant& v ) - { - variant tmp; - variants vars(2); - vars[0] = s.which(); - s.visit( from_static_variant(vars[1]) ); - v = std::move(vars); - } - template void from_variant( const fc::variant& v, fc::static_variant& s ) - { - auto ar = v.get_array(); - if( ar.size() < 2 ) return; - s.set_which( ar[0].as_uint64() ); - s.visit( to_static_variant(ar[1]) ); - } +template void to_variant( const std::variant& s, fc::variant& v ) +{ + variants vars(2); + vars[0] = s.index(); + std::visit( from_static_variant(vars[1]), s ); + v = std::move(vars); +} - template struct get_typename { static const char* name() { return BOOST_CORE_TYPEID(static_variant).name(); } }; -} // namespace fc +template void from_variant( const fc::variant& v, std::variant& s ) +{ + auto ar = v.get_array(); + if( ar.size() < 2 ) + { + s = std::variant(); + return; + } + from_index(s, ar[0].as_uint64()); + std::visit( to_static_variant(ar[1]), s ); +} + +template struct get_typename { static const char* name() { return BOOST_CORE_TYPEID(std::variant).name(); } }; + +} \ No newline at end of file diff --git a/include/fc/string.hpp b/include/fc/string.hpp index 3a9323514..74dcf690b 100644 --- a/include/fc/string.hpp +++ b/include/fc/string.hpp @@ -1,9 +1,9 @@ #pragma once #include #include -#include #ifndef USE_FC_STRING +#include #include namespace fc { @@ -23,7 +23,7 @@ namespace fc inline fc::string to_string( size_t s) { return to_string(uint64_t(s)); } #endif - typedef fc::optional ostring; + typedef std::optional ostring; class variant_object; fc::string format_string( const fc::string&, const variant_object&, bool minimize = false ); fc::string trim( const fc::string& ); @@ -143,7 +143,7 @@ namespace fc { fc::string to_string( uint64_t ); fc::string to_string( int64_t ); - typedef fc::optional ostring; + typedef std::optional ostring; class variant_object; fc::string format_string( const fc::string&, const variant_object& ); diff --git a/include/fc/time.hpp b/include/fc/time.hpp index a401476e4..1c1b433bd 100644 --- a/include/fc/time.hpp +++ b/include/fc/time.hpp @@ -1,7 +1,6 @@ #pragma once #include #include -#include #ifdef _MSC_VER #pragma warning (push) @@ -121,7 +120,7 @@ namespace fc { uint32_t utc_seconds; }; - typedef fc::optional otime_point; + typedef std::optional otime_point; /** return a human-readable approximate time, relative to now() * e.g., "4 hours ago", "2 months ago", etc. diff --git a/include/fc/uint128.hpp b/include/fc/uint128.hpp index c12ad0bd0..4663ccc4f 100644 --- a/include/fc/uint128.hpp +++ b/include/fc/uint128.hpp @@ -122,9 +122,7 @@ namespace fc uint64_t lo; }; static_assert( sizeof(uint128) == 2*sizeof(uint64_t), "validate packing assumptions" ); - - typedef uint128 uint128_t; - + class variant; void to_variant( const uint128& var, variant& vo ); @@ -155,7 +153,7 @@ namespace std }; } -FC_REFLECT( fc::uint128_t, (hi)(lo) ) +FC_REFLECT( fc::uint128, (hi)(lo) ) #ifdef _MSC_VER #pragma warning (pop) diff --git a/include/fc/utf8.hpp b/include/fc/utf8.hpp index c5730295d..84468690c 100644 --- a/include/fc/utf8.hpp +++ b/include/fc/utf8.hpp @@ -8,7 +8,16 @@ namespace fc { - std::string prune_invalid_utf8( const std::string& str ); + /** + * 0x80-0x9F C1 control characters are considered invalid as well as invalid utf8 code points. + * @return true if prune_invalid_utf8 should be called. + */ + bool is_valid_utf8( const std::string_view& str ); + + /** + * Invalid utf8 code points are purned, 0x80-0x9F C1 control characters are escaped + */ + std::string prune_invalid_utf8( const std::string_view& str ); bool is_utf8( const std::string& str ); diff --git a/include/fc/variant.hpp b/include/fc/variant.hpp index 2dca7ef12..37d6bb20c 100644 --- a/include/fc/variant.hpp +++ b/include/fc/variant.hpp @@ -10,14 +10,13 @@ #include // memset -#include #include #include #include #include #include - #include +#include namespace fc { @@ -41,98 +40,97 @@ namespace fc class time_point_sec; class microseconds; template struct safe; - template - class static_variant; struct blob { std::vector data; }; - void to_variant( const blob& var, variant& vo ); - void from_variant( const variant& var, blob& vo ); + void to_variant( const blob& var, fc::variant& vo ); + void from_variant( const fc::variant& var, blob& vo ); - template void to_variant( const boost::multi_index_container& s, variant& v ); - template void from_variant( const variant& v, boost::multi_index_container& s ); + template void to_variant( const boost::multi_index_container& s, fc::variant& v ); + template void from_variant( const fc::variant& v, boost::multi_index_container& s ); - using namespace boost::multiprecision; template - using UInt = number >; + using UInt = boost::multiprecision::number< + boost::multiprecision::cpp_int_backend >; template - using Int = number >; + using Int = boost::multiprecision::number< + boost::multiprecision::cpp_int_backend >; - void to_variant( const UInt<8>& n, variant& v ); - void from_variant( const variant& v, UInt<8>& n ); + void to_variant( const UInt<8>& n, fc::variant& v ); + void from_variant( const fc::variant& v, UInt<8>& n ); - void to_variant( const UInt<16>& n, variant& v ); - void from_variant( const variant& v, UInt<16>& n ); + void to_variant( const UInt<16>& n, fc::variant& v ); + void from_variant( const fc::variant& v, UInt<16>& n ); - void to_variant( const UInt<32>& n, variant& v ); - void from_variant( const variant& v, UInt<32>& n ); + void to_variant( const UInt<32>& n, fc::variant& v ); + void from_variant( const fc::variant& v, UInt<32>& n ); - void to_variant( const UInt<64>& n, variant& v ); - void from_variant( const variant& v, UInt<64>& n ); + void to_variant( const UInt<64>& n, fc::variant& v ); + void from_variant( const fc::variant& v, UInt<64>& n ); - template void to_variant( const boost::multiprecision::number& n, variant& v ); - template void from_variant( const variant& v, boost::multiprecision::number& n ); + template void to_variant( const boost::multiprecision::number& n, fc::variant& v ); + template void from_variant( const fc::variant& v, boost::multiprecision::number& n ); - template void to_variant( const safe& s, variant& v ); - template void from_variant( const variant& v, safe& s ); - template void to_variant( const std::unique_ptr& s, variant& v ); - template void from_variant( const variant& v, std::unique_ptr& s ); + template void to_variant( const safe& s, fc::variant& v ); + template void from_variant( const fc::variant& v, safe& s ); + template void to_variant( const std::unique_ptr& s, fc::variant& v ); + template void from_variant( const fc::variant& v, std::unique_ptr& s ); - template void to_variant( const static_variant& s, variant& v ); - template void from_variant( const variant& v, static_variant& s ); + template void to_variant( const std::variant& s, fc::variant& v ); + template void from_variant( const fc::variant& v, std::variant& s ); - void to_variant( const uint8_t& var, variant& vo ); - void from_variant( const variant& var, uint8_t& vo ); - void to_variant( const int8_t& var, variant& vo ); - void from_variant( const variant& var, int8_t& vo ); + void to_variant( const uint8_t& var, fc::variant& vo ); + void from_variant( const fc::variant& var, uint8_t& vo ); + void to_variant( const int8_t& var, fc::variant& vo ); + void from_variant( const fc::variant& var, int8_t& vo ); - void to_variant( const uint16_t& var, variant& vo ); - void from_variant( const variant& var, uint16_t& vo ); - void to_variant( const int16_t& var, variant& vo ); - void from_variant( const variant& var, int16_t& vo ); + void to_variant( const uint16_t& var, fc::variant& vo ); + void from_variant( const fc::variant& var, uint16_t& vo ); + void to_variant( const int16_t& var, fc::variant& vo ); + void from_variant( const fc::variant& var, int16_t& vo ); - void to_variant( const uint32_t& var, variant& vo ); - void from_variant( const variant& var, uint32_t& vo ); - void to_variant( const int32_t& var, variant& vo ); - void from_variant( const variant& var, int32_t& vo ); + void to_variant( const uint32_t& var, fc::variant& vo ); + void from_variant( const fc::variant& var, uint32_t& vo ); + void to_variant( const int32_t& var, fc::variant& vo ); + void from_variant( const fc::variant& var, int32_t& vo ); - void to_variant( const unsigned __int128& var, variant& vo ); - void from_variant( const variant& var, unsigned __int128& vo ); - void to_variant( const __int128& var, variant& vo ); - void from_variant( const variant& var, __int128& vo ); + void to_variant( const unsigned __int128& var, fc::variant& vo ); + void from_variant( const fc::variant& var, unsigned __int128& vo ); + void to_variant( const __int128& var, fc::variant& vo ); + void from_variant( const fc::variant& var, __int128& vo ); - void to_variant( const variant_object& var, variant& vo ); - void from_variant( const variant& var, variant_object& vo ); - void to_variant( const mutable_variant_object& var, variant& vo ); - void from_variant( const variant& var, mutable_variant_object& vo ); - void to_variant( const std::vector& var, variant& vo ); - void from_variant( const variant& var, std::vector& vo ); + void to_variant( const variant_object& var, fc::variant& vo ); + void from_variant( const fc::variant& var, variant_object& vo ); + void to_variant( const mutable_variant_object& var, fc::variant& vo ); + void from_variant( const fc::variant& var, mutable_variant_object& vo ); + void to_variant( const std::vector& var, fc::variant& vo ); + void from_variant( const fc::variant& var, std::vector& vo ); template - void to_variant( const std::unordered_map& var, variant& vo ); + void to_variant( const std::unordered_map& var, fc::variant& vo ); template - void from_variant( const variant& var, std::unordered_map& vo ); + void from_variant( const fc::variant& var, std::unordered_map& vo ); template - void to_variant( const std::map& var, variant& vo ); + void to_variant( const std::map& var, fc::variant& vo ); template - void from_variant( const variant& var, std::map& vo ); + void from_variant( const fc::variant& var, std::map& vo ); template - void to_variant( const std::multimap& var, variant& vo ); + void to_variant( const std::multimap& var, fc::variant& vo ); template - void from_variant( const variant& var, std::multimap& vo ); + void from_variant( const fc::variant& var, std::multimap& vo ); template - void to_variant( const std::unordered_set& var, variant& vo ); + void to_variant( const std::unordered_set& var, fc::variant& vo ); template - void from_variant( const variant& var, std::unordered_set& vo ); + void from_variant( const fc::variant& var, std::unordered_set& vo ); template - void to_variant( const std::deque& var, variant& vo ); + void to_variant( const std::deque& var, fc::variant& vo ); template - void from_variant( const variant& var, std::deque& vo ); + void from_variant( const fc::variant& var, std::deque& vo ); template void to_variant( const boost::container::deque& d, fc::variant& vo ); @@ -140,43 +138,43 @@ namespace fc void from_variant( const fc::variant& v, boost::container::deque& d ); template - void to_variant( const std::set& var, variant& vo ); + void to_variant( const std::set& var, fc::variant& vo ); template - void from_variant( const variant& var, std::set& vo ); + void from_variant( const fc::variant& var, std::set& vo ); template - void to_variant( const std::array& var, variant& vo ); + void to_variant( const std::array& var, fc::variant& vo ); template - void from_variant( const variant& var, std::array& vo ); + void from_variant( const fc::variant& var, std::array& vo ); - void to_variant( const time_point& var, variant& vo ); - void from_variant( const variant& var, time_point& vo ); + void to_variant( const time_point& var, fc::variant& vo ); + void from_variant( const fc::variant& var, time_point& vo ); - void to_variant( const time_point_sec& var, variant& vo ); - void from_variant( const variant& var, time_point_sec& vo ); + void to_variant( const time_point_sec& var, fc::variant& vo ); + void from_variant( const fc::variant& var, time_point_sec& vo ); - void to_variant( const microseconds& input_microseconds, variant& output_variant ); - void from_variant( const variant& input_variant, microseconds& output_microseconds ); + void to_variant( const microseconds& input_microseconds, fc::variant& output_variant ); + void from_variant( const fc::variant& input_variant, microseconds& output_microseconds ); #ifdef __APPLE__ - void to_variant( size_t s, variant& v ); + void to_variant( size_t s, fc::variant& v ); #elif !defined(_MSC_VER) - void to_variant( long long int s, variant& v ); - void to_variant( unsigned long long int s, variant& v ); + void to_variant( long long int s, fc::variant& v ); + void to_variant( unsigned long long int s, fc::variant& v ); #endif - void to_variant( const std::string& s, variant& v ); + void to_variant( const std::string& s, fc::variant& v ); template - void to_variant( const std::shared_ptr& var, variant& vo ); + void to_variant( const std::shared_ptr& var, fc::variant& vo ); template - void from_variant( const variant& var, std::shared_ptr& vo ); + void from_variant( const fc::variant& var, std::shared_ptr& vo ); - typedef std::vector variants; + typedef std::vector variants; template - void to_variant( const std::pair& t, variant& v ); + void to_variant( const std::pair& t, fc::variant& v ); template - void from_variant( const variant& v, std::pair& p ); + void from_variant( const fc::variant& v, std::pair& p ); @@ -348,10 +346,10 @@ namespace fc } template - variant( const optional& v ) + explicit variant( const std::optional& v ) { memset( this, 0, sizeof(*this) ); - if( v.valid() ) *this = variant(*v); + if( v.has_value() ) *this = variant(*v); } template @@ -366,32 +364,33 @@ namespace fc double _data; ///< Alligned according to double requirements char _type[sizeof(void*)]; ///< pad to void* size }; - typedef optional ovariant; + + typedef std::optional ovariant; /** @ingroup Serializable */ - void from_variant( const variant& var, string& vo ); + void from_variant( const fc::variant& var, string& vo ); /** @ingroup Serializable */ - void from_variant( const variant& var, variants& vo ); - void from_variant( const variant& var, variant& vo ); + void from_variant( const fc::variant& var, fc::variants& vo ); + void from_variant( const fc::variant& var, fc::variant& vo ); /** @ingroup Serializable */ - void from_variant( const variant& var, int64_t& vo ); + void from_variant( const fc::variant& var, int64_t& vo ); /** @ingroup Serializable */ - void from_variant( const variant& var, uint64_t& vo ); + void from_variant( const fc::variant& var, uint64_t& vo ); /** @ingroup Serializable */ - void from_variant( const variant& var, bool& vo ); + void from_variant( const fc::variant& var, bool& vo ); /** @ingroup Serializable */ - void from_variant( const variant& var, double& vo ); + void from_variant( const fc::variant& var, double& vo ); /** @ingroup Serializable */ - void from_variant( const variant& var, float& vo ); + void from_variant( const fc::variant& var, float& vo ); /** @ingroup Serializable */ - void from_variant( const variant& var, int32_t& vo ); + void from_variant( const fc::variant& var, int32_t& vo ); /** @ingroup Serializable */ - void from_variant( const variant& var, uint32_t& vo ); + void from_variant( const fc::variant& var, uint32_t& vo ); /** @ingroup Serializable */ template - void from_variant( const variant& var, optional& vo ) + void from_variant( const variant& var, std::optional& vo ) { - if( var.is_null() ) vo = optional(); + if( var.is_null() ) vo = std::optional(); else { vo = T(); @@ -399,17 +398,17 @@ namespace fc } } template - void to_variant( const std::unordered_set& var, variant& vo ) + void to_variant( const std::unordered_set& var, fc::variant& vo ) { if( var.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); - std::vector vars(var.size()); + std::vector vars(var.size()); size_t i = 0; for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = variant(*itr); + vars[i] = fc::variant(*itr); vo = vars; } template - void from_variant( const variant& var, std::unordered_set& vo ) + void from_variant( const fc::variant& var, std::unordered_set& vo ) { const variants& vars = var.get_array(); if( vars.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); @@ -421,17 +420,17 @@ namespace fc template - void to_variant( const std::unordered_map& var, variant& vo ) + void to_variant( const std::unordered_map& var, fc::variant& vo ) { if( var.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); - std::vector< variant > vars(var.size()); + std::vector< fc::variant > vars(var.size()); size_t i = 0; for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) vars[i] = fc::variant(*itr); vo = vars; } template - void from_variant( const variant& var, std::unordered_map& vo ) + void from_variant( const fc::variant& var, std::unordered_map& vo ) { const variants& vars = var.get_array(); if( vars.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); @@ -441,17 +440,17 @@ namespace fc } template - void to_variant( const std::map& var, variant& vo ) + void to_variant( const std::map& var, fc::variant& vo ) { if( var.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); - std::vector< variant > vars(var.size()); + std::vector< fc::variant > vars(var.size()); size_t i = 0; for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) vars[i] = fc::variant(*itr); vo = vars; } template - void from_variant( const variant& var, std::map& vo ) + void from_variant( const fc::variant& var, std::map& vo ) { const variants& vars = var.get_array(); if( vars.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); @@ -461,17 +460,17 @@ namespace fc } template - void to_variant( const std::multimap& var, variant& vo ) + void to_variant( const std::multimap& var, fc::variant& vo ) { if( var.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); - std::vector< variant > vars(var.size()); + std::vector< fc::variant > vars(var.size()); size_t i = 0; for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) vars[i] = fc::variant(*itr); vo = vars; } template - void from_variant( const variant& var, std::multimap& vo ) + void from_variant( const fc::variant& var, std::multimap& vo ) { const variants& vars = var.get_array(); if( vars.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); @@ -482,17 +481,17 @@ namespace fc template - void to_variant( const std::set& var, variant& vo ) + void to_variant( const std::set& var, fc::variant& vo ) { if( var.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); - std::vector vars(var.size()); + std::vector vars(var.size()); size_t i = 0; for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = variant(*itr); + vars[i] = fc::variant(*itr); vo = vars; } template - void from_variant( const variant& var, std::set& vo ) + void from_variant( const fc::variant& var, std::set& vo ) { const variants& vars = var.get_array(); if( vars.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); @@ -504,7 +503,7 @@ namespace fc /** @ingroup Serializable */ template - void from_variant( const variant& var, std::deque& tmp ) + void from_variant( const fc::variant& var, std::deque& tmp ) { const variants& vars = var.get_array(); if( vars.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); @@ -515,18 +514,18 @@ namespace fc /** @ingroup Serializable */ template - void to_variant( const std::deque& t, variant& v ) + void to_variant( const std::deque& t, fc::variant& v ) { if( t.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); - std::vector vars(t.size()); + std::vector vars(t.size()); for( size_t i = 0; i < t.size(); ++i ) - vars[i] = variant(t[i]); + vars[i] = fc::variant(t[i]); v = std::move(vars); } /** @ingroup Serializable */ template - void from_variant( const variant& v, boost::container::deque& d ) + void from_variant( const fc::variant& v, boost::container::deque& d ) { const variants& vars = v.get_array(); if( vars.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); @@ -544,14 +543,14 @@ namespace fc if( d.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); variants vars(d.size()); for( size_t i = 0; i < d.size(); ++i ) { - vars[i] = variant( d[i] ); + vars[i] = fc::variant( d[i] ); } vo = std::move( vars ); } /** @ingroup Serializable */ template - void from_variant( const variant& var, std::vector& tmp ) + void from_variant( const fc::variant& var, std::vector& tmp ) { const variants& vars = var.get_array(); if( vars.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); @@ -563,18 +562,18 @@ namespace fc /** @ingroup Serializable */ template - void to_variant( const std::vector& t, variant& v ) + void to_variant( const std::vector& t, fc::variant& v ) { if( t.size() > MAX_NUM_ARRAY_ELEMENTS ) throw std::range_error( "too large" ); - std::vector vars(t.size()); + std::vector vars(t.size()); for( size_t i = 0; i < t.size(); ++i ) - vars[i] = variant(t[i]); + vars[i] = fc::variant(t[i]); v = std::move(vars); } /** @ingroup Serializable */ template - void from_variant( const variant& var, std::array& tmp ) + void from_variant( const fc::variant& var, std::array& tmp ) { const variants& vars = var.get_array(); for( std::size_t i = 0; i < S; ++i ) @@ -583,27 +582,27 @@ namespace fc /** @ingroup Serializable */ template - void to_variant( const std::array& t, variant& v ) + void to_variant( const std::array& t, fc::variant& v ) { - std::vector vars(S); + std::vector vars(S); for( std::size_t i = 0; i < S; ++i ) - vars[i] = variant(t[i]); + vars[i] = fc::variant(t[i]); v = std::move(vars); } /** @ingroup Serializable */ template - void to_variant( const std::pair& t, variant& v ) + void to_variant( const std::pair& t, fc::variant& v ) { - std::vector vars(2); - vars[0] = variant(t.first); - vars[1] = variant(t.second); + std::vector vars(2); + vars[0] = fc::variant(t.first); + vars[1] = fc::variant(t.second); v = vars; } /** @ingroup Serializable */ template - void from_variant( const variant& v, std::pair& p ) + void from_variant( const fc::variant& v, std::pair& p ) { const variants& vars = v.get_array(); if( vars.size() > 0 ) @@ -627,17 +626,17 @@ namespace fc } #ifdef __APPLE__ - inline void to_variant( size_t s, variant& v ) { v = variant(uint64_t(s)); } + inline void to_variant( size_t s, fc::variant& v ) { v = fc::variant(uint64_t(s)); } #endif template - void to_variant( const std::shared_ptr& var, variant& vo ) + void to_variant( const std::shared_ptr& var, fc::variant& vo ) { if( var ) to_variant( *var, vo ); else vo = nullptr; } template - void from_variant( const variant& var, std::shared_ptr& vo ) + void from_variant( const fc::variant& var, std::shared_ptr& vo ) { if( var.is_null() ) vo = nullptr; else if( vo ) from_variant( var, *vo ); @@ -647,14 +646,14 @@ namespace fc } } template - void to_variant( const std::unique_ptr& var, variant& vo ) + void to_variant( const std::unique_ptr& var, fc::variant& vo ) { if( var ) to_variant( *var, vo ); else vo = nullptr; } template - void from_variant( const variant& var, std::unique_ptr& vo ) + void from_variant( const fc::variant& var, std::unique_ptr& vo ) { if( var.is_null() ) vo.reset(); else if( vo ) from_variant( var, *vo ); @@ -666,44 +665,44 @@ namespace fc template - void to_variant( const safe& s, variant& v ) { v = s.value; } + void to_variant( const safe& s, fc::variant& v ) { v = s.value; } template - void from_variant( const variant& v, safe& s ) { s.value = v.as_uint64(); } + void from_variant( const fc::variant& v, safe& s ) { s.value = v.as_uint64(); } - template void to_variant( const boost::multi_index_container& c, variant& v ) + template void to_variant( const boost::multi_index_container& c, fc::variant& v ) { - std::vector vars; + std::vector vars; vars.reserve( c.size() ); for( const auto& item : c ) - vars.emplace_back( variant(item) ); + vars.emplace_back( fc::variant(item) ); v = std::move(vars); } - template void from_variant( const variant& v, boost::multi_index_container& c ) + template void from_variant( const fc::variant& v, boost::multi_index_container& c ) { const variants& vars = v.get_array(); c.clear(); for( const auto& item : vars ) c.insert( item.as() ); } - template void to_variant( const boost::multiprecision::number& n, variant& v ) { + template void to_variant( const boost::multiprecision::number& n, fc::variant& v ) { v = n.str(); } - template void from_variant( const variant& v, boost::multiprecision::number& n ) { + template void from_variant( const fc::variant& v, boost::multiprecision::number& n ) { n = boost::multiprecision::number(v.get_string()); } - variant operator + ( const variant& a, const variant& b ); - variant operator - ( const variant& a, const variant& b ); - variant operator * ( const variant& a, const variant& b ); - variant operator / ( const variant& a, const variant& b ); + fc::variant operator + ( const fc::variant& a, const fc::variant& b ); + fc::variant operator - ( const fc::variant& a, const fc::variant& b ); + fc::variant operator * ( const fc::variant& a, const fc::variant& b ); + fc::variant operator / ( const fc::variant& a, const fc::variant& b ); - bool operator == ( const variant& a, const variant& b ); - bool operator != ( const variant& a, const variant& b ); - bool operator < ( const variant& a, const variant& b ); - bool operator > ( const variant& a, const variant& b ); - bool operator ! ( const variant& a ); + bool operator == ( const fc::variant& a, const fc::variant& b ); + bool operator != ( const fc::variant& a, const fc::variant& b ); + bool operator < ( const fc::variant& a, const fc::variant& b ); + bool operator > ( const fc::variant& a, const fc::variant& b ); + bool operator ! ( const fc::variant& a ); } // namespace fc #include diff --git a/secp256k1/CMakeLists.txt b/secp256k1/CMakeLists.txt index 3be0ea4a6..19056d415 100644 --- a/secp256k1/CMakeLists.txt +++ b/secp256k1/CMakeLists.txt @@ -1,19 +1,36 @@ -cmake_minimum_required(VERSION 3.4) -project(secp256k1) +set(GMP_USAGES "On;Auto;Off") +set(GMP_USAGE "On" CACHE STRING "libgmp usage: On: required; Auto: used if present; Off: not used") +set_property(CACHE GMP_USAGE PROPERTY STRINGS ${GMP_USAGES}) -find_package(GMP REQUIRED) +if(NOT GMP_USAGE IN_LIST GMP_USAGES) + message(FATAL_ERROR "GMP_USAGE must be set to one of: ${GMP_USAGES}") +endif() + +if(GMP_USAGE STREQUAL "On") + find_package(GMP REQUIRED) +elseif(GMP_USAGE) + find_package(GMP) +endif() + +if(GMP_FOUND) + set(SECP256K1_CONFIG_INC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/config_with_gmp") +else() + set(SECP256K1_CONFIG_INC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/config_without_gmp") + unset(GMP_INCLUDE_DIR CACHE) + unset(GMP_LIBRARIES CACHE) +endif() add_library(secp256k1 STATIC - upstream/src/secp256k1.c + secp256k1/src/secp256k1.c ) target_include_directories(secp256k1 PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/upstream/ - ${CMAKE_CURRENT_SOURCE_DIR}/upstream/include + secp256k1 + secp256k1/include PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/upstream/src - ${CMAKE_CURRENT_SOURCE_DIR} + secp256k1/src + "${SECP256K1_CONFIG_INC_DIR}" ${GMP_INCLUDE_DIR} ) diff --git a/secp256k1/config_with_gmp/libsecp256k1-config.h b/secp256k1/config_with_gmp/libsecp256k1-config.h new file mode 100644 index 000000000..000953f9b --- /dev/null +++ b/secp256k1/config_with_gmp/libsecp256k1-config.h @@ -0,0 +1,17 @@ +#pragma once + +#define ENABLE_MODULE_RECOVERY 1 + +#define ECMULT_GEN_PREC_BITS 4 +#define ECMULT_WINDOW_SIZE 15 + +//use GMP for bignum +#define HAVE_LIBGMP 1 +#define USE_NUM_GMP 1 +#define USE_FIELD_INV_NUM 1 +#define USE_SCALAR_INV_NUM 1 + +//enable asm +#ifdef __x86_64__ + #define USE_ASM_X86_64 1 +#endif diff --git a/secp256k1/config_without_gmp/libsecp256k1-config.h b/secp256k1/config_without_gmp/libsecp256k1-config.h new file mode 100644 index 000000000..a81452121 --- /dev/null +++ b/secp256k1/config_without_gmp/libsecp256k1-config.h @@ -0,0 +1,16 @@ +#pragma once + +#define ENABLE_MODULE_RECOVERY 1 + +#define ECMULT_GEN_PREC_BITS 4 +#define ECMULT_WINDOW_SIZE 15 + +//use internal field & num impls +#define USE_FIELD_INV_BUILTIN 1 +#define USE_SCALAR_INV_BUILTIN 1 +#define USE_NUM_NONE 1 + +//enable asm +#ifdef __x86_64__ + #define USE_ASM_X86_64 1 +#endif diff --git a/secp256k1/libsecp256k1-config.h b/secp256k1/libsecp256k1-config.h deleted file mode 100644 index c1f4762c9..000000000 --- a/secp256k1/libsecp256k1-config.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -//optimizations that any compiler we target have -#define HAVE_BUILTIN_CLZLL 1 -#define HAVE_BUILTIN_EXPECT 1 -#define HAVE___INT128 1 - -//use GMP for bignum -#define HAVE_LIBGMP 1 -#define USE_NUM_GMP 1 -#define USE_FIELD_INV_NUM 1 -#define USE_SCALAR_INV_NUM 1 - -//use impls best for 64-bit -#define USE_FIELD_5X52 1 -#define USE_SCALAR_4X64 1 - -//enable asm -#ifdef __x86_64__ - #define USE_ASM_X86_64 1 -#endif diff --git a/secp256k1/secp256k1 b/secp256k1/secp256k1 new file mode 160000 index 000000000..b61f9da54 --- /dev/null +++ b/secp256k1/secp256k1 @@ -0,0 +1 @@ +Subproject commit b61f9da54eff6d8137e0681b403b48be62f0460a diff --git a/secp256k1/upstream b/secp256k1/upstream deleted file mode 160000 index bd067945e..000000000 --- a/secp256k1/upstream +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bd067945ead3b514fba884abd0de95fc4b5db9ae diff --git a/src/compress/miniz.c b/src/compress/miniz.c index 298725042..ce98e146f 100644 --- a/src/compress/miniz.c +++ b/src/compress/miniz.c @@ -2287,7 +2287,10 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } - if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32; + if (!dist) break; + q = (const mz_uint16*)(d->m_dict + probe_pos); + if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; + p = s; probe_len = 32; do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); if (!probe_len) diff --git a/src/crypto/_elliptic_impl_priv.hpp b/src/crypto/_elliptic_impl_priv.hpp index 8c2a1abff..45d0ef879 100644 --- a/src/crypto/_elliptic_impl_priv.hpp +++ b/src/crypto/_elliptic_impl_priv.hpp @@ -8,7 +8,7 @@ namespace fc { namespace ecc { namespace detail { -const secp256k1_context_t* _get_context(); +const secp256k1_context* _get_context(); void _init_lib(); class private_key_impl diff --git a/src/crypto/aes.cpp b/src/crypto/aes.cpp index 93dc1a026..282ede004 100644 --- a/src/crypto/aes.cpp +++ b/src/crypto/aes.cpp @@ -382,6 +382,8 @@ std::vector aes_load( const fc::path& file, const fc::sha512& key ) return aes_decrypt( key, cipher ); } FC_RETHROW_EXCEPTIONS( warn, "", ("file",file) ) } +#if OPENSSL_VERSION_NUMBER < 0x10100000L + /* This stuff has to go somewhere, I guess this is as good a place as any... OpenSSL isn't thread-safe unless you give it access to some mutexes, so the CRYPTO_set_id_callback() function needs to be called before there's any @@ -441,5 +443,5 @@ openssl_thread_config::~openssl_thread_config() openssl_mutexes = nullptr; } } - +#endif } // namespace fc diff --git a/src/crypto/crc.cpp b/src/crypto/crc.cpp index 3b9545503..2467840c5 100644 --- a/src/crypto/crc.cpp +++ b/src/crypto/crc.cpp @@ -515,6 +515,9 @@ uint32_t crc32cSlicingBy8(uint32_t crc, const void* data, size_t length) { #define CRC32C_POLY 0x1EDC6F41 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-const-variable" + #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF]) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Copyright 2001, D. Otis. Use this program, code or tables */ @@ -601,6 +604,9 @@ static const uint32_t crc_c[256] = { 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, }; + +#pragma GCC diagnostic pop + #if !defined __SSE4_2__ || (defined __SSE4_2__ && !defined __x86_64__) diff --git a/src/crypto/elliptic_common.cpp b/src/crypto/elliptic_common.cpp index 33547f39e..4fa0925b9 100644 --- a/src/crypto/elliptic_common.cpp +++ b/src/crypto/elliptic_common.cpp @@ -110,15 +110,6 @@ namespace fc { namespace ecc { return public_key(data); } - public_key public_key::child( const fc::sha256& offset )const - { - fc::sha256::encoder enc; - fc::raw::pack( enc, *this ); - fc::raw::pack( enc, offset ); - - return add( enc.result() ); - } - private_key private_key::child( const fc::sha256& offset )const { fc::sha256::encoder enc; diff --git a/src/crypto/elliptic_impl_priv.cpp b/src/crypto/elliptic_impl_priv.cpp index 585ffdef1..1134c0b4b 100644 --- a/src/crypto/elliptic_impl_priv.cpp +++ b/src/crypto/elliptic_impl_priv.cpp @@ -1,6 +1,7 @@ #include #include +#include #include "_elliptic_impl_priv.hpp" @@ -71,30 +72,35 @@ namespace fc { namespace ecc { { FC_ASSERT( my->_key != empty_priv ); public_key_data pub; - unsigned int pk_len; - FC_ASSERT( secp256k1_ec_pubkey_create( detail::_get_context(), (unsigned char*) pub.begin(), (int*) &pk_len, (unsigned char*) my->_key.data(), 1 ) ); - FC_ASSERT( pk_len == pub.size() ); + size_t pub_len = sizeof(pub); + secp256k1_pubkey secp_pub; + FC_ASSERT( secp256k1_ec_pubkey_create( detail::_get_context(), &secp_pub, (unsigned char*) my->_key.data() ) ); + secp256k1_ec_pubkey_serialize( detail::_get_context(), (unsigned char*)&pub, &pub_len, &secp_pub, SECP256K1_EC_COMPRESSED ); + FC_ASSERT( pub_len == pub.size() ); return public_key(pub); } static int extended_nonce_function( unsigned char *nonce32, const unsigned char *msg32, - const unsigned char *key32, unsigned int attempt, - const void *data ) { + const unsigned char *key32, const unsigned char* algo16, + void* data, unsigned int attempt ) { unsigned int* extra = (unsigned int*) data; (*extra)++; - return secp256k1_nonce_function_default( nonce32, msg32, key32, *extra, nullptr ); + return secp256k1_nonce_function_default( nonce32, msg32, key32, algo16, nullptr, *extra ); } compact_signature private_key::sign_compact( const fc::sha256& digest, bool require_canonical )const { FC_ASSERT( my->_key != empty_priv ); compact_signature result; + secp256k1_ecdsa_recoverable_signature secp_sig; int recid; unsigned int counter = 0; do { - FC_ASSERT( secp256k1_ecdsa_sign_compact( detail::_get_context(), (unsigned char*) digest.data(), (unsigned char*) result.begin() + 1, (unsigned char*) my->_key.data(), extended_nonce_function, &counter, &recid )); + FC_ASSERT( secp256k1_ecdsa_sign_recoverable( detail::_get_context(), &secp_sig, (unsigned char*) digest.data(), (unsigned char*) my->_key.data(), extended_nonce_function, &counter )); + secp256k1_ecdsa_recoverable_signature_serialize_compact( detail::_get_context(), result.data + 1, &recid, &secp_sig); } while( require_canonical && !public_key::is_canonical( result ) ); + result.begin()[0] = 27 + 4 + recid; return result; } diff --git a/src/crypto/elliptic_r1.cpp b/src/crypto/elliptic_r1.cpp index da8044294..84b318f20 100644 --- a/src/crypto/elliptic_r1.cpp +++ b/src/crypto/elliptic_r1.cpp @@ -458,15 +458,6 @@ namespace fc { namespace crypto { namespace r1 { EC_POINT_get_affine_coordinates_GFp( group, pub, self.my->_pub_x.get(), self.my->_pub_y.get(), nullptr ); */ } - public_key_point_data public_key::serialize_ecc_point()const - { - public_key_point_data dat; - if( !my->_key ) return dat; - EC_KEY_set_conv_form( my->_key, POINT_CONVERSION_UNCOMPRESSED ); - char* front = &dat.data[0]; - i2o_ECPublicKey( my->_key, (unsigned char**)&front ); - return dat; - } public_key::public_key() { diff --git a/src/crypto/elliptic_secp256k1.cpp b/src/crypto/elliptic_secp256k1.cpp index 47b55b790..84eacf44f 100644 --- a/src/crypto/elliptic_secp256k1.cpp +++ b/src/crypto/elliptic_secp256k1.cpp @@ -10,6 +10,7 @@ #include #include +#include #if _WIN32 # include @@ -24,13 +25,13 @@ namespace fc { namespace ecc { namespace detail { - const secp256k1_context_t* _get_context() { - static secp256k1_context_t* ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_RANGEPROOF | SECP256K1_CONTEXT_COMMIT ); + const secp256k1_context* _get_context() { + static secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); return ctx; } void _init_lib() { - static const secp256k1_context_t* ctx = _get_context(); + static const secp256k1_context* ctx = _get_context(); static int init_o = init_openssl(); (void)ctx; (void)init_o; @@ -63,15 +64,21 @@ namespace fc { namespace ecc { } static const public_key_data empty_pub; - static const private_key_secret empty_priv; + fc::sha512 private_key::get_shared_secret( const public_key& other )const { + static const private_key_secret empty_priv; FC_ASSERT( my->_key != empty_priv ); FC_ASSERT( other.my->_key != empty_pub ); - public_key_data pub(other.my->_key); - FC_ASSERT( secp256k1_ec_pubkey_tweak_mul( detail::_get_context(), (unsigned char*) pub.begin(), pub.size(), (unsigned char*) my->_key.data() ) ); - return fc::sha512::hash( pub.begin() + 1, pub.size() - 1 ); + secp256k1_pubkey secp_pubkey; + FC_ASSERT( secp256k1_ec_pubkey_parse( detail::_get_context(), &secp_pubkey, (unsigned char*)other.serialize().data, other.serialize().size() ) ); + FC_ASSERT( secp256k1_ec_pubkey_tweak_mul( detail::_get_context(), &secp_pubkey, (unsigned char*) my->_key.data() ) ); + public_key_data serialized_result; + size_t serialized_result_sz = sizeof(serialized_result); + secp256k1_ec_pubkey_serialize(detail::_get_context(), (unsigned char*)&serialized_result.data, &serialized_result_sz, &secp_pubkey, SECP256K1_EC_COMPRESSED ); + FC_ASSERT( serialized_result_sz == sizeof(serialized_result) ); + return fc::sha512::hash( serialized_result.begin() + 1, serialized_result.size() - 1 ); } @@ -100,15 +107,6 @@ namespace fc { namespace ecc { return my->_key != empty_pub; } - public_key public_key::add( const fc::sha256& digest )const - { - FC_ASSERT( my->_key != empty_pub ); - public_key_data new_key; - memcpy( new_key.begin(), my->_key.begin(), new_key.size() ); - FC_ASSERT( secp256k1_ec_pubkey_tweak_add( detail::_get_context(), (unsigned char*) new_key.begin(), new_key.size(), (unsigned char*) digest.data() ) ); - return public_key( new_key ); - } - std::string public_key::to_base58() const { FC_ASSERT( my->_key != empty_pub ); @@ -121,17 +119,6 @@ namespace fc { namespace ecc { return my->_key; } - public_key_point_data public_key::serialize_ecc_point()const - { - FC_ASSERT( my->_key != empty_pub ); - public_key_point_data dat; - unsigned int pk_len = my->_key.size(); - memcpy( dat.begin(), my->_key.begin(), pk_len ); - FC_ASSERT( secp256k1_ec_pubkey_decompress( detail::_get_context(), (unsigned char *) dat.begin(), (int*) &pk_len ) ); - FC_ASSERT( pk_len == dat.size() ); - return dat; - } - public_key::public_key( const public_key_point_data& dat ) { const char* front = &dat.data[0]; @@ -164,108 +151,15 @@ namespace fc { namespace ecc { FC_ASSERT( is_canonical( c ), "signature is not canonical" ); } - unsigned int pk_len; - FC_ASSERT( secp256k1_ecdsa_recover_compact( detail::_get_context(), (unsigned char*) digest.data(), (unsigned char*) c.begin() + 1, (unsigned char*) my->_key.begin(), (int*) &pk_len, 1, (*c.begin() - 27) & 3 ) ); - FC_ASSERT( pk_len == my->_key.size() ); - } - - - commitment_type blind( const blind_factor_type& blind, uint64_t value ) - { - commitment_type result; - FC_ASSERT( secp256k1_pedersen_commit( detail::_get_context(), (unsigned char*)&result, (unsigned char*)&blind, value ) ); - return result; - } + secp256k1_pubkey secp_pub; + secp256k1_ecdsa_recoverable_signature secp_sig; - blind_factor_type blind_sum( const std::vector& blinds_in, uint32_t non_neg ) - { - blind_factor_type result; - std::vector blinds(blinds_in.size()); - for( uint32_t i = 0; i < blinds_in.size(); ++i ) blinds[i] = (const unsigned char*)&blinds_in[i]; - FC_ASSERT( secp256k1_pedersen_blind_sum( detail::_get_context(), (unsigned char*)&result, blinds.data(), blinds_in.size(), non_neg ) ); - return result; - } - - /** verifies taht commnits + neg_commits + excess == 0 */ - bool verify_sum( const std::vector& commits_in, const std::vector& neg_commits_in, int64_t excess ) - { - std::vector commits(commits_in.size()); - for( uint32_t i = 0; i < commits_in.size(); ++i ) commits[i] = (const unsigned char*)&commits_in[i]; - std::vector neg_commits(neg_commits_in.size()); - for( uint32_t i = 0; i < neg_commits_in.size(); ++i ) neg_commits[i] = (const unsigned char*)&neg_commits_in[i]; - - return secp256k1_pedersen_verify_tally( detail::_get_context(), commits.data(), commits.size(), neg_commits.data(), neg_commits.size(), excess ); - } - - bool verify_range( uint64_t& min_val, uint64_t& max_val, const commitment_type& commit, const std::vector& proof ) - { - return secp256k1_rangeproof_verify( detail::_get_context(), &min_val, &max_val, (const unsigned char*)&commit, (const unsigned char*)proof.data(), proof.size() ); - } - - std::vector range_proof_sign( uint64_t min_value, - const commitment_type& commit, - const blind_factor_type& commit_blind, - const blind_factor_type& nonce, - int8_t base10_exp, - uint8_t min_bits, - uint64_t actual_value - ) - { - int proof_len = 5134; - std::vector proof(proof_len); - - FC_ASSERT( secp256k1_rangeproof_sign( detail::_get_context(), - (unsigned char*)proof.data(), - &proof_len, min_value, - (const unsigned char*)&commit, - (const unsigned char*)&commit_blind, - (const unsigned char*)&nonce, - base10_exp, min_bits, actual_value ) ); - proof.resize(proof_len); - return proof; - } - - - bool verify_range_proof_rewind( blind_factor_type& blind_out, - uint64_t& value_out, - string& message_out, - const blind_factor_type& nonce, - uint64_t& min_val, - uint64_t& max_val, - commitment_type commit, - const std::vector& proof ) - { - char msg[4096]; - int mlen = 0; - FC_ASSERT( secp256k1_rangeproof_rewind( detail::_get_context(), - (unsigned char*)&blind_out, - &value_out, - (unsigned char*)msg, - &mlen, - (const unsigned char*)&nonce, - &min_val, - &max_val, - (const unsigned char*)&commit, - (const unsigned char*)proof.data(), - proof.size() ) ); - - message_out = std::string( msg, mlen ); - return true; - } - - range_proof_info range_get_info( const std::vector& proof ) - { - range_proof_info result; - FC_ASSERT( secp256k1_rangeproof_info( detail::_get_context(), - (int*)&result.exp, - (int*)&result.mantissa, - (uint64_t*)&result.min_value, - (uint64_t*)&result.max_value, - (const unsigned char*)proof.data(), - (int)proof.size() ) ); - - return result; - } + FC_ASSERT( secp256k1_ecdsa_recoverable_signature_parse_compact( detail::_get_context(), &secp_sig, (unsigned char*)c.begin() + 1, (*c.begin() - 27) & 3) ); + FC_ASSERT( secp256k1_ecdsa_recover( detail::_get_context(), &secp_pub, &secp_sig, (unsigned char*) digest.data() ) ); + size_t serialized_result_sz = my->_key.size(); + secp256k1_ec_pubkey_serialize( detail::_get_context(), (unsigned char*)&my->_key.data, &serialized_result_sz, &secp_pub, SECP256K1_EC_COMPRESSED ); + FC_ASSERT( serialized_result_sz == my->_key.size() ); + } } } diff --git a/src/crypto/elliptic_webauthn.cpp b/src/crypto/elliptic_webauthn.cpp index cb1de5980..3c0c2b098 100644 --- a/src/crypto/elliptic_webauthn.cpp +++ b/src/crypto/elliptic_webauthn.cpp @@ -89,6 +89,7 @@ struct webauthn_json_handler : public rapidjson::BaseReaderHandler { @@ -36,7 +36,7 @@ namespace fc { namespace crypto { signature private_key::sign( const sha256& digest, bool require_canonical ) const { - return signature(_storage.visit(sign_visitor(digest, require_canonical))); + return signature(std::visit(sign_visitor(digest, require_canonical), _storage)); } struct generate_shared_secret_visitor : visitor { @@ -48,7 +48,7 @@ namespace fc { namespace crypto { sha512 operator()(const KeyType& key) const { using PublicKeyType = typename KeyType::public_key_type; - return key.generate_shared_secret(_pub_storage.template get()); + return key.generate_shared_secret(std::template get(_pub_storage)); } const public_key::storage_type& _pub_storage; @@ -56,7 +56,7 @@ namespace fc { namespace crypto { sha512 private_key::generate_shared_secret( const public_key& pub ) const { - return _storage.visit(generate_shared_secret_visitor(pub._storage)); + return std::visit(generate_shared_secret_visitor(pub._storage), _storage); } template @@ -88,13 +88,13 @@ namespace fc { namespace crypto { return Data(fc::variant(key_bytes).as()); } - static private_key::storage_type parse_base58(const string& base58str) + static private_key::storage_type priv_parse_base58(const string& base58str) { const auto pivot = base58str.find('_'); if (pivot == std::string::npos) { // wif import - using default_type = private_key::storage_type::template type_at<0>; + using default_type = std::variant_alternative_t<0, private_key::storage_type>; return private_key::storage_type(from_wif(base58str)); } else { constexpr auto prefix = config::private_key_base_prefix; @@ -108,19 +108,19 @@ namespace fc { namespace crypto { } private_key::private_key(const std::string& base58str) - :_storage(parse_base58(base58str)) + :_storage(priv_parse_base58(base58str)) {} std::string private_key::to_string(const fc::yield_function_t& yield) const { - auto which = _storage.which(); + auto which = _storage.index(); if (which == 0) { - using default_type = storage_type::template type_at<0>; - return to_wif(_storage.template get(), yield); + using default_type = std::variant_alternative_t<0, private_key::storage_type>; + return to_wif(std::template get(_storage), yield); } - auto data_str = _storage.visit(base58str_visitor(yield)); + auto data_str = std::visit(base58str_visitor(yield), _storage); return std::string(config::private_key_base_prefix) + "_" + data_str; } diff --git a/src/crypto/public_key.cpp b/src/crypto/public_key.cpp index 48983241c..622a73cfc 100644 --- a/src/crypto/public_key.cpp +++ b/src/crypto/public_key.cpp @@ -20,12 +20,12 @@ namespace fc { namespace crypto { }; public_key::public_key( const signature& c, const sha256& digest, bool check_canonical ) - :_storage(c._storage.visit(recovery_visitor(digest, check_canonical))) + :_storage(std::visit(recovery_visitor(digest, check_canonical), c._storage)) { } int public_key::which() const { - return _storage.which(); + return _storage.index(); } static public_key::storage_type parse_base58(const std::string& base58str) @@ -33,7 +33,7 @@ namespace fc { namespace crypto { constexpr auto legacy_prefix = config::public_key_legacy_prefix; if(prefix_matches(legacy_prefix, base58str) && base58str.find('_') == std::string::npos ) { auto sub_str = base58str.substr(const_strlen(legacy_prefix)); - using default_type = typename public_key::storage_type::template type_at<0>; + using default_type = typename std::variant_alternative_t<0, public_key::storage_type>; //public_key::storage_type::template type_at<0>; using data_type = default_type::data_type; using wrapper = checksummed_data; auto bin = fc::from_base58(sub_str); @@ -69,14 +69,14 @@ namespace fc { namespace crypto { bool public_key::valid()const { - return _storage.visit(is_valid_visitor()); + return std::visit(is_valid_visitor(), _storage); } std::string public_key::to_string(const fc::yield_function_t& yield) const { - auto data_str = _storage.visit(base58str_visitor(yield)); + auto data_str = std::visit(base58str_visitor(yield), _storage); - auto which = _storage.which(); + auto which = _storage.index(); if (which == 0) { return std::string(config::public_key_legacy_prefix) + data_str; } else { diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp index af337f6fd..1b6e9f163 100644 --- a/src/crypto/ripemd160.cpp +++ b/src/crypto/ripemd160.cpp @@ -112,7 +112,7 @@ bool operator == ( const ripemd160& h1, const ripemd160& h2 ) { memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } else - memset( &bi, char(0), sizeof(bi) ); + memset( bi._hash, char(0), sizeof(bi._hash) ); } } // fc diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp index 29c98a1e2..2aa21c9a9 100644 --- a/src/crypto/sha1.cpp +++ b/src/crypto/sha1.cpp @@ -22,7 +22,8 @@ string sha1::str()const { } sha1::operator string()const { return str(); } -char* sha1::data()const { return (char*)&_hash[0]; } +char* sha1::data() { return (char*)&_hash[0]; } +const char* sha1::data()const { return (char*)&_hash[0]; } struct sha1::encoder::impl { @@ -97,7 +98,7 @@ bool operator == ( const sha1& h1, const sha1& h2 ) { memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } else - memset( &bi, char(0), sizeof(bi) ); + memset( bi._hash, char(0), sizeof(bi._hash) ); } } // fc diff --git a/src/crypto/sha224.cpp b/src/crypto/sha224.cpp index ac00dbbf1..5c6fad25d 100644 --- a/src/crypto/sha224.cpp +++ b/src/crypto/sha224.cpp @@ -21,8 +21,8 @@ namespace fc { } sha224::operator string()const { return str(); } - char* sha224::data()const { return (char*)&_hash[0]; } - + char* sha224::data() { return (char*)&_hash[0]; } + const char* sha224::data() const { return (const char*)&_hash[0]; } struct sha224::encoder::impl { SHA256_CTX ctx; @@ -93,7 +93,7 @@ namespace fc { memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } else - memset( &bi, char(0), sizeof(bi) ); + memset( bi._hash, char(0), sizeof(bi._hash) ); } template<> diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp index 807384b00..c7e9d53c3 100644 --- a/src/crypto/sha256.cpp +++ b/src/crypto/sha256.cpp @@ -28,7 +28,8 @@ namespace fc { } sha256::operator string()const { return str(); } - char* sha256::data()const { return (char*)&_hash[0]; } + const char* sha256::data()const { return (const char*)&_hash[0]; } + char* sha256::data() { return (char*)&_hash[0]; } struct sha256::encoder::impl { @@ -214,7 +215,7 @@ namespace fc { memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } else - memset( &bi, char(0), sizeof(bi) ); + memset( bi._hash, char(0), sizeof(bi._hash) ); } uint64_t hash64(const char* buf, size_t len) diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp index ec4e116cd..1a5929ccf 100644 --- a/src/crypto/sha512.cpp +++ b/src/crypto/sha512.cpp @@ -21,7 +21,8 @@ namespace fc { } sha512::operator string()const { return str(); } - char* sha512::data()const { return (char*)&_hash[0]; } + char* sha512::data() { return (char*)&_hash[0]; } + const char* sha512::data()const { return (const char*)&_hash[0]; } struct sha512::encoder::impl { @@ -99,7 +100,7 @@ namespace fc { memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } else - memset( &bi, char(0), sizeof(bi) ); + memset( bi._hash, char(0), sizeof(bi._hash) ); } template<> diff --git a/src/crypto/signature.cpp b/src/crypto/signature.cpp index 1372679f1..ce5c7acfa 100644 --- a/src/crypto/signature.cpp +++ b/src/crypto/signature.cpp @@ -16,7 +16,7 @@ namespace fc { namespace crypto { } }; - static signature::storage_type parse_base58(const std::string& base58str) + static signature::storage_type sig_parse_base58(const std::string& base58str) { try { constexpr auto prefix = config::signature_base_prefix; @@ -32,30 +32,30 @@ namespace fc { namespace crypto { } FC_RETHROW_EXCEPTIONS( warn, "error parsing signature", ("str", base58str ) ) } signature::signature(const std::string& base58str) - :_storage(parse_base58(base58str)) + :_storage(sig_parse_base58(base58str)) {} int signature::which() const { - return _storage.which(); + return _storage.index(); } template struct overloaded : Ts... { using Ts::operator()...; }; template overloaded(Ts...) -> overloaded; size_t signature::variable_size() const { - return _storage.visit(overloaded { + return std::visit(overloaded { [&](const auto& k1r1) { - return 0; + return static_cast(0); }, [&](const webauthn::signature& wa) { - return wa.variable_size(); + return static_cast(wa.variable_size()); } - }); + }, _storage); } std::string signature::to_string(const fc::yield_function_t& yield) const { - auto data_str = _storage.visit(base58str_visitor(yield)); + auto data_str = std::visit(base58str_visitor(yield), _storage); yield(); return std::string(config::signature_base_prefix) + "_" + data_str; } @@ -79,7 +79,7 @@ namespace fc { namespace crypto { } size_t hash_value(const signature& b) { - return b._storage.visit(hash_visitor()); + return std::visit(hash_visitor(), b._storage); } } } // eosio::blockchain diff --git a/src/exception.cpp b/src/exception.cpp index b05b8cd98..a9d9de221 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -118,7 +118,7 @@ namespace fc :my( fc::move(c.my) ){} const char* exception::name()const throw() { return my->_name.c_str(); } - const char* exception::what()const throw() { return my->_what.c_str(); } + const char* exception::what()const noexcept { return my->_what.c_str(); } int64_t exception::code()const throw() { return my->_code; } exception::~exception(){} @@ -332,6 +332,14 @@ namespace fc _inner = {std::move(e)}; } + std_exception_wrapper std_exception_wrapper::from_current_exception(const std::exception& e) + { + return std_exception_wrapper{FC_LOG_MESSAGE(warn, "rethrow ${what}: ", ("what",e.what())), + std::current_exception(), + BOOST_CORE_TYPEID(e).name(), + e.what()}; + } + std::exception_ptr std_exception_wrapper::get_inner_exception()const { return _inner; } NO_RETURN void std_exception_wrapper::dynamic_rethrow_exception()const diff --git a/src/filesystem.cpp b/src/filesystem.cpp index 2337d1017..4c3eb2ab3 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -170,6 +170,8 @@ namespace fc { bool path::is_relative()const { return _p->is_relative(); } bool path::is_absolute()const { return _p->is_absolute(); } + bool path::empty() const { return _p->empty(); } + directory_iterator::directory_iterator( const fc::path& p ) :_p(p){} @@ -245,7 +247,24 @@ namespace fc { void copy( const path& f, const path& t ) { boost::system::error_code ec; try { + #if BOOST_VERSION > 107300 + if (exists(t)){ + throw boost::system::system_error(boost::system::errc::make_error_code(boost::system::errc::errc_t::file_exists)); + } + if ( boost::filesystem::is_directory( f ) ) { + boost::filesystem::copy(boost::filesystem::path(f), + boost::filesystem::path(t), + boost::filesystem::copy_options::directories_only, + ec ); + } else { + boost::filesystem::copy(boost::filesystem::path(f), + boost::filesystem::path(t), + boost::filesystem::copy_options::none, + ec ); + } + #else boost::filesystem::copy( boost::filesystem::path(f), boost::filesystem::path(t), ec ); + #endif } catch ( boost::system::system_error& e ) { FC_THROW( "Copy from ${srcfile} to ${dstfile} failed because ${reason}", ("srcfile",f)("dstfile",t)("reason",e.what() ) ); @@ -254,8 +273,8 @@ namespace fc { ("srcfile",f)("dstfile",t)("inner", fc::except_str() ) ); } if( ec ) { - FC_THROW( "Copy from ${srcfile} to ${dstfile} failed because ${reason}", - ("srcfile",f)("dstfile",t)("reason", ec.category().name() ) ); + FC_THROW( "Copy from ${srcfile} to ${dstfile} failed because ${reason}, category: ${cat}", + ("srcfile",f)("dstfile",t)("reason", ec.message())("cat", ec.category().name()) ); } } void resize_file( const path& f, size_t t ) @@ -428,7 +447,7 @@ namespace fc { void temp_file_base::remove() { - if (_path.valid()) + if (_path) { try { @@ -444,7 +463,7 @@ namespace fc { void temp_file_base::release() { - _path = fc::optional(); + _path = std::optional(); } const fc::path& home_path() diff --git a/src/io/json.cpp b/src/io/json.cpp index 93102345d..01d57b084 100644 --- a/src/io/json.cpp +++ b/src/io/json.cpp @@ -3,6 +3,7 @@ //#include #include //#include +#include #include #include #include @@ -485,91 +486,96 @@ namespace fc */ /** - * Convert '\t', '\a', '\n', '\\' and '"' to "\t\a\n\\\"" - * - * All other characters are printed as UTF8. + * Convert '\t', '\r', '\n', '\\' and '"' to "\t\r\n\\\"" if escape_control_chars == true + * Convert all other < 32 & 127 ascii to escaped unicode "\u00xx" + * Removes invalid utf8 characters + * Escapes Control sequence Introducer 0x9b to \u009b + * All other characters unmolested. */ - void escape_string( const string& str, std::ostream& os, const json::yield_function_t& yield ) + std::string escape_string( const std::string_view& str, const json::yield_function_t& yield, bool escape_control_chars ) { - os << '"'; + string r; + const auto init_size = str.size(); + r.reserve( init_size + 13 ); // allow for a few escapes size_t i = 0; for( auto itr = str.begin(); itr != str.end(); ++i,++itr ) { - if( i % json::escape_string_yeild_check_count == 0 ) yield(os); + if( i % json::escape_string_yield_check_count == 0 ) yield( init_size + r.size() ); switch( *itr ) { - case '\b': // \x08 - os << "\\b"; - break; - case '\f': // \x0c - os << "\\f"; - break; + case '\x00': r += "\\u0000"; break; + case '\x01': r += "\\u0001"; break; + case '\x02': r += "\\u0002"; break; + case '\x03': r += "\\u0003"; break; + case '\x04': r += "\\u0004"; break; + case '\x05': r += "\\u0005"; break; + case '\x06': r += "\\u0006"; break; + case '\x07': r += "\\u0007"; break; // \a is not valid JSON + case '\x08': r += "\\u0008"; break; // \b + // case '\x09': r += "\\u0009"; break; // \t + // case '\x0a': r += "\\u000a"; break; // \n + case '\x0b': r += "\\u000b"; break; + case '\x0c': r += "\\u000c"; break; // \f + // case '\x0d': r += "\\u000d"; break; // \r + case '\x0e': r += "\\u000e"; break; + case '\x0f': r += "\\u000f"; break; + case '\x10': r += "\\u0010"; break; + case '\x11': r += "\\u0011"; break; + case '\x12': r += "\\u0012"; break; + case '\x13': r += "\\u0013"; break; + case '\x14': r += "\\u0014"; break; + case '\x15': r += "\\u0015"; break; + case '\x16': r += "\\u0016"; break; + case '\x17': r += "\\u0017"; break; + case '\x18': r += "\\u0018"; break; + case '\x19': r += "\\u0019"; break; + case '\x1a': r += "\\u001a"; break; + case '\x1b': r += "\\u001b"; break; + case '\x1c': r += "\\u001c"; break; + case '\x1d': r += "\\u001d"; break; + case '\x1e': r += "\\u001e"; break; + case '\x1f': r += "\\u001f"; break; + + case '\x7f': r += "\\u007f"; break; + + // if escape_control_chars=true these fall-through to default + case '\t': // \x09 + if( escape_control_chars ) { + r += "\\t"; + break; + } case '\n': // \x0a - os << "\\n"; - break; + if( escape_control_chars ) { + r += "\\n"; + break; + } case '\r': // \x0d - os << "\\r"; - break; - case '\t': // \x09 - os << "\\t"; - break; + if( escape_control_chars ) { + r += "\\r"; + break; + } case '\\': - os << "\\\\"; - break; + if( escape_control_chars ) { + r += "\\\\"; + break; + } case '\"': - os << "\\\""; - break; - case '\x00': os << "\\u0000"; break; - case '\x01': os << "\\u0001"; break; - case '\x02': os << "\\u0002"; break; - case '\x03': os << "\\u0003"; break; - case '\x04': os << "\\u0004"; break; - case '\x05': os << "\\u0005"; break; - case '\x06': os << "\\u0006"; break; - case '\x07': os << "\\u0007"; break; // \a is not valid JSON - // case '\x08': os << "\\u0008"; break; // \b - // case '\x09': os << "\\u0009"; break; // \t - // case '\x0a': os << "\\u000a"; break; // \n - case '\x0b': os << "\\u000b"; break; - // case '\x0c': os << "\\u000c"; break; // \f - // case '\x0d': os << "\\u000d"; break; // \r - case '\x0e': os << "\\u000e"; break; - case '\x0f': os << "\\u000f"; break; - - case '\x10': os << "\\u0010"; break; - case '\x11': os << "\\u0011"; break; - case '\x12': os << "\\u0012"; break; - case '\x13': os << "\\u0013"; break; - case '\x14': os << "\\u0014"; break; - case '\x15': os << "\\u0015"; break; - case '\x16': os << "\\u0016"; break; - case '\x17': os << "\\u0017"; break; - case '\x18': os << "\\u0018"; break; - case '\x19': os << "\\u0019"; break; - case '\x1a': os << "\\u001a"; break; - case '\x1b': os << "\\u001b"; break; - case '\x1c': os << "\\u001c"; break; - case '\x1d': os << "\\u001d"; break; - case '\x1e': os << "\\u001e"; break; - case '\x1f': os << "\\u001f"; break; - + if( escape_control_chars ) { + r += "\\\""; + break; + } default: - os << *itr; - //toUTF8( *itr, os ); + r += *itr; } } - os << '"'; - } - std::ostream& json::to_stream( std::ostream& out, const std::string& str, const json::yield_function_t& yield ) - { - escape_string( str, out, yield ); - return out; + + return is_valid_utf8( r ) ? r : prune_invalid_utf8( r ); } template void to_stream( T& os, const variants& a, const json::yield_function_t& yield, const json::output_formatting format ) { - yield(os); + yield(os.tellp()); os << '['; auto itr = a.begin(); @@ -586,13 +592,13 @@ namespace fc template void to_stream( T& os, const variant_object& o, const json::yield_function_t& yield, const json::output_formatting format ) { - yield(os); + yield(os.tellp()); os << '{'; auto itr = o.begin(); while( itr != o.end() ) { - escape_string( itr->key(), os, yield ); + os << '"' << escape_string( itr->key(), yield ) << '"'; os << ':'; to_stream( os, itr->value(), yield, format ); ++itr; @@ -605,7 +611,7 @@ namespace fc template void to_stream( T& os, const variant& v, const json::yield_function_t& yield, const json::output_formatting format ) { - yield(os); + yield(os.tellp()); switch( v.get_type() ) { case variant::null_type: @@ -643,10 +649,10 @@ namespace fc os << v.as_string(); return; case variant::string_type: - escape_string( v.get_string(), os, yield ); + os << '"' << escape_string( v.get_string(), yield ) << '"'; return; case variant::blob_type: - escape_string( v.as_string(), os, yield ); + os << '"' << escape_string( v.as_string(), yield ) << '"'; return; case variant::array_type: { @@ -669,7 +675,7 @@ namespace fc { std::stringstream ss; fc::to_stream( ss, v, yield, format ); - yield(ss); + yield(ss.tellp()); return ss.str(); } @@ -781,7 +787,7 @@ namespace fc return o.good(); } else { std::ofstream o(fi.generic_string().c_str()); - const auto yield = [&](std::ostream& os) { + const auto yield = [&](size_t s) { // no limitation }; fc::to_stream( o, v, yield, format ); @@ -827,30 +833,6 @@ namespace fc } */ - std::ostream& json::to_stream( std::ostream& out, const variant& v, const json::yield_function_t& yield, const json::output_formatting format ) - { - fc::to_stream( out, v, yield, format ); - return out; - } - std::ostream& json::to_stream( std::ostream& out, const variants& v, const json::yield_function_t& yield, const json::output_formatting format ) - { - fc::to_stream( out, v, yield, format ); - return out; - } - std::ostream& json::to_stream( std::ostream& out, const variant_object& v, const json::yield_function_t& yield, const json::output_formatting format ) - { - fc::to_stream( out, v, yield, format ); - return out; - } - - std::ostream& json::to_stream( std::ostream& out, const variant& v, const fc::time_point& deadline, const json::output_formatting format, const uint64_t max_len ) { - const auto yield = [&](std::ostream& os) { - FC_CHECK_DEADLINE(deadline); - FC_ASSERT( os.tellp() <= max_len ); - }; - return to_stream(out, v, yield, format); - } - bool json::is_valid( const std::string& utf8_str, const json::parse_type ptype, const uint32_t max_depth ) { if( utf8_str.size() == 0 ) return false; diff --git a/src/log/console_appender.cpp b/src/log/console_appender.cpp index a4aeb51df..45992f9db 100644 --- a/src/log/console_appender.cpp +++ b/src/log/console_appender.cpp @@ -20,7 +20,7 @@ namespace fc { public: config cfg; color::type lc[log_level::off+1]; - bool use_syslog_header{getenv("JOURNAL_STREAM")}; + bool use_syslog_header{getenv("JOURNAL_STREAM") != nullptr}; #ifdef WIN32 HANDLE console_handle; #endif @@ -48,10 +48,10 @@ namespace fc { #endif my->cfg = console_appender_config; #ifdef WIN32 - if (my->cfg.stream = stream::std_error) - my->console_handle = GetStdHandle(STD_ERROR_HANDLE); - else if (my->cfg.stream = stream::std_out) - my->console_handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (my->cfg.stream == stream::std_error) + my->console_handle = GetStdHandle(STD_ERROR_HANDLE); + else if (my->cfg.stream == stream::std_out) + my->console_handle = GetStdHandle(STD_OUTPUT_HANDLE); #endif for( int i = 0; i < log_level::off+1; ++i ) @@ -94,7 +94,7 @@ namespace fc { //fc::string message = fc::format_string( m.get_format(), m.get_data() ); //fc::variant lmsg(m); - FILE* out = stream::std_error ? stderr : stdout; + FILE* out = my->cfg.stream == stream::std_error ? stderr : stdout; //fc::string fmt_str = fc::format_string( cfg.format, mutable_variant_object(m.get_context())( "message", message) ); @@ -150,7 +150,7 @@ namespace fc { void console_appender::print( const std::string& text, color::type text_color ) { - FILE* out = stream::std_error ? stderr : stdout; + FILE* out = my->cfg.stream == stream::std_error ? stderr : stdout; #ifdef WIN32 if (my->console_handle != INVALID_HANDLE_VALUE) diff --git a/src/log/dmlog_appender.cpp b/src/log/dmlog_appender.cpp index c495d73aa..a550a7e1f 100644 --- a/src/log/dmlog_appender.cpp +++ b/src/log/dmlog_appender.cpp @@ -16,9 +16,8 @@ namespace fc { class dmlog_appender::impl { public: - bool is_stopped; + bool is_stopped = false; boost::asio::io_service* io_service; - boost::mutex log_mutex; }; dmlog_appender::dmlog_appender( const variant& args ) @@ -37,7 +36,6 @@ namespace fc { FILE* out = stdout; string message = format_string( "DMLOG " + m.get_format() + "\n", m.get_data() ); - std::unique_lock lock(my->log_mutex); if (my->is_stopped) { // It might happen that `io_server->stop` was called due to printing errors but did not take // effect just yet. So if we are stopped, print a line that we are terminated and return. diff --git a/src/log/gelf_appender.cpp b/src/log/gelf_appender.cpp index b5b3fc643..8a7b810ce 100644 --- a/src/log/gelf_appender.cpp +++ b/src/log/gelf_appender.cpp @@ -29,9 +29,9 @@ namespace fc class gelf_appender::impl { public: - config cfg; - optional gelf_endpoint; - udp_socket gelf_socket; + config cfg; + std::optional gelf_endpoint; + udp_socket gelf_socket; impl(const config& c) : cfg(c) diff --git a/src/log/logger_config.cpp b/src/log/logger_config.cpp index 032b29c26..6d8484362 100644 --- a/src/log/logger_config.cpp +++ b/src/log/logger_config.cpp @@ -66,7 +66,6 @@ namespace fc { log_config::get().logger_map.clear(); log_config::get().appender_map.clear(); - //slog( "\n%s", fc::json::to_pretty_string(cfg).c_str() ); for( size_t i = 0; i < cfg.appenders.size(); ++i ) { // create appender auto fact_itr = log_config::get().appender_factory_map.find( cfg.appenders[i].type ); @@ -81,17 +80,17 @@ namespace fc { auto lgr = log_config::get().logger_map[cfg.loggers[i].name]; // TODO: finish configure logger here... - if( cfg.loggers[i].parent.valid() ) { + if( cfg.loggers[i].parent ) { lgr.set_parent( log_config::get().logger_map[*cfg.loggers[i].parent] ); } lgr.set_name(cfg.loggers[i].name); - if( cfg.loggers[i].level.valid() ) lgr.set_log_level( *cfg.loggers[i].level ); + if( cfg.loggers[i].level ) lgr.set_log_level( *cfg.loggers[i].level ); for( auto a = cfg.loggers[i].appenders.begin(); a != cfg.loggers[i].appenders.end(); ++a ){ auto ap_it = log_config::get().appender_map.find(*a); if( ap_it != log_config::get().appender_map.end() ) { - lgr.add_appender(ap_it->second); + lgr.add_appender( ap_it->second ); } } } diff --git a/src/log/zipkin.cpp b/src/log/zipkin.cpp new file mode 100644 index 000000000..ea7e35913 --- /dev/null +++ b/src/log/zipkin.cpp @@ -0,0 +1,331 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace { + std::atomic sighup_requested = false; +} + +namespace fc { + +struct local_endpoint_resolver { + using tcp = boost::asio::ip::tcp; + using error_code = boost::system::error_code; + + local_endpoint_resolver() + : resolver(ctx) + , sock(ctx) + , timer(ctx) {} + boost::asio::io_context ctx; + tcp::resolver resolver; + tcp::socket sock; + boost::asio::deadline_timer timer; + std::string remote; + tcp::resolver::results_type endpoints; + std::optional local_endpoint; + + void async_resolve(std::string remote_host, std::string port) { + remote = remote_host + ":" + port; + resolver.async_resolve(remote_host, port, [this](const error_code& ec, tcp::resolver::results_type resolved) { + if (ec) + throw boost::system::system_error(ec); + endpoints = resolved; + do_connect(); + }); + } + + void do_connect() { + boost::asio::async_connect(sock, endpoints, [this](const error_code& ec, const tcp::endpoint& endpoint) { + if (ec) { + wlog("failed to connect to ${remote}, retry in 5 seconds", ("remote", remote)); + timer.expires_from_now(boost::posix_time::seconds(5)); + timer.async_wait([this](const error_code& ec) { + if (!ec) + do_connect(); + }); + return; + } + local_endpoint = sock.local_endpoint(); + ilog("connected to ${remote}", ("remote", remote)); + }); + } +}; + +zipkin_config& zipkin_config::get() { + static zipkin_config the_one; + return the_one; +} + +void zipkin_config::init( const std::string& url, const std::string& service_name, uint32_t timeout_us, uint32_t retry_interval_us, uint32_t wait_time_seconds ) { + get().zip = std::make_unique( url, service_name, timeout_us, retry_interval_us, wait_time_seconds ); +} + +zipkin& zipkin_config::get_zipkin() { + if( !get().zip ) { + FC_THROW_EXCEPTION( fc::assert_exception, "uninitialized zipkin" ); + } + return *get().zip; +} + +void zipkin_config::shutdown() { + if( zipkin* z = get_zipkin_() ) { + z->shutdown(); + } +} + +uint64_t zipkin_config::get_next_unique_id() { + if( !get().zip ) { + FC_THROW_EXCEPTION( fc::assert_exception, "uninitialized zipkin" ); + } + return get().zip->get_next_unique_id(); +} + +void zipkin_config::handle_sighup(){ + static_assert(std::atomic::is_always_lock_free == true, "expected a lock-free atomic type"); + sighup_requested = true; +} + +class zipkin::impl { +public: + static constexpr uint32_t max_consecutive_errors = 9; + + const std::string zipkin_url; + const std::string service_name; + const uint32_t timeout_us; + const uint32_t retry_interval_us; + std::mutex mtx; + uint64_t next_id = 0; + http_client http; + bool connected = false; + // thread safe + std::atomic timer_expired = true; + std::atomic consecutive_errors = 0; + std::atomic stopped = 0; + std::optional endpoint; + std::thread thread; + boost::asio::io_context ctx; + boost::asio::deadline_timer timer{ctx}; + boost::asio::io_context::strand work_strand{ctx}; + boost::asio::executor_work_guard work_guard = boost::asio::make_work_guard(ctx); + std::optional local_endpoint; + + + impl( std::string url, std::string service_name, uint32_t timeout_us, uint32_t retry_interval_us ) + : zipkin_url( std::move(url) ) + , service_name( std::move(service_name) ) + , timeout_us( timeout_us ) + , retry_interval_us( retry_interval_us ) { + } + + void init(uint32_t wait_time_seconds); + void shutdown(); + + void log( zipkin_span::span_data&& span ); + + ~impl(); +}; + +void zipkin::impl::init(uint32_t wait_time_seconds) { + if (wait_time_seconds > 0) { + endpoint = url( zipkin_url ); + if (!endpoint->host() || endpoint->host()->empty()) + FC_THROW("Invalid url ${url}", ("url", zipkin_url)); + + local_endpoint_resolver resolver; + resolver.async_resolve(*endpoint->host(), std::to_string(*endpoint->port())); + auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(wait_time_seconds); + resolver.ctx.run_until(deadline); + + local_endpoint = resolver.local_endpoint; + + if (!local_endpoint) { + FC_THROW("Unable to connect to ${url} within ${wait_time_seconds} seconds", ("url", zipkin_url)("wait_time_seconds", wait_time_seconds)); + } + } + + thread = std::thread( [this]() { + fc::set_os_thread_name( "zipkin" ); + while( true ) { + try { + ctx.run(); + break; + } FC_LOG_AND_DROP(); + } + } ); +} + +zipkin::impl::~impl() { + try { + shutdown(); + } catch (...) {} +} + +void zipkin::impl::shutdown() { + if( stopped.exchange(1) ) return; + boost::system::error_code ec; + timer.cancel(ec); + work_guard.reset(); // drain the queue + thread.join(); +} + +zipkin::zipkin( const std::string& url, const std::string& service_name, uint32_t timeout_us, uint32_t retry_interval_us, uint32_t wait_time_seconds ) : + my( new impl( url, service_name, timeout_us, retry_interval_us ) ) { + my->init(wait_time_seconds); +} + +uint64_t zipkin::get_next_unique_id() { + std::scoped_lock g( my->mtx ); + if( my->next_id == 0 ) { + std::mt19937_64 engine( std::random_device{}() ); + std::uniform_int_distribution distribution(1); + my->next_id = distribution( engine ); + } + return my->next_id++; +} + +void zipkin::shutdown() { + my->shutdown(); +} + +fc::variant create_zipkin_variant( zipkin_span::span_data&& span, const std::string& service_name, std::optional& local_endpoint ) { + // https://zipkin.io/zipkin-api/ + // std::string traceId; // [a-f0-9]{16,32} unique id for trace, all children spans shared same id + // std::string name; // logical operation, should have low cardinality + // std::string parentId; // The parent span id, or absent if root span + // std::string id // a-f0-9]{16} + // int64_t timestamp // epoch microseconds of start of span + // int64_t duration // microseconds of span + + fc::mutable_variant_object mvo; + mvo( "id", fc::to_hex( reinterpret_cast(&span.id), sizeof( span.id ) ) ); + mvo( "traceId", fc::to_hex( reinterpret_cast(&span.trace_id), sizeof( span.trace_id ) ) ); + if( span.parent_id != 0 ) { + mvo( "parentId", fc::to_hex( reinterpret_cast(&span.parent_id), sizeof( span.parent_id ) ) ); + } + mvo( "name", std::move( span.name ) ); + mvo( "timestamp", span.start.time_since_epoch().count() ); + mvo( "duration", (span.stop - span.start).count() ); + + mutable_variant_object local_endpoint_mvo("serviceName", service_name); + if (local_endpoint) { + const auto &address = local_endpoint->address(); + local_endpoint_mvo( address.is_v4() ? "ipv4": "ipv6", address.to_string()); + } + mvo( "localEndpoint", local_endpoint_mvo ); + + mvo( "tags", std::move( span.tags ) ); + span.id = 0; // stop destructor of span from calling log again + + // /api/v2/spans takes an array of spans + fc::variants result; + result.emplace_back( std::move( mvo ) ); + + return result; +} + +void zipkin::post_request(zipkin_span::span_data&& span) { + boost::asio::post(my->work_strand, [my=my.get(), span{std::move(span)}]() mutable { + my->log( std::move( span ) ); + }); +} + +void zipkin::log( zipkin_span::span_data&& span ) { + if( my->stopped ) { + return; + }else if( sighup_requested.load()) { + sighup_requested = false; + my->consecutive_errors = 0; + ilog("Retry connecting to zipkin: ${u} ...", ("u", my->zipkin_url) ); + }else if( my->consecutive_errors > my->max_consecutive_errors ) { + return; + } + + if( my->consecutive_errors > 0 ) { + if( my->timer_expired ) { + my->timer_expired = false; + my->timer.expires_from_now(boost::posix_time::microsec(my->retry_interval_us)); + my->timer.async_wait([this](const boost::system::error_code& ec) { + sighup_requested = true; + if(!ec) + my->timer_expired = true; + }); + } + }else { + post_request(std::move(span)); + } +} + +void zipkin::impl::log( zipkin_span::span_data&& span ) { + auto errors = consecutive_errors.load(); + if ((errors > max_consecutive_errors) || (stopped && errors > 1)) { + if( errors < max_consecutive_errors + 5) { // reduce log spam + wlog("errors=${consecutive_errors} > limit(${max_consecutive_errors}) dropping: ${span}", + ("consecutive_errors", errors)("max_consecutive_errors", max_consecutive_errors) + ("span", create_zipkin_variant(std::move(span), service_name, local_endpoint))); + } + ++consecutive_errors; + return; + } + + fc::variant zip_span; + try { + auto deadline = fc::time_point::now() + fc::microseconds( timeout_us ); + if( !endpoint ) { + endpoint = url( zipkin_url ); + dlog( "connecting to zipkin: ${p}", ("p", *endpoint) ); + } + + zip_span = create_zipkin_variant(std::move(span), service_name, local_endpoint); + http.post_sync(*endpoint, zip_span, deadline, fc::json::output_formatting::legacy_generator); + + consecutive_errors = 0; + if (!connected){ + connected = true; + ilog("Connected to zipkin: ${u}", ("u", zipkin_url)); + } + return; + } catch( const fc::exception& e ) { + wlog( "unable to connect to zipkin: ${u}, error: ${e}, dropping: ${s}", + ("u", zipkin_url)("e", e.to_detail_string())("s", zip_span) ); + } catch( const std::exception& e ) { + wlog( "unable to connect to zipkin: ${u}, error: ${e}, dropping: ${s}", + ("u", zipkin_url)("e", e.what())("s", zip_span) ); + } catch( ... ) { + wlog( "unable to connect to zipkin: ${u}, error: unknown, dropping: ${s}", + ("u", zipkin_url)("s", zip_span) ); + } + ++consecutive_errors; + connected = false; +} + +uint64_t zipkin_span::to_id( const fc::sha256& id ) { + // avoid 0 since id of 0 is used as a flag + return id._hash[3] == 0 ? 1 : id._hash[3]; +} + +zipkin_span::~zipkin_span() { + if( data.id == 0 ) + return; + try { + if( zipkin_config::is_enabled() ) { + data.stop = time_point::now(); + zipkin_config::get_zipkin().log( std::move( data ) ); + } + } catch( ... ) {} +} + +std::string zipkin_span::trace_id_string() const { + return fc::to_hex(reinterpret_cast(&data.trace_id), sizeof(data.trace_id)); +} + +} // fc diff --git a/src/network/gntp.cpp b/src/network/gntp.cpp index 89c17354f..0c522d313 100644 --- a/src/network/gntp.cpp +++ b/src/network/gntp.cpp @@ -45,19 +45,19 @@ namespace fc class gntp_notifier_impl { public: - gntp_notifier_impl(const std::string& host_to_notify = "127.0.0.1", uint16_t port = 23053, const optional& password = optional()); + gntp_notifier_impl(const std::string& host_to_notify = "127.0.0.1", uint16_t port = 23053, const std::optional& password = std::optional()); // there's no API to change these right now, it will always notify localhost at the default GNTP port std::string hostname; uint16_t port; - optional password; + std::optional password; std::string application_name; gntp_icon_ptr application_icon; gntp_notification_type_list notification_types; // list of all notification types we're registered to send - optional endpoint; // cache the last endpoint we've connected to + std::optional endpoint; // cache the last endpoint we've connected to bool connection_failed; // true after we've tried to connect and failed bool is_registered; // true after we've registered @@ -66,7 +66,7 @@ namespace fc }; gntp_notifier_impl::gntp_notifier_impl(const std::string& host_to_notify /* = "127.0.0.1" */, uint16_t port /* = 23053 */, - const optional& password /* = optional() */) : + const std::optional& password /* = std::optional() */) : hostname(host_to_notify), port(port), password(password), @@ -94,14 +94,14 @@ namespace fc ("error_report", er.to_detail_string())); sock->close(); // clear the cached endpoint and fall through to the full connection procedure - endpoint = optional(); + endpoint = std::optional(); } catch (...) { ilog("Failed to connect to GNTP service using an endpoint that previously worked"); sock->close(); // clear the cached endpoint and fall through to the full connection procedure - endpoint = optional(); + endpoint = std::optional(); } } if (!connected) @@ -165,7 +165,7 @@ namespace fc } gntp_notifier::gntp_notifier(const std::string& host_to_notify /* = "127.0.0.1" */, uint16_t port /* = 23053 */, - const optional& password /* = optional() */) : + const std::optional& password /* = std::optional() */) : my(new detail::gntp_notifier_impl(host_to_notify, port, password)) { } @@ -243,7 +243,7 @@ namespace fc } } gntp_guid gntp_notifier::send_notification(std::string name, std::string title, std::string text, - const gntp_icon_ptr& icon, optional coalescingId /* = optional() */) + const gntp_icon_ptr& icon, std::optional coalescingId /* = std::optional() */) { if (my->connection_failed) return gntp_guid(); diff --git a/src/network/http/http_client.cpp b/src/network/http/http_client.cpp index a943b9cc0..8d712a44e 100644 --- a/src/network/http/http_client.cpp +++ b/src/network/http/http_client.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -16,9 +17,7 @@ using tcp = boost::asio::ip::tcp; // from namespace http = boost::beast::http; // from namespace ssl = boost::asio::ssl; // from -#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS namespace local = boost::asio::local; -#endif namespace fc { @@ -35,14 +34,8 @@ class http_client_impl { using host_key = std::tuple; using raw_socket_ptr = std::unique_ptr; using ssl_socket_ptr = std::unique_ptr>; -#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS using unix_socket_ptr = std::unique_ptr; -#endif - using connection = static_variant; + using connection = std::variant; using connection_map = std::map; using unix_url_split_map = std::map; using error_code = boost::system::error_code; @@ -85,7 +78,7 @@ class http_client_impl { } }); - optional f_result; + std::optional f_result; f(f_result); _ioc.restart(); @@ -118,7 +111,7 @@ class http_client_impl { tcp::resolver local_resolver(_ioc); bool cancelled = false; - auto res = sync_do_with_deadline(s, deadline, [&local_resolver, &cancelled, &s, &host, &port](optional& final_ec){ + auto res = sync_do_with_deadline(s, deadline, [&local_resolver, &cancelled, &s, &host, &port](std::optional& final_ec){ local_resolver.async_resolve(host, port, [&cancelled, &s, &final_ec](const error_code& ec, tcp::resolver::results_type resolved ){ if (ec) { final_ec.emplace(ec); @@ -141,7 +134,7 @@ class http_client_impl { template error_code sync_write_with_timeout(SyncReadStream& s, http::request& req, const deadline_type& deadline ) { - return sync_do_with_deadline(s, deadline, [&s, &req](optional& final_ec){ + return sync_do_with_deadline(s, deadline, [&s, &req](std::optional& final_ec){ http::async_write(s, req, [&final_ec]( const error_code& ec, std::size_t ) { final_ec.emplace(ec); }); @@ -150,7 +143,7 @@ class http_client_impl { template error_code sync_read_with_timeout(SyncReadStream& s, boost::beast::flat_buffer& buffer, http::response& res, const deadline_type& deadline ) { - return sync_do_with_deadline(s, deadline, [&s, &buffer, &res](optional& final_ec){ + return sync_do_with_deadline(s, deadline, [&s, &buffer, &res](std::optional& final_ec){ http::async_read(s, buffer, res, [&final_ec]( const error_code& ec, std::size_t ) { final_ec.emplace(ec); }); @@ -167,7 +160,6 @@ class http_client_impl { return std::make_tuple(dest.proto(), *dest.host(), port); } -#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS connection_map::iterator create_unix_connection( const url& dest, const deadline_type& deadline) { auto key = url_to_host_key(dest); auto socket = std::make_unique(_ioc); @@ -182,7 +174,6 @@ class http_client_impl { return res.first; } -#endif connection_map::iterator create_raw_connection( const url& dest, const deadline_type& deadline ) { auto key = url_to_host_key(dest); @@ -213,7 +204,7 @@ class http_client_impl { error_code ec = sync_connect_with_timeout(ssl_socket->next_layer(), *dest.host(), dest.port() ? std::to_string(*dest.port()) : "443", deadline); if (!ec) { - ec = sync_do_with_deadline(ssl_socket->next_layer(), deadline, [&ssl_socket](optional& final_ec) { + ec = sync_do_with_deadline(ssl_socket->next_layer(), deadline, [&ssl_socket](std::optional& final_ec) { ssl_socket->async_handshake(ssl::stream_base::client, [&final_ec](const error_code& ec) { final_ec.emplace(ec); }); @@ -233,10 +224,8 @@ class http_client_impl { return create_raw_connection(dest, deadline); } else if (dest.proto() == "https") { return create_ssl_connection(dest, deadline); -#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS } else if (dest.proto() == "unix") { return create_unix_connection(dest, deadline); -#endif } else { FC_THROW("Unknown protocol ${proto}", ("proto", dest.proto())); } @@ -251,15 +240,13 @@ class http_client_impl { return !ptr->lowest_layer().is_open(); } -#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS bool operator() ( const unix_socket_ptr& ptr) const { return !ptr->is_open(); } -#endif }; bool check_closed( const connection_map::iterator& conn_itr ) { - if (conn_itr->second.visit(check_closed_visitor())) { + if (std::visit(check_closed_visitor(), conn_itr->second)) { _connections.erase(conn_itr); return true; } else { @@ -313,7 +300,10 @@ class http_client_impl { const deadline_type& deadline; }; - variant post_sync(const url& dest, const variant& payload, const fc::time_point& _deadline) { + variant + post_sync(const url &dest, const variant &payload, + const fc::time_point &_deadline, + json::output_formatting formatting) { static const deadline_type epoch(boost::gregorian::date(1970, 1, 1)); auto deadline = epoch + boost::posix_time::microseconds(_deadline.time_since_epoch().count()); FC_ASSERT(dest.host(), "No host set on URL"); @@ -337,7 +327,7 @@ class http_client_impl { req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); req.set(http::field::content_type, "application/json"); req.keep_alive(true); - req.body() = json::to_string(payload, _deadline); + req.body() = json::to_string(payload, _deadline, formatting); req.prepare_payload(); auto conn_iter = get_connection(dest, deadline); @@ -346,7 +336,7 @@ class http_client_impl { }); // Send the HTTP request to the remote host - error_code ec = conn_iter->second.visit(write_request_visitor(this, req, deadline)); + error_code ec = std::visit(write_request_visitor(this, req, deadline), conn_iter->second); FC_ASSERT(!ec, "Failed to send request: ${message}", ("message",ec.message())); // This buffer is used for reading and must be persisted @@ -356,7 +346,7 @@ class http_client_impl { http::response res; // Receive the HTTP response - ec = conn_iter->second.visit(read_response_visitor(this, buffer, res, deadline)); + ec = std::visit(read_response_visitor(this, buffer, res, deadline), conn_iter->second); FC_ASSERT(!ec, "Failed to read response: ${message}", ("message",ec.message())); // if the connection can be kept open, keep it open @@ -364,7 +354,12 @@ class http_client_impl { eraser.cancel(); } - auto result = json::from_string(res.body()); + fc::variant result; + if( !res.body().empty() ) { + try { + result = json::from_string( res.body() ); + } catch( ... ) {} + } if (res.result() == http::status::internal_server_error) { fc::exception_ptr excp; try { @@ -372,8 +367,7 @@ class http_client_impl { excp = std::make_shared(err_var["code"].as_int64(), err_var["name"].as_string(), err_var["what"].as_string()); if (err_var.contains("details")) { - auto details = err_var["details"].get_array(); - for (const auto dvar : details) { + for (const auto& dvar : err_var["details"].get_array()) { excp->append_log(FC_LOG_MESSAGE(error, dvar.get_object()["message"].as_string())); } } @@ -388,12 +382,13 @@ class http_client_impl { } } else if (res.result() == http::status::not_found) { FC_THROW("URL not found: ${url}", ("url", (std::string)dest)); + } else if (res.result() == http::status::bad_request) { + FC_THROW("Received request: ${msg}", ("msg", res.body())); } return result; } -#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS /* Unix URLs work a little special here. They'll originally be in the format of unix:///home/username/eosio-wallet/keosd.sock/v1/wallet/sign_digest @@ -426,9 +421,8 @@ class http_client_impl { if(socket_file.empty()) FC_THROW_EXCEPTION( parse_error_exception, "couldn't discover socket path"); url_path = "/" / url_path; - return _unix_url_paths.emplace(full_url, fc::url("unix", socket_file.string(), ostring(), ostring(), url_path.string(), ostring(), ovariant_object(), fc::optional())).first->second; + return _unix_url_paths.emplace(full_url, fc::url("unix", socket_file.string(), ostring(), ostring(), url_path.string(), ostring(), ovariant_object(), std::optional())).first->second; } -#endif boost::asio::io_context _ioc; ssl::context _sslc; @@ -443,13 +437,12 @@ http_client::http_client() } -variant http_client::post_sync(const url& dest, const variant& payload, const fc::time_point& deadline) { -#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS - if(dest.proto() == "unix") - return _my->post_sync(_my->get_unix_url(*dest.host()), payload, deadline); +variant http_client::post_sync(const url& dest, const variant& payload, const fc::time_point& deadline, + json::output_formatting formatting) { + if (dest.proto() == "unix") + return _my->post_sync(_my->get_unix_url(*dest.host()), payload, deadline, formatting); else -#endif - return _my->post_sync(dest, payload, deadline); + return _my->post_sync(dest, payload, deadline, formatting); } void http_client::add_cert(const std::string& cert_pem_string) { @@ -464,4 +457,4 @@ http_client::~http_client() { } -} \ No newline at end of file +} diff --git a/src/network/ntp.cpp b/src/network/ntp.cpp index 539407195..c73880278 100644 --- a/src/network/ntp.cpp +++ b/src/network/ntp.cpp @@ -100,11 +100,23 @@ namespace fc { throw; } + catch ( const std::bad_alloc& ) + { + throw; + } + catch ( const boost::interprocess::bad_alloc& ) + { + throw; + } // this could fail to resolve but we want to go on to other hosts.. catch ( const fc::exception& e ) { elog( "${e}", ("e",e.to_detail_string() ) ); } + catch ( const std::exception& e ) + { + elog( "${e}", ("e",e.what() ) ); + } } } // request_now @@ -243,11 +255,11 @@ namespace fc my->_ntp_thread.async( [=](){ my->request_now(); } ).get(); } - optional ntp::get_time()const + std::optional ntp::get_time()const { if( my->_last_ntp_delta_initialized ) return fc::time_point::now() + fc::microseconds(my->_last_ntp_delta_microseconds); - return optional(); + return std::optional(); } } //namespace fc diff --git a/src/network/udt_socket.cpp b/src/network/udt_socket.cpp index 8a814b346..3806ee787 100644 --- a/src/network/udt_socket.cpp +++ b/src/network/udt_socket.cpp @@ -159,9 +159,14 @@ namespace fc { { try { close(); - } catch ( const fc::exception& e ) - { + } catch ( const std::bad_alloc& ) { + throw; + } catch ( const boost::interprocess::bad_alloc& ) { + throw; + } catch ( const fc::exception& e ) { wlog( "${e}", ("e", e.to_detail_string() ) ); + } catch ( const std::exception& e ) { + wlog( "${e}", ("e", e.what() ) ); } } @@ -337,9 +342,14 @@ namespace fc { { try { close(); - } catch ( const fc::exception& e ) - { + } catch ( const std::bad_alloc& ) { + throw; + } catch ( const boost::interprocess::bad_alloc& ) { + throw; + } catch ( const fc::exception& e ) { wlog( "${e}", ("e", e.to_detail_string() ) ); + } catch ( const std::exception& e ) { + wlog( "${e}", ("e", e.what() ) ); } } diff --git a/src/network/url.cpp b/src/network/url.cpp index 069f94f7a..defc2ab7c 100644 --- a/src/network/url.cpp +++ b/src/network/url.cpp @@ -60,7 +60,7 @@ namespace fc _path = fc::path( "/" ) / _lpath; #endif std::getline( ss, _largs ); - if( _args.valid() && _args->size() ) + if( _args && _args->size() ) { // TODO: args = fc::move(_args); _query = fc::move(_largs); @@ -74,7 +74,7 @@ namespace fc opath _path; ostring _query; ovariant_object _args; - fc::optional _port; + std::optional _port; }; } @@ -91,17 +91,17 @@ namespace fc { std::stringstream ss; ss<_proto<<"://"; - if( my->_user.valid() ) { + if( my->_user ) { ss << *my->_user; - if( my->_pass.valid() ) { + if( my->_pass ) { ss<<":"<<*my->_pass; } ss<<"@"; } - if( my->_host.valid() ) ss<<*my->_host; - if( my->_port.valid() ) ss<<":"<<*my->_port; - if( my->_path.valid() ) ss<_path->generic_string(); - if( my->_query.valid() ) ss<<"?"<<*my->_query; + if( my->_host ) ss<<*my->_host; + if( my->_port ) ss<<":"<<*my->_port; + if( my->_path ) ss<_path->generic_string(); + if( my->_query ) ss<<"?"<<*my->_query; // if( my->_args ) ss<<"?"<<*my->_args; return ss.str(); } @@ -132,7 +132,7 @@ namespace fc } url::url( const string& proto, const ostring& host, const ostring& user, const ostring& pass, - const opath& path, const ostring& query, const ovariant_object& args, const fc::optional& port) + const opath& path, const ostring& query, const ovariant_object& args, const std::optional& port) :my( std::make_shared() ) { my->_proto = proto; @@ -191,7 +191,7 @@ namespace fc { return my->_args; } - fc::optional url::port()const + std::optional url::port()const { return my->_port; } diff --git a/src/rpc/cli.cpp b/src/rpc/cli.cpp index d3070fb8b..64fafbe18 100644 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -118,10 +118,22 @@ void cli::run() else std::cout << itr->second( result, args ) << "\n"; } + catch ( const std::bad_alloc& ) + { + throw; + } + catch ( const boost::interprocess::bad_alloc& ) + { + throw; + } catch ( const fc::exception& e ) { std::cout << e.to_detail_string() << "\n"; } + catch ( const std::exception& e ) + { + std::cout << e.what() << "\n"; + } } } diff --git a/src/rpc/http_api.cpp b/src/rpc/http_api.cpp index c9a778687..41b009f26 100644 --- a/src/rpc/http_api.cpp +++ b/src/rpc/http_api.cpp @@ -86,6 +86,13 @@ void http_api_connection::on_request( const fc::http::request& req, const fc::ht std::string resp_body; http::reply::status_code resp_status; + auto handle_error = [&](const auto& e) + { + resp_status = http::reply::InternalServerError; + resp_body = ""; + wdump((e.to_detail_string())); + }; + try { resp.add_header( "Content-Type", "application/json" ); @@ -96,16 +103,33 @@ void http_api_connection::on_request( const fc::http::request& req, const fc::ht if( var_obj.contains( "method" ) ) { auto call = var.as(); + auto handle_error_inner = [&](const auto& e) + { + resp_body = fc::json::to_string( fc::rpc::response( *call.id, error_object{ 1, e.to_detail_string(), fc::variant(e)} ) ); + resp_status = http::reply::InternalServerError;} + }; + try { auto result = _rpc_state.local_call( call.method, call.params ); resp_body = fc::json::to_string( fc::rpc::response( *call.id, result ) ); resp_status = http::reply::OK; } + catch ( const std::bad_alloc& ) + { + throw; + } + catch ( const boost::interprocess::bad_alloc& ) + { + throw; + } catch ( const fc::exception& e ) { - resp_body = fc::json::to_string( fc::rpc::response( *call.id, error_object{ 1, e.to_detail_string(), fc::variant(e)} ) ); - resp_status = http::reply::InternalServerError; + handle_error_inner(e); + } + catch ( const std::exception& e ) + { + handle_error_inner(fc::std_exception_wrapper::from_current_exception(e)); } } else @@ -114,22 +138,45 @@ void http_api_connection::on_request( const fc::http::request& req, const fc::ht resp_body = ""; } } + catch ( const std::bad_alloc& ) + { + throw; + } + catch ( const boost::interprocess::bad_alloc& ) + { + throw; + } catch ( const fc::exception& e ) { - resp_status = http::reply::InternalServerError; - resp_body = ""; - wdump((e.to_detail_string())); + handle_error(e); + } + catch ( const std::exception& e ) + { + handle_error(fc::std_exception_wrapper::from_current_exception(e)); } + try { resp.set_status( resp_status ); resp.set_length( resp_body.length() ); resp.write( resp_body.c_str(), resp_body.length() ); } + catch ( const std::bad_alloc& ) + { + throw; + } + catch ( const boost::interprocess::bad_alloc& ) + { + throw; + } catch( const fc::exception& e ) { wdump((e.to_detail_string())); } + catch ( const std::exception& e ) + { + wdump((fc::std_exception_wrapper::from_current_exception(e).to_detail_string())); + } return; } diff --git a/src/rpc/json_connection.cpp b/src/rpc/json_connection.cpp deleted file mode 100644 index bde046a15..000000000 --- a/src/rpc/json_connection.cpp +++ /dev/null @@ -1,719 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fc { namespace rpc { - - namespace detail - { - class json_connection_impl - { - public: - json_connection_impl( fc::buffered_istream_ptr&& in, fc::buffered_ostream_ptr&& out ) - :_in(fc::move(in)),_out(fc::move(out)),_eof(false),_next_id(0),_logger("json_connection"){} - - fc::buffered_istream_ptr _in; - fc::buffered_ostream_ptr _out; - - fc::future _done; - fc::future _handle_message_future; - bool _eof; - - uint64_t _next_id; - boost::unordered_map::ptr> _awaiting; - boost::unordered_map _methods; - boost::unordered_map _named_param_methods; - - fc::mutex _write_mutex; - std::function _on_close; - - logger _logger; - - void send_result( variant id, variant result ) - { - ilog( "send: {\"id\": ${i}, \"result\": ${r}}", ("i",id)("r",result) ); - { - fc::scoped_lock lock(_write_mutex); - *_out << "{\"id\":"; - json::to_stream( *_out, id ); - *_out << ",\"result\":"; - json::to_stream( *_out, result); - *_out << "}\n"; - _out->flush(); - } - } - void send_error( variant id, fc::exception& e ) - { - ilog( "send: {\"id\": ${i}, \"error\":{\"message\": ${what},\"code\":0,\"data\":${data}}}", - ("i",id)("what",e.what())("data", e) ); - { - fc::scoped_lock lock(_write_mutex); - *_out << "{\"id\":"; - json::to_stream( *_out, id ); - *_out << ",\"error\":{\"message\":"; - json::to_stream( *_out, fc::string(e.what()) ); - *_out <<",\"code\":0,\"data\":"; - json::to_stream( *_out, variant(e)); - *_out << "}}\n"; - _out->flush(); - } - //wlog( "exception: ${except}", ("except", variant(e)) ); - } - - void handle_message( const variant_object& obj ) - { - wlog( "recv: ${msg}", ("msg", obj) ); - fc::exception_ptr eptr; - try - { - auto m = obj.find("method"); - auto i = obj.find("id"); - if( m != obj.end() ) - { - fc::exception except; - bool exception_caught = false; - try - { - auto p = obj.find("params"); - variant result; - if( p == obj.end() ) - { - auto pmi = _methods.find(m->value().as_string()); - auto nmi = _named_param_methods.find(m->value().as_string()); - if( pmi != _methods.end() ) - { - result = pmi->second( variants() ); - } - else if( nmi != _named_param_methods.end() ) - { - result = nmi->second( variant_object() ); - } - else // invalid method - { - FC_THROW_EXCEPTION( exception, "Invalid Method '${method}'", ("method",m->value().as_string())); - } - } - else if( p->value().is_array() ) - { - auto pmi = _methods.find(m->value().as_string()); - if( pmi != _methods.end() ) - { - result = pmi->second( p->value().get_array() ); - } - else // invalid method / param combo - { - FC_THROW_EXCEPTION( exception, "Invalid method or params '${method}'", - ("method",m->value().as_string())); - } - - } - else if( p->value().is_object() ) - { - auto nmi = _named_param_methods.find(m->value().as_string()); - if( nmi != _named_param_methods.end() ) - { - result = nmi->second( p->value().get_object() ); - } - else // invalid method / param combo? - { - FC_THROW_EXCEPTION( exception, "Invalid method or params '${method}'", - ("method",m->value().as_string())); - } - } - else // invalid params - { - FC_THROW_EXCEPTION( exception, "Invalid Params for method ${method}", - ("method",m->value().as_string())); - } - if( i != obj.end() ) - { - send_result( i->value(), result ); - } - } - catch ( fc::exception& e ) - { - exception_caught = true; - except = e; - } - if( exception_caught && i != obj.end() ) - send_error( i->value(), except ); - else - fc_wlog( _logger, "json rpc exception: ${exception}", ("exception",except) ); - } - else if( i != obj.end() ) //handle any received JSON response - { - uint64_t id = i->value().as_int64(); - auto await = _awaiting.find(id); - if( await != _awaiting.end() ) - { - auto r = obj.find("result"); - auto e = obj.find("error"); - if( r != obj.end() ) //if regular result response - { - await->second->set_value( r->value() ); - } - else if( e != obj.end() ) //if error response - { - fc::exception_ptr eptr; - try - { - auto err = e->value().get_object(); - auto data = err.find( "data" ); - if( data != err.end() ) - { - //wlog( "exception: ${except}", ("except", data->value() ) ); - await->second->set_exception( data->value().as().dynamic_copy_exception() ); - } - else - await->second->set_exception( exception_ptr(new FC_EXCEPTION( exception, "${error}", ("error",e->value()) ) ) ); - } - catch ( fc::exception& e ) - { - elog( "Error parsing exception: ${e}", ("e", e.to_detail_string() ) ); - eptr = e.dynamic_copy_exception(); - } - if( eptr ) await->second->set_exception( eptr ); - } - else // id found without error, result, nor method field - { - fc_wlog( _logger, "no error or result specified in '${message}'", ("message",obj) ); - } - } - } - else // no method nor request id... invalid message - { - - } - } - catch ( fc::exception& e ) // catch all other errors... - { - fc_elog( _logger, "json rpc exception: ${exception}", ("exception",e )); - elog( "json rpc exception: ${exception}", ("exception",e )); - eptr = e.dynamic_copy_exception(); - } - if( eptr ) { close(eptr); } - } - - void read_loop() - { - fc::exception_ptr eptr; - try - { - fc::string line; - while( !_done.canceled() ) - { - variant v = json::from_stream(*_in); - ///ilog( "input: ${in}", ("in", v ) ); - //wlog( "recv: ${line}", ("line", line) ); - _handle_message_future = fc::async([=](){ handle_message(v.get_object()); }, "json_connection handle_message"); - } - } - catch ( eof_exception& eof ) - { - _eof = true; - eptr = eof.dynamic_copy_exception(); - } - catch ( exception& e ) - { - eptr = e.dynamic_copy_exception(); - } - catch ( ... ) - { - eptr = fc::exception_ptr(new FC_EXCEPTION( unhandled_exception, "json connection read error" )); - } - if( eptr ) close( eptr ); - } - - void close( fc::exception_ptr e ) - { - wlog( "close ${reason}", ("reason", e->to_detail_string() ) ); - if( _on_close ) - _on_close(e); - for( auto itr = _awaiting.begin(); itr != _awaiting.end(); ++itr ) - { - itr->second->set_exception( e->dynamic_copy_exception() ); - } - } - }; - }//namespace detail - - json_connection::json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out ) - :my( new detail::json_connection_impl(fc::move(in),fc::move(out)) ) - {} - - json_connection::~json_connection() - { - close(); - } - - fc::future json_connection::exec() - { - if( my->_done.valid() ) - { - FC_THROW_EXCEPTION( assert_exception, "start should only be called once" ); - } - return my->_done = fc::async( [=](){ my->read_loop(); }, "json_connection read_loop" ); - } - - void json_connection::close() - { - try - { - if( my->_handle_message_future.valid() && !my->_handle_message_future.ready() ) - my->_handle_message_future.cancel_and_wait(__FUNCTION__); - if( my->_done.valid() && !my->_done.ready() ) - { - my->_done.cancel("json_connection is destructing"); - my->_out->close(); - my->_done.wait(); - } - } - catch ( fc::canceled_exception& ){} // expected exception - catch ( fc::eof_exception& ){} // expected exception - catch ( fc::exception& e ) - { - // unhandled, unexpected exception cannot throw from destructor, so log it. - wlog( "${exception}", ("exception",e.to_detail_string()) ); - } - } - - void json_connection::set_on_disconnected_callback(std::function callback) - { - my->_on_close = callback; - } - - void json_connection::add_method( const fc::string& name, method m ) - { - ilog( "add method ${name}", ("name",name) ); - my->_methods.emplace(std::pair(name,fc::move(m))); - } - void json_connection::add_named_param_method( const fc::string& name, named_param_method m ) - { - ilog( "add named param method ${name}", ("name",name) ); - my->_named_param_methods.emplace(std::pair(name,fc::move(m))); - } - void json_connection::remove_method( const fc::string& name ) - { - my->_methods.erase(name); - my->_named_param_methods.erase(name); - } - void json_connection::notice( const fc::string& method, const variants& args ) - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"method\":"; - json::to_stream( *my->_out, method ); - if( args.size() ) - { - *my->_out << ",\"params\":"; - fc::json::to_stream( *my->_out, args ); - *my->_out << "}\n"; - } - else - { - *my->_out << ",\"params\":[]}\n"; - } - } - void json_connection::notice( const fc::string& method, const variant_object& named_args ) - { - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << ",\"params\":"; - fc::json::to_stream( *my->_out, named_args ); - *my->_out << "}\n"; - my->_out->flush(); - } - } - void json_connection::notice( const fc::string& method ) - { - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << "}\n"; - my->_out->flush(); - } - } - - - future json_connection::async_call( const fc::string& method, const variants& args ) - { - auto id = my->_next_id++; - my->_awaiting[id] = fc::promise::ptr( new fc::promise("json_connection::async_call") ); - - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"id\":"; - *my->_out << id; - *my->_out << ",\"method\":"; - json::to_stream( *my->_out, method ); - if( args.size() ) - { - *my->_out << ",\"params\":"; - fc::json::to_stream( *my->_out, args ); - *my->_out << "}\n"; - } - else - { - *my->_out << ",\"params\":[]}\n"; - } - my->_out->flush(); - } - return my->_awaiting[id]; - } - - future json_connection::async_call( const fc::string& method, const variant& a1 ) - { - auto id = my->_next_id++; - my->_awaiting[id] = fc::promise::ptr( new fc::promise("json_connection::async_call") ); - - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"id\":"; - *my->_out << id; - *my->_out << ",\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << ",\"params\":["; - fc::json::to_stream( *my->_out, a1 ); - *my->_out << "]}\n"; - my->_out->flush(); - } - return my->_awaiting[id]; - } - future json_connection::async_call( const fc::string& method, const variant& a1, const variant& a2 ) - { - auto id = my->_next_id++; - my->_awaiting[id] = fc::promise::ptr( new fc::promise("json_connection::async_call") ); - - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"id\":"; - *my->_out << id; - *my->_out << ",\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << ",\"params\":["; - fc::json::to_stream( *my->_out, a1 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a2 ); - *my->_out << "]}\n"; - my->_out->flush(); - } - return my->_awaiting[id]; - } - future json_connection::async_call( const fc::string& method, const variant& a1, const variant& a2, const variant& a3 ) - { - auto id = my->_next_id++; - my->_awaiting[id] = fc::promise::ptr( new fc::promise("json_connection::async_call") ); - - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"id\":"; - *my->_out << id; - *my->_out << ",\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << ",\"params\":["; - fc::json::to_stream( *my->_out, a1 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a2 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a3 ); - *my->_out << "]}\n"; - my->_out->flush(); - } - return my->_awaiting[id]; - } - - future json_connection::async_call( const fc::string& method, const variant& a1, const variant& a2, const variant& a3, const variant& a4 ) - { - auto id = my->_next_id++; - my->_awaiting[id] = fc::promise::ptr( new fc::promise("json_connection::async_call") ); - - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"id\":"; - *my->_out << id; - *my->_out << ",\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << ",\"params\":["; - fc::json::to_stream( *my->_out, a1 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a2 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a3 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a4 ); - *my->_out << "]}\n"; - my->_out->flush(); - } - return my->_awaiting[id]; - } - - future json_connection::async_call( const fc::string& method, const variant& a1, const variant& a2, const variant& a3, const variant& a4, const variant& a5 ) - { - auto id = my->_next_id++; - my->_awaiting[id] = fc::promise::ptr( new fc::promise("json_connection::async_call") ); - - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"id\":"; - *my->_out << id; - *my->_out << ",\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << ",\"params\":["; - fc::json::to_stream( *my->_out, a1 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a2 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a3 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a4 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a5 ); - *my->_out << "]}\n"; - my->_out->flush(); - } - return my->_awaiting[id]; - } - - future json_connection::async_call( const fc::string& method, const variant& a1, const variant& a2, const variant& a3, const variant& a4, const variant& a5, const variant& a6 ) - { - auto id = my->_next_id++; - my->_awaiting[id] = fc::promise::ptr( new fc::promise("json_connection::async_call") ); - - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"id\":"; - *my->_out << id; - *my->_out << ",\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << ",\"params\":["; - fc::json::to_stream( *my->_out, a1 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a2 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a3 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a4 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a5 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a6 ); - *my->_out << "]}\n"; - my->_out->flush(); - } - return my->_awaiting[id]; - } - future json_connection::async_call( const fc::string& method, const variant& a1, const variant& a2, const variant& a3, const variant& a4, const variant& a5, const variant& a6, const variant& a7 ) - { - auto id = my->_next_id++; - my->_awaiting[id] = fc::promise::ptr( new fc::promise("json_connection::async_call") ); - - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"id\":"; - *my->_out << id; - *my->_out << ",\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << ",\"params\":["; - fc::json::to_stream( *my->_out, a1 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a2 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a3 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a4 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a5 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a6 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a7 ); - *my->_out << "]}\n"; - my->_out->flush(); - } - return my->_awaiting[id]; - } - future json_connection::async_call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - const variant& a6, - const variant& a7, - const variant& a8 ) - { - auto id = my->_next_id++; - my->_awaiting[id] = fc::promise::ptr( new fc::promise("json_connection::async_call") ); - - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"id\":"; - *my->_out << id; - *my->_out << ",\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << ",\"params\":["; - fc::json::to_stream( *my->_out, a1 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a2 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a3 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a4 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a5 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a6 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a7 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a8 ); - *my->_out << "]}\n"; - my->_out->flush(); - } - return my->_awaiting[id]; - } - future json_connection::async_call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - const variant& a6, - const variant& a7, - const variant& a8, - const variant& a9 ) - { - auto id = my->_next_id++; - my->_awaiting[id] = fc::promise::ptr( new fc::promise("json_connection::async_call") ); - - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"id\":"; - *my->_out << id; - *my->_out << ",\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << ",\"params\":["; - fc::json::to_stream( *my->_out, a1 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a2 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a3 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a4 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a5 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a6 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a7 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a8 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a9 ); - *my->_out << "]}\n"; - my->_out->flush(); - } - return my->_awaiting[id]; - } - future json_connection::async_call( const fc::string& method, - const variant& a1, - const variant& a2, - const variant& a3, - const variant& a4, - const variant& a5, - const variant& a6, - const variant& a7, - const variant& a8, - const variant& a9, - const variant& a10 ) - { - auto id = my->_next_id++; - my->_awaiting[id] = fc::promise::ptr( new fc::promise("json_connection::async_call") ); - - { - fc::scoped_lock lock(my->_write_mutex); - *my->_out << "{\"id\":"; - *my->_out << id; - *my->_out << ",\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << ",\"params\":["; - fc::json::to_stream( *my->_out, a1 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a2 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a3 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a4 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a5 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a6 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a7 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a8 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a9 ); - *my->_out << ","; - fc::json::to_stream( *my->_out, a10 ); - *my->_out << "]}\n"; - my->_out->flush(); - } - return my->_awaiting[id]; - } - - future json_connection::async_call( const fc::string& method, mutable_variant_object named_args ) - { - return async_call( method, variant_object( fc::move(named_args) ) ); - } - future json_connection::async_call( const fc::string& method, const variant_object& named_args ) - { - auto id = my->_next_id++; - my->_awaiting[id] = fc::promise::ptr( new fc::promise("json_connection::async_call") ); - fc::scoped_lock lock(my->_write_mutex); - { - *my->_out << "{\"id\":"; - *my->_out << id; - *my->_out << ",\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << ",\"params\":"; - fc::json::to_stream( *my->_out, named_args ); - *my->_out << "}\n"; - my->_out->flush(); - } - return my->_awaiting[id]; - } - future json_connection::async_call( const fc::string& method ) - { - auto id = my->_next_id++; - my->_awaiting[id] = fc::promise::ptr( new fc::promise("json_connection::async_call") ); - fc::scoped_lock lock(my->_write_mutex); - { - *my->_out << "{\"id\":"; - *my->_out << id; - *my->_out << ",\"method\":"; - json::to_stream( *my->_out, method ); - *my->_out << "}\n"; - my->_out->flush(); - } - return my->_awaiting[id]; - } - - logger json_connection::get_logger()const - { - return my->_logger; - } - - void json_connection::set_logger( const logger& l ) - { - my->_logger = l; - } - -}} diff --git a/src/rpc/state.cpp b/src/rpc/state.cpp index 49fc79ca9..0bad77f0a 100644 --- a/src/rpc/state.cpp +++ b/src/rpc/state.cpp @@ -45,7 +45,7 @@ void state::handle_reply( const response& response ) request state::start_remote_call( const string& method_name, variants args ) { request request{ _next_id++, method_name, std::move(args) }; - _awaiting[*request.id].reset( new boost::fibers::promise() ); + _awaiting[*request.id].reset( new boost::fibers::promise() ); return request; } variant state::wait_for_response( uint64_t request_id ) diff --git a/src/rpc/websocket_api.cpp b/src/rpc/websocket_api.cpp index 60ef7062b..f89e2f0c0 100644 --- a/src/rpc/websocket_api.cpp +++ b/src/rpc/websocket_api.cpp @@ -77,7 +77,7 @@ void websocket_api_connection::send_notice( uint64_t callback_id, variants args /* = variants() */ ) { - fc::rpc::request req{ optional(), "notice", {callback_id, std::move(args)}}; + fc::rpc::request req{ std::optional(), "notice", {callback_id, std::move(args)}}; _connection.send_message( fc::json::to_string(req) ); } @@ -86,6 +86,13 @@ std::string websocket_api_connection::on_message( bool send_message /* = true */ ) { wdump((message)); + + auto handle_error = [&](const auto& e) + { + wdump((e.to_detail_string())); + return e.to_detail_string(); + }; + try { auto var = fc::json::from_string(message); @@ -94,6 +101,17 @@ std::string websocket_api_connection::on_message( { auto call = var.as(); exception_ptr optexcept; + + auto handle_error_inner = [&](const auto& e) + { + if (!call.id) + { + return nullptr; + } + + return e.dynamic_copy_exception(); + }; + try { auto result = _rpc_state.local_call( call.method, call.params ); @@ -105,13 +123,23 @@ std::string websocket_api_connection::on_message( return reply; } } + catch ( const std::bad_alloc& ) + { + throw; + } + catch ( const boost::interprocess::bad_alloc& ) + { + throw; + } catch ( const fc::exception& e ) { - if( call.id ) - { - optexcept = e.dynamic_copy_exception(); - } + optexcept = handle_error_inner(e); + } + catch ( const std::exception& e ) + { + optexcept = handle_error_inner(fc::std_exception_wrapper::from_current_exception(e)); } + if( optexcept ) { auto reply = fc::json::to_string( response( *call.id, error_object{ 1, optexcept->to_detail_string(), fc::variant(*optexcept)} ) ); @@ -127,10 +155,21 @@ std::string websocket_api_connection::on_message( _rpc_state.handle_reply( reply ); } } + catch ( const std::bad_alloc& ) + { + throw; + } + catch ( const boost::interprocess::bad_alloc& ) + { + throw; + } catch ( const fc::exception& e ) { - wdump((e.to_detail_string())); - return e.to_detail_string(); + return handle_error(e); + } + catch ( const std::exception& e) + { + return handle_error(fc::std_exception_wrapper::from_current_exception(e)); } return string(); } diff --git a/src/uint128.cpp b/src/uint128.cpp index c5b26a1eb..523569d78 100644 --- a/src/uint128.cpp +++ b/src/uint128.cpp @@ -331,7 +331,7 @@ namespace fc uint64_t y[4]; // final result y[0] = sl; - uint128_t acc = sh; + uint128 acc = sh; acc += ql; acc += rl; y[1] = acc.lo; diff --git a/src/utf8.cpp b/src/utf8.cpp index 811de8c25..b274e3eaf 100644 --- a/src/utf8.cpp +++ b/src/utf8.cpp @@ -2,33 +2,68 @@ #include "utf8/checked.h" #include "utf8/core.h" -#include "utf8/unchecked.h" -#include -#include #include #include -#include namespace fc { - bool is_utf8( const std::string& str ) + inline constexpr char hex_digits[] = "0123456789abcdef"; + + bool is_utf8( const std::string& str ) + { + return utf8::is_valid( str.begin(), str.end() ); + } + + // tweaked utf8::find_invalid that also considers provided range as invalid + // @param invalid_range, indicates additional invalid values + // @return [iterator to found invalid char, the value found if in range of provided pair invalid_range otherwise UINT32_MAX] + template + std::pair find_invalid(octet_iterator start, octet_iterator end, + const std::pair& invalid_range) { - return utf8::is_valid( str.begin(), str.end() ); + FC_ASSERT( invalid_range.first <= invalid_range.second ); + octet_iterator result = start; + uint32_t value = UINT32_MAX; + while( result != end ) { + octet_iterator itr = result; + utf8::internal::utf_error err_code = utf8::internal::validate_next( result, end, value ); + if( err_code != utf8::internal::UTF8_OK ) + return {result, UINT32_MAX}; + if( value >= invalid_range.first && value <= invalid_range.second ) + return {itr, value}; + } + return {result, UINT32_MAX}; } - string prune_invalid_utf8( const string& str ) { - string result; - auto itr = utf8::find_invalid(str.begin(), str.end()); - if( itr == str.end() ) return str; + bool is_valid_utf8( const std::string_view& str ) { + const auto invalid_range = std::make_pair(0x80, 0x9F); + auto [itr, v] = find_invalid( str.begin(), str.end(), invalid_range ); + return itr == str.end(); + } + + // escape 0x80-0x9F C1 control characters + string prune_invalid_utf8( const std::string_view& str ) { + const auto invalid_range = std::make_pair(0x80, 0x9F); + auto [itr, v] = find_invalid( str.begin(), str.end(), invalid_range ); + if( itr == str.end() ) return std::string( str ); + + string result; + auto escape = [&result](uint32_t v) { // v is [0x80-0x9F] + result += "\\u00"; + result += hex_digits[v >> 4u]; + result += hex_digits[v & 15u]; + }; result = string( str.begin(), itr ); + if( v != UINT32_MAX ) escape(v); while( itr != str.end() ) { ++itr; auto start = itr; - itr = utf8::find_invalid( start, str.end()); + std::tie(itr, v) = find_invalid( start, str.end(), invalid_range ); result += string( start, itr ); + if( v != UINT32_MAX ) escape(v); } return result; } diff --git a/src/variant.cpp b/src/variant.cpp index b13f28725..d91a913bc 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include namespace fc @@ -713,6 +714,15 @@ void from_variant( const variant& var, std::vector& vo ) } } +void to_variant( const blob& b, variant& v ) { + v = variant(base64_encode(b.data.data(), b.data.size())); +} + +void from_variant( const variant& v, blob& b ) { + string _s = base64_decode(v.as_string()); + b.data = std::vector(_s.begin(), _s.end()); +} + void to_variant( const UInt<8>& n, variant& v ) { v = uint64_t(n); } // TODO: warn on overflow? void from_variant( const variant& v, UInt<8>& n ) { n = static_cast(v.as_uint64()); } @@ -730,6 +740,14 @@ void from_variant( const variant& v, UInt<64>& n ) { n = v.as_uint64(); } constexpr size_t minimize_max_size = 1024; +// same behavior as std::string::substr only removes invalid utf8, and lower ascii +void clean_append( string& app, const std::string_view& s, size_t pos = 0, size_t len = string::npos ) { + std::string_view sub = s.substr( pos, len ); + app.reserve( app.size() + sub.size() ); + const bool escape_control_chars = false; + app += escape_string( sub, nullptr, escape_control_chars ); +} + string format_string( const string& frmt, const variant_object& args, bool minimize ) { std::string result; @@ -746,9 +764,9 @@ string format_string( const string& frmt, const variant_object& args, bool minim size_t next = format.find( '$' ); while( prev != string::npos && prev < format.size() ) { if( next != string::npos ) { - result += format.substr( prev, next - prev ); + clean_append( result, format, prev, next - prev ); } else { - result += format.substr( prev ); + clean_append( result, format, prev ); } // if we got to the end, return it. @@ -779,7 +797,9 @@ string format_string( const string& frmt, const variant_object& args, bool minim } else { const auto max_length = minimize ? minimize_sub_max_size : std::numeric_limits::max(); try { - result += json::to_string(val->value(), fc::time_point::maximum(), json::output_formatting::stringify_large_ints_and_doubles, max_length); + // clean_append not needed as to_string is valid utf8 + result += json::to_string( val->value(), fc::time_point::maximum(), + json::output_formatting::stringify_large_ints_and_doubles, max_length ); } catch (...) { replaced = false; } @@ -788,25 +808,25 @@ string format_string( const string& frmt, const variant_object& args, bool minim if( minimize && val->value().get_blob().data.size() > minimize_sub_max_size ) { replaced = false; } else { - result += val->value().as_string(); + clean_append( result, val->value().as_string() ); } } else if( val->value().is_string() ) { if( minimize && val->value().get_string().size() > minimize_sub_max_size ) { auto sz = std::min( minimize_sub_max_size, minimize_max_size - result.size() ); - result += val->value().get_string().substr( 0, sz ); + clean_append( result, val->value().get_string(), 0, sz ); result += "..."; } else { - result += val->value().get_string(); + clean_append( result, val->value().get_string() ); } } else { - result += val->value().as_string(); + clean_append( result, val->value().as_string() ); } } else { replaced = false; } if( !replaced ) { result += "${"; - result += key; + clean_append( result, key ); result += "}"; } prev = next + 1; @@ -816,7 +836,7 @@ string format_string( const string& frmt, const variant_object& args, bool minim // we didn't find it.. continue to while... } } else { - result += format[prev]; + clean_append( result, format, prev, 1 ); ++prev; next = format.find( '$', prev ); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4d6c4bb3e..8d292ed67 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -9,3 +9,8 @@ add_executable( test_base64 test_base64.cpp ) target_link_libraries( test_base64 fc ) add_test(NAME test_base64 COMMAND libraries/fc/test/test_base64 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + +add_executable( test_filesystem test_filesystem.cpp ) +target_link_libraries( test_filesystem fc ) + +add_test(NAME test_filesystem COMMAND libraries/fc/test/test_filesystem WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/test/crypto/CMakeLists.txt b/test/crypto/CMakeLists.txt index c625a8e88..c293ed2ea 100644 --- a/test/crypto/CMakeLists.txt +++ b/test/crypto/CMakeLists.txt @@ -2,7 +2,7 @@ add_executable( test_cypher_suites test_cypher_suites.cpp ) target_link_libraries( test_cypher_suites fc ) add_executable( test_webauthn test_webauthn.cpp ) -target_link_libraries( test_webauthn fc ${Boost_LIBRARIES}) +target_link_libraries( test_webauthn fc ) add_test(NAME test_cypher_suites COMMAND libraries/fc/test/crypto/test_cypher_suites WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) add_test(NAME test_webauthn COMMAND libraries/fc/test/crypto/test_webauthn WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) \ No newline at end of file diff --git a/test/io/test_json.cpp b/test/io/test_json.cpp index 6552a0e79..a07fbefad 100644 --- a/test/io/test_json.cpp +++ b/test/io/test_json.cpp @@ -11,21 +11,21 @@ BOOST_AUTO_TEST_SUITE(json_test_suite) namespace json_test_util { constexpr size_t exception_limit_size = 250; - const json::yield_function_t yield_deadline_exception_at_start = [](std::ostream& os) { + const json::yield_function_t yield_deadline_exception_at_start = [](size_t s) { FC_CHECK_DEADLINE(fc::time_point::now() - fc::milliseconds(1)); }; - const json::yield_function_t yield_deadline_exception_in_mid = [](std::ostream& os) { - if (os.tellp() >= exception_limit_size) { + const json::yield_function_t yield_deadline_exception_in_mid = [](size_t s) { + if (s >= exception_limit_size) { throw fc::timeout_exception(fc::exception_code::timeout_exception_code, "timeout_exception", "execution timed out" ); } }; - const json::yield_function_t yield_length_exception = [](std::ostream& os) { - FC_ASSERT( os.tellp() <= exception_limit_size ); + const json::yield_function_t yield_length_exception = [](size_t s) { + FC_ASSERT( s <= exception_limit_size ); }; - const json::yield_function_t yield_no_limitation = [](std::ostream& os) { + const json::yield_function_t yield_no_limitation = [](size_t s) { // no limitation }; @@ -42,176 +42,8 @@ namespace json_test_util { const string escape_input_str = "\\b\\f\\n\\r\\t-\\-\\\\-\\x0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f" \ "\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f-" + repeat_chars; - const auto multiple_num = [](const size_t num, const size_t base) -> size_t { - return (num / base + ((num % base == 0) ? 0 : 1)) * base; - }; - } // namespace json_test_util -BOOST_AUTO_TEST_CASE(to_stream_test) -{ - { - // to_stream( ostream& out, const fc::string&, const yield_function_t& yield ); - std::stringstream escape_out_str_ss; - fc::escape_string(json_test_util::escape_input_str, escape_out_str_ss, json_test_util::yield_no_limitation); - const auto size_different = escape_out_str_ss.str().size() - json_test_util::escape_input_str.size(); - const auto expected_out_str_size = json_test_util::multiple_num(json_test_util::exception_limit_size, json::escape_string_yeild_check_count) + size_different - 1; - BOOST_CHECK_LT(json_test_util::repeat_char_num, json_test_util::escape_input_str.size()); - BOOST_CHECK_LT(json_test_util::escape_input_str.size() - json_test_util::repeat_char_num, json_test_util::exception_limit_size); // by using size_different to calculate expected string - { - std::stringstream deadline_exception_at_start_ss; - BOOST_CHECK_EXCEPTION(json::to_stream( deadline_exception_at_start_ss, json_test_util::escape_input_str, json_test_util::yield_deadline_exception_at_start), - fc::timeout_exception, - json_test_util::time_except_verf_func); - BOOST_CHECK_EQUAL(deadline_exception_at_start_ss.str(), "\""); - } - { - std::stringstream deadline_exception_in_mid_ss; - BOOST_CHECK_EXCEPTION(json::to_stream( deadline_exception_in_mid_ss, json_test_util::escape_input_str, json_test_util::yield_deadline_exception_in_mid), - fc::timeout_exception, - json_test_util::time_except_verf_func); - BOOST_CHECK_EQUAL(deadline_exception_in_mid_ss.str(), escape_out_str_ss.str().substr(0, expected_out_str_size)); - } - { - std::stringstream length_except_mid_ss; - BOOST_CHECK_EXCEPTION(json::to_stream(length_except_mid_ss, json_test_util::escape_input_str, json_test_util::yield_length_exception), - fc::assert_exception, - json_test_util::length_limit_except_verf_func); - BOOST_CHECK_EQUAL(length_except_mid_ss.str(), escape_out_str_ss.str().substr(0, expected_out_str_size)); - } - } - { - // to_stream( ostream& out, const variant& v, const fc::time_point& deadline, const uint64_t max_len = max_length_limit, output_formatting format = stringify_large_ints_and_doubles ); - { - variant v(json_test_util::escape_input_str); - std::stringstream deadline_exception_at_start_ss; - BOOST_CHECK_EXCEPTION(json::to_stream( deadline_exception_at_start_ss, v, fc::time_point::min(), json::output_formatting::stringify_large_ints_and_doubles, json::max_length_limit), - fc::timeout_exception, - json_test_util::time_except_verf_func); - BOOST_CHECK_EQUAL(deadline_exception_at_start_ss.str().empty(), true); - } - { - constexpr size_t max_len = 10; - variant v(json_test_util::repeat_chars); - std::stringstream length_exception_in_mid_ss; - BOOST_CHECK_EXCEPTION(json::to_stream( length_exception_in_mid_ss, v, fc::time_point::maximum(), json::output_formatting::stringify_large_ints_and_doubles, max_len), - fc::assert_exception, - json_test_util::length_limit_except_verf_func); - BOOST_CHECK_EQUAL(length_exception_in_mid_ss.str(), - "\"" + json_test_util::repeat_chars.substr(0, json_test_util::multiple_num(max_len, json::escape_string_yeild_check_count))); - } - { - variant v(json_test_util::repeat_chars); - std::stringstream length_exception_in_mid_ss; - BOOST_CHECK_NO_THROW(json::to_stream( length_exception_in_mid_ss, v, fc::time_point::maximum(), json::output_formatting::stringify_large_ints_and_doubles, json::max_length_limit)); - BOOST_CHECK_EQUAL(length_exception_in_mid_ss.str(), "\"" + json_test_util::repeat_chars + "\""); - } - } - { - // to_stream( ostream& out, const variant& v, const yield_function_t& yield, output_formatting format = stringify_large_ints_and_doubles ); - const variant v(json_test_util::repeat_chars); - BOOST_CHECK_LT(json_test_util::exception_limit_size, json_test_util::repeat_chars.size()); - { - std::stringstream deadline_exception_at_start_ss; - BOOST_CHECK_EXCEPTION(json::to_stream( deadline_exception_at_start_ss, v, json_test_util::yield_deadline_exception_at_start), - fc::timeout_exception, - json_test_util::time_except_verf_func); - BOOST_CHECK_EQUAL(deadline_exception_at_start_ss.str().empty(), true); - } - { - std::stringstream deadline_exception_in_mid_ss; - BOOST_CHECK_EXCEPTION(json::to_stream( deadline_exception_in_mid_ss, v, json_test_util::yield_deadline_exception_in_mid), - fc::timeout_exception, - json_test_util::time_except_verf_func); - BOOST_CHECK_EQUAL(deadline_exception_in_mid_ss.str(), - "\"" + json_test_util::repeat_chars.substr(0, json_test_util::multiple_num(json_test_util::exception_limit_size, json::escape_string_yeild_check_count))); - } - { - std::stringstream length_exception_in_mid_ss; - BOOST_CHECK_EXCEPTION(json::to_stream( length_exception_in_mid_ss, v, json_test_util::yield_length_exception), - fc::assert_exception, - json_test_util::length_limit_except_verf_func); - BOOST_CHECK_EQUAL(length_exception_in_mid_ss.str(), - "\"" + json_test_util::repeat_chars.substr(0, json_test_util::multiple_num(json_test_util::exception_limit_size, json::escape_string_yeild_check_count))); - } - { - std::stringstream no_exception_ss; - BOOST_CHECK_NO_THROW(json::to_stream( no_exception_ss, v, json_test_util::yield_no_limitation)); - BOOST_CHECK_EQUAL(no_exception_ss.str(), "\"" + json_test_util::repeat_chars + "\""); - } - } - { - // to_stream( ostream& out, const variants& v, const yield_function_t& yield, output_formatting format = stringify_large_ints_and_doubles ); - const std::string a_list(json_test_util::repeat_char_num, 'a'); - const std::string b_list(json_test_util::repeat_char_num, 'b'); - const variants variant_list{variant(a_list), variant(b_list)}; - BOOST_CHECK_LT(json_test_util::exception_limit_size, a_list.size() + b_list.size()); - { - std::stringstream deadline_exception_at_start_ss; - BOOST_CHECK_EXCEPTION(json::to_stream( deadline_exception_at_start_ss, variant_list, json_test_util::yield_deadline_exception_at_start), - fc::timeout_exception, - json_test_util::time_except_verf_func); - BOOST_CHECK_EQUAL(deadline_exception_at_start_ss.str().empty(), true); - } - { - std::stringstream deadline_exception_in_mid_ss; - BOOST_CHECK_EXCEPTION(json::to_stream( deadline_exception_in_mid_ss, variant_list, json_test_util::yield_deadline_exception_in_mid), - fc::timeout_exception, - json_test_util::time_except_verf_func); - BOOST_CHECK_EQUAL(deadline_exception_in_mid_ss.str(), - "[\"" + a_list.substr(0, json_test_util::multiple_num(json_test_util::exception_limit_size, json::escape_string_yeild_check_count))); - } - { - std::stringstream length_exception_in_mid_ss; - BOOST_CHECK_EXCEPTION(json::to_stream( length_exception_in_mid_ss, variant_list, json_test_util::yield_length_exception), - fc::assert_exception, - json_test_util::length_limit_except_verf_func); - BOOST_CHECK_EQUAL(length_exception_in_mid_ss.str(), - "[\"" + a_list.substr(0, json_test_util::multiple_num(json_test_util::exception_limit_size, json::escape_string_yeild_check_count))); - } - { - std::stringstream no_exception_ss; - BOOST_CHECK_NO_THROW(json::to_stream( no_exception_ss, variant_list, json_test_util::yield_no_limitation)); - BOOST_CHECK_EQUAL(no_exception_ss.str(), "[\"" + a_list + "\",\"" + b_list + "\"]"); - } - } - { - // to_stream( ostream& out, const variant_object& v, const yield_function_t& yield, output_formatting format = stringify_large_ints_and_doubles ); - const std::string a_list(json_test_util::repeat_char_num, 'a'); - const std::string b_list(json_test_util::repeat_char_num, 'b'); - const variant_object vo(mutable_variant_object()("a", a_list)("b", b_list)); - BOOST_CHECK_LT(json_test_util::exception_limit_size, a_list.size() + b_list.size()); - { - std::stringstream deadline_exception_at_start_ss; - BOOST_CHECK_EXCEPTION(json::to_stream( deadline_exception_at_start_ss, vo, json_test_util::yield_deadline_exception_at_start), - fc::timeout_exception, - json_test_util::time_except_verf_func); - BOOST_CHECK_EQUAL(deadline_exception_at_start_ss.str().empty(), true); - } - { - std::stringstream deadline_exception_in_mid_ss; - BOOST_CHECK_EXCEPTION(json::to_stream( deadline_exception_in_mid_ss, vo, json_test_util::yield_deadline_exception_in_mid), - fc::timeout_exception, - json_test_util::time_except_verf_func); - BOOST_CHECK_EQUAL(deadline_exception_in_mid_ss.str(), - "{\"a\":\"" + a_list.substr(0, json_test_util::multiple_num(json_test_util::exception_limit_size, json::escape_string_yeild_check_count))); - } - { - std::stringstream length_exception_in_mid_ss; - BOOST_CHECK_EXCEPTION(json::to_stream( length_exception_in_mid_ss, vo, json_test_util::yield_length_exception), - fc::assert_exception, - json_test_util::length_limit_except_verf_func); - BOOST_CHECK_EQUAL(length_exception_in_mid_ss.str(), - "{\"a\":\"" + a_list.substr(0, json_test_util::multiple_num(json_test_util::exception_limit_size, json::escape_string_yeild_check_count))); - } - { - std::stringstream no_exception_ss; - BOOST_CHECK_NO_THROW(json::to_stream( no_exception_ss, vo, json_test_util::yield_no_limitation)); - BOOST_CHECK_EQUAL(no_exception_ss.str(), "{\"a\":\"" + a_list + "\",\"b\":\"" + b_list + "\"}"); - } - } -} - BOOST_AUTO_TEST_CASE(to_string_test) { { // to_string( const variant& v, const fc::time_point& deadline, const uint64_t max_len = max_length_limit, output_formatting format = stringify_large_ints_and_doubles); @@ -366,35 +198,27 @@ BOOST_AUTO_TEST_CASE(to_pretty_string_test) BOOST_AUTO_TEST_CASE(escape_string_test) { - std::stringstream escape_out_str_ss; - fc::escape_string(json_test_util::escape_input_str, escape_out_str_ss, json_test_util::yield_no_limitation); - const auto size_different = escape_out_str_ss.str().size() - json_test_util::escape_input_str.size(); - const auto expected_out_str_size = json_test_util::multiple_num(json_test_util::exception_limit_size, json::escape_string_yeild_check_count) + size_different - 1; + std::string escape_out_str; + escape_out_str = fc::escape_string(json_test_util::escape_input_str, json_test_util::yield_no_limitation); BOOST_CHECK_LT(json_test_util::repeat_char_num, json_test_util::escape_input_str.size()); BOOST_CHECK_LT(json_test_util::escape_input_str.size() - json_test_util::repeat_char_num, json_test_util::exception_limit_size); // by using size_different to calculate expected string { // simulate exceed time exception at the beginning of processing - std::stringstream escape_time_except_begin_ss; - BOOST_CHECK_EXCEPTION(escape_string(json_test_util::escape_input_str, escape_time_except_begin_ss, json_test_util::yield_deadline_exception_at_start), + BOOST_CHECK_EXCEPTION(escape_string(json_test_util::escape_input_str, json_test_util::yield_deadline_exception_at_start), fc::timeout_exception, json_test_util::time_except_verf_func); - BOOST_CHECK_EQUAL(escape_time_except_begin_ss.str(), "\""); } { // simulate exceed time exception in the middle of processing - std::stringstream escape_time_except_mid_ss; - BOOST_CHECK_EXCEPTION(escape_string(json_test_util::escape_input_str, escape_time_except_mid_ss, json_test_util::yield_deadline_exception_in_mid), + BOOST_CHECK_EXCEPTION(escape_string(json_test_util::escape_input_str, json_test_util::yield_deadline_exception_in_mid), fc::timeout_exception, json_test_util::time_except_verf_func); - BOOST_CHECK_EQUAL(escape_time_except_mid_ss.str(), escape_out_str_ss.str().substr(0, expected_out_str_size)); } { // length limitation exception in the middle of processing - std::stringstream length_except_mid_ss; - BOOST_CHECK_EXCEPTION(escape_string(json_test_util::escape_input_str, length_except_mid_ss, json_test_util::yield_length_exception), + BOOST_CHECK_EXCEPTION(escape_string(json_test_util::escape_input_str, json_test_util::yield_length_exception), fc::assert_exception, json_test_util::length_limit_except_verf_func); - BOOST_CHECK_EQUAL(length_except_mid_ss.str(), escape_out_str_ss.str().substr(0, expected_out_str_size)); } } diff --git a/test/static_variant/test_static_variant.cpp b/test/static_variant/test_static_variant.cpp index 14bbd6033..77cbaa7dd 100644 --- a/test/static_variant/test_static_variant.cpp +++ b/test/static_variant/test_static_variant.cpp @@ -1,234 +1,56 @@ #define BOOST_TEST_MODULE static_variant #include - -#include #include - -using namespace fc; - -template -struct comparable_type { - - int value; - - template> - bool operator== (const comparable_type& other ) const { - return value == other.value; - } - - template> - bool operator!= (const comparable_type& other ) const { - return value != other.value; - } - - template> - bool operator< (const comparable_type& other ) const { - return value < other.value; - } - - template> - bool operator<= (const comparable_type& other ) const { - return value <= other.value; - } - - template> - bool operator> (const comparable_type& other ) const { - return value > other.value; - } - - template> - bool operator>= (const comparable_type& other ) const { - return value >= other.value; - } -}; - -template class Op, typename Variant> -std::is_convertible, const Variant&, const Variant&>, bool> variant_has_op_test(int); - -template class Op, typename Variant> -std::false_type variant_has_op_test(...); - -template class Op, typename Variant> -constexpr bool variant_has_op_v = decltype(variant_has_op_test(0))::value; - -using not_comparable = comparable_type<>; -using full_comparable = comparable_type; -using eq_only = comparable_type; -using neq_only = comparable_type; -using lt_only = comparable_type; -using lte_only = comparable_type; -using gt_only = comparable_type; -using gte_only = comparable_type; +#include +#include BOOST_AUTO_TEST_SUITE(static_variant_test_suite) - BOOST_AUTO_TEST_CASE(test_eq) - { - // ensure that the given comparisons are present IFF the types support it - BOOST_REQUIRE(( !variant_has_op_v > )); - BOOST_REQUIRE(( variant_has_op_v > )); - - // ensure that given comparisons are present IFF the ALL types support it - BOOST_REQUIRE(( !variant_has_op_v > )); - BOOST_REQUIRE(( variant_has_op_v > )); - - // ensure the operator returns expected values - BOOST_REQUIRE(( static_variant(full_comparable{1}) == static_variant(full_comparable{1}) )); - BOOST_REQUIRE(( !(static_variant(full_comparable{1}) == static_variant(full_comparable{2})) )); - - // ensure the operator respects binary equivalent but different types - BOOST_REQUIRE(( !(static_variant(full_comparable{1}) == static_variant(eq_only{1})) )); - } - - BOOST_AUTO_TEST_CASE(test_neq) - { - // ensure that the given comparisons are present IFF the types support it - BOOST_REQUIRE(( !variant_has_op_v > )); - BOOST_REQUIRE(( variant_has_op_v > )); - - // ensure that given comparisons are present IFF the ALL types support it - BOOST_REQUIRE(( !variant_has_op_v > )); - BOOST_REQUIRE(( variant_has_op_v > )); - - // ensure the operator returns expected values - BOOST_REQUIRE(( static_variant(full_comparable{1}) != static_variant(full_comparable{2}) )); - BOOST_REQUIRE(( !(static_variant(full_comparable{1}) != static_variant(full_comparable{1})) )); - - // ensure the operator respects binary equivalent but different types - BOOST_REQUIRE(( static_variant(full_comparable{1}) != static_variant(neq_only{1}) )); - } - - BOOST_AUTO_TEST_CASE(test_lt) - { - // ensure that the given comparisons are present IFF the types support it - BOOST_REQUIRE(( !variant_has_op_v > )); - BOOST_REQUIRE(( variant_has_op_v > )); - - // ensure that given comparisons are present IFF the ALL types support it - BOOST_REQUIRE(( !variant_has_op_v > )); - BOOST_REQUIRE(( variant_has_op_v > )); - - // ensure the operator returns expected values - BOOST_REQUIRE(( static_variant(full_comparable{1}) < static_variant(full_comparable{2}) )); - BOOST_REQUIRE(( !(static_variant(full_comparable{1}) < static_variant(full_comparable{1})) )); - BOOST_REQUIRE(( !(static_variant(full_comparable{1}) < static_variant(full_comparable{0})) )); - - // ensure the operator respects binary equivalent but different types - BOOST_REQUIRE(( static_variant(full_comparable{1}) < static_variant(lt_only{1}) )); - BOOST_REQUIRE(( !(static_variant(full_comparable{1}) < static_variant(full_comparable{1})) )); - BOOST_REQUIRE(( !(static_variant(lt_only{1}) < static_variant(full_comparable{1})) )); - } - - BOOST_AUTO_TEST_CASE(test_lte) + BOOST_AUTO_TEST_CASE(to_from_fc_variant) { - // ensure that the given comparisons are present IFF the types support it - BOOST_REQUIRE(( !variant_has_op_v > )); - BOOST_REQUIRE(( variant_has_op_v > )); + using variant_type = std::variant; + auto std_variant_1 = variant_type{false}; + auto fc_variant = fc::variant{}; - // ensure that given comparisons are present IFF the ALL types support it - BOOST_REQUIRE(( !variant_has_op_v > )); - BOOST_REQUIRE(( variant_has_op_v > )); + fc::to_variant(std_variant_1, fc_variant); - // ensure the operator returns expected values - BOOST_REQUIRE(( static_variant(full_comparable{1}) <= static_variant(full_comparable{2}) )); - BOOST_REQUIRE(( static_variant(full_comparable{1}) <= static_variant(full_comparable{1}) )); - BOOST_REQUIRE(( !(static_variant(full_comparable{1}) <= static_variant(full_comparable{0})) )); + auto std_variant_2 = variant_type{}; + fc::from_variant(fc_variant, std_variant_2); - // ensure the operator respects binary equivalent but different types - BOOST_REQUIRE(( static_variant(full_comparable{1}) <= static_variant(lte_only{1}) )); - BOOST_REQUIRE(( static_variant(full_comparable{1}) <= static_variant(full_comparable{1}) )); - BOOST_REQUIRE(( !(static_variant(lte_only{1}) <= static_variant(full_comparable{1})) )); + BOOST_REQUIRE(std_variant_1 == std_variant_2); } - BOOST_AUTO_TEST_CASE(test_gt) + BOOST_AUTO_TEST_CASE(get) { - // ensure that the given comparisons are present IFF the types support it - BOOST_REQUIRE(( !variant_has_op_v > )); - BOOST_REQUIRE(( variant_has_op_v > )); - - // ensure that given comparisons are present IFF the ALL types support it - BOOST_REQUIRE(( !variant_has_op_v > )); - BOOST_REQUIRE(( variant_has_op_v > )); + using variant_type = std::variant; - // ensure the operator returns expected values - BOOST_REQUIRE(( !(static_variant(full_comparable{1}) > static_variant(full_comparable{2})) )); - BOOST_REQUIRE(( !(static_variant(full_comparable{1}) > static_variant(full_comparable{1})) )); - BOOST_REQUIRE(( static_variant(full_comparable{1}) > static_variant(full_comparable{0}) )); + auto v1 = variant_type{std::string{"hello world"}}; + BOOST_CHECK_EXCEPTION(std::get(v1), std::bad_variant_access, [](const auto& e) { return true; }); + auto result1 = std::get(v1); + BOOST_REQUIRE(result1 == std::string{"hello world"}); - // ensure the operator respects binary equivalent but different types - BOOST_REQUIRE(( !(static_variant(full_comparable{1}) > static_variant(gt_only{1})) )); - BOOST_REQUIRE(( !(static_variant(full_comparable{1}) > static_variant(full_comparable{1})) )); - BOOST_REQUIRE(( static_variant(gt_only{1}) > static_variant(full_comparable{1}) )); + const auto v2 = variant_type{std::string{"hello world"}}; + BOOST_CHECK_EXCEPTION(std::get(v2), std::bad_variant_access, [](const auto& e) { return true; }); + const auto result2 = std::get(v2); + BOOST_REQUIRE(result2 == std::string{"hello world"}); } - BOOST_AUTO_TEST_CASE(test_gte) + BOOST_AUTO_TEST_CASE(static_variant_from_index) { - // ensure that the given comparisons are present IFF the types support it - BOOST_REQUIRE(( !variant_has_op_v > )); - BOOST_REQUIRE(( variant_has_op_v > )); + using variant_type = std::variant; + auto v = variant_type{}; - // ensure that given comparisons are present IFF the ALL types support it - BOOST_REQUIRE(( !variant_has_op_v > )); - BOOST_REQUIRE(( variant_has_op_v > )); + BOOST_CHECK_EXCEPTION(fc::from_index(v, 3), fc::assert_exception, [](const auto& e) { return e.code() == fc::assert_exception_code; }); - // ensure the operator returns expected values - BOOST_REQUIRE(( !(static_variant(full_comparable{1}) >= static_variant(full_comparable{2})) )); - BOOST_REQUIRE(( static_variant(full_comparable{1}) >= static_variant(full_comparable{1}) )); - BOOST_REQUIRE(( static_variant(full_comparable{1}) >= static_variant(full_comparable{0}) )); - - // ensure the operator respects binary equivalent but different types - BOOST_REQUIRE(( !(static_variant(full_comparable{1}) >= static_variant(gte_only{1})) )); - BOOST_REQUIRE(( static_variant(full_comparable{1}) >= static_variant(full_comparable{1}) )); - BOOST_REQUIRE(( static_variant(gte_only{1}) >= static_variant(full_comparable{1}) )); + fc::from_index(v, 2); + BOOST_REQUIRE(std::string{} == std::get(v)); } - enum class selected_op { - STRING_LVALUE_REF, - STRING_RVALUE_REF, - STRING_CONST_REF, - VECTOR_LVALUE_REF, - VECTOR_RVALUE_REF, - VECTOR_CONST_REF - }; - - struct test_visitor_type { - selected_op operator()(string&) const { return selected_op::STRING_LVALUE_REF; } - selected_op operator()(string&&) const { return selected_op::STRING_RVALUE_REF; } - selected_op operator()(const string&) const { return selected_op::STRING_CONST_REF; } - - selected_op operator()(std::vector&) const { return selected_op::VECTOR_LVALUE_REF; } - selected_op operator()(std::vector&&) const { return selected_op::VECTOR_RVALUE_REF; } - selected_op operator()(const std::vector&) const { return selected_op::VECTOR_CONST_REF; } - }; - - BOOST_AUTO_TEST_CASE(test_visitor) + BOOST_AUTO_TEST_CASE(static_variant_get_index) { - test_visitor_type visitor; - using var_type = static_variant>; - var_type string_lvalue = string("abcd"); - const var_type string_const_value = string("abcd"); - - BOOST_CHECK(string_lvalue.visit(visitor) == selected_op::STRING_LVALUE_REF); - BOOST_CHECK(var_type(string("abcd")).visit(visitor) == selected_op::STRING_RVALUE_REF); - BOOST_CHECK(string_const_value.visit(visitor) == selected_op::STRING_CONST_REF); - - var_type vector_lvalue = std::vector{}; - const var_type vector_const_value = std::vector{}; - - BOOST_CHECK(vector_lvalue.visit(visitor) == selected_op::VECTOR_LVALUE_REF); - BOOST_CHECK(var_type(std::vector{}).visit(visitor) == selected_op::VECTOR_LVALUE_REF); - BOOST_CHECK(vector_const_value.visit(visitor) == selected_op::VECTOR_CONST_REF); - } - - BOOST_AUTO_TEST_CASE(test_get) { - test_visitor_type visitor; - - using var_type = static_variant>; - var_type lvalue(string("abc")); - const var_type const_value(string("abc")); - - BOOST_CHECK(visitor(lvalue.get()) == selected_op::STRING_LVALUE_REF); - BOOST_CHECK(visitor(const_value.get()) == selected_op::STRING_CONST_REF); - BOOST_CHECK(visitor(var_type(string("abc")).get()) == selected_op::STRING_RVALUE_REF); + using variant_type = std::variant; + BOOST_REQUIRE((fc::get_index() == 0)); + BOOST_REQUIRE((fc::get_index() == 1)); + BOOST_REQUIRE((fc::get_index() == 2)); + BOOST_REQUIRE((fc::get_index() == std::variant_size_v)); // Isn't a type contained in variant. } - BOOST_AUTO_TEST_SUITE_END() diff --git a/test/test_filesystem.cpp b/test/test_filesystem.cpp new file mode 100644 index 000000000..53020171a --- /dev/null +++ b/test/test_filesystem.cpp @@ -0,0 +1,95 @@ +#define BOOST_TEST_MODULE fc_filesystem +#include +#include +#include +#include + +using namespace fc; + +std::string getFileContent(const string& filename) { + string ret; + boost::filesystem::ifstream ifs { filename }; + ifs >> ret; + ifs.close(); + return ret; +} + +BOOST_AUTO_TEST_SUITE(fc_filesystem) + +BOOST_AUTO_TEST_CASE(dir_copy) try { + // 1. check whether dir can be copied when target dir does not exist, + // but not recursively (compatible with 1.73) + + const string src_dir {"/tmp/fc_copy_test_src"}; + if (!fc::exists(src_dir)) { + create_directories(src_dir); + } + + BOOST_CHECK_EQUAL(fc::exists(src_dir), true); + const string test_file_name = "fc_copy_test_file"; + if (!fc::exists(src_dir + "/" + test_file_name)) { + boost::filesystem::ofstream ofs { src_dir + "/" + test_file_name}; + ofs << "This the test of fc system copy \n"; + ofs.close(); + } + BOOST_CHECK_EQUAL(fc::exists(src_dir + "/" + test_file_name), true); + + const string tgt_dir {"/tmp/fc_copy_test_tgt"}; + if (fc::exists(tgt_dir)) { + remove_all(tgt_dir); + } + BOOST_CHECK_EQUAL(fc::exists(tgt_dir), false); + + fc::copy(src_dir, tgt_dir); + BOOST_CHECK_EQUAL(fc::exists(tgt_dir), true); + // check not copied recursively + BOOST_CHECK_EQUAL(fc::exists(tgt_dir + "/" + test_file_name), false); + + // 2. check whether exception be thrown (no overwritten) when target dir does exist, + BOOST_CHECK_EQUAL(fc::exists(tgt_dir), true); + BOOST_CHECK_EXCEPTION(fc::copy(src_dir, tgt_dir), fc::exception, [](const fc::exception& e) { + return e.code() == fc::unspecified_exception_code; + }); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(file_copy) try { + // 1. check whether file can be copied when target file does not exist, + const string src_dir {"/tmp/fc_copy_test_src"}; + if (!fc::exists(src_dir)) { + create_directories(src_dir); + } + + BOOST_CHECK_EQUAL(fc::exists(src_dir), true); + const string test_file_name = "fc_copy_test_file"; + if (!fc::exists(src_dir + "/" + test_file_name)) { + boost::filesystem::ofstream ofs { src_dir + "/" + test_file_name}; + ofs << "This the test of fc system copy \n"; + ofs.close(); + } + BOOST_CHECK_EQUAL(fc::exists(src_dir + "/" + test_file_name), true); + + const string tgt_dir {"/tmp/fc_copy_test_tgt"}; + if (!fc::exists(tgt_dir)) { + fc::copy(src_dir, tgt_dir); + } + BOOST_CHECK_EQUAL(fc::exists(tgt_dir), true); + BOOST_CHECK_EQUAL(fc::exists(tgt_dir + "/" + test_file_name), false); + fc::copy(src_dir + "/" + test_file_name, tgt_dir + "/" + test_file_name); + BOOST_CHECK_EQUAL(fc::exists(tgt_dir + "/" + test_file_name), true); + const string src_file_content = getFileContent(src_dir + "/" + test_file_name); + BOOST_CHECK_EQUAL(src_file_content.empty(), false); + const string tgt_file_content = getFileContent(tgt_dir + "/" + test_file_name); + BOOST_CHECK_EQUAL(src_file_content, tgt_file_content); + + // 2. check whether exception be thrown (no overwritten) when target file does exist, + BOOST_CHECK_EQUAL(fc::exists(tgt_dir + "/" + test_file_name), true); + BOOST_CHECK_EXCEPTION(fc::copy(src_dir + "/" + test_file_name, tgt_dir + "/" + test_file_name), + fc::exception, + [](const fc::exception& e) { + return e.code() == fc::unspecified_exception_code; + }); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/vendor/websocketpp/.gitignore b/vendor/websocketpp/.gitignore deleted file mode 100644 index 1d0c71514..000000000 --- a/vendor/websocketpp/.gitignore +++ /dev/null @@ -1,94 +0,0 @@ -# make .git* files visible to git -!.gitignore -!.gitattributes - -.DS_Store - -#vim stuff -*~ -*.swp - -*.o -*.so -*.so.? -*.so.?.?.? -*.a -*.dylib -lib/* - -# CMake -*.cmake -*.dir -CMakeFiles -INSTALL.* -ZERO_CHECK.* -CMakeCache.txt -install_manifest.txt - -# Windows/Visual Studio -*.vcproj* -*.sln -*.suo -*.ncb -*/Debug/* -*/*/Debug/* -bin/Debug -*/Release/* -*/*/Release/* -*/RelWithDebInfo/* -*/*/RelWithDebInfo/* - -# explicitly allow this path with /debug/ in it -!websocketpp/transport/debug/* - -objs_shared/ -objs_static/ - -examples/chat_server/chat_server -examples/echo_server/echo_server -examples/chat_client/chat_client -examples/echo_client/echo_client -test/basic/tests -libwebsocketpp.dylib.0.1.0 - -websocketpp.xcodeproj/xcuserdata/* -websocketpp.xcodeproj/project.xcworkspace/xcuserdata/* -policy_based_notes.hpp - -examples/echo_server_tls/echo_server_tls - -examples/fuzzing_client/fuzzing_client - -examples/stress_client/stress_client - -examples/broadcast_server_tls/broadcast_server - -test/basic/perf - -examples/echo_server_tls/echo_server_tls - -examples/concurrent_server/concurrent_server - -examples/fuzzing_server_tls/fuzzing_server - -examples/wsperf/wsperf - -.sconsign.dblite - -build/ -doxygen/ -examples/wsperf/wsperf_client - -*.out - -*.log -*.opensdf -*.sdf -*.vcxproj -*.vcxproj.filters -*.user -install -Makefile -bin - -Testing/Temporary/CTestCostData.txt diff --git a/vendor/websocketpp/.travis.yml b/vendor/websocketpp/.travis.yml deleted file mode 100644 index a2aa97050..000000000 --- a/vendor/websocketpp/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: cpp -compiler: - - gcc -before_install: - #- sudo apt-get install libboost-chrono1.48-dev libboost-regex1.48-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y - - sudo add-apt-repository -y ppa:boost-latest/ppa && sudo apt-get update -q && sudo apt-get install -y libboost-chrono1.55-dev libboost-random1.55-dev libboost-regex1.55-dev libboost-system1.55-dev libboost-thread1.55-dev libboost-test1.55-dev -env: - global: - - BOOST_INCLUDES=/usr/include - - BOOST_LIBS=/usr/lib/x86_64-linux-gnu -script: scons -j 2 && scons test -branches: - only: - - master - - develop -notifications: - recipients: - - travis@zaphoyd.com - email: - on_success: change - on_failure: always diff --git a/vendor/websocketpp/CMakeLists.txt b/vendor/websocketpp/CMakeLists.txt deleted file mode 100644 index f60caa1dc..000000000 --- a/vendor/websocketpp/CMakeLists.txt +++ /dev/null @@ -1,261 +0,0 @@ - -############ Setup project and cmake - -# Project name -project (websocketpp) - -# Minimum cmake requirement. We should require a quite recent -# cmake for the dependency find macros etc. to be up to date. -cmake_minimum_required (VERSION 2.6) - -set (WEBSOCKETPP_MAJOR_VERSION 0) -set (WEBSOCKETPP_MINOR_VERSION 7) -set (WEBSOCKETPP_PATCH_VERSION 0) -set (WEBSOCKETPP_VERSION ${WEBSOCKETPP_MAJOR_VERSION}.${WEBSOCKETPP_MINOR_VERSION}.${WEBSOCKETPP_PATCH_VERSION}) - -set_property(GLOBAL PROPERTY USE_FOLDERS ON) - -set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files") -if (WIN32 AND NOT CYGWIN) - set (DEF_INSTALL_CMAKE_DIR cmake) -else () - set (DEF_INSTALL_CMAKE_DIR lib/cmake/websocketpp) -endif () -set (INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") - -# Make relative paths absolute (needed later on) -foreach (p INCLUDE CMAKE) - set (var INSTALL_${p}_DIR) - if (NOT IS_ABSOLUTE "${${var}}") - set (${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") - endif () -endforeach () - -# Set CMake library search policy -if (COMMAND cmake_policy) - cmake_policy (SET CMP0003 NEW) - cmake_policy (SET CMP0005 NEW) -endif () - -# Disable unnecessary build types -set (CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo;Debug" CACHE STRING "Configurations" FORCE) - -# Include our cmake macros -set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) -include (CMakeHelpers) - -############ Paths - -set (WEBSOCKETPP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) -set (WEBSOCKETPP_INCLUDE ${WEBSOCKETPP_ROOT}/websocketpp) -set (WEBSOCKETPP_BUILD_ROOT ${CMAKE_CURRENT_BINARY_DIR}) -set (WEBSOCKETPP_BIN ${WEBSOCKETPP_BUILD_ROOT}/bin) -set (WEBSOCKETPP_LIB ${WEBSOCKETPP_BUILD_ROOT}/lib) - -# CMake install step prefix. I assume linux users want the prefix to -# be the default /usr or /usr/local so this is only adjusted on Windows. -# - Windows: Build the INSTALL project in your solution file. -# - Linux/OSX: make install. -if (MSVC) - set (CMAKE_INSTALL_PREFIX "${WEBSOCKETPP_ROOT}/install") -endif () - -############ Build customization - -# Override from command line "CMake -D