From d821d4a9936e715ae2073cc9028172a835946111 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Fri, 30 Oct 2015 13:47:22 -0400 Subject: [PATCH 1/4] Get rid of enforce_white_list() #416 --- libraries/chain/account_object.cpp | 7 ++++++- libraries/chain/confidential_evaluator.cpp | 2 +- .../chain/include/graphene/chain/asset_object.hpp | 2 -- libraries/chain/include/graphene/chain/hardfork.hpp | 1 + .../include/graphene/chain/protocol/asset_ops.hpp | 9 ++++----- libraries/chain/market_evaluator.cpp | 12 ++++++++++-- libraries/chain/withdraw_permission_evaluator.cpp | 13 ++++++++++++- tests/tests/operation_tests.cpp | 2 +- tests/tests/uia_tests.cpp | 2 +- 9 files changed, 36 insertions(+), 14 deletions(-) diff --git a/libraries/chain/account_object.cpp b/libraries/chain/account_object.cpp index ef52056c..6ef1c042 100644 --- a/libraries/chain/account_object.cpp +++ b/libraries/chain/account_object.cpp @@ -41,6 +41,12 @@ share_type cut_fee(share_type a, uint16_t p) bool account_object::is_authorized_asset(const asset_object& asset_obj, const database& d) const { + if( d.head_block_time() > HARDFORK_416_TIME ) + { + if( !(asset_obj.options.flags & white_list) ) + return true; + } + for( const auto id : blacklisting_accounts ) { if( asset_obj.options.blacklist_authorities.find(id) != asset_obj.options.blacklist_authorities.end() ) @@ -68,7 +74,6 @@ void account_balance_object::adjust_balance(const asset& delta) balance += delta.amount; } - void account_statistics_object::process_fees(const account_object& a, database& d) const { if( pending_fees > 0 || pending_vested_fees > 0 ) diff --git a/libraries/chain/confidential_evaluator.cpp b/libraries/chain/confidential_evaluator.cpp index 014e6224..065cbe43 100644 --- a/libraries/chain/confidential_evaluator.cpp +++ b/libraries/chain/confidential_evaluator.cpp @@ -32,7 +32,7 @@ void_result transfer_to_blind_evaluator::do_evaluate( const transfer_to_blind_op const auto& atype = o.amount.asset_id(db()); FC_ASSERT( atype.allow_confidential() ); FC_ASSERT( !atype.is_transfer_restricted() ); - FC_ASSERT( !atype.enforce_white_list() ); + FC_ASSERT( !(atype.options.flags & white_list) ); for( const auto& out : o.outputs ) { diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index 4496fe03..1ffe7e95 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -82,8 +82,6 @@ namespace graphene { namespace chain { /// @return true if symbol is a valid ticker symbol; false otherwise. static bool is_valid_symbol( const string& symbol ); - /// @return true if accounts must be on a whitelist in order to hold this asset; false otherwise. - bool enforce_white_list()const { return options.flags & white_list; } /// @return true if this is a market-issued asset; false otherwise. bool is_market_issued()const { return bitasset_data_id.valid(); } /// @return true if users may request force-settlement of this market-issued asset; false otherwise diff --git a/libraries/chain/include/graphene/chain/hardfork.hpp b/libraries/chain/include/graphene/chain/hardfork.hpp index 503e5f0b..da94532d 100644 --- a/libraries/chain/include/graphene/chain/hardfork.hpp +++ b/libraries/chain/include/graphene/chain/hardfork.hpp @@ -23,3 +23,4 @@ #define HARDFORK_357_TIME (fc::time_point_sec( 1444416300 )) #define HARDFORK_359_TIME (fc::time_point_sec( 1444416300 )) #define HARDFORK_415_TIME (fc::time_point_sec( 1446652800 )) +#define HARDFORK_416_TIME (fc::time_point_sec( 1446652800 )) diff --git a/libraries/chain/include/graphene/chain/protocol/asset_ops.hpp b/libraries/chain/include/graphene/chain/protocol/asset_ops.hpp index e0cd26eb..afb7b8e2 100644 --- a/libraries/chain/include/graphene/chain/protocol/asset_ops.hpp +++ b/libraries/chain/include/graphene/chain/protocol/asset_ops.hpp @@ -53,12 +53,11 @@ namespace graphene { namespace chain { /// the core exchange rate. price core_exchange_rate; - /// A set of accounts which maintain whitelists to consult for this asset. If enforce_white_list() returns - /// true, an account may only send, receive, trade, etc. in this asset if one of these accounts appears in - /// its account_object::whitelisting_accounts field. + /// A set of accounts which maintain whitelists to consult for this asset. If whitelist_authorities + /// is non-empty, then only accounts in whitelist_authorities are allowed to hold, use, or transfer the asset. flat_set whitelist_authorities; - /// A set of accounts which maintain blacklists to consult for this asset. If enforce_white_list() returns - /// true, an account may only send, receive, trade, etc. in this asset if none of these accounts appears in + /// A set of accounts which maintain blacklists to consult for this asset. If flags & white_list is set, + /// an account may only send, receive, trade, etc. in this asset if none of these accounts appears in /// its account_object::blacklisting_accounts field. If the account is blacklisted, it may not transact in /// this asset even if it is also whitelisted. flat_set blacklist_authorities; diff --git a/libraries/chain/market_evaluator.cpp b/libraries/chain/market_evaluator.cpp index 19f7742f..f357a18e 100644 --- a/libraries/chain/market_evaluator.cpp +++ b/libraries/chain/market_evaluator.cpp @@ -42,8 +42,16 @@ void_result limit_order_create_evaluator::do_evaluate(const limit_order_create_o if( _sell_asset->options.blacklist_markets.size() ) FC_ASSERT( _sell_asset->options.blacklist_markets.find(_receive_asset->id) == _sell_asset->options.blacklist_markets.end() ); - if( _sell_asset->enforce_white_list() ) FC_ASSERT( _seller->is_authorized_asset( *_sell_asset, d ) ); - if( _receive_asset->enforce_white_list() ) FC_ASSERT( _seller->is_authorized_asset( *_receive_asset, d ) ); + if( d.head_block_time() <= HARDFORK_416_TIME ) + { + if( _sell_asset->options.flags & white_list ) FC_ASSERT( _seller->is_authorized_asset( *_sell_asset, d ) ); + if( _receive_asset->options.flags & white_list ) FC_ASSERT( _seller->is_authorized_asset( *_receive_asset, d ) ); + } + else + { + FC_ASSERT( _seller->is_authorized_asset( *_sell_asset, d ) ); + FC_ASSERT( _seller->is_authorized_asset( *_receive_asset, d ) ); + } FC_ASSERT( d.get_balance( *_seller, *_sell_asset ) >= op.amount_to_sell, "insufficient balance", ("balance",d.get_balance(*_seller,*_sell_asset))("amount_to_sell",op.amount_to_sell) ); diff --git a/libraries/chain/withdraw_permission_evaluator.cpp b/libraries/chain/withdraw_permission_evaluator.cpp index 17e96c45..1c1fb620 100644 --- a/libraries/chain/withdraw_permission_evaluator.cpp +++ b/libraries/chain/withdraw_permission_evaluator.cpp @@ -23,6 +23,7 @@ #include #include #include +#include namespace graphene { namespace chain { @@ -65,7 +66,17 @@ void_result withdraw_permission_claim_evaluator::do_evaluate(const withdraw_perm const asset_object& _asset = op.amount_to_withdraw.asset_id(d); if( _asset.is_transfer_restricted() ) FC_ASSERT( _asset.issuer == permit.authorized_account || _asset.issuer == permit.withdraw_from_account ); - if( _asset.enforce_white_list() ) + if( d.head_block_time() <= HARDFORK_416_TIME ) + { + if( _asset.options.flags & white_list ) + { + const account_object& from = op.withdraw_to_account(d); + const account_object& to = permit.authorized_account(d); + FC_ASSERT( to.is_authorized_asset( _asset, d ) ); + FC_ASSERT( from.is_authorized_asset( _asset, d ) ); + } + } + else { const account_object& from = op.withdraw_to_account(d); const account_object& to = permit.authorized_account(d); diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 001450af..b85b3161 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -687,7 +687,7 @@ BOOST_AUTO_TEST_CASE( create_uia ) const asset_object& test_asset = test_asset_id(db); BOOST_CHECK(test_asset.symbol == "TEST"); BOOST_CHECK(asset(1, test_asset_id) * test_asset.options.core_exchange_rate == asset(2)); - BOOST_CHECK(!test_asset.enforce_white_list()); + BOOST_CHECK((test_asset.options.flags & white_list) == 0); BOOST_CHECK(test_asset.options.max_supply == 100000000); BOOST_CHECK(!test_asset.bitasset_data_id.valid()); BOOST_CHECK(test_asset.options.market_fee_percent == GRAPHENE_MAX_MARKET_FEE_PERCENT/100); diff --git a/tests/tests/uia_tests.cpp b/tests/tests/uia_tests.cpp index 924a91fd..25b13484 100644 --- a/tests/tests/uia_tests.cpp +++ b/tests/tests/uia_tests.cpp @@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE( create_advanced_uia ) const asset_object& test_asset = test_asset_id(db); BOOST_CHECK(test_asset.symbol == "ADVANCED"); BOOST_CHECK(asset(1, test_asset_id) * test_asset.options.core_exchange_rate == asset(2)); - BOOST_CHECK(test_asset.enforce_white_list()); + BOOST_CHECK(test_asset.options.flags & white_list); BOOST_CHECK(test_asset.options.max_supply == 100000000); BOOST_CHECK(!test_asset.bitasset_data_id.valid()); BOOST_CHECK(test_asset.options.market_fee_percent == GRAPHENE_MAX_MARKET_FEE_PERCENT/100); From 4f2b8bd6f6dc295f2197002611b03cb1e8f8b234 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Fri, 30 Oct 2015 14:22:02 -0400 Subject: [PATCH 2/4] HARDFORK Move fee blacklist check to evaluator #419 --- libraries/chain/evaluator.cpp | 19 ++++++++++++++----- .../chain/include/graphene/chain/hardfork.hpp | 1 + libraries/chain/transfer_evaluator.cpp | 17 +++++++++++++---- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/libraries/chain/evaluator.cpp b/libraries/chain/evaluator.cpp index 4a190963..878d98cb 100644 --- a/libraries/chain/evaluator.cpp +++ b/libraries/chain/evaluator.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -46,17 +47,25 @@ database& generic_evaluator::db()const { return trx_state->db(); } void generic_evaluator::prepare_fee(account_id_type account_id, asset fee) { + const database& d = db(); fee_from_account = fee; FC_ASSERT( fee.amount >= 0 ); - fee_paying_account = &account_id(db()); - fee_paying_account_statistics = &fee_paying_account->statistics(db()); + fee_paying_account = &account_id(d); + fee_paying_account_statistics = &fee_paying_account->statistics(d); - fee_asset = &fee.asset_id(db()); - fee_asset_dyn_data = &fee_asset->dynamic_asset_data_id(db()); + fee_asset = &fee.asset_id(d); + fee_asset_dyn_data = &fee_asset->dynamic_asset_data_id(d); + + if( d.head_block_time() > HARDFORK_419_TIME ) + { + FC_ASSERT( fee_paying_account->is_authorized_asset( *fee_asset, d ), "Account ${acct} '${name}' attempted to pay fee by using asset ${a} '${sym}', which is unauthorized due to whitelist / blacklist", + ("acct", fee_paying_account->id)("name", fee_paying_account->name)("a", fee_asset->id)("sym", fee_asset->symbol) ); + } if( fee_from_account.asset_id == asset_id_type() ) core_fee_paid = fee_from_account.amount; - else { + else + { asset fee_from_pool = fee_from_account * fee_asset->options.core_exchange_rate; FC_ASSERT( fee_from_pool.asset_id == asset_id_type() ); core_fee_paid = fee_from_pool.amount; diff --git a/libraries/chain/include/graphene/chain/hardfork.hpp b/libraries/chain/include/graphene/chain/hardfork.hpp index da94532d..821f9306 100644 --- a/libraries/chain/include/graphene/chain/hardfork.hpp +++ b/libraries/chain/include/graphene/chain/hardfork.hpp @@ -24,3 +24,4 @@ #define HARDFORK_359_TIME (fc::time_point_sec( 1444416300 )) #define HARDFORK_415_TIME (fc::time_point_sec( 1446652800 )) #define HARDFORK_416_TIME (fc::time_point_sec( 1446652800 )) +#define HARDFORK_419_TIME (fc::time_point_sec( 1446652800 )) diff --git a/libraries/chain/transfer_evaluator.cpp b/libraries/chain/transfer_evaluator.cpp index 521f2f55..0f1a1f3c 100644 --- a/libraries/chain/transfer_evaluator.cpp +++ b/libraries/chain/transfer_evaluator.cpp @@ -21,6 +21,7 @@ #include #include #include +#include namespace graphene { namespace chain { void_result transfer_evaluator::do_evaluate( const transfer_operation& op ) @@ -53,8 +54,12 @@ void_result transfer_evaluator::do_evaluate( const transfer_operation& op ) ); } - if( fee_asset_type.options.flags & white_list ) - FC_ASSERT( from_account.is_authorized_asset( asset_type, d ) ); + if( d.head_block_time() <= HARDFORK_419_TIME ) + { + if( fee_asset_type.options.flags & white_list ) + FC_ASSERT( from_account.is_authorized_asset( asset_type, d ) ); + } + // the above becomes no-op after hardfork because this check will then be performed in evaluator if( asset_type.is_transfer_restricted() ) { @@ -108,8 +113,12 @@ void_result override_transfer_evaluator::do_evaluate( const override_transfer_op FC_ASSERT( from_account.is_authorized_asset( asset_type, d ) ); } - if( fee_asset_type.options.flags & white_list ) - FC_ASSERT( from_account.is_authorized_asset( asset_type, d ) ); + if( d.head_block_time() <= HARDFORK_419_TIME ) + { + if( fee_asset_type.options.flags & white_list ) + FC_ASSERT( from_account.is_authorized_asset( asset_type, d ) ); + } + // the above becomes no-op after hardfork because this check will then be performed in evaluator FC_ASSERT( d.get_balance( from_account, asset_type ).amount >= op.amount.amount, "", ("total_transfer",op.amount)("balance",d.get_balance(from_account, asset_type).amount) ); From a126520fa3224203eee117150691e5249feefa3b Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Fri, 30 Oct 2015 09:32:28 -0400 Subject: [PATCH 3/4] HARDFORK Allow creation of sub-assets #409 --- libraries/chain/asset_evaluator.cpp | 36 +++++++++++++------ .../chain/include/graphene/chain/hardfork.hpp | 1 + 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index 03e07e66..0d8f299f 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -45,20 +45,36 @@ void_result asset_create_evaluator::do_evaluate( const asset_create_operation& o for( auto id : op.common_options.blacklist_authorities ) d.get_object(id); - auto& asset_indx = db().get_index_type().indices().get(); + auto& asset_indx = d.get_index_type().indices().get(); auto asset_symbol_itr = asset_indx.find( op.symbol ); FC_ASSERT( asset_symbol_itr == asset_indx.end() ); - auto dotpos = op.symbol.find( '.' ); - if( dotpos != std::string::npos ) { - auto prefix = op.symbol.substr( 0, dotpos ); - auto asset_symbol_itr = asset_indx.find( op.symbol ); - FC_ASSERT( asset_symbol_itr != asset_indx.end(), "Asset ${s} may only be created by issuer of ${p}, but ${p} has not been registered", - ("s",op.symbol)("p",prefix) ); - FC_ASSERT( asset_symbol_itr->issuer == op.issuer, "Asset ${s} may only be created by issuer of ${p}, ${i}", - ("s",op.symbol)("p",prefix)("i", op.issuer(d).name) ); + if( d.head_block_time() <= HARDFORK_409_TIME ) + { + auto dotpos = op.symbol.find( '.' ); + if( dotpos != std::string::npos ) + { + auto prefix = op.symbol.substr( 0, dotpos ); + auto asset_symbol_itr = asset_indx.find( op.symbol ); + FC_ASSERT( asset_symbol_itr != asset_indx.end(), "Asset ${s} may only be created by issuer of ${p}, but ${p} has not been registered", + ("s",op.symbol)("p",prefix) ); + FC_ASSERT( asset_symbol_itr->issuer == op.issuer, "Asset ${s} may only be created by issuer of ${p}, ${i}", + ("s",op.symbol)("p",prefix)("i", op.issuer(d).name) ); + } + } + else + { + auto dotpos = op.symbol.rfind( '.' ); + if( dotpos != std::string::npos ) + { + auto prefix = op.symbol.substr( 0, dotpos ); + auto asset_symbol_itr = asset_indx.find( prefix ); + FC_ASSERT( asset_symbol_itr != asset_indx.end(), "Asset ${s} may only be created by issuer of ${p}, but ${p} has not been registered", + ("s",op.symbol)("p",prefix) ); + FC_ASSERT( asset_symbol_itr->issuer == op.issuer, "Asset ${s} may only be created by issuer of ${p}, ${i}", + ("s",op.symbol)("p",prefix)("i", op.issuer(d).name) ); + } } - core_fee_paid -= core_fee_paid.value/2; diff --git a/libraries/chain/include/graphene/chain/hardfork.hpp b/libraries/chain/include/graphene/chain/hardfork.hpp index 503e5f0b..1417855d 100644 --- a/libraries/chain/include/graphene/chain/hardfork.hpp +++ b/libraries/chain/include/graphene/chain/hardfork.hpp @@ -22,4 +22,5 @@ #define HARDFORK_357_TIME (fc::time_point_sec( 1444416300 )) #define HARDFORK_359_TIME (fc::time_point_sec( 1444416300 )) +#define HARDFORK_409_TIME (fc::time_point_sec( 1446652800 )) #define HARDFORK_415_TIME (fc::time_point_sec( 1446652800 )) From f72ed2f5321bd8b56ffbccf28c88e77a3008ffac Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Sat, 31 Oct 2015 14:50:11 -0400 Subject: [PATCH 4/4] uia_tests.cpp: Implement asset_name_test #409 --- tests/common/database_fixture.cpp | 2 ++ tests/tests/uia_tests.cpp | 47 +++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 676c53b5..f7431f40 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -501,7 +501,9 @@ const asset_object& database_fixture::create_user_issued_asset( const string& na creator.common_options.max_supply = GRAPHENE_MAX_SHARE_SUPPLY; creator.common_options.flags = flags; creator.common_options.issuer_permissions = flags; + trx.operations.clear(); trx.operations.push_back(std::move(creator)); + set_expiration( db, trx ); trx.validate(); processed_transaction ptx = db.push_transaction(trx, ~0); trx.operations.clear(); diff --git a/tests/tests/uia_tests.cpp b/tests/tests/uia_tests.cpp index 41cda68f..0a7cf778 100644 --- a/tests/tests/uia_tests.cpp +++ b/tests/tests/uia_tests.cpp @@ -414,5 +414,52 @@ BOOST_AUTO_TEST_CASE( transfer_restricted_test ) } } +BOOST_AUTO_TEST_CASE( asset_name_test ) +{ + try + { + ACTORS( (alice)(bob) ); + + auto has_asset = [&]( std::string symbol ) -> bool + { + const auto& assets_by_symbol = db.get_index_type().indices().get(); + return assets_by_symbol.find( symbol ) != assets_by_symbol.end(); + }; + + // Alice creates asset "ALPHA" + BOOST_CHECK( !has_asset("ALPHA") ); BOOST_CHECK( !has_asset("ALPHA.ONE") ); + create_user_issued_asset( "ALPHA", alice_id(db), 0 ); + BOOST_CHECK( has_asset("ALPHA") ); BOOST_CHECK( !has_asset("ALPHA.ONE") ); + + // Nobody can create another asset named ALPHA + GRAPHENE_REQUIRE_THROW( create_user_issued_asset( "ALPHA", bob_id(db), 0 ), fc::exception ); + BOOST_CHECK( has_asset("ALPHA") ); BOOST_CHECK( !has_asset("ALPHA.ONE") ); + GRAPHENE_REQUIRE_THROW( create_user_issued_asset( "ALPHA", alice_id(db), 0 ), fc::exception ); + BOOST_CHECK( has_asset("ALPHA") ); BOOST_CHECK( !has_asset("ALPHA.ONE") ); + + // Bob can't create ALPHA.ONE + GRAPHENE_REQUIRE_THROW( create_user_issued_asset( "ALPHA.ONE", bob_id(db), 0 ), fc::exception ); + BOOST_CHECK( has_asset("ALPHA") ); BOOST_CHECK( !has_asset("ALPHA.ONE") ); + if( db.head_block_time() <= HARDFORK_409_TIME ) + { + // Alice can't create ALPHA.ONE before hardfork + GRAPHENE_REQUIRE_THROW( create_user_issued_asset( "ALPHA.ONE", alice_id(db), 0 ), fc::exception ); + BOOST_CHECK( has_asset("ALPHA") ); BOOST_CHECK( !has_asset("ALPHA.ONE") ); + generate_blocks( HARDFORK_409_TIME ); + generate_block(); + // Bob can't create ALPHA.ONE after hardfork + GRAPHENE_REQUIRE_THROW( create_user_issued_asset( "ALPHA.ONE", bob_id(db), 0 ), fc::exception ); + BOOST_CHECK( has_asset("ALPHA") ); BOOST_CHECK( !has_asset("ALPHA.ONE") ); + } + // Alice can create it + create_user_issued_asset( "ALPHA.ONE", alice_id(db), 0 ); + BOOST_CHECK( has_asset("ALPHA") ); BOOST_CHECK( has_asset("ALPHA.ONE") ); + } + catch(fc::exception& e) + { + edump((e.to_detail_string())); + throw; + } +} BOOST_AUTO_TEST_SUITE_END()