diff --git a/libraries/blockchain/address.cpp b/libraries/blockchain/address.cpp index 29244a3ef..44c578d03 100644 --- a/libraries/blockchain/address.cpp +++ b/libraries/blockchain/address.cpp @@ -11,40 +11,41 @@ namespace bts { address::address( const std::string& base58str ) { FC_ASSERT( is_valid( base58str ) ); - std::vector v = fc::from_base58( base58str.substr( strlen(BTS_ADDRESS_PREFIX) ) ); - memcpy( (char*)addr._hash, v.data(), std::min( v.size()-4, sizeof(addr) ) ); + std::string prefix( BTS_ADDRESS_PREFIX ); + std::vector v = fc::from_base58( base58str.substr( prefix.size() ) ); + memcpy( (char*)addr._hash, v.data(), std::min( v.size()-4, sizeof( addr ) ) ); } address::address( const withdraw_condition& condition ) { - // uint32_t address_type = 1; fc::sha512::encoder enc; fc::raw::pack( enc, condition ); - // enc.write( (char*)&address_type, sizeof(address_type) ); addr = fc::ripemd160::hash( enc.result() ); } /** * Validates checksum and length of base58 address * - // TODO is_valid should not throw, should return false... * @return true if successful, throws an exception with reason if invalid. */ + // TODO: This should return false rather than throwing bool address::is_valid( const std::string& base58str ) { try { - FC_ASSERT( base58str.size() > strlen(BTS_ADDRESS_PREFIX) ); // could probably increase from 10 to some min length - FC_ASSERT( base58str.substr( 0, strlen(BTS_ADDRESS_PREFIX) ) == BTS_ADDRESS_PREFIX ); - std::vector v = fc::from_base58( base58str.substr( strlen(BTS_ADDRESS_PREFIX) ) ); + std::string prefix( BTS_ADDRESS_PREFIX ); + const size_t prefix_len = prefix.size(); + FC_ASSERT( base58str.size() > prefix_len ); + FC_ASSERT( base58str.substr( 0, prefix_len ) == prefix ); + std::vector v = fc::from_base58( base58str.substr( prefix_len ) ); FC_ASSERT( v.size() > 4, "all addresses must have a 4 byte checksum" ); - FC_ASSERT(v.size() <= sizeof(fc::ripemd160) + 4, "all addresses are less than 24 bytes"); - auto checksum = fc::ripemd160::hash( v.data(), v.size() - 4 ); - FC_ASSERT( memcmp( v.data()+20, (char*)checksum._hash, 4 ) == 0, "address checksum mismatch" ); + FC_ASSERT(v.size() <= sizeof( fc::ripemd160 ) + 4, "all addresses are less than 24 bytes"); + const fc::ripemd160 checksum = fc::ripemd160::hash( v.data(), v.size() - 4 ); + FC_ASSERT( memcmp( v.data() + 20, (char*)checksum._hash, 4 ) == 0, "address checksum mismatch" ); return true; } FC_RETHROW_EXCEPTIONS( warn, "invalid address '${a}'", ("a", base58str) ) } address::address( const fc::ecc::public_key& pub ) { - auto dat = pub.serialize(); - addr = fc::ripemd160::hash( fc::sha512::hash( dat.data, sizeof(dat) ) ); + auto dat = pub.serialize(); + addr = fc::ripemd160::hash( fc::sha512::hash( dat.data, sizeof( dat ) ) ); } address::address( const pts_address& ptsaddr ) @@ -54,21 +55,21 @@ namespace bts { address::address( const fc::ecc::public_key_data& pub ) { - addr = fc::ripemd160::hash( fc::sha512::hash( pub.data, sizeof(pub) ) ); + addr = fc::ripemd160::hash( fc::sha512::hash( pub.data, sizeof( pub ) ) ); } address::address( const bts::blockchain::public_key_type& pub ) { - addr = fc::ripemd160::hash( fc::sha512::hash( pub.key_data.data, sizeof(pub.key_data) ) ); + addr = fc::ripemd160::hash( fc::sha512::hash( pub.key_data.data, sizeof( pub.key_data ) ) ); } address::operator std::string()const { fc::array bin_addr; - memcpy( (char*)&bin_addr, (char*)&addr, sizeof(addr) ); - auto checksum = fc::ripemd160::hash( (char*)&addr, sizeof(addr) ); + memcpy( (char*)&bin_addr, (char*)&addr, sizeof( addr ) ); + auto checksum = fc::ripemd160::hash( (char*)&addr, sizeof( addr ) ); memcpy( ((char*)&bin_addr)+20, (char*)&checksum._hash[0], 4 ); - return BTS_ADDRESS_PREFIX + fc::to_base58( bin_addr.data, sizeof(bin_addr) ); + return BTS_ADDRESS_PREFIX + fc::to_base58( bin_addr.data, sizeof( bin_addr ) ); } } } // namespace bts::blockchain diff --git a/libraries/blockchain/chain_database.cpp b/libraries/blockchain/chain_database.cpp index 6111d2b2c..b4473614b 100644 --- a/libraries/blockchain/chain_database.cpp +++ b/libraries/blockchain/chain_database.cpp @@ -48,16 +48,19 @@ namespace bts { namespace blockchain { vector trx_to_discard; _pending_trx_state = std::make_shared( self->shared_from_this() ); + unsigned num_pending_transaction_considered = 0; auto itr = _pending_transaction_db.begin(); while( itr.valid() ) { - auto trx = itr.value(); - auto trx_id = trx.id(); - try { - auto eval_state = self->evaluate_transaction( trx, _relay_fee ); + signed_transaction trx = itr.value(); + transaction_id_type trx_id = itr.key(); + assert(trx_id == trx.id()); + try + { + transaction_evaluation_state_ptr eval_state = self->evaluate_transaction( trx, _relay_fee ); share_type fees = eval_state->get_fees(); _pending_fee_index[ fee_index( fees, trx_id ) ] = eval_state; - _pending_transaction_db.store( trx_id, trx ); + wlog("revalidated pending transaction id ${id}", ("id", trx_id)); } catch ( const fc::canceled_exception& ) { @@ -69,11 +72,15 @@ namespace bts { namespace blockchain { wlog( "discarding invalid transaction: ${id} ${e}", ("id",trx_id)("e",e.to_detail_string()) ); } + ++num_pending_transaction_considered; ++itr; } for( const auto& item : trx_to_discard ) _pending_transaction_db.remove( item ); + wlog("revalidate_pending complete, there are now ${pending_count} evaluated transactions, ${num_pending_transaction_considered} raw transactions", + ("pending_count", _pending_fee_index.size()) + ("num_pending_transaction_considered", num_pending_transaction_considered)); } void chain_database_impl::open_database( const fc::path& data_dir ) @@ -347,7 +354,7 @@ namespace bts { namespace blockchain { { std::unordered_set confirmed_trx_ids; - for( const auto& trx : blk.user_transactions ) + for( const signed_transaction& trx : blk.user_transactions ) { auto id = trx.id(); confirmed_trx_ids.insert( id ); @@ -365,7 +372,8 @@ namespace bts { namespace blockchain { uint32_t last_checkpoint_block_num = 0; if( !CHECKPOINT_BLOCKS.empty() ) last_checkpoint_block_num = (--(CHECKPOINT_BLOCKS.end()))->first; - if( (!_revalidate_pending.valid() || _revalidate_pending.ready()) && _head_block_header.block_num >= last_checkpoint_block_num ) + if( (!_revalidate_pending.valid() || _revalidate_pending.ready()) && + _head_block_header.block_num >= last_checkpoint_block_num ) _revalidate_pending = fc::async( [=](){ revalidate_pending(); }, "revalidate_pending" ); _pending_trx_state = std::make_shared( self->shared_from_this() ); @@ -1870,10 +1878,13 @@ namespace bts { namespace blockchain { /** this should throw if the trx is invalid */ transaction_evaluation_state_ptr chain_database::store_pending_transaction( const signed_transaction& trx, bool override_limits ) { try { - auto trx_id = trx.id(); - auto current_itr = my->_pending_transaction_db.find( trx_id ); - if( current_itr.valid() ) return nullptr; + if (override_limits) + wlog("storing new local transaction with id ${id}", ("id", trx_id)); + + auto current_itr = my->_pending_transaction_db.find(trx_id); + if( current_itr.valid() ) + return nullptr; share_type relay_fee = my->_relay_fee; if( !override_limits ) @@ -1885,7 +1896,7 @@ namespace bts { namespace blockchain { } } - auto eval_state = evaluate_transaction( trx, relay_fee ); + transaction_evaluation_state_ptr eval_state = evaluate_transaction( trx, relay_fee ); share_type fees = eval_state->get_fees(); //if( fees < my->_relay_fee ) @@ -3152,7 +3163,7 @@ namespace bts { namespace blockchain { return prices[prices.size()/2]; } return oprice(); - } FC_CAPTURE_AND_RETHROW( (asset_id) ) } + } FC_CAPTURE_AND_RETHROW( (asset_id)(base_id) ) } vector chain_database::get_feeds_for_asset( const asset_id_type& asset_id, const asset_id_type& base_id )const { try { diff --git a/libraries/blockchain/extended_address.cpp b/libraries/blockchain/extended_address.cpp index 7e79902f3..69431c875 100644 --- a/libraries/blockchain/extended_address.cpp +++ b/libraries/blockchain/extended_address.cpp @@ -11,7 +11,7 @@ namespace bts { namespace blockchain { { } - extended_public_key::~extended_public_key(){} + extended_public_key::~extended_public_key(){} extended_public_key::extended_public_key( const fc::ecc::public_key& key, const fc::sha256& code ) :pub_key(key),chain_code(code) @@ -101,7 +101,7 @@ namespace bts { namespace blockchain { memcpy( (char*)&ikey_right, ((char*)&ikey) + sizeof(ikey_left), sizeof(ikey_right) ); child_key.priv_key = fc::ecc::private_key::generate_from_seed( priv_key, ikey_left ).get_secret(); - child_key.chain_code = ikey_right; + child_key.chain_code = ikey_right; return child_key; } FC_RETHROW_EXCEPTIONS( warn, "child index ${child_idx}", ("child_idx", child_idx ) ) } @@ -132,7 +132,7 @@ namespace bts { namespace blockchain { memcpy( (char*)&ikey_right, ((char*)&ikey) + sizeof(ikey_left), sizeof(ikey_right) ); child_key.priv_key = fc::ecc::private_key::generate_from_seed( priv_key, ikey_left ).get_secret(); - child_key.chain_code = ikey_right; + child_key.chain_code = ikey_right; return child_key; } FC_RETHROW_EXCEPTIONS( warn, "child index ${child_idx}", ("child_idx", child_idx ) ) } @@ -154,10 +154,12 @@ namespace bts { namespace blockchain { { try { uint32_t checksum = 0; - FC_ASSERT( base58str.size() > strlen( BTS_ADDRESS_PREFIX ) ); - FC_ASSERT( base58str.substr( 0, strlen( BTS_ADDRESS_PREFIX ) ) == BTS_ADDRESS_PREFIX ); + std::string prefix( BTS_ADDRESS_PREFIX ); + const size_t prefix_len = prefix.size(); + FC_ASSERT( base58str.size() > prefix_len ); + FC_ASSERT( base58str.substr( 0, prefix_len ) == prefix ); - std::vector data = fc::from_base58( base58str.substr( strlen( BTS_ADDRESS_PREFIX ) ) ); + std::vector data = fc::from_base58( base58str.substr( prefix_len ) ); FC_ASSERT( data.size() == (33+32+4) ); fc::datastream ds(data.data(),data.size()); @@ -196,8 +198,8 @@ namespace bts { namespace blockchain { } } // namespace bts::blockchain -namespace fc -{ +namespace fc +{ void to_variant( const bts::blockchain::extended_address& ext_addr, fc::variant& vo ) { vo = std::string(ext_addr); diff --git a/libraries/blockchain/include/bts/blockchain/checkpoints.hpp b/libraries/blockchain/include/bts/blockchain/checkpoints.hpp index b762dc6d4..a1ae6c752 100644 --- a/libraries/blockchain/include/bts/blockchain/checkpoints.hpp +++ b/libraries/blockchain/include/bts/blockchain/checkpoints.hpp @@ -13,5 +13,5 @@ const static std::map CHECKPOINT_BLOCK { 600000, bts::blockchain::block_id_type( "f278db8722235343c9db9f077fe67c54a5f25f3b" ) }, { 700000, bts::blockchain::block_id_type( "f120ff9b159661b9ac084a0a69c58dcbd79cbb49" ) }, { 800000, bts::blockchain::block_id_type( "0e94ad17c598e42e5ec2f522a05bf4df6a1778da" ) }, - { 855200, bts::blockchain::block_id_type( "d0dabe7b2a5c09a10f7b980dee02d8b48568adc8" ) } + { 863300, bts::blockchain::block_id_type( "9ad71eb07c202fdc81661d246c3d26ac2a4ba98f" ) } }; diff --git a/libraries/blockchain/types.cpp b/libraries/blockchain/types.cpp index e8e7b0945..34019b1f3 100644 --- a/libraries/blockchain/types.cpp +++ b/libraries/blockchain/types.cpp @@ -17,9 +17,10 @@ namespace bts { namespace blockchain { public_key_type::public_key_type( const std::string& base58str ) { - static const size_t prefix_len = strlen(BTS_ADDRESS_PREFIX); + std::string prefix( BTS_ADDRESS_PREFIX ); + const size_t prefix_len = prefix.size(); FC_ASSERT( base58str.size() > prefix_len ); - FC_ASSERT( base58str.substr( 0, prefix_len ) == BTS_ADDRESS_PREFIX, "", ("base58str", base58str) ); + FC_ASSERT( base58str.substr( 0, prefix_len ) == prefix , "", ("base58str", base58str) ); auto bin = fc::from_base58( base58str.substr( prefix_len ) ); auto bin_key = fc::raw::unpack(bin); key_data = bin_key.data; diff --git a/libraries/client/client.cpp b/libraries/client/client.cpp index 361ca4cfd..fb71717bb 100644 --- a/libraries/client/client.cpp +++ b/libraries/client/client.cpp @@ -228,7 +228,7 @@ void print_banner() { std::cout<<"================================================================\n"; std::cout<<"= =\n"; - std::cout<<"= Welcome to BitShares "<< std::setw(5) << std::left << BTS_ADDRESS_PREFIX<<" =\n"; + std::cout<<"= Welcome to BitShares "<< std::setw(5) << std::left << BTS_ADDRESS_PREFIX << " =\n"; std::cout<<"= =\n"; std::cout<<"= This software is in alpha testing and is not suitable for =\n"; std::cout<<"= real monetary transactions or trading. Use at your own =\n"; @@ -3302,7 +3302,7 @@ config load_config( const fc::path& datadir, bool enable_ulog ) info["blockchain_delegate_pay_rate"] = _chain_db->get_delegate_pay_rate(); info["blockchain_share_supply"] = variant(); - const auto share_record = _chain_db->get_asset_record( BTS_ADDRESS_PREFIX ); + const auto share_record = _chain_db->get_asset_record( BTS_BLOCKCHAIN_SYMBOL ); if( share_record.valid() ) info["blockchain_share_supply"] = share_record->current_share_supply; diff --git a/libraries/db/include/bts/db/cached_level_map.hpp b/libraries/db/include/bts/db/cached_level_map.hpp index a91c5fe1a..a786dd37f 100644 --- a/libraries/db/include/bts/db/cached_level_map.hpp +++ b/libraries/db/include/bts/db/cached_level_map.hpp @@ -43,13 +43,13 @@ namespace bts { namespace db { void flush() { - // TODO... - // start batch - for( auto item : _dirty ) - _db.store( item, _cache[item] ); - for( auto item : _dirty_remove ) - _db.remove( item ); - // end batch + typename level_map::write_batch batch = _db.create_batch(); + for( const auto& item : _dirty ) + batch.store(item, _cache[item]); + for( const auto& item : _dirty_remove ) + batch.remove(item); + batch.commit(); + _dirty.clear(); _dirty_remove.clear(); } diff --git a/libraries/db/include/bts/db/level_map.hpp b/libraries/db/include/bts/db/level_map.hpp index 14ef73803..4e2451244 100644 --- a/libraries/db/include/bts/db/level_map.hpp +++ b/libraries/db/include/bts/db/level_map.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -263,7 +264,89 @@ namespace bts { namespace db { return true; } FC_RETHROW_EXCEPTIONS( warn, "error reading last item from database" ); } - void store( const Key& k, const Value& v, bool sync = false ) + /** this class allows batched, atomic database writes. + * usage: + * { + * write_batch batch = _db.create_batch(); + * batch.store(key1, value1); + * batch.store(key2, value2); + * } + * when the batch goes out of scope, the operations are commited to the database + */ + class write_batch + { + private: + leveldb::WriteBatch _batch; + level_map* _map; + + friend class level_map; + write_batch(level_map* map) : + _map(map) + { + } + public: + ~write_batch() + { + try + { + commit(); + } + catch (const fc::canceled_exception&) + { + throw; + } + catch (const fc::exception&) + { + // we're in a destructor, nothing we can do... + } + } + + void commit() + { + try + { + FC_ASSERT(_map->is_open(), "Database is not open!"); + + ldb::Status status = _map->_db->Write(ldb::WriteOptions(), &_batch); + if (status.IsNotFound()) + FC_THROW_EXCEPTION(fc::key_not_found_exception, "unable to find key while applying batch"); + if (!status.ok()) + FC_THROW_EXCEPTION(db_exception, "database error while applying batch: ${msg}", ("msg", status.ToString())); + _batch.Clear(); + } + FC_RETHROW_EXCEPTIONS(warn, "error applying batch"); + } + + void abort() + { + _batch.Clear(); + } + + void store(const Key& k, const Value& v) + { + std::vector 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()); + + _batch.Put(ks, vs); + } + + void remove(const Key& k, bool sync = false) + { + std::vector kslice = fc::raw::pack(k); + ldb::Slice ks(kslice.data(), kslice.size()); + _batch.Delete(ks); + } + }; + + write_batch create_batch() + { + return write_batch(this); + } + + void store(const Key& k, const Value& v, bool sync = false) { try { FC_ASSERT( is_open(), "Database is not open!" ); diff --git a/libraries/fc b/libraries/fc index 307252e23..d1f51dd64 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 307252e23adfb43b41a6a4ff5683c72f86c0083a +Subproject commit d1f51dd643bc9063a56bd830208dfb0033cc81be diff --git a/libraries/leveldb b/libraries/leveldb index 42dcc7edf..028f94092 160000 --- a/libraries/leveldb +++ b/libraries/leveldb @@ -1 +1 @@ -Subproject commit 42dcc7edfc98c50038e4604fa630c626db17bf42 +Subproject commit 028f9409247be6d3d09a157e8eb347a173afc599 diff --git a/libraries/net/node.cpp b/libraries/net/node.cpp index e26310df4..88db81a0e 100644 --- a/libraries/net/node.cpp +++ b/libraries/net/node.cpp @@ -4236,7 +4236,7 @@ namespace bts { namespace net { namespace detail { { bts::client::trx_message transaction_message_to_broadcast = item_to_broadcast.as(); hash_of_message_contents = transaction_message_to_broadcast.trx.id(); // for debugging - dlog( "broadcasting trx: ${trx}", ("trx",transaction_message_to_broadcast) ); + dlog( "broadcasting trx: ${trx}", ("trx", transaction_message_to_broadcast) ); } message_hash_type hash_of_item_to_broadcast = item_to_broadcast.id(); diff --git a/programs/utils/CMakeLists.txt b/programs/utils/CMakeLists.txt index 76e154c4e..edb94ca68 100644 --- a/programs/utils/CMakeLists.txt +++ b/programs/utils/CMakeLists.txt @@ -33,6 +33,9 @@ target_link_libraries( map_bts_network fc bts_net bts_client) add_executable( pack_web pack_web.cpp ) target_link_libraries( pack_web fc ) +add_executable( compute_item_hashes compute_item_hashes.cpp ) +target_link_libraries( compute_item_hashes fc bts_net bts_client) + if( ${INCLUDE_QT_WALLET} ) add_subdirectory( web_update_utility ) endif() diff --git a/programs/utils/compute_item_hashes.cpp b/programs/utils/compute_item_hashes.cpp new file mode 100644 index 000000000..23f25277a --- /dev/null +++ b/programs/utils/compute_item_hashes.cpp @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + + +int main(int argc, char*argv[]) +{ + for (;;) + { + fc::variant json_as_variant; + try + { + fc::buffered_istream istream(fc::cin_ptr); + json_as_variant = fc::json::from_stream(istream); + } + catch (const fc::eof_exception& e) + { + elog("EOF, exiting"); + return 0; + } + catch (const fc::exception& e) + { + elog("Error parsing json: ${what}", ("what", e.to_string())); + continue; + } + + fc::variant_object json_as_variant_object; + try + { + json_as_variant_object = json_as_variant.get_object(); + } + catch (const fc::exception& e) + { + elog("Error interpreting json as object: ${what}", ("what", e.to_string())); + continue; + } + + if (json_as_variant_object.contains("trx")) + { + ilog("Object contains the key 'trx', assuming it is a trx_message"); + bts::client::trx_message trx_msg; + try + { + trx_msg = json_as_variant.as(); + } + catch (const fc::exception& e) + { + elog("Error interpreting json as bts::client::trx_message: ${what}", ("what", e.to_string())); + } + + ilog("Parsed bts::client::trx_message with id ${msg_id} containing transaction ${trx_id}", + ("msg_id", bts::net::message(trx_msg).id())("trx_id", trx_msg.trx.id())); + } + } + +#if 0 + + // parse command-line options + boost::program_options::options_description option_config("Allowed options"); + option_config.add_options()("help", "display this help message") + ("prologue" , boost::program_options::value(), "Add the contents of this file to start of generated C++ source") + ("epilogue" , boost::program_options::value(), "Add the contents of this file to end of generated C++ source") + ("json" , boost::program_options::value(), "The json file to convert to C++ source code") + ("out" , boost::program_options::value(), "The file to generate"); + boost::program_options::variables_map option_variables; + try + { + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(option_config).run(), option_variables); + boost::program_options::notify(option_variables); + } + catch (boost::program_options::error&) + { + std::cerr << "Error parsing command-line options\n\n"; + std::cerr << option_config << "\n"; + return 1; + } +#endif + return 0; +} diff --git a/programs/web_wallet b/programs/web_wallet index 81f0281e2..a62cbd8a4 160000 --- a/programs/web_wallet +++ b/programs/web_wallet @@ -1 +1 @@ -Subproject commit 81f0281e2ce26c3086a6c18a70bb5157edb62572 +Subproject commit a62cbd8a4a54db2b6a0b92895b1f3f8c92cdbe61