diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 2ce2f99d..dce52c29 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -85,6 +85,8 @@ add_library( graphene_chain block_database.cpp + is_authorized_asset.cpp + ${HEADERS} "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) diff --git a/libraries/chain/account_object.cpp b/libraries/chain/account_object.cpp index 1006cdcb..90d97692 100644 --- a/libraries/chain/account_object.cpp +++ b/libraries/chain/account_object.cpp @@ -42,35 +42,6 @@ share_type cut_fee(share_type a, uint16_t p) return r.to_uint64(); } -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() ) - return false; - } - - if( d.head_block_time() > HARDFORK_415_TIME ) - { - if( asset_obj.options.whitelist_authorities.size() == 0 ) - return true; - } - - for( const auto id : whitelisting_accounts ) - { - if( asset_obj.options.whitelist_authorities.find(id) != asset_obj.options.whitelist_authorities.end() ) - return true; - } - - return false; -} - void account_balance_object::adjust_balance(const asset& delta) { assert(delta.asset_id == asset_type); diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index 17113d9c..9a467bec 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -152,11 +153,7 @@ void_result asset_issue_evaluator::do_evaluate( const asset_issue_operation& o ) FC_ASSERT( !a.is_market_issued(), "Cannot manually issue a market-issued asset." ); to_account = &o.issue_to_account(d); - - if( a.options.flags & white_list ) - { - FC_ASSERT( to_account->is_authorized_asset( a, d ) ); - } + FC_ASSERT( is_authorized_asset( d, *to_account, a ) ); asset_dyn_data = &a.dynamic_asset_data_id(d); FC_ASSERT( (asset_dyn_data->current_supply + o.asset_to_issue.amount) <= a.options.max_supply ); @@ -188,11 +185,7 @@ void_result asset_reserve_evaluator::do_evaluate( const asset_reserve_operation& ); from_account = &o.payer(d); - - if( a.options.flags & white_list ) - { - FC_ASSERT( from_account->is_authorized_asset( a, d ) ); - } + FC_ASSERT( is_authorized_asset( d, *from_account, a ) ); asset_dyn_data = &a.dynamic_asset_data_id(d); FC_ASSERT( (asset_dyn_data->current_supply - o.amount_to_reserve.amount) >= 0 ); diff --git a/libraries/chain/evaluator.cpp b/libraries/chain/evaluator.cpp index a4fa2def..06e31c21 100644 --- a/libraries/chain/evaluator.cpp +++ b/libraries/chain/evaluator.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -61,7 +62,7 @@ database& generic_evaluator::db()const { return trx_state->db(); } 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", + FC_ASSERT( is_authorized_asset( d, *fee_paying_account, *fee_asset ), "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) ); } diff --git a/libraries/chain/include/graphene/chain/account_object.hpp b/libraries/chain/include/graphene/chain/account_object.hpp index 3039784e..e2d74363 100644 --- a/libraries/chain/include/graphene/chain/account_object.hpp +++ b/libraries/chain/include/graphene/chain/account_object.hpp @@ -243,12 +243,6 @@ namespace graphene { namespace chain { return !is_basic_account(now); } - /** - * @return true if this account is whitelisted and not blacklisted to transact in the provided asset; false - * otherwise. - */ - bool is_authorized_asset(const asset_object& asset_obj, const database& d)const; - account_id_type get_id()const { return id; } }; diff --git a/libraries/chain/include/graphene/chain/is_authorized_asset.hpp b/libraries/chain/include/graphene/chain/is_authorized_asset.hpp new file mode 100644 index 00000000..5062136e --- /dev/null +++ b/libraries/chain/include/graphene/chain/is_authorized_asset.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once + +namespace graphene { namespace chain { + +class account_object; +class asset_object; +class database; + +namespace detail { + +bool _is_authorized_asset(const database& d, const account_object& acct, const asset_object& asset_obj); + +} + +/** + * @return true if the account is whitelisted and not blacklisted to transact in the provided asset; false + * otherwise. + */ + +inline bool is_authorized_asset(const database& d, const account_object& acct, const asset_object& asset_obj) +{ + bool fast_check = !(asset_obj.options.flags & white_list); + + if( fast_check ) + return true; + + bool slow_check = detail::_is_authorized_asset( d, acct, asset_obj ); + return slow_check; +} + +} } diff --git a/libraries/chain/is_authorized_asset.cpp b/libraries/chain/is_authorized_asset.cpp new file mode 100644 index 00000000..8168a505 --- /dev/null +++ b/libraries/chain/is_authorized_asset.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include +#include + +namespace graphene { namespace chain { + +namespace detail { + +bool _is_authorized_asset( + const database& d, + const account_object& acct, + const asset_object& asset_obj) +{ + for( const auto id : acct.blacklisting_accounts ) + { + if( asset_obj.options.blacklist_authorities.find(id) != asset_obj.options.blacklist_authorities.end() ) + return false; + } + + if( d.head_block_time() > HARDFORK_415_TIME ) + { + if( asset_obj.options.whitelist_authorities.size() == 0 ) + return true; + } + + for( const auto id : acct.whitelisting_accounts ) + { + if( asset_obj.options.whitelist_authorities.find(id) != asset_obj.options.whitelist_authorities.end() ) + return true; + } + + return false; +} + +} // detail + +} } // graphene::chain diff --git a/libraries/chain/market_evaluator.cpp b/libraries/chain/market_evaluator.cpp index 10e2cb98..27c31ae4 100644 --- a/libraries/chain/market_evaluator.cpp +++ b/libraries/chain/market_evaluator.cpp @@ -23,11 +23,14 @@ */ #include #include +#include + +#include + #include #include #include -#include -#include +#include #include @@ -49,16 +52,8 @@ 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( 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( is_authorized_asset( d, *_seller, *_sell_asset ) ); + FC_ASSERT( is_authorized_asset( d, *_seller, *_receive_asset ) ); 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/transfer_evaluator.cpp b/libraries/chain/transfer_evaluator.cpp index 25304963..accc6ca3 100644 --- a/libraries/chain/transfer_evaluator.cpp +++ b/libraries/chain/transfer_evaluator.cpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace graphene { namespace chain { void_result transfer_evaluator::do_evaluate( const transfer_operation& op ) @@ -35,34 +36,23 @@ void_result transfer_evaluator::do_evaluate( const transfer_operation& op ) const account_object& from_account = op.from(d); const account_object& to_account = op.to(d); const asset_object& asset_type = op.amount.asset_id(d); - const asset_object& fee_asset_type = op.fee.asset_id(d); try { - if( asset_type.options.flags & white_list ) - { - GRAPHENE_ASSERT( - from_account.is_authorized_asset( asset_type, d ), - transfer_from_account_not_whitelisted, - "'from' account ${from} is not whitelisted for asset ${asset}", - ("from",op.from) - ("asset",op.amount.asset_id) - ); - GRAPHENE_ASSERT( - to_account.is_authorized_asset( asset_type, d ), - transfer_to_account_not_whitelisted, - "'to' account ${to} is not whitelisted for asset ${asset}", - ("to",op.to) - ("asset",op.amount.asset_id) - ); - } - - 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 + GRAPHENE_ASSERT( + is_authorized_asset( d, from_account, asset_type ), + transfer_from_account_not_whitelisted, + "'from' account ${from} is not whitelisted for asset ${asset}", + ("from",op.from) + ("asset",op.amount.asset_id) + ); + GRAPHENE_ASSERT( + is_authorized_asset( d, to_account, asset_type ), + transfer_to_account_not_whitelisted, + "'to' account ${to} is not whitelisted for asset ${asset}", + ("to",op.to) + ("asset",op.amount.asset_id) + ); if( asset_type.is_transfer_restricted() ) { @@ -108,18 +98,13 @@ void_result override_transfer_evaluator::do_evaluate( const override_transfer_op const account_object& from_account = op.from(d); const account_object& to_account = op.to(d); - const asset_object& fee_asset_type = op.fee.asset_id(d); - if( asset_type.options.flags & white_list ) - { - FC_ASSERT( to_account.is_authorized_asset( asset_type, d ) ); - FC_ASSERT( from_account.is_authorized_asset( asset_type, d ) ); - } + FC_ASSERT( is_authorized_asset( d, to_account, asset_type ) ); + FC_ASSERT( is_authorized_asset( d, from_account, asset_type ) ); 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 ) ); + FC_ASSERT( is_authorized_asset( d, from_account, asset_type ) ); } // the above becomes no-op after hardfork because this check will then be performed in evaluator diff --git a/libraries/chain/withdraw_permission_evaluator.cpp b/libraries/chain/withdraw_permission_evaluator.cpp index 0fdc4607..d001b441 100644 --- a/libraries/chain/withdraw_permission_evaluator.cpp +++ b/libraries/chain/withdraw_permission_evaluator.cpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace graphene { namespace chain { @@ -69,23 +70,10 @@ 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( 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); - FC_ASSERT( to.is_authorized_asset( _asset, d ) ); - FC_ASSERT( from.is_authorized_asset( _asset, d ) ); - } + const account_object& from = op.withdraw_to_account(d); + const account_object& to = permit.authorized_account(d); + FC_ASSERT( is_authorized_asset( d, to, _asset ) ); + FC_ASSERT( is_authorized_asset( d, from, _asset ) ); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index d848f743..7a9e7ce4 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -322,8 +322,10 @@ void database_fixture::generate_blocks(fc::time_point_sec timestamp, bool miss_i if( miss_intermediate_blocks ) { generate_block(); - auto slots_to_miss = db.get_slot_at_time(timestamp) - 1; - if( slots_to_miss <= 0 ) return; + auto slots_to_miss = db.get_slot_at_time(timestamp); + if( slots_to_miss <= 1 ) + return; + --slots_to_miss; generate_block(~0, init_account_priv_key, slots_to_miss); return; } diff --git a/tests/tests/uia_tests.cpp b/tests/tests/uia_tests.cpp index 8876f23e..442d5080 100644 --- a/tests/tests/uia_tests.cpp +++ b/tests/tests/uia_tests.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -161,7 +162,7 @@ BOOST_AUTO_TEST_CASE( issue_whitelist_uia ) } PUSH_TX( db, trx, ~0 ); - BOOST_CHECK(nathan_id(db).is_authorized_asset(uia_id(db), db)); + BOOST_CHECK(is_authorized_asset( db, nathan_id(db), uia_id(db) )); BOOST_CHECK_EQUAL(get_balance(nathan_id, uia_id), 1000); // Make a whitelist, now it should fail @@ -265,7 +266,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) wop.account_to_list = nathan.id; trx.operations.back() = wop; PUSH_TX( db, trx, ~0 ); - BOOST_CHECK( !(nathan.is_authorized_asset(advanced, db)) ); + BOOST_CHECK( !(is_authorized_asset( db, nathan, advanced )) ); BOOST_TEST_MESSAGE( "Attempting to transfer from nathan after blacklisting, should fail" ); op.amount = advanced.amount(50); @@ -323,7 +324,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) trx.operations.back() = op; //Fail because nathan is blacklisted - BOOST_CHECK(!nathan.is_authorized_asset(advanced, db)); + BOOST_CHECK(!is_authorized_asset( db, nathan, advanced )); GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); //Remove nathan from committee's whitelist, add him to dan's. This should not authorize him to hold ADVANCED. @@ -340,7 +341,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) trx.operations.back() = op; //Fail because nathan is not whitelisted - BOOST_CHECK(!nathan.is_authorized_asset(advanced, db)); + BOOST_CHECK(!is_authorized_asset( db, nathan, advanced )); GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); burn.payer = dan.id;