diff --git a/libraries/chain/asset.cpp b/libraries/chain/asset.cpp index 36963571..c03cd11d 100644 --- a/libraries/chain/asset.cpp +++ b/libraries/chain/asset.cpp @@ -90,7 +90,7 @@ namespace graphene { namespace chain { FC_ASSERT( result <= GRAPHENE_MAX_SHARE_SUPPLY ); return asset( result.to_uint64(), b.base.asset_id ); } - FC_ASSERT( !"invalid asset * price", "", ("asset",a)("price",b) ); + FC_THROW_EXCEPTION( fc::assert_exception, "invalid asset * price", ("asset",a)("price",b) ); } price operator / ( const asset& base, const asset& quote ) diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 6c749a8e..9d9e3bdb 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -453,7 +453,10 @@ processed_transaction database::_apply_transaction( const signed_transaction& tr eval_state._sigs.reserve( trx.signatures.size() ); for( const auto& sig : trx.signatures ) + { FC_ASSERT( eval_state._sigs.insert( std::make_pair( public_key_type(fc::ecc::public_key( sig, trx.digest() )), false) ).second, "Multiple signatures by same key detected" ) ; + } + } //If we're skipping tapos check, but not dupe check, assume all transactions have maximum expiration time. @@ -531,9 +534,11 @@ processed_transaction database::_apply_transaction( const signed_transaction& tr eval_state._sigs.reserve( trx.signatures.size() ); for( const auto& sig : trx.signatures ) + { FC_ASSERT(eval_state._sigs.insert( std::make_pair(public_key_type(fc::ecc::public_key(sig, trx.digest(tapos_block_summary.block_id) )), false)).second, "Multiple signatures by same key detected"); + } } //Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration @@ -579,7 +584,9 @@ processed_transaction database::_apply_transaction( const signed_transaction& tr if( !(skip & (skip_transaction_signatures|skip_authority_check)) ) { for( const auto& item : eval_state._sigs ) + { FC_ASSERT( item.second, "All signatures must be used", ("item",item) ); + } } return ptrx; diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 8d9d7c47..c33ad3d0 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -107,12 +107,12 @@ void database::update_active_witnesses() assert( _witness_count_histogram_buffer.size() > 0 ); share_type stake_target = _total_voting_stake / 2; share_type stake_tally = _witness_count_histogram_buffer[0]; - int witness_count = 0; - while( (size_t(witness_count) < _witness_count_histogram_buffer.size()) + size_t witness_count = 0; + while( (witness_count < _witness_count_histogram_buffer.size() - 1) && (stake_tally <= stake_target) ) stake_tally += _witness_count_histogram_buffer[++witness_count]; - auto wits = sort_votable_objects(std::max(witness_count*2+1, GRAPHENE_MIN_WITNESS_COUNT)); + auto wits = sort_votable_objects(std::max(witness_count*2+1, (size_t)GRAPHENE_MIN_WITNESS_COUNT)); const global_property_object& gpo = get_global_properties(); // Update witness authority @@ -173,12 +173,12 @@ void database::update_active_delegates() assert( _committee_count_histogram_buffer.size() > 0 ); uint64_t stake_target = _total_voting_stake / 2; uint64_t stake_tally = _committee_count_histogram_buffer[0]; - int delegate_count = 0; - while( (size_t(delegate_count) < _committee_count_histogram_buffer.size()) + size_t delegate_count = 0; + while( (delegate_count < _committee_count_histogram_buffer.size() - 1) && (stake_tally <= stake_target) ) stake_tally += _committee_count_histogram_buffer[++delegate_count]; - auto delegates = sort_votable_objects(std::max(delegate_count*2+1, GRAPHENE_MIN_DELEGATE_COUNT)); + auto delegates = sort_votable_objects(std::max(delegate_count*2+1, (size_t)GRAPHENE_MIN_DELEGATE_COUNT)); // Update genesis authorities if( !delegates.empty() ) diff --git a/libraries/chain/include/graphene/chain/balance_evaluator.hpp b/libraries/chain/include/graphene/chain/balance_evaluator.hpp index 6b2c8b22..fb3276d6 100644 --- a/libraries/chain/include/graphene/chain/balance_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/balance_evaluator.hpp @@ -21,8 +21,15 @@ public: database& d = db(); balance = &op.balance_to_claim(d); - - FC_ASSERT(trx_state->signed_by( balance->owner, true /*maybe pts*/ )); + FC_ASSERT(op.balance_owner_key == balance->owner || + pts_address(op.balance_owner_key, false, 56) == balance->owner || + pts_address(op.balance_owner_key, true, 56) == balance->owner || + pts_address(op.balance_owner_key, false, 0) == balance->owner || + pts_address(op.balance_owner_key, true, 0) == balance->owner, + "balance_owner_key does not match balance's owner"); + if( !(d.get_node_properties().skip_flags & (database::skip_authority_check | + database::skip_transaction_signatures)) ) + FC_ASSERT(trx_state->signed_by(op.balance_owner_key)); FC_ASSERT(op.total_claimed.asset_id == balance->asset_type()); if( balance->vesting_policy.valid() ) { diff --git a/libraries/chain/include/graphene/chain/operations.hpp b/libraries/chain/include/graphene/chain/operations.hpp index 9b2e4e2d..cb0c5494 100644 --- a/libraries/chain/include/graphene/chain/operations.hpp +++ b/libraries/chain/include/graphene/chain/operations.hpp @@ -143,6 +143,7 @@ namespace graphene { namespace chain { asset fee; account_id_type deposit_to_account; balance_id_type balance_to_claim; + public_key_type balance_owner_key; asset total_claimed; account_id_type fee_payer()const { return deposit_to_account; } @@ -1651,7 +1652,8 @@ FC_REFLECT( graphene::chain::custom_operation, (fee)(payer)(required_auths)(id)( FC_REFLECT( graphene::chain::assert_operation, (fee)(fee_paying_account)(predicates)(required_auths) ) FC_REFLECT( graphene::chain::void_result, ) -FC_REFLECT( graphene::chain::balance_claim_operation, (fee)(deposit_to_account)(balance_to_claim)(total_claimed) ) +FC_REFLECT( graphene::chain::balance_claim_operation, + (fee)(deposit_to_account)(balance_to_claim)(balance_owner_key)(total_claimed) ) FC_REFLECT_TYPENAME( graphene::chain::operation ) FC_REFLECT_TYPENAME( graphene::chain::operation_result ) diff --git a/libraries/chain/include/graphene/chain/transaction_evaluation_state.hpp b/libraries/chain/include/graphene/chain/transaction_evaluation_state.hpp index 7c0ececd..6f914e2b 100644 --- a/libraries/chain/include/graphene/chain/transaction_evaluation_state.hpp +++ b/libraries/chain/include/graphene/chain/transaction_evaluation_state.hpp @@ -25,10 +25,8 @@ namespace graphene { namespace chain { struct signed_transaction; /** - * Place holder for state tracked while processing a - * transaction. This class provides helper methods - * that are common to many different operations and - * also tracks which keys have signed the transaction + * Place holder for state tracked while processing a transaction. This class provides helper methods that are + * common to many different operations and also tracks which keys have signed the transaction */ class transaction_evaluation_state { @@ -36,26 +34,24 @@ namespace graphene { namespace chain { transaction_evaluation_state( database* db = nullptr ) :_db(db){} - bool check_authority( const account_object&, authority::classification auth_class = authority::active, int depth = 0 ); + bool check_authority(const account_object&, + authority::classification auth_class = authority::active, + int depth = 0); database& db()const { FC_ASSERT( _db ); return *_db; } - bool signed_by( key_id_type id ); - bool signed_by( const address& a, bool maybe_pts = false ); + bool signed_by(key_id_type id); + bool signed_by(const public_key_type& k); - /** derived from signatures on transaction - flat_set
signed_by; - */ - /** cached approval (accounts and keys) */ - flat_set< pair > approved_by; + /// cached approval (accounts and keys) + flat_set> approved_by; + + /// Used to look up new objects using transaction relative IDs + vector operation_results; /** - * Used to lookup new objects using transaction relative IDs - */ - vector operation_results; - - /** When an address is referenced via check authority it is flagged as being used, - * all addresses must be flagged as being used or the transaction will fail. + * When an address is referenced via check authority it is flagged as being used, all addresses must be + * flagged as being used or the transaction will fail. */ flat_map _sigs; const signed_transaction* _trx = nullptr; diff --git a/libraries/chain/include/graphene/chain/types.hpp b/libraries/chain/include/graphene/chain/types.hpp index b9277c72..628f4de1 100644 --- a/libraries/chain/include/graphene/chain/types.hpp +++ b/libraries/chain/include/graphene/chain/types.hpp @@ -357,9 +357,9 @@ namespace graphene { namespace chain { uint64_t account_len6_fee = 5*UINT64_C(500000000); ///< about $50 uint64_t account_len5_fee = 5*UINT64_C(1000000000); ///< about $100 uint64_t account_len4_fee = 5*UINT64_C(2000000000); ///< about $200 - uint64_t account_len3_fee = 5*3000000000; ///< about $300 - uint64_t account_len2_fee = 5*4000000000; ///< about $400 - uint64_t asset_create_fee = 5ll*500000000; ///< about $35 for LTM, the cost to register the cheapest asset + uint64_t account_len3_fee = 5*UINT64_C(3000000000); ///< about $300 + uint64_t account_len2_fee = 5*UINT64_C(4000000000); ///< about $400 + uint64_t asset_create_fee = 5*UINT64_C(500000000); ///< about $35 for LTM, the cost to register the cheapest asset uint64_t asset_update_fee = 150000; ///< the cost to modify a registered asset uint64_t asset_issue_fee = 700000; ///< the cost to print a UIA and send it to an account uint64_t asset_burn_fee = 1500000; ///< the cost to burn an asset diff --git a/libraries/chain/transaction_evaluation_state.cpp b/libraries/chain/transaction_evaluation_state.cpp index e0e8fba4..4f3b10c8 100644 --- a/libraries/chain/transaction_evaluation_state.cpp +++ b/libraries/chain/transaction_evaluation_state.cpp @@ -94,35 +94,21 @@ namespace graphene { namespace chain { } return false; } - bool transaction_evaluation_state::signed_by( key_id_type id ) + bool transaction_evaluation_state::signed_by(key_id_type id) { assert(_trx); assert(_db); - //wdump((_sigs)(id(*_db).key_address())(*_trx) ); - auto itr = _sigs.find( id(*_db).key() ); + + return signed_by(id(*_db).key()); + } + bool transaction_evaluation_state::signed_by(const public_key_type& k) + { + assert(_db); + + auto itr = _sigs.find(k); if( itr != _sigs.end() ) return itr->second = true; - return false; - } - bool transaction_evaluation_state::signed_by( const address& a, bool maybe_pts ) - { - if( _db->get_node_properties().skip_flags & (database::skip_authority_check|database::skip_transaction_signatures) ) - return true; - for( auto itr = _sigs.begin(); itr != _sigs.end(); ++itr ) - { - if( itr->first == a ) return itr->second = true; - if( maybe_pts ) - { - //pts normal - if( pts_address( itr->first, false, 56 ) == a ) return itr->second = true; - //pts compressed - if( pts_address( itr->first, true, 56 ) == a ) return itr->second = true; - // btc normal - if( pts_address( itr->first, false, 0 ) == a ) return itr->second = true; - // btc compressed - if( pts_address( itr->first, true, 0 ) == a ) return itr->second = true; - } - } + return false; } diff --git a/libraries/db/include/graphene/db/index.hpp b/libraries/db/include/graphene/db/index.hpp index 0f341416..75d1d4ac 100644 --- a/libraries/db/include/graphene/db/index.hpp +++ b/libraries/db/include/graphene/db/index.hpp @@ -170,7 +170,7 @@ namespace graphene { namespace db { const T* result = dynamic_cast(item.get()); if( result != nullptr ) return *result; } - FC_ASSERT( !"invalid index type" ); + FC_THROW_EXCEPTION( fc::assert_exception, "invalid index type" ); } protected: diff --git a/libraries/net/include/graphene/net/node.hpp b/libraries/net/include/graphene/net/node.hpp index 34950843..7dfbe190 100644 --- a/libraries/net/include/graphene/net/node.hpp +++ b/libraries/net/include/graphene/net/node.hpp @@ -83,7 +83,7 @@ namespace graphene { namespace net { case trx_message_type: return handle_transaction(message_to_process.as(), sync_mode); default: - FC_ASSERT( !"Invalid Message Type" ); + FC_THROW( "Invalid Message Type" ); }; } diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index bb7604ef..aad45e91 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -52,6 +52,7 @@ int main(int argc, char** argv) { auto history_plug = node.register_plugin(); auto market_history_plug = node.register_plugin(); + try { bpo::options_description cli, cfg; node.set_program_options(cli, cfg); @@ -59,6 +60,11 @@ int main(int argc, char** argv) { cfg_options.add(cfg); bpo::store(bpo::parse_command_line(argc, argv, app_options), options); } + catch (const boost::program_options::error& e) + { + std::cerr << "Error parsing command line: " << e.what() << "\n"; + return 1; + } if( options.count("help") ) { diff --git a/tests/tests/authority_tests.cpp b/tests/tests/authority_tests.cpp index 65b59b00..d2c7e0ac 100644 --- a/tests/tests/authority_tests.cpp +++ b/tests/tests/authority_tests.cpp @@ -381,13 +381,13 @@ BOOST_AUTO_TEST_CASE( genesis_authority ) sign(trx, key_id_type(), genesis_key); BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); - auto sign = [&] { trx.signatures.clear(); trx.sign(nathan_key_id,nathan_key); }; + auto sign = [&] { trx.signatures.clear(); trx.sign(nathan_key); }; proposal_create_operation pop; pop.proposed_ops.push_back({trx.operations.front()}); pop.expiration_time = db.head_block_time() + global_params.genesis_proposal_review_period*2; pop.fee_paying_account = nathan.id; - trx.operations.back() = pop; + trx.operations = {pop}; sign(); // The review period isn't set yet. Make sure it throws. @@ -480,7 +480,6 @@ BOOST_FIXTURE_TEST_CASE( fired_delegates, database_fixture ) pop.expiration_time = db.head_block_time() + *pop.review_period_seconds * 3; pop.proposed_ops.emplace_back(transfer_operation({asset(),account_id_type(), nathan->id, asset(100000)})); trx.operations.push_back(pop); - sign(trx, key_id_type(), genesis_key); const proposal_object& prop = db.get(PUSH_TX( db, trx ).operation_results.front().get()); proposal_id_type pid = prop.id; BOOST_CHECK(!pid(db).is_authorized_to_execute(db)); diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index d72d1aba..b0b9e613 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -349,7 +349,6 @@ BOOST_AUTO_TEST_CASE( switch_forks_undo_create ) cop.name = "nathan"; cop.owner = authority(1, key_id_type(), 1); trx.operations.push_back(cop); - trx.sign( key_id_type(), delegate_priv_key ); PUSH_TX( db1, trx ); auto aw = db1.get_global_properties().active_witnesses; diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index 86e660aa..c479356c 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -993,12 +993,14 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) op.deposit_to_account = db.get_index_type().indices().get().find("n")->get_id(); op.total_claimed = asset(1); op.balance_to_claim = balance_id_type(1); + op.balance_owner_key = generate_private_key("x").get_public_key(); trx.operations = {op}; trx.sign(generate_private_key("n")); // Fail because I'm claiming from an address which hasn't signed BOOST_CHECK_THROW(db.push_transaction(trx), fc::exception); trx.clear(); op.balance_to_claim = balance_id_type(); + op.balance_owner_key = generate_private_key("n").get_public_key(); trx.operations = {op}; trx.sign(generate_private_key("n")); db.push_transaction(trx);