├── tests ├── rpc.cpp ├── all_tests.cpp ├── sleep.cpp ├── crypto │ ├── rand_test.cpp │ ├── ecc-interop.sh │ ├── array_initialization_test.cpp │ ├── bigint_test.cpp │ ├── aes_test.cpp │ └── base_n_tests.cpp ├── ws_test_server.cpp ├── ws_test_client.cpp ├── run-parallel-tests.sh ├── io │ └── tcp_test.cpp ├── compress │ └── compress.cpp ├── rate_limiting.cpp ├── CMakeLists.txt ├── stacktrace_test.cpp ├── utf8_test.cpp ├── logging_tests.cpp ├── network │ └── ip_tests.cpp └── bloom_test.cpp ├── include └── fc │ ├── compress │ └── zlib.hpp │ ├── network │ ├── resolve.hpp │ ├── tcp_socket_io_hooks.hpp │ ├── rate_limiting.hpp │ ├── udp_socket.hpp │ ├── http │ │ └── connection.hpp │ ├── tcp_socket.hpp │ └── url.hpp │ ├── crypto │ ├── rand.hpp │ ├── digest.hpp │ ├── base58.hpp │ ├── hex.hpp │ ├── base64.hpp │ ├── dh.hpp │ ├── hmac.hpp │ ├── aes.hpp │ ├── openssl.hpp │ ├── bigint.hpp │ ├── sha512.hpp │ ├── sha1.hpp │ ├── city.hpp │ ├── sha224.hpp │ ├── sha256.hpp │ └── ripemd160.hpp │ ├── git_revision.hpp │ ├── thread │ ├── scoped_lock.hpp │ ├── priority.hpp │ ├── spin_lock.hpp │ ├── spin_yield_lock.hpp │ ├── non_preemptable_scope_check.hpp │ ├── unique_lock.hpp │ └── thread_specific.hpp │ ├── interprocess │ ├── signals.hpp │ └── file_mapping.hpp │ ├── platform_independence.hpp │ ├── config.hpp │ ├── fwd.hpp │ ├── utf8.hpp │ ├── io │ ├── sstream.hpp │ ├── stdio.hpp │ ├── fstream.hpp │ ├── buffered_iostream.hpp │ ├── varint.hpp │ ├── enum_type.hpp │ └── datastream.hpp │ ├── log │ ├── gelf_appender.hpp │ ├── file_appender.hpp │ ├── appender.hpp │ ├── logger_config.hpp │ └── console_appender.hpp │ ├── string.hpp │ ├── rpc │ ├── websocket_api.hpp │ ├── cli.hpp │ └── state.hpp │ ├── container │ └── flat_fwd.hpp │ ├── stacktrace.hpp │ ├── popcount.hpp │ ├── signals.hpp │ └── uint128.hpp ├── src ├── crypto │ ├── _digest_common.hpp │ ├── rand.cpp │ ├── _elliptic_impl_priv.hpp │ ├── _elliptic_impl_pub.hpp │ ├── hex.cpp │ ├── _digest_common.cpp │ ├── sha1.cpp │ ├── openssl.cpp │ ├── sha224.cpp │ └── elliptic_impl_priv.cpp ├── io │ ├── varint.cpp │ ├── datastream.cpp │ └── sstream.cpp ├── git_revision.cpp.in ├── utf8 │ └── ReleaseNotes ├── compress │ └── zlib.cpp ├── thread │ ├── non_preemptable_scope_check.cpp │ ├── spin_lock.cpp │ ├── spin_yield_lock.cpp │ └── thread_specific.cpp ├── static_variant.cpp ├── network │ └── resolve.cpp ├── interprocess │ ├── signals.cpp │ └── file_mapping.cpp ├── utf8.cpp ├── log │ ├── appender.cpp │ └── logger_config.cpp ├── popcount.cpp ├── stacktrace.cpp └── rpc │ └── state.cpp ├── .gitmodules ├── .gitignore ├── CMakeModules ├── Boost │ └── BoostConfig.cmake └── CheckLibcxxAtomic.cmake ├── licenses ├── ZLIB_LICENSE.md ├── MIT_variant_LICENSE.md ├── MIT_X11_LICENSE.md ├── MIT_Thrift_LICENSE.md └── Boost_License-1.0.txt ├── sonar-project.properties ├── GitVersionGen └── GetGitRevisionDescription.cmake.in ├── README.md ├── README-ecc.md ├── .github └── workflows │ ├── build-and-test-macos.yml │ ├── build-and-test-ubuntu-debug.yml │ └── build-and-test-ubuntu-release.yml ├── .travis.yml ├── CONTRIBUTORS.txt └── fc.natvis /tests/rpc.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | int main( int argc, char** argv ) 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /tests/all_tests.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE AllTests 2 | #include 3 | 4 | -------------------------------------------------------------------------------- /include/fc/compress/zlib.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace fc 6 | { 7 | 8 | std::string zlib_compress(const std::string& in); 9 | 10 | } // namespace fc 11 | -------------------------------------------------------------------------------- /include/fc/network/resolve.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace fc 5 | { 6 | std::vector resolve( const std::string& host, uint16_t port ); 7 | } 8 | -------------------------------------------------------------------------------- /include/fc/crypto/rand.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace fc { 4 | 5 | /* provides access to the OpenSSL random number generator */ 6 | void rand_bytes(char* buf, int count); 7 | } // namespace fc 8 | -------------------------------------------------------------------------------- /include/fc/git_revision.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace fc { 5 | 6 | extern const char* const git_revision_sha; 7 | extern const uint32_t git_revision_unix_timestamp; 8 | 9 | } // end namespace fc 10 | -------------------------------------------------------------------------------- /src/crypto/_digest_common.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* Common stuff for cryptographic hashes 4 | */ 5 | namespace fc { namespace detail { 6 | void shift_l( const char* in, char* out, std::size_t n, unsigned int i); 7 | void shift_r( const char* in, char* out, std::size_t n, unsigned int i); 8 | }} 9 | -------------------------------------------------------------------------------- /include/fc/thread/scoped_lock.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace fc { 4 | template 5 | class scoped_lock { 6 | public: 7 | scoped_lock( T& l ):_lock(l) { _lock.lock(); } 8 | ~scoped_lock() { _lock.unlock(); } 9 | T& _lock; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/io/varint.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace fc 5 | { 6 | void to_variant( const unsigned_int& var, variant& vo, uint32_t max_depth ) { vo = var.value; } 7 | void from_variant( const variant& var, unsigned_int& vo, uint32_t max_depth ) { vo.value = var.as_uint64(); } 8 | } 9 | -------------------------------------------------------------------------------- /include/fc/crypto/digest.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace fc { 7 | 8 | template 9 | fc::sha256 digest( const T& value ) 10 | { 11 | fc::sha256::encoder enc; 12 | fc::raw::pack( enc, value ); 13 | return enc.result(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/io/datastream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | [[noreturn]] void fc::detail::throw_datastream_range_error(char const* method, size_t len, int64_t over) 5 | { 6 | FC_THROW_EXCEPTION( out_of_range_exception, "${method} datastream of length ${len} over by ${over}", ("method",std::string(method))("len",len)("over",over) ); 7 | } 8 | -------------------------------------------------------------------------------- /tests/sleep.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main( int argc, char** argv ) 5 | { 6 | fc::thread test("test"); 7 | auto result = test.async( [=]() { 8 | while( true ) 9 | { 10 | fc::usleep( fc::microseconds(1000) ); 11 | } 12 | }); 13 | char c; 14 | std::cin >> c; 15 | test.quit(); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /src/git_revision.cpp.in: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define FC_GIT_REVISION_SHA "@FC_GIT_REVISION_SHA@" 4 | #define FC_GIT_REVISION_UNIX_TIMESTAMP @FC_GIT_REVISION_UNIX_TIMESTAMP@ 5 | 6 | namespace fc { 7 | 8 | const char* const git_revision_sha = FC_GIT_REVISION_SHA; 9 | const uint32_t git_revision_unix_timestamp = FC_GIT_REVISION_UNIX_TIMESTAMP; 10 | 11 | } // end namespace fc 12 | -------------------------------------------------------------------------------- /include/fc/crypto/base58.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace fc { 6 | std::string to_base58( const char* d, size_t s ); 7 | std::string to_base58( const std::vector& data ); 8 | std::vector from_base58( const std::string& base58_str ); 9 | size_t from_base58( const std::string& base58_str, char* out_data, size_t out_data_len ); 10 | } 11 | -------------------------------------------------------------------------------- /include/fc/crypto/hex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace fc { 7 | uint8_t from_hex( char c ); 8 | std::string to_hex( const char* d, uint32_t s ); 9 | std::string to_hex( const std::vector& data ); 10 | 11 | /** 12 | * @return the number of bytes decoded 13 | */ 14 | size_t from_hex( const std::string& hex_str, char* out_data, size_t out_data_len ); 15 | } 16 | -------------------------------------------------------------------------------- /include/fc/interprocess/signals.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace fc 6 | { 7 | /// Set a handler to process an IPC (inter process communication) signal. 8 | /// Handler will be called from ASIO thread. 9 | /// @return shared pointer to the signal_set that holds the handler 10 | std::shared_ptr set_signal_handler( std::function handler, int signal_num ); 11 | } 12 | -------------------------------------------------------------------------------- /include/fc/crypto/base64.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace fc { 5 | std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len); 6 | inline std::string base64_encode(char const* bytes_to_encode, unsigned int in_len) { return base64_encode( (unsigned char const*)bytes_to_encode, in_len); } 7 | std::string base64_encode( const std::string& enc ); 8 | std::string base64_decode( const std::string& encoded_string); 9 | } // namespace fc 10 | -------------------------------------------------------------------------------- /include/fc/platform_independence.hpp: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #include 3 | #ifdef _M_X64 4 | #define __builtin_popcountll __popcnt64 5 | #else 6 | inline int __builtin_popcountll(unsigned __int64 value) 7 | { 8 | unsigned int lowBits = (unsigned int)value; 9 | int count = __popcnt(lowBits); 10 | unsigned int highBits = (unsigned int)(value >> 32); 11 | count += __popcnt(highBits); 12 | return count; 13 | } 14 | #endif 15 | #endif -------------------------------------------------------------------------------- /include/fc/config.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FC_PACK_MAX_DEPTH 2 | // The maximum level of object nesting is around 20% of this value 3 | #define FC_PACK_MAX_DEPTH 1000 4 | #endif 5 | 6 | #ifndef FC_MAX_LOG_OBJECT_DEPTH 7 | // how many levels of nested objects are displayed in log messages 8 | #define FC_MAX_LOG_OBJECT_DEPTH 200 9 | #endif 10 | 11 | #ifndef FC_MAX_PREALLOC_SIZE 12 | // how many elements will be reserve()d when deserializing vectors 13 | #define FC_MAX_PREALLOC_SIZE (256UL) 14 | #endif 15 | -------------------------------------------------------------------------------- /src/utf8/ReleaseNotes: -------------------------------------------------------------------------------- 1 | utf8 cpp library 2 | Release 2.3.4 3 | 4 | A minor bug fix release. Thanks to all who reported bugs. 5 | 6 | Note: Version 2.3.3 contained a regression, and therefore was removed. 7 | 8 | Changes from version 2.3.2 9 | - Bug fix [39]: checked.h Line 273 and unchecked.h Line 182 have an extra ';' 10 | - Bug fix [36]: replace_invalid() only works with back_inserter 11 | 12 | Files included in the release: utf8.h, core.h, checked.h, unchecked.h, utf8cpp.html, ReleaseNotes 13 | -------------------------------------------------------------------------------- /src/crypto/rand.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | namespace fc { 8 | 9 | void rand_bytes(char* buf, int count) 10 | { 11 | static int init = init_openssl(); 12 | (void)init; 13 | 14 | int result = RAND_bytes((unsigned char*)buf, count); 15 | if (result != 1) 16 | FC_THROW("Error calling OpenSSL's RAND_bytes(): ${code}", ("code", (uint32_t)ERR_get_error())); 17 | } 18 | 19 | } // namespace fc 20 | -------------------------------------------------------------------------------- /src/compress/zlib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "miniz.c" 4 | 5 | namespace fc 6 | { 7 | std::string zlib_compress(const std::string& in) 8 | { 9 | size_t compressed_message_length; 10 | char* compressed_message = (char*)tdefl_compress_mem_to_heap(in.c_str(), in.size(), &compressed_message_length, TDEFL_WRITE_ZLIB_HEADER | TDEFL_DEFAULT_MAX_PROBES); 11 | std::string result(compressed_message, compressed_message_length); 12 | free(compressed_message); 13 | return result; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/diff-match-patch-cpp-stl"] 2 | path = vendor/diff-match-patch-cpp-stl 3 | url = https://github.com/leutloff/diff-match-patch-cpp-stl 4 | [submodule "vendor/secp256k1-zkp"] 5 | path = vendor/secp256k1-zkp 6 | url = https://github.com/bitshares/secp256k1-zkp.git 7 | [submodule "vendor/websocketpp"] 8 | path = vendor/websocketpp 9 | url = https://github.com/bitshares/websocketpp.git 10 | [submodule "vendor/editline"] 11 | path = vendor/editline 12 | url = https://github.com/troglobit/editline.git 13 | -------------------------------------------------------------------------------- /src/thread/non_preemptable_scope_check.cpp: -------------------------------------------------------------------------------- 1 | #ifndef NDEBUG 2 | #include 3 | #include 4 | #include "thread_d.hpp" 5 | 6 | 7 | namespace fc 8 | { 9 | non_preemptable_scope_check::non_preemptable_scope_check() 10 | { 11 | ++thread::current().my->non_preemptable_scope_count; 12 | } 13 | 14 | non_preemptable_scope_check::~non_preemptable_scope_check() 15 | { 16 | assert(thread::current().my->non_preemptable_scope_count > 0); 17 | --thread::current().my->non_preemptable_scope_count; 18 | } 19 | } // fc 20 | #endif -------------------------------------------------------------------------------- /src/static_variant.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | namespace fc { namespace impl { 5 | 6 | dynamic_storage::dynamic_storage() : storage(nullptr) {}; 7 | 8 | dynamic_storage::~dynamic_storage() 9 | { 10 | release(); 11 | } 12 | 13 | void* dynamic_storage::data() const 14 | { 15 | FC_ASSERT( storage != nullptr ); 16 | return (void*)storage; 17 | } 18 | 19 | void dynamic_storage::alloc( size_t size ) 20 | { 21 | release(); 22 | storage = new char[size]; 23 | } 24 | 25 | void dynamic_storage::release() 26 | { 27 | delete [] storage; 28 | storage = nullptr; 29 | } 30 | 31 | }} 32 | -------------------------------------------------------------------------------- /src/crypto/_elliptic_impl_priv.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | /* private_key_impl based on libsecp256k1 5 | * used by mixed + secp256k1 6 | */ 7 | 8 | namespace fc { namespace ecc { namespace detail { 9 | 10 | 11 | const secp256k1_context_t* _get_context(); 12 | void _init_lib(); 13 | 14 | class private_key_impl 15 | { 16 | public: 17 | private_key_impl() BOOST_NOEXCEPT; 18 | private_key_impl( const private_key_impl& cpy ) BOOST_NOEXCEPT; 19 | 20 | private_key_impl& operator=( const private_key_impl& pk ) BOOST_NOEXCEPT; 21 | 22 | private_key_secret _key; 23 | }; 24 | 25 | }}} 26 | -------------------------------------------------------------------------------- /src/network/resolve.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace fc 6 | { 7 | std::vector resolve( const std::string& host, uint16_t port ) 8 | { 9 | auto ep = fc::asio::tcp::resolve( host, std::to_string(uint64_t(port)) ); 10 | std::vector eps; 11 | eps.reserve(ep.size()); 12 | for( auto itr = ep.begin(); itr != ep.end(); ++itr ) 13 | { 14 | if( itr->address().is_v4() ) 15 | { 16 | eps.push_back( fc::ip::endpoint(itr->address().to_v4().to_ulong(), itr->port()) ); 17 | } 18 | // TODO: add support for v6 19 | } 20 | return eps; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | *.dll 11 | 12 | # Compiled Static libraries 13 | *.lai 14 | *.la 15 | *.a 16 | *.lib 17 | 18 | # CMake->MSVC artifacts 19 | *.sln 20 | *.vcxproj 21 | ALL_BUILD 22 | ZERO_CHECK 23 | 24 | # MSVC secondary artifacts 25 | *.suo 26 | *.vcxproj.filters 27 | *.vcxproj.user 28 | *.pdb 29 | *.ilk 30 | *.lastbuildstate 31 | *.sdf 32 | *.opensdf 33 | Debug/ 34 | Release/ 35 | 36 | CMakeCache.txt 37 | CMakeFiles 38 | Makefile 39 | cmake_install.cmake 40 | *.cbp 41 | 42 | libfc.a 43 | libfc_debug.a 44 | 45 | *.sw* 46 | 47 | fc_automoc.cpp 48 | git_revision.cpp 49 | GitSHA3.cpp 50 | 51 | task_cancel_test 52 | -------------------------------------------------------------------------------- /include/fc/network/tcp_socket_io_hooks.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace fc 5 | { 6 | class tcp_socket_io_hooks 7 | { 8 | public: 9 | virtual ~tcp_socket_io_hooks() {} 10 | virtual size_t readsome(boost::asio::ip::tcp::socket& socket, char* buffer, size_t length) = 0; 11 | virtual size_t readsome(boost::asio::ip::tcp::socket& socket, const std::shared_ptr& buffer, size_t length, size_t offset) = 0; 12 | virtual size_t writesome(boost::asio::ip::tcp::socket& socket, const char* buffer, size_t length) = 0; 13 | virtual size_t writesome(boost::asio::ip::tcp::socket& socket, const std::shared_ptr& buffer, size_t length, size_t offset) = 0; 14 | }; 15 | } // namesapce fc 16 | -------------------------------------------------------------------------------- /src/interprocess/signals.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace fc 5 | { 6 | std::shared_ptr set_signal_handler( std::function handler, int signal_num ) 7 | { 8 | std::shared_ptr sig_set( new boost::asio::signal_set( fc::asio::default_io_service(), 9 | signal_num) ); 10 | sig_set->async_wait( [sig_set,handler]( const boost::system::error_code& err, int num ) 11 | { 12 | if( err != boost::asio::error::operation_aborted ) 13 | handler( num ); 14 | sig_set->cancel(); 15 | } ); 16 | return sig_set; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /include/fc/thread/priority.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _FC_PRIORITY_HPP_ 2 | #define _FC_PRIORITY_HPP_ 3 | 4 | namespace fc { 5 | /** 6 | * An integer value used to sort asynchronous tasks. The higher the 7 | * prioirty the sooner it will be run. 8 | */ 9 | class priority { 10 | public: 11 | explicit priority( int v = 0):value(v){} 12 | priority( const priority& p ):value(p.value){} 13 | bool operator < ( const priority& p )const { 14 | return value < p.value; 15 | } 16 | static priority max() { return priority(10000); } 17 | static priority min() { return priority(-10000); } 18 | static priority _internal__priority_for_short_sleeps() { return priority(-100000); } 19 | int value; 20 | }; 21 | } 22 | #endif // _FC_PRIORITY_HPP_ 23 | -------------------------------------------------------------------------------- /include/fc/crypto/dh.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace fc { 7 | 8 | struct diffie_hellman { 9 | diffie_hellman():valid(0),g(5){ fc::init_openssl(); } 10 | bool generate_params( int s, uint8_t g ); 11 | bool generate_pub_key(); 12 | bool compute_shared_key( const char* buf, uint32_t s ); 13 | bool compute_shared_key( const std::vector& pubk); 14 | bool validate(); 15 | 16 | std::vector p; 17 | std::vector pub_key; 18 | std::vector priv_key; 19 | std::vector shared_key; 20 | bool valid; 21 | uint8_t g; 22 | }; 23 | 24 | } // namespace fc 25 | 26 | 27 | -------------------------------------------------------------------------------- /CMakeModules/Boost/BoostConfig.cmake: -------------------------------------------------------------------------------- 1 | # This overrides `find_package(Boost ... CONFIG ... )` calls 2 | # - calls the CMake's built-in `FindBoost.cmake` and adds `pthread` library dependency 3 | 4 | MESSAGE(STATUS "Using custom FindBoost config") 5 | 6 | find_package(Boost 1.58 REQUIRED COMPONENTS ${Boost_FIND_COMPONENTS}) 7 | 8 | # Inject `pthread` dependency to Boost if needed 9 | if (UNIX AND NOT CYGWIN) 10 | list(FIND Boost_FIND_COMPONENTS thread _using_boost_thread) 11 | if (_using_boost_thread GREATER -1) 12 | find_library(BOOST_THREAD_LIBRARY NAMES pthread DOC "The threading library used by boost-thread") 13 | if (BOOST_THREAD_LIBRARY) 14 | MESSAGE(STATUS "Adding Boost thread lib dependency: ${BOOST_THREAD_LIBRARY}") 15 | list(APPEND Boost_LIBRARIES ${BOOST_THREAD_LIBRARY}) 16 | endif () 17 | endif () 18 | endif () 19 | -------------------------------------------------------------------------------- /licenses/ZLIB_LICENSE.md: -------------------------------------------------------------------------------- 1 | This source code is provided 'as-is', without any express or implied 2 | warranty. In no event will the author be held liable for any damages 3 | arising from the use of this software. 4 | 5 | Permission is granted to anyone to use this software for any purpose, 6 | including commercial applications, and to alter it and redistribute it 7 | freely, subject to the following restrictions: 8 | 9 | 1. The origin of this source code must not be misrepresented; you must not 10 | claim that you wrote the original source code. If you use this source code 11 | in a product, an acknowledgment in the product documentation would be 12 | appreciated but is not required. 13 | 14 | 2. Altered source versions must be plainly marked as such, and must not be 15 | misrepresented as being the original source code. 16 | 17 | 3. This notice may not be removed or altered from any source distribution. 18 | -------------------------------------------------------------------------------- /tests/crypto/rand_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | static void check_randomness( const char* buffer, size_t len ) { 8 | if (len == 0) { return; } 9 | // count bit runs and 0's / 1's 10 | unsigned int zc = 0, oc = 0, rc = 0, last = 2; 11 | for (size_t k = len; k; k--) { 12 | char c = *buffer++; 13 | for (int i = 0; i < 8; i++) { 14 | unsigned int bit = c & 1; 15 | c >>= 1; 16 | if (bit) { oc++; } else { zc++; } 17 | if (bit != last) { rc++; last = bit; } 18 | } 19 | } 20 | BOOST_CHECK_EQUAL( 8*len, zc + oc ); 21 | } 22 | 23 | BOOST_AUTO_TEST_SUITE(fc_crypto) 24 | 25 | BOOST_AUTO_TEST_CASE(rand_test) 26 | { 27 | char buffer[128]; 28 | fc::rand_bytes( buffer, sizeof(buffer) ); 29 | check_randomness( buffer, sizeof(buffer) ); 30 | } 31 | 32 | BOOST_AUTO_TEST_SUITE_END() 33 | -------------------------------------------------------------------------------- /tests/ws_test_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char** argv) 10 | { 11 | // set up logging 12 | fc::appender::ptr ca(new fc::console_appender); 13 | fc::logger l = fc::logger::get("rpc"); 14 | l.add_appender( ca ); 15 | 16 | fc::http::websocket_server server("MyForwardHeaderKey"); 17 | 18 | server.on_connection([&]( const fc::http::websocket_connection_ptr& c ){ 19 | c->on_message_handler([&](const std::string& s){ 20 | c->send_message("echo: " + s); 21 | }); 22 | }); 23 | 24 | server.listen( 0 ); 25 | server.start_accept(); 26 | 27 | wlog( "Port: ${port}", ("port", server.get_listening_port()) ); 28 | 29 | while( true ) 30 | { 31 | fc::usleep( fc::microseconds(100) ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /include/fc/fwd.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace fc { 4 | 5 | /** 6 | * @brief Used to forward declare value types. 7 | * 8 | */ 9 | template 10 | class fwd { 11 | public: 12 | template fwd( U&& u ); 13 | template fwd( U&& u, V&& v ); 14 | template fwd( U&& u, V&& v, X&&, Y&& ); 15 | fwd(); 16 | 17 | fwd( const fwd& f ); 18 | fwd( fwd&& f ); 19 | 20 | operator const T&()const; 21 | operator T&(); 22 | 23 | T& operator*(); 24 | const T& operator*()const; 25 | const T* operator->()const; 26 | 27 | T* operator->(); 28 | bool operator !()const; 29 | 30 | template 31 | T& operator = ( U&& u ); 32 | 33 | T& operator = ( fwd&& u ); 34 | T& operator = ( const fwd& u ); 35 | 36 | ~fwd(); 37 | 38 | private: 39 | alignas(Align) char _store[S]; 40 | }; 41 | 42 | 43 | } // namespace fc 44 | 45 | -------------------------------------------------------------------------------- /include/fc/utf8.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __UTF8_HPP 2 | #define __UTF8_HPP 3 | 4 | #include 5 | 6 | // This file contains general purpose utilities related to UTF-8 <-> Unicode conversions 7 | 8 | namespace fc 9 | { 10 | 11 | std::string prune_invalid_utf8( const std::string& str ); 12 | 13 | bool is_utf8( const std::string& str ); 14 | 15 | /** Decodes utf 8 std::string into unicode string. 16 | @param input - input string to be decoded and stored in 'storage' 17 | @param storage - buffer for converted text. Cannot be nullptr. 18 | */ 19 | void decodeUtf8(const std::string& input, std::wstring* storage); 20 | 21 | /** Encodes given wide (unicode) string into UTF-8 representation. 22 | @param input - input string to be encoded and stored in 'storage' 23 | @param storage - buffer for converted text. Cannot be nullptr. 24 | */ 25 | void encodeUtf8(const std::wstring& input, std::string* storage); 26 | 27 | } /// namespace fc 28 | 29 | #endif ///__UTF8_HPP 30 | 31 | -------------------------------------------------------------------------------- /include/fc/io/sstream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace fc { 6 | 7 | class stringstream : virtual public iostream { 8 | public: 9 | stringstream(); 10 | stringstream( std::string& s); 11 | stringstream( const std::string& s); 12 | ~stringstream(); 13 | 14 | std::string str(); 15 | void str(const std::string& s); 16 | 17 | void clear(); 18 | 19 | virtual bool eof()const; 20 | virtual size_t writesome( const char* buf, size_t len ); 21 | virtual size_t writesome( const std::shared_ptr& buf, size_t len, size_t offset ); 22 | virtual size_t readsome( char* buf, size_t len ); 23 | virtual size_t readsome( const std::shared_ptr& buf, size_t len, size_t offset ); 24 | virtual void close(); 25 | virtual void flush(); 26 | char peek(); 27 | 28 | private: 29 | class impl; 30 | fwd my; 31 | }; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /include/fc/log/gelf_appender.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace fc 8 | { 9 | // Log appender that sends log messages in JSON format over UDP 10 | // https://www.graylog2.org/resources/gelf/specification 11 | class gelf_appender : public appender 12 | { 13 | public: 14 | struct config 15 | { 16 | string endpoint = "127.0.0.1:12201"; 17 | string host = "fc"; // the name of the host, source or application that sent this message (just passed through to GELF server) 18 | uint32_t max_object_depth = FC_MAX_LOG_OBJECT_DEPTH; 19 | }; 20 | 21 | gelf_appender(const variant& args); 22 | ~gelf_appender(); 23 | virtual void log(const log_message& m) override; 24 | 25 | private: 26 | class impl; 27 | std::unique_ptr my; 28 | }; 29 | } // namespace fc 30 | 31 | #include 32 | FC_REFLECT(fc::gelf_appender::config, 33 | (endpoint)(host)(max_object_depth)) 34 | -------------------------------------------------------------------------------- /src/crypto/_elliptic_impl_pub.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | /* public_key_impl implementation based on openssl 6 | * used by mixed + openssl 7 | */ 8 | 9 | namespace fc { namespace ecc { namespace detail { 10 | 11 | void _init_lib(); 12 | 13 | class public_key_impl 14 | { 15 | public: 16 | public_key_impl() BOOST_NOEXCEPT; 17 | public_key_impl( const public_key_impl& cpy ) BOOST_NOEXCEPT; 18 | public_key_impl( public_key_impl&& cpy ) BOOST_NOEXCEPT; 19 | ~public_key_impl() BOOST_NOEXCEPT; 20 | 21 | public_key_impl& operator=( const public_key_impl& pk ) BOOST_NOEXCEPT; 22 | 23 | public_key_impl& operator=( public_key_impl&& pk ) BOOST_NOEXCEPT; 24 | 25 | static int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check); 26 | 27 | EC_KEY* _key = nullptr; 28 | 29 | private: 30 | void free_key() BOOST_NOEXCEPT; 31 | }; 32 | 33 | }}} 34 | -------------------------------------------------------------------------------- /licenses/MIT_variant_LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013 Kenneth Micklas 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. 8 | -------------------------------------------------------------------------------- /licenses/MIT_X11_LICENSE.md: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in 9 | all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.organization=bitshares-on-github 2 | 3 | sonar.projectKey=bitshares_bitshares-fc 4 | sonar.projectName=BitShares-FC 5 | sonar.projectDescription=Fast-compiling C++ library 6 | 7 | sonar.host.url=https://sonarcloud.io 8 | 9 | sonar.links.homepage=https://bitshares.org 10 | sonar.links.ci=https://github.com/bitshares/bitshares-fc/actions 11 | sonar.links.issue=https://github.com/bitshares/bitshares-core/issues 12 | sonar.links.scm=https://github.com/bitshares/bitshares-fc/tree/master 13 | 14 | # Note: 15 | # According to docs, sonar.tests is ignored by the C/C++/Objective-C analyzer. 16 | # See https://docs.sonarcloud.io/advanced-setup/languages/c-c-objective-c/#language-specific-properties 17 | sonar.tests=tests 18 | 19 | sonar.exclusions=vendor/**/*,tests/**/* 20 | sonar.sources=src,include 21 | sonar.cfamily.build-wrapper-output=bw-output 22 | 23 | # Note: 24 | # It is hard to get the gcov sensor working, but gcovr works. 25 | # See https://community.sonarsource.com/t/code-coverage-incorrect-for-c-gcov-project/41837/5 26 | #sonar.cfamily.gcov.reportsPath=. 27 | sonar.coverageReportPaths=coverage.xml 28 | -------------------------------------------------------------------------------- /include/fc/interprocess/file_mapping.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace boost { 7 | namespace interprocess { 8 | class file_mapping; 9 | class mapped_region; 10 | } 11 | } 12 | namespace fc { 13 | enum mode_t { 14 | read_only, 15 | write_only, 16 | read_write 17 | }; 18 | 19 | class file_mapping { 20 | public: 21 | file_mapping( const char* file, mode_t ); 22 | ~file_mapping(); 23 | private: 24 | friend class mapped_region; 25 | #ifdef _WIN64 26 | fc::fwd my; 27 | #else 28 | fc::fwd my; 29 | #endif 30 | }; 31 | 32 | class mapped_region { 33 | public: 34 | mapped_region( const file_mapping& fm, mode_t m, uint64_t start, size_t size ); 35 | mapped_region( const file_mapping& fm, mode_t m ); 36 | ~mapped_region(); 37 | void flush(); 38 | void* get_address()const; 39 | size_t get_size()const; 40 | private: 41 | fc::fwd my; 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /tests/crypto/ecc-interop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #TIME=time 4 | 5 | cd "`dirname $0`"/.. 6 | 7 | echo Building ecc_test with openssl... 8 | ( 9 | cmake -D ECC_IMPL=openssl . 10 | make ecc_test 11 | mv ecc_test ecc_test.openssl 12 | ) >/dev/null 2>&1 13 | 14 | echo Building ecc_test with secp256k1... 15 | ( 16 | cmake -D ECC_IMPL=secp256k1 . 17 | make ecc_test 18 | mv ecc_test ecc_test.secp256k1 19 | ) >/dev/null 2>&1 20 | 21 | echo Building ecc_test with mixed... 22 | ( 23 | cmake -D ECC_IMPL=mixed . 24 | make ecc_test 25 | mv ecc_test ecc_test.mixed 26 | ) >/dev/null 2>&1 27 | 28 | run () { 29 | echo "Running ecc_test.$1 test ecc.interop.$2 ..." 30 | $TIME "./ecc_test.$1" test "ecc.interop.$2" 31 | } 32 | 33 | run openssl openssl 34 | run openssl openssl 35 | run secp256k1 secp256k1 36 | run secp256k1 secp256k1 37 | run mixed mixed 38 | run mixed mixed 39 | run openssl secp256k1 40 | run openssl mixed 41 | run secp256k1 openssl 42 | run secp256k1 mixed 43 | run mixed openssl 44 | run mixed secp256k1 45 | 46 | echo Done. 47 | 48 | rm -f ecc_test.openssl ecc_test.secp256k1 ecc_test.mixed ecc.interop.openssl ecc.interop.secp256k1 ecc.interop.mixed 49 | -------------------------------------------------------------------------------- /include/fc/thread/spin_lock.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace fc { 4 | class microseconds; 5 | class time_point; 6 | 7 | /** 8 | * @class spin_lock 9 | * @brief modified spin-lock that yields on failure, but becomes a 'spin lock' 10 | * if there are no other tasks to yield to. 11 | * 12 | * This kind of lock is lighter weight than a full mutex, but potentially slower 13 | * than a staight spin_lock. 14 | * 15 | * This spin_lock does not block the current thread, but instead attempts to use 16 | * an atomic operation to aquire the lock. If unsuccessful, then it yields to 17 | * other tasks before trying again. If there are no other tasks then yield is 18 | * a no-op and spin_lock becomes a spin-lock. 19 | */ 20 | class spin_lock { 21 | public: 22 | spin_lock(); 23 | bool try_lock(); 24 | bool try_lock_for( const microseconds& rel_time ); 25 | bool try_lock_until( const time_point& abs_time ); 26 | void lock(); 27 | void unlock(); 28 | 29 | private: 30 | enum lock_store {locked,unlocked}; 31 | int _lock; 32 | }; 33 | 34 | } // namespace fc 35 | 36 | -------------------------------------------------------------------------------- /include/fc/thread/spin_yield_lock.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace fc { 4 | class microseconds; 5 | class time_point; 6 | 7 | /** 8 | * @class spin_yield_lock 9 | * @brief modified spin-lock that yields on failure, but becomes a 'spin lock' 10 | * if there are no other tasks to yield to. 11 | * 12 | * This kind of lock is lighter weight than a full mutex, but potentially slower 13 | * than a staight spin_lock. 14 | * 15 | * This spin_yield_lock does not block the current thread, but instead attempts to use 16 | * an atomic operation to aquire the lock. If unsuccessful, then it yields to 17 | * other tasks before trying again. If there are no other tasks then yield is 18 | * a no-op and spin_yield_lock becomes a spin-lock. 19 | */ 20 | class spin_yield_lock { 21 | public: 22 | spin_yield_lock(); 23 | bool try_lock(); 24 | bool try_lock_for( const microseconds& rel_time ); 25 | bool try_lock_until( const time_point& abs_time ); 26 | void lock(); 27 | void unlock(); 28 | 29 | private: 30 | enum lock_store {locked,unlocked}; 31 | int _lock; 32 | }; 33 | 34 | } // namespace fc 35 | 36 | -------------------------------------------------------------------------------- /include/fc/string.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace fc 7 | { 8 | using std::string; 9 | 10 | int64_t to_int64( const std::string& ); 11 | uint64_t to_uint64( const std::string& ); 12 | double to_double( const std::string& ); 13 | std::string to_string( double ); 14 | std::string to_string( uint64_t ); 15 | std::string to_string( int64_t ); 16 | std::string to_string( uint16_t ); 17 | std::string to_pretty_string( int64_t ); 18 | inline std::string to_string( int32_t v ) { return to_string( int64_t(v) ); } 19 | inline std::string to_string( uint32_t v ){ return to_string( uint64_t(v) ); } 20 | #if defined(__APPLE__) or defined(__OpenBSD__) 21 | inline std::string to_string( size_t s) { return to_string(uint64_t(s)); } 22 | #endif 23 | 24 | typedef fc::optional ostring; 25 | class variant_object; 26 | std::string format_string( const std::string&, const variant_object&, uint32_t max_object_depth = 200 ); 27 | std::string trim( const std::string& ); 28 | std::string to_lower( const std::string& ); 29 | string trim_and_normalize_spaces( const string& s ); 30 | 31 | uint64_t parse_size( const string& s ); 32 | } 33 | -------------------------------------------------------------------------------- /src/interprocess/file_mapping.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace fc { 7 | 8 | 9 | file_mapping::file_mapping( const char* file, mode_t m ) : 10 | my(file, m == read_only ? boost::interprocess::read_only : boost::interprocess::read_write ) 11 | {} 12 | 13 | file_mapping::~file_mapping() {} 14 | 15 | 16 | 17 | mapped_region::mapped_region( const file_mapping& fm, mode_t m, uint64_t start, size_t size ) : 18 | my( *fm.my, m == read_only ? boost::interprocess::read_only : boost::interprocess::read_write ,start, size) 19 | {} 20 | 21 | mapped_region::mapped_region( const file_mapping& fm, mode_t m ) : 22 | my( *fm.my, m == read_only ? boost::interprocess::read_only : boost::interprocess::read_write) 23 | {} 24 | 25 | mapped_region::~mapped_region(){} 26 | 27 | void* mapped_region::get_address() const 28 | { 29 | return my->get_address(); 30 | } 31 | 32 | void mapped_region::flush() 33 | { 34 | my->flush(); 35 | } 36 | 37 | size_t mapped_region::get_size() const 38 | { 39 | return my->get_size(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /include/fc/network/rate_limiting.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace fc 9 | { 10 | namespace detail 11 | { 12 | class rate_limiting_group_impl; 13 | } 14 | 15 | class tcp_socket; 16 | 17 | class rate_limiting_group 18 | { 19 | public: 20 | rate_limiting_group(uint32_t upload_bytes_per_second, uint32_t download_bytes_per_second, uint32_t burstiness_in_seconds = 1); 21 | ~rate_limiting_group(); 22 | 23 | void set_upload_limit(uint32_t upload_bytes_per_second); 24 | uint32_t get_upload_limit() const; 25 | 26 | void set_download_limit(uint32_t download_bytes_per_second); 27 | uint32_t get_download_limit() const; 28 | 29 | uint32_t get_actual_upload_rate() const; 30 | uint32_t get_actual_download_rate() const; 31 | void set_actual_rate_time_constant(microseconds time_constant); 32 | 33 | void add_tcp_socket(tcp_socket* tcp_socket_to_limit); 34 | void remove_tcp_socket(tcp_socket* tcp_socket_to_stop_limiting); 35 | private: 36 | std::unique_ptr my; 37 | }; 38 | typedef std::shared_ptr rate_limiting_group_ptr; 39 | 40 | } // namesapce fc 41 | 42 | -------------------------------------------------------------------------------- /include/fc/log/file_appender.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace fc { 9 | 10 | class file_appender : public appender { 11 | public: 12 | struct config { 13 | config( const fc::path& p = "log.txt" ); 14 | 15 | std::string format; 16 | fc::path filename; 17 | bool flush = true; 18 | bool rotate = false; 19 | microseconds rotation_interval; 20 | microseconds rotation_limit; 21 | uint32_t max_object_depth = FC_MAX_LOG_OBJECT_DEPTH; 22 | }; 23 | file_appender( const variant& args ); 24 | ~file_appender(); 25 | virtual void log( const log_message& m )override; 26 | 27 | private: 28 | class impl; 29 | std::unique_ptr my; 30 | }; 31 | } // namespace fc 32 | 33 | #include 34 | FC_REFLECT( fc::file_appender::config, 35 | (format)(filename)(flush)(rotate)(rotation_interval)(rotation_limit)(max_object_depth) ) 36 | -------------------------------------------------------------------------------- /include/fc/io/stdio.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace fc 5 | { 6 | 7 | class cout_t : virtual public ostream { 8 | public: 9 | virtual size_t writesome( const char* buf, size_t len ); 10 | virtual size_t writesome( const std::shared_ptr& buf, size_t len, size_t offset ); 11 | virtual void close(); 12 | virtual void flush(); 13 | }; 14 | 15 | class cerr_t : virtual public ostream { 16 | public: 17 | virtual size_t writesome( const char* buf, size_t len ); 18 | virtual size_t writesome( const std::shared_ptr& buf, size_t len, size_t offset ); 19 | virtual void close(); 20 | virtual void flush(); 21 | }; 22 | 23 | class cin_t : virtual public istream { 24 | public: 25 | ~cin_t(); 26 | virtual size_t readsome( char* buf, size_t len ); 27 | virtual size_t readsome( const std::shared_ptr& buf, size_t len, size_t offset ); 28 | virtual istream& read( char* buf, size_t len ); 29 | virtual bool eof()const; 30 | }; 31 | 32 | extern cout_t& cout; 33 | extern cerr_t& cerr; 34 | extern cin_t& cin; 35 | 36 | extern std::shared_ptr cin_ptr; 37 | extern std::shared_ptr cout_ptr; 38 | extern std::shared_ptr cerr_ptr; 39 | } 40 | -------------------------------------------------------------------------------- /include/fc/rpc/websocket_api.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace fc { namespace rpc { 7 | 8 | class websocket_api_connection : public api_connection 9 | { 10 | public: 11 | websocket_api_connection( const std::shared_ptr &c, 12 | uint32_t max_conversion_depth ); 13 | ~websocket_api_connection(); 14 | 15 | virtual variant send_call( 16 | api_id_type api_id, 17 | string method_name, 18 | variants args = variants() ) override; 19 | virtual variant send_callback( 20 | uint64_t callback_id, 21 | variants args = variants() ) override; 22 | virtual void send_notice( 23 | uint64_t callback_id, 24 | variants args = variants() ) override; 25 | 26 | protected: 27 | response on_message( const std::string& message ); 28 | response on_request( const variant& message ); 29 | void on_response( const variant& message ); 30 | 31 | std::shared_ptr _connection; 32 | fc::rpc::state _rpc_state; 33 | }; 34 | 35 | } } // namespace fc::rpc 36 | -------------------------------------------------------------------------------- /src/thread/spin_lock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace fc { 8 | #define define_self boost::atomic* self = (boost::atomic*)&_lock 9 | spin_lock::spin_lock() 10 | { 11 | define_self; 12 | new (self) boost::atomic(); 13 | static_assert( sizeof(boost::atomic) == sizeof(_lock), "" ); 14 | self->store(unlocked); 15 | } 16 | 17 | bool spin_lock::try_lock() { 18 | define_self; 19 | return self->exchange(locked, boost::memory_order_acquire)!=locked; 20 | } 21 | 22 | bool spin_lock::try_lock_for( const fc::microseconds& us ) { 23 | return try_lock_until( fc::time_point::now() + us ); 24 | } 25 | 26 | bool spin_lock::try_lock_until( const fc::time_point& abs_time ) { 27 | while( abs_time > time_point::now() ) { 28 | if( try_lock() ) 29 | return true; 30 | } 31 | return false; 32 | } 33 | 34 | void spin_lock::lock() { 35 | define_self; 36 | while( self->exchange(locked, boost::memory_order_acquire)==locked) { } 37 | } 38 | 39 | void spin_lock::unlock() { 40 | define_self; 41 | self->store(unlocked, boost::memory_order_release); 42 | } 43 | 44 | #undef define_self 45 | 46 | } // namespace fc 47 | -------------------------------------------------------------------------------- /include/fc/network/udp_socket.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace fc { 5 | namespace ip { 6 | class endpoint; 7 | class address; 8 | } 9 | 10 | /** 11 | * The udp_socket class has reference semantics, all copies will 12 | * refer to the same underlying socket. 13 | */ 14 | class udp_socket { 15 | public: 16 | udp_socket(); 17 | udp_socket( const udp_socket& s ); 18 | ~udp_socket(); 19 | 20 | void open(); 21 | void set_receive_buffer_size( size_t s ); 22 | void bind( const fc::ip::endpoint& ); 23 | size_t receive_from( char* b, size_t l, fc::ip::endpoint& from ); 24 | size_t receive_from( const std::shared_ptr& b, size_t l, fc::ip::endpoint& from ); 25 | size_t send_to( const char* b, size_t l, const fc::ip::endpoint& to ); 26 | size_t send_to( const std::shared_ptr& b, size_t l, const fc::ip::endpoint& to ); 27 | void close(); 28 | 29 | void set_multicast_enable_loopback( bool ); 30 | void set_reuse_address( bool ); 31 | void join_multicast_group( const fc::ip::address& a ); 32 | 33 | void connect( const fc::ip::endpoint& e ); 34 | fc::ip::endpoint local_endpoint()const; 35 | 36 | private: 37 | class impl; 38 | std::shared_ptr my; 39 | }; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /include/fc/thread/non_preemptable_scope_check.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | // This file defines a macro: 6 | // ASSERT_TASK_NOT_PREEMPTED() 7 | // This macro is used to declare that the current scope is not expected to yield. 8 | // If the task does yield, it will generate an assertion. 9 | // 10 | // Use this when you you're coding somethign that must not yield, and you think you 11 | // have done it (just by virtue of the fact that you don't think you've called any 12 | // functions that could yield). This will help detect when your assumptions are 13 | // wrong and you accidentally call something that yields. 14 | // 15 | // This has no cost in release mode, and is extremely cheap in debug mode. 16 | 17 | #define FC_NON_PREEMPTABLE_SCOPE_COMBINE_HELPER(x,y) x ## y 18 | #define FC_NON_PREEMPTABLE_SCOPE_COMBINE(x,y) FC_NON_PREEMPTABLE_SCOPE_COMBINE_HELPER(x,y) 19 | 20 | #ifdef NDEBUG 21 | # define ASSERT_TASK_NOT_PREEMPTED() do {} while (0) 22 | #else 23 | # define ASSERT_TASK_NOT_PREEMPTED() fc::non_preemptable_scope_check FC_NON_PREEMPTABLE_SCOPE_COMBINE(scope_checker_, __LINE__) 24 | 25 | namespace fc 26 | { 27 | class non_preemptable_scope_check 28 | { 29 | public: 30 | non_preemptable_scope_check(); 31 | ~non_preemptable_scope_check(); 32 | }; 33 | } // namespace fc 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /GitVersionGen/GetGitRevisionDescription.cmake.in: -------------------------------------------------------------------------------- 1 | # 2 | # Internal file for GetGitRevisionDescription.cmake 3 | # 4 | # Requires CMake 2.6 or newer (uses the 'function' command) 5 | # 6 | # Original Author: 7 | # 2009-2010 Ryan Pavlik 8 | # http://academic.cleardefinition.com 9 | # Iowa State University HCI Graduate Program/VRAC 10 | # 11 | # Copyright Iowa State University 2009-2010. 12 | # Distributed under the Boost Software License, Version 1.0. 13 | # (See accompanying file LICENSE_1_0.txt or copy at 14 | # http://www.boost.org/LICENSE_1_0.txt) 15 | 16 | set(HEAD_HASH) 17 | 18 | file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) 19 | 20 | string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) 21 | if(HEAD_CONTENTS MATCHES "ref") 22 | # named branch 23 | string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") 24 | if(EXISTS "@GIT_DIR@/${HEAD_REF}") 25 | configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) 26 | elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") 27 | configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) 28 | set(HEAD_HASH "${HEAD_REF}") 29 | endif() 30 | else() 31 | # detached HEAD 32 | configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) 33 | endif() 34 | 35 | if(NOT HEAD_HASH) 36 | file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) 37 | string(STRIP "${HEAD_HASH}" HEAD_HASH) 38 | endif() 39 | -------------------------------------------------------------------------------- /src/utf8.cpp: -------------------------------------------------------------------------------- 1 | #include "fc/utf8.hpp" 2 | 3 | #include "utf8/checked.h" 4 | #include "utf8/core.h" 5 | #include "utf8/unchecked.h" 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace fc { 13 | 14 | bool is_utf8( const std::string& str ) 15 | { 16 | return utf8::is_valid( str.begin(), str.end() ); 17 | } 18 | 19 | string prune_invalid_utf8( const string& str ) { 20 | string result; 21 | 22 | auto itr = utf8::find_invalid(str.begin(), str.end()); 23 | if( itr == str.end() ) return str; 24 | 25 | result = string( str.begin(), itr ); 26 | while( itr != str.end() ) { 27 | ++itr; 28 | auto start = itr; 29 | itr = utf8::find_invalid( start, str.end()); 30 | result += string( start, itr ); 31 | } 32 | return result; 33 | } 34 | 35 | void decodeUtf8(const std::string& input, std::wstring* storage) 36 | { 37 | assert(storage != nullptr); 38 | 39 | utf8::utf8to32(input.begin(), input.end(), std::back_inserter(*storage)); 40 | } 41 | 42 | void encodeUtf8(const std::wstring& input, std::string* storage) 43 | { 44 | assert(storage != nullptr); 45 | 46 | utf8::utf32to8(input.begin(), input.end(), std::back_inserter(*storage)); 47 | } 48 | 49 | } ///namespace fc 50 | 51 | 52 | -------------------------------------------------------------------------------- /licenses/MIT_Thrift_LICENSE.md: -------------------------------------------------------------------------------- 1 | // Copyright 2006 Nemanja Trifunovic 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /licenses/Boost_License-1.0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /include/fc/container/flat_fwd.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace fc { 8 | 9 | using boost::container::flat_map; 10 | using boost::container::flat_set; 11 | namespace bip = boost::interprocess; 12 | 13 | namespace raw { 14 | template 15 | void pack( Stream& s, const flat_set& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); 16 | template 17 | void unpack( Stream& s, flat_set& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); 18 | template 19 | void pack( Stream& s, const flat_map& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); 20 | template 21 | void unpack(Stream& s, flat_map& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); 22 | 23 | 24 | template 25 | void pack( Stream& s, const bip::vector& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); 26 | template 27 | void unpack( Stream& s, bip::vector& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); 28 | } // namespace raw 29 | 30 | } // fc 31 | -------------------------------------------------------------------------------- /include/fc/stacktrace.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 BitShares Blockchain Foundation, and contributors. 3 | * 4 | * The MIT License 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #pragma once 26 | 27 | #include 28 | 29 | namespace fc { 30 | 31 | void print_stacktrace(std::ostream& out); 32 | void print_stacktrace_on_segfault(); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/thread/spin_yield_lock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace fc { 8 | void yield(); 9 | 10 | #define define_self boost::atomic* self = (boost::atomic*)&_lock 11 | 12 | spin_yield_lock::spin_yield_lock() 13 | { 14 | define_self; 15 | new (self) boost::atomic(); 16 | static_assert( sizeof(boost::atomic) == sizeof(_lock), "" ); 17 | self->store(unlocked); 18 | } 19 | 20 | bool spin_yield_lock::try_lock() { 21 | define_self; 22 | return self->exchange(locked, boost::memory_order_acquire)!=locked; 23 | } 24 | 25 | bool spin_yield_lock::try_lock_for( const fc::microseconds& us ) { 26 | return try_lock_until( fc::time_point::now() + us ); 27 | } 28 | 29 | bool spin_yield_lock::try_lock_until( const fc::time_point& abs_time ) { 30 | while( abs_time > time_point::now() ) { 31 | if( try_lock() ) 32 | return true; 33 | yield(); 34 | } 35 | return false; 36 | } 37 | 38 | void spin_yield_lock::lock() { 39 | define_self; 40 | while( self->exchange(locked, boost::memory_order_acquire)==locked) { 41 | yield(); 42 | } 43 | } 44 | 45 | void spin_yield_lock::unlock() { 46 | define_self; 47 | self->store(unlocked, boost::memory_order_release); 48 | } 49 | #undef define_self 50 | 51 | } // namespace fc 52 | -------------------------------------------------------------------------------- /tests/ws_test_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char** argv) 10 | { 11 | try 12 | { 13 | // set up logging 14 | fc::appender::ptr ca(new fc::console_appender); 15 | fc::logger l = fc::logger::get("rpc"); 16 | l.add_appender( ca ); 17 | 18 | fc::http::websocket_client client; 19 | fc::http::websocket_connection_ptr s_conn, c_conn; 20 | std::string url = argv[1]; 21 | wlog( "Connecting to server at url ${url}", ("url", url) ); 22 | c_conn = client.connect( "ws://" + url ); 23 | 24 | std::string echo; 25 | c_conn->on_message_handler([&](const std::string& s){ 26 | echo = s; 27 | }); 28 | c_conn->send_message( "hello world" ); 29 | fc::usleep( fc::milliseconds(500) ); 30 | if (echo != std::string("echo: hello world") ) 31 | wlog( "Test1 failed, echo value: [${echo}]", ("echo", echo) ); 32 | c_conn->send_message( "again" ); 33 | fc::usleep( fc::milliseconds(500) ); 34 | if ("echo: again" != echo) 35 | wlog( "Test2 failed, echo value: [${echo}]", ("echo", echo) ); 36 | } 37 | catch (const websocketpp::exception& ex) 38 | { 39 | elog( "websocketpp::exception thrown: ${err}", ("err", ex.what()) ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /include/fc/thread/unique_lock.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace fc { 5 | struct try_to_lock_t{}; 6 | class time_point; 7 | 8 | /** 9 | * Including Boost's unique lock drastically increases compile times 10 | * for something that is this trivial! 11 | */ 12 | template 13 | class unique_lock { 14 | public: 15 | unique_lock( T& l, const fc::time_point& abs ):_lock(l) { _locked = _lock.try_lock_until(abs); } 16 | unique_lock( T& l, try_to_lock_t ):_lock(l) { _locked = _lock.try_lock(); } 17 | unique_lock( T& l ): _locked(false), _lock(l) { lock(); } 18 | ~unique_lock() { if (_locked) unlock(); } 19 | operator bool() const { return _locked; } 20 | void unlock() { assert(_locked); if (_locked) { _lock.unlock(); _locked = false;} } 21 | void lock() { assert(!_locked); if (!_locked) { _lock.lock(); _locked = true; } } 22 | private: 23 | unique_lock( const unique_lock& ); 24 | unique_lock& operator=( const unique_lock& ); 25 | bool _locked; 26 | T& _lock; 27 | }; 28 | 29 | } 30 | 31 | /** 32 | * Emulate java with the one quirk that the open bracket must come before 33 | * the synchronized 'keyword'. 34 | * 35 | * 36 | { synchronized( lock_type ) 37 | 38 | } 39 | * 40 | */ 41 | #define synchronized(X) fc::unique_lock __lock(((X))); 42 | 43 | -------------------------------------------------------------------------------- /include/fc/log/appender.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace fc { 6 | class appender; 7 | class log_message; 8 | class variant; 9 | 10 | class appender_factory { 11 | public: 12 | typedef std::shared_ptr ptr; 13 | 14 | virtual ~appender_factory(){}; 15 | virtual std::shared_ptr create( const variant& args ) = 0; 16 | }; 17 | 18 | namespace detail { 19 | template 20 | class appender_factory_impl : public appender_factory { 21 | public: 22 | virtual std::shared_ptr create( const variant& args ) { 23 | return std::shared_ptr(new T(args)); 24 | } 25 | }; 26 | } 27 | 28 | class appender { 29 | public: 30 | typedef std::shared_ptr ptr; 31 | 32 | template 33 | static bool register_appender(const std::string& type) { 34 | return register_appender( type, appender_factory::ptr( new detail::appender_factory_impl() ) ); 35 | } 36 | 37 | virtual ~appender() = default; 38 | static appender::ptr create( const std::string& name, const std::string& type, const variant& args ); 39 | static appender::ptr get( const std::string& name ); 40 | static bool register_appender( const std::string& type, const appender_factory::ptr& f ); 41 | 42 | virtual void log( const log_message& m ) = 0; 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /tests/run-parallel-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$#" -lt 1 ]; then 4 | echo "Usage: $0 [arguments]" 1>&2 5 | exit 1 6 | fi 7 | 8 | CACHE="$( find . -name CMakeCache.txt )" 9 | if [ "$CACHE" != "" ]; then 10 | BOOST_INC="$( grep Boost_INCLUDE_DIR:PATH "$CACHE" | cut -d= -f 2 )" 11 | if [ "$BOOST_INC" != "" ]; then 12 | BOOST_VERSION="$( grep '^#define *BOOST_VERSION ' "$BOOST_INC/boost/version.hpp" | sed 's=^.* ==' )" 13 | fi 14 | fi 15 | 16 | if [ "$BOOST_VERSION" = "" -o "$BOOST_VERSION" -lt 105900 ]; then 17 | echo "Boost version '$BOOST_VERSION' - executing tests serially" 18 | "$@" 19 | elif ! command -v parallel >/dev/null 2>&1; then 20 | echo "Can not find the 'parallel' command - executing tests serially" 21 | "$@" 22 | else 23 | echo "=== $1 list_content test begin ===" 24 | "$1" --list_content 2>&1 \ 25 | | grep '\*$' \ 26 | | sed 's=\*$==;s=^ =/=' 27 | echo "=== $1 list_content test end ===" 28 | "$1" --list_content 2>&1 \ 29 | | grep '\*$' \ 30 | | sed 's=\*$==;s=^ =/=' \ 31 | | (while read t; do 32 | case "$t" in 33 | /*) echo "$pre$t"; found=1; ;; 34 | *) if [ -n "$pre" -a "$found" = "0" ]; then 35 | echo "$pre" 36 | fi 37 | pre="$t" 38 | found=0 39 | ;; 40 | esac 41 | done 42 | if [ -n "$pre" -a "$found" = "0" ]; then 43 | echo "$pre" 44 | fi) \ 45 | | parallel echo Running {}\; "$@" -t {} 46 | fi 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FC 2 | == 3 | 4 | Build status: [![](https://github.com/bitshares/bitshares-fc/workflows/macOS/badge.svg?branch=master)](https://github.com/bitshares/bitshares-fc/actions?query=workflow%3A"macOS"+branch%3Amaster) 5 | [![](https://github.com/bitshares/bitshares-fc/workflows/Ubuntu%20Debug/badge.svg?branch=master)](https://github.com/bitshares/bitshares-fc/actions?query=workflow%3A"Ubuntu+Debug"+branch%3Amaster) 6 | [![](https://github.com/bitshares/bitshares-fc/workflows/Ubuntu%20Release/badge.svg?branch=master)](https://github.com/bitshares/bitshares-fc/actions?query=workflow%3A"Ubuntu+Release"+branch%3Amaster) 7 | 8 | **NOTE:** This fork reverts upstream commit a421e280488385cab26a42153f7ce3c8d5b6281f to avoid changing the BitShares API. 9 | 10 | FC stands for fast-compiling c++ library and provides a set of utility libraries useful 11 | for the development of asynchronous libraries. Some of the highlights include: 12 | 13 | - Cooperative Multi-Tasking Library with support for Futures, mutexes, signals. 14 | - Wrapper on Boost ASIO for handling async opperations cooperatively with easy to code synchronous style. 15 | - Reflection for C++ allowing automatic serialization in Json & Binary of C++ Structs 16 | - Automatic generation of client / server stubs for reflected interfaces with support for JSON-RPC 17 | - Cryptographic Primitives for a variaty of hashes and encryption algorithms 18 | - Logging Infrastructure 19 | - Wraps many Boost APIs, such as boost::filesystem, boost::thread, and boost::exception to acceleate compiles 20 | - Support for unofficial Boost.Process library. 21 | -------------------------------------------------------------------------------- /tests/io/tcp_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace fc { namespace test { 7 | 8 | class my_io_class : public fc::asio::default_io_service_scope 9 | { 10 | public: 11 | static void reset_num_threads() { fc::asio::default_io_service_scope::num_io_threads = 0; } 12 | }; 13 | 14 | }} // fc::test 15 | 16 | BOOST_AUTO_TEST_SUITE(tcp_tests) 17 | 18 | /*** 19 | * Running this test through valgrind will show 20 | * a memory leak due to lack of logic in destructor. 21 | * See https://github.com/bitshares/bitshares-fc/blob/51688042b0b9f99f03224f54fb937fe024fe5ced/src/asio.cpp#L152 22 | */ 23 | BOOST_AUTO_TEST_CASE(tcpconstructor_test) 24 | { 25 | fc::tcp_socket socket; 26 | } 27 | 28 | /*** 29 | * Test the control of number of threads from outside 30 | */ 31 | BOOST_AUTO_TEST_CASE( number_threads_test ) 32 | { 33 | // to erase leftovers from previous tests 34 | fc::test::my_io_class::reset_num_threads(); 35 | 36 | fc::asio::default_io_service_scope::set_num_threads(12); 37 | 38 | fc::test::my_io_class my_class; 39 | 40 | BOOST_CHECK_EQUAL( 12, my_class.get_num_threads() ); 41 | } 42 | 43 | /*** 44 | * Test the control of number of threads from outside 45 | */ 46 | BOOST_AUTO_TEST_CASE( default_number_threads_test ) 47 | { 48 | // to erase leftovers from previous tests 49 | fc::test::my_io_class::reset_num_threads(); 50 | 51 | fc::test::my_io_class my_class; 52 | 53 | fc::asio::default_io_service(); 54 | 55 | BOOST_CHECK( my_class.get_num_threads() > 1 ); 56 | } 57 | 58 | BOOST_AUTO_TEST_SUITE_END() 59 | -------------------------------------------------------------------------------- /src/crypto/hex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace fc { 5 | 6 | uint8_t from_hex( char c ) { 7 | if( c >= '0' && c <= '9' ) 8 | return c - '0'; 9 | if( c >= 'a' && c <= 'f' ) 10 | return c - 'a' + 10; 11 | if( c >= 'A' && c <= 'F' ) 12 | return c - 'A' + 10; 13 | FC_THROW_EXCEPTION( exception, "Invalid hex character '${c}'", ("c", std::string(&c,1) ) ); 14 | return 0; 15 | } 16 | 17 | std::string to_hex( const char* d, uint32_t s ) 18 | { 19 | std::string r; 20 | const char* to_hex="0123456789abcdef"; 21 | uint8_t* c = (uint8_t*)d; 22 | for( uint32_t i = 0; i < s; ++i ) 23 | (r += to_hex[(c[i]>>4)]) += to_hex[(c[i] &0x0f)]; 24 | return r; 25 | } 26 | 27 | size_t from_hex( const std::string& hex_str, char* out_data, size_t out_data_len ) { 28 | std::string::const_iterator i = hex_str.begin(); 29 | uint8_t* out_pos = (uint8_t*)out_data; 30 | uint8_t* out_end = out_pos + out_data_len; 31 | while( i != hex_str.end() && out_end != out_pos ) { 32 | *out_pos = from_hex( *i ) << 4; 33 | ++i; 34 | if( i != hex_str.end() ) { 35 | *out_pos |= from_hex( *i ); 36 | ++i; 37 | } 38 | ++out_pos; 39 | } 40 | return out_pos - (uint8_t*)out_data; 41 | } 42 | std::string to_hex( const std::vector& data ) 43 | { 44 | if( data.size() ) 45 | return to_hex( data.data(), data.size() ); 46 | return ""; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /README-ecc.md: -------------------------------------------------------------------------------- 1 | ECC Support 2 | =========== 3 | 4 | include/fc/crypto/elliptic.hpp defines an interface for some cryptographic 5 | wrapper classes handling elliptic curve cryptography. 6 | 7 | Three implementations of this interface exist. One is based on OpenSSL, the 8 | others are based on libsecp256k1 (see https://github.com/bitcoin/secp256k1 ). 9 | The implementation to be used is selected at compile time using the 10 | cmake variable "ECC_IMPL". It can take one of three values, openssl or 11 | secp256k1 or mixed . 12 | The default is "openssl". The alternatives can be configured when invoking 13 | cmake, for example 14 | 15 | cmake -D ECC_IMPL=secp256k1 . 16 | 17 | If secp256k1 or mixed is chosen, the secp256k1 library and its include file 18 | must already be installed in the appropriate library / include directories on 19 | your system. 20 | 21 | 22 | Testing 23 | ------- 24 | 25 | Type "make ecc_test" to build the ecc_test executable from 26 | tests/crypto/ecc_test.cpp with the currently configured ECC implementation. 27 | 28 | ecc_test expects two arguments: 29 | 30 | ecc_test 31 | 32 | is a somewhat arbitrary password used for testing. 33 | 34 | is a data file containing intermediate test results. 35 | If the file does not exist, it will be created and intermediate results from 36 | the current ECC backend are written to it. 37 | If the file does exist, intermediate results from the current ECC backend 38 | are compared with the file contents. 39 | 40 | For a full round of interoperability testing, you can use the script 41 | tests/crypto/ecc-interop.sh . 42 | None of the test runs should produce any output. 43 | 44 | -------------------------------------------------------------------------------- /include/fc/popcount.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 BitShares Blockchain Foundation, and contributors. 3 | * 4 | * The MIT License 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | 30 | namespace fc { 31 | 32 | #if _MSC_VER || __GNUC__ || __clang__ 33 | inline uint8_t popcount( uint64_t v ) { return __builtin_popcountll(v); } 34 | #else 35 | uint8_t popcount( uint64_t v ); 36 | #endif 37 | 38 | uint8_t popcount( const fc::uint128_t& v ); 39 | 40 | } // namespace fc 41 | -------------------------------------------------------------------------------- /include/fc/rpc/cli.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace fc { namespace rpc { 12 | 13 | /** 14 | * Provides a simple wrapper for RPC calls to a given interface. 15 | */ 16 | class cli : public api_connection 17 | { 18 | public: 19 | cli( uint32_t max_depth ) : api_connection(max_depth) {} 20 | ~cli(); 21 | 22 | virtual variant send_call( api_id_type api_id, string method_name, variants args = variants() ); 23 | virtual variant send_callback( uint64_t callback_id, variants args = variants() ); 24 | virtual void send_notice( uint64_t callback_id, variants args = variants() ); 25 | 26 | void start(); 27 | void stop(); 28 | void cancel(); 29 | void wait(); 30 | void format_result( const string& method, std::function formatter); 31 | 32 | virtual void getline( const std::string& prompt, std::string& line ); 33 | 34 | void set_prompt( const string& prompt ); 35 | 36 | void set_regex_secret( const string& expr ); 37 | 38 | private: 39 | void run(); 40 | 41 | std::string _prompt = ">>>"; 42 | std::map > _result_formatters; 43 | fc::future _run_complete; 44 | fc::thread* _getline_thread = nullptr; ///< Wait for user input in this thread 45 | }; 46 | } } 47 | -------------------------------------------------------------------------------- /src/crypto/_digest_common.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "_digest_common.hpp" 3 | 4 | namespace fc { namespace detail { 5 | static void shift_l( const uint8_t* in, uint8_t* out, std::size_t n, unsigned int i) { 6 | if (i < n) { 7 | memcpy( out, in + i, n-i ); 8 | } else { 9 | i = n; 10 | } 11 | memset( out + (n-i), 0, i ); 12 | } 13 | 14 | void shift_l( const char* in, char* out, std::size_t n, unsigned int i) { 15 | const uint8_t* in8 = (uint8_t*) in; 16 | uint8_t* out8 = (uint8_t*) out; 17 | 18 | if (i >= 8) { 19 | shift_l( in8, out8, n, i / 8 ); 20 | i &= 7; 21 | in8 = out8; 22 | } 23 | 24 | std::size_t p; 25 | for( p = 0; p < n-1; ++p ) 26 | out8[p] = (in8[p] << i) | (in8[p+1]>>(8-i)); 27 | out8[p] = in8[p] << i; 28 | } 29 | static void shift_r( const uint8_t* in, uint8_t* out, std::size_t n, unsigned int i) { 30 | if (i < n) { 31 | memcpy( out+i, in, n-i ); 32 | } else { 33 | i = n; 34 | } 35 | memset( out, 0, i ); 36 | } 37 | 38 | void shift_r( const char* in, char* out, std::size_t n, unsigned int i) { 39 | const uint8_t* in8 = (uint8_t*) in; 40 | uint8_t* out8 = (uint8_t*) out; 41 | 42 | if (i >= 8) { 43 | shift_r( in8, out8, n, i / 8 ); 44 | i &= 7; 45 | in8 = out8; 46 | } 47 | 48 | std::size_t p; 49 | for( p = n-1; p > 0; --p ) 50 | out8[p] = (in8[p] >> i) | (in8[p-1]<<(8-i)); 51 | out8[p] = in8[p] >> i; 52 | } 53 | }} 54 | -------------------------------------------------------------------------------- /tests/compress/compress.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | BOOST_AUTO_TEST_SUITE(compress) 9 | 10 | extern "C" { 11 | 12 | enum 13 | { 14 | TINFL_FLAG_PARSE_ZLIB_HEADER = 1, 15 | TINFL_FLAG_HAS_MORE_INPUT = 2, 16 | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, 17 | TINFL_FLAG_COMPUTE_ADLER32 = 8 18 | }; 19 | 20 | extern char* tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); 21 | 22 | } 23 | 24 | static std::string zlib_decompress( const std::string compressed ) 25 | { 26 | size_t decomp_len; 27 | char* decomp = tinfl_decompress_mem_to_heap( compressed.c_str(), compressed.length(), &decomp_len, TINFL_FLAG_PARSE_ZLIB_HEADER ); 28 | std::string result( decomp, decomp_len ); 29 | free( decomp ); 30 | return result; 31 | } 32 | 33 | BOOST_AUTO_TEST_CASE(zlib_test) 34 | { 35 | std::ifstream testfile; 36 | testfile.open("README.md"); 37 | 38 | std::stringstream buffer; 39 | std::string line; 40 | std::getline( testfile, line ); 41 | while( testfile.good() ) 42 | { 43 | buffer << line << "\n"; 44 | std::string compressed = fc::zlib_compress( line ); 45 | std::string decomp = zlib_decompress( compressed ); 46 | BOOST_CHECK_EQUAL( decomp, line ); 47 | 48 | std::getline( testfile, line ); 49 | } 50 | 51 | line = buffer.str(); 52 | std::string compressed = fc::zlib_compress( line ); 53 | std::string decomp = zlib_decompress( compressed ); 54 | BOOST_CHECK_EQUAL( decomp, line ); 55 | } 56 | 57 | BOOST_AUTO_TEST_SUITE_END() 58 | -------------------------------------------------------------------------------- /include/fc/log/logger_config.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace fc { 5 | class path; 6 | struct appender_config { 7 | appender_config(const string& name = "", 8 | const string& type = "", 9 | variant args = variant()) : 10 | name(name), 11 | type(type), 12 | args(std::move(args)), 13 | enabled(true) 14 | {} 15 | string name; 16 | string type; 17 | variant args; 18 | bool enabled; 19 | }; 20 | 21 | struct logger_config { 22 | logger_config(const std::string& name = ""):name(name),enabled(true),additivity(false){} 23 | string name; 24 | ostring parent; 25 | /// if not set, then parents level is used. 26 | fc::optional level; 27 | bool enabled; 28 | /// if any appenders are sepecified, then parent's appenders are not set. 29 | bool additivity; 30 | std::vector appenders; 31 | 32 | logger_config& add_appender( const string& s ); 33 | }; 34 | 35 | struct logging_config { 36 | static logging_config default_config(); 37 | std::vector includes; 38 | std::vector appenders; 39 | std::vector loggers; 40 | }; 41 | 42 | void configure_logging( const fc::path& log_config ); 43 | bool configure_logging( const logging_config& l ); 44 | } 45 | 46 | #include 47 | FC_REFLECT( fc::appender_config, (name)(type)(args)(enabled) ) 48 | FC_REFLECT( fc::logger_config, (name)(parent)(level)(enabled)(additivity)(appenders) ) 49 | FC_REFLECT( fc::logging_config, (includes)(appenders)(loggers) ) 50 | -------------------------------------------------------------------------------- /include/fc/signals.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(_MSC_VER) && _MSC_VER >= 1400 4 | #pragma warning(push) 5 | #pragma warning(disable:4996) 6 | #endif 7 | 8 | #include 9 | 10 | #if defined(_MSC_VER) && _MSC_VER >= 1400 11 | #pragma warning(pop) 12 | #endif 13 | 14 | #include 15 | #include 16 | 17 | namespace fc { 18 | #if !defined(BOOST_NO_TEMPLATE_ALIASES) 19 | template 20 | using signal = boost::signals2::signal; 21 | 22 | using scoped_connection = boost::signals2::scoped_connection; 23 | #else 24 | /** Workaround for missing Template Aliases feature in the VS 2012. 25 | \warning Class defined below cannot have defined constructor (even base class has it) 26 | since it is impossible to reference directly template class arguments outside this class. 27 | This code will work until someone will use non-default constructor as it is defined in 28 | boost::signals2::signal. 29 | */ 30 | template 31 | class signal : public boost::signals2::signal 32 | { 33 | public: 34 | }; 35 | #endif 36 | 37 | template 38 | inline T wait( boost::signals2::signal& sig, const microseconds& timeout_us=microseconds::maximum() ) { 39 | typename promise::ptr p = promise::create("fc::signal::wait"); 40 | boost::signals2::scoped_connection c( sig.connect( [=]( T t ) { p->set_value(t); } )); 41 | return p->wait( timeout_us ); 42 | } 43 | 44 | inline void wait( boost::signals2::signal& sig, const microseconds& timeout_us=microseconds::maximum() ) { 45 | promise::ptr p = promise::create("fc::signal::wait"); 46 | boost::signals2::scoped_connection c( sig.connect( [=]() { p->set_value(); } )); 47 | p->wait( timeout_us ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /include/fc/crypto/hmac.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: hmac.hpp 3 | * Author: Peter Conrad 4 | * 5 | * Created on 1. Juli 2015, 21:48 6 | */ 7 | 8 | #ifndef HMAC_HPP 9 | #define HMAC_HPP 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace fc { 16 | 17 | template 18 | class hmac 19 | { 20 | public: 21 | hmac() {} 22 | 23 | H digest( const char* c, uint32_t c_len, const char* d, uint32_t d_len ) 24 | { 25 | encoder.reset(); 26 | add_key(c, c_len, 0x36); 27 | encoder.write( d, d_len ); 28 | H intermediate = encoder.result(); 29 | 30 | encoder.reset(); 31 | add_key(c, c_len, 0x5c); 32 | encoder.write( intermediate.data(), intermediate.data_size() ); 33 | return encoder.result(); 34 | } 35 | 36 | private: 37 | void add_key( const char* c, const uint32_t c_len, char pad ) 38 | { 39 | if ( c_len > internal_block_size() ) 40 | { 41 | H hash = H::hash( c, c_len ); 42 | add_key( hash.data(), hash.data_size(), pad ); 43 | } 44 | else 45 | for (unsigned int i = 0; i < internal_block_size(); i++ ) 46 | { 47 | encoder.put( pad ^ ((i < c_len) ? *c++ : 0) ); 48 | } 49 | } 50 | 51 | unsigned int internal_block_size() const; 52 | 53 | H dummy; 54 | typename H::encoder encoder; 55 | }; 56 | 57 | typedef hmac hmac_sha224; 58 | typedef hmac hmac_sha256; 59 | typedef hmac hmac_sha512; 60 | } 61 | 62 | #endif /* HMAC_HPP */ 63 | 64 | -------------------------------------------------------------------------------- /include/fc/io/fstream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace fc { 8 | class path; 9 | class ofstream : virtual public ostream { 10 | public: 11 | ofstream(); 12 | ofstream( const fc::path& file, std::ios_base::openmode m = std::ios_base::out | std::ios_base::binary ); 13 | ~ofstream(); 14 | 15 | void open( const fc::path& file, std::ios_base::openmode m = std::ios_base::out | std::ios_base::binary ); 16 | size_t writesome( const char* buf, size_t len ); 17 | size_t writesome(const std::shared_ptr& buffer, size_t len, size_t offset); 18 | void put( char c ); 19 | void close(); 20 | void flush(); 21 | 22 | private: 23 | class impl; 24 | std::shared_ptr my; 25 | }; 26 | 27 | class ifstream : virtual public istream { 28 | public: 29 | enum mode { in, binary }; 30 | enum seekdir { beg, cur, end }; 31 | 32 | ifstream(); 33 | ifstream( const fc::path& file, int m = binary); 34 | ~ifstream(); 35 | 36 | void open( const fc::path& file, int m ); 37 | size_t readsome( char* buf, size_t len ); 38 | size_t readsome(const std::shared_ptr& buffer, size_t max, size_t offset); 39 | ifstream& read( char* buf, size_t len ); 40 | ifstream& seekg( size_t p, seekdir d = beg ); 41 | using istream::get; 42 | void get( char& c ) { read( &c, 1 ); } 43 | void close(); 44 | bool eof()const; 45 | private: 46 | class impl; 47 | std::shared_ptr my; 48 | }; 49 | 50 | /** 51 | * Grab the full contents of a file into a string object. 52 | * NB reading a full file into memory is a poor choice 53 | * if the file may be very large. 54 | */ 55 | void read_file_contents( const fc::path& filename, std::string& result ); 56 | 57 | } // namespace fc 58 | -------------------------------------------------------------------------------- /include/fc/thread/thread_specific.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "thread.hpp" 3 | 4 | namespace fc 5 | { 6 | namespace detail 7 | { 8 | unsigned get_next_unused_thread_storage_slot(); 9 | unsigned get_next_unused_task_storage_slot(); 10 | } 11 | 12 | template 13 | class thread_specific_ptr 14 | { 15 | private: 16 | unsigned slot; 17 | public: 18 | thread_specific_ptr() : 19 | slot(detail::get_next_unused_thread_storage_slot()) 20 | {} 21 | 22 | T* get() const 23 | { 24 | return static_cast(detail::get_thread_specific_data(slot)); 25 | } 26 | T* operator->() const 27 | { 28 | return get(); 29 | } 30 | T& operator*() const 31 | { 32 | return *get(); 33 | } 34 | operator bool() const 35 | { 36 | return get() != static_cast(0); 37 | } 38 | static void cleanup_function(void* obj) 39 | { 40 | delete static_cast(obj); 41 | } 42 | void reset(T* new_value = 0) 43 | { 44 | detail::set_thread_specific_data(slot, new_value, cleanup_function); 45 | } 46 | }; 47 | 48 | template 49 | class task_specific_ptr 50 | { 51 | private: 52 | unsigned slot; 53 | public: 54 | task_specific_ptr() : 55 | slot(detail::get_next_unused_task_storage_slot()) 56 | {} 57 | 58 | T* get() const 59 | { 60 | return static_cast(detail::get_task_specific_data(slot)); 61 | } 62 | T* operator->() const 63 | { 64 | return get(); 65 | } 66 | T& operator*() const 67 | { 68 | return *get(); 69 | } 70 | operator bool() const 71 | { 72 | return get() != static_cast(0); 73 | } 74 | static void cleanup_function(void* obj) 75 | { 76 | delete static_cast(obj); 77 | } 78 | void reset(T* new_value = 0) 79 | { 80 | detail::set_task_specific_data(slot, new_value, cleanup_function); 81 | } 82 | }; 83 | 84 | } 85 | -------------------------------------------------------------------------------- /.github/workflows/build-and-test-macos.yml: -------------------------------------------------------------------------------- 1 | name: macOS 2 | on: [ push, pull_request ] 3 | env: 4 | CCACHE_COMPRESS: exists means true 5 | CCACHE_SLOPPINESS: include_file_ctime,include_file_mtime,time_macros 6 | jobs: 7 | test-macos: 8 | name: Build and run tests in macOS 9 | strategy: 10 | matrix: 11 | os: [macos-11.0] 12 | runs-on: ${{ matrix.os }} 13 | steps: 14 | - name: Install dependencies 15 | run: | 16 | brew install autoconf automake libtool 17 | brew install ccache 18 | brew install parallel 19 | brew search boost 20 | brew install bitshares/boost/boost@1.69 21 | - uses: actions/checkout@v3 22 | with: 23 | submodules: recursive 24 | - name: Configure 25 | run: | 26 | mkdir -p _build 27 | pushd _build 28 | cmake -D CMAKE_BUILD_TYPE=Release \ 29 | -D CMAKE_C_COMPILER_LAUNCHER=ccache \ 30 | -D CMAKE_CXX_COMPILER_LAUNCHER=ccache \ 31 | -D BOOST_ROOT=/usr/local/opt/boost@1.69 \ 32 | -D OPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1 \ 33 | .. 34 | popd 35 | - name: Load Cache 36 | uses: actions/cache@v3 37 | with: 38 | path: ccache 39 | key: ccache-${{ matrix.os }}-${{ github.ref }}-${{ github.sha }} 40 | restore-keys: | 41 | ccache-${{ matrix.os }}-${{ github.ref }}- 42 | ccache-${{ matrix.os }}- 43 | - name: Build 44 | run: | 45 | export CCACHE_DIR="$GITHUB_WORKSPACE/ccache" 46 | mkdir -p "$CCACHE_DIR" 47 | make -j 2 -C _build 48 | df -h 49 | - name: Unit-Tests 50 | run: | 51 | parallel echo Running {}\; sh -c "./{}" <<_EOT_ 52 | tests/run-parallel-tests.sh _build/tests/all_tests -l test_suite 53 | _build/tests/bloom_test -- README.md 54 | _build/tests/ecc_test README.md 55 | _build/tests/hmac_test 56 | _build/tests/task_cancel_test 57 | _EOT_ 58 | -------------------------------------------------------------------------------- /src/log/appender.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "console_defines.h" 13 | 14 | 15 | namespace fc { 16 | 17 | std::unordered_map& get_appender_map() { 18 | static std::unordered_map lm; 19 | return lm; 20 | } 21 | std::unordered_map& get_appender_factory_map() { 22 | static std::unordered_map lm; 23 | return lm; 24 | } 25 | appender::ptr appender::get( const std::string& s ) { 26 | static fc::spin_lock appender_spinlock; 27 | scoped_lock lock(appender_spinlock); 28 | return get_appender_map()[s]; 29 | } 30 | bool appender::register_appender( const std::string& type, const appender_factory::ptr& f ) 31 | { 32 | get_appender_factory_map()[type] = f; 33 | return true; 34 | } 35 | appender::ptr appender::create( const std::string& name, const std::string& type, const variant& args ) 36 | { 37 | auto fact_itr = get_appender_factory_map().find(type); 38 | if( fact_itr == get_appender_factory_map().end() ) { 39 | //wlog( "Unknown appender type '%s'", type.c_str() ); 40 | return appender::ptr(); 41 | } 42 | auto ap = fact_itr->second->create( args ); 43 | get_appender_map()[name] = ap; 44 | return ap; 45 | } 46 | 47 | static bool reg_console_appender = appender::register_appender( "console" ); 48 | static bool reg_file_appender = appender::register_appender( "file" ); 49 | static bool reg_gelf_appender = appender::register_appender( "gelf" ); 50 | 51 | } // namespace fc 52 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c++ 2 | 3 | cache: ccache 4 | 5 | git: 6 | depth: 1 7 | 8 | dist: xenial 9 | 10 | sudo: true 11 | 12 | install: 13 | - sudo apt-get install --allow-unauthenticated libboost-thread-dev libboost-iostreams-dev libboost-date-time-dev libboost-system-dev libboost-filesystem-dev libboost-program-options-dev libboost-chrono-dev libboost-test-dev libboost-context-dev libboost-regex-dev libboost-coroutine-dev cmake parallel 14 | 15 | addons: 16 | sonarcloud: 17 | organization: "flwyiq7go36p6lipr64tbesy5jayad3q" 18 | token: 19 | secure: "Y0DhI1Fn7QXqdYF5kCUFV0l0XUOp5iYp+kHYVAWpt1HSYN5889GTO3SgsZoT7+Cmo1HLAe2P8tSCzz3lECDI0rWMuk7wxFRMVmnxBpbR5P61+Mhe4t/LhSGzuT3PAscttFNPexpDmePKO0EgTY7PemMtXR8LZ2O/RngAMWWfH0Wmyngy68Bm9CvpWfW9aQ8ZUMsjpbDmbaE9dN6FLABE1YZzVL+9SA07gOSQzry/SLbRY19+g9OicaAoCdQCdvIem6af1qIy0x5uDFfz4x1Sows9awBOsAOf6V5WmFlV21YwR1RhT+4WffB+VrMYOF8YpzoUrS+CPmPWlkDDN3fuKsqRGYpbBIxyqBQ+rahDtXfoD5ZbGY1UYTbrHGD8VTNVbvdqAsVEfgZ8ci7NxBnIL3VDduxP1qb46chTJb9KeeIETtN8qTdfsZyudveZLKmULKah8uaOkMX2bJT6oikluVXJnI0OybHQrrMwHula/qmEj3FnC3KKPmL84F/6DSPiiojx+qsMa0STQE9ZwzeJPc8KjllsTYKL492IDQJDXkWGS+PwlOXResr2Dhu/rfYKy6qpHQJzreoPcIRmeM7rFamJZHkqdaldJGm+iQacX2byKJ/tT93IM6hW0BEi4Haucwn1f0Ig5tzE8mzro1/Rj35a9ti2jmO0NWjyeBwnCVo=" 20 | 21 | env: 22 | global: 23 | - CCACHE_COMPRESS=exists_means_true 24 | - CCACHE_MAXSIZE=1Gi 25 | - CCACHE_SLOPPINESS=include_file_ctime,include_file_mtime,time_macros 26 | 27 | script: 28 | - ccache -s 29 | - cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_FLAGS=--coverage -DCMAKE_CXX_FLAGS=--coverage -DBoost_USE_STATIC_LIBS=OFF -DCMAKE_CXX_OUTPUT_EXTENSION_REPLACE=ON . 30 | - 'which build-wrapper-linux-x86-64 && build-wrapper-linux-x86-64 --out-dir bw-output make -j 2 || make -j 2' 31 | - set -o pipefail 32 | - tests/run-parallel-tests.sh tests/all_tests -l message 33 | - tests/hmac_test 2>&1 | cat 34 | - tests/ecc_test README.md 2>&1 | cat 35 | - 'find CMakeFiles/fc.dir -type d | while read d; do gcov -o "$d" "${d/CMakeFiles*.dir/./}"/*.cpp; done >/dev/null' 36 | - 'which sonar-scanner && sonar-scanner || true' 37 | - ccache -s 38 | -------------------------------------------------------------------------------- /include/fc/crypto/aes.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | namespace fc { 11 | class path; 12 | 13 | class aes_encoder 14 | { 15 | public: 16 | aes_encoder(); 17 | ~aes_encoder(); 18 | 19 | void init( const fc::sha256& key, const uint128_t& init_value ); 20 | uint32_t encode( const char* plaintxt, uint32_t len, char* ciphertxt ); 21 | 22 | private: 23 | struct impl; 24 | fc::fwd my; 25 | }; 26 | class aes_decoder 27 | { 28 | public: 29 | aes_decoder(); 30 | ~aes_decoder(); 31 | 32 | void init( const fc::sha256& key, const uint128_t& init_value ); 33 | uint32_t decode( const char* ciphertxt, uint32_t len, char* plaintext ); 34 | 35 | private: 36 | struct impl; 37 | fc::fwd my; 38 | }; 39 | 40 | unsigned aes_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, 41 | unsigned char *iv, unsigned char *ciphertext); 42 | unsigned aes_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, 43 | unsigned char *iv, unsigned char *plaintext); 44 | unsigned aes_cfb_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, 45 | unsigned char *iv, unsigned char *plaintext); 46 | 47 | std::vector aes_encrypt( const fc::sha512& key, const std::vector& plain_text ); 48 | std::vector aes_decrypt( const fc::sha512& key, const std::vector& cipher_text ); 49 | 50 | /** encrypts plain_text and then includes a checksum that enables us to verify the integrety of 51 | * the file / key prior to decryption. 52 | */ 53 | void aes_save( const fc::path& file, const fc::sha512& key, std::vector plain_text ); 54 | 55 | /** 56 | * recovers the plain_text saved via aes_save() 57 | */ 58 | std::vector aes_load( const fc::path& file, const fc::sha512& key ); 59 | 60 | } // namespace fc 61 | -------------------------------------------------------------------------------- /src/popcount.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 BitShares Blockchain Foundation, and contributors. 3 | * 4 | * The MIT License 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | 27 | namespace fc { 28 | 29 | #if _MSC_VER || __GNUC__ || __clang__ 30 | #else 31 | uint8_t popcount( uint64_t v ) 32 | { 33 | // Public Domain code taken from http://graphics.stanford.edu/~seander/bithacks.html 34 | uint8_t c; 35 | static const int S[] = {1, 2, 4, 8, 16, 32}; 36 | static const uint64_t B[] = {0x5555555555555555, 0x3333333333333333, 0x0F0F0F0F0F0F0F0F, 37 | 0x00FF00FF00FF00FF, 0x0000FFFF0000FFFF, 0x00000000FFFFFFFF }; 38 | 39 | c = v - ((v >> 1) & B[0]); 40 | c = ((c >> S[1]) & B[1]) + (c & B[1]); 41 | c = ((c >> S[2]) + c) & B[2]; 42 | c = ((c >> S[3]) + c) & B[3]; 43 | c = ((c >> S[4]) + c) & B[4]; 44 | return ((c >> S[5]) + c) & B[5]; 45 | } 46 | #endif 47 | 48 | uint8_t popcount( const uint128_t& v ) 49 | { 50 | return popcount( static_cast(v >> 64) ) 51 | + popcount( static_cast(v & 0xffffffffffffffffULL) ); 52 | } 53 | 54 | } // namespace fc 55 | -------------------------------------------------------------------------------- /tests/rate_limiting.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | fc::rate_limiting_group rate_limiter(1000000, 1000000); 9 | 10 | void download_url(const std::string& ip_address, const std::string& url) 11 | { 12 | fc::http::connection http_connection; 13 | rate_limiter.add_tcp_socket(&http_connection.get_socket()); 14 | http_connection.connect_to(fc::ip::endpoint(fc::ip::address(ip_address.c_str()), 80)); 15 | std::cout << "Starting download...\n"; 16 | fc::time_point start_time(fc::time_point::now()); 17 | fc::http::reply reply = http_connection.request("GET", "http://mirror.cs.vt.edu/pub/cygwin/glibc/releases/glibc-2.9.tar.gz"); 18 | fc::time_point end_time(fc::time_point::now()); 19 | 20 | std::cout << "HTTP return code: " << reply.status << "\n"; 21 | std::cout << "Retreived " << reply.body.size() << " bytes in " << ((end_time - start_time).count() / fc::milliseconds(1).count()) << "ms\n"; 22 | std::cout << "Average speed " << ((1000 * (uint64_t)reply.body.size()) / ((end_time - start_time).count() / fc::milliseconds(1).count())) << " bytes per second"; 23 | } 24 | 25 | int main( int argc, char** argv ) 26 | { 27 | rate_limiter.set_actual_rate_time_constant(fc::seconds(1)); 28 | 29 | std::vector > download_futures; 30 | download_futures.push_back(fc::async([](){ download_url("198.82.184.145", "http://mirror.cs.vt.edu/pub/cygwin/glibc/releases/glibc-2.9.tar.gz"); })); 31 | download_futures.push_back(fc::async([](){ download_url("198.82.184.145", "http://mirror.cs.vt.edu/pub/cygwin/glibc/releases/glibc-2.7.tar.gz"); })); 32 | 33 | while (1) 34 | { 35 | bool all_done = true; 36 | for (unsigned i = 0; i < download_futures.size(); ++i) 37 | if (!download_futures[i].ready()) 38 | all_done = false; 39 | if (all_done) 40 | break; 41 | std::cout << "Current measurement of actual transfer rate: upload " << rate_limiter.get_actual_upload_rate() << ", download " << rate_limiter.get_actual_download_rate() << "\n"; 42 | fc::usleep(fc::seconds(1)); 43 | } 44 | 45 | for (unsigned i = 0; i < download_futures.size(); ++i) 46 | download_futures[i].wait(); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /CONTRIBUTORS.txt: -------------------------------------------------------------------------------- 1 | Contributors to this repository, in descending order by number of commits. Update with 2 | head -5 CONTRIBUTORS.txt >contrib.tmp && git shortlog -s -e -n | cut -f 2 >>contrib.tmp && mv contrib.tmp CONTRIBUTORS.txt 3 | 4 | ============================================================================== 5 | 6 | Daniel Larimer 7 | Peter Conrad 8 | abitmore 9 | Eric Frias 10 | John M. Jones 11 | Vikram Rajkumar 12 | Nathan Hourt 13 | theoreticalbts 14 | Dan Notestein 15 | vogel76 16 | Alfredo Garcia 17 | crypto-ape <43807588+crypto-ape@users.noreply.github.com> 18 | Valera Cogut 19 | Michael Vandeberg 20 | Nikolai Mushegian 21 | Qi Xing 22 | HackFisher 23 | Valentine Zavgorodnev 24 | Anton Autushka 25 | Karl Semich <0xloem@gmail.com> 26 | PaulEU 27 | Scott Howard 28 | batmaninpink 29 | Daniel Brockman 30 | Fabian Schuh 31 | Gandalf-the-Grey 32 | Nicolas Wack 33 | Tzadik Vanderhoof 34 | Yuvaraj Gogoi 35 | arhag 36 | grzegorzs 37 | Alexey Frolov 38 | BrownBear <-> 39 | Matias Romeo 40 | Wei Yang 41 | alt 42 | skchaudhari 43 | Anonymous 44 | BITSG-Jerry 45 | Dmitry Yakovitsky 46 | Haruka Ma 47 | Kevin Heifner 48 | Spartucus 49 | ioBanker <37595908+ioBanker@users.noreply.github.com> 50 | kinglaw <58291@qq.com> 51 | liukunyu 52 | lubos.ilcik 53 | phoenixint 54 | sinetek 55 | -------------------------------------------------------------------------------- /src/stacktrace.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2019 BitShares Blockchain Foundation, and contributors. 3 | * 4 | * The MIT License 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | // only include stacktrace stuff if boost >= 1.65 and not macOS 29 | #if BOOST_VERSION / 100 >= 1065 && !defined(__APPLE__) 30 | #include 31 | #include 32 | #if defined(__OpenBSD__) 33 | #define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED 34 | #endif 35 | #include 36 | 37 | namespace fc 38 | { 39 | 40 | static void segfault_signal_handler(int signum) 41 | { 42 | ::signal(signum, SIG_DFL); 43 | std::stringstream ss; 44 | ss << boost::stacktrace::stacktrace(); 45 | elog(ss.str()); 46 | ::raise(SIGABRT); 47 | } 48 | 49 | void print_stacktrace_on_segfault() 50 | { 51 | ::signal(SIGSEGV, &segfault_signal_handler); 52 | } 53 | 54 | void print_stacktrace(std::ostream& out) 55 | { 56 | out << boost::stacktrace::stacktrace(); 57 | } 58 | 59 | } 60 | #else 61 | // Stacktrace output requires Boost 1.65 or above. 62 | // Therefore calls to these methods do nothing. 63 | namespace fc 64 | { 65 | void print_stacktrace_on_segfault() {} 66 | void print_stacktrace(std::ostream& out) {} 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /include/fc/uint128.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 BitShares Blockchain Foundation, and contributors. 3 | * 4 | * The MIT License 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #pragma once 26 | 27 | #ifdef __SIZEOF_INT128__ 28 | 29 | #include 30 | 31 | namespace fc { 32 | 33 | using int128_t = __int128_t; 34 | using uint128_t = __uint128_t; 35 | 36 | inline uint64_t uint128_lo64(const uint128_t x) { 37 | return static_cast(x & 0xffffffffffffffffULL); 38 | } 39 | inline uint64_t uint128_hi64(const uint128_t x) { 40 | return static_cast( x >> 64 ); 41 | } 42 | 43 | } // namespace fc 44 | 45 | #else // __SIZEOF_INT128__ 46 | 47 | #include 48 | 49 | namespace fc { 50 | 51 | using boost::multiprecision::int128_t; 52 | using boost::multiprecision::uint128_t; 53 | 54 | inline uint64_t uint128_lo64(const uint128_t& x) { 55 | return static_cast(x & 0xffffffffffffffffULL); 56 | } 57 | inline uint64_t uint128_hi64(const uint128_t& x) { 58 | return static_cast( x >> 64 ); 59 | } 60 | 61 | } // namespace fc 62 | 63 | #endif // __SIZEOF_INT128__ 64 | 65 | namespace fc { 66 | 67 | inline uint128_t uint128( const uint64_t hi, const uint64_t lo ) { 68 | return ( uint128_t(hi) << 64 ) + lo; 69 | } 70 | 71 | } // namespace fc 72 | -------------------------------------------------------------------------------- /include/fc/crypto/openssl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | /** 14 | * @file openssl.hpp 15 | * Provides common utility calls for wrapping openssl c api. 16 | */ 17 | namespace fc 18 | { 19 | class path; 20 | 21 | template 22 | struct ssl_wrapper 23 | { 24 | ssl_wrapper(ssl_type* obj):obj(obj) {} 25 | ssl_wrapper( ssl_wrapper& copy ) = delete; 26 | ssl_wrapper& operator=( ssl_wrapper& copy ) = delete; 27 | 28 | operator ssl_type*() { return obj; } 29 | operator const ssl_type*() const { return obj; } 30 | ssl_type* operator->() { return obj; } 31 | const ssl_type* operator->() const { return obj; } 32 | 33 | ssl_type* obj; 34 | }; 35 | 36 | #define SSL_TYPE_DECL(name, ssl_type) \ 37 | struct name : public ssl_wrapper \ 38 | { \ 39 | name( ssl_type* obj=nullptr ); \ 40 | name( name&& move ); \ 41 | ~name(); \ 42 | name& operator=( name&& move ); \ 43 | }; 44 | 45 | SSL_TYPE_DECL(ec_group, EC_GROUP) 46 | SSL_TYPE_DECL(ec_point, EC_POINT) 47 | SSL_TYPE_DECL(ecdsa_sig, ECDSA_SIG) 48 | SSL_TYPE_DECL(bn_ctx, BN_CTX) 49 | SSL_TYPE_DECL(evp_cipher_ctx, EVP_CIPHER_CTX) 50 | SSL_TYPE_DECL(ssl_dh, DH) 51 | 52 | /** allocates a bignum by default.. */ 53 | struct ssl_bignum : public ssl_wrapper 54 | { 55 | ssl_bignum() : ssl_wrapper(BN_new()) {} 56 | ~ssl_bignum() { BN_free(obj); } 57 | }; 58 | 59 | /** Allows to explicitly specify OpenSSL configuration file path to be loaded at OpenSSL library init. 60 | If not set OpenSSL will try to load the conf. file (openssl.cnf) from the path it was 61 | configured with what caused serious Keyhotee startup bugs on some Win7, Win8 machines. 62 | \warning to be effective this method should be used before any part using OpenSSL, especially 63 | before init_openssl call 64 | */ 65 | void store_configuration_path(const path& filePath); 66 | int init_openssl(); 67 | 68 | } // namespace fc 69 | -------------------------------------------------------------------------------- /CMakeModules/CheckLibcxxAtomic.cmake: -------------------------------------------------------------------------------- 1 | # Taken from https://chromium.googlesource.com/chromium/llvm-project/libcxx/+/refs/heads/master/cmake/Modules/CheckLibcxxAtomic.cmake 2 | # Apache License v2.0 with LLVM Exceptions 3 | 4 | INCLUDE(CheckCXXSourceCompiles) 5 | 6 | # Sometimes linking against libatomic is required for atomic ops, if 7 | # the platform doesn't support lock-free atomics. 8 | 9 | function(check_cxx_atomics varname) 10 | set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) 11 | set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11") 12 | if (${LIBCXX_GCC_TOOLCHAIN}) 13 | set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} --gcc-toolchain=${LIBCXX_GCC_TOOLCHAIN}") 14 | endif() 15 | if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize) 16 | set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all") 17 | endif() 18 | if (CMAKE_C_FLAGS MATCHES -fsanitize-coverage OR CMAKE_CXX_FLAGS MATCHES -fsanitize-coverage) 19 | set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters") 20 | endif() 21 | 22 | set(OLD_CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES}) 23 | set(CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIRS}) 24 | 25 | check_cxx_source_compiles(" 26 | #include 27 | #include 28 | 29 | boost::lockfree::queue> q; 30 | int main(int, char**) { 31 | uint32_t* a; 32 | uint32_t* b; 33 | q.push(a); 34 | q.pop(b); 35 | } 36 | " ${varname}) 37 | set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) 38 | set(CMAKE_REQUIRED_INCLUDES ${OLD_CMAKE_REQUIRED_INCLUDES}) 39 | endfunction(check_cxx_atomics) 40 | 41 | # Perform the check for 64bit atomics without libatomic. 42 | check_cxx_atomics(LIBCXX_HAVE_CXX_ATOMICS_WITHOUT_LIB) 43 | # If not, check if the library exists, and atomics work with it. 44 | if(NOT LIBCXX_HAVE_CXX_ATOMICS_WITHOUT_LIB) 45 | check_library_exists(atomic __atomic_fetch_add_8 "" LIBCXX_HAS_ATOMIC_LIB) 46 | if(LIBCXX_HAS_ATOMIC_LIB) 47 | list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") 48 | check_cxx_atomics(LIBCXX_HAVE_CXX_ATOMICS_WITH_LIB) 49 | if (NOT LIBCXX_HAVE_CXX_ATOMICS_WITH_LIB) 50 | message(WARNING "Host compiler must support std::atomic!") 51 | endif() 52 | else() 53 | message(WARNING "Host compiler appears to require libatomic, but cannot find it.") 54 | endif() 55 | endif() 56 | -------------------------------------------------------------------------------- /src/io/sstream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace fc { 8 | class stringstream::impl { 9 | public: 10 | impl( std::string&s ) 11 | :ss( s ) 12 | { ss.exceptions( std::stringstream::badbit ); } 13 | 14 | impl( const std::string&s ) 15 | :ss( s ) 16 | { ss.exceptions( std::stringstream::badbit ); } 17 | 18 | impl(){ss.exceptions( std::stringstream::badbit ); } 19 | 20 | std::stringstream ss; 21 | }; 22 | 23 | stringstream::stringstream( std::string& s ) 24 | :my(s) { 25 | } 26 | stringstream::stringstream( const std::string& s ) 27 | :my(s) { 28 | } 29 | stringstream::stringstream(){} 30 | stringstream::~stringstream(){} 31 | 32 | 33 | std::string stringstream::str(){ 34 | return my->ss.str();//.c_str();//*reinterpret_cast(&st); 35 | } 36 | 37 | void stringstream::str(const std::string& s) { 38 | my->ss.str(s); 39 | } 40 | 41 | void stringstream::clear() { 42 | my->ss.clear(); 43 | } 44 | 45 | 46 | bool stringstream::eof()const { 47 | return my->ss.eof(); 48 | } 49 | size_t stringstream::writesome( const char* buf, size_t len ) { 50 | my->ss.write(buf,len); 51 | if( my->ss.eof() ) 52 | { 53 | FC_THROW_EXCEPTION( eof_exception, "stringstream" ); 54 | } 55 | return len; 56 | } 57 | size_t stringstream::writesome( const std::shared_ptr& buf, size_t len, size_t offset ) 58 | { 59 | return writesome(buf.get() + offset, len); 60 | } 61 | 62 | size_t stringstream::readsome( char* buf, size_t len ) { 63 | size_t r = static_cast(my->ss.readsome(buf,len)); 64 | if( my->ss.eof() || r == 0 ) 65 | { 66 | FC_THROW_EXCEPTION( eof_exception, "stringstream" ); 67 | } 68 | return r; 69 | } 70 | size_t stringstream::readsome( const std::shared_ptr& buf, size_t len, size_t offset ) 71 | { 72 | return readsome(buf.get() + offset, len); 73 | } 74 | 75 | 76 | void stringstream::close(){ my->ss.flush(); }; 77 | void stringstream::flush(){ my->ss.flush(); }; 78 | 79 | char stringstream::peek() 80 | { 81 | char c = my->ss.peek(); 82 | if( my->ss.eof() ) 83 | { 84 | FC_THROW_EXCEPTION( eof_exception, "stringstream" ); 85 | } 86 | return c; 87 | } 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/rpc/state.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace fc { namespace rpc { 6 | state::~state() 7 | { 8 | close(); 9 | } 10 | 11 | void state::add_method( const std::string& name, method m ) 12 | { 13 | _methods.emplace(std::pair(name,std::move(m))); 14 | } 15 | 16 | void state::remove_method( const std::string& name ) 17 | { 18 | _methods.erase(name); 19 | } 20 | 21 | variant state::local_call( const string& method_name, const variants& args ) 22 | { 23 | auto method_itr = _methods.find(method_name); 24 | if( method_itr == _methods.end() && _unhandled ) 25 | return _unhandled( method_name, args ); 26 | FC_ASSERT( method_itr != _methods.end(), "Unknown Method: ${name}", ("name",method_name) ); 27 | return method_itr->second(args); 28 | } 29 | 30 | void state::handle_reply( const response& response ) 31 | { 32 | FC_ASSERT( response.id, "Response without ID: ${response}", ("response",response) ); 33 | auto await = _awaiting.find( *response.id ); 34 | FC_ASSERT( await != _awaiting.end(), "Unknown Response ID: ${id}", ("id",response.id)("response",response) ); 35 | if( response.result ) 36 | await->second->set_value( *response.result ); 37 | else if( response.error ) 38 | { 39 | await->second->set_exception( exception_ptr(new FC_EXCEPTION( exception, "${error}", ("error",response.error->message)("data",response) ) ) ); 40 | } 41 | else 42 | await->second->set_value( fc::variant() ); 43 | _awaiting.erase(await); 44 | } 45 | 46 | request state::start_remote_call( const string& method_name, variants args ) 47 | { 48 | request request{ _next_id++, method_name, std::move(args) }; 49 | _awaiting[*request.id] = fc::promise::create("json_connection::async_call"); 50 | return request; 51 | } 52 | variant state::wait_for_response( const variant& request_id ) 53 | { 54 | auto itr = _awaiting.find(request_id); 55 | FC_ASSERT( itr != _awaiting.end() ); 56 | return fc::future( itr->second ).wait(); 57 | } 58 | void state::close() 59 | { 60 | for( auto item : _awaiting ) 61 | item.second->set_exception( fc::exception_ptr(new FC_EXCEPTION( eof_exception, "connection closed" )) ); 62 | _awaiting.clear(); 63 | } 64 | void state::on_unhandled( const std::function& unhandled ) 65 | { 66 | _unhandled = unhandled; 67 | } 68 | 69 | } } // namespace fc::rpc 70 | -------------------------------------------------------------------------------- /include/fc/crypto/bigint.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | struct bignum_st; 7 | typedef bignum_st BIGNUM; 8 | 9 | namespace fc { 10 | class bigint { 11 | public: 12 | bigint( const std::vector& bige ); 13 | bigint( const char* bige, uint32_t l ); 14 | bigint(uint64_t value); 15 | bigint( ); 16 | bigint( const bigint& c ); 17 | bigint( bigint&& c ); 18 | explicit bigint( BIGNUM* n ); 19 | ~bigint(); 20 | 21 | bigint& operator = ( const bigint& a ); 22 | bigint& operator = ( bigint&& a ); 23 | 24 | explicit operator bool()const; 25 | 26 | bool is_negative()const; 27 | int64_t to_int64()const; 28 | 29 | int64_t log2()const; 30 | bigint exp( const bigint& c )const; 31 | 32 | static bigint random( uint32_t bits, int t, int ); 33 | 34 | bool operator < ( const bigint& c )const; 35 | bool operator > ( const bigint& c )const; 36 | bool operator >= ( const bigint& c )const; 37 | bool operator == ( const bigint& c )const; 38 | bool operator != ( const bigint& c )const; 39 | 40 | bigint operator + ( const bigint& a )const; 41 | bigint operator * ( const bigint& a )const; 42 | bigint operator / ( const bigint& a )const; 43 | bigint operator % ( const bigint& a )const; 44 | bigint operator /= ( const bigint& a ); 45 | bigint operator *= ( const bigint& a ); 46 | bigint& operator += ( const bigint& a ); 47 | bigint& operator -= ( const bigint& a ); 48 | bigint& operator <<= ( uint32_t i ); 49 | bigint& operator >>= ( uint32_t i ); 50 | bigint operator - ( const bigint& a )const; 51 | 52 | 53 | bigint operator++(int); 54 | bigint& operator++(); 55 | bigint operator--(int); 56 | bigint& operator--(); 57 | 58 | operator std::string()const; 59 | 60 | // returns bignum as bigendian bytes 61 | operator std::vector()const; 62 | 63 | BIGNUM* dup()const; 64 | 65 | BIGNUM* get()const { return n; } 66 | private: 67 | BIGNUM* n; 68 | }; 69 | 70 | class variant; 71 | /** encodes the big int as base64 string, or a number */ 72 | void to_variant( const bigint& bi, variant& v, uint32_t max_depth = 1 ); 73 | /** decodes the big int as base64 string, or a number */ 74 | void from_variant( const variant& v, bigint& bi, uint32_t max_depth = 1 ); 75 | } // namespace fc 76 | 77 | -------------------------------------------------------------------------------- /include/fc/rpc/state.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace fc { namespace rpc { 7 | struct request 8 | { 9 | optional id; 10 | std::string method; 11 | variants params; 12 | optional jsonrpc; 13 | }; 14 | 15 | struct error_object 16 | { 17 | int64_t code; 18 | std::string message; 19 | optional data; 20 | }; 21 | 22 | struct response 23 | { 24 | response() {} 25 | response( const optional& _id, const variant& _result, 26 | const optional& version = optional() ) 27 | : id(_id), jsonrpc(version), result(_result) {} 28 | response( const optional& _id, const error_object& error, 29 | const optional& version = optional() ) 30 | : id(_id), jsonrpc(version), error(error) {} 31 | optional id; 32 | optional jsonrpc; 33 | optional result; 34 | optional error; 35 | }; 36 | 37 | class state 38 | { 39 | public: 40 | typedef std::function method; 41 | ~state(); 42 | 43 | void add_method( const std::string& name, method m ); 44 | void remove_method( const std::string& name ); 45 | 46 | variant local_call( const string& method_name, const variants& args ); 47 | void handle_reply( const response& response ); 48 | 49 | request start_remote_call( const string& method_name, variants args ); 50 | variant wait_for_response( const variant& request_id ); 51 | 52 | void close(); 53 | 54 | void on_unhandled( const std::function& unhandled ); 55 | 56 | private: 57 | uint64_t _next_id = 1; 58 | std::map::ptr> _awaiting; 59 | std::unordered_map _methods; 60 | std::function _unhandled; 61 | }; 62 | } } // namespace fc::rpc 63 | 64 | FC_REFLECT( fc::rpc::request, (id)(method)(params)(jsonrpc) ); 65 | FC_REFLECT( fc::rpc::error_object, (code)(message)(data) ) 66 | FC_REFLECT( fc::rpc::response, (id)(jsonrpc)(result)(error) ) 67 | -------------------------------------------------------------------------------- /include/fc/io/buffered_iostream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace fc 5 | { 6 | namespace detail 7 | { 8 | class buffered_istream_impl; 9 | class buffered_ostream_impl; 10 | } 11 | 12 | /** 13 | * @brief Reads data from an unbuffered stream 14 | * and enables peek functionality. 15 | */ 16 | class buffered_istream : public virtual istream 17 | { 18 | public: 19 | buffered_istream( istream_ptr is ); 20 | buffered_istream( buffered_istream&& o ); 21 | 22 | buffered_istream& operator=( buffered_istream&& i ); 23 | 24 | virtual ~buffered_istream(); 25 | 26 | /** read at least 1 byte or throw, if no data is available 27 | * this method should block cooperatively until data is 28 | * available or fc::eof_exception is thrown. 29 | * 30 | * @pre len > 0 31 | * @pre buf != nullptr 32 | * @throws fc::eof if at least 1 byte cannot be read 33 | **/ 34 | virtual size_t readsome( char* buf, size_t len ); 35 | virtual size_t readsome( const std::shared_ptr& buf, size_t len, size_t offset ); 36 | 37 | /** 38 | * This method may block until at least 1 character is 39 | * available. 40 | */ 41 | virtual char peek() const; 42 | 43 | private: 44 | std::unique_ptr my; 45 | }; 46 | typedef std::shared_ptr buffered_istream_ptr; 47 | 48 | 49 | /** 50 | * 51 | */ 52 | class buffered_ostream : public virtual ostream 53 | { 54 | public: 55 | buffered_ostream( ostream_ptr o, size_t bufsize = 4096 ); 56 | buffered_ostream( buffered_ostream&& m ); 57 | ~buffered_ostream(); 58 | 59 | buffered_ostream& operator=( buffered_ostream&& m ); 60 | /** 61 | * This method will return immediately unless the buffer 62 | * is full, in which case it will flush which may block. 63 | */ 64 | virtual size_t writesome( const char* buf, size_t len ); 65 | virtual size_t writesome( const std::shared_ptr& buf, size_t len, size_t offset ); 66 | 67 | virtual void close(); 68 | virtual void flush(); 69 | private: 70 | std::unique_ptr my; 71 | }; 72 | typedef std::shared_ptr buffered_ostream_ptr; 73 | } 74 | -------------------------------------------------------------------------------- /tests/crypto/array_initialization_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 BitShares Blockchain Foundation, and contributors. 3 | * 4 | * The MIT License 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | static void check_null_key() 32 | { 33 | fc::ecc::public_key_data key1; 34 | fc::ecc::public_key_data key2; 35 | unsigned char zeroes[33]; 36 | static_assert( key1.size() == sizeof(zeroes), "Wrong array size!" ); 37 | memset( zeroes, 0, sizeof(zeroes) ); 38 | BOOST_CHECK( !memcmp( key1.data(), zeroes, sizeof(zeroes) ) ); 39 | BOOST_CHECK( !memcmp( key2.data(), zeroes, sizeof(zeroes) ) ); 40 | 41 | // now "pollute" the keys for the next invocation 42 | key1 = fc::ecc::private_key::generate().get_public_key(); 43 | for( unsigned char c = 0; c < key2.size(); c++ ) 44 | { 45 | key2[c] = c ^ 17; 46 | zeroes[c] = c ^ 47; 47 | } 48 | 49 | // ...and use them to prevent the compiler from optimizing the pollution away. 50 | wlog( "Key1: ${k}", ("k",fc::ecc::public_key::to_base58(key1)) ); 51 | wlog( "Key2: ${k}", ("k",fc::ecc::public_key::to_base58(key2)) ); 52 | } 53 | 54 | BOOST_AUTO_TEST_SUITE(fc_crypto) 55 | 56 | BOOST_AUTO_TEST_CASE(array_init_test) 57 | { 58 | check_null_key(); 59 | check_null_key(); 60 | { 61 | char junk[128]; 62 | fc::rand_bytes( junk, sizeof(junk) ); 63 | } 64 | check_null_key(); 65 | } 66 | 67 | BOOST_AUTO_TEST_SUITE_END() 68 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if( ECC_IMPL STREQUAL secp256k1 ) 2 | add_executable( blind all_tests.cpp crypto/blind.cpp ) 3 | target_link_libraries( blind fc ) 4 | endif() 5 | 6 | add_executable( task_cancel_test all_tests.cpp thread/task_cancel.cpp ) 7 | target_link_libraries( task_cancel_test fc ) 8 | 9 | 10 | add_executable( bloom_test all_tests.cpp bloom_test.cpp ) 11 | target_link_libraries( bloom_test fc ) 12 | 13 | add_executable( hmac_test hmac_test.cpp ) 14 | target_link_libraries( hmac_test fc ) 15 | 16 | add_executable( ecc_test crypto/ecc_test.cpp ) 17 | target_link_libraries( ecc_test fc ) 18 | 19 | add_executable( ws_test_server ws_test_server.cpp ) 20 | target_link_libraries( ws_test_server fc ) 21 | 22 | add_executable( ws_test_client ws_test_client.cpp ) 23 | target_link_libraries( ws_test_client fc ) 24 | 25 | #add_executable( test_aes aes_test.cpp ) 26 | #target_link_libraries( test_aes fc ${rt_library} ${pthread_library} ) 27 | #add_executable( test_sleep sleep.cpp ) 28 | #target_link_libraries( test_sleep fc ) 29 | #add_executable( test_rate_limiting rate_limiting.cpp ) 30 | #target_link_libraries( test_rate_limiting fc ) 31 | 32 | add_executable( all_tests all_tests.cpp 33 | compress/compress.cpp 34 | crypto/aes_test.cpp 35 | crypto/array_initialization_test.cpp 36 | crypto/base_n_tests.cpp 37 | crypto/bigint_test.cpp 38 | crypto/blind.cpp 39 | crypto/dh_test.cpp 40 | crypto/rand_test.cpp 41 | crypto/sha_tests.cpp 42 | io/json_tests.cpp 43 | io/stream_tests.cpp 44 | io/tcp_test.cpp 45 | io/varint_tests.cpp 46 | network/ip_tests.cpp 47 | network/http/websocket_test.cpp 48 | thread/task_cancel.cpp 49 | thread/thread_tests.cpp 50 | thread/parallel_tests.cpp 51 | bloom_test.cpp 52 | reflection_tests.cpp 53 | safe_tests.cpp 54 | serialization_test.cpp 55 | stacktrace_test.cpp 56 | time_test.cpp 57 | utf8_test.cpp 58 | variant_test.cpp 59 | logging_tests.cpp 60 | api_tests.cpp 61 | ) 62 | target_link_libraries( all_tests fc ) 63 | -------------------------------------------------------------------------------- /include/fc/crypto/sha512.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace fc 7 | { 8 | 9 | class sha512 10 | { 11 | public: 12 | sha512(); 13 | explicit sha512( const std::string& hex_str ); 14 | 15 | std::string str()const; 16 | operator std::string()const; 17 | 18 | char* data()const; 19 | static constexpr size_t data_size() { return 512 / 8; } 20 | 21 | static sha512 hash( const char* d, uint32_t dlen ); 22 | static sha512 hash( const std::string& ); 23 | 24 | template 25 | static sha512 hash( const T& t ) 26 | { 27 | sha512::encoder e; 28 | e << t; 29 | return e.result(); 30 | } 31 | 32 | class encoder 33 | { 34 | public: 35 | encoder(); 36 | ~encoder(); 37 | 38 | void write( const char* d, uint32_t dlen ); 39 | void put( char c ) { write( &c, 1 ); } 40 | void reset(); 41 | sha512 result(); 42 | 43 | private: 44 | struct impl; 45 | fc::fwd my; 46 | }; 47 | 48 | template 49 | inline friend T& operator<<( T& ds, const sha512& ep ) { 50 | ds.write( ep.data(), sizeof(ep) ); 51 | return ds; 52 | } 53 | 54 | template 55 | inline friend T& operator>>( T& ds, sha512& ep ) { 56 | ds.read( ep.data(), sizeof(ep) ); 57 | return ds; 58 | } 59 | friend sha512 operator << ( const sha512& h1, uint32_t i ); 60 | friend bool operator == ( const sha512& h1, const sha512& h2 ); 61 | friend bool operator != ( const sha512& h1, const sha512& h2 ); 62 | friend sha512 operator ^ ( const sha512& h1, const sha512& h2 ); 63 | friend bool operator >= ( const sha512& h1, const sha512& h2 ); 64 | friend bool operator > ( const sha512& h1, const sha512& h2 ); 65 | friend bool operator < ( const sha512& h1, const sha512& h2 ); 66 | 67 | boost::endian::little_uint64_buf_t _hash[8]; 68 | }; 69 | 70 | namespace raw { 71 | 72 | template 73 | inline void pack( T& ds, const sha512& ep, uint32_t _max_depth ) { 74 | ds << ep; 75 | } 76 | 77 | template 78 | inline void unpack( T& ds, sha512& ep, uint32_t _max_depth ) { 79 | ds >> ep; 80 | } 81 | 82 | } 83 | 84 | typedef fc::sha512 uint512; 85 | 86 | class variant; 87 | void to_variant( const sha512& bi, variant& v, uint32_t max_depth ); 88 | void from_variant( const variant& v, sha512& bi, uint32_t max_depth ); 89 | 90 | } // fc 91 | 92 | #include 93 | FC_REFLECT_TYPENAME( fc::sha512 ) 94 | -------------------------------------------------------------------------------- /src/thread/thread_specific.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "thread_d.hpp" 4 | #include 5 | 6 | namespace fc 7 | { 8 | namespace detail 9 | { 10 | boost::atomic thread_specific_slot_counter; 11 | unsigned get_next_unused_thread_storage_slot() 12 | { 13 | return thread_specific_slot_counter.fetch_add(1); 14 | } 15 | 16 | void* get_specific_data(std::vector *specific_data, unsigned slot) 17 | { 18 | return slot < specific_data->size() ? 19 | (*specific_data)[slot].value : nullptr; 20 | } 21 | void set_specific_data(std::vector *specific_data, unsigned slot, void* new_value, void(*cleanup)(void*)) 22 | { 23 | if (slot + 1 > specific_data->size()) 24 | specific_data->resize(slot + 1); 25 | (*specific_data)[slot] = detail::specific_data_info(new_value, cleanup); 26 | } 27 | 28 | void* get_thread_specific_data(unsigned slot) 29 | { 30 | return get_specific_data(&thread::current().my->thread_specific_data, slot); 31 | } 32 | void set_thread_specific_data(unsigned slot, void* new_value, void(*cleanup)(void*)) 33 | { 34 | return set_specific_data(&thread::current().my->thread_specific_data, slot, new_value, cleanup); 35 | } 36 | 37 | unsigned get_next_unused_task_storage_slot() 38 | { 39 | return thread::current().my->next_unused_task_storage_slot++; 40 | } 41 | void* get_task_specific_data(unsigned slot) 42 | { 43 | context* current_context = thread::current().my->current; 44 | if (!current_context || 45 | !current_context->cur_task) 46 | return get_specific_data(&thread::current().my->non_task_specific_data, slot); 47 | if (current_context->cur_task->_task_specific_data) 48 | return get_specific_data(current_context->cur_task->_task_specific_data, slot); 49 | return nullptr; 50 | } 51 | void set_task_specific_data(unsigned slot, void* new_value, void(*cleanup)(void*)) 52 | { 53 | context* current_context = thread::current().my->current; 54 | if (!current_context || 55 | !current_context->cur_task) 56 | set_specific_data(&thread::current().my->non_task_specific_data, slot, new_value, cleanup); 57 | else 58 | { 59 | if (!current_context->cur_task->_task_specific_data) 60 | current_context->cur_task->_task_specific_data = new std::vector; 61 | set_specific_data(current_context->cur_task->_task_specific_data, slot, new_value, cleanup); 62 | } 63 | } 64 | } 65 | } // end namespace fc 66 | -------------------------------------------------------------------------------- /tests/crypto/bigint_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | BOOST_AUTO_TEST_SUITE(fc_crypto) 7 | 8 | BOOST_AUTO_TEST_CASE(bigint_test_1) 9 | { 10 | int64_t counter = 0, accu = 0, c_sq; 11 | fc::bigint bi_accu(accu); 12 | do { 13 | c_sq = counter * counter; 14 | fc::bigint add(c_sq); 15 | bi_accu += add; 16 | accu += c_sq; 17 | BOOST_CHECK( fc::bigint(accu) == bi_accu ); 18 | 19 | bi_accu = bi_accu + add; 20 | accu = accu + c_sq; 21 | BOOST_CHECK_EQUAL( accu, bi_accu.to_int64() ); 22 | 23 | bi_accu = fc::bigint( bi_accu.dup() ); 24 | 25 | counter++; 26 | } while (c_sq < 1000000); 27 | 28 | fc::variant test; 29 | fc::to_variant( bi_accu, test ); 30 | fc::bigint other; 31 | fc::from_variant( test, other ); 32 | BOOST_CHECK( other == bi_accu ); 33 | } 34 | 35 | BOOST_AUTO_TEST_CASE(bigint_test_2) 36 | { 37 | const fc::bigint bi_1(1), bi_3(3), bi_17(17), bi_65537(65537); 38 | fc::bigint bi_accu(bi_1); 39 | do { 40 | std::vector bytes = bi_accu; 41 | fc::bigint a_1( bytes ); 42 | a_1 = a_1 + bi_1; 43 | BOOST_CHECK( bi_accu < a_1 ); 44 | 45 | bi_accu = a_1 * bi_accu; 46 | BOOST_CHECK( bi_accu >= a_1 ); 47 | } while ( bi_accu.log2() <= 128 ); 48 | 49 | // Test self-assignment (a=a) has no effect, but throw in some arcanity to avoid a compiler warning 50 | const volatile auto* bi_accu_self = &bi_accu; 51 | bi_accu = const_cast(*bi_accu_self); 52 | 53 | BOOST_CHECK( bi_accu && !bi_accu.is_negative() && bi_accu != bi_1 ); 54 | 55 | BOOST_CHECK( bi_3.exp( bi_accu.log2() ) > bi_accu ); 56 | 57 | fc::bigint big(1); 58 | big <<= 30; big += bi_17; big <<= 30; big++; 59 | big <<= 30; big -= bi_17; big >>= 5; big--; 60 | fc::bigint rest = bi_accu % big; 61 | BOOST_CHECK( (bi_accu - rest) / big == bi_accu / big ); 62 | 63 | fc::bigint big2; big2 = big; 64 | big2 *= bi_65537.exp(3); 65 | big2 /= bi_65537.exp(3); 66 | BOOST_CHECK( big2 == big ); 67 | big--; 68 | 69 | BOOST_CHECK_EQUAL( (std::string) bi_1, "1" ); 70 | BOOST_CHECK_EQUAL( (std::string) bi_3, "3" ); 71 | BOOST_CHECK_EQUAL( (std::string) bi_17, "17" ); 72 | BOOST_CHECK_EQUAL( (std::string) bi_65537, "65537" ); 73 | BOOST_CHECK_EQUAL( (std::string) bi_65537.exp(3), "281487861809153" ); 74 | BOOST_CHECK_EQUAL( (std::string) bi_accu, "12864938683278671740537145998360961546653259485195806" ); 75 | BOOST_CHECK_EQUAL( (std::string) big, "38685626840157682946539517" ); 76 | } 77 | 78 | BOOST_AUTO_TEST_SUITE_END() 79 | 80 | -------------------------------------------------------------------------------- /include/fc/network/http/connection.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace fc { 7 | namespace ip { class endpoint; } 8 | class tcp_socket; 9 | 10 | namespace http { 11 | 12 | struct header 13 | { 14 | header( std::string k, std::string v ) 15 | :key(std::move(k)),val(std::move(v)){} 16 | header(){} 17 | std::string key; 18 | std::string val; 19 | }; 20 | 21 | typedef std::vector
headers; 22 | 23 | struct reply 24 | { 25 | enum status_code { 26 | OK = 200, 27 | RecordCreated = 201, 28 | NoContent = 204, 29 | BadRequest = 400, 30 | NotAuthorized = 401, 31 | NotFound = 404, 32 | Found = 302, 33 | InternalServerError = 500 34 | }; 35 | reply( status_code c = OK):status(c){} 36 | int status; 37 | std::vector
headers; 38 | std::vector body; 39 | std::string body_as_string; 40 | }; 41 | 42 | struct request 43 | { 44 | std::string get_header( const std::string& key )const; 45 | std::string remote_endpoint; 46 | std::string method; 47 | std::string domain; 48 | std::string path; 49 | std::vector
headers; 50 | std::vector body; 51 | }; 52 | 53 | std::vector
parse_urlencoded_params( const std::string& f ); 54 | 55 | /** 56 | * Connections have reference semantics, all copies refer to the same 57 | * underlying socket. 58 | */ 59 | class connection 60 | { 61 | public: 62 | connection(); 63 | ~connection(); 64 | // used for clients 65 | void connect_to( const fc::ip::endpoint& ep ); 66 | http::reply request( const std::string& method, const std::string& url, const std::string& body = std::string(), const headers& = headers()); 67 | 68 | // used for servers 69 | fc::tcp_socket& get_socket()const; 70 | 71 | http::request read_request()const; 72 | 73 | class impl; 74 | private: 75 | std::unique_ptr my; 76 | }; 77 | 78 | typedef std::shared_ptr connection_ptr; 79 | 80 | } } // fc::http 81 | 82 | #include 83 | FC_REFLECT( fc::http::header, (key)(val) ) 84 | FC_REFLECT( fc::http::reply, (status)(headers)(body)(body_as_string) ) 85 | -------------------------------------------------------------------------------- /include/fc/log/console_appender.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace fc 7 | { 8 | class console_appender : public appender 9 | { 10 | public: 11 | struct color 12 | { 13 | enum type { 14 | red, 15 | green, 16 | brown, 17 | blue, 18 | magenta, 19 | cyan, 20 | white, 21 | console_default, 22 | }; 23 | }; 24 | 25 | struct stream { enum type { std_out, std_error }; }; 26 | 27 | struct level_color 28 | { 29 | level_color( log_level l=log_level::all, 30 | color::type c=color::console_default ) 31 | :level(l),color(c){} 32 | 33 | log_level level; 34 | console_appender::color::type color; 35 | }; 36 | 37 | struct config 38 | { 39 | config() 40 | :format( "${timestamp} ${thread_name} ${context} ${file}:${line} ${method} ${level}] ${message}" ), 41 | stream(console_appender::stream::std_error),max_object_depth(FC_MAX_LOG_OBJECT_DEPTH),flush(true){} 42 | 43 | std::string format; 44 | console_appender::stream::type stream; 45 | std::vector level_colors; 46 | uint32_t max_object_depth; 47 | bool flush; 48 | }; 49 | 50 | 51 | console_appender( const variant& args ); 52 | console_appender( const config& cfg ); 53 | console_appender(); 54 | 55 | ~console_appender(); 56 | virtual void log( const log_message& m ); 57 | 58 | void print( const std::string& text_to_print, 59 | color::type text_color = color::console_default ); 60 | 61 | void configure( const config& cfg ); 62 | 63 | private: 64 | class impl; 65 | std::unique_ptr my; 66 | }; 67 | } // namespace fc 68 | 69 | #include 70 | FC_REFLECT_ENUM( fc::console_appender::stream::type, (std_out)(std_error) ) 71 | FC_REFLECT_ENUM( fc::console_appender::color::type, (red)(green)(brown)(blue)(magenta)(cyan)(white)(console_default) ) 72 | FC_REFLECT( fc::console_appender::level_color, (level)(color) ) 73 | FC_REFLECT( fc::console_appender::config, (format)(stream)(level_colors)(max_object_depth)(flush) ) 74 | -------------------------------------------------------------------------------- /include/fc/network/tcp_socket.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace fc { 10 | namespace ip { class endpoint; } 11 | 12 | class tcp_socket_io_hooks; 13 | 14 | class tcp_socket : public virtual iostream 15 | { 16 | public: 17 | tcp_socket(); 18 | tcp_socket( tcp_socket& copy ) = delete; 19 | ~tcp_socket(); 20 | tcp_socket& operator=( tcp_socket& copy ) = delete; 21 | 22 | void connect_to( const fc::ip::endpoint& remote_endpoint ); 23 | void bind( const fc::ip::endpoint& local_endpoint ); 24 | void enable_keep_alives(const fc::microseconds& interval); 25 | void set_io_hooks(tcp_socket_io_hooks* new_hooks); 26 | void set_reuse_address(bool enable = true); // set SO_REUSEADDR 27 | fc::ip::endpoint remote_endpoint() const; 28 | fc::ip::endpoint local_endpoint() const; 29 | 30 | using istream::get; 31 | void get( char& c ) 32 | { 33 | read( &c, 1 ); 34 | } 35 | 36 | 37 | /// istream interface 38 | /// @{ 39 | virtual size_t readsome( char* buffer, size_t max ); 40 | virtual size_t readsome(const std::shared_ptr& buffer, size_t max, size_t offset); 41 | virtual bool eof()const; 42 | /// @} 43 | 44 | /// ostream interface 45 | /// @{ 46 | virtual size_t writesome( const char* buffer, size_t len ); 47 | virtual size_t writesome(const std::shared_ptr& buffer, size_t len, size_t offset); 48 | virtual void flush(); 49 | virtual void close(); 50 | /// @} 51 | 52 | void open(); 53 | bool is_open()const; 54 | 55 | private: 56 | friend class tcp_server; 57 | class impl; 58 | fc::fwd) + 61 | sizeof(fc::future) + 62 | sizeof(boost::asio::ip::tcp::socket) + 63 | sizeof(tcp_socket_io_hooks*) 64 | > my; 65 | 66 | }; 67 | typedef std::shared_ptr tcp_socket_ptr; 68 | 69 | 70 | class tcp_server 71 | { 72 | public: 73 | tcp_server(); 74 | ~tcp_server(); 75 | 76 | void close(); 77 | void accept( tcp_socket& s ); 78 | void set_reuse_address(bool enable = true); // set SO_REUSEADDR, call before listen 79 | void listen( uint16_t port ); 80 | void listen( const fc::ip::endpoint& ep ); 81 | fc::ip::endpoint get_local_endpoint() const; 82 | uint16_t get_port()const; 83 | private: 84 | // non copyable 85 | tcp_server( const tcp_server& ); 86 | tcp_server& operator=(const tcp_server& s ); 87 | 88 | class impl; 89 | impl* my; 90 | }; 91 | 92 | } // namesapce fc 93 | 94 | -------------------------------------------------------------------------------- /tests/crypto/aes_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | BOOST_AUTO_TEST_SUITE(fc_crypto) 12 | 13 | BOOST_AUTO_TEST_CASE(aes_test) 14 | { 15 | std::ifstream testfile; 16 | testfile.open("README.md"); 17 | 18 | auto key = fc::sha512::hash( "hello", 5 ); 19 | std::stringstream buffer; 20 | std::string line; 21 | std::getline( testfile, line ); 22 | while( testfile.good() ) 23 | { 24 | // std::cout << line << "\n"; 25 | buffer << line << "\n"; 26 | try { 27 | std::vector data( line.c_str(),line.c_str()+line.size()+1 ); 28 | std::vector crypt = fc::aes_encrypt( key, data ); 29 | std::vector dcrypt = fc::aes_decrypt( key, crypt ); 30 | BOOST_CHECK( data == dcrypt ); 31 | 32 | // memset( crypt.data(), 0, crypt.size() ); 33 | // fc::aes_encoder enc; 34 | // enc.init( fc::sha256::hash((char*)&key,sizeof(key) ), fc::city_hash_crc_128( (char*)&key, sizeof(key) ) ); 35 | // auto len = enc.encode( dcrypt.data(), dcrypt.size(), crypt.data() ); 36 | // BOOST_CHECK_EQUAL( dcrypt.size(), len ); 37 | // 38 | // fc::aes_decoder dec; 39 | // dec.init( fc::sha256::hash((char*)&key,sizeof(key) ), fc::city_hash_crc_128( (char*)&key, sizeof(key) ) ); 40 | // len = dec.decode( crypt.data(), len, dcrypt.data() ); 41 | // BOOST_CHECK_EQUAL( dcrypt.size(), len ); 42 | // BOOST_CHECK( !memcmp( dcrypt.data(), data.data(), len) ); 43 | } 44 | catch ( fc::exception& e ) 45 | { 46 | std::cout< data( line.c_str(),line.c_str()+line.size()+1 ); 53 | std::vector crypt = fc::aes_encrypt( key, data ); 54 | std::vector dcrypt = fc::aes_decrypt( key, crypt ); 55 | BOOST_CHECK( data == dcrypt ); 56 | 57 | // memset( crypt.data(), 0, crypt.size() ); 58 | // fc::aes_encoder enc; 59 | // enc.init( fc::sha256::hash((char*)&key,sizeof(key) ), fc::city_hash_crc_128( (char*)&key, sizeof(key) ) ); 60 | // auto len = enc.encode( dcrypt.data(), dcrypt.size(), crypt.data() ); 61 | // BOOST_CHECK_EQUAL( dcrypt.size(), len ); 62 | // 63 | // fc::aes_decoder dec; 64 | // dec.init( fc::sha256::hash((char*)&key,sizeof(key) ), fc::city_hash_crc_128( (char*)&key, sizeof(key) ) ); 65 | // len = dec.decode( crypt.data(), len, dcrypt.data() ); 66 | // BOOST_CHECK_EQUAL( dcrypt.size(), len ); 67 | // BOOST_CHECK( !memcmp( dcrypt.data(), data.data(), len) ); 68 | } 69 | 70 | BOOST_AUTO_TEST_SUITE_END() 71 | -------------------------------------------------------------------------------- /include/fc/io/varint.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace fc { 5 | 6 | struct unsigned_int { 7 | unsigned_int( uint64_t v = 0 ):value(v){} 8 | 9 | template 10 | unsigned_int( T v ):value(v){} 11 | 12 | template 13 | operator T()const { return static_cast(value); } 14 | 15 | unsigned_int& operator=( uint64_t v ) { value = v; return *this; } 16 | 17 | uint64_t value; 18 | 19 | friend bool operator==( const unsigned_int& i, const uint64_t& v ) { return i.value == v; } 20 | friend bool operator==( const uint64_t& i, const unsigned_int& v ) { return i == v.value; } 21 | friend bool operator==( const unsigned_int& i, const unsigned_int& v ) { return i.value == v.value; } 22 | 23 | friend bool operator!=( const unsigned_int& i, const uint64_t& v ) { return i.value != v; } 24 | friend bool operator!=( const uint64_t& i, const unsigned_int& v ) { return i != v.value; } 25 | friend bool operator!=( const unsigned_int& i, const unsigned_int& v ) { return i.value != v.value; } 26 | 27 | friend bool operator<( const unsigned_int& i, const uint64_t& v ) { return i.value < v; } 28 | friend bool operator<( const uint64_t& i, const unsigned_int& v ) { return i < v.value; } 29 | friend bool operator<( const unsigned_int& i, const unsigned_int& v ) { return i.value < v.value; } 30 | 31 | friend bool operator<=( const unsigned_int& i, const uint64_t& v ) { return i.value <= v; } 32 | friend bool operator<=( const uint64_t& i, const unsigned_int& v ) { return i <= v.value; } 33 | friend bool operator<=( const unsigned_int& i, const unsigned_int& v ) { return i.value <= v.value; } 34 | 35 | friend bool operator>( const unsigned_int& i, const uint64_t& v ) { return i.value > v; } 36 | friend bool operator>( const uint64_t& i, const unsigned_int& v ) { return i > v.value; } 37 | friend bool operator>( const unsigned_int& i, const unsigned_int& v ) { return i.value > v.value; } 38 | 39 | friend bool operator>=( const unsigned_int& i, const uint64_t& v ) { return i.value >= v; } 40 | friend bool operator>=( const uint64_t& i, const unsigned_int& v ) { return i >= v.value; } 41 | friend bool operator>=( const unsigned_int& i, const unsigned_int& v ) { return i.value >= v.value; } 42 | }; 43 | 44 | class variant; 45 | 46 | void to_variant( const unsigned_int& var, variant& vo, uint32_t max_depth = 1 ); 47 | void from_variant( const variant& var, unsigned_int& vo, uint32_t max_depth = 1 ); 48 | 49 | } // namespace fc 50 | 51 | #include 52 | namespace std 53 | { 54 | template<> 55 | struct hash 56 | { 57 | public: 58 | size_t operator()(const fc::unsigned_int &a) const 59 | { 60 | return std::hash()(a.value); 61 | } 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /.github/workflows/build-and-test-ubuntu-debug.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu Debug 2 | on: [ push, pull_request ] 3 | env: 4 | CCACHE_COMPRESS: exists means true 5 | CCACHE_SLOPPINESS: include_file_ctime,include_file_mtime,time_macros 6 | jobs: 7 | test-debug: 8 | name: Build and run tests in Debug mode 9 | strategy: 10 | matrix: 11 | os: [ ubuntu-20.04 ] 12 | runs-on: ${{ matrix.os }} 13 | steps: 14 | - name: Install dependencies 15 | run: | 16 | sudo apt-get update 17 | openssl_ver=`sudo apt-cache madison openssl | grep xenial-updates | awk '{print $3}'` 18 | libssl_ver=`sudo apt-cache madison libssl-dev | grep xenial-updates | awk '{print $3}'` 19 | [ -n "${openssl_ver}" ] && [ -n "${libssl_ver}" ] && \ 20 | sudo apt-get install -y --allow-downgrades openssl=${openssl_ver} libssl-dev=${libssl_ver} 21 | sudo apt-get install -y \ 22 | ccache \ 23 | parallel \ 24 | libboost-thread-dev \ 25 | libboost-iostreams-dev \ 26 | libboost-date-time-dev \ 27 | libboost-system-dev \ 28 | libboost-filesystem-dev \ 29 | libboost-program-options-dev \ 30 | libboost-chrono-dev \ 31 | libboost-test-dev \ 32 | libboost-context-dev \ 33 | libboost-regex-dev \ 34 | libboost-coroutine-dev 35 | - uses: actions/checkout@v3 36 | with: 37 | submodules: recursive 38 | - name: Configure 39 | run: | 40 | mkdir -p _build 41 | pushd _build 42 | export -n BOOST_ROOT BOOST_INCLUDEDIR BOOST_LIBRARYDIR 43 | cmake -D CMAKE_BUILD_TYPE=Debug \ 44 | -D CMAKE_CXX_OUTPUT_EXTENSION_REPLACE=ON \ 45 | -D CMAKE_C_COMPILER=gcc \ 46 | -D CMAKE_C_COMPILER_LAUNCHER=ccache \ 47 | -D CMAKE_CXX_COMPILER=g++ \ 48 | -D CMAKE_CXX_COMPILER_LAUNCHER=ccache \ 49 | .. 50 | popd 51 | - name: Load Cache 52 | uses: actions/cache@v3 53 | with: 54 | path: ccache 55 | key: ccache-debug-${{ matrix.os }}-${{ github.ref }}-${{ github.sha }} 56 | restore-keys: | 57 | ccache-debug-${{ matrix.os }}-${{ github.ref }}- 58 | ccache-debug-${{ matrix.os }}- 59 | - name: Build 60 | run: | 61 | export CCACHE_DIR="$GITHUB_WORKSPACE/ccache" 62 | mkdir -p "$CCACHE_DIR" 63 | make -j 2 -C _build 64 | - name: Test 65 | run: | 66 | parallel echo Running {}\; sh -c "./{}" <<_EOT_ 67 | tests/run-parallel-tests.sh _build/tests/all_tests -l test_suite 68 | _build/tests/bloom_test -- README.md 69 | _build/tests/ecc_test README.md 70 | _build/tests/hmac_test 71 | _build/tests/task_cancel_test 72 | _EOT_ 73 | -------------------------------------------------------------------------------- /.github/workflows/build-and-test-ubuntu-release.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu Release 2 | on: [ push, pull_request ] 3 | env: 4 | CCACHE_COMPRESS: exists means true 5 | CCACHE_SLOPPINESS: include_file_ctime,include_file_mtime,time_macros 6 | jobs: 7 | test-release: 8 | name: Build and run tests in Release mode 9 | strategy: 10 | matrix: 11 | os: [ ubuntu-20.04 ] 12 | runs-on: ${{ matrix.os }} 13 | steps: 14 | - name: Install dependencies 15 | run: | 16 | sudo apt-get update 17 | openssl_ver=`sudo apt-cache madison openssl | grep xenial-updates | awk '{print $3}'` 18 | libssl_ver=`sudo apt-cache madison libssl-dev | grep xenial-updates | awk '{print $3}'` 19 | [ -n "${openssl_ver}" ] && [ -n "${libssl_ver}" ] && \ 20 | sudo apt-get install -y --allow-downgrades openssl=${openssl_ver} libssl-dev=${libssl_ver} 21 | sudo apt-get install -y \ 22 | ccache \ 23 | parallel \ 24 | libboost-thread-dev \ 25 | libboost-iostreams-dev \ 26 | libboost-date-time-dev \ 27 | libboost-system-dev \ 28 | libboost-filesystem-dev \ 29 | libboost-program-options-dev \ 30 | libboost-chrono-dev \ 31 | libboost-test-dev \ 32 | libboost-context-dev \ 33 | libboost-regex-dev \ 34 | libboost-coroutine-dev 35 | - uses: actions/checkout@v3 36 | with: 37 | submodules: recursive 38 | - name: Configure 39 | run: | 40 | mkdir -p _build 41 | pushd _build 42 | export -n BOOST_ROOT BOOST_INCLUDEDIR BOOST_LIBRARYDIR 43 | cmake -D CMAKE_BUILD_TYPE=Release \ 44 | -D CMAKE_CXX_OUTPUT_EXTENSION_REPLACE=ON \ 45 | -D CMAKE_C_COMPILER=gcc \ 46 | -D CMAKE_C_COMPILER_LAUNCHER=ccache \ 47 | -D CMAKE_CXX_COMPILER=g++ \ 48 | -D CMAKE_CXX_COMPILER_LAUNCHER=ccache \ 49 | .. 50 | popd 51 | - name: Load Cache 52 | uses: actions/cache@v3 53 | with: 54 | path: ccache 55 | key: ccache-release-${{ matrix.os }}-${{ github.ref }}-${{ github.sha }} 56 | restore-keys: | 57 | ccache-release-${{ matrix.os }}-${{ github.ref }}- 58 | ccache-release-${{ matrix.os }}- 59 | - name: Build 60 | run: | 61 | export CCACHE_DIR="$GITHUB_WORKSPACE/ccache" 62 | mkdir -p "$CCACHE_DIR" 63 | make -j 2 -C _build 64 | - name: Test 65 | run: | 66 | parallel echo Running {}\; sh -c "./{}" <<_EOT_ 67 | tests/run-parallel-tests.sh _build/tests/all_tests -l test_suite 68 | _build/tests/bloom_test -- README.md 69 | _build/tests/ecc_test README.md 70 | _build/tests/hmac_test 71 | _build/tests/task_cancel_test 72 | _EOT_ 73 | -------------------------------------------------------------------------------- /include/fc/crypto/sha1.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace fc{ 9 | 10 | class sha1 11 | { 12 | public: 13 | sha1(); 14 | explicit sha1( const std::string& hex_str ); 15 | 16 | std::string str()const; 17 | operator std::string()const; 18 | 19 | char* data()const; 20 | static constexpr size_t data_size() { return 20; } 21 | 22 | static sha1 hash( const char* d, uint32_t dlen ); 23 | static sha1 hash( const std::string& ); 24 | 25 | template 26 | static sha1 hash( const T& t ) 27 | { 28 | sha1::encoder e; 29 | e << t; 30 | return e.result(); 31 | } 32 | 33 | class encoder 34 | { 35 | public: 36 | encoder(); 37 | ~encoder(); 38 | 39 | void write( const char* d, uint32_t dlen ); 40 | void put( char c ) { write( &c, 1 ); } 41 | void reset(); 42 | sha1 result(); 43 | 44 | private: 45 | struct impl; 46 | fc::fwd my; 47 | }; 48 | 49 | template 50 | inline friend T& operator<<( T& ds, const sha1& ep ) { 51 | ds.write( ep.data(), sizeof(ep) ); 52 | return ds; 53 | } 54 | 55 | template 56 | inline friend T& operator>>( T& ds, sha1& ep ) { 57 | ds.read( ep.data(), sizeof(ep) ); 58 | return ds; 59 | } 60 | friend sha1 operator << ( const sha1& h1, uint32_t i ); 61 | friend bool operator == ( const sha1& h1, const sha1& h2 ); 62 | friend bool operator != ( const sha1& h1, const sha1& h2 ); 63 | friend sha1 operator ^ ( const sha1& h1, const sha1& h2 ); 64 | friend bool operator >= ( const sha1& h1, const sha1& h2 ); 65 | friend bool operator > ( const sha1& h1, const sha1& h2 ); 66 | friend bool operator < ( const sha1& h1, const sha1& h2 ); 67 | 68 | boost::endian::little_uint32_buf_t _hash[5]; 69 | }; 70 | 71 | namespace raw { 72 | 73 | template 74 | inline void pack( T& ds, const sha1& ep, uint32_t _max_depth ) { 75 | ds << ep; 76 | } 77 | 78 | template 79 | inline void unpack( T& ds, sha1& ep, uint32_t _max_depth ) { 80 | ds >> ep; 81 | } 82 | 83 | } 84 | 85 | class variant; 86 | void to_variant( const sha1& bi, variant& v, uint32_t max_depth ); 87 | void from_variant( const variant& v, sha1& bi, uint32_t max_depth ); 88 | 89 | } // namespace fc 90 | 91 | namespace std 92 | { 93 | template<> 94 | struct hash 95 | { 96 | size_t operator()( const fc::sha1& s )const 97 | { 98 | return *((size_t*)&s); 99 | } 100 | }; 101 | } 102 | 103 | #include 104 | FC_REFLECT_TYPENAME( fc::sha1 ) 105 | -------------------------------------------------------------------------------- /fc.natvis: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | *(const int64_t*)(&_data) 17 | *(const uint64_t*)(&_data) 18 | *(const double*)(&_data) 19 | *(const bool*)(&_data) 20 | *(const const_string_ptr*)(&_data) 21 | *(const const_variants_ptr*)(&_data) 22 | *(const const_variant_object_ptr*)(&_data) 23 | (fc::variant::type_id)(*(((char*)(&_data)) + sizeof(fc::variant) - 1)) 24 | 25 | 26 | 27 | 28 | {*($T1*)(((_store)._store)._data)} 29 | 30 | ($T1*)(((_store)._store)._data) 31 | 32 | 33 | 34 | 35 | 36 | invalid 37 | valid, value = {*(($T1*)_value)} 38 | 39 | ($T1*)_value 40 | _valid 41 | 42 | 43 | 44 | 45 | {_p} 46 | 47 | _p 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /include/fc/crypto/city.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 Google, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | // 21 | // CityHash, by Geoff Pike and Jyrki Alakuijala 22 | // 23 | // This file provides a few functions for hashing strings. On x86-64 24 | // hardware in 2011, CityHash64() is faster than other high-quality 25 | // hash functions, such as Murmur. This is largely due to higher 26 | // instruction-level parallelism. CityHash64() and CityHash128() also perform 27 | // well on hash-quality tests. 28 | // 29 | // CityHash128() is optimized for relatively long strings and returns 30 | // a 128-bit hash. For strings more than about 2000 bytes it can be 31 | // faster than CityHash64(). 32 | // 33 | // Functions in the CityHash family are not suitable for cryptography. 34 | // 35 | // WARNING: This code has not been tested on big-endian platforms! 36 | // It is known to work well on little-endian platforms that have a small penalty 37 | // for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs. 38 | // 39 | // By the way, for some hash functions, given strings a and b, the hash 40 | // of a+b is easily derived from the hashes of a and b. This property 41 | // doesn't hold for any hash functions in this file. 42 | #pragma once 43 | 44 | #include 45 | 46 | #include // for size_t. 47 | #include 48 | #include 49 | 50 | namespace fc { 51 | 52 | // Hash function for a byte array. 53 | uint64_t city_hash64(const char *buf, size_t len); 54 | 55 | #if SIZE_MAX > UINT32_MAX 56 | inline size_t city_hash_size_t(const char *buf, size_t len) { return city_hash64(buf, len); } 57 | #else 58 | uint32_t city_hash32(const char *buf, size_t len); 59 | inline size_t city_hash_size_t(const char *buf, size_t len) { return city_hash32(buf, len); } 60 | #endif 61 | 62 | // Hash function for a byte array. 63 | uint128_t city_hash_crc_128(const char *s, size_t len); 64 | 65 | } // namespace fc 66 | -------------------------------------------------------------------------------- /include/fc/crypto/sha224.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace fc 7 | { 8 | 9 | class sha224 10 | { 11 | public: 12 | sha224(); 13 | explicit sha224( const string& hex_str ); 14 | 15 | string str()const; 16 | operator string()const; 17 | 18 | char* data()const; 19 | static constexpr size_t data_size() { return 224 / 8; } 20 | 21 | static sha224 hash( const char* d, uint32_t dlen ); 22 | static sha224 hash( const string& ); 23 | 24 | template 25 | static sha224 hash( const T& t ) 26 | { 27 | sha224::encoder e; 28 | fc::raw::pack(e,t); 29 | return e.result(); 30 | } 31 | 32 | class encoder 33 | { 34 | public: 35 | encoder(); 36 | ~encoder(); 37 | 38 | void write( const char* d, uint32_t dlen ); 39 | void put( char c ) { write( &c, 1 ); } 40 | void reset(); 41 | sha224 result(); 42 | 43 | private: 44 | struct impl; 45 | fc::fwd my; 46 | }; 47 | 48 | template 49 | inline friend T& operator<<( T& ds, const sha224& ep ) { 50 | static_assert( sizeof(ep) == (8*3+4), "sha224 size mismatch" ); 51 | ds.write( ep.data(), sizeof(ep) ); 52 | return ds; 53 | } 54 | 55 | template 56 | inline friend T& operator>>( T& ds, sha224& ep ) { 57 | ds.read( ep.data(), sizeof(ep) ); 58 | return ds; 59 | } 60 | friend sha224 operator << ( const sha224& h1, uint32_t i ); 61 | friend bool operator == ( const sha224& h1, const sha224& h2 ); 62 | friend bool operator != ( const sha224& h1, const sha224& h2 ); 63 | friend sha224 operator ^ ( const sha224& h1, const sha224& h2 ); 64 | friend bool operator >= ( const sha224& h1, const sha224& h2 ); 65 | friend bool operator > ( const sha224& h1, const sha224& h2 ); 66 | friend bool operator < ( const sha224& h1, const sha224& h2 ); 67 | 68 | boost::endian::little_uint32_buf_t _hash[7]; 69 | }; 70 | 71 | namespace raw { 72 | 73 | template 74 | inline void pack( T& ds, const sha224& ep, uint32_t _max_depth ) { 75 | ds << ep; 76 | } 77 | 78 | template 79 | inline void unpack( T& ds, sha224& ep, uint32_t _max_depth ) { 80 | ds >> ep; 81 | } 82 | 83 | } 84 | 85 | class variant; 86 | void to_variant( const sha224& bi, variant& v, uint32_t max_depth ); 87 | void from_variant( const variant& v, sha224& bi, uint32_t max_depth ); 88 | 89 | } // fc 90 | namespace std 91 | { 92 | template<> 93 | struct hash 94 | { 95 | size_t operator()( const fc::sha224& s )const 96 | { 97 | return *((size_t*)&s); 98 | } 99 | }; 100 | } 101 | #include 102 | FC_REFLECT_TYPENAME( fc::sha224 ) 103 | -------------------------------------------------------------------------------- /tests/stacktrace_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | BOOST_AUTO_TEST_SUITE(fc_stacktrace) 14 | 15 | BOOST_AUTO_TEST_CASE(stacktrace_test) 16 | { 17 | // print the stack trace 18 | std::stringstream ss; 19 | fc::print_stacktrace(ss); 20 | std::string results = ss.str(); 21 | #if BOOST_VERSION / 100 >= 1065 && !defined(__APPLE__) 22 | BOOST_CHECK(!results.empty()); 23 | BOOST_CHECK(results.find("fc::print_stacktrace") != std::string::npos); 24 | #else 25 | BOOST_CHECK(results.empty()); 26 | #endif 27 | } 28 | 29 | BOOST_AUTO_TEST_CASE(threaded_stacktrace_test) 30 | { 31 | fc::thread test_thread("a_thread"); 32 | std::string results = test_thread.async( 33 | [] ()->std::string { 34 | // cause a pause 35 | for(int i = 0; i < 10000; i++); 36 | std::stringstream ss; 37 | fc::print_stacktrace(ss); 38 | return ss.str(); 39 | } 40 | ).wait(); 41 | #if BOOST_VERSION / 100 >= 1065 && !defined(__APPLE__) 42 | BOOST_CHECK(!results.empty()); 43 | BOOST_CHECK(results.find("fc::print_stacktrace") != std::string::npos); 44 | #else 45 | BOOST_CHECK(results.empty()); 46 | #endif 47 | } 48 | 49 | #if BOOST_VERSION / 100 >= 1065 && !defined(__APPLE__) 50 | class _svdt_visitor 51 | { 52 | public: 53 | typedef std::string result_type; 54 | std::string operator()( int64_t i )const 55 | { 56 | std::stringstream ss; 57 | fc::print_stacktrace(ss); 58 | return ss.str(); 59 | } 60 | template 61 | std::string operator()( T i )const { return "Unexpected!"; } 62 | }; 63 | 64 | BOOST_AUTO_TEST_CASE(static_variant_depth_test) 65 | { 66 | int64_t i = 1; 67 | fc::static_variant,std::vector,std::vector, 68 | uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t> test(i); 69 | 70 | std::string stacktrace = test.visit( _svdt_visitor() ); 71 | std::cerr << stacktrace << "\n"; 72 | std::vector lines; 73 | boost::split( lines, stacktrace, boost::is_any_of("\n") ); 74 | int count = 0; 75 | for( const auto& line : lines ) 76 | if( line.find("_svdt_visitor") != std::string::npos ) count++; 77 | BOOST_CHECK_LT( 1, count ); // test.visit(), static_variant::visit, function object, visitor. 78 | // The actual count depends on compiler and optimization settings. 79 | BOOST_CHECK_GT( 12, count ); // It *should* be less than the number of static variant components. 80 | // some is implementation-dependent 81 | } 82 | #endif 83 | 84 | /* this test causes a segfault on purpose to test the event handler 85 | BOOST_AUTO_TEST_CASE(cause_segfault) 86 | { 87 | fc::print_stacktrace_on_segfault(); 88 | ::raise(SIGSEGV); 89 | } 90 | */ 91 | BOOST_AUTO_TEST_SUITE_END() 92 | -------------------------------------------------------------------------------- /src/crypto/sha1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "_digest_common.hpp" 9 | 10 | namespace fc 11 | { 12 | 13 | sha1::sha1() { memset( _hash, 0, sizeof(_hash) ); } 14 | sha1::sha1( const std::string& hex_str ) { 15 | fc::from_hex( hex_str, (char*)_hash, sizeof(_hash) ); 16 | } 17 | 18 | string sha1::str()const { 19 | return fc::to_hex( (char*)_hash, sizeof(_hash) ); 20 | } 21 | sha1::operator std::string()const { return str(); } 22 | 23 | char* sha1::data()const { return (char*)&_hash[0]; } 24 | 25 | 26 | struct sha1::encoder::impl { 27 | SHA_CTX ctx; 28 | }; 29 | 30 | sha1::encoder::~encoder() {} 31 | sha1::encoder::encoder() { 32 | reset(); 33 | } 34 | 35 | sha1 sha1::hash( const char* d, uint32_t dlen ) { 36 | encoder e; 37 | e.write(d,dlen); 38 | return e.result(); 39 | } 40 | sha1 sha1::hash( const std::string& s ) { 41 | return hash( s.c_str(), s.size() ); 42 | } 43 | 44 | void sha1::encoder::write( const char* d, uint32_t dlen ) { 45 | SHA1_Update( &my->ctx, d, dlen); 46 | } 47 | sha1 sha1::encoder::result() { 48 | sha1 h; 49 | SHA1_Final((uint8_t*)h.data(), &my->ctx ); 50 | return h; 51 | } 52 | void sha1::encoder::reset() { 53 | SHA1_Init( &my->ctx); 54 | } 55 | 56 | sha1 operator << ( const sha1& h1, uint32_t i ) { 57 | sha1 result; 58 | fc::detail::shift_l( h1.data(), result.data(), result.data_size(), i ); 59 | return result; 60 | } 61 | sha1 operator ^ ( const sha1& h1, const sha1& h2 ) { 62 | sha1 result; 63 | result._hash[0] = h1._hash[0].value() ^ h2._hash[0].value(); 64 | result._hash[1] = h1._hash[1].value() ^ h2._hash[1].value(); 65 | result._hash[2] = h1._hash[2].value() ^ h2._hash[2].value(); 66 | result._hash[3] = h1._hash[3].value() ^ h2._hash[3].value(); 67 | result._hash[4] = h1._hash[4].value() ^ h2._hash[4].value(); 68 | return result; 69 | } 70 | bool operator >= ( const sha1& h1, const sha1& h2 ) { 71 | return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) >= 0; 72 | } 73 | bool operator > ( const sha1& h1, const sha1& h2 ) { 74 | return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) > 0; 75 | } 76 | bool operator < ( const sha1& h1, const sha1& h2 ) { 77 | return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) < 0; 78 | } 79 | bool operator != ( const sha1& h1, const sha1& h2 ) { 80 | return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) != 0; 81 | } 82 | bool operator == ( const sha1& h1, const sha1& h2 ) { 83 | return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0; 84 | } 85 | 86 | void to_variant( const sha1& bi, variant& v, uint32_t max_depth ) 87 | { 88 | to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth ); 89 | } 90 | void from_variant( const variant& v, sha1& bi, uint32_t max_depth ) 91 | { 92 | std::vector ve = v.as< std::vector >( max_depth ); 93 | memset( &bi, char(0), sizeof(bi) ); 94 | if( ve.size() ) 95 | memcpy( &bi, ve.data(), std::min(ve.size(),sizeof(bi)) ); 96 | } 97 | 98 | } // fc 99 | -------------------------------------------------------------------------------- /include/fc/crypto/sha256.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace fc 8 | { 9 | 10 | class sha256 11 | { 12 | public: 13 | sha256(); 14 | explicit sha256( const string& hex_str ); 15 | explicit sha256( const char *data, size_t size ); 16 | 17 | string str()const; 18 | operator string()const; 19 | 20 | char* data()const; 21 | static constexpr size_t data_size() { return 256 / 8; } 22 | 23 | static sha256 hash( const char* d, uint32_t dlen ); 24 | static sha256 hash( const string& ); 25 | static sha256 hash( const sha256& ); 26 | 27 | template 28 | static sha256 hash( const T& t ) 29 | { 30 | sha256::encoder e; 31 | fc::raw::pack(e,t); 32 | return e.result(); 33 | } 34 | 35 | class encoder 36 | { 37 | public: 38 | encoder(); 39 | ~encoder(); 40 | 41 | void write( const char* d, uint32_t dlen ); 42 | void put( char c ) { write( &c, 1 ); } 43 | void reset(); 44 | sha256 result(); 45 | 46 | private: 47 | struct impl; 48 | fc::fwd my; 49 | }; 50 | 51 | template 52 | inline friend T& operator<<( T& ds, const sha256& ep ) { 53 | ds.write( ep.data(), sizeof(ep) ); 54 | return ds; 55 | } 56 | 57 | template 58 | inline friend T& operator>>( T& ds, sha256& ep ) { 59 | ds.read( ep.data(), sizeof(ep) ); 60 | return ds; 61 | } 62 | friend sha256 operator << ( const sha256& h1, uint32_t i ); 63 | friend sha256 operator >> ( const sha256& h1, uint32_t i ); 64 | friend bool operator == ( const sha256& h1, const sha256& h2 ); 65 | friend bool operator != ( const sha256& h1, const sha256& h2 ); 66 | friend sha256 operator ^ ( const sha256& h1, const sha256& h2 ); 67 | friend bool operator >= ( const sha256& h1, const sha256& h2 ); 68 | friend bool operator > ( const sha256& h1, const sha256& h2 ); 69 | friend bool operator < ( const sha256& h1, const sha256& h2 ); 70 | 71 | boost::endian::little_uint64_buf_t _hash[4]; 72 | }; 73 | 74 | namespace raw { 75 | 76 | template 77 | inline void pack( T& ds, const sha256& ep, uint32_t _max_depth ) { 78 | ds << ep; 79 | } 80 | 81 | template 82 | inline void unpack( T& ds, sha256& ep, uint32_t _max_depth ) { 83 | ds >> ep; 84 | } 85 | 86 | } 87 | 88 | typedef sha256 uint256; 89 | 90 | class variant; 91 | void to_variant( const sha256& bi, variant& v, uint32_t max_depth ); 92 | void from_variant( const variant& v, sha256& bi, uint32_t max_depth ); 93 | 94 | } // fc 95 | namespace std 96 | { 97 | template<> 98 | struct hash 99 | { 100 | size_t operator()( const fc::sha256& s )const 101 | { 102 | return *((size_t*)&s); 103 | } 104 | }; 105 | } 106 | 107 | #include 108 | FC_REFLECT_TYPENAME( fc::sha256 ) 109 | -------------------------------------------------------------------------------- /src/crypto/openssl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace fc 12 | { 13 | struct openssl_scope 14 | { 15 | static path & _configurationFilePath() 16 | { 17 | static path orderindependentstorage; 18 | return orderindependentstorage; 19 | } 20 | openssl_scope() 21 | { 22 | ERR_load_crypto_strings(); 23 | OpenSSL_add_all_algorithms(); 24 | 25 | const boost::filesystem::path& boostPath = _configurationFilePath(); 26 | if(boostPath.empty() == false) 27 | { 28 | std::string varSetting("OPENSSL_CONF="); 29 | varSetting += _configurationFilePath().to_native_ansi_path(); 30 | #if defined(WIN32) 31 | _putenv((char*)varSetting.c_str()); 32 | #else 33 | putenv((char*)varSetting.c_str()); 34 | #endif 35 | } 36 | #if OPENSSL_VERSION_NUMBER < 0x10100000L 37 | // no longer needed as of OpenSSL 1.1 38 | // if special initialization is necessary in versions 1.1 and above, 39 | // use OPENSSL_init_crypto 40 | OPENSSL_config(nullptr); 41 | #endif 42 | } 43 | 44 | ~openssl_scope() 45 | { 46 | #if not defined(LIBRESSL_VERSION_NUMBER) 47 | // No FIPS in LibreSSL. 48 | // https://marc.info/?l=openbsd-misc&m=139819485423701&w=2 49 | FIPS_mode_set(0); 50 | #endif 51 | CONF_modules_unload(1); 52 | EVP_cleanup(); 53 | CRYPTO_cleanup_all_ex_data(); 54 | ERR_free_strings(); 55 | } 56 | }; 57 | 58 | void store_configuration_path(const path& filePath) 59 | { 60 | openssl_scope::_configurationFilePath() = filePath; 61 | } 62 | 63 | int init_openssl() 64 | { 65 | static openssl_scope ossl; 66 | return 0; 67 | } 68 | 69 | #define SSL_TYPE_IMPL(name, ssl_type, free_func) \ 70 | name::name( ssl_type* obj ) : ssl_wrapper(obj) {} \ 71 | name::name( name&& move ) : ssl_wrapper( move.obj ) \ 72 | { \ 73 | move.obj = nullptr; \ 74 | } \ 75 | name::~name() \ 76 | { \ 77 | if( obj != nullptr ) \ 78 | free_func(obj); \ 79 | } \ 80 | name& name::operator=( name&& move ) \ 81 | { \ 82 | if( this != &move ) \ 83 | { \ 84 | if( obj != nullptr ) \ 85 | free_func(obj); \ 86 | obj = move.obj; \ 87 | move.obj = nullptr; \ 88 | } \ 89 | return *this; \ 90 | } 91 | 92 | SSL_TYPE_IMPL(ec_group, EC_GROUP, EC_GROUP_free) 93 | SSL_TYPE_IMPL(ec_point, EC_POINT, EC_POINT_free) 94 | SSL_TYPE_IMPL(ecdsa_sig, ECDSA_SIG, ECDSA_SIG_free) 95 | SSL_TYPE_IMPL(bn_ctx, BN_CTX, BN_CTX_free) 96 | SSL_TYPE_IMPL(evp_cipher_ctx, EVP_CIPHER_CTX, EVP_CIPHER_CTX_free ) 97 | SSL_TYPE_IMPL(ssl_dh, DH, DH_free) 98 | } 99 | -------------------------------------------------------------------------------- /tests/utf8_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace fc; 6 | 7 | static const std::string TEST_INVALID_1("\375\271\261\241\201\211\001"); 8 | static const std::string TEST_INVALID_2("\371\261\241\201\211\001"); 9 | static const std::string TEST_VALID_1("\361\241\201\211\001"); 10 | static const std::string TEST_VALID_2("\361\241\201\211"); 11 | static const std::string TEST_INVALID_3("\361\241\201"); 12 | static const std::string TEST_INVALID_4("\361\241\201\001"); 13 | static const std::string TEST_INVALID_5("\361\241"); 14 | static const std::string TEST_INVALID_6("\361\241\001"); 15 | static const std::string TEST_INVALID_7("\361"); 16 | static const std::string TEST_INVALID_8("\361\001"); 17 | static const std::string TEST_INVALID_9("\355\244\200"); 18 | static const std::string TEST_INVALID_10("\355\244\200\001"); 19 | static const std::string TEST_INVALID_11("\340\214\200"); 20 | static const std::string TEST_INVALID_12("\340\214\200\001"); 21 | 22 | BOOST_AUTO_TEST_SUITE(fc) 23 | 24 | BOOST_AUTO_TEST_CASE(utf8_test) 25 | { 26 | std::wstring test(L"\0\001\002"); 27 | test.reserve(65536); 28 | for (wchar_t c = 0xffff; c >= 0xe000; c--) { 29 | test.push_back(c); 30 | } 31 | for (wchar_t c = 0xd7ff; c > 2; c--) { 32 | test.push_back(c); 33 | } 34 | for (wchar_t c = 1; c < 16; c++) { 35 | test.push_back((c << 16) | 0xffff); 36 | } 37 | 38 | std::string storage; 39 | storage.reserve(257*1024); 40 | fc::encodeUtf8(test, &storage); 41 | BOOST_CHECK(fc::is_utf8(storage)); 42 | 43 | std::wstring decoded; 44 | decoded.reserve(65536); 45 | fc::decodeUtf8(storage, &decoded); 46 | BOOST_CHECK(test.compare(decoded) == 0); 47 | 48 | BOOST_CHECK(fc::is_utf8(TEST_VALID_1)); 49 | BOOST_CHECK(fc::is_utf8(TEST_VALID_2)); 50 | BOOST_CHECK(!fc::is_utf8(TEST_INVALID_1)); 51 | BOOST_CHECK(!fc::is_utf8(TEST_INVALID_2)); 52 | BOOST_CHECK(!fc::is_utf8(TEST_INVALID_3)); 53 | BOOST_CHECK(!fc::is_utf8(TEST_INVALID_4)); 54 | BOOST_CHECK(!fc::is_utf8(TEST_INVALID_5)); 55 | BOOST_CHECK(!fc::is_utf8(TEST_INVALID_6)); 56 | BOOST_CHECK(!fc::is_utf8(TEST_INVALID_7)); 57 | BOOST_CHECK(!fc::is_utf8(TEST_INVALID_8)); 58 | BOOST_CHECK(!fc::is_utf8(TEST_INVALID_9)); 59 | BOOST_CHECK(!fc::is_utf8(TEST_INVALID_10)); 60 | BOOST_CHECK(!fc::is_utf8(TEST_INVALID_11)); 61 | BOOST_CHECK(!fc::is_utf8(TEST_INVALID_12)); 62 | 63 | decoded.clear(); 64 | try { 65 | fc::decodeUtf8(TEST_INVALID_1, &decoded); 66 | BOOST_FAIL("expected invalid utf8 exception"); 67 | } catch (const std::exception& e) { 68 | BOOST_CHECK(!strncmp("Invalid UTF-8", e.what(), 14)); 69 | } 70 | try { 71 | fc::decodeUtf8(TEST_INVALID_9, &decoded); 72 | BOOST_FAIL("expected invalid code point exception"); 73 | } catch (const std::exception& e) { 74 | BOOST_CHECK(!strncmp("Invalid code point", e.what(), 19)); 75 | } 76 | try { 77 | fc::decodeUtf8(TEST_INVALID_11, &decoded); 78 | BOOST_FAIL("expected invalid utf8 exception"); 79 | } catch (const std::exception& e) { 80 | BOOST_CHECK(!strncmp("Invalid UTF-8", e.what(), 14)); 81 | } 82 | } 83 | 84 | BOOST_AUTO_TEST_SUITE_END() 85 | -------------------------------------------------------------------------------- /include/fc/io/enum_type.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace fc 7 | { 8 | template 9 | class enum_type 10 | { 11 | public: 12 | enum_type( EnumType t ) 13 | :value(t){} 14 | 15 | enum_type( IntType t ) 16 | :value( (EnumType)t ){} 17 | 18 | enum_type(){} 19 | 20 | explicit operator IntType()const { return static_cast(value); } 21 | operator EnumType()const { return value; } 22 | operator std::string()const { return fc::reflector::to_string(value); } 23 | 24 | enum_type& operator=( IntType i ) { value = (EnumType)i; return *this;} 25 | enum_type& operator=( EnumType i ) { value = i; return *this;} 26 | bool operator<( EnumType i ) const { return value < i; } 27 | bool operator>( EnumType i ) const { return value < i; } 28 | 29 | bool operator<(const enum_type& e) const { return value < e.value;} 30 | bool operator>(const enum_type& e) const { return value > e.value;} 31 | 32 | bool operator<=(const enum_type& e) const { return value <= e.value;} 33 | bool operator>=(const enum_type& e) const { return value >= e.value;} 34 | 35 | friend bool operator==( const enum_type& e, IntType i ){ return e.value == (EnumType)i;} 36 | friend bool operator==( const enum_type& e, EnumType i ){ return e.value == i; } 37 | 38 | friend bool operator==( const enum_type& e, const enum_type& i ){ return e.value == i.value; } 39 | friend bool operator==( IntType i, const enum_type& e){ return e.value == (EnumType)i; } 40 | friend bool operator==( EnumType i, const enum_type& e ){ return e.value == i; } 41 | 42 | friend bool operator!=( const enum_type& e, IntType i ){ return e.value != (EnumType)i;} 43 | friend bool operator!=( const enum_type& e, EnumType i ){ return e.value != i; } 44 | friend bool operator!=( const enum_type& e, const enum_type& i ){ return e.value != i.value; } 45 | 46 | EnumType value; 47 | }; 48 | 49 | 50 | template 51 | void to_variant( const enum_type& var, variant& vo, uint32_t max_depth = 1 ) 52 | { 53 | to_variant( var.value, vo, max_depth ); 54 | } 55 | template 56 | void from_variant( const variant& var, enum_type& vo, uint32_t max_depth ) 57 | { 58 | vo.value = var.as(1); 59 | } 60 | 61 | 62 | /** serializes like an IntType */ 63 | namespace raw 64 | { 65 | template 66 | inline void pack( Stream& s, const fc::enum_type& tp, uint32_t _max_depth ) 67 | { 68 | FC_ASSERT( _max_depth > 0 ); 69 | fc::raw::pack( s, static_cast(tp), _max_depth - 1 ); 70 | } 71 | 72 | template 73 | inline void unpack( Stream& s, fc::enum_type& tp, uint32_t _max_depth ) 74 | { 75 | FC_ASSERT( _max_depth > 0 ); 76 | IntType t; 77 | fc::raw::unpack( s, t, _max_depth - 1 ); 78 | tp = t; 79 | } 80 | } 81 | 82 | } 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/crypto/sha224.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "_digest_common.hpp" 9 | 10 | namespace fc { 11 | 12 | sha224::sha224() { memset( _hash, 0, sizeof(_hash) ); } 13 | sha224::sha224( const string& hex_str ) { 14 | fc::from_hex( hex_str, (char*)_hash, sizeof(_hash) ); 15 | } 16 | 17 | string sha224::str()const { 18 | return fc::to_hex( (char*)_hash, sizeof(_hash) ); 19 | } 20 | sha224::operator string()const { return str(); } 21 | 22 | char* sha224::data()const { return (char*)&_hash[0]; } 23 | 24 | 25 | struct sha224::encoder::impl { 26 | SHA256_CTX ctx; 27 | }; 28 | 29 | sha224::encoder::~encoder() {} 30 | sha224::encoder::encoder() { 31 | reset(); 32 | } 33 | 34 | sha224 sha224::hash( const char* d, uint32_t dlen ) { 35 | encoder e; 36 | e.write(d,dlen); 37 | return e.result(); 38 | } 39 | sha224 sha224::hash( const string& s ) { 40 | return hash( s.c_str(), s.size() ); 41 | } 42 | 43 | void sha224::encoder::write( const char* d, uint32_t dlen ) { 44 | SHA224_Update( &my->ctx, d, dlen); 45 | } 46 | sha224 sha224::encoder::result() { 47 | sha224 h; 48 | SHA224_Final((uint8_t*)h.data(), &my->ctx ); 49 | return h; 50 | } 51 | void sha224::encoder::reset() { 52 | SHA224_Init( &my->ctx); 53 | } 54 | 55 | sha224 operator << ( const sha224& h1, uint32_t i ) { 56 | sha224 result; 57 | fc::detail::shift_l( h1.data(), result.data(), result.data_size(), i ); 58 | return result; 59 | } 60 | sha224 operator ^ ( const sha224& h1, const sha224& h2 ) { 61 | sha224 result; 62 | for( uint32_t i = 0; i < 7; ++i ) 63 | result._hash[i] = h1._hash[i].value() ^ h2._hash[i].value(); 64 | return result; 65 | } 66 | bool operator >= ( const sha224& h1, const sha224& h2 ) { 67 | return memcmp( h1._hash, h2._hash, sizeof(sha224) ) >= 0; 68 | } 69 | bool operator > ( const sha224& h1, const sha224& h2 ) { 70 | return memcmp( h1._hash, h2._hash, sizeof(sha224) ) > 0; 71 | } 72 | bool operator < ( const sha224& h1, const sha224& h2 ) { 73 | return memcmp( h1._hash, h2._hash, sizeof(sha224) ) < 0; 74 | } 75 | bool operator != ( const sha224& h1, const sha224& h2 ) { 76 | return memcmp( h1._hash, h2._hash, sizeof(sha224) ) != 0; 77 | } 78 | bool operator == ( const sha224& h1, const sha224& h2 ) { 79 | return memcmp( h1._hash, h2._hash, sizeof(sha224) ) == 0; 80 | } 81 | 82 | void to_variant( const sha224& bi, variant& v, uint32_t max_depth ) 83 | { 84 | to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth ); 85 | } 86 | void from_variant( const variant& v, sha224& bi, uint32_t max_depth ) 87 | { 88 | std::vector ve = v.as< std::vector >( max_depth ); 89 | memset( &bi, char(0), sizeof(bi) ); 90 | if( ve.size() ) 91 | memcpy( &bi, ve.data(), std::min(ve.size(),sizeof(bi)) ); 92 | } 93 | 94 | template<> 95 | unsigned int hmac::internal_block_size() const { return 64; } 96 | } 97 | -------------------------------------------------------------------------------- /include/fc/crypto/ripemd160.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace fc{ 8 | class sha512; 9 | class sha256; 10 | 11 | class ripemd160 12 | { 13 | public: 14 | ripemd160(); 15 | explicit ripemd160( const string& hex_str ); 16 | 17 | string str()const; 18 | explicit operator string()const; 19 | 20 | char* data()const; 21 | static constexpr size_t data_size() { return 160/8; } 22 | 23 | static ripemd160 hash( const fc::sha512& h ); 24 | static ripemd160 hash( const fc::sha256& h ); 25 | static ripemd160 hash( const char* d, uint32_t dlen ); 26 | static ripemd160 hash( const string& ); 27 | 28 | template 29 | static ripemd160 hash( const T& t ) 30 | { 31 | ripemd160::encoder e; 32 | fc::raw::pack(e,t); 33 | return e.result(); 34 | } 35 | 36 | class encoder 37 | { 38 | public: 39 | encoder(); 40 | ~encoder(); 41 | 42 | void write( const char* d, uint32_t dlen ); 43 | void put( char c ) { write( &c, 1 ); } 44 | void reset(); 45 | ripemd160 result(); 46 | 47 | private: 48 | class impl; 49 | fc::fwd my; 50 | }; 51 | 52 | template 53 | inline friend T& operator<<( T& ds, const ripemd160& ep ) { 54 | ds.write( ep.data(), sizeof(ep) ); 55 | return ds; 56 | } 57 | 58 | template 59 | inline friend T& operator>>( T& ds, ripemd160& ep ) { 60 | ds.read( ep.data(), sizeof(ep) ); 61 | return ds; 62 | } 63 | friend ripemd160 operator << ( const ripemd160& h1, uint32_t i ); 64 | friend bool operator == ( const ripemd160& h1, const ripemd160& h2 ); 65 | friend bool operator != ( const ripemd160& h1, const ripemd160& h2 ); 66 | friend ripemd160 operator ^ ( const ripemd160& h1, const ripemd160& h2 ); 67 | friend bool operator >= ( const ripemd160& h1, const ripemd160& h2 ); 68 | friend bool operator > ( const ripemd160& h1, const ripemd160& h2 ); 69 | friend bool operator < ( const ripemd160& h1, const ripemd160& h2 ); 70 | 71 | boost::endian::little_uint32_buf_t _hash[5]; 72 | }; 73 | 74 | namespace raw { 75 | 76 | template 77 | inline void pack( T& ds, const ripemd160& ep, uint32_t _max_depth ) { 78 | ds << ep; 79 | } 80 | 81 | template 82 | inline void unpack( T& ds, ripemd160& ep, uint32_t _max_depth ) { 83 | ds >> ep; 84 | } 85 | 86 | } 87 | 88 | class variant; 89 | void to_variant( const ripemd160& bi, variant& v, uint32_t max_depth ); 90 | void from_variant( const variant& v, ripemd160& bi, uint32_t max_depth ); 91 | 92 | typedef ripemd160 uint160_t; 93 | typedef ripemd160 uint160; 94 | 95 | template<> struct get_typename { static const char* name() { return "uint160_t"; } }; 96 | 97 | } // namespace fc 98 | 99 | namespace std 100 | { 101 | template<> 102 | struct hash 103 | { 104 | size_t operator()( const fc::ripemd160& s )const 105 | { 106 | return *((size_t*)&s); 107 | } 108 | }; 109 | } 110 | -------------------------------------------------------------------------------- /tests/crypto/base_n_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | static const std::string TEST1(""); 11 | static const std::string TEST2("\0\00101", 4); 12 | static const std::string TEST3("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 13 | static const std::string TEST4("\377\376\000\375\001\374", 6); 14 | static const std::string TEST5("\0\0\0", 3); 15 | 16 | static void test_16( const std::string& test, const std::string& expected ) 17 | { 18 | std::vector vec( test.begin(), test.end() ); 19 | std::string enc1 = fc::to_hex( vec ); 20 | std::string enc2 = fc::to_hex( test.c_str(), test.size() ); 21 | BOOST_CHECK_EQUAL( enc1, enc2 ); 22 | BOOST_CHECK_EQUAL( expected, enc2 ); 23 | 24 | char out[32]; 25 | size_t len = fc::from_hex( enc1, out, 32 ); 26 | BOOST_CHECK_EQUAL( test.size(), len ); 27 | BOOST_CHECK( !memcmp( test.c_str(), out, len ) ); 28 | if (len > 10) { 29 | BOOST_CHECK( fc::from_hex( enc1, out, 10 ) <= 10 ); 30 | } 31 | } 32 | 33 | BOOST_AUTO_TEST_SUITE(fc_crypto) 34 | 35 | BOOST_AUTO_TEST_CASE(hex_test) 36 | { 37 | test_16( TEST1, "" ); 38 | test_16( TEST2, "00013031" ); 39 | test_16( TEST3, "4142434445464748494a4b4c4d4e4f505152535455565758595a" ); 40 | test_16( TEST4, "fffe00fd01fc" ); 41 | test_16( TEST5, "000000" ); 42 | } 43 | 44 | 45 | static void test_58( const std::string& test, const std::string& expected ) 46 | { 47 | std::vector vec( test.begin(), test.end() ); 48 | std::string enc1 = fc::to_base58( vec ); 49 | std::string enc2 = fc::to_base58( test.c_str(), test.size() ); 50 | BOOST_CHECK_EQUAL( enc1, enc2 ); 51 | BOOST_CHECK_EQUAL( expected, enc2 ); 52 | 53 | std::vector dec = fc::from_base58( enc1 ); 54 | BOOST_CHECK_EQUAL( vec.size(), dec.size() ); 55 | BOOST_CHECK( vec == dec ); 56 | 57 | char buffer[64]; 58 | size_t len = fc::from_base58( enc1, buffer, 64 ); 59 | BOOST_CHECK( len <= 64 ); 60 | BOOST_CHECK( vec.empty() || !memcmp( vec.data(), buffer, len ) ); 61 | if ( len > 10 ) { 62 | BOOST_CHECK_THROW(fc::from_base58( enc1, buffer, 10 ), fc::exception); 63 | } 64 | 65 | } 66 | 67 | BOOST_AUTO_TEST_CASE(base58_test) 68 | { 69 | test_58( TEST1, "" ); 70 | test_58( TEST2, "1Q9e" ); 71 | test_58( TEST3, "2zuFXTJSTRK6ESktqhM2QDBkCnH1U46CnxaD" ); 72 | test_58( TEST4, "3CUeREErf" ); 73 | test_58( TEST5, "111" ); 74 | } 75 | 76 | 77 | static void test_64( const std::string& test, const std::string& expected ) 78 | { 79 | std::string enc1 = fc::base64_encode( test ); 80 | std::string enc2 = fc::base64_encode( test.c_str(), test.size() ); 81 | BOOST_CHECK_EQUAL( enc1, enc2 ); 82 | BOOST_CHECK_EQUAL( expected, enc2 ); 83 | 84 | std::string dec = fc::base64_decode( enc1 ); 85 | BOOST_CHECK_EQUAL( test.size(), dec.size() ); 86 | BOOST_CHECK_EQUAL( test, dec ); 87 | } 88 | 89 | BOOST_AUTO_TEST_CASE(base64_test) 90 | { 91 | test_64( TEST1, "" ); 92 | test_64( TEST2, "AAEwMQ==" ); 93 | test_64( TEST3, "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=" ); 94 | test_64( TEST4, "//4A/QH8" ); 95 | test_64( TEST5, "AAAA" ); 96 | } 97 | 98 | 99 | BOOST_AUTO_TEST_SUITE_END() 100 | -------------------------------------------------------------------------------- /include/fc/network/url.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace fc { 9 | 10 | typedef fc::optional ostring; 11 | typedef fc::optional opath; 12 | typedef fc::optional ovariant_object; 13 | 14 | namespace detail { class url_impl; } 15 | 16 | class mutable_url; 17 | 18 | /** 19 | * Used to pass an immutable URL and 20 | * query its parts. 21 | */ 22 | class url 23 | { 24 | public: 25 | url(); 26 | explicit url( const string& u ); 27 | url( const url& c ); 28 | url( url&& c ); 29 | url( mutable_url&& c ); 30 | url( const mutable_url& c ); 31 | ~url(); 32 | 33 | url& operator=( const url& c ); 34 | url& operator=( url&& c ); 35 | 36 | url& operator=( const mutable_url& c ); 37 | url& operator=( mutable_url&& c ); 38 | 39 | bool operator==( const url& cmp )const; 40 | 41 | operator string()const; 42 | 43 | //// file, ssh, tcp, http, ssl, etc... 44 | string proto()const; 45 | ostring host()const; 46 | ostring user()const; 47 | ostring pass()const; 48 | opath path()const; 49 | ovariant_object args()const; 50 | fc::optional port()const; 51 | 52 | private: 53 | friend class mutable_url; 54 | std::shared_ptr my; 55 | }; 56 | 57 | void to_variant( const url& u, fc::variant& v, uint32_t max_depth = 1 ); 58 | void from_variant( const fc::variant& v, url& u, uint32_t max_depth = 1 ); 59 | 60 | /** 61 | * Used to create / manipulate a URL 62 | */ 63 | class mutable_url 64 | { 65 | public: 66 | mutable_url(); 67 | explicit mutable_url( const string& mutable_url ); 68 | mutable_url( const mutable_url& c ); 69 | mutable_url( const url& c ); 70 | mutable_url( mutable_url&& c ); 71 | ~mutable_url(); 72 | 73 | mutable_url& operator=( const url& c ); 74 | mutable_url& operator=( const mutable_url& c ); 75 | mutable_url& operator=( mutable_url&& c ); 76 | 77 | bool operator==( const mutable_url& cmp )const; 78 | bool operator==( const url& cmp )const; 79 | 80 | operator string()const; 81 | 82 | //// file, ssh, tcp, http, ssl, etc... 83 | string proto()const; 84 | ostring host()const; 85 | ostring user()const; 86 | ostring pass()const; 87 | opath path()const; 88 | ovariant_object args()const; 89 | fc::optional port()const; 90 | 91 | void set_proto( string ); 92 | void set_host( string ); 93 | void set_user( string ); 94 | void set_pass( string ); 95 | void set_path( fc::path p ); 96 | void set_args( variant_object ); 97 | void set_port( uint16_t ); 98 | 99 | private: 100 | friend class url; 101 | std::unique_ptr my; 102 | }; 103 | 104 | } // namespace fc 105 | 106 | -------------------------------------------------------------------------------- /src/log/logger_config.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace fc { 14 | extern std::unordered_map& get_logger_map(); 15 | extern std::unordered_map& get_appender_map(); 16 | logger_config& logger_config::add_appender( const string& s ) { appenders.push_back(s); return *this; } 17 | 18 | void configure_logging( const fc::path& lc ) 19 | { 20 | configure_logging( fc::json::from_file(lc) ); 21 | } 22 | bool configure_logging( const logging_config& cfg ) 23 | { 24 | try { 25 | static bool reg_console_appender = appender::register_appender( "console" ); 26 | static bool reg_file_appender = appender::register_appender( "file" ); 27 | get_logger_map().clear(); 28 | get_appender_map().clear(); 29 | 30 | for( size_t i = 0; i < cfg.appenders.size(); ++i ) { 31 | appender::create( cfg.appenders[i].name, cfg.appenders[i].type, cfg.appenders[i].args ); 32 | // TODO... process enabled 33 | } 34 | for( size_t i = 0; i < cfg.loggers.size(); ++i ) { 35 | auto lgr = logger::get( cfg.loggers[i].name ); 36 | 37 | // TODO: finish configure logger here... 38 | if( cfg.loggers[i].parent.valid() ) { 39 | lgr.set_parent( logger::get( *cfg.loggers[i].parent ) ); 40 | } 41 | lgr.set_name(cfg.loggers[i].name); 42 | if( cfg.loggers[i].level.valid() ) lgr.set_log_level( *cfg.loggers[i].level ); 43 | 44 | 45 | for( auto a = cfg.loggers[i].appenders.begin(); a != cfg.loggers[i].appenders.end(); ++a ){ 46 | auto ap = appender::get( *a ); 47 | if( ap ) { lgr.add_appender(ap); } 48 | } 49 | } 50 | return reg_console_appender || reg_file_appender; 51 | } catch ( exception& e ) 52 | { 53 | fc::cerr< 3 | #include 4 | 5 | namespace fc { 6 | 7 | namespace detail 8 | { 9 | [[noreturn]] void throw_datastream_range_error( const char* file, size_t len, int64_t over ); 10 | } 11 | 12 | /** 13 | * The purpose of this datastream is to provide a fast, effecient, means 14 | * of calculating the amount of data "about to be written" and then 15 | * writing it. This means having two modes of operation, "test run" where 16 | * you call the entire pack sequence calculating the size, and then 17 | * actually packing it after doing a single allocation. 18 | */ 19 | template 20 | class datastream { 21 | public: 22 | datastream( T start, size_t s ) 23 | :_start(start),_pos(start),_end(start+s){}; 24 | 25 | 26 | inline void skip( size_t s ){ _pos += s; } 27 | inline bool read( char* d, size_t s ) { 28 | if( size_t(_end - _pos) >= (size_t)s ) { 29 | memcpy( d, _pos, s ); 30 | _pos += s; 31 | return true; 32 | } 33 | detail::throw_datastream_range_error( "read", _end-_start, int64_t(-((_end-_pos) - 1))); 34 | } 35 | 36 | inline bool write( const char* d, size_t s ) { 37 | if( _end - _pos >= (int32_t)s ) { 38 | memcpy( _pos, d, s ); 39 | _pos += s; 40 | return true; 41 | } 42 | detail::throw_datastream_range_error( "write", _end-_start, int64_t(-((_end-_pos) - 1))); 43 | } 44 | 45 | inline bool put(char c) { 46 | if( _pos < _end ) { 47 | *_pos = c; 48 | ++_pos; 49 | return true; 50 | } 51 | detail::throw_datastream_range_error( "put", _end-_start, int64_t(-((_end-_pos) - 1))); 52 | } 53 | 54 | inline bool get( unsigned char& c ) { return get( *(char*)&c ); } 55 | inline bool get( char& c ) 56 | { 57 | if( _pos < _end ) { 58 | c = *_pos; 59 | ++_pos; 60 | return true; 61 | } 62 | detail::throw_datastream_range_error( "get", _end-_start, int64_t(-((_end-_pos) - 1))); 63 | } 64 | 65 | T pos()const { return _pos; } 66 | inline bool valid()const { return _pos <= _end && _pos >= _start; } 67 | inline bool seekp(size_t p) { _pos = _start + p; return _pos <= _end; } 68 | inline size_t tellp()const { return _pos - _start; } 69 | inline size_t remaining()const { return _end - _pos; } 70 | private: 71 | T _start; 72 | T _pos; 73 | T _end; 74 | }; 75 | 76 | template<> 77 | class datastream { 78 | public: 79 | datastream( size_t init_size = 0):_size(init_size){}; 80 | inline bool skip( size_t s ) { _size += s; return true; } 81 | inline bool write( const char* ,size_t s ) { _size += s; return true; } 82 | inline bool put(char ) { ++_size; return true; } 83 | inline bool valid()const { return true; } 84 | inline bool seekp(size_t p) { _size = p; return true; } 85 | inline size_t tellp()const { return _size; } 86 | inline size_t remaining()const { return 0; } 87 | private: 88 | size_t _size; 89 | }; 90 | 91 | } // namespace fc 92 | 93 | -------------------------------------------------------------------------------- /tests/logging_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | BOOST_AUTO_TEST_SUITE(logging_tests) 21 | 22 | BOOST_AUTO_TEST_CASE(log_reboot) 23 | { 24 | BOOST_TEST_MESSAGE("Setting up logger"); 25 | fc::file_appender::config conf; 26 | fc::temp_directory log_dir; 27 | conf.filename = log_dir.path() / "my.log"; 28 | BOOST_TEST_MESSAGE( std::string( "conf.filename=" ) + conf.filename.string() ); 29 | conf.format = "${timestamp} ${thread_name} ${context} ${file}:${line} ${method} ${level}] ${message}"; 30 | conf.flush = true; 31 | conf.rotate = true; 32 | conf.rotation_interval = fc::seconds(5); // rotate every 5 seconds 33 | conf.rotation_limit = fc::seconds(20); // Don't keep files older than 20 seconds 34 | conf.max_object_depth = 200; 35 | 36 | fc::appender::ptr fa = fc::appender::create("file", "file", fc::variant(conf, 200)); 37 | 38 | fc::path prev_log_filename = ""; 39 | 40 | BOOST_TEST_MESSAGE("Starting Loop"); 41 | int file_changed_count = 0; 42 | for(int i = 0; i < conf.rotation_limit.to_seconds(); i++) 43 | { 44 | fc::log_context ctx(fc::log_level::all, "my_file.cpp", i, "my_method()"); 45 | fc::log_message my_log_message( ctx, "${message}", {"message","This is a test"} ); 46 | fc::time_point now = fc::time_point::now(); 47 | fa->log(my_log_message); 48 | 49 | fc::time_point new_now = fc::time_point::now(); 50 | int64_t interval_seconds = conf.rotation_interval.to_seconds(); 51 | int64_t file_number = now.sec_since_epoch() / interval_seconds; 52 | bool file_changed = ( new_now.sec_since_epoch() / interval_seconds != file_number ); 53 | if( file_changed ) 54 | ++file_changed_count; 55 | fc::time_point_sec start_time = fc::time_point_sec( (uint32_t)(file_number * interval_seconds) ); 56 | std::string timestamp_string = start_time.to_non_delimited_iso_string(); 57 | fc::path link_filename = conf.filename; 58 | fc::path log_filename = link_filename.parent_path() / (link_filename.filename().string() + "." + timestamp_string); 59 | 60 | if (prev_log_filename != log_filename) { 61 | if (i > conf.rotation_interval.to_seconds() && !file_changed ) { 62 | std::string rez; 63 | fc::read_file_contents(prev_log_filename, rez); 64 | std::size_t found = rez.find("my_file.cpp:" + std::to_string(i - 1)); 65 | BOOST_CHECK(found != std::string::npos); 66 | 67 | fc::read_file_contents(log_filename, rez); 68 | found = rez.find("my_file.cpp:" + std::to_string(i)); 69 | BOOST_CHECK(found != std::string::npos); 70 | } 71 | prev_log_filename = log_filename; 72 | } 73 | 74 | fc::usleep(fc::seconds(1)); 75 | } 76 | if( file_changed_count >= 3 ) { 77 | BOOST_FAIL( "It is not expected that file name changes too frequently" ); 78 | } 79 | BOOST_TEST_MESSAGE("Loop complete"); 80 | } 81 | 82 | BOOST_AUTO_TEST_SUITE_END() 83 | -------------------------------------------------------------------------------- /tests/network/ip_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | BOOST_AUTO_TEST_SUITE(fc_network) 7 | 8 | BOOST_AUTO_TEST_CASE(ip_address_test) 9 | { 10 | std::vector local_ips { "127.0.0.1", "127.20.30.40" }; 11 | std::vector multicast_ips { "224.88.77.66", "239.11.23.45" }; 12 | std::vector private_ips { "10.2.3.4", "169.254.7.9", "192.168.5.6", "172.30.8.10" }; 13 | std::vector public_ips { "2.3.4.55", "200.100.50.25" }; 14 | std::vector bad_ips { "some_string", "2.300.4.55", "200:100.50.25.1" }; 15 | 16 | for( auto& ip_str : local_ips ) 17 | { 18 | fc::ip::address ip(ip_str); 19 | BOOST_CHECK( ip.is_loopback_address() ); 20 | BOOST_CHECK( !ip.is_multicast_address() ); 21 | BOOST_CHECK( !ip.is_private_address() ); 22 | BOOST_CHECK( !ip.is_public_address() ); 23 | } 24 | for( auto& ip_str : multicast_ips ) 25 | { 26 | fc::ip::address ip; 27 | ip = ip_str; 28 | BOOST_CHECK( !ip.is_loopback_address() ); 29 | BOOST_CHECK( ip.is_multicast_address() ); 30 | BOOST_CHECK( !ip.is_private_address() ); 31 | BOOST_CHECK( !ip.is_public_address() ); 32 | } 33 | for( auto& ip_str : private_ips ) 34 | { 35 | fc::ip::address ip(ip_str); 36 | BOOST_CHECK( !ip.is_loopback_address() ); 37 | BOOST_CHECK( !ip.is_multicast_address() ); 38 | BOOST_CHECK( ip.is_private_address() ); 39 | BOOST_CHECK( !ip.is_public_address() ); 40 | } 41 | for( auto& ip_str : public_ips ) 42 | { 43 | fc::ip::address ip; 44 | ip = ip_str; 45 | BOOST_CHECK( !ip.is_loopback_address() ); 46 | BOOST_CHECK( !ip.is_multicast_address() ); 47 | BOOST_CHECK( !ip.is_private_address() ); 48 | BOOST_CHECK( ip.is_public_address() ); 49 | } 50 | for( auto& ip_str : bad_ips ) 51 | { 52 | BOOST_CHECK_THROW( fc::ip::address( ip_str ).is_public_address(), fc::exception ); 53 | fc::ip::address ip; 54 | BOOST_CHECK_THROW( ip = ip_str, fc::exception ); 55 | } 56 | 57 | fc::ip::address ip1(100U); 58 | fc::ip::address ip2; 59 | ip2 = 100U; 60 | fc::ip::address ip3("0.0.0.100"); 61 | fc::ip::address ip4; 62 | ip4 = std::string("0.0.0.100"); 63 | std::string ip5_str("100.0.0.0"); 64 | fc::ip::address ip5("100.0.0.0"); 65 | 66 | BOOST_CHECK( ip1 == ip2 ); 67 | BOOST_CHECK( ip1 == ip3 ); 68 | BOOST_CHECK( ip1 == ip4 ); 69 | BOOST_CHECK( ip1 != ip5 ); 70 | BOOST_CHECK( uint32_t(ip1) == 100U ); 71 | BOOST_CHECK( std::string(ip1) == std::string("0.0.0.100") ); 72 | } 73 | 74 | BOOST_AUTO_TEST_CASE(ip_endpoint_test) 75 | { 76 | fc::ip::address ip100("0.0.0.100"); 77 | fc::ip::endpoint ep1(ip100, 100); 78 | fc::ip::endpoint ep2(100, 100); 79 | fc::ip::endpoint ep3(100, 101); 80 | fc::ip::endpoint ep4(101, 100); 81 | BOOST_CHECK( ep1 == ep2 ); 82 | BOOST_CHECK( ep1 != ep3 ); 83 | BOOST_CHECK( ep1 < ep3 ); 84 | BOOST_CHECK( ep1 < ep4 ); 85 | BOOST_CHECK( ep3 < ep4 ); 86 | 87 | std::string ep5_str("1.2.3.4:567"); 88 | fc::ip::endpoint ep5 = fc::ip::endpoint::from_string( ep5_str ); 89 | BOOST_CHECK( std::string(ep5) == ep5_str ); 90 | 91 | fc::variant v; 92 | fc::to_variant( ep5, v, 2 ); 93 | 94 | fc::ip::endpoint ep6; 95 | fc::from_variant( v, ep6, 2 ); 96 | 97 | BOOST_CHECK( ep5 == ep6 ); 98 | } 99 | 100 | BOOST_AUTO_TEST_SUITE_END() 101 | -------------------------------------------------------------------------------- /src/crypto/elliptic_impl_priv.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "_elliptic_impl_priv.hpp" 6 | 7 | /* used by mixed + secp256k1 */ 8 | 9 | namespace fc { namespace ecc { 10 | namespace detail { 11 | 12 | private_key_impl::private_key_impl() BOOST_NOEXCEPT 13 | { 14 | _init_lib(); 15 | } 16 | 17 | private_key_impl::private_key_impl( const private_key_impl& cpy ) BOOST_NOEXCEPT 18 | { 19 | _init_lib(); 20 | this->_key = cpy._key; 21 | } 22 | 23 | private_key_impl& private_key_impl::operator=( const private_key_impl& pk ) BOOST_NOEXCEPT 24 | { 25 | _key = pk._key; 26 | return *this; 27 | } 28 | } 29 | 30 | static const private_key_secret empty_priv; 31 | 32 | private_key::private_key() {} 33 | 34 | private_key::private_key( const private_key& pk ) : my( pk.my ) {} 35 | 36 | private_key::private_key( private_key&& pk ) : my( std::move( pk.my ) ) {} 37 | 38 | private_key::~private_key() {} 39 | 40 | private_key& private_key::operator=( private_key&& pk ) 41 | { 42 | my = std::move( pk.my ); 43 | return *this; 44 | } 45 | 46 | private_key& private_key::operator=( const private_key& pk ) 47 | { 48 | my = pk.my; 49 | return *this; 50 | } 51 | 52 | private_key private_key::regenerate( const fc::sha256& secret ) 53 | { 54 | private_key self; 55 | self.my->_key = secret; 56 | return self; 57 | } 58 | 59 | fc::sha256 private_key::get_secret()const 60 | { 61 | return my->_key; 62 | } 63 | 64 | private_key::private_key( EC_KEY* k ) 65 | { 66 | my->_key = get_secret( k ); 67 | EC_KEY_free(k); 68 | } 69 | 70 | public_key private_key::get_public_key()const 71 | { 72 | FC_ASSERT( my->_key != empty_priv ); 73 | public_key_data pub; 74 | unsigned int pk_len; 75 | FC_ASSERT( secp256k1_ec_pubkey_create( detail::_get_context(), pub.data(), (int*) &pk_len, 76 | (unsigned char*) my->_key.data(), 1 ) ); 77 | FC_ASSERT( pk_len == pub.size() ); 78 | return public_key(pub); 79 | } 80 | 81 | static int extended_nonce_function( unsigned char *nonce32, const unsigned char *msg32, 82 | const unsigned char *key32, unsigned int attempt, 83 | const void *data ) { 84 | unsigned int* extra = (unsigned int*) data; 85 | (*extra)++; 86 | return secp256k1_nonce_function_default( nonce32, msg32, key32, *extra, nullptr ); 87 | } 88 | 89 | compact_signature private_key::sign_compact( const fc::sha256& digest, bool require_canonical )const 90 | { 91 | FC_ASSERT( my->_key != empty_priv ); 92 | compact_signature result; 93 | int recid; 94 | unsigned int counter = 0; 95 | do 96 | { 97 | FC_ASSERT( secp256k1_ecdsa_sign_compact( detail::_get_context(), (unsigned char*) digest.data(), 98 | result.data() + 1, (unsigned char*) my->_key.data(), 99 | extended_nonce_function, &counter, &recid )); 100 | } while( require_canonical && !public_key::is_canonical( result ) ); 101 | result.data()[0] = 27 + 4 + recid; 102 | return result; 103 | } 104 | 105 | }} 106 | -------------------------------------------------------------------------------- /tests/bloom_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace fc; 14 | 15 | static bloom_parameters setup_parameters() 16 | { 17 | bloom_parameters parameters; 18 | 19 | // How many elements roughly do we expect to insert? 20 | parameters.projected_element_count = 100000; 21 | 22 | // Maximum tolerable false positive probability? (0,1) 23 | parameters.false_positive_probability = 0.0001; // 1 in 10000 24 | 25 | // Simple randomizer (optional) 26 | parameters.random_seed = 0xA5A5A5A5; 27 | 28 | if (!parameters) 29 | { 30 | BOOST_FAIL( "Error - Invalid set of bloom filter parameters!" ); 31 | } 32 | 33 | parameters.compute_optimal_parameters(); 34 | 35 | return parameters; 36 | } 37 | 38 | BOOST_AUTO_TEST_SUITE(fc_crypto) 39 | 40 | BOOST_AUTO_TEST_CASE(bloom_test_1) 41 | { 42 | try { 43 | 44 | //Instantiate Bloom Filter 45 | bloom_filter filter(setup_parameters()); 46 | 47 | uint32_t count = 0; 48 | std::string line; 49 | std::ifstream in("README.md"); 50 | std::ofstream words("words.txt"); 51 | while( in.good() && count < 100000 ) 52 | { 53 | std::getline(in, line); 54 | // std::cout << "'"< -100; --i) 117 | { 118 | BOOST_CHECK( !filter.contains(i) ); 119 | } 120 | } 121 | } 122 | catch ( const fc::exception& e ) 123 | { 124 | edump((e.to_detail_string()) ); 125 | } 126 | } 127 | 128 | BOOST_AUTO_TEST_SUITE_END() 129 | --------------------------------------------------------------------------------