From 5e91e095c04bde597ad44ca28100d2262aacf121 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 27 Oct 2015 15:00:57 -0400 Subject: [PATCH 01/19] vesting_balance_object.cpp: Handle vesting_seconds == 0 case #390 --- libraries/chain/vesting_balance_object.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/chain/vesting_balance_object.cpp b/libraries/chain/vesting_balance_object.cpp index 296e4cea..fc32a249 100644 --- a/libraries/chain/vesting_balance_object.cpp +++ b/libraries/chain/vesting_balance_object.cpp @@ -94,7 +94,7 @@ fc::uint128_t cdd_vesting_policy::compute_coin_seconds_earned(const vesting_poli delta_coin_seconds *= delta_seconds; fc::uint128_t coin_seconds_earned_cap = ctx.balance.amount.value; - coin_seconds_earned_cap *= vesting_seconds; + coin_seconds_earned_cap *= std::max(vesting_seconds, 1u); return std::min(coin_seconds_earned + delta_coin_seconds, coin_seconds_earned_cap); } @@ -110,7 +110,7 @@ asset cdd_vesting_policy::get_allowed_withdraw(const vesting_policy_context& ctx if(ctx.now <= start_claim) return asset(0, ctx.balance.asset_id); fc::uint128_t cs_earned = compute_coin_seconds_earned(ctx); - fc::uint128_t withdraw_available = cs_earned / vesting_seconds; + fc::uint128_t withdraw_available = cs_earned / std::max(vesting_seconds, 1u); assert(withdraw_available <= ctx.balance.amount.value); return asset(withdraw_available.to_uint64(), ctx.balance.asset_id); } @@ -123,14 +123,14 @@ void cdd_vesting_policy::on_deposit(const vesting_policy_context& ctx) void cdd_vesting_policy::on_deposit_vested(const vesting_policy_context& ctx) { on_deposit(ctx); - coin_seconds_earned += ctx.amount.amount.value * vesting_seconds; + coin_seconds_earned += ctx.amount.amount.value * std::max(vesting_seconds, 1u); } void cdd_vesting_policy::on_withdraw(const vesting_policy_context& ctx) { update_coin_seconds_earned(ctx); fc::uint128_t coin_seconds_needed = ctx.amount.amount.value; - coin_seconds_needed *= vesting_seconds; + coin_seconds_needed *= std::max(vesting_seconds, 1u); // is_withdraw_allowed should forbid any withdrawal that // would trigger this assert assert(coin_seconds_needed <= coin_seconds_earned); From fda84dfe8bdafe1b7e35565c1b022548b6f046f6 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Sat, 24 Oct 2015 12:21:48 -0400 Subject: [PATCH 02/19] witness: Submit wakeup time for fc::schedule() on local system clock, not NTP --- libraries/plugins/witness/witness.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/libraries/plugins/witness/witness.cpp b/libraries/plugins/witness/witness.cpp index fd346342..acdad202 100644 --- a/libraries/plugins/witness/witness.cpp +++ b/libraries/plugins/witness/witness.cpp @@ -146,12 +146,18 @@ void witness_plugin::plugin_shutdown() void witness_plugin::schedule_production_loop() { //Schedule for the next second's tick regardless of chain state - // If we would wait less than 200ms, wait for the whole second. - fc::time_point now = graphene::time::now(); - fc::time_point_sec next_second( now + fc::microseconds( 1200000 ) ); - //wdump( (now.time_since_epoch().count())(next_second) ); + // If we would wait less than 50ms, wait for the whole second. + fc::time_point ntp_now = graphene::time::now(); + fc::time_point fc_now = fc::time_point::now(); + int64_t time_to_next_second = 1000000 - (ntp_now.time_since_epoch().count() % 1000000); + if( time_to_next_second < 50000 ) // we must sleep for at least 50ms + time_to_next_second += 1000000; + + fc::time_point next_wakeup( fc_now + fc::microseconds( time_to_next_second ) ); + + //wdump( (now.time_since_epoch().count())(next_wakeup.time_since_epoch().count()) ); _block_production_task = fc::schedule([this]{block_production_loop();}, - next_second, "Witness Block Production"); + next_wakeup, "Witness Block Production"); } block_production_condition::block_production_condition_enum witness_plugin::block_production_loop() From 7d9d96fe630897ecaa19f6c208b446395d14c640 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Mon, 26 Oct 2015 17:07:26 -0400 Subject: [PATCH 03/19] genesis_util: apply_patch appends to empty list with warning --- programs/genesis_util/apply_patch.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/programs/genesis_util/apply_patch.py b/programs/genesis_util/apply_patch.py index 259ee6c9..bbce41b4 100755 --- a/programs/genesis_util/apply_patch.py +++ b/programs/genesis_util/apply_patch.py @@ -31,6 +31,9 @@ def main(): with open(filename, "r") as f: patch = json.load(f) for k, v in patch.get("append", {}).items(): + if k not in genesis: + genesis[k] = [] + sys.stderr.write("[WARN] item {k} was created\n".format(k=k)) genesis[k].extend(v) sys.stderr.write("appended {n} items to {k}\n".format(n=len(v), k=k)) for k, v in patch.get("replace", {}).items(): From 76ba85f93e596b1e6b3062952829837da24e4cde Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Fri, 23 Oct 2015 18:16:40 -0400 Subject: [PATCH 04/19] genesis_util: Implement generate_init_config.py --- programs/genesis_util/generate_init_config.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100755 programs/genesis_util/generate_init_config.py diff --git a/programs/genesis_util/generate_init_config.py b/programs/genesis_util/generate_init_config.py new file mode 100755 index 00000000..6e65c69b --- /dev/null +++ b/programs/genesis_util/generate_init_config.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 + +import argparse +import json +import subprocess +import sys + +def dump_json(obj, out, pretty): + if pretty: + json.dump(obj, out, indent=2, sort_keys=True) + else: + json.dump(obj, out, separators=(",", ":"), sort_keys=True) + return + +def main(): + parser = argparse.ArgumentParser(description="Generate a patch file that adds init accounts") + parser.add_argument("-o", "--output", metavar="OUT", default="-", help="output filename (default: stdout)") + parser.add_argument("-n", "--num", metavar="N", default=11, type=int, help="number of init witnesses") + parser.add_argument("-w", "--witness", metavar="N", default=1, type=int, help="starting witness ID") + parser.add_argument("-p", "--pretty", action="store_true", default=False, help="pretty print output") + parser.add_argument("-m", "--mname", metavar="HOSTNAME", default="", help="machine name of target machine") + parser.add_argument("-s", "--secret", metavar="SECRET", default=None, help="private key generation secret") + opts = parser.parse_args() + + if opts.secret is None: + sys.stderr.write("missing required parameter --secret\n") + sys.stderr.flush() + sys.exit(1) + + out_wits = [] + out_keys = [] + + for i in range(opts.num): + if opts.mname != "": + istr = "wit-block-signing-"+opts.mname+"-"+str(i) + else: + istr = "wit-block-signing-"+str(i) + prod_str = subprocess.check_output(["programs/genesis_util/get_dev_key", opts.secret, istr]).decode("utf-8") + prod = json.loads(prod_str) + out_wits.append('witness-id = "1.6.'+str(opts.witness+i)+'"\n') + out_keys.append("private-key = "+json.dumps([prod[0]["public_key"], prod[0]["private_key"]])+"\n") + + out_data = "".join(out_wits + ["\n"] + out_keys) + + if opts.output == "-": + sys.stdout.write(out_data) + sys.stdout.flush() + else: + with open(opts.output, "w") as f: + f.write(out_data) + return + +if __name__ == "__main__": + main() From 57015b43faa766f0ed0cdfecf85d5271a7b3471e Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Mon, 26 Oct 2015 21:25:16 -0400 Subject: [PATCH 05/19] Add missing FC_REFLECT_TYPENAME #414 --- libraries/chain/include/graphene/chain/protocol/base.hpp | 1 + libraries/chain/include/graphene/chain/protocol/types.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/libraries/chain/include/graphene/chain/protocol/base.hpp b/libraries/chain/include/graphene/chain/protocol/base.hpp index 92708933..5f9114b1 100644 --- a/libraries/chain/include/graphene/chain/protocol/base.hpp +++ b/libraries/chain/include/graphene/chain/protocol/base.hpp @@ -117,4 +117,5 @@ namespace graphene { namespace chain { } } // graphene::chain FC_REFLECT_TYPENAME( graphene::chain::operation_result ) +FC_REFLECT_TYPENAME( graphene::chain::future_extensions ) FC_REFLECT( graphene::chain::void_result, ) diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index 94c8a58e..ec0006b1 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -310,6 +310,7 @@ FC_REFLECT_TYPENAME( graphene::chain::operation_history_id_type ) FC_REFLECT_TYPENAME( graphene::chain::withdraw_permission_id_type ) FC_REFLECT_TYPENAME( graphene::chain::vesting_balance_id_type ) FC_REFLECT_TYPENAME( graphene::chain::worker_id_type ) +FC_REFLECT_TYPENAME( graphene::chain::balance_id_type ) FC_REFLECT_TYPENAME( graphene::chain::global_property_id_type ) FC_REFLECT_TYPENAME( graphene::chain::dynamic_global_property_id_type ) FC_REFLECT_TYPENAME( graphene::chain::asset_dynamic_data_id_type ) From d1f9216f8598290b514e59e2ed656c00458f7ab1 Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Wed, 28 Oct 2015 11:51:38 -0400 Subject: [PATCH 06/19] HARDFORK enable whitelisting of everyone, but blacklisting of some --- libraries/chain/account_object.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/libraries/chain/account_object.cpp b/libraries/chain/account_object.cpp index 79729638..839a4537 100644 --- a/libraries/chain/account_object.cpp +++ b/libraries/chain/account_object.cpp @@ -38,12 +38,23 @@ 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 { +bool account_object::is_authorized_asset(const asset_object& asset_obj) const +{ for( const auto id : blacklisting_accounts ) - if( asset_obj.options.blacklist_authorities.find(id) != asset_obj.options.blacklist_authorities.end() ) return false; + { + if( asset_obj.options.blacklist_authorities.find(id) != asset_obj.options.blacklist_authorities.end() ) + return false; + } + + 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; + { + if( asset_obj.options.whitelist_authorities.find(id) != asset_obj.options.whitelist_authorities.end() ) + return true; + } + return false; } From 20c8ca8fa1552bfca814610c4a8e3d8e337e209b Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Fri, 30 Oct 2015 09:50:48 -0400 Subject: [PATCH 07/19] Fix #398 - reserve_asset was calling fund_fee_pool in wallet --- libraries/wallet/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index cccf510a..3858f4c1 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2955,7 +2955,7 @@ signed_transaction wallet_api::reserve_asset(string from, string symbol, bool broadcast /* = false */) { - return my->fund_asset_fee_pool(from, amount, symbol, broadcast); + return my->reserve_asset(from, amount, symbol, broadcast); } signed_transaction wallet_api::global_settle_asset(string symbol, From db045f453cd303d32b42142144b1363f8fd62f80 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Fri, 30 Oct 2015 13:10:09 -0400 Subject: [PATCH 08/19] Implement hardfork logic for #415 --- libraries/chain/account_object.cpp | 10 +++++++--- libraries/chain/asset_evaluator.cpp | 8 ++++---- .../include/graphene/chain/account_object.hpp | 2 +- .../chain/include/graphene/chain/hardfork.hpp | 1 + libraries/chain/market_evaluator.cpp | 6 +++--- libraries/chain/transfer_evaluator.cpp | 16 ++++++++-------- .../chain/withdraw_permission_evaluator.cpp | 6 +++--- tests/tests/uia_tests.cpp | 6 +++--- 8 files changed, 30 insertions(+), 25 deletions(-) diff --git a/libraries/chain/account_object.cpp b/libraries/chain/account_object.cpp index 839a4537..ef52056c 100644 --- a/libraries/chain/account_object.cpp +++ b/libraries/chain/account_object.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include namespace graphene { namespace chain { @@ -38,7 +39,7 @@ 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 +bool account_object::is_authorized_asset(const asset_object& asset_obj, const database& d) const { for( const auto id : blacklisting_accounts ) { @@ -46,8 +47,11 @@ bool account_object::is_authorized_asset(const asset_object& asset_obj) const return false; } - if( asset_obj.options.whitelist_authorities.size() == 0 ) - return true; + if( d.head_block_time() > HARDFORK_415_TIME ) + { + if( asset_obj.options.whitelist_authorities.size() == 0 ) + return true; + } for( const auto id : whitelisting_accounts ) { diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index 2fe586da..03e07e66 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -126,7 +126,7 @@ object_id_type asset_create_evaluator::do_apply( const asset_create_operation& o void_result asset_issue_evaluator::do_evaluate( const asset_issue_operation& o ) { try { - database& d = db(); + const database& d = db(); const asset_object& a = o.asset_to_issue.asset_id(d); FC_ASSERT( o.issuer == a.issuer ); @@ -136,7 +136,7 @@ void_result asset_issue_evaluator::do_evaluate( const asset_issue_operation& o ) if( a.options.flags & white_list ) { - FC_ASSERT( to_account->is_authorized_asset( a ) ); + FC_ASSERT( to_account->is_authorized_asset( a, d ) ); } asset_dyn_data = &a.dynamic_asset_data_id(d); @@ -158,7 +158,7 @@ void_result asset_issue_evaluator::do_apply( const asset_issue_operation& o ) void_result asset_reserve_evaluator::do_evaluate( const asset_reserve_operation& o ) { try { - database& d = db(); + const database& d = db(); const asset_object& a = o.amount_to_reserve.asset_id(d); GRAPHENE_ASSERT( @@ -172,7 +172,7 @@ void_result asset_reserve_evaluator::do_evaluate( const asset_reserve_operation& if( a.options.flags & white_list ) { - FC_ASSERT( from_account->is_authorized_asset( a ) ); + FC_ASSERT( from_account->is_authorized_asset( a, d ) ); } asset_dyn_data = &a.dynamic_asset_data_id(d); diff --git a/libraries/chain/include/graphene/chain/account_object.hpp b/libraries/chain/include/graphene/chain/account_object.hpp index 7c6dac90..5067292d 100644 --- a/libraries/chain/include/graphene/chain/account_object.hpp +++ b/libraries/chain/include/graphene/chain/account_object.hpp @@ -229,7 +229,7 @@ namespace graphene { namespace chain { * @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; + 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/hardfork.hpp b/libraries/chain/include/graphene/chain/hardfork.hpp index 01907932..503e5f0b 100644 --- a/libraries/chain/include/graphene/chain/hardfork.hpp +++ b/libraries/chain/include/graphene/chain/hardfork.hpp @@ -22,3 +22,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 )) diff --git a/libraries/chain/market_evaluator.cpp b/libraries/chain/market_evaluator.cpp index a0eeac97..19f7742f 100644 --- a/libraries/chain/market_evaluator.cpp +++ b/libraries/chain/market_evaluator.cpp @@ -29,7 +29,7 @@ namespace graphene { namespace chain { void_result limit_order_create_evaluator::do_evaluate(const limit_order_create_operation& op) { try { - database& d = db(); + const database& d = db(); FC_ASSERT( op.expiration >= d.head_block_time() ); @@ -42,8 +42,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( _sell_asset->enforce_white_list() ) FC_ASSERT( _seller->is_authorized_asset( *_sell_asset ) ); - if( _receive_asset->enforce_white_list() ) FC_ASSERT( _seller->is_authorized_asset( *_receive_asset ) ); + 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 ) ); 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 91e6eeb4..521f2f55 100644 --- a/libraries/chain/transfer_evaluator.cpp +++ b/libraries/chain/transfer_evaluator.cpp @@ -26,7 +26,7 @@ namespace graphene { namespace chain { void_result transfer_evaluator::do_evaluate( const transfer_operation& op ) { try { - database& d = db(); + const database& d = db(); const account_object& from_account = op.from(d); const account_object& to_account = op.to(d); @@ -38,14 +38,14 @@ void_result transfer_evaluator::do_evaluate( const transfer_operation& op ) if( asset_type.options.flags & white_list ) { GRAPHENE_ASSERT( - from_account.is_authorized_asset( asset_type ), + 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 ), + 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) @@ -54,7 +54,7 @@ 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 ) ); + FC_ASSERT( from_account.is_authorized_asset( asset_type, d ) ); if( asset_type.is_transfer_restricted() ) { @@ -87,7 +87,7 @@ void_result transfer_evaluator::do_apply( const transfer_operation& o ) void_result override_transfer_evaluator::do_evaluate( const override_transfer_operation& op ) { try { - database& d = db(); + const database& d = db(); const asset_object& asset_type = op.amount.asset_id(d); GRAPHENE_ASSERT( @@ -104,12 +104,12 @@ void_result override_transfer_evaluator::do_evaluate( const override_transfer_op if( asset_type.options.flags & white_list ) { - FC_ASSERT( to_account.is_authorized_asset( asset_type ) ); - FC_ASSERT( from_account.is_authorized_asset( asset_type ) ); + FC_ASSERT( to_account.is_authorized_asset( asset_type, d ) ); + 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 ) ); + FC_ASSERT( from_account.is_authorized_asset( asset_type, d ) ); 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) ); diff --git a/libraries/chain/withdraw_permission_evaluator.cpp b/libraries/chain/withdraw_permission_evaluator.cpp index 620a2af7..17e96c45 100644 --- a/libraries/chain/withdraw_permission_evaluator.cpp +++ b/libraries/chain/withdraw_permission_evaluator.cpp @@ -53,7 +53,7 @@ object_id_type withdraw_permission_create_evaluator::do_apply(const operation_ty void_result withdraw_permission_claim_evaluator::do_evaluate(const withdraw_permission_claim_evaluator::operation_type& op) { try { - database& d = db(); + const database& d = db(); const withdraw_permission_object& permit = op.withdraw_permission(d); FC_ASSERT(permit.expiration > d.head_block_time() ); @@ -69,8 +69,8 @@ void_result withdraw_permission_claim_evaluator::do_evaluate(const withdraw_perm { const account_object& from = op.withdraw_to_account(d); const account_object& to = permit.authorized_account(d); - FC_ASSERT( to.is_authorized_asset( _asset ) ); - FC_ASSERT( from.is_authorized_asset( _asset ) ); + FC_ASSERT( to.is_authorized_asset( _asset, d ) ); + FC_ASSERT( from.is_authorized_asset( _asset, d ) ); } return void_result(); diff --git a/tests/tests/uia_tests.cpp b/tests/tests/uia_tests.cpp index 2ef816c9..924a91fd 100644 --- a/tests/tests/uia_tests.cpp +++ b/tests/tests/uia_tests.cpp @@ -156,7 +156,7 @@ BOOST_AUTO_TEST_CASE( issue_whitelist_uia ) trx.operations.back() = wop; PUSH_TX( db, trx, ~0 ); - BOOST_CHECK(nathan.is_authorized_asset(advanced)); + BOOST_CHECK(nathan.is_authorized_asset(advanced, db)); trx.operations.back() = op; PUSH_TX( db, trx, ~0 ); @@ -254,7 +254,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) trx.operations.back() = op; //Fail because nathan is blacklisted - BOOST_CHECK(!nathan.is_authorized_asset(advanced)); + BOOST_CHECK(!nathan.is_authorized_asset(advanced, db)); 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. @@ -271,7 +271,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)); + BOOST_CHECK(!nathan.is_authorized_asset(advanced, db)); GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); burn.payer = dan.id; From 032eeda416f2214a83a10de86944c5d80e4a39a4 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 27 Oct 2015 18:41:38 -0400 Subject: [PATCH 09/19] generic_index.hpp: Change sparse_index to use ordered_unique --- libraries/db/include/graphene/db/generic_index.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/db/include/graphene/db/generic_index.hpp b/libraries/db/include/graphene/db/generic_index.hpp index 1ccb4154..d93546cf 100644 --- a/libraries/db/include/graphene/db/generic_index.hpp +++ b/libraries/db/include/graphene/db/generic_index.hpp @@ -23,7 +23,6 @@ #include #include #include -#include #include namespace graphene { namespace chain { @@ -117,7 +116,7 @@ namespace graphene { namespace chain { struct sparse_index : public generic_index, member > From e8b1deec03a83d313e9e31243fb66d29c05f4511 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Fri, 30 Oct 2015 18:17:19 -0400 Subject: [PATCH 10/19] uia_tests.cpp: Mostly rewrite issue_whitelist_uia to test new whitelist logic #415 --- tests/tests/uia_tests.cpp | 66 +++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/tests/tests/uia_tests.cpp b/tests/tests/uia_tests.cpp index 924a91fd..4054143c 100644 --- a/tests/tests/uia_tests.cpp +++ b/tests/tests/uia_tests.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -134,33 +135,72 @@ BOOST_AUTO_TEST_CASE( override_transfer_test2 ) BOOST_AUTO_TEST_CASE( issue_whitelist_uia ) { try { - INVOKE(create_advanced_uia); - const asset_object& advanced = get_asset("ADVANCED"); - const account_object& nathan = create_account("nathan"); - upgrade_to_lifetime_member(nathan); + account_id_type dan_id = create_account("dan").id; + const asset_id_type uia_id = create_user_issued_asset( + "WLUIA", dan_id(db), white_list ).id; + account_id_type nathan_id = create_account("nathan").id; + account_id_type vikram_id = create_account("vikram").id; trx.clear(); asset_issue_operation op; - op.issuer = advanced.issuer; - op.asset_to_issue = advanced.amount(1000); - op.issue_to_account = nathan.id; //({asset(), advanced.issuer, advanced.amount(1000), nathan.id}); + op.issuer = uia_id(db).issuer; + op.asset_to_issue = asset(1000, uia_id); + op.issue_to_account = nathan_id; trx.operations.emplace_back(op); - //Fail because nathan is not whitelisted. + set_expiration( db, trx ); + //Fail because nathan is not whitelisted, but only before hardfork time GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + generate_blocks( HARDFORK_415_TIME ); + generate_block(); + set_expiration( db, trx ); + PUSH_TX( db, trx, ~0 ); + + BOOST_CHECK(nathan_id(db).is_authorized_asset(uia_id(db), db)); + BOOST_CHECK_EQUAL(get_balance(nathan_id, uia_id), 1000); + + // Make a whitelist, now it should fail + { + BOOST_TEST_MESSAGE( "Changing the whitelist authority" ); + asset_update_operation uop; + uop.issuer = dan_id; + uop.asset_to_update = uia_id; + uop.new_options = uia_id(db).options; + uop.new_options.whitelist_authorities.insert(dan_id); + trx.operations.back() = uop; + PUSH_TX( db, trx, ~0 ); + BOOST_CHECK( uia_id(db).options.whitelist_authorities.find(dan_id) != uia_id(db).options.whitelist_authorities.end() ); + } + + // Fail because there is a whitelist authority and I'm not whitelisted + trx.operations.back() = op; + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, ~0 ), fc::exception ); account_whitelist_operation wop; - wop.authorizing_account = account_id_type(); - wop.account_to_list = nathan.id; + wop.authorizing_account = dan_id; + wop.account_to_list = vikram_id; wop.new_listing = account_whitelist_operation::white_listed; trx.operations.back() = wop; + // Fail because whitelist function is restricted to members only + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, ~0 ), fc::exception ); + upgrade_to_lifetime_member( dan_id ); + trx.operations.clear(); + trx.operations.push_back( wop ); PUSH_TX( db, trx, ~0 ); - BOOST_CHECK(nathan.is_authorized_asset(advanced, db)); + // Still fail after an irrelevant account was added trx.operations.back() = op; - PUSH_TX( db, trx, ~0 ); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, ~0 ), fc::exception ); + + wop.account_to_list = nathan_id; + trx.operations.back() = wop; + PUSH_TX( db, trx, ~0 ); + trx.operations.back() = op; + BOOST_CHECK_EQUAL(get_balance(nathan_id, uia_id), 1000); + // Finally succeed when we were whitelisted + PUSH_TX( db, trx, ~0 ); + BOOST_CHECK_EQUAL(get_balance(nathan_id, uia_id), 2000); - BOOST_CHECK_EQUAL(get_balance(nathan, advanced), 1000); } catch(fc::exception& e) { edump((e.to_detail_string())); throw; From 1559df551a5cdcfbe4a2788584c7c291f6d80a74 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Sat, 31 Oct 2015 10:40:37 -0400 Subject: [PATCH 11/19] uia_tests.cpp: Fix transfer_whitelist_uia test broken by issue_whitelist_uia changes #415 --- tests/tests/uia_tests.cpp | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/tests/tests/uia_tests.cpp b/tests/tests/uia_tests.cpp index 4054143c..c8a7ae05 100644 --- a/tests/tests/uia_tests.cpp +++ b/tests/tests/uia_tests.cpp @@ -135,9 +135,9 @@ BOOST_AUTO_TEST_CASE( override_transfer_test2 ) BOOST_AUTO_TEST_CASE( issue_whitelist_uia ) { try { - account_id_type dan_id = create_account("dan").id; + account_id_type izzy_id = create_account("izzy").id; const asset_id_type uia_id = create_user_issued_asset( - "WLUIA", dan_id(db), white_list ).id; + "ADVANCED", izzy_id(db), white_list ).id; account_id_type nathan_id = create_account("nathan").id; account_id_type vikram_id = create_account("vikram").id; trx.clear(); @@ -162,13 +162,13 @@ BOOST_AUTO_TEST_CASE( issue_whitelist_uia ) { BOOST_TEST_MESSAGE( "Changing the whitelist authority" ); asset_update_operation uop; - uop.issuer = dan_id; + uop.issuer = izzy_id; uop.asset_to_update = uia_id; uop.new_options = uia_id(db).options; - uop.new_options.whitelist_authorities.insert(dan_id); + uop.new_options.whitelist_authorities.insert(izzy_id); trx.operations.back() = uop; PUSH_TX( db, trx, ~0 ); - BOOST_CHECK( uia_id(db).options.whitelist_authorities.find(dan_id) != uia_id(db).options.whitelist_authorities.end() ); + BOOST_CHECK( uia_id(db).options.whitelist_authorities.find(izzy_id) != uia_id(db).options.whitelist_authorities.end() ); } // Fail because there is a whitelist authority and I'm not whitelisted @@ -176,14 +176,14 @@ BOOST_AUTO_TEST_CASE( issue_whitelist_uia ) GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, ~0 ), fc::exception ); account_whitelist_operation wop; - wop.authorizing_account = dan_id; + wop.authorizing_account = izzy_id; wop.account_to_list = vikram_id; wop.new_listing = account_whitelist_operation::white_listed; trx.operations.back() = wop; // Fail because whitelist function is restricted to members only GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, ~0 ), fc::exception ); - upgrade_to_lifetime_member( dan_id ); + upgrade_to_lifetime_member( izzy_id ); trx.operations.clear(); trx.operations.push_back( wop ); PUSH_TX( db, trx, ~0 ); @@ -214,6 +214,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) const asset_object& advanced = get_asset("ADVANCED"); const account_object& nathan = get_account("nathan"); const account_object& dan = create_account("dan"); + account_id_type izzy_id = get_account("izzy").id; upgrade_to_lifetime_member(dan); trx.clear(); @@ -229,23 +230,36 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) BOOST_TEST_MESSAGE( "Adding dan to whitelist for asset ADVANCED" ); account_whitelist_operation wop; - wop.authorizing_account = account_id_type(); + wop.authorizing_account = izzy_id; wop.account_to_list = dan.id; wop.new_listing = account_whitelist_operation::white_listed; trx.operations.back() = wop; PUSH_TX( db, trx, ~0 ); - BOOST_TEST_MESSAGE( "Attempting to trnsfer from nathan to dan after whitelisting dan, should succeed" ); + BOOST_TEST_MESSAGE( "Attempting to transfer from nathan to dan after whitelisting dan, should succeed" ); trx.operations.back() = op; PUSH_TX( db, trx, ~0 ); - BOOST_CHECK_EQUAL(get_balance(nathan, advanced), 900); + BOOST_CHECK_EQUAL(get_balance(nathan, advanced), 1900); BOOST_CHECK_EQUAL(get_balance(dan, advanced), 100); BOOST_TEST_MESSAGE( "Attempting to blacklist nathan" ); + { + BOOST_TEST_MESSAGE( "Changing the blacklist authority" ); + asset_update_operation uop; + uop.issuer = izzy_id; + uop.asset_to_update = advanced.id; + uop.new_options = advanced.options; + uop.new_options.blacklist_authorities.insert(izzy_id); + trx.operations.back() = uop; + PUSH_TX( db, trx, ~0 ); + BOOST_CHECK( advanced.options.blacklist_authorities.find(izzy_id) != advanced.options.blacklist_authorities.end() ); + } + wop.new_listing |= account_whitelist_operation::black_listed; wop.account_to_list = nathan.id; trx.operations.back() = wop; PUSH_TX( db, trx, ~0 ); + BOOST_CHECK( !(nathan.is_authorized_asset(advanced, db)) ); BOOST_TEST_MESSAGE( "Attempting to transfer from nathan after blacklisting, should fail" ); op.amount = advanced.amount(50); @@ -270,6 +284,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) { BOOST_TEST_MESSAGE( "Changing the blacklist authority to dan" ); asset_update_operation op; + op.issuer = izzy_id; op.asset_to_update = advanced.id; op.new_options = advanced.options; op.new_options.blacklist_authorities.clear(); @@ -282,7 +297,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) BOOST_TEST_MESSAGE( "Attempting to transfer from dan back to nathan" ); trx.operations.back() = op; PUSH_TX( db, trx, ~0 ); - BOOST_CHECK_EQUAL(get_balance(nathan, advanced), 950); + BOOST_CHECK_EQUAL(get_balance(nathan, advanced), 1950); BOOST_CHECK_EQUAL(get_balance(dan, advanced), 50); BOOST_TEST_MESSAGE( "Blacklisting nathan by dan" ); @@ -298,7 +313,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) 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. - wop.authorizing_account = account_id_type(); + wop.authorizing_account = izzy_id; wop.account_to_list = nathan.id; wop.new_listing = account_whitelist_operation::no_listing; trx.operations.back() = wop; From fabe83fbadd711dd8e66dd67e266d6e64fc2b074 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Fri, 30 Oct 2015 19:12:05 -0400 Subject: [PATCH 12/19] database_fixture.cpp: Make GRAPHENE_TESTING_GENESIS_TIMESTAMP configurable #427 --- tests/common/database_fixture.cpp | 2 ++ tests/common/database_fixture.hpp | 2 +- tests/tests/main.cpp | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index e671aba4..676c53b5 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -46,6 +46,8 @@ using namespace graphene::chain::test; +uint32_t GRAPHENE_TESTING_GENESIS_TIMESTAMP = 1431700000; + namespace graphene { namespace chain { using std::cout; diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 4f38c603..9bb218a9 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -29,7 +29,7 @@ using namespace graphene::db; -#define GRAPHENE_TESTING_GENESIS_TIMESTAMP (1431700000) +extern uint32_t GRAPHENE_TESTING_GENESIS_TIMESTAMP; #define PUSH_TX \ graphene::chain::test::_push_transaction diff --git a/tests/tests/main.cpp b/tests/tests/main.cpp index c3ce0631..906bbca0 100644 --- a/tests/tests/main.cpp +++ b/tests/tests/main.cpp @@ -23,8 +23,16 @@ #include #include +extern uint32_t GRAPHENE_TESTING_GENESIS_TIMESTAMP; + boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) { std::srand(time(NULL)); std::cout << "Random number generator seeded to " << time(NULL) << std::endl; + const char* genesis_timestamp_str = getenv("GRAPHENE_TESTING_GENESIS_TIMESTAMP"); + if( genesis_timestamp_str != nullptr ) + { + GRAPHENE_TESTING_GENESIS_TIMESTAMP = std::stoul( genesis_timestamp_str ); + } + std::cout << "GRAPHENE_TESTING_GENESIS_TIMESTAMP is " << GRAPHENE_TESTING_GENESIS_TIMESTAMP << std::endl; return nullptr; } From cf4efca17f7c92418a02760e8c31308aeac45ae9 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Sat, 31 Oct 2015 10:28:23 -0400 Subject: [PATCH 13/19] uia_tests.cpp: Add hardfork logic to issue_whitelist_uia #415 --- tests/tests/uia_tests.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/tests/uia_tests.cpp b/tests/tests/uia_tests.cpp index c8a7ae05..41cda68f 100644 --- a/tests/tests/uia_tests.cpp +++ b/tests/tests/uia_tests.cpp @@ -149,10 +149,13 @@ BOOST_AUTO_TEST_CASE( issue_whitelist_uia ) trx.operations.emplace_back(op); set_expiration( db, trx ); //Fail because nathan is not whitelisted, but only before hardfork time - GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); - generate_blocks( HARDFORK_415_TIME ); - generate_block(); - set_expiration( db, trx ); + if( db.head_block_time() <= HARDFORK_415_TIME ) + { + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + generate_blocks( HARDFORK_415_TIME ); + generate_block(); + set_expiration( db, trx ); + } PUSH_TX( db, trx, ~0 ); BOOST_CHECK(nathan_id(db).is_authorized_asset(uia_id(db), db)); From e1a692b33c95e36f4a59f5b4ca18451c695d232f Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Sat, 31 Oct 2015 10:39:16 -0400 Subject: [PATCH 14/19] operation_tests2.cpp: Fix witness_create test to comply with new witness schedule (breakage revealed by #427) --- tests/tests/operation_tests2.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index ee05ffd9..ecf4a1ad 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -453,15 +453,16 @@ BOOST_AUTO_TEST_CASE( witness_create ) generate_block(); int produced = 0; - // Make sure we get scheduled exactly once in witnesses.size() blocks + // Make sure we get scheduled at least once in witnesses.size()*2 blocks + // may take this many unless we measure where in the scheduling round we are // TODO: intense_test that repeats this loop many times - for( size_t i=0; i Date: Tue, 27 Oct 2015 18:41:21 -0400 Subject: [PATCH 15/19] global_property_object.hpp: Reflect last_budget_time #414 --- .../chain/include/graphene/chain/global_property_object.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index b861e5be..61aecf97 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -128,6 +128,7 @@ FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene:: (time) (current_witness) (next_maintenance_time) + (last_budget_time) (witness_budget) (accounts_registered_this_interval) (recently_missed_count) From 7c9d4584b88bbfdd9505d450b15a41a9338c0c1f Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Sat, 31 Oct 2015 15:29:00 -0400 Subject: [PATCH 16/19] operation_tests2.cpp: Don't use real time for balance_object_test starting_time, breakage revealed by #427 --- tests/tests/operation_tests2.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index ecf4a1ad..a799d7c9 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -1037,8 +1037,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) fc::temp_directory td( graphene::utilities::temp_directory_path() ); genesis_state.initial_balances.push_back({generate_private_key("n").get_public_key(), GRAPHENE_SYMBOL, 1}); genesis_state.initial_balances.push_back({generate_private_key("x").get_public_key(), GRAPHENE_SYMBOL, 1}); - auto starting_time = time_point_sec((time_point::now().sec_since_epoch() / GRAPHENE_DEFAULT_BLOCK_INTERVAL + 1) * - GRAPHENE_DEFAULT_BLOCK_INTERVAL); + fc::time_point_sec starting_time = genesis_state.initial_timestamp + 3000; auto n_key = generate_private_key("n"); auto x_key = generate_private_key("x"); From 28eddf1b6fd6378054a7500e94d4877c2cdcc965 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Sat, 31 Oct 2015 15:37:17 -0400 Subject: [PATCH 17/19] block_tests.cpp: Fix generate_empty_blocks not working correctly when last_irreversible_block_num skipped over 200 Revealed by #427, related to #407 --- tests/tests/block_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index f6124583..96e8d393 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE( generate_empty_blocks ) { database db; db.open(data_dir.path(), []{return genesis_state_type();}); - BOOST_CHECK_EQUAL( db.head_block_num(), 200 ); + BOOST_CHECK_EQUAL( db.head_block_num(), cutoff_block.block_num() ); b = cutoff_block; for( uint32_t i = 0; i < 200; ++i ) { @@ -169,7 +169,7 @@ BOOST_AUTO_TEST_CASE( generate_empty_blocks ) //BOOST_CHECK( cur_witness != prev_witness ); b = db.generate_block(db.get_slot_time(1), cur_witness, init_account_priv_key, database::skip_nothing); } - BOOST_CHECK_EQUAL( db.head_block_num(), 400 ); + BOOST_CHECK_EQUAL( db.head_block_num(), cutoff_block.block_num()+200 ); } } catch (fc::exception& e) { edump((e.to_detail_string())); From 55fef1b1616377e552a1f1aecca77ef9115ce18f Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Fri, 30 Oct 2015 09:57:45 -0400 Subject: [PATCH 18/19] db_update.cpp: Don't clear expired feeds for non-market-issued assets #410 --- libraries/chain/db_update.cpp | 10 ++++++---- .../chain/include/graphene/chain/asset_object.hpp | 8 ++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 1fc7fc83..2b6ba2e7 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -366,11 +366,13 @@ void database::clear_expired_orders() void database::update_expired_feeds() { - auto& asset_idx = get_index_type().indices(); - for( const asset_object& a : asset_idx ) + auto& asset_idx = get_index_type().indices().get(); + auto itr = asset_idx.lower_bound( true /** market issued */ ); + while( itr != asset_idx.end() ) { - if( !a.is_market_issued() ) - continue; + const asset_object& a = *itr; + ++itr; + assert( a.is_market_issued() ); const asset_bitasset_data_object& b = a.bitasset_data(*this); if( b.feed_is_expired(head_block_time()) ) diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index 4496fe03..1661fa7f 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -213,7 +213,6 @@ namespace graphene { namespace chain { void update_median_feeds(time_point_sec current_time); }; - struct by_feed_expiration; typedef multi_index_container< asset_bitasset_data_object, @@ -227,17 +226,19 @@ namespace graphene { namespace chain { typedef flat_index asset_bitasset_data_index; struct by_symbol; + struct by_type; typedef multi_index_container< asset_object, indexed_by< ordered_unique< tag, member< object, object_id_type, &object::id > >, - ordered_unique< tag, member > + ordered_unique< tag, member >, + ordered_non_unique< tag, const_mem_fun > > > asset_object_multi_index_type; typedef generic_index asset_index; - } } // graphene::chain + FC_REFLECT_DERIVED( graphene::chain::asset_dynamic_data_object, (graphene::db::object), (current_supply)(confidential_supply)(accumulated_fees)(fee_pool) ) @@ -260,4 +261,3 @@ FC_REFLECT_DERIVED( graphene::chain::asset_object, (graphene::db::object), (dynamic_asset_data_id) (bitasset_data_id) ) - From d588ac987ce140e7f35911b06e8bc4d4dc9e472d Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Wed, 28 Oct 2015 11:43:56 -0400 Subject: [PATCH 19/19] operation_tests2.cpp: Implement zero_second_vbo test for issue #390 --- tests/tests/operation_tests2.cpp | 116 +++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index ee05ffd9..730b6b84 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1207,6 +1208,121 @@ BOOST_AUTO_TEST_CASE(transfer_with_memo) { } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE(zero_second_vbo) +{ + try + { + ACTOR(alice); + // don't pay witnesses so we have some worker budget to work with + + transfer(account_id_type(), alice_id, asset(int64_t(100000) * 1100 * 1000 * 1000)); + { + asset_reserve_operation op; + op.payer = alice_id; + op.amount_to_reserve = asset(int64_t(100000) * 1000 * 1000 * 1000); + transaction tx; + tx.operations.push_back( op ); + set_expiration( db, tx ); + db.push_transaction( tx, database::skip_authority_check | database::skip_tapos_check | database::skip_transaction_signatures ); + } + enable_fees(); + upgrade_to_lifetime_member(alice_id); + generate_block(); + + auto check_vesting_1b = [&](vesting_balance_id_type vbid) + { + // this function checks that Alice can't draw any right now, + // but one block later, she can withdraw it all. + + vesting_balance_withdraw_operation withdraw_op; + withdraw_op.vesting_balance = vbid; + withdraw_op.owner = alice_id; + withdraw_op.amount = asset(1); + + signed_transaction withdraw_tx; + withdraw_tx.operations.push_back( withdraw_op ); + sign(withdraw_tx, alice_private_key); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, withdraw_tx ), fc::exception ); + + generate_block(); + withdraw_tx = signed_transaction(); + withdraw_op.amount = asset(500); + withdraw_tx.operations.push_back( withdraw_op ); + set_expiration( db, withdraw_tx ); + sign(withdraw_tx, alice_private_key); + PUSH_TX( db, withdraw_tx ); + }; + + // This block creates a zero-second VBO with a vesting_balance_create_operation. + { + cdd_vesting_policy_initializer pinit; + pinit.vesting_seconds = 0; + + vesting_balance_create_operation create_op; + create_op.creator = alice_id; + create_op.owner = alice_id; + create_op.amount = asset(500); + create_op.policy = pinit; + + signed_transaction create_tx; + create_tx.operations.push_back( create_op ); + set_expiration( db, create_tx ); + sign(create_tx, alice_private_key); + + processed_transaction ptx = PUSH_TX( db, create_tx ); + vesting_balance_id_type vbid = ptx.operation_results[0].get(); + check_vesting_1b( vbid ); + } + + // This block creates a zero-second VBO with a worker_create_operation. + { + worker_create_operation create_op; + create_op.owner = alice_id; + create_op.work_begin_date = db.head_block_time(); + create_op.work_end_date = db.head_block_time() + fc::days(1000); + create_op.daily_pay = share_type( 10000 ); + create_op.name = "alice"; + create_op.url = ""; + create_op.initializer = vesting_balance_worker_initializer(0); + signed_transaction create_tx; + create_tx.operations.push_back(create_op); + set_expiration( db, create_tx ); + sign(create_tx, alice_private_key); + processed_transaction ptx = PUSH_TX( db, create_tx ); + worker_id_type wid = ptx.operation_results[0].get(); + + // vote it in + account_update_operation vote_op; + vote_op.account = alice_id; + vote_op.new_options = alice_id(db).options; + vote_op.new_options->votes.insert(wid(db).vote_for); + signed_transaction vote_tx; + vote_tx.operations.push_back(vote_op); + set_expiration( db, vote_tx ); + sign( vote_tx, alice_private_key ); + PUSH_TX( db, vote_tx ); + + // vote it in, wait for one maint. for vote to take effect + vesting_balance_id_type vbid = wid(db).worker.get().balance; + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); + // wait for another maint. for worker to be paid + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + BOOST_CHECK( vbid(db).get_allowed_withdraw(db.head_block_time()) == asset(0) ); + generate_block(); + BOOST_CHECK( vbid(db).get_allowed_withdraw(db.head_block_time()) == asset(10000) ); + + /* + db.get_index_type< simple_index >().inspect_all_objects( + [&](const object& o) + { + ilog( "budget: ${brec}", ("brec", static_cast(o)) ); + }); + */ + } + } FC_LOG_AND_RETHROW() +} + // TODO: Write linear VBO tests BOOST_AUTO_TEST_SUITE_END()