From 3eedabbac251b8afa585cb644f4b2b4596f2d37a Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 11 Aug 2015 14:48:38 -0400 Subject: [PATCH] Compute scaled precision at compile time, use in tests (fixes failures by prev commit) --- libraries/chain/asset_object.cpp | 4 +-- .../include/graphene/chain/protocol/asset.hpp | 8 +++++ libraries/chain/protocol/asset.cpp | 23 +++++++++++++ tests/tests/basic_tests.cpp | 32 ++++++++++++++++++- tests/tests/operation_tests.cpp | 8 ++--- 5 files changed, 67 insertions(+), 8 deletions(-) diff --git a/libraries/chain/asset_object.cpp b/libraries/chain/asset_object.cpp index f56b107a..6f054efc 100644 --- a/libraries/chain/asset_object.cpp +++ b/libraries/chain/asset_object.cpp @@ -110,9 +110,7 @@ asset asset_object::amount_from_string(string amount_string) const share_type satoshis = 0; - share_type scaled_precision = 1; - for( uint8_t i = 0; i < precision; ++i ) - scaled_precision *= 10; + share_type scaled_precision = asset::scaled_precision( precision ); const auto decimal_pos = amount_string.find( '.' ); const string lhs = amount_string.substr( negative_found, decimal_pos ); diff --git a/libraries/chain/include/graphene/chain/protocol/asset.hpp b/libraries/chain/include/graphene/chain/protocol/asset.hpp index 967a5c8e..83961747 100644 --- a/libraries/chain/include/graphene/chain/protocol/asset.hpp +++ b/libraries/chain/include/graphene/chain/protocol/asset.hpp @@ -21,6 +21,8 @@ namespace graphene { namespace chain { + extern const int64_t scaled_precision_lut[]; + struct asset { asset( share_type a = 0, asset_id_type id = asset_id_type() ) @@ -80,6 +82,12 @@ namespace graphene { namespace chain { FC_ASSERT( a.asset_id == b.asset_id ); return asset( a.amount + b.amount, a.asset_id ); } + + static share_type scaled_precision( uint8_t precision ) + { + FC_ASSERT( precision < 19 ); + return scaled_precision_lut[ precision ]; + } }; /** diff --git a/libraries/chain/protocol/asset.cpp b/libraries/chain/protocol/asset.cpp index 6ee16443..0bdaf17c 100644 --- a/libraries/chain/protocol/asset.cpp +++ b/libraries/chain/protocol/asset.cpp @@ -146,4 +146,27 @@ namespace graphene { namespace chain { return (asset( cp.numerator(), settlement_price.base.asset_id ) / asset( cp.denominator(), settlement_price.quote.asset_id )); } +// compile-time table of powers of 10 using template metaprogramming + +template< int N > +struct p10 +{ + static const int64_t v = 10 * p10::v; +}; + +template<> +struct p10<0> +{ + static const int64_t v = 1; +}; + +const int64_t scaled_precision_lut[19] = +{ + p10< 0 >::v, p10< 1 >::v, p10< 2 >::v, p10< 3 >::v, + p10< 4 >::v, p10< 5 >::v, p10< 6 >::v, p10< 7 >::v, + p10< 8 >::v, p10< 9 >::v, p10< 10 >::v, p10< 11 >::v, + p10< 12 >::v, p10< 13 >::v, p10< 14 >::v, p10< 15 >::v, + p10< 16 >::v, p10< 17 >::v, p10< 18 >::v +}; + } } // graphene::chain diff --git a/tests/tests/basic_tests.cpp b/tests/tests/basic_tests.cpp index 376c53fe..6aeae968 100644 --- a/tests/tests/basic_tests.cpp +++ b/tests/tests/basic_tests.cpp @@ -314,10 +314,40 @@ BOOST_AUTO_TEST_CASE( witness_rng_test_bits ) } FC_LOG_AND_RETHROW() } - BOOST_AUTO_TEST_CASE( exceptions ) { GRAPHENE_CHECK_THROW(FC_THROW_EXCEPTION(balance_claim_invalid_claim_amount, "Etc"), balance_claim_invalid_claim_amount); } +BOOST_AUTO_TEST_CASE( scaled_precision ) +{ + const int64_t _k = 1000; + const int64_t _m = _k*_k; + const int64_t _g = _m*_k; + const int64_t _t = _g*_k; + const int64_t _p = _t*_k; + const int64_t _e = _p*_k; + + BOOST_CHECK( asset::scaled_precision( 0) == share_type( 1 ) ); + BOOST_CHECK( asset::scaled_precision( 1) == share_type( 10 ) ); + BOOST_CHECK( asset::scaled_precision( 2) == share_type( 100 ) ); + BOOST_CHECK( asset::scaled_precision( 3) == share_type( 1*_k) ); + BOOST_CHECK( asset::scaled_precision( 4) == share_type( 10*_k) ); + BOOST_CHECK( asset::scaled_precision( 5) == share_type( 100*_k) ); + BOOST_CHECK( asset::scaled_precision( 6) == share_type( 1*_m) ); + BOOST_CHECK( asset::scaled_precision( 7) == share_type( 10*_m) ); + BOOST_CHECK( asset::scaled_precision( 8) == share_type( 100*_m) ); + BOOST_CHECK( asset::scaled_precision( 9) == share_type( 1*_g) ); + BOOST_CHECK( asset::scaled_precision(10) == share_type( 10*_g) ); + BOOST_CHECK( asset::scaled_precision(11) == share_type( 100*_g) ); + BOOST_CHECK( asset::scaled_precision(12) == share_type( 1*_t) ); + BOOST_CHECK( asset::scaled_precision(13) == share_type( 10*_t) ); + BOOST_CHECK( asset::scaled_precision(14) == share_type( 100*_t) ); + BOOST_CHECK( asset::scaled_precision(15) == share_type( 1*_p) ); + BOOST_CHECK( asset::scaled_precision(16) == share_type( 10*_p) ); + BOOST_CHECK( asset::scaled_precision(17) == share_type( 100*_p) ); + BOOST_CHECK( asset::scaled_precision(18) == share_type( 1*_e) ); + GRAPHENE_CHECK_THROW( asset::scaled_precision(19), fc::exception ); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 55fa23d4..c1971142 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -921,7 +921,7 @@ BOOST_AUTO_TEST_CASE( uia_fees ) const asset_dynamic_data_object& asset_dynamic = test_asset.dynamic_asset_data_id(db); const account_object& nathan_account = get_account("nathan"); const account_object& committee_account = account_id_type()(db); - const auto prec = asset_id_type()(db).precision; + const share_type prec = asset::scaled_precision( asset_id_type()(db).precision ); fund_fee_pool(committee_account, test_asset, 1000*prec); BOOST_CHECK(asset_dynamic.fee_pool == 1000*prec); @@ -1128,7 +1128,7 @@ BOOST_AUTO_TEST_CASE( fill_order ) BOOST_AUTO_TEST_CASE( witness_pay_test ) { try { - const auto prec = asset_id_type()(db).precision; + const share_type prec = asset::scaled_precision( asset_id_type()(db).precision ); // there is an immediate maintenance interval in the first block // which will initialize last_budget_time @@ -1188,7 +1188,7 @@ BOOST_AUTO_TEST_CASE( witness_pay_test ) PUSH_TX( db, trx ); auto pay_fee_time = db.head_block_time().sec_since_epoch(); trx.clear(); - BOOST_CHECK_EQUAL(get_balance(*nathan, *core), 20000*prec - account_upgrade_operation::fee_parameters_type().membership_lifetime_fee );; + BOOST_CHECK( get_balance(*nathan, *core) == 20000*prec - account_upgrade_operation::fee_parameters_type().membership_lifetime_fee );; generate_block(); nathan = &get_account("nathan"); @@ -1215,7 +1215,7 @@ BOOST_AUTO_TEST_CASE( witness_pay_test ) schedule_maint(); // The 80% lifetime referral fee went to the committee account, which burned it. Check that it's here. - BOOST_CHECK_EQUAL( core->reserved(db).value, 8000*prec ); + BOOST_CHECK( core->reserved(db).value == 8000*prec ); generate_block(); BOOST_CHECK_EQUAL( core->reserved(db).value, 999999406 ); BOOST_CHECK_EQUAL( db.get_dynamic_global_properties().witness_budget.value, ref_budget );