Updates from BitShares FC #22
4 changed files with 86 additions and 74 deletions
|
|
@ -28,6 +28,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <openssl/bn.h>
|
#include <openssl/bn.h>
|
||||||
|
|
||||||
|
namespace fc { namespace detail {
|
||||||
|
|
||||||
/** Errors thrown by the bignum class */
|
/** Errors thrown by the bignum class */
|
||||||
class bignum_error : public std::runtime_error
|
class bignum_error : public std::runtime_error
|
||||||
{
|
{
|
||||||
|
|
@ -605,11 +607,10 @@ inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vch
|
||||||
return DecodeBase58(str.c_str(), vchRet);
|
return DecodeBase58(str.c_str(), vchRet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
namespace fc {
|
|
||||||
|
|
||||||
std::string to_base58( const char* d, size_t s ) {
|
std::string to_base58( const char* d, size_t s ) {
|
||||||
return EncodeBase58( (const unsigned char*)d, (const unsigned char*)d+s ).c_str();
|
return fc::detail::EncodeBase58( (const unsigned char*)d, (const unsigned char*)d+s ).c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_base58( const std::vector<char>& d )
|
std::string to_base58( const std::vector<char>& d )
|
||||||
|
|
@ -620,8 +621,9 @@ std::string to_base58( const std::vector<char>& d )
|
||||||
}
|
}
|
||||||
std::vector<char> from_base58( const std::string& base58_str ) {
|
std::vector<char> from_base58( const std::string& base58_str ) {
|
||||||
std::vector<unsigned char> out;
|
std::vector<unsigned char> out;
|
||||||
if( !DecodeBase58( base58_str.c_str(), out ) ) {
|
if( !fc::detail::DecodeBase58( base58_str.c_str(), out ) ) {
|
||||||
FC_THROW_EXCEPTION( parse_error_exception, "Unable to decode base58 string ${base58_str}", ("base58_str",base58_str) );
|
FC_THROW_EXCEPTION( parse_error_exception, "Unable to decode base58 string ${base58_str}",
|
||||||
|
("base58_str",base58_str) );
|
||||||
}
|
}
|
||||||
return std::vector<char>((const char*)out.data(), ((const char*)out.data())+out.size() );
|
return std::vector<char>((const char*)out.data(), ((const char*)out.data())+out.size() );
|
||||||
}
|
}
|
||||||
|
|
@ -629,10 +631,10 @@ std::vector<char> from_base58( const std::string& base58_str ) {
|
||||||
* @return the number of bytes decoded
|
* @return the number of bytes decoded
|
||||||
*/
|
*/
|
||||||
size_t from_base58( const std::string& base58_str, char* out_data, size_t out_data_len ) {
|
size_t from_base58( const std::string& base58_str, char* out_data, size_t out_data_len ) {
|
||||||
//slog( "%s", base58_str.c_str() );
|
|
||||||
std::vector<unsigned char> out;
|
std::vector<unsigned char> out;
|
||||||
if( !DecodeBase58( base58_str.c_str(), out ) ) {
|
if( !fc::detail::DecodeBase58( base58_str.c_str(), out ) ) {
|
||||||
FC_THROW_EXCEPTION( parse_error_exception, "Unable to decode base58 string ${base58_str}", ("base58_str",base58_str) );
|
FC_THROW_EXCEPTION( parse_error_exception, "Unable to decode base58 string ${base58_str}",
|
||||||
|
("base58_str",base58_str) );
|
||||||
}
|
}
|
||||||
FC_ASSERT( out.size() <= out_data_len );
|
FC_ASSERT( out.size() <= out_data_len );
|
||||||
if (!out.empty()) {
|
if (!out.empty()) {
|
||||||
|
|
@ -640,6 +642,7 @@ size_t from_base58( const std::string& base58_str, char* out_data, size_t out_da
|
||||||
}
|
}
|
||||||
return out.size();
|
return out.size();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
} // fc
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
#include <fc/rpc/api_connection.hpp>
|
#include <fc/rpc/api_connection.hpp>
|
||||||
#include <fc/rpc/websocket_api.hpp>
|
#include <fc/rpc/websocket_api.hpp>
|
||||||
|
|
||||||
|
namespace fc { namespace test {
|
||||||
|
|
||||||
class calculator
|
class calculator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -15,9 +17,6 @@ class calculator
|
||||||
void on_result2( const std::function<void(int32_t)>& cb, int test );
|
void on_result2( const std::function<void(int32_t)>& cb, int test );
|
||||||
};
|
};
|
||||||
|
|
||||||
FC_API( calculator, (add)(sub)(on_result)(on_result2) )
|
|
||||||
|
|
||||||
|
|
||||||
class login_api
|
class login_api
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -29,8 +28,6 @@ class login_api
|
||||||
fc::optional<fc::api<calculator>> calc;
|
fc::optional<fc::api<calculator>> calc;
|
||||||
std::set<std::string> test( const std::string&, const std::string& ) { return std::set<std::string>(); }
|
std::set<std::string> test( const std::string&, const std::string& ) { return std::set<std::string>(); }
|
||||||
};
|
};
|
||||||
FC_API( login_api, (get_calc)(test) );
|
|
||||||
|
|
||||||
|
|
||||||
class optionals_api
|
class optionals_api
|
||||||
{
|
{
|
||||||
|
|
@ -44,9 +41,6 @@ public:
|
||||||
return fc::json::to_string(fc::variants{{first,2}, {second, 2}, {third, 2}});
|
return fc::json::to_string(fc::variants{{first,2}, {second, 2}, {third, 2}});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
FC_API( optionals_api, (foo)(bar) );
|
|
||||||
|
|
||||||
using namespace fc;
|
|
||||||
|
|
||||||
class some_calculator
|
class some_calculator
|
||||||
{
|
{
|
||||||
|
|
@ -58,6 +52,12 @@ class some_calculator
|
||||||
std::function<void(int32_t)> _cb;
|
std::function<void(int32_t)> _cb;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}} // fc::test
|
||||||
|
|
||||||
|
FC_API( fc::test::calculator, (add)(sub)(on_result)(on_result2) )
|
||||||
|
FC_API( fc::test::login_api, (get_calc)(test) );
|
||||||
|
FC_API( fc::test::optionals_api, (foo)(bar) );
|
||||||
|
|
||||||
using namespace fc::http;
|
using namespace fc::http;
|
||||||
using namespace fc::rpc;
|
using namespace fc::rpc;
|
||||||
|
|
||||||
|
|
@ -67,14 +67,14 @@ BOOST_AUTO_TEST_SUITE(api_tests)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(login_test) {
|
BOOST_AUTO_TEST_CASE(login_test) {
|
||||||
try {
|
try {
|
||||||
fc::api<calculator> calc_api( std::make_shared<some_calculator>() );
|
fc::api<fc::test::calculator> calc_api( std::make_shared<fc::test::some_calculator>() );
|
||||||
|
|
||||||
auto server = std::make_shared<fc::http::websocket_server>();
|
auto server = std::make_shared<fc::http::websocket_server>();
|
||||||
server->on_connection([&]( const websocket_connection_ptr& c ){
|
server->on_connection([&]( const websocket_connection_ptr& c ){
|
||||||
auto wsc = std::make_shared<websocket_api_connection>(c, MAX_DEPTH);
|
auto wsc = std::make_shared<websocket_api_connection>(c, MAX_DEPTH);
|
||||||
auto login = std::make_shared<login_api>();
|
auto login = std::make_shared<fc::test::login_api>();
|
||||||
login->calc = calc_api;
|
login->calc = calc_api;
|
||||||
wsc->register_api(fc::api<login_api>(login));
|
wsc->register_api(fc::api<fc::test::login_api>(login));
|
||||||
c->set_session_data( wsc );
|
c->set_session_data( wsc );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(login_test) {
|
||||||
auto con = client->connect( "ws://localhost:" + std::to_string(listen_port) );
|
auto con = client->connect( "ws://localhost:" + std::to_string(listen_port) );
|
||||||
server->stop_listening();
|
server->stop_listening();
|
||||||
auto apic = std::make_shared<websocket_api_connection>(con, MAX_DEPTH);
|
auto apic = std::make_shared<websocket_api_connection>(con, MAX_DEPTH);
|
||||||
auto remote_login_api = apic->get_remote_api<login_api>();
|
auto remote_login_api = apic->get_remote_api<fc::test::login_api>();
|
||||||
auto remote_calc = remote_login_api->get_calc();
|
auto remote_calc = remote_login_api->get_calc();
|
||||||
bool remote_triggered = false;
|
bool remote_triggered = false;
|
||||||
remote_calc->on_result( [&remote_triggered]( uint32_t r ) { remote_triggered = true; } );
|
remote_calc->on_result( [&remote_triggered]( uint32_t r ) { remote_triggered = true; } );
|
||||||
|
|
@ -103,8 +103,8 @@ BOOST_AUTO_TEST_CASE(login_test) {
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(optionals_test) {
|
BOOST_AUTO_TEST_CASE(optionals_test) {
|
||||||
try {
|
try {
|
||||||
auto optionals = std::make_shared<optionals_api>();
|
auto optionals = std::make_shared<fc::test::optionals_api>();
|
||||||
fc::api<optionals_api> oapi(optionals);
|
fc::api<fc::test::optionals_api> oapi(optionals);
|
||||||
BOOST_CHECK_EQUAL(oapi->foo("a"), "[\"a\",null,null]");
|
BOOST_CHECK_EQUAL(oapi->foo("a"), "[\"a\",null,null]");
|
||||||
BOOST_CHECK_EQUAL(oapi->foo("a", "b"), "[\"a\",\"b\",null]");
|
BOOST_CHECK_EQUAL(oapi->foo("a", "b"), "[\"a\",\"b\",null]");
|
||||||
BOOST_CHECK_EQUAL(oapi->foo("a", "b", "c"), "[\"a\",\"b\",\"c\"]");
|
BOOST_CHECK_EQUAL(oapi->foo("a", "b", "c"), "[\"a\",\"b\",\"c\"]");
|
||||||
|
|
@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(optionals_test) {
|
||||||
auto server = std::make_shared<fc::http::websocket_server>();
|
auto server = std::make_shared<fc::http::websocket_server>();
|
||||||
server->on_connection([&]( const websocket_connection_ptr& c ){
|
server->on_connection([&]( const websocket_connection_ptr& c ){
|
||||||
auto wsc = std::make_shared<websocket_api_connection>(c, MAX_DEPTH);
|
auto wsc = std::make_shared<websocket_api_connection>(c, MAX_DEPTH);
|
||||||
wsc->register_api(fc::api<optionals_api>(optionals));
|
wsc->register_api(fc::api<fc::test::optionals_api>(optionals));
|
||||||
c->set_session_data( wsc );
|
c->set_session_data( wsc );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE(optionals_test) {
|
||||||
auto client = std::make_shared<fc::http::websocket_client>();
|
auto client = std::make_shared<fc::http::websocket_client>();
|
||||||
auto con = client->connect( "ws://localhost:" + std::to_string(listen_port) );
|
auto con = client->connect( "ws://localhost:" + std::to_string(listen_port) );
|
||||||
auto apic = std::make_shared<websocket_api_connection>(con, MAX_DEPTH);
|
auto apic = std::make_shared<websocket_api_connection>(con, MAX_DEPTH);
|
||||||
auto remote_optionals = apic->get_remote_api<optionals_api>();
|
auto remote_optionals = apic->get_remote_api<fc::test::optionals_api>();
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(remote_optionals->foo("a"), "[\"a\",null,null]");
|
BOOST_CHECK_EQUAL(remote_optionals->foo("a"), "[\"a\",null,null]");
|
||||||
BOOST_CHECK_EQUAL(remote_optionals->foo("a", "b"), "[\"a\",\"b\",null]");
|
BOOST_CHECK_EQUAL(remote_optionals->foo("a", "b"), "[\"a\",\"b\",null]");
|
||||||
|
|
@ -145,8 +145,8 @@ BOOST_AUTO_TEST_CASE(optionals_test) {
|
||||||
|
|
||||||
auto client2 = std::make_shared<fc::http::websocket_client>();
|
auto client2 = std::make_shared<fc::http::websocket_client>();
|
||||||
auto con2 = client2->connect( "ws://localhost:" + std::to_string(listen_port) );
|
auto con2 = client2->connect( "ws://localhost:" + std::to_string(listen_port) );
|
||||||
string response;
|
std::string response;
|
||||||
con2->on_message_handler([&](const std::string& s){
|
con2->on_message_handler([&response](const std::string& s){
|
||||||
response = s;
|
response = s;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,16 @@
|
||||||
#include <fc/network/tcp_socket.hpp>
|
#include <fc/network/tcp_socket.hpp>
|
||||||
#include <fc/asio.hpp>
|
#include <fc/asio.hpp>
|
||||||
|
|
||||||
|
namespace fc { namespace test {
|
||||||
|
|
||||||
|
class my_io_class : public fc::asio::default_io_service_scope
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void reset_num_threads() { fc::asio::default_io_service_scope::num_io_threads = 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // fc::test
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(tcp_tests)
|
BOOST_AUTO_TEST_SUITE(tcp_tests)
|
||||||
|
|
||||||
/***
|
/***
|
||||||
|
|
@ -15,23 +25,17 @@ BOOST_AUTO_TEST_CASE(tcpconstructor_test)
|
||||||
fc::tcp_socket socket;
|
fc::tcp_socket socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
class my_io_class : public fc::asio::default_io_service_scope
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void reset_num_threads() { fc::asio::default_io_service_scope::num_io_threads = 0; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Test the control of number of threads from outside
|
* Test the control of number of threads from outside
|
||||||
*/
|
*/
|
||||||
BOOST_AUTO_TEST_CASE( number_threads_test )
|
BOOST_AUTO_TEST_CASE( number_threads_test )
|
||||||
{
|
{
|
||||||
// to erase leftovers from previous tests
|
// to erase leftovers from previous tests
|
||||||
my_io_class::reset_num_threads();
|
fc::test::my_io_class::reset_num_threads();
|
||||||
|
|
||||||
fc::asio::default_io_service_scope::set_num_threads(12);
|
fc::asio::default_io_service_scope::set_num_threads(12);
|
||||||
|
|
||||||
my_io_class my_class;
|
fc::test::my_io_class my_class;
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL( 12, my_class.get_num_threads() );
|
BOOST_CHECK_EQUAL( 12, my_class.get_num_threads() );
|
||||||
}
|
}
|
||||||
|
|
@ -42,9 +46,9 @@ BOOST_AUTO_TEST_CASE( number_threads_test )
|
||||||
BOOST_AUTO_TEST_CASE( default_number_threads_test )
|
BOOST_AUTO_TEST_CASE( default_number_threads_test )
|
||||||
{
|
{
|
||||||
// to erase leftovers from previous tests
|
// to erase leftovers from previous tests
|
||||||
my_io_class::reset_num_threads();
|
fc::test::my_io_class::reset_num_threads();
|
||||||
|
|
||||||
my_io_class my_class;
|
fc::test::my_io_class my_class;
|
||||||
|
|
||||||
fc::asio::default_io_service();
|
fc::asio::default_io_service();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace fc { namespace test {
|
||||||
|
|
||||||
struct thread_config {
|
struct thread_config {
|
||||||
thread_config() {
|
thread_config() {
|
||||||
for( int i = 0; i < boost::unit_test::framework::master_test_suite().argc - 1; ++i )
|
for( int i = 0; i < boost::unit_test::framework::master_test_suite().argc - 1; ++i )
|
||||||
|
|
@ -42,13 +44,51 @@ struct thread_config {
|
||||||
{
|
{
|
||||||
uint16_t threads = atoi(boost::unit_test::framework::master_test_suite().argv[++i]);
|
uint16_t threads = atoi(boost::unit_test::framework::master_test_suite().argv[++i]);
|
||||||
std::cout << "Using " << threads << " pool threads\n";
|
std::cout << "Using " << threads << " pool threads\n";
|
||||||
fc::asio::default_io_service_scope::set_num_threads(threads);
|
asio::default_io_service_scope::set_num_threads(threads);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BOOST_GLOBAL_FIXTURE( thread_config );
|
const std::string TEXT = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"$%&/()=?,.-#+´{[]}`*'_:;<>|";
|
||||||
|
|
||||||
|
template<typename Hash>
|
||||||
|
class hash_test {
|
||||||
|
public:
|
||||||
|
std::string _hashname = get_typename<Hash>::name();
|
||||||
|
|
||||||
|
void run_single_threaded() {
|
||||||
|
const std::string first = Hash::hash(TEXT).str();
|
||||||
|
time_point start = time_point::now();
|
||||||
|
for( int i = 0; i < 1000; i++ )
|
||||||
|
BOOST_CHECK_EQUAL( first, Hash::hash(TEXT).str() );
|
||||||
|
time_point end = time_point::now();
|
||||||
|
ilog( "${c} single-threaded ${h}'s in ${t}µs", ("c",1000)("h",_hashname)("t",end-start) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_multi_threaded() {
|
||||||
|
const std::string first = Hash::hash(TEXT).str();
|
||||||
|
std::vector<future<std::string>> results;
|
||||||
|
results.reserve( 10000 );
|
||||||
|
time_point start = time_point::now();
|
||||||
|
for( int i = 0; i < 10000; i++ )
|
||||||
|
results.push_back( do_parallel( [] () { return Hash::hash(TEXT).str(); } ) );
|
||||||
|
for( auto& result: results )
|
||||||
|
BOOST_CHECK_EQUAL( first, result.wait() );
|
||||||
|
time_point end = time_point::now();
|
||||||
|
ilog( "${c} multi-threaded ${h}'s in ${t}µs", ("c",10000)("h",_hashname)("t",end-start) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
run_single_threaded();
|
||||||
|
run_multi_threaded();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // fc::test
|
||||||
|
|
||||||
|
using namespace fc::test;
|
||||||
|
|
||||||
|
BOOST_GLOBAL_FIXTURE( thread_config );
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(parallel_tests)
|
BOOST_AUTO_TEST_SUITE(parallel_tests)
|
||||||
|
|
||||||
|
|
@ -96,41 +136,6 @@ BOOST_AUTO_TEST_CASE( do_something_parallel )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string TEXT = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"$%&/()=?,.-#+´{[]}`*'_:;<>|";
|
|
||||||
|
|
||||||
template<typename Hash>
|
|
||||||
class hash_test {
|
|
||||||
public:
|
|
||||||
std::string _hashname = fc::get_typename<Hash>::name();
|
|
||||||
|
|
||||||
void run_single_threaded() {
|
|
||||||
const std::string first = Hash::hash(TEXT).str();
|
|
||||||
fc::time_point start = fc::time_point::now();
|
|
||||||
for( int i = 0; i < 1000; i++ )
|
|
||||||
BOOST_CHECK_EQUAL( first, Hash::hash(TEXT).str() );
|
|
||||||
fc::time_point end = fc::time_point::now();
|
|
||||||
ilog( "${c} single-threaded ${h}'s in ${t}µs", ("c",1000)("h",_hashname)("t",end-start) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_multi_threaded() {
|
|
||||||
const std::string first = Hash::hash(TEXT).str();
|
|
||||||
std::vector<fc::future<std::string>> results;
|
|
||||||
results.reserve( 10000 );
|
|
||||||
fc::time_point start = fc::time_point::now();
|
|
||||||
for( int i = 0; i < 10000; i++ )
|
|
||||||
results.push_back( fc::do_parallel( [] () { return Hash::hash(TEXT).str(); } ) );
|
|
||||||
for( auto& result: results )
|
|
||||||
BOOST_CHECK_EQUAL( first, result.wait() );
|
|
||||||
fc::time_point end = fc::time_point::now();
|
|
||||||
ilog( "${c} multi-threaded ${h}'s in ${t}µs", ("c",10000)("h",_hashname)("t",end-start) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void run() {
|
|
||||||
run_single_threaded();
|
|
||||||
run_multi_threaded();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( hash_parallel )
|
BOOST_AUTO_TEST_CASE( hash_parallel )
|
||||||
{
|
{
|
||||||
hash_test<fc::ripemd160>().run();
|
hash_test<fc::ripemd160>().run();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue