parameter_description_list api_generator::load_parameters(const fc::variants& json_parameter_descriptions) { parameter_description_list parameters; for (const fc::variant& parameter_description_variant : json_parameter_descriptions) { fc::variant_object json_parameter_description = parameter_description_variant.get_object(); parameter_description parameter; FC_ASSERT(json_parameter_description.contains("name"), "parameter is missing \"name\""); parameter.name = json_parameter_description["name"].as_string(); try { FC_ASSERT(json_parameter_description.contains("description"), "parameter is missing \"description\""); parameter.description = json_parameter_description["description"].as_string(); FC_ASSERT(json_parameter_description.contains("type"), "parameter is missing \"type\""); parameter.type = lookup_type_mapping(json_parameter_description["type"].as_string()); if( json_parameter_description.contains( "prompt" ) ) parameter.prompt = json_parameter_description["prompt"].as_bool(); if (json_parameter_description.contains("default_value")) parameter.default_value = json_parameter_description["default_value"]; if (json_parameter_description.contains("example")) parameter.example = json_parameter_description["example"]; } FC_RETHROW_EXCEPTIONS(error, "error processing parameter ${name}", ("name", parameter.name)); parameters.push_back(parameter); } return parameters; }
char parseEscape( T& in ) { if( in.peek() == '\\' ) { try { in.get(); switch( in.peek() ) { case 't': in.get(); return '\t'; case 'n': in.get(); return '\n'; case 'r': in.get(); return '\r'; case '\\': in.get(); return '\\'; default: return in.get(); } } FC_RETHROW_EXCEPTIONS( info, "Stream ended with '\\'" ); } FC_THROW_EXCEPTION( parse_error_exception, "Expected '\\'" ); }
void signed_transaction::sign( const fc::ecc::private_key& k ) { try { sigs.insert( k.sign_compact( digest() ) ); } FC_RETHROW_EXCEPTIONS( warn, "error signing transaction", ("trx", *this ) ); }
void stcp_socket::close() { try { _sock.close(); }FC_RETHROW_EXCEPTIONS( warn, "error closing stcp socket" ); }
/** * A price will reorder the asset types such that the * asset type with the lower enum value is always the * denominator. Therefore bts/usd and usd/bts will * always result in a price measured in usd/bts because * asset::bts < asset::usd. */ price operator / ( const asset& a, const asset& b ) { try { if( a.asset_id == b.asset_id ) FC_CAPTURE_AND_THROW( asset_divide_by_self ); price p; auto l = a; auto r = b; if( l.asset_id < r.asset_id ) { std::swap(l,r); } ilog( "${a} / ${b}", ("a",l)("b",r) ); if( r.amount == 0 ) FC_CAPTURE_AND_THROW( asset_divide_by_zero, (r) ); p.base_asset_id = r.asset_id; p.quote_asset_id = l.asset_id; fc::bigint bl = l.amount; fc::bigint br = r.amount; fc::bigint result = (bl * fc::bigint(BTS_PRICE_PRECISION)) / br; p.ratio = result; return p; } FC_RETHROW_EXCEPTIONS( warn, "${a} / ${b}", ("a",a)("b",b) ); }
variants arrayFromStream( T& in ) { variants ar; try { if( in.peek() != '[' ) FC_THROW_EXCEPTION( parse_error_exception, "Expected '['" ); in.get(); skip_white_space(in); while( in.peek() != ']' ) { if( in.peek() == ',' ) { in.get(); continue; } if( skip_white_space(in) ) continue; ar.push_back( variant_from_stream<T, parser_type>(in) ); skip_white_space(in); } if( in.peek() != ']' ) FC_THROW_EXCEPTION( parse_error_exception, "Expected ']' after parsing ${variant}", ("variant", ar) ); in.get(); } FC_RETHROW_EXCEPTIONS( warn, "Attempting to parse array ${array}", ("array", ar ) ); return ar; }
variants arrayFromStreamBase( T& in, std::function<variant(T&)>& get_value ) { variants ar; try { if( in.peek() != '[' ) FC_THROW_EXCEPTION( parse_error_exception, "Expected '['" ); in.get(); while( in.peek() != ']' ) { if( in.peek() == ',' ) { in.get(); continue; } if( skip_white_space(in) ) continue; ar.push_back( get_value(in) ); } if( in.peek() != ']' ) FC_THROW_EXCEPTION( parse_error_exception, "Expected ']' after parsing ${variant}", ("variant", ar) ); in.get(); } FC_RETHROW_EXCEPTIONS( warn, "Attempting to parse array ${array}", ("array", ar ) ); return ar; }
/** * A price will reorder the asset types such that the * asset type with the lower enum value is always the * denominator. Therefore bts/usd and usd/bts will * always result in a price measured in usd/bts because * asset::bts < asset::usd. */ price operator / ( const asset& a, const asset& b ) { try { ilog( "${a} / ${b}", ("a",a)("b",b) ); price p; auto l = a; auto r = b; if( l.asset_id < r.asset_id ) { std::swap(l,r); } ilog( "${a} / ${b}", ("a",l)("b",r) ); p.base_asset_id = r.asset_id; p.quote_asset_id = l.asset_id; //fc::uint128 bl(l.amount); //fc::uint128 bl(r.amount); // p.ratio = (bl* BTS_PRICE_PRECISION) / br; fc::bigint bl = l.amount; fc::bigint br = r.amount; fc::bigint result = (bl * fc::bigint(BTS_PRICE_PRECISION)) / br; p.ratio = result; return p; } FC_RETHROW_EXCEPTIONS( warn, "${a} / ${b}", ("a",a)("b",b) ); }
void tcp_socket::close() { try { if( is_open() ) { my->_sock.close(); } } FC_RETHROW_EXCEPTIONS( warn, "error closing tcp socket" ); }
void tcp_server::accept( tcp_socket& s ) { try { FC_ASSERT( my != nullptr ); fc::asio::tcp::accept( my->_accept, s.my->_sock ); } FC_RETHROW_EXCEPTIONS( warn, "Unable to accept connection on socket." ); }
fc::ip::endpoint tcp_socket::remote_endpoint()const { try { auto rep = my->_sock.remote_endpoint(); return fc::ip::endpoint(rep.address().to_v4().to_ulong(), rep.port() ); } FC_RETHROW_EXCEPTIONS( warn, "error getting socket's remote endpoint" ); }
fc::ip::endpoint tcp_socket::local_endpoint() const { try { auto boost_local_endpoint = my->_sock.local_endpoint(); return fc::ip::endpoint(boost_local_endpoint.address().to_v4().to_ulong(), boost_local_endpoint.port() ); } FC_RETHROW_EXCEPTIONS( warn, "error getting socket's local endpoint" ); }
std::string tokenFromStream( T& in ) { fc::stringstream token; try { char c = in.peek(); while( true ) { switch( c = in.peek() ) { case '\\': token << parseEscape( in ); break; case '\t': case ' ': case ',': case ':': case '\0': case '\n': case '\x04': in.get(); return token.str(); case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '_': case '-': case '.': case '+': case '/': token << c; in.get(); break; default: return token.str(); } } return token.str(); } catch( const fc::eof_exception& eof ) { return token.str(); } catch (const std::ios_base::failure&) { return token.str(); } FC_RETHROW_EXCEPTIONS( warn, "while parsing token '${token}'", ("token", token.str() ) ); }
/** * Assuming a.type is either the numerator.type or denominator.type in * the price equation, return the number of the other asset type that * could be exchanged at price p. * * ie: p = 3 usd/bts & a = 4 bts then result = 12 usd * ie: p = 3 usd/bts & a = 4 usd then result = 1.333 bts */ asset operator * ( const asset& a, const price& p ) { try { if( a.asset_id == p.base_asset_id ) { fc::bigint ba( a.amount ); // 64.64 fc::bigint r( p.ratio ); // 64.64 auto amnt = ba * r; // 128.128 amnt /= BTS_PRICE_PRECISION; // 128.64 auto lg2 = amnt.log2(); if( lg2 >= 128 ) { FC_THROW_EXCEPTION( addition_overflow, "overflow ${a} * ${p}", ("a",a)("p",p) ); } asset rtn; rtn.amount = amnt.to_int64(); rtn.asset_id = p.quote_asset_id; ilog( "${a} * ${p} => ${rtn}", ("a", a)("p",p )("rtn",rtn) ); return rtn; } else if( a.asset_id == p.quote_asset_id ) { fc::bigint amt( a.amount ); // 64.64 amt *= BTS_PRICE_PRECISION; //<<= 64; // 64.128 fc::bigint pri( p.ratio ); // 64.64 auto result = amt / pri; // 64.64 // ilog( "amt: ${amt} / ${pri}", ("amt",string(amt))("pri",string(pri) ) ); // ilog( "${r}", ("r",string(result) ) ); auto lg2 = result.log2(); if( lg2 >= 128 ) { // wlog( "." ); FC_THROW_EXCEPTION( addition_overflow, "overflow ${a} / ${p} = ${r} lg2 = ${l}", ("a",a)("p",p)("r", std::string(result) )("l",lg2) ); } // result += 5000000000; // TODO: evaluate this rounding factor.. asset r; r.amount = result.to_int64(); r.asset_id = p.base_asset_id; ilog( "r.amount = ${r}", ("r",r.amount) ); ilog( "${a} * ${p} => ${rtn}", ("a", a)("p",p )("rtn",r) ); return r; } FC_THROW_EXCEPTION( asset_type_mismatch, "type mismatch multiplying asset ${a} by price ${p}", ("a",a)("p",p) ); } FC_RETHROW_EXCEPTIONS( warn, "type mismatch multiplying asset ${a} by price ${p}", ("a",a)("p",p) ); }
std::string stringFromStream( T& in ) { try { char c = in.peek(), c2; switch( c ) { case '\'': if( strict ) FC_THROW_EXCEPTION( parse_error_exception, "expected: '\"' at beginning of string, got '\''" ); // falls through case '"': return quoteStringFromStream<T, strict, true>( in ); case 'r': if( strict ) FC_THROW_EXCEPTION( parse_error_exception, "raw strings not supported in strict mode" ); case 'R': in.get(); c2 = in.peek(); switch( c2 ) { case '"': case '\'': if( strict ) FC_THROW_EXCEPTION( parse_error_exception, "raw strings not supported in strict mode" ); return quoteStringFromStream<T, strict, false>( in ); default: if( strict ) FC_THROW_EXCEPTION( parse_error_exception, "unquoted strings not supported in strict mode" ); return c+tokenFromStream( in ); } break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '_': case '-': case '.': case '+': case '/': if( strict ) FC_THROW_EXCEPTION( parse_error_exception, "unquoted strings not supported in strict mode" ); return tokenFromStream( in ); default: FC_THROW_EXCEPTION( parse_error_exception, "expected: string" ); } } FC_RETHROW_EXCEPTIONS( warn, "while parsing string" ); return {}; }
void connection::connect( const fc::ip::endpoint& ep ) { try { // TODO: do we have to worry about multiple calls to connect? my->sock = std::make_shared<stcp_socket>(); my->sock->connect_to(ep); my->remote_ep = remote_endpoint(); ilog( " connected to ${ep}", ("ep", ep) ); my->_read_loop_complete = fc::async( [=](){ my->read_loop(); } ); } FC_RETHROW_EXCEPTIONS( warn, "error connecting to ${ep}", ("ep",ep) ); }
void tcp_server::listen( uint16_t port ) { if( !my ) my = new impl; try { my->_accept.bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4(), port)); my->_accept.listen(256); } FC_RETHROW_EXCEPTIONS(warn, "error listening on socket"); }
void tcp_server::listen( const fc::ip::endpoint& ep ) { if( !my ) my = new impl; try { my->_accept.bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4::from_string((string)ep.get_address()), ep.port())); my->_accept.listen(); } FC_RETHROW_EXCEPTIONS(warn, "error listening on socket"); }
/** * Adds the owner to the required signature list * Adds the balance to the trx balance sheet * * TODO: this input is also valid if it is 1 year old and an output exists * paying 95% of the balance back to the owner. * * TODO: what if the source is an unvested market order... it means the * proceeds of this trx are also 'unvested'. Perhaps we will have to * propagate the vested state along with the trx, if any inputs are * sourced from an unvested trx, the new trx is also 'unvested' until * the most receint input is fully vested. */ void trx_validation_state::validate_signature( const meta_trx_input& in ) { try { auto cbs = in.output.as<claim_by_signature_output>(); ilog( "${cbs}", ("cbs",cbs)); required_sigs.insert( cbs.owner ); asset output_bal( in.output.amount, in.output.unit ); balance_sheet[(asset::type)in.output.unit].in += output_bal; } FC_RETHROW_EXCEPTIONS( warn, "validating signature input ${i}", ("i",in) ); }
void connection::send( const message& m ) { try { fc::scoped_lock<fc::mutex> lock(my->write_lock); size_t len = MAIL_PACKED_MESSAGE_HEADER + m.size; len = 16*((len+15)/16); //pad the message we send to a multiple of 16 bytes std::vector<char> tmp(len); memcpy( tmp.data(), (char*)&m, MAIL_PACKED_MESSAGE_HEADER ); memcpy( tmp.data() + MAIL_PACKED_MESSAGE_HEADER, m.data.data(), m.size ); my->sock->write( tmp.data(), tmp.size() ); my->sock->flush(); } FC_RETHROW_EXCEPTIONS( warn, "unable to send message" ); }
variant_object objectFromStream( T& in, uint32_t depth ) { depth++; FC_ASSERT( depth <= JSON_MAX_RECURSION_DEPTH ); mutable_variant_object obj; try { char c = in.peek(); if( c != '{' ) FC_THROW_EXCEPTION( parse_error_exception, "Expected '{', but read '${char}'", ("char",string(&c, &c + 1)) ); in.get(); skip_white_space( in, depth ); while( in.peek() != '}' ) { if( in.peek() == ',' ) { in.get(); continue; } if( skip_white_space( in, depth ) ) continue; string key = stringFromStream( in, depth ); skip_white_space( in, depth ); if( in.peek() != ':' ) { FC_THROW_EXCEPTION( parse_error_exception, "Expected ':' after key \"${key}\"", ("key", key) ); } in.get(); auto val = variant_from_stream<T, parser_type>( in, depth ); obj(std::move(key),std::move(val)); skip_white_space( in, depth ); } if( in.peek() == '}' ) { in.get(); return obj; } FC_THROW_EXCEPTION( parse_error_exception, "Expected '}' after ${variant}", ("variant", obj ) ); } catch( const fc::eof_exception& e ) { FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF: ${e}", ("e", e.to_detail_string() ) ); } catch( const std::ios_base::failure& e ) { FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF: ${e}", ("e", e.what() ) ); } FC_RETHROW_EXCEPTIONS( warn, "Error parsing object" ); }
void store( const Key& k, const Value& v, bool sync = false ) { try { FC_ASSERT( is_open(), "Database is not open!" ); ldb::Slice ks( (char*)&k, sizeof(k) ); auto vec = fc::raw::pack(v); ldb::Slice vs( vec.data(), vec.size() ); auto status = _db->Put( sync ? _sync_options : _write_options, ks, vs ); if( !status.ok() ) { FC_THROW_EXCEPTION( level_pod_map_failure, "database error: ${msg}", ("msg", status.ToString() ) ); } } FC_RETHROW_EXCEPTIONS( warn, "error storing ${key} = ${value}", ("key",k)("value",v) ); }
void api_generator::load_method_descriptions(const fc::variants& method_descriptions) { for (const fc::variant& method_description_variant : method_descriptions) { fc::variant_object json_method_description = method_description_variant.get_object(); FC_ASSERT(json_method_description.contains("method_name"), "method entry missing \"method_name\""); std::string method_name = json_method_description["method_name"].as_string(); FC_ASSERT(_registered_method_names.find(method_name) == _registered_method_names.end(), "Error: multiple methods registered with the name ${name}", ("name", method_name)); _registered_method_names.insert(method_name); try { method_description method; method.name = method_name; FC_ASSERT(json_method_description.contains("return_type"), "method entry missing \"return_type\""); std::string return_type_name = json_method_description["return_type"].as_string(); method.return_type = lookup_type_mapping(return_type_name); FC_ASSERT(json_method_description.contains("parameters"), "method entry missing \"parameters\""); method.parameters = load_parameters(json_method_description["parameters"].get_array()); method.is_const = json_method_description.contains("is_const") && json_method_description["is_const"].as_bool(); FC_ASSERT(json_method_description.contains("prerequisites"), "method entry missing \"prerequisites\""); method.prerequisites = load_prerequisites(json_method_description["prerequisites"]); if (json_method_description.contains("aliases")) { method.aliases = json_method_description["aliases"].as<std::vector<std::string> >(); for (const std::string& alias : method.aliases) { FC_ASSERT(_registered_method_names.find(alias) == _registered_method_names.end(), "Error: alias \"${alias}\" conflicts with an existing method or alias", ("alias", alias)); _registered_method_names.insert(alias); } } if (json_method_description.contains("description")) method.brief_description = json_method_description["description"].as_string(); if (json_method_description.contains("detailed_description")) method.detailed_description = json_method_description["detailed_description"].as_string(); _methods.push_back(method); } FC_RETHROW_EXCEPTIONS(warn, "error encountered parsing method description for method \"${method_name}\"", ("method_name", method_name)); } }
bool last( Key& k ) { try { FC_ASSERT( is_open(), "Database is not open!" ); std::unique_ptr<ldb::Iterator> it( _db->NewIterator( _iter_options ) ); FC_ASSERT( it != nullptr ); it->SeekToLast(); if( !it->Valid() ) { return false; } FC_ASSERT( sizeof( Key) == it->key().size() ); k = *((Key*)it->key().data()); return true; } FC_RETHROW_EXCEPTIONS( warn, "error reading last item from database" ); }
void store( const Key& k, const Value& v ) { try { ldb::Slice ks( (char*)&k, sizeof(k) ); auto vec = fc::raw::pack(v); ldb::Slice vs( vec.data(), vec.size() ); auto status = _db->Put( ldb::WriteOptions(), ks, vs ); if( !status.ok() ) { FC_THROW_EXCEPTION( exception, "database error: ${msg}", ("msg", status.ToString() ) ); } } FC_RETHROW_EXCEPTIONS( warn, "error storing ${key} = ${value}", ("key",k)("value",v) ); }
bool last( Key& k ) { try { FC_ASSERT( is_open(), "Database is not open!" ); std::unique_ptr<ldb::Iterator> it( _db->NewIterator( ldb::ReadOptions() ) ); FC_ASSERT( it != nullptr ); it->SeekToLast(); if( !it->Valid() ) { return false; } fc::datastream<const char*> ds2( it->key().data(), it->key().size() ); fc::raw::unpack( ds2, k ); return true; } FC_RETHROW_EXCEPTIONS( warn, "error reading last item from database" ); }
void remove( const Key& k, bool sync = false ) { try { FC_ASSERT( is_open(), "Database is not open!" ); ldb::Slice ks( (char*)&k, sizeof(k) ); auto status = _db->Delete( sync ? _sync_options : _write_options, ks ); if( status.IsNotFound() ) { FC_THROW_EXCEPTION( fc::key_not_found_exception, "unable to find key ${key}", ("key",k) ); } if( !status.ok() ) { FC_THROW_EXCEPTION( level_pod_map_failure, "database error: ${msg}", ("msg", status.ToString() ) ); } } FC_RETHROW_EXCEPTIONS( warn, "error removing ${key}", ("key",k) ); }
void message_oriented_connection_impl::send_message(const message& message_to_send) { VERIFY_CORRECT_THREAD(); #if 0 // this gets too verbose #ifndef NDEBUG fc::optional<fc::ip::endpoint> remote_endpoint; if (_sock.get_socket().is_open()) remote_endpoint = _sock.get_socket().remote_endpoint(); struct scope_logger { const fc::optional<fc::ip::endpoint>& endpoint; scope_logger(const fc::optional<fc::ip::endpoint>& endpoint) : endpoint(endpoint) { dlog("entering message_oriented_connection::send_message() for peer ${endpoint}", ("endpoint", endpoint)); } ~scope_logger() { dlog("leaving message_oriented_connection::send_message() for peer ${endpoint}", ("endpoint", endpoint)); } } send_message_scope_logger(remote_endpoint); #endif #endif struct verify_no_send_in_progress { bool& var; verify_no_send_in_progress(bool& var) : var(var) { if (var) elog("Error: two tasks are calling message_oriented_connection::send_message() at the same time"); assert(!var); var = true; } ~verify_no_send_in_progress() { var = false; } } _verify_no_send_in_progress(_send_message_in_progress); try { size_t size_of_message_and_header = sizeof(message_header) + message_to_send.size; if( message_to_send.size > MAX_MESSAGE_SIZE ) elog("Trying to send a message larger than MAX_MESSAGE_SIZE. This probably won't work..."); //pad the message we send to a multiple of 16 bytes size_t size_with_padding = 16 * ((size_of_message_and_header + 15) / 16); std::unique_ptr<char[]> padded_message(new char[size_with_padding]); memcpy(padded_message.get(), (char*)&message_to_send, sizeof(message_header)); memcpy(padded_message.get() + sizeof(message_header), message_to_send.data.data(), message_to_send.size ); char* paddingSpace = padded_message.get() + sizeof(message_header) + message_to_send.size; size_t toClean = size_with_padding - size_of_message_and_header; memset(paddingSpace, 0, toClean); _sock.write(padded_message.get(), size_with_padding); _sock.flush(); _bytes_sent += size_with_padding; _last_message_sent_time = fc::time_point::now(); } FC_RETHROW_EXCEPTIONS( warn, "unable to send message" ); }
void remove( const Key& k, bool sync = false ) { try { FC_ASSERT( is_open(), "Database is not open!" ); std::vector<char> kslice = fc::raw::pack( k ); ldb::Slice ks( kslice.data(), kslice.size() ); auto status = _db->Delete( ldb::WriteOptions(), ks ); if( status.IsNotFound() ) { FC_THROW_EXCEPTION( fc::key_not_found_exception, "unable to find key ${key}", ("key",k) ); } if( !status.ok() ) { FC_THROW_EXCEPTION( db_exception, "database error: ${msg}", ("msg", status.ToString() ) ); } } FC_RETHROW_EXCEPTIONS( warn, "error removing ${key}", ("key",k) ); }
void store( const Key& k, const Value& v, bool sync = false ) { try { FC_ASSERT( is_open(), "Database is not open!" ); std::vector<char> kslice = fc::raw::pack( k ); ldb::Slice ks( kslice.data(), kslice.size() ); auto vec = fc::raw::pack(v); ldb::Slice vs( vec.data(), vec.size() ); auto status = _db->Put( ldb::WriteOptions(), ks, vs ); if( !status.ok() ) { FC_THROW_EXCEPTION( db_exception, "database error: ${msg}", ("msg", status.ToString() ) ); } } FC_RETHROW_EXCEPTIONS( warn, "error storing ${key} = ${value}", ("key",k)("value",v) ); }