From b134fbe43c416373a0f24f6d641fdaf71273751c Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Tue, 7 Jul 2015 12:58:49 -0400 Subject: [PATCH 01/28] Move some unacceptably slow tests to intense_tests Speeds up chain_tests runs from ~30s to ~5s on my system. --- tests/intense/block_tests.cpp | 88 +++++++++++++++++++++++++++++++++++ tests/tests/block_tests.cpp | 85 +++------------------------------ tests/tests/fee_tests.cpp | 41 ---------------- 3 files changed, 95 insertions(+), 119 deletions(-) diff --git a/tests/intense/block_tests.cpp b/tests/intense/block_tests.cpp index ffe2d67d..212267a5 100644 --- a/tests/intense/block_tests.cpp +++ b/tests/intense/block_tests.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -401,4 +402,91 @@ BOOST_FIXTURE_TEST_CASE( generic_scheduler_mc_test, database_fixture ) } } +BOOST_FIXTURE_TEST_CASE( tapos_rollover, database_fixture ) +{ + try + { + ACTORS((alice)(bob)); + const auto& core = asset_id_type()(db); + + BOOST_TEST_MESSAGE( "Give Alice some money" ); + transfer(genesis_account, alice_id, asset(10000)); + generate_block(); + + BOOST_TEST_MESSAGE( "Generate up to block 0xFF00" ); + generate_blocks( 0xFF00 ); + signed_transaction xfer_tx; + + BOOST_TEST_MESSAGE( "Transfer money at/about 0xFF00" ); + transfer_operation xfer_op; + xfer_op.from = alice_id; + xfer_op.to = bob_id; + xfer_op.amount = asset(1000); + + xfer_tx.operations.push_back( xfer_op ); + xfer_tx.set_expiration( db.head_block_id(), 0x1000 ); + sign( xfer_tx, alice_private_key ); + PUSH_TX( db, xfer_tx, 0 ); + generate_block(); + + BOOST_TEST_MESSAGE( "Sign new tx's" ); + xfer_tx.set_expiration( db.head_block_id(), 0x1000 ); + xfer_tx.signatures.clear(); + sign( xfer_tx, alice_private_key ); + + BOOST_TEST_MESSAGE( "Generate up to block 0x10010" ); + generate_blocks( 0x110 ); + + BOOST_TEST_MESSAGE( "Transfer at/about block 0x10010 using reference block at/about 0xFF00" ); + PUSH_TX( db, xfer_tx, 0 ); + generate_block(); + } + catch (fc::exception& e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_FIXTURE_TEST_CASE(bulk_discount, database_fixture) +{ try { + ACTOR(nathan); + // Give nathan ALLLLLL the money! + transfer(GRAPHENE_COMMITTEE_ACCOUNT, nathan_id, db.get_balance(GRAPHENE_COMMITTEE_ACCOUNT, asset_id_type())); + enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); + upgrade_to_lifetime_member(nathan_id); + share_type new_fees; + while( nathan_id(db).statistics(db).lifetime_fees_paid + new_fees < GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN ) + { + transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); + new_fees += transfer_operation().calculate_fee(db.current_fee_schedule()); + } + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); + auto old_cashback = nathan_id(db).cashback_balance(db).balance; + + transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); + + BOOST_CHECK_EQUAL(nathan_id(db).cashback_balance(db).balance.amount.value, + old_cashback.amount.value + GRAPHENE_BLOCKCHAIN_PRECISION * 8); + + new_fees = 0; + while( nathan_id(db).statistics(db).lifetime_fees_paid + new_fees < GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MAX ) + { + transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); + new_fees += transfer_operation().calculate_fee(db.current_fee_schedule()); + } + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); + old_cashback = nathan_id(db).cashback_balance(db).balance; + + transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + + BOOST_CHECK_EQUAL(nathan_id(db).cashback_balance(db).balance.amount.value, + old_cashback.amount.value + GRAPHENE_BLOCKCHAIN_PRECISION * 9); +} FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 1293aacd..43a72e89 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -823,7 +823,7 @@ BOOST_FIXTURE_TEST_CASE( pop_block_twice, database_fixture ) // Sam is the creator of accounts private_key_type genesis_key = delegate_priv_key; private_key_type sam_key = generate_private_key("sam"); - account_object sam_account_object = create_account( "sam", sam_key ); + account_object sam_account_object = create_account("sam", sam_key); //Get a sane head block time generate_block( skip_flags ); @@ -839,18 +839,16 @@ BOOST_FIXTURE_TEST_CASE( pop_block_twice, database_fixture ) // transfer from genesis account to Sam account transfer(genesis_account_object, sam_account_object, core.amount(100000)); - generate_block( skip_flags ); + generate_block(skip_flags); - create_account( "alice" ); - generate_block( skip_flags ); - create_account( "bob" ); - generate_block( skip_flags ); + create_account("alice"); + generate_block(skip_flags); + create_account("bob"); + generate_block(skip_flags); db.pop_block(); db.pop_block(); - } - catch( const fc::exception& e ) - { + } catch(const fc::exception& e) { edump( (e.to_detail_string()) ); throw; } @@ -882,73 +880,4 @@ BOOST_FIXTURE_TEST_CASE( witness_scheduler_missed_blocks, database_fixture ) }); } FC_LOG_AND_RETHROW() } -BOOST_FIXTURE_TEST_CASE( account_create_fee_scaling, database_fixture ) -{ try { - auto accounts_per_scale = db.get_global_properties().parameters.accounts_per_fee_scale; - enable_fees(1); - - BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 1); - for( int i = db.get_dynamic_global_properties().accounts_registered_this_interval; i < accounts_per_scale; ++i ) - create_account("shill" + fc::to_string(i)); - generate_block(); - BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 16); - for( int i = 0; i < accounts_per_scale; ++i ) - create_account("moreshills" + fc::to_string(i)); - generate_block(); - BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 256); - for( int i = 0; i < accounts_per_scale; ++i ) - create_account("moarshills" + fc::to_string(i)); - generate_block(); - BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 4096); - - generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 1); -} FC_LOG_AND_RETHROW() } - -BOOST_FIXTURE_TEST_CASE( tapos_rollover, database_fixture ) -{ - try - { - ACTORS((alice)(bob)); - const auto& core = asset_id_type()(db); - - BOOST_TEST_MESSAGE( "Give Alice some money" ); - transfer(genesis_account, alice_id, asset(10000)); - generate_block(); - - BOOST_TEST_MESSAGE( "Generate up to block 0xFF00" ); - generate_blocks( 0xFF00 ); - signed_transaction xfer_tx; - - BOOST_TEST_MESSAGE( "Transfer money at/about 0xFF00" ); - transfer_operation xfer_op; - xfer_op.from = alice_id; - xfer_op.to = bob_id; - xfer_op.amount = asset(1000); - - xfer_tx.operations.push_back( xfer_op ); - xfer_tx.set_expiration( db.head_block_id(), 0x1000 ); - sign( xfer_tx, alice_private_key ); - PUSH_TX( db, xfer_tx, 0 ); - generate_block(); - - BOOST_TEST_MESSAGE( "Sign new tx's" ); - xfer_tx.set_expiration( db.head_block_id(), 0x1000 ); - xfer_tx.signatures.clear(); - sign( xfer_tx, alice_private_key ); - - BOOST_TEST_MESSAGE( "Generate up to block 0x10010" ); - generate_blocks( 0x110 ); - - BOOST_TEST_MESSAGE( "Transfer at/about block 0x10010 using reference block at/about 0xFF00" ); - PUSH_TX( db, xfer_tx, 0 ); - generate_block(); - } - catch (fc::exception& e) - { - edump((e.to_detail_string())); - throw; - } -} - BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/fee_tests.cpp b/tests/tests/fee_tests.cpp index b330aaf9..e25a850b 100644 --- a/tests/tests/fee_tests.cpp +++ b/tests/tests/fee_tests.cpp @@ -130,45 +130,4 @@ BOOST_AUTO_TEST_CASE( cashback_test ) BOOST_CHECK_EQUAL(stud_id(db).cashback_balance(db).balance.amount.value, 25750); } FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(bulk_discount) -{ try { - ACTOR(nathan); - // Give nathan ALLLLLL the money! - transfer(GRAPHENE_COMMITTEE_ACCOUNT, nathan_id, db.get_balance(GRAPHENE_COMMITTEE_ACCOUNT, asset_id_type())); - enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); - upgrade_to_lifetime_member(nathan_id); - share_type new_fees; - while( nathan_id(db).statistics(db).lifetime_fees_paid + new_fees < GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN ) - { - transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); - new_fees += transfer_operation().calculate_fee(db.current_fee_schedule()); - } - generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); - auto old_cashback = nathan_id(db).cashback_balance(db).balance; - - transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); - generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); - - BOOST_CHECK_EQUAL(nathan_id(db).cashback_balance(db).balance.amount.value, - old_cashback.amount.value + GRAPHENE_BLOCKCHAIN_PRECISION * 8); - - new_fees = 0; - while( nathan_id(db).statistics(db).lifetime_fees_paid + new_fees < GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MAX ) - { - transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); - new_fees += transfer_operation().calculate_fee(db.current_fee_schedule()); - } - generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); - old_cashback = nathan_id(db).cashback_balance(db).balance; - - transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); - generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - - BOOST_CHECK_EQUAL(nathan_id(db).cashback_balance(db).balance.amount.value, - old_cashback.amount.value + GRAPHENE_BLOCKCHAIN_PRECISION * 9); -} FC_LOG_AND_RETHROW() } - BOOST_AUTO_TEST_SUITE_END() From e6e7f70ff9fa6120a8c9a2fbeb2a333c294e65cd Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Tue, 7 Jul 2015 13:59:01 -0400 Subject: [PATCH 02/28] Resolve #98: Finish testing of genesis balances --- .../chain/include/graphene/chain/types.hpp | 2 - tests/tests/operation_tests2.cpp | 59 +++++++++++++------ 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/libraries/chain/include/graphene/chain/types.hpp b/libraries/chain/include/graphene/chain/types.hpp index f0bbe79d..9c7fcbef 100644 --- a/libraries/chain/include/graphene/chain/types.hpp +++ b/libraries/chain/include/graphene/chain/types.hpp @@ -322,8 +322,6 @@ namespace graphene { namespace chain { // return ((fc::uint128(data_size(ts...)) * data_fee) / BYTES_PER_DATA_FEE).to_uint64(); } - - /** * Standard fees * diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index f1cf9dab..24d99f04 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -42,8 +42,6 @@ BOOST_FIXTURE_TEST_SUITE( operation_tests, database_fixture ) BOOST_AUTO_TEST_CASE( withdraw_permission_create ) { try { - //ACTORS((nathan)(dan)) - //idump((nathan)(dan)); auto nathan_private_key = generate_private_key("nathan"); auto dan_private_key = generate_private_key("dan"); account_id_type nathan_id = create_account("nathan", nathan_private_key.get_public_key()).id; @@ -1031,6 +1029,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) auto slot = db.get_slot_at_time(starting_time); db.generate_block(starting_time, db.get_scheduled_witness(slot).first, delegate_priv_key, database::skip_nothing); + trx.set_expiration(db.head_block_id()); const balance_object& vesting_balance_1 = balance_id_type(2)(db); const balance_object& vesting_balance_2 = balance_id_type(3)(db); @@ -1045,7 +1044,6 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) op.total_claimed = asset(1); op.balance_owner_key = v1_key.get_public_key(); trx.clear(); - trx.set_expiration(db.head_block_id()); trx.operations = {op}; trx.sign(n_key); trx.sign(v1_key); @@ -1070,8 +1068,9 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) trx.sign(n_key); trx.sign(v2_key); db.push_transaction(trx); - BOOST_CHECK_EQUAL(db.get_balance(op.deposit_to_account, asset_id_type()).amount.value, 101); + BOOST_CHECK_EQUAL(vesting_balance_2.balance.amount.value, 300); + op.total_claimed.amount = 10; trx.operations = {op}; trx.signatures.clear(); @@ -1080,23 +1079,47 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) // Attempting to claim twice within a day BOOST_CHECK_THROW(db.push_transaction(trx), balance_claimed_too_often); -// TODO: test withdrawing entire vesting_balance_1 balance, remainder of vesting_balance_2 balance -// slot = db.get_slot_at_time(vesting_balance_1.vesting_policy->begin_timestamp + 60); -// db.generate_block(starting_time, db.get_scheduled_witness(slot).first, delegate_priv_key, database::skip_nothing); + db.generate_block(db.get_slot_time(1), db.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); + slot = db.get_slot_at_time(vesting_balance_1.vesting_policy->begin_timestamp + 60); + db.generate_block(db.get_slot_time(slot), db.get_scheduled_witness(slot).first, delegate_priv_key, database::skip_nothing); + trx.set_expiration(db.head_block_id()); -// op.balance_to_claim = vesting_balance_1.id; -// op.total_claimed.amount = 500; -// op.balance_owner_key = v1_key.get_public_key(); -// trx.operations = {op}; -// trx.signatures.clear(); -// trx.sign(n_key); -// trx.sign(v2_key); -// db.push_transaction(trx); -// BOOST_CHECK(db.find_object(op.balance_to_claim) == nullptr); + op.balance_to_claim = vesting_balance_1.id; + op.total_claimed.amount = 500; + op.balance_owner_key = v1_key.get_public_key(); + trx.operations = {op}; + trx.signatures.clear(); + trx.sign(n_key); + trx.sign(v1_key); + db.push_transaction(trx); + BOOST_CHECK(db.find_object(op.balance_to_claim) == nullptr); + BOOST_CHECK_EQUAL(db.get_balance(op.deposit_to_account, asset_id_type()).amount.value, 601); + + op.balance_to_claim = vesting_balance_2.id; + op.balance_owner_key = v2_key.get_public_key(); + op.total_claimed.amount = 10; + trx.operations = {op}; + trx.signatures.clear(); + trx.sign(n_key); + trx.sign(v2_key); + // Attempting to claim twice within a day + BOOST_CHECK_THROW(db.push_transaction(trx), balance_claimed_too_often); + + db.generate_block(db.get_slot_time(1), db.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); + slot = db.get_slot_at_time(db.head_block_time() + fc::days(1)); + db.generate_block(db.get_slot_time(slot), db.get_scheduled_witness(slot).first, delegate_priv_key, database::skip_nothing); + trx.set_expiration(db.head_block_id()); + + op.total_claimed = vesting_balance_2.balance; + trx.operations = {op}; + trx.signatures.clear(); + trx.sign(n_key); + trx.sign(v2_key); + db.push_transaction(trx); + BOOST_CHECK(db.find_object(op.balance_to_claim) == nullptr); + BOOST_CHECK_EQUAL(db.get_balance(op.deposit_to_account, asset_id_type()).amount.value, 901); } FC_LOG_AND_RETHROW() } // TODO: Write linear VBO tests BOOST_AUTO_TEST_SUITE_END() - - From 2241fda3af372990527982db49dafd875d5805de Mon Sep 17 00:00:00 2001 From: Vikram Rajkumar Date: Tue, 7 Jul 2015 14:02:02 -0400 Subject: [PATCH 03/28] Add genesis_state_type::initial_worker_type; #17 --- libraries/chain/db_init.cpp | 23 +++++++++-- .../include/graphene/chain/genesis_state.hpp | 39 +++++++++++++------ 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 9cceaea3..03f24086 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -402,22 +402,39 @@ void database::init_genesis(const genesis_state_type& genesis_state) adjust_balance(GRAPHENE_COMMITTEE_ACCOUNT, -get_balance(GRAPHENE_COMMITTEE_ACCOUNT,{})); } - // Create initial witnesses and delegates + // Create initial witnesses std::for_each(genesis_state.initial_witness_candidates.begin(), genesis_state.initial_witness_candidates.end(), [&](const genesis_state_type::initial_witness_type& witness) { witness_create_operation op; + op.witness_account = get_account_id(witness.owner_name); op.block_signing_key = witness.block_signing_key; op.initial_secret = secret_hash_type::hash( secret_hash_type() ); - op.witness_account = get_account_id(witness.owner_name); apply_operation(genesis_eval_state, op); }); + + // Create initial committee members std::for_each(genesis_state.initial_committee_candidates.begin(), genesis_state.initial_committee_candidates.end(), [&](const genesis_state_type::initial_committee_member_type& member) { delegate_create_operation op; op.delegate_account = get_account_id(member.owner_name); - apply_operation(genesis_eval_state, op).get(); + apply_operation(genesis_eval_state, op); }); + // Create initial workers + std::for_each( genesis_state.initial_worker_candidates.begin(), genesis_state.initial_worker_candidates.end(), + [ & ]( const genesis_state_type::initial_worker_type& worker ) + { + worker_create_operation op; + op.owner = get_account_id( worker.owner_name ); + op.work_begin_date = time_point_sec( GRAPHENE_GENESIS_TIMESTAMP ); + op.work_end_date = time_point_sec::maximum(); + op.daily_pay = worker.daily_pay; + op.name = "Genesis-Worker-" + worker.owner_name; + op.initializer = vesting_balance_worker_type::initializer( 0 ); + + apply_operation( genesis_eval_state, std::move( op ) ); + } ); + // Set active witnesses modify(get_global_properties(), [&](global_property_object& p) { auto idx = get_index_type().indices(); diff --git a/libraries/chain/include/graphene/chain/genesis_state.hpp b/libraries/chain/include/graphene/chain/genesis_state.hpp index 594e9542..15b4f5e9 100644 --- a/libraries/chain/include/graphene/chain/genesis_state.hpp +++ b/libraries/chain/include/graphene/chain/genesis_state.hpp @@ -79,6 +79,11 @@ struct genesis_state_type { /// Must correspond to one of the initial accounts string owner_name; }; + struct initial_worker_type { + /// Must correspond to one of the initial accounts + string owner_name; + share_type daily_pay; + }; chain_parameters initial_parameters; vector initial_accounts; @@ -89,26 +94,36 @@ struct genesis_state_type { vector initial_witness_candidates; // These are only candidates; the chain will have no active committee members at genesis vector initial_committee_candidates; + vector initial_worker_candidates; }; } } // namespace graphene::chain FC_REFLECT(graphene::chain::genesis_state_type::initial_account_type, (name)(owner_key)(active_key)(is_lifetime_member)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_balance_type, - (owner)(asset_symbol)(amount)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_vesting_balance_type, - (owner)(asset_symbol)(amount)(begin_timestamp)(vesting_duration_seconds)(begin_balance)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_witness_type, (owner_name)(block_signing_key)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_committee_member_type, (owner_name)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type::initial_bitasset_options::initial_collateral_position, - (collateral)(debt)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type::initial_bitasset_options, - (feed_lifetime_sec)(minimum_feeds)(force_settlement_delay_sec)(force_settlement_offset_percent) - (maximum_force_settlement_volume)(backing_asset_symbol)(maintenance_collateral_ratio)(collateral_records)) + FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type, (symbol)(description)(precision)(issuer_name)(max_supply)(market_fee_percent) (issuer_permissions)(flags)(bitasset_options)(initial_accumulated_fees)) +FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type::initial_bitasset_options, + (feed_lifetime_sec)(minimum_feeds)(force_settlement_delay_sec)(force_settlement_offset_percent) + (maximum_force_settlement_volume)(backing_asset_symbol)(maintenance_collateral_ratio)(collateral_records)) + +FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type::initial_bitasset_options::initial_collateral_position, + (collateral)(debt)) + +FC_REFLECT(graphene::chain::genesis_state_type::initial_balance_type, + (owner)(asset_symbol)(amount)) + +FC_REFLECT(graphene::chain::genesis_state_type::initial_vesting_balance_type, + (owner)(asset_symbol)(amount)(begin_timestamp)(vesting_duration_seconds)(begin_balance)) + +FC_REFLECT(graphene::chain::genesis_state_type::initial_witness_type, (owner_name)(block_signing_key)) + +FC_REFLECT(graphene::chain::genesis_state_type::initial_committee_member_type, (owner_name)) + +FC_REFLECT(graphene::chain::genesis_state_type::initial_worker_type, (owner_name)(daily_pay)) + FC_REFLECT(graphene::chain::genesis_state_type, (initial_parameters)(initial_accounts)(initial_assets)(initial_balances) (initial_vesting_balances)(initial_active_witnesses)(initial_witness_candidates) - (initial_committee_candidates)) + (initial_committee_candidates)(initial_worker_candidates)) From 38956692eef1d8946f8fe08bc4429e12d48ba41a Mon Sep 17 00:00:00 2001 From: Vikram Rajkumar Date: Tue, 7 Jul 2015 15:06:06 -0400 Subject: [PATCH 04/28] Fix a couple misleading names --- .../chain/include/graphene/chain/config.hpp | 4 ++-- .../include/graphene/chain/genesis_state.hpp | 20 +++++++++---------- .../chain/include/graphene/chain/types.hpp | 8 ++++---- libraries/chain/operations.cpp | 10 +++++----- libraries/chain/proposal_evaluator.cpp | 2 +- tests/intense/block_tests.cpp | 2 +- tests/tests/authority_tests.cpp | 14 ++++++------- tests/tests/block_tests.cpp | 4 ++-- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 6e56ecbf..33ae226c 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -86,7 +86,7 @@ #define GRAPHENE_DEFAULT_MAX_WITNESSES (1001) // SHOULD BE ODD #define GRAPHENE_DEFAULT_MAX_COMMITTEE (1001) // SHOULD BE ODD #define GRAPHENE_DEFAULT_MAX_PROPOSAL_LIFETIME_SEC (60*60*24*7*4) // Four weeks -#define GRAPHENE_DEFAULT_GENESIS_PROPOSAL_REVIEW_PERIOD_SEC (60*60*24*7*2) // Two weeks +#define GRAPHENE_DEFAULT_COMMITTEE_PROPOSAL_REVIEW_PERIOD_SEC (60*60*24*7*2) // Two weeks #define GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE (20*GRAPHENE_1_PERCENT) #define GRAPHENE_DEFAULT_LIFETIME_REFERRER_PERCENT_OF_FEE (30*GRAPHENE_1_PERCENT) #define GRAPHENE_DEFAULT_MAX_BULK_DISCOUNT_PERCENT (50*GRAPHENE_1_PERCENT) @@ -139,7 +139,7 @@ * Reserved Account IDs with special meaning */ ///@{ -/// Represents the current committee members, two-week review period (GRAPHENE_DEFAULT_GENESIS_PROPOSAL_REVIEW_PERIOD_SEC) +/// Represents the current committee members, two-week review period #define GRAPHENE_COMMITTEE_ACCOUNT (graphene::chain::account_id_type(0)) /// Represents the current witnesses #define GRAPHENE_WITNESS_ACCOUNT (graphene::chain::account_id_type(1)) diff --git a/libraries/chain/include/graphene/chain/genesis_state.hpp b/libraries/chain/include/graphene/chain/genesis_state.hpp index 15b4f5e9..16d95d59 100644 --- a/libraries/chain/include/graphene/chain/genesis_state.hpp +++ b/libraries/chain/include/graphene/chain/genesis_state.hpp @@ -85,16 +85,16 @@ struct genesis_state_type { share_type daily_pay; }; - chain_parameters initial_parameters; - vector initial_accounts; - vector initial_assets; - vector initial_balances; - vector initial_vesting_balances; - int initial_active_witnesses = GRAPHENE_DEFAULT_NUM_WITNESSES; - vector initial_witness_candidates; - // These are only candidates; the chain will have no active committee members at genesis - vector initial_committee_candidates; - vector initial_worker_candidates; + time_point_sec initial_timestamp; + chain_parameters initial_parameters; + vector initial_accounts; + vector initial_assets; + vector initial_balances; + vector initial_vesting_balances; + int initial_active_witnesses = GRAPHENE_DEFAULT_NUM_WITNESSES; + vector initial_witness_candidates; + vector initial_committee_candidates; + vector initial_worker_candidates; }; } } // namespace graphene::chain diff --git a/libraries/chain/include/graphene/chain/types.hpp b/libraries/chain/include/graphene/chain/types.hpp index 9c7fcbef..cd9a9d2f 100644 --- a/libraries/chain/include/graphene/chain/types.hpp +++ b/libraries/chain/include/graphene/chain/types.hpp @@ -448,7 +448,7 @@ namespace graphene { namespace chain { fee_schedule_type current_fees; ///< current schedule of fees uint8_t block_interval = GRAPHENE_DEFAULT_BLOCK_INTERVAL; ///< interval in seconds between blocks uint32_t maintenance_interval = GRAPHENE_DEFAULT_MAINTENANCE_INTERVAL; ///< interval in sections between blockchain maintenance events - uint32_t genesis_proposal_review_period = GRAPHENE_DEFAULT_GENESIS_PROPOSAL_REVIEW_PERIOD_SEC; ///< minimum time in seconds that a proposed transaction requiring genesis authority may not be signed, prior to expiration + uint32_t committee_proposal_review_period = GRAPHENE_DEFAULT_COMMITTEE_PROPOSAL_REVIEW_PERIOD_SEC; ///< minimum time in seconds that a proposed transaction requiring committee authority may not be signed, prior to expiration uint32_t maximum_transaction_size = GRAPHENE_DEFAULT_MAX_TRANSACTION_SIZE; ///< maximum allowable size in bytes for a transaction uint32_t maximum_block_size = GRAPHENE_DEFAULT_MAX_BLOCK_SIZE; ///< maximum allowable size in bytes for a block uint32_t maximum_undo_history = GRAPHENE_DEFAULT_MAX_UNDO_HISTORY; ///< maximum number of undo states to keep in RAM @@ -499,8 +499,8 @@ namespace graphene { namespace chain { "Block size limit is too low" ); FC_ASSERT( maximum_time_until_expiration > block_interval, "Maximum transaction expiration time must be greater than a block interval" ); - FC_ASSERT( maximum_proposal_lifetime - genesis_proposal_review_period > block_interval, - "Genesis proposal review period must be less than the maximum proposal lifetime" ); + FC_ASSERT( maximum_proposal_lifetime - committee_proposal_review_period > block_interval, + "Committee proposal review period must be less than the maximum proposal lifetime" ); } }; @@ -615,7 +615,7 @@ FC_REFLECT( graphene::chain::chain_parameters, (current_fees) (block_interval) (maintenance_interval) - (genesis_proposal_review_period) + (committee_proposal_review_period) (maximum_transaction_size) (maximum_block_size) (maximum_undo_history) diff --git a/libraries/chain/operations.cpp b/libraries/chain/operations.cpp index 002f2313..bd9ed86c 100644 --- a/libraries/chain/operations.cpp +++ b/libraries/chain/operations.cpp @@ -457,7 +457,7 @@ proposal_create_operation proposal_create_operation::genesis_proposal(const data auto global_params = db.get_global_properties().parameters; proposal_create_operation op = {account_id_type(), asset(), {}, db.head_block_time() + global_params.maximum_proposal_lifetime, - global_params.genesis_proposal_review_period}; + global_params.committee_proposal_review_period}; op.fee = op.calculate_fee(global_params.current_fees); return op; } @@ -859,11 +859,11 @@ struct required_active_visitor /** for most operations this is just the fee payer */ template - void operator()(const T& o)const - { + void operator()(const T& o)const + { result.insert( o.fee_payer() ); } - void operator()(const account_update_operation& o)const + void operator()(const account_update_operation& o)const { /// if owner authority is required, no active authority is required if( !(o.owner || o.active) ) /// TODO: document why active cannot be updated by active? @@ -906,7 +906,7 @@ struct required_owner_visitor template void operator()(const T& o)const {} - void operator()(const account_update_operation& o)const + void operator()(const account_update_operation& o)const { if( o.owner || o.active ) /// TODO: document why active cannot be updated by active? result.insert( o.account ); diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index 535bf354..7ff90a20 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -42,7 +42,7 @@ void_result proposal_create_evaluator::do_evaluate(const proposal_create_operati } if( auths.find(account_id_type()) != auths.end() ) FC_ASSERT( o.review_period_seconds - && *o.review_period_seconds >= global_parameters.genesis_proposal_review_period ); + && *o.review_period_seconds >= global_parameters.committee_proposal_review_period ); } for( const op_wrapper& op : o.proposed_ops ) diff --git a/tests/intense/block_tests.cpp b/tests/intense/block_tests.cpp index 212267a5..db8209e3 100644 --- a/tests/intense/block_tests.cpp +++ b/tests/intense/block_tests.cpp @@ -72,7 +72,7 @@ BOOST_FIXTURE_TEST_CASE( update_account_keys, database_fixture ) generate_block( skip_flags ); db.modify(db.get_global_properties(), [](global_property_object& p) { - p.parameters.genesis_proposal_review_period = fc::hours(1).to_seconds(); + p.parameters.committee_proposal_review_period = fc::hours(1).to_seconds(); }); transaction tx; diff --git a/tests/tests/authority_tests.cpp b/tests/tests/authority_tests.cpp index d0dc5436..47f9a246 100644 --- a/tests/tests/authority_tests.cpp +++ b/tests/tests/authority_tests.cpp @@ -366,7 +366,7 @@ BOOST_AUTO_TEST_CASE( genesis_authority ) // Signatures are for suckers. db.modify(db.get_global_properties(), [](global_property_object& p) { // Turn the review period WAY down, so it doesn't take long to produce blocks to that point in simulated time. - p.parameters.genesis_proposal_review_period = fc::days(1).to_seconds(); + p.parameters.committee_proposal_review_period = fc::days(1).to_seconds(); }); BOOST_TEST_MESSAGE( "transfering 100000 CORE to nathan, signing with genesis key" ); @@ -378,19 +378,19 @@ BOOST_AUTO_TEST_CASE( genesis_authority ) 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.expiration_time = db.head_block_time() + global_params.committee_proposal_review_period*2; pop.fee_paying_account = nathan.id; trx.operations = {pop}; sign(); // The review period isn't set yet. Make sure it throws. BOOST_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception ); - pop.review_period_seconds = global_params.genesis_proposal_review_period / 2; + pop.review_period_seconds = global_params.committee_proposal_review_period / 2; trx.operations.back() = pop; sign(); // The review period is too short. Make sure it throws. BOOST_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception ); - pop.review_period_seconds = global_params.genesis_proposal_review_period; + pop.review_period_seconds = global_params.committee_proposal_review_period; trx.operations.back() = pop; sign(); proposal_object prop = db.get(PUSH_TX( db, trx ).operation_results.front().get()); @@ -405,7 +405,7 @@ BOOST_AUTO_TEST_CASE( genesis_authority ) generate_block(); BOOST_REQUIRE(db.find_object(prop.id)); BOOST_CHECK_EQUAL(get_balance(nathan, asset_id_type()(db)), 0); - + BOOST_TEST_MESSAGE( "Checking that the proposal is not authorized to execute" ); BOOST_REQUIRE(!db.get(prop.id).is_authorized_to_execute(db)); trx.operations.clear(); @@ -456,7 +456,7 @@ BOOST_FIXTURE_TEST_CASE( fired_delegates, database_fixture ) db.modify(db.get_global_properties(), [](global_property_object& p) { // Turn the review period WAY down, so it doesn't take long to produce blocks to that point in simulated time. - p.parameters.genesis_proposal_review_period = fc::days(1).to_seconds(); + p.parameters.committee_proposal_review_period = fc::days(1).to_seconds(); }); for( int i = 0; i < 15; ++i ) @@ -840,7 +840,7 @@ BOOST_FIXTURE_TEST_CASE( max_authority_membership, database_fixture ) generate_block(); db.modify(db.get_global_properties(), [](global_property_object& p) { - p.parameters.genesis_proposal_review_period = fc::hours(1).to_seconds(); + p.parameters.committee_proposal_review_period = fc::hours(1).to_seconds(); }); transaction tx; diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 43a72e89..ce3a5655 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -622,7 +622,7 @@ BOOST_FIXTURE_TEST_CASE( change_block_interval, database_fixture ) generate_block(); db.modify(db.get_global_properties(), [](global_property_object& p) { - p.parameters.genesis_proposal_review_period = fc::hours(1).to_seconds(); + p.parameters.committee_proposal_review_period = fc::hours(1).to_seconds(); }); { @@ -829,7 +829,7 @@ BOOST_FIXTURE_TEST_CASE( pop_block_twice, database_fixture ) generate_block( skip_flags ); db.modify(db.get_global_properties(), [](global_property_object& p) { - p.parameters.genesis_proposal_review_period = fc::hours(1).to_seconds(); + p.parameters.committee_proposal_review_period = fc::hours(1).to_seconds(); }); transaction tx; From 9b5bd12c67771a779e0042a67ff632e7e3ee4fbc Mon Sep 17 00:00:00 2001 From: Vikram Rajkumar Date: Tue, 7 Jul 2015 15:37:31 -0400 Subject: [PATCH 05/28] Add genesis_state_type::initial_timestamp; #17 --- libraries/chain/db_init.cpp | 7 +++++-- libraries/chain/db_witness_schedule.cpp | 3 --- .../chain/include/graphene/chain/config.hpp | 1 - .../include/graphene/chain/genesis_state.hpp | 2 +- tests/app/main.cpp | 3 ++- tests/common/database_fixture.cpp | 2 ++ tests/common/database_fixture.hpp | 4 ++-- tests/tests/block_tests.cpp | 19 +++++++++++-------- 8 files changed, 23 insertions(+), 18 deletions(-) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 03f24086..93be6dc9 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -138,6 +138,9 @@ void database::initialize_indexes() void database::init_genesis(const genesis_state_type& genesis_state) { try { + FC_ASSERT( genesis_state.initial_timestamp != time_point_sec(), "Must initialize genesis timestamp." ); + FC_ASSERT( genesis_state.initial_timestamp.sec_since_epoch() % GRAPHENE_DEFAULT_BLOCK_INTERVAL == 0, + "Genesis timestamp must be divisible by GRAPHENE_DEFAULT_BLOCK_INTERVAL." ); FC_ASSERT(genesis_state.initial_witness_candidates.size() > 0, "Cannot start a chain with zero witnesses."); FC_ASSERT(genesis_state.initial_active_witnesses <= genesis_state.initial_witness_candidates.size(), @@ -246,7 +249,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) }); create( [&](dynamic_global_property_object& p) { - p.time = fc::time_point_sec(GRAPHENE_GENESIS_TIMESTAMP); + p.time = genesis_state.initial_timestamp; p.witness_budget = 0; }); create([&](block_summary_object&) {}); @@ -426,7 +429,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) { worker_create_operation op; op.owner = get_account_id( worker.owner_name ); - op.work_begin_date = time_point_sec( GRAPHENE_GENESIS_TIMESTAMP ); + op.work_begin_date = genesis_state.initial_timestamp; op.work_end_date = time_point_sec::maximum(); op.daily_pay = worker.daily_pay; op.name = "Genesis-Worker-" + worker.owner_name; diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index a6d82bf6..98ce95dd 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -23,9 +23,6 @@ namespace graphene { namespace chain { -static_assert((GRAPHENE_GENESIS_TIMESTAMP % GRAPHENE_DEFAULT_BLOCK_INTERVAL) == 0, - "GRAPHENE_GENESIS_TIMESTAMP must be aligned to a block interval."); - pair database::get_scheduled_witness(uint32_t slot_num)const { if( slot_num == 0 ) diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 33ae226c..aaa40b18 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -100,7 +100,6 @@ #define GRAPHENE_DEFAULT_FEE_LIQUIDATION_THRESHOLD GRAPHENE_BLOCKCHAIN_PRECISION * 100; #define GRAPHENE_DEFAULT_ACCOUNTS_PER_FEE_SCALE 1000 #define GRAPHENE_DEFAULT_ACCOUNT_FEE_SCALE_BITSHIFTS 4 -#define GRAPHENE_GENESIS_TIMESTAMP (1431700000) /// Should be divisible by GRAPHENE_DEFAULT_BLOCK_INTERVAL #define GRAPHENE_MAX_WORKER_NAME_LENGTH 63 diff --git a/libraries/chain/include/graphene/chain/genesis_state.hpp b/libraries/chain/include/graphene/chain/genesis_state.hpp index 16d95d59..2721fa95 100644 --- a/libraries/chain/include/graphene/chain/genesis_state.hpp +++ b/libraries/chain/include/graphene/chain/genesis_state.hpp @@ -124,6 +124,6 @@ FC_REFLECT(graphene::chain::genesis_state_type::initial_committee_member_type, ( FC_REFLECT(graphene::chain::genesis_state_type::initial_worker_type, (owner_name)(daily_pay)) FC_REFLECT(graphene::chain::genesis_state_type, - (initial_parameters)(initial_accounts)(initial_assets)(initial_balances) + (initial_timestamp)(initial_parameters)(initial_accounts)(initial_assets)(initial_balances) (initial_vesting_balances)(initial_active_witnesses)(initial_witness_candidates) (initial_committee_candidates)(initial_worker_candidates)) diff --git a/tests/app/main.cpp b/tests/app/main.cpp index c1d00537..086b0ba7 100644 --- a/tests/app/main.cpp +++ b/tests/app/main.cpp @@ -40,7 +40,8 @@ BOOST_AUTO_TEST_CASE( two_node_network ) fc::temp_directory app2_dir; fc::temp_file genesis_json; - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + // TODO: Time should be read from the blockchain + fc::time_point_sec now( 1431700000 ); graphene::app::application app1; app1.register_plugin(); diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 9e9579c6..72ccccfe 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -60,6 +60,8 @@ database_fixture::database_fixture() mhplugin->plugin_set_app(&app); mhplugin->plugin_initialize(options); + genesis_state.initial_timestamp = time_point_sec( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); + genesis_state.initial_active_witnesses = 10; for( int i = 0; i < genesis_state.initial_active_witnesses; ++i ) { diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 75f6c5fb..834f9ee0 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -23,6 +23,8 @@ using namespace graphene::db; +#define GRAPHENE_TESTING_GENESIS_TIMESTAMP (1431700000) + #define PUSH_TX \ graphene::chain::test::_push_transaction @@ -102,8 +104,6 @@ struct database_fixture { fc::ecc::private_key delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); public_key_type delegate_pub_key; - fc::time_point_sec genesis_time = fc::time_point_sec( GRAPHENE_GENESIS_TIMESTAMP ); - fc::time_point_sec now = fc::time_point_sec( GRAPHENE_GENESIS_TIMESTAMP ); optional data_dir; bool skip_key_index_test = false; uint32_t anon_acct_count; diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index ce3a5655..4c793ea6 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -36,6 +36,9 @@ using namespace graphene::chain; genesis_state_type make_genesis() { genesis_state_type genesis_state; + + genesis_state.initial_timestamp = time_point_sec( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); + auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key"))); genesis_state.initial_active_witnesses = 10; for( int i = 0; i < genesis_state.initial_active_witnesses; ++i ) @@ -117,7 +120,7 @@ BOOST_AUTO_TEST_CASE( block_database_test ) BOOST_AUTO_TEST_CASE( generate_empty_blocks ) { try { - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); fc::temp_directory data_dir; signed_block b; @@ -169,7 +172,7 @@ BOOST_AUTO_TEST_CASE( undo_block ) { database db; db.open(data_dir.path(), make_genesis() ); - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); for( uint32_t i = 0; i < 5; ++i ) @@ -205,7 +208,7 @@ BOOST_AUTO_TEST_CASE( fork_blocks ) try { fc::temp_directory data_dir1; fc::temp_directory data_dir2; - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); database db1; db1.open(data_dir1.path(), make_genesis()); @@ -269,7 +272,7 @@ BOOST_AUTO_TEST_CASE( fork_blocks ) BOOST_AUTO_TEST_CASE( undo_pending ) { try { - fc::time_point_sec now(GRAPHENE_GENESIS_TIMESTAMP); + fc::time_point_sec now(GRAPHENE_TESTING_GENESIS_TIMESTAMP); fc::temp_directory data_dir; { database db; @@ -334,7 +337,7 @@ BOOST_AUTO_TEST_CASE( switch_forks_undo_create ) db1.open(dir1.path(), make_genesis()); db2.open(dir2.path(), make_genesis()); - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); public_key_type delegate_pub_key = delegate_priv_key.get_public_key(); const graphene::db::index& account_idx = db1.get_index(protocol_ids, account_object_type); @@ -355,7 +358,7 @@ BOOST_AUTO_TEST_CASE( switch_forks_undo_create ) BOOST_CHECK(nathan_id(db1).name == "nathan"); - now = fc::time_point_sec( GRAPHENE_GENESIS_TIMESTAMP ); + now = fc::time_point_sec( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); now += db2.block_interval(); b = db2.generate_block(now, db2.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); db1.push_block(b); @@ -384,7 +387,7 @@ BOOST_AUTO_TEST_CASE( switch_forks_undo_create ) BOOST_AUTO_TEST_CASE( duplicate_transactions ) { try { - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); fc::temp_directory dir1, dir2; database db1, @@ -433,7 +436,7 @@ BOOST_AUTO_TEST_CASE( duplicate_transactions ) BOOST_AUTO_TEST_CASE( tapos ) { try { - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); fc::temp_directory dir1, dir2; database db1, From 1dd7316d44ada0283d199f421cbcbc59e6dc1775 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Mon, 6 Jul 2015 14:36:06 -0400 Subject: [PATCH 06/28] Split network API into network_broadcast_api and network_node_api #118 --- libraries/app/api.cpp | 42 +++++++---- libraries/app/include/graphene/app/api.hpp | 84 ++++++++++++++++------ libraries/wallet/wallet.cpp | 12 ++-- 3 files changed, 94 insertions(+), 44 deletions(-) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index c72af05b..bf71f665 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -350,20 +350,22 @@ namespace graphene { namespace app { bool login_api::login(const string& user, const string& password) { auto db_api = std::make_shared(std::ref(*_app.chain_database())); - auto net_api = std::make_shared(std::ref(_app)); + auto net_broadcast_api = std::make_shared(std::ref(_app)); auto hist_api = std::make_shared(_app); + auto net_node_api = std::make_shared(std::ref(_app)); _database_api = db_api; - _network_api = net_api; + _network_broadcast_api = net_broadcast_api; _history_api = hist_api; + _network_node_api = net_node_api; return true; } - network_api::network_api(application& a):_app(a) + network_broadcast_api::network_broadcast_api(application& a):_app(a) { _applied_block_connection = _app.chain_database()->applied_block.connect([this](const signed_block& b){ on_applied_block(b); }); } - void network_api::on_applied_block( const signed_block& b ) + void network_broadcast_api::on_applied_block( const signed_block& b ) { if( _callbacks.size() ) { @@ -381,18 +383,14 @@ namespace graphene { namespace app { } } - void network_api::add_node(const fc::ip::endpoint& ep) - { - _app.p2p_node()->add_node(ep); - } - - void network_api::broadcast_transaction(const signed_transaction& trx) + void network_broadcast_api::broadcast_transaction(const signed_transaction& trx) { trx.validate(); _app.chain_database()->push_transaction(trx); _app.p2p_node()->broadcast_transaction(trx); } - void network_api::broadcast_transaction_with_callback( confirmation_callback cb, const signed_transaction& trx) + + void network_broadcast_api::broadcast_transaction_with_callback( confirmation_callback cb, const signed_transaction& trx) { trx.validate(); _callbacks[trx.id()] = cb; @@ -400,16 +398,30 @@ namespace graphene { namespace app { _app.p2p_node()->broadcast_transaction(trx); } + network_node_api::network_node_api( application& a ) : _app( a ) + { + } - std::vector network_api::get_connected_peers() const + void network_node_api::add_node(const fc::ip::endpoint& ep) + { + _app.p2p_node()->add_node(ep); + } + + std::vector network_node_api::get_connected_peers() const { return _app.p2p_node()->get_connected_peers(); } - fc::api login_api::network()const + fc::api login_api::network_broadcast()const { - FC_ASSERT(_network_api); - return *_network_api; + FC_ASSERT(_network_broadcast_api); + return *_network_broadcast_api; + } + + fc::api login_api::network_node()const + { + FC_ASSERT(_network_node_api); + return *_network_node_api; } fc::api login_api::database()const diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index 3f8ecb7f..d57eb2d1 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -45,7 +45,7 @@ namespace graphene { namespace app { * * This API exposes accessors on the database which query state tracked by a blockchain validating node. This API is * read-only; all modifications to the database must be performed via transactions. Transactions are broadcast via - * the @ref network_api. + * the @ref network_broadcast_api. */ class database_api { @@ -332,14 +332,12 @@ namespace graphene { namespace app { }; /** - * @brief The network_api class implements the RPC API for the network - * - * This API has methods to query the network status, connect to new peers, and send transactions. + * @brief The network_broadcast_api class allows broadcasting of transactions. */ - class network_api + class network_broadcast_api { public: - network_api(application& a); + network_broadcast_api(application& a); struct transaction_confirmation { @@ -367,15 +365,13 @@ namespace graphene { namespace app { void broadcast_transaction_with_callback( confirmation_callback cb, const signed_transaction& trx); /** - * @brief add_node Connect to a new peer - * @param ep The IP/Port of the peer to connect to + * @brief Not reflected, thus not accessible to API clients. + * + * This function is registered to receive the applied_block + * signal from the chain database when a block is received. + * It then dispatches callbacks to clients who have requested + * to be notified when a particular txid is included in a block. */ - void add_node(const fc::ip::endpoint& ep); - /** - * @brief Get status of all current connections to peers - */ - std::vector get_connected_peers() const; - void on_applied_block( const signed_block& b ); private: boost::signals2::scoped_connection _applied_block_connection; @@ -383,6 +379,35 @@ namespace graphene { namespace app { application& _app; }; + /** + * @brief The network_node_api class allows maintenance of p2p connections. + */ + class network_node_api + { + public: + network_node_api(application& a); + + /** + * @brief add_node Connect to a new peer + * @param ep The IP/Port of the peer to connect to + */ + void add_node(const fc::ip::endpoint& ep); + + /** + * @brief Get status of all current connections to peers + * @brief Not reflected, thus not accessible to API clients. + * + * This function is registered to receive the applied_block + * signal from the chain database when a block is received. + * It then dispatches callbacks to clients who have requested + * to be notified when a particular txid is included in a block. + */ + std::vector get_connected_peers() const; + + private: + application& _app; + }; + /** * @brief The login_api class implements the bottom layer of the RPC API * @@ -404,23 +429,26 @@ namespace graphene { namespace app { * has sucessfully authenticated. */ bool login(const string& user, const string& password); - /// @brief Retrieve the network API - fc::api network()const; + /// @brief Retrieve the network broadcast API + fc::api network_broadcast()const; /// @brief Retrieve the database API fc::api database()const; /// @brief Retrieve the history API fc::api history()const; + /// @brief Retrieve the network node API + fc::api network_node()const; private: application& _app; optional< fc::api > _database_api; - optional< fc::api > _network_api; + optional< fc::api > _network_broadcast_api; + optional< fc::api > _network_node_api; optional< fc::api > _history_api; }; }} // graphene::app -FC_REFLECT( graphene::app::network_api::transaction_confirmation, +FC_REFLECT( graphene::app::network_broadcast_api::transaction_confirmation, (id)(block_num)(trx_num)(trx) ) FC_API(graphene::app::database_api, @@ -461,13 +489,23 @@ FC_API(graphene::app::database_api, (get_margin_positions) (get_balance_objects) ) -FC_API(graphene::app::history_api, (get_account_history)(get_market_history)(get_market_history_buckets)) -FC_API(graphene::app::network_api, (broadcast_transaction)(broadcast_transaction_with_callback) - /* (add_node)(get_connected_peers) */ - ) +FC_API(graphene::app::history_api, + (get_account_history) + (get_market_history) + (get_market_history_buckets) + ) +FC_API(graphene::app::network_broadcast_api, + (broadcast_transaction) + (broadcast_transaction_with_callback) + ) +FC_API(graphene::app::network_node_api, + (add_node) + (get_connected_peers) + ) FC_API(graphene::app::login_api, (login) - (network) + (network_broadcast) (database) (history) + (network_node) ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index ec50756b..2b36a086 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -301,7 +301,7 @@ public: : self(s), _remote_api(rapi), _remote_db(rapi->database()), - _remote_net(rapi->network()), + _remote_net_broadcast(rapi->network_broadcast()), _remote_hist(rapi->history()) { _remote_db->subscribe_to_objects( [=]( const fc::variant& obj ) @@ -737,7 +737,7 @@ public: } if( broadcast ) - _remote_net->broadcast_transaction( tx ); + _remote_net_broadcast->broadcast_transaction( tx ); return tx; } FC_CAPTURE_AND_RETHROW( (name)(owner)(active)(registrar_account)(referrer_account)(referrer_percent)(broadcast) ) } @@ -863,7 +863,7 @@ public: if( save_wallet ) save_wallet_file(); if( broadcast ) - _remote_net->broadcast_transaction( tx ); + _remote_net_broadcast->broadcast_transaction( tx ); return tx; } FC_CAPTURE_AND_RETHROW( (account_name)(registrar_account)(referrer_account)(broadcast) ) } @@ -1446,7 +1446,7 @@ public: } if( broadcast ) - _remote_net->broadcast_transaction( tx ); + _remote_net_broadcast->broadcast_transaction( tx ); return tx; } @@ -1691,7 +1691,7 @@ public: fc::api _remote_api; fc::api _remote_db; - fc::api _remote_net; + fc::api _remote_net_broadcast; fc::api _remote_hist; #ifdef __unix__ @@ -2436,7 +2436,7 @@ signed_transaction wallet_api::import_balance( string name_or_id, const vector(boost::sort(tx.signatures))); if( broadcast ) - my->_remote_net->broadcast_transaction(tx); + my->_remote_net_broadcast->broadcast_transaction(tx); return tx; } FC_CAPTURE_AND_RETHROW( (name_or_id) ) } From d31e0108b43df7c447b68114fc58e5238a7f27e4 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 7 Jul 2015 14:03:55 -0400 Subject: [PATCH 07/28] app: Implement username / password based API access #139 --- libraries/app/api.cpp | 47 ++++++++++++++--- libraries/app/application.cpp | 40 ++++++++++++++- libraries/app/include/graphene/app/api.hpp | 4 +- .../app/include/graphene/app/api_access.hpp | 50 +++++++++++++++++++ .../app/include/graphene/app/application.hpp | 2 + 5 files changed, 133 insertions(+), 10 deletions(-) create mode 100644 libraries/app/include/graphene/app/api_access.hpp diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index bf71f665..e32115d7 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -16,6 +16,7 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +#include #include #include #include @@ -349,17 +350,47 @@ namespace graphene { namespace app { bool login_api::login(const string& user, const string& password) { - auto db_api = std::make_shared(std::ref(*_app.chain_database())); - auto net_broadcast_api = std::make_shared(std::ref(_app)); - auto hist_api = std::make_shared(_app); - auto net_node_api = std::make_shared(std::ref(_app)); - _database_api = db_api; - _network_broadcast_api = net_broadcast_api; - _history_api = hist_api; - _network_node_api = net_node_api; + optional< api_access_info > acc = _app.get_api_access_info( user ); + if( !acc.valid() ) + return false; + if( acc->password_hash_b64 != "*" ) + { + std::string password_salt = fc::base64_decode( acc->password_salt_b64 ); + std::string acc_password_hash = fc::base64_decode( acc->password_hash_b64 ); + + fc::sha256 hash_obj = fc::sha256::hash( password + password_salt ); + if( hash_obj.data_size() != acc_password_hash.length() ) + return false; + if( memcmp( hash_obj.data(), acc_password_hash.c_str(), hash_obj.data_size() ) != 0 ) + return false; + } + + for( const std::string& api_name : acc->allowed_apis ) + enable_api( api_name ); return true; } + void login_api::enable_api( const std::string& api_name ) + { + if( api_name == "database_api" ) + { + _database_api = std::make_shared< database_api >( std::ref( *_app.chain_database() ) ); + } + else if( api_name == "network_broadcast_api" ) + { + _network_broadcast_api = std::make_shared< network_broadcast_api >( std::ref( _app ) ); + } + else if( api_name == "history_api" ) + { + _history_api = std::make_shared< history_api >( _app ); + } + else if( api_name == "network_node_api" ) + { + _network_node_api = std::make_shared< network_node_api >( std::ref(_app) ); + } + return; + } + network_broadcast_api::network_broadcast_api(application& a):_app(a) { _applied_block_connection = _app.chain_database()->applied_block.connect([this](const signed_block& b){ on_applied_block(b); }); diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 1a9a932c..e92ca5a2 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -15,9 +15,10 @@ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include +#include #include #include -#include #include @@ -200,11 +201,41 @@ namespace detail { _chain_db->reindex(_data_dir / "blockchain", initial_state); } + if( _options->count("apiaccess") ) + _apiaccess = fc::json::from_file( _options->at("apiaccess").as() ) + .as(); + else + { + // TODO: Remove this generous default access policy + // when the UI logs in properly + _apiaccess = api_access(); + api_access_info wild_access; + wild_access.password_hash_b64 = "*"; + wild_access.password_salt_b64 = "*"; + wild_access.allowed_apis.push_back( "database_api" ); + wild_access.allowed_apis.push_back( "network_broadcast_api" ); + wild_access.allowed_apis.push_back( "history_api" ); + _apiaccess.permission_map["*"] = wild_access; + } + reset_p2p_node(_data_dir); reset_websocket_server(); reset_websocket_tls_server(); } FC_CAPTURE_AND_RETHROW() } + optional< api_access_info > get_api_access_info( const string& username )const + { + optional< api_access_info > result; + auto it = _apiaccess.permission_map.find( username ); + if( it == _apiaccess.permission_map.end() ) + { + it = _apiaccess.permission_map.find( "*" ); + if( it == _apiaccess.permission_map.end() ) + return result; + } + return it->second; + } + /** * If delegate has the item, the network has no need to fetch it. */ @@ -410,6 +441,7 @@ namespace detail { fc::path _data_dir; const bpo::variables_map* _options = nullptr; + api_access _apiaccess; std::shared_ptr _chain_db; std::shared_ptr _p2p_network; @@ -449,6 +481,7 @@ void application::set_program_options(boost::program_options::options_descriptio ("server-pem,p", bpo::value()->implicit_value("server.pem"), "The TLS certificate file for this server") ("server-pem-password,P", bpo::value()->implicit_value(""), "Password for this certificate") ("genesis-json", bpo::value(), "File to read Genesis State from") + ("apiaccess", bpo::value(), "JSON file specifying API permissions") ; command_line_options.add(configuration_file_options); command_line_options.add_options() @@ -519,6 +552,11 @@ void application::set_block_production(bool producing_blocks) my->_is_block_producer = producing_blocks; } +optional< api_access_info > application::get_api_access_info( const string& username )const +{ + return my->get_api_access_info( username ); +} + void graphene::app::application::add_plugin(const string& name, std::shared_ptr p) { my->_plugins[name] = p; diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index d57eb2d1..531dadb1 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -29,7 +29,6 @@ #include #include - #include #include @@ -439,6 +438,9 @@ namespace graphene { namespace app { fc::api network_node()const; private: + /// @brief Called to enable an API, not reflected. + void enable_api( const string& api_name ); + application& _app; optional< fc::api > _database_api; optional< fc::api > _network_broadcast_api; diff --git a/libraries/app/include/graphene/app/api_access.hpp b/libraries/app/include/graphene/app/api_access.hpp new file mode 100644 index 00000000..b6f4e2f3 --- /dev/null +++ b/libraries/app/include/graphene/app/api_access.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, Cryptonomex, Inc. + * All rights reserved. + * + * This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and + * the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification, + * are permitted until September 8, 2015, provided that the following conditions are met: + * + * 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#pragma once + +#include + +#include +#include +#include + +namespace graphene { namespace app { + +struct api_access_info +{ + std::string password_hash_b64; + std::string password_salt_b64; + std::vector< std::string > allowed_apis; +}; + +struct api_access +{ + std::map< std::string, api_access_info > permission_map; +}; + +} } // graphene::app + +FC_REFLECT( graphene::app::api_access_info, + (password_hash_b64) + (password_salt_b64) + (allowed_apis) + ) + +FC_REFLECT( graphene::app::api_access, + (permission_map) + ) diff --git a/libraries/app/include/graphene/app/application.hpp b/libraries/app/include/graphene/app/application.hpp index f7ee1450..4eccc980 100644 --- a/libraries/app/include/graphene/app/application.hpp +++ b/libraries/app/include/graphene/app/application.hpp @@ -17,6 +17,7 @@ */ #pragma once +#include #include #include @@ -74,6 +75,7 @@ namespace graphene { namespace app { std::shared_ptr chain_database()const; void set_block_production(bool producing_blocks); + fc::optional< api_access_info > get_api_access_info( const string& username )const; private: void add_plugin( const string& name, std::shared_ptr p ); From ad7d0841c22ef6c3fbfb2be34bd8f6aec526f247 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 7 Jul 2015 15:57:29 -0400 Subject: [PATCH 08/28] saltpass.py: Implement simple salted hash script --- .gitignore | 3 +++ programs/witness_node/saltpass.py | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100755 programs/witness_node/saltpass.py diff --git a/.gitignore b/.gitignore index 5cdb0935..c4d159d2 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ witness_node_data_dir programs/witness_node/object_database/* object_database/* + +*.pyc +*.pyo diff --git a/programs/witness_node/saltpass.py b/programs/witness_node/saltpass.py new file mode 100755 index 00000000..6562fc23 --- /dev/null +++ b/programs/witness_node/saltpass.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 + +import base64 +import getpass +import hashlib +import json +import os + +pw = getpass.getpass("enter your password: ") +pw_bytes = pw.encode("utf-8") +salt_bytes = os.urandom(8) +salt_b64 = base64.b64encode( salt_bytes ) +pw_hash = hashlib.sha256( pw_bytes + salt_bytes ).digest() +pw_hash_b64 = base64.b64encode( pw_hash ) + +print(json.dumps( +{ + "password_hash_b64" : pw_hash_b64.decode("ascii"), + "password_salt_b64" : salt_b64.decode("ascii"), +}, +sort_keys=True, +indent=3, separators=(',', ' : ') +)) From 8f25a3fee966217993b825f9c3679d5ad376217f Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 7 Jul 2015 15:57:48 -0400 Subject: [PATCH 09/28] README.md: Document login API changes --- README.md | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7e06a971..4c72ebcc 100644 --- a/README.md +++ b/README.md @@ -118,15 +118,38 @@ API 0 is accessible using regular JSON-RPC: $ curl --data '{"jsonrpc": "2.0", "method": "get_accounts", "params": [["1.2.0"]], "id": 1}' http://127.0.0.1:8090/rpc -You can use the login API to obtain `network`, `database` and `history` API's. Here is an example of how to call `add_node` from the `network` API: +Accessing restricted API's +-------------------------- + +You can restrict API's to particular users by specifying an `apiaccess` file in `config.ini`. Here is an example `apiaccess` file which allows +user `bytemaster` with password `supersecret` to access four different API's: + + { + "permission_map" : + [ + [ + "bytemaster", + { + "password_hash_b64" : "9e9GF7ooXVb9k4BoSfNIPTelXeGOZ5DrgOYMj94elaY=", + "password_salt_b64" : "INDdM6iCi/8=", + "allowed_apis" : ["database_api", "network_broadcast_api", "history_api", "network_node_api"] + } + ] + ] + } + +Passwords are stored in `base64` as as salted `sha256` hashes. A simple Python script, `saltpass.py` is avaliable to obtain hash and salt values from a password. +A single asterisk `"*"` may be specified as username or password hash to accept any value. + +With the above configuration, here is an example of how to call `add_node` from the `network_node` API: {"id":1, "method":"call", "params":[1,"login",["bytemaster", "supersecret"]]} - {"id":2, "method":"call", "params":[1,"network",[]]} + {"id":2, "method":"call", "params":[1,"network_node",[]]} {"id":3, "method":"call", "params":[2,"add_node",["127.0.0.1:9090"]]} -Note, the call to `network` is necessary to obtain the correct API identifier for the network API. It is not guaranteed that the network API identifier will always be `2`. +Note, the call to `network_node` is necessary to obtain the correct API identifier for the network API. It is not guaranteed that the network API identifier will always be `2`. -Since the `network` API requires login, it is only accessible over the websocket RPC. Our `doxygen` documentation contains the most up-to-date information +Since the `network_node` API requires login, it is only accessible over the websocket RPC. Our `doxygen` documentation contains the most up-to-date information about API's for the [witness node](https://bitshares.github.io/doxygen/namespacegraphene_1_1app.html) and the [wallet](https://bitshares.github.io/doxygen/classgraphene_1_1wallet_1_1wallet__api.html). If you want information which is not available from an API, it might be available From 3d60449c6ec4bfda4851b089ef5d8988255bf2e6 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Tue, 7 Jul 2015 17:39:38 -0400 Subject: [PATCH 10/28] Progress #8: Test shorts and force settles --- libraries/chain/asset_evaluator.cpp | 3 +++ libraries/chain/call_order_evaluator.cpp | 5 +++-- .../chain/include/graphene/chain/database.hpp | 2 +- tests/common/database_fixture.hpp | 14 ++++++++++++-- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index 60255490..fcf1c23e 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -394,6 +395,8 @@ void_result asset_settle_evaluator::do_evaluate(const asset_settle_evaluator::op FC_ASSERT(asset_to_settle->can_force_settle() || bitasset.has_settlement() ); if( bitasset.is_prediction_market ) FC_ASSERT( bitasset.has_settlement(), "global settlement must occur before force settling a prediction market" ); + else if( bitasset.current_feed.settlement_price.is_null() ) + FC_THROW_EXCEPTION(insufficient_feeds, "Cannot force settle with no price feed."); FC_ASSERT(d.get_balance(d.get(op.account), *asset_to_settle) >= op.amount); return void_result(); diff --git a/libraries/chain/call_order_evaluator.cpp b/libraries/chain/call_order_evaluator.cpp index 379e2287..3db43f42 100644 --- a/libraries/chain/call_order_evaluator.cpp +++ b/libraries/chain/call_order_evaluator.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include namespace graphene { namespace chain { @@ -43,8 +44,8 @@ void_result call_order_update_evaluator::do_evaluate(const call_order_update_ope if( _bitasset_data->is_prediction_market ) FC_ASSERT( o.delta_collateral.amount == o.delta_debt.amount ); - else - FC_ASSERT( !_bitasset_data->current_feed.settlement_price.is_null() ); + else if( _bitasset_data->current_feed.settlement_price.is_null() ) + FC_THROW_EXCEPTION(insufficient_feeds, "Cannot borrow asset with no price feed."); if( o.delta_debt.amount < 0 ) { diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 7de14fbd..0f06eb89 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -69,7 +69,7 @@ namespace graphene { namespace chain { * @class database * @brief tracks the blockchain state in an extensible manner */ - class database : public object_database + class database : public db::object_database { public: //////////////////// db_management.cpp //////////////////// diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 834f9ee0..449f3fd4 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -73,7 +73,7 @@ using namespace graphene::db; #define INVOKE(test) ((struct test*)this)->test_method(); trx.clear() #define PREP_ACTOR(name) \ - fc::ecc::private_key name ## _private_key = generate_private_key(BOOST_PP_STRINGIZE(name)); + fc::ecc::private_key name ## _private_key = generate_private_key(BOOST_PP_STRINGIZE(name)); #define ACTOR(name) \ PREP_ACTOR(name) \ @@ -146,10 +146,20 @@ struct database_fixture { ); void force_global_settle(const asset_object& what, const price& p); + void force_settle(account_id_type who, asset what) + { force_settle(who(db), what); } void force_settle(const account_object& who, asset what); + void update_feed_producers(asset_id_type mia, flat_set producers) + { update_feed_producers(mia(db), producers); } void update_feed_producers(const asset_object& mia, flat_set producers); + void publish_feed(asset_id_type mia, account_id_type by, const price_feed& f) + { publish_feed(mia(db), by(db), f); } void publish_feed(const asset_object& mia, const account_object& by, const price_feed& f); + void borrow(account_id_type who, asset what, asset collateral) + { borrow(who(db), what, collateral); } void borrow(const account_object& who, asset what, asset collateral); + void cover(account_id_type who, asset what, asset collateral_freed) + { cover(who(db), what, collateral_freed); } void cover(const account_object& who, asset what, asset collateral_freed); const asset_object& get_asset( const string& symbol )const; @@ -163,7 +173,7 @@ struct database_fixture { uint16_t market_fee_percent = 100 /*1%*/, uint16_t flags = charge_market_fee); const asset_object& create_user_issued_asset( const string& name ); - const asset_object& create_user_issued_asset( const string& name, + const asset_object& create_user_issued_asset( const string& name, const account_object& issuer, uint16_t flags ); void issue_uia( const account_object& recipient, asset amount ); From ed3848815506533307780ce7125c110088367549 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Tue, 7 Jul 2015 19:35:33 -0400 Subject: [PATCH 11/28] Fix witness_node --- libraries/app/application.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index e92ca5a2..8fbebb5e 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -61,6 +61,9 @@ namespace detail { genesis_state_type initial_state; initial_state.initial_parameters.current_fees.set_all_fees(GRAPHENE_BLOCKCHAIN_PRECISION); initial_state.initial_active_witnesses = 10; + initial_state.initial_timestamp = time_point_sec(time_point::now().sec_since_epoch() / + initial_state.initial_parameters.block_interval * + initial_state.initial_parameters.block_interval); for( int i = 0; i < initial_state.initial_active_witnesses; ++i ) { auto name = "init"+fc::to_string(i); From 7bb608a30560ae13f5dc5ef503a44eed0d20a979 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 7 Jul 2015 22:22:21 -0400 Subject: [PATCH 12/28] types.hpp: Remove parameter_extension as it breaks js_operation_serializer --- libraries/chain/include/graphene/chain/types.hpp | 4 ---- programs/js_operation_serializer/main.cpp | 1 - 2 files changed, 5 deletions(-) diff --git a/libraries/chain/include/graphene/chain/types.hpp b/libraries/chain/include/graphene/chain/types.hpp index cd9a9d2f..e5f71593 100644 --- a/libraries/chain/include/graphene/chain/types.hpp +++ b/libraries/chain/include/graphene/chain/types.hpp @@ -441,8 +441,6 @@ namespace graphene { namespace chain { bool is_valid_v1( const std::string& base58str ); }; - typedef static_variant<> parameter_extension; - struct chain_parameters { fee_schedule_type current_fees; ///< current schedule of fees @@ -475,7 +473,6 @@ namespace graphene { namespace chain { share_type fee_liquidation_threshold = GRAPHENE_DEFAULT_FEE_LIQUIDATION_THRESHOLD; ///< value in CORE at which accumulated fees in blockchain-issued market assets should be liquidated uint16_t accounts_per_fee_scale = GRAPHENE_DEFAULT_ACCOUNTS_PER_FEE_SCALE; ///< number of accounts between fee scalings uint8_t account_fee_scale_bitshifts = GRAPHENE_DEFAULT_ACCOUNT_FEE_SCALE_BITSHIFTS; ///< number of times to left bitshift account registration fee at each scaling - vector extensions; void validate()const { @@ -642,7 +639,6 @@ FC_REFLECT( graphene::chain::chain_parameters, (fee_liquidation_threshold) (accounts_per_fee_scale) (account_fee_scale_bitshifts) - (extensions) ) FC_REFLECT_TYPENAME( graphene::chain::share_type ) diff --git a/programs/js_operation_serializer/main.cpp b/programs/js_operation_serializer/main.cpp index 19751220..0ed4e1e4 100644 --- a/programs/js_operation_serializer/main.cpp +++ b/programs/js_operation_serializer/main.cpp @@ -367,7 +367,6 @@ int main( int argc, char** argv ) detail_ns::js_name>::name("key_data"); detail_ns::js_name::name("operation_result"); detail_ns::js_name::name("header_extension"); - detail_ns::js_name::name("parameter_extension"); detail_ns::js_name>::name("worker_initializer"); detail_ns::js_name>::name("vesting_policy_initializer"); detail_ns::serializer::init(); From e86755673584eeb8804a90524d38a8b5a87699ac Mon Sep 17 00:00:00 2001 From: Eric Frias Date: Wed, 8 Jul 2015 09:26:13 -0400 Subject: [PATCH 13/28] Fix outdated info in README section about using Doxygen docs in CLI wallet help. --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c72ebcc..fd8ed41b 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,15 @@ Questions - Is there a way to generate help with parameter names and method descriptions? Yes. Documentation of the code base, including APIs, can be generated using Doxygen. Simply run `doxygen` in this directory. - We are thinking of integrating Doxygen's XML output format to provide a better `help` command to the CLI wallet. + + If both Doxygen and perl are available in your build environment, the CLI wallet's `help` and `gethelp` + commands will display help generated from the doxygen documentation. + + If your CLI wallet's `help` command displays descriptions without parameter names like + `signed_transaction transfer(string, string, string, string, string, bool)` + it means CMake was unable to find Doxygen or perl during configuration. If found, the + output should look like this: + `signed_transaction transfer(string from, string to, string amount, string asset_symbol, string memo, bool broadcast)` - Is there a way to allow external program to drive `cli_wallet` via websocket, JSONRPC, or HTTP? From a735198ac0a16d6acf3abfbdd473089b1b7e98f1 Mon Sep 17 00:00:00 2001 From: Vikram Rajkumar Date: Wed, 8 Jul 2015 11:32:15 -0400 Subject: [PATCH 14/28] Update submodules --- docs | 2 +- libraries/fc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs b/docs index d0d1fd5b..97435c1a 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit d0d1fd5b5e7eaab29d94b6b0388c5d6673f1a134 +Subproject commit 97435c1a622e41e0a5fc1be72aaadea62e1b7adb diff --git a/libraries/fc b/libraries/fc index 1ce9f4c3..787e4abf 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 1ce9f4c37e6d3b7672ca9cfb152d236085f31f74 +Subproject commit 787e4abf3ff6f1ced9fabc9d30963d8b73137ae7 From 16db253535877a4a666aae9830dd5c4c0e36b626 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 7 Jul 2015 21:48:48 -0400 Subject: [PATCH 15/28] db_fixture.hpp: Implement some macros for exception checking --- tests/common/database_fixture.hpp | 63 +++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 449f3fd4..39ad99f4 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -21,6 +21,8 @@ #include #include +#include + using namespace graphene::db; #define GRAPHENE_TESTING_GENESIS_TIMESTAMP (1431700000) @@ -39,13 +41,6 @@ using namespace graphene::db; op.validate(); \ op.field = temp; \ } -#define REQUIRE_OP_VALIDATION_FAILURE( op, field, value ) \ -{ \ - const auto temp = op.field; \ - op.field = value; \ - BOOST_REQUIRE_THROW( op.validate(), fc::exception ); \ - op.field = temp; \ -} #define REQUIRE_OP_EVALUATION_SUCCESS( op, field, value ) \ { \ const auto temp = op.field; \ @@ -54,17 +49,61 @@ using namespace graphene::db; op.field = temp; \ db.push_transaction( trx, ~0 ); \ } -///Shortcut to require an exception when processing a transaction with an operation containing an expected bad value -/// Uses require insteach of check, because these transactions are expected to fail. If they don't, subsequent tests -/// may spuriously succeed or fail due to unexpected database state. -#define REQUIRE_THROW_WITH_VALUE(op, field, value) \ + +#define GRAPHENE_REQUIRE_THROW( expr, exc_type ) \ +{ \ + std::string req_throw_info = fc::json::to_string( \ + fc::mutable_variant_object() \ + ("source_file", __FILE__) \ + ("source_lineno", __LINE__) \ + ("expr", #expr) \ + ("exc_type", #exc_type) \ + ); \ + std::cout << "GRAPHENE_REQUIRE_THROW begin " \ + << req_throw_info << std::endl; \ + BOOST_REQUIRE_THROW( expr, exc_type ); \ + std::cout << "GRAPHENE_REQUIRE_THROW end " \ + << req_throw_info << std::endl; \ +} + +#define GRAPHENE_CHECK_THROW( expr, exc_type ) \ +{ \ + std::string req_throw_info = fc::json::to_string( \ + fc::mutable_variant_object() \ + ("source_file", __FILE__) \ + ("source_lineno", __LINE__) \ + ("expr", #expr) \ + ("exc_type", #exc_type) \ + ); \ + std::cout << "GRAPHENE_CHECK_THROW begin " \ + << req_throw_info << std::endl; \ + BOOST_CHECK_THROW( expr, exc_type ); \ + std::cout << "GRAPHENE_CHECK_THROW end " \ + << req_throw_info << std::endl; \ +} + +#define REQUIRE_OP_VALIDATION_FAILURE_2( op, field, value, exc_type ) \ +{ \ + const auto temp = op.field; \ + op.field = value; \ + GRAPHENE_REQUIRE_THROW( op.validate(), exc_type ); \ + op.field = temp; \ +} +#define REQUIRE_OP_VALIDATION_FAILURE( op, field, value ) \ + REQUIRE_OP_VALIDATION_FAILURE_2( op, field, value, fc::exception ) + +#define REQUIRE_THROW_WITH_VALUE_2(op, field, value, exc_type) \ { \ auto bak = op.field; \ op.field = value; \ trx.operations.back() = op; \ op.field = bak; \ - BOOST_REQUIRE_THROW(db.push_transaction(trx, ~0), fc::exception); \ + GRAPHENE_REQUIRE_THROW(db.push_transaction(trx, ~0), exc_type); \ } + +#define REQUIRE_THROW_WITH_VALUE( op, field, value ) \ + REQUIRE_THROW_WITH_VALUE_2( op, field, value, fc::exception ) + ///This simply resets v back to its default-constructed value. Requires v to have a working assingment operator and /// default constructor. #define RESET(v) v = decltype(v)() From 4229e335259f1942203287b124f10926e541d3ee Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Wed, 8 Jul 2015 12:28:29 -0400 Subject: [PATCH 16/28] tests: replace BOOST_REQUIRE_THROW / BOOST_CHECK_THROW with GRAPHENE_*_THROW --- tests/intense/block_tests.cpp | 2 +- tests/tests/authority_tests.cpp | 44 ++++++++++++++++---------------- tests/tests/basic_tests.cpp | 2 +- tests/tests/block_tests.cpp | 20 +++++++-------- tests/tests/operation_tests.cpp | 30 +++++++++++----------- tests/tests/operation_tests2.cpp | 22 ++++++++-------- tests/tests/uia_tests.cpp | 24 ++++++++--------- 7 files changed, 72 insertions(+), 72 deletions(-) diff --git a/tests/intense/block_tests.cpp b/tests/intense/block_tests.cpp index db8209e3..1b608037 100644 --- a/tests/intense/block_tests.cpp +++ b/tests/intense/block_tests.cpp @@ -207,7 +207,7 @@ BOOST_FIXTURE_TEST_CASE( update_account_keys, database_fixture ) trx.sign( *owner_privkey[i] ); if( i < int(create_op.owner.weight_threshold-1) ) { - BOOST_REQUIRE_THROW(db.push_transaction(trx), fc::exception); + GRAPHENE_REQUIRE_THROW(db.push_transaction(trx), fc::exception); } else { diff --git a/tests/tests/authority_tests.cpp b/tests/tests/authority_tests.cpp index 47f9a246..32a3bff8 100644 --- a/tests/tests/authority_tests.cpp +++ b/tests/tests/authority_tests.cpp @@ -80,7 +80,7 @@ BOOST_AUTO_TEST_CASE( any_two_of_three ) transfer_operation op = {asset(), nathan.id, account_id_type(), core.amount(500)}; trx.operations.push_back(op); sign(trx, nathan_key1); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); sign(trx, nathan_key2); PUSH_TX( db, trx, database::skip_transaction_dupe_check ); BOOST_CHECK_EQUAL(get_balance(nathan, core), old_balance - 500); @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE( any_two_of_three ) trx.signatures.clear(); //sign(trx, fc::ecc::private_key::generate()); sign(trx,nathan_key3); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); BOOST_CHECK_EQUAL(get_balance(nathan, core), old_balance - 1500); } catch (fc::exception& e) { edump((e.to_detail_string())); @@ -135,16 +135,16 @@ BOOST_AUTO_TEST_CASE( recursive_accounts ) BOOST_TEST_MESSAGE( "Attempting to transfer with no signatures, should fail" ); transfer_operation op = {asset(), child.id, account_id_type(), core.amount(500)}; trx.operations.push_back(op); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); BOOST_TEST_MESSAGE( "Attempting to transfer with parent1 signature, should fail" ); sign(trx,parent1_key); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); trx.signatures.clear(); BOOST_TEST_MESSAGE( "Attempting to transfer with parent2 signature, should fail" ); sign(trx,parent2_key); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); BOOST_TEST_MESSAGE( "Attempting to transfer with parent1 and parent2 signature, should succeed" ); sign(trx,parent1_key); @@ -172,14 +172,14 @@ BOOST_AUTO_TEST_CASE( recursive_accounts ) op = {asset(),child.id, account_id_type(), core.amount(500)}; trx.operations.push_back(op); BOOST_TEST_MESSAGE( "Attempting transfer with no signatures, should fail" ); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); BOOST_TEST_MESSAGE( "Attempting transfer just parent1, should fail" ); sign(trx, parent1_key); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); trx.signatures.clear(); BOOST_TEST_MESSAGE( "Attempting transfer just parent2, should fail" ); sign(trx, parent2_key); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); BOOST_TEST_MESSAGE( "Attempting transfer both parents, should succeed" ); sign(trx, parent1_key); @@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE( recursive_accounts ) trx.operations.push_back(op); sign(trx, parent1_key); sign(trx, parent2_key); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); trx.signatures.clear(); trx.sign( parent2_key ); trx.sign( grandparent_key ); @@ -244,7 +244,7 @@ BOOST_AUTO_TEST_CASE( recursive_accounts ) sign(trx, grandparent_key); sign(trx, delegate_priv_key); //Fails due to recursion depth. - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); BOOST_TEST_MESSAGE( "verify child key can override recursion checks" ); trx.signatures.clear(); sign(trx, child_key); @@ -268,7 +268,7 @@ BOOST_AUTO_TEST_CASE( recursive_accounts ) trx.operations.push_back(op); sign(trx, parent2_key); //Fails due to recursion depth. - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); } catch (fc::exception& e) { edump((e.to_detail_string())); throw; @@ -331,11 +331,11 @@ BOOST_AUTO_TEST_CASE( proposed_single_account ) trx.operations = {proposal_update_operation{account_id_type(), asset(), proposal.id,{nathan.id},flat_set{},flat_set{},flat_set{},flat_set{},flat_set{}}}; trx.sign( genesis_key ); //Genesis may not add nathan's approval. - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); trx.operations = {proposal_update_operation{account_id_type(), asset(), proposal.id,{account_id_type()},flat_set{},flat_set{},flat_set{},flat_set{},flat_set{}}}; trx.sign( genesis_key ); //Genesis has no stake in the transaction. - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); trx.signatures.clear(); trx.operations = {proposal_update_operation{nathan.id, asset(), proposal.id,{nathan.id},flat_set{},flat_set{},flat_set{},flat_set{},flat_set{}}}; @@ -372,7 +372,7 @@ BOOST_AUTO_TEST_CASE( genesis_authority ) BOOST_TEST_MESSAGE( "transfering 100000 CORE to nathan, signing with genesis key" ); trx.operations.push_back(transfer_operation({asset(), account_id_type(), nathan.id, asset(100000)})); sign(trx, genesis_key); - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); auto sign = [&] { trx.signatures.clear(); trx.sign(nathan_key); }; @@ -384,12 +384,12 @@ BOOST_AUTO_TEST_CASE( genesis_authority ) sign(); // The review period isn't set yet. Make sure it throws. - BOOST_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception ); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception ); pop.review_period_seconds = global_params.committee_proposal_review_period / 2; trx.operations.back() = pop; sign(); // The review period is too short. Make sure it throws. - BOOST_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception ); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception ); pop.review_period_seconds = global_params.committee_proposal_review_period; trx.operations.back() = pop; sign(); @@ -435,7 +435,7 @@ BOOST_AUTO_TEST_CASE( genesis_authority ) trx.operations.back() = uop; trx.sign( genesis_key); // Should throw because the transaction is now in review. - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); generate_blocks(prop.expiration_time); BOOST_CHECK_EQUAL(get_balance(nathan, asset_id_type()(db)), 100000); @@ -590,7 +590,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_two_accounts, database_fixture ) uop.active_approvals_to_add = {dan.get_id()}; trx.operations.push_back(uop); trx.sign(nathan_key); - BOOST_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception); trx.sign(dan_key); PUSH_TX( db, trx ); @@ -911,7 +911,7 @@ BOOST_FIXTURE_TEST_CASE( max_authority_membership, database_fixture ) if( num_keys > max_authority_membership ) { - BOOST_REQUIRE_THROW(PUSH_TX( db, tx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, tx, ~0 ), fc::exception); } else { @@ -976,7 +976,7 @@ BOOST_FIXTURE_TEST_CASE( bogus_signature, database_fixture ) trx.operations.push_back( xfer_op ); BOOST_TEST_MESSAGE( "Invalidating Alices Signature" ); // Alice's signature is now invalid - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception ); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception ); // Re-sign, now OK (sig is replaced) BOOST_TEST_MESSAGE( "Resign with Alice's Signature" ); trx.signatures.clear(); @@ -988,7 +988,7 @@ BOOST_FIXTURE_TEST_CASE( bogus_signature, database_fixture ) trx.sign( alice_key ); trx.sign( charlie_key ); // Signed by third-party Charlie (irrelevant key, not in authority) - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception ); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception ); } FC_LOG_AND_RETHROW() } @@ -1029,7 +1029,7 @@ BOOST_FIXTURE_TEST_CASE( voting_account, database_fixture ) trx.operations.push_back(op); trx.sign(vikram_private_key); // Fails because num_committee is larger than the cardinality of committee members being voted for - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); op.new_options->num_committee = 3; trx.operations = {op}; trx.signatures.clear(); diff --git a/tests/tests/basic_tests.cpp b/tests/tests/basic_tests.cpp index 56f4cf96..1b9621ce 100644 --- a/tests/tests/basic_tests.cpp +++ b/tests/tests/basic_tests.cpp @@ -330,7 +330,7 @@ BOOST_AUTO_TEST_CASE( data_fees ) BOOST_AUTO_TEST_CASE( exceptions ) { - BOOST_CHECK_THROW(FC_THROW_EXCEPTION(invalid_claim_amount, "Etc"), invalid_claim_amount); + GRAPHENE_CHECK_THROW(FC_THROW_EXCEPTION(invalid_claim_amount, "Etc"), invalid_claim_amount); } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 4c793ea6..69aae949 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -254,7 +254,7 @@ BOOST_AUTO_TEST_CASE( fork_blocks ) b.transactions.back().operations.emplace_back(transfer_operation()); b.sign(delegate_priv_key); BOOST_CHECK_EQUAL(b.block_num(), 14); - BOOST_CHECK_THROW(PUSH_BLOCK( db1, b ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_BLOCK( db1, b ), fc::exception); } BOOST_CHECK_EQUAL(db1.head_block_num(), 13); BOOST_CHECK_EQUAL(db1.head_block_id().str(), db1_tip); @@ -367,7 +367,7 @@ BOOST_AUTO_TEST_CASE( switch_forks_undo_create ) b = db2.generate_block(now, db2.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); db1.push_block(b); - BOOST_CHECK_THROW(nathan_id(db1), fc::exception); + GRAPHENE_CHECK_THROW(nathan_id(db1), fc::exception); PUSH_TX( db2, trx ); @@ -417,14 +417,14 @@ BOOST_AUTO_TEST_CASE( duplicate_transactions ) trx.sign( delegate_priv_key ); PUSH_TX( db1, trx, skip_sigs ); - BOOST_CHECK_THROW(PUSH_TX( db1, trx, skip_sigs ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db1, trx, skip_sigs ), fc::exception); now += db1.block_interval(); auto b = db1.generate_block( now, db1.get_scheduled_witness( 1 ).first, delegate_priv_key, skip_sigs ); PUSH_BLOCK( db2, b, skip_sigs ); - BOOST_CHECK_THROW(PUSH_TX( db1, trx, skip_sigs ), fc::exception); - BOOST_CHECK_THROW(PUSH_TX( db2, trx, skip_sigs ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db1, trx, skip_sigs ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db2, trx, skip_sigs ), fc::exception); BOOST_CHECK_EQUAL(db1.get_balance(nathan_id, asset_id_type()).amount.value, 500); BOOST_CHECK_EQUAL(db2.get_balance(nathan_id, asset_id_type()).amount.value, 500); } catch (fc::exception& e) { @@ -476,7 +476,7 @@ BOOST_AUTO_TEST_CASE( tapos ) trx.operations.push_back(transfer_operation({asset(), account_id_type(), nathan_id, asset(50)})); trx.sign(delegate_priv_key); //relative_expiration is 1, but ref block is 2 blocks old, so this should fail. - BOOST_REQUIRE_THROW(PUSH_TX( db1, trx, database::skip_transaction_signatures | database::skip_authority_check ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db1, trx, database::skip_transaction_signatures | database::skip_authority_check ), fc::exception); trx.set_expiration(db1.head_block_id(), 2); trx.signatures.clear(); trx.sign(delegate_priv_key); @@ -601,17 +601,17 @@ BOOST_FIXTURE_TEST_CASE( double_sign_check, database_fixture ) trx.validate(); BOOST_TEST_MESSAGE( "Verify that not-signing causes an exception" ); - BOOST_REQUIRE_THROW( db.push_transaction(trx, 0), fc::exception ); + GRAPHENE_REQUIRE_THROW( db.push_transaction(trx, 0), fc::exception ); BOOST_TEST_MESSAGE( "Verify that double-signing causes an exception" ); trx.sign(bob_private_key); trx.sign(bob_private_key); - BOOST_REQUIRE_THROW( db.push_transaction(trx, 0), fc::exception ); + GRAPHENE_REQUIRE_THROW( db.push_transaction(trx, 0), fc::exception ); BOOST_TEST_MESSAGE( "Verify that signing with an extra, unused key fails" ); trx.signatures.pop_back(); trx.sign(generate_private_key("bogus")); - BOOST_REQUIRE_THROW( db.push_transaction(trx, 0), fc::exception ); + GRAPHENE_REQUIRE_THROW( db.push_transaction(trx, 0), fc::exception ); BOOST_TEST_MESSAGE( "Verify that signing once with the proper key passes" ); trx.signatures.pop_back(); @@ -776,7 +776,7 @@ BOOST_FIXTURE_TEST_CASE( unimp_force_settlement, database_fixture ) trx.operations.push_back(sop); trx.sign(key_id_type(),private_key); //Trx has expired by now. Make sure it throws. - BOOST_CHECK_THROW(settle_id = PUSH_TX( db, trx ).operation_results.front().get(), fc::exception); + GRAPHENE_CHECK_THROW(settle_id = PUSH_TX( db, trx ).operation_results.front().get(), fc::exception); trx.set_expiration(db.head_block_time() + fc::minutes(1)); trx.sign(key_id_type(),private_key); settle_id = PUSH_TX( db, trx ).operation_results.front().get(); diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index e61d0f89..04d35ef0 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE( call_order_update_test ) BOOST_REQUIRE_EQUAL( get_balance( dan, core ), 10000000 - 10000 + 5000 ); BOOST_TEST_MESSAGE( "verifying that attempting to cover the full amount without claiming the collateral fails" ); - BOOST_REQUIRE_THROW( cover( dan, bitusd.amount(2500), core.amount(0) ), fc::exception ); + GRAPHENE_REQUIRE_THROW( cover( dan, bitusd.amount(2500), core.amount(0) ), fc::exception ); cover( dan, bitusd.amount(2500), core.amount(5000)); @@ -127,14 +127,14 @@ BOOST_AUTO_TEST_CASE( call_order_update_test ) BOOST_REQUIRE_EQUAL( get_balance( dan, core ), 10000000 - 20000 ); BOOST_TEST_MESSAGE( "increasing debt without increasing collateral again" ); - BOOST_REQUIRE_THROW( borrow( dan, bitusd.amount(80000), asset(0)), fc::exception ); + GRAPHENE_REQUIRE_THROW( borrow( dan, bitusd.amount(80000), asset(0)), fc::exception ); BOOST_TEST_MESSAGE( "attempting to claim all collateral without paying off debt" ); - BOOST_REQUIRE_THROW( cover( dan, bitusd.amount(0), asset(20000)), fc::exception ); + GRAPHENE_REQUIRE_THROW( cover( dan, bitusd.amount(0), asset(20000)), fc::exception ); BOOST_TEST_MESSAGE( "attempting reduce collateral without paying off any debt" ); cover( dan, bitusd.amount(0), asset(1000)); BOOST_TEST_MESSAGE( "attempting change call price to be below minimum for debt/collateral ratio" ); - BOOST_REQUIRE_THROW( cover( dan, bitusd.amount(0), asset(0)), fc::exception ); + GRAPHENE_REQUIRE_THROW( cover( dan, bitusd.amount(0), asset(0)), fc::exception ); } catch (fc::exception& e) { edump((e.to_detail_string())); @@ -255,7 +255,7 @@ BOOST_AUTO_TEST_CASE( black_swan ) force_settle(borrower, bitusd.amount(100)); BOOST_TEST_MESSAGE( "Verify that we cannot borrow after black swan" ); - BOOST_REQUIRE_THROW( borrow(borrower, bitusd.amount(1000), asset(2000)), fc::exception ); + GRAPHENE_REQUIRE_THROW( borrow(borrower, bitusd.amount(1000), asset(2000)), fc::exception ); } catch( const fc::exception& e) { edump((e.to_detail_string())); throw; @@ -275,22 +275,22 @@ BOOST_AUTO_TEST_CASE( prediction_market ) transfer(genesis_account, nathan_id, asset(init_balance)); BOOST_TEST_MESSAGE( "Require throw for mismatch collateral amounts" ); - BOOST_REQUIRE_THROW( borrow( dan, pmark.amount(1000), asset(2000) ), fc::exception ); + GRAPHENE_REQUIRE_THROW( borrow( dan, pmark.amount(1000), asset(2000) ), fc::exception ); BOOST_TEST_MESSAGE( "Open position with equal collateral" ); borrow( dan, pmark.amount(1000), asset(1000) ); BOOST_TEST_MESSAGE( "Cover position with unequal asset should fail." ); - BOOST_REQUIRE_THROW( cover( dan, pmark.amount(500), asset(1000) ), fc::exception ); + GRAPHENE_REQUIRE_THROW( cover( dan, pmark.amount(500), asset(1000) ), fc::exception ); BOOST_TEST_MESSAGE( "Cover half of position with equal ammounts" ); cover( dan, pmark.amount(500), asset(500) ); BOOST_TEST_MESSAGE( "Verify that forced settlment fails before global settlement" ); - BOOST_REQUIRE_THROW( force_settle( dan, pmark.amount(100) ), fc::exception ); + GRAPHENE_REQUIRE_THROW( force_settle( dan, pmark.amount(100) ), fc::exception ); BOOST_TEST_MESSAGE( "Shouldn't be allowed to force settle at more than 1 collateral per debt" ); - BOOST_REQUIRE_THROW( force_global_settle( pmark, pmark.amount(100) / core.amount(105) ), fc::exception ); + GRAPHENE_REQUIRE_THROW( force_global_settle( pmark, pmark.amount(100) / core.amount(105) ), fc::exception ); force_global_settle( pmark, pmark.amount(100) / core.amount(95) ); @@ -328,7 +328,7 @@ BOOST_AUTO_TEST_CASE( create_account_test ) op.owner.add_authority(account_id_type(9999999999), 10); trx.operations.back() = op; op.owner = auth_bak; - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); op.owner = auth_bak; trx.operations.back() = op; @@ -487,7 +487,7 @@ BOOST_AUTO_TEST_CASE( create_mia ) BOOST_CHECK(bitusd.symbol == "BITUSD"); BOOST_CHECK(bitusd.bitasset_data(db).options.short_backing_asset == asset_id_type()); BOOST_CHECK(bitusd.dynamic_asset_data_id(db).current_supply == 0); - BOOST_REQUIRE_THROW( create_bitasset("BITUSD"), fc::exception); + GRAPHENE_REQUIRE_THROW( create_bitasset("BITUSD"), fc::exception); } catch ( const fc::exception& e ) { elog( "${e}", ("e", e.to_detail_string() ) ); throw; @@ -574,7 +574,7 @@ BOOST_AUTO_TEST_CASE( create_uia ) 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); - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); const asset_dynamic_data_object& test_asset_dynamic_data = test_asset.dynamic_asset_data_id(db); BOOST_CHECK(test_asset_dynamic_data.current_supply == 0); @@ -649,7 +649,7 @@ BOOST_AUTO_TEST_CASE( update_uia ) trx.operations.back() = op; PUSH_TX( db, trx, ~0 ); op.issuer = account_id_type(); - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); op.new_issuer.reset(); } catch(fc::exception& e) { edump((e.to_detail_string())); @@ -1078,7 +1078,7 @@ BOOST_AUTO_TEST_CASE( limit_order_fill_or_kill ) trx.operations.clear(); trx.operations.push_back(op); - BOOST_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); op.fill_or_kill = false; trx.operations.back() = op; PUSH_TX( db, trx, ~0 ); @@ -1088,7 +1088,7 @@ BOOST_AUTO_TEST_CASE( limit_order_fill_or_kill ) BOOST_AUTO_TEST_CASE( fill_order ) { try { fill_order_operation o; - BOOST_CHECK_THROW(o.validate(), fc::exception); + GRAPHENE_CHECK_THROW(o.validate(), fc::exception); o.calculate_fee(db.current_fee_schedule()); } FC_LOG_AND_RETHROW() } diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index 24d99f04..49c7637d 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE( withdraw_permission_test ) op.amount_to_withdraw = asset(1); trx.operations.push_back(op); //Throws because we haven't entered the first withdrawal period yet. - BOOST_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception); //Get to the actual withdrawal period generate_blocks(permit(db).period_start_time); @@ -165,7 +165,7 @@ BOOST_AUTO_TEST_CASE( withdraw_permission_test ) trx.operations.push_back(op); trx.sign(dan_private_key); //Throws because nathan doesn't have the money - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); op.amount_to_withdraw = asset(1); trx.clear(); trx.operations = {op}; @@ -200,7 +200,7 @@ BOOST_AUTO_TEST_CASE( withdraw_permission_test ) trx.operations.push_back(op); trx.sign(dan_private_key); //Throws because the permission has expired - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); } } FC_LOG_AND_RETHROW() } @@ -368,7 +368,7 @@ BOOST_AUTO_TEST_CASE( mia_feeds ) op.publisher = nathan_id; trx.operations.back() = op; - BOOST_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); } } FC_LOG_AND_RETHROW() } @@ -893,7 +893,7 @@ BOOST_AUTO_TEST_CASE( unimp_force_settlement_unavailable ) sop.amount = asset(50, bit_usd); trx.operations = {sop}; //Force settlement is disabled; check that it fails - BOOST_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); { //Enable force settlement asset_update_operation op; @@ -967,7 +967,7 @@ BOOST_AUTO_TEST_CASE( assert_op_test ) op.predicates.back() = fc::raw::pack(predicate(pred::account_name_eq_lit{ nathan_id, "dan" })); trx.operations.back() = op; trx.sign(nathan_private_key); - BOOST_CHECK_THROW( PUSH_TX( db, trx ), fc::exception ); + GRAPHENE_CHECK_THROW( PUSH_TX( db, trx ), fc::exception ); } FC_LOG_AND_RETHROW() } @@ -1014,7 +1014,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) trx.operations = {op}; trx.sign(n_key); // Fail because I'm claiming from an address which hasn't signed - BOOST_CHECK_THROW(db.push_transaction(trx), fc::exception); + GRAPHENE_CHECK_THROW(db.push_transaction(trx), fc::exception); trx.clear(); op.balance_to_claim = balance_id_type(); op.balance_owner_key = n_key.get_public_key(); @@ -1048,7 +1048,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) trx.sign(n_key); trx.sign(v1_key); // Attempting to claim 1 from a balance with 0 available - BOOST_CHECK_THROW(db.push_transaction(trx), invalid_claim_amount); + GRAPHENE_CHECK_THROW(db.push_transaction(trx), invalid_claim_amount); op.balance_to_claim = vesting_balance_2.id; op.total_claimed.amount = 151; @@ -1058,7 +1058,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) trx.sign(n_key); trx.sign(v2_key); // Attempting to claim 151 from a balance with 150 available - BOOST_CHECK_THROW(db.push_transaction(trx), invalid_claim_amount); + GRAPHENE_CHECK_THROW(db.push_transaction(trx), invalid_claim_amount); op.balance_to_claim = vesting_balance_2.id; op.total_claimed.amount = 100; @@ -1077,7 +1077,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) trx.sign(n_key); trx.sign(v2_key); // Attempting to claim twice within a day - BOOST_CHECK_THROW(db.push_transaction(trx), balance_claimed_too_often); + GRAPHENE_CHECK_THROW(db.push_transaction(trx), balance_claimed_too_often); db.generate_block(db.get_slot_time(1), db.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); slot = db.get_slot_at_time(vesting_balance_1.vesting_policy->begin_timestamp + 60); @@ -1103,7 +1103,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) trx.sign(n_key); trx.sign(v2_key); // Attempting to claim twice within a day - BOOST_CHECK_THROW(db.push_transaction(trx), balance_claimed_too_often); + GRAPHENE_CHECK_THROW(db.push_transaction(trx), balance_claimed_too_often); db.generate_block(db.get_slot_time(1), db.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); slot = db.get_slot_at_time(db.head_block_time() + fc::days(1)); diff --git a/tests/tests/uia_tests.cpp b/tests/tests/uia_tests.cpp index 72d4df30..7a14a1f6 100644 --- a/tests/tests/uia_tests.cpp +++ b/tests/tests/uia_tests.cpp @@ -84,10 +84,10 @@ BOOST_AUTO_TEST_CASE( override_transfer_test ) trx.operations.push_back(otrans); BOOST_TEST_MESSAGE( "Require throwing without signature" ); - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); BOOST_TEST_MESSAGE( "Require throwing with dan's signature" ); trx.sign( dan_private_key ); - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); BOOST_TEST_MESSAGE( "Pass with issuer's signature" ); trx.signatures.clear(); trx.sign( sam_private_key ); @@ -112,14 +112,14 @@ BOOST_AUTO_TEST_CASE( override_transfer_test2 ) trx.operations.push_back(otrans); BOOST_TEST_MESSAGE( "Require throwing without signature" ); - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); BOOST_TEST_MESSAGE( "Require throwing with dan's signature" ); trx.sign( dan_private_key ); - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); BOOST_TEST_MESSAGE( "Fail because overide_authority flag is not set" ); trx.signatures.clear(); trx.sign( sam_private_key ); - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception ); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception ); BOOST_REQUIRE_EQUAL( get_balance( dan, advanced ), 1000 ); BOOST_REQUIRE_EQUAL( get_balance( eric, advanced ), 0 ); @@ -137,7 +137,7 @@ BOOST_AUTO_TEST_CASE( issue_whitelist_uia ) asset_issue_operation op({asset(), advanced.issuer, advanced.amount(1000), nathan.id}); trx.operations.emplace_back(op); //Fail because nathan is not whitelisted. - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); account_whitelist_operation wop({asset(), account_id_type(), nathan.id, account_whitelist_operation::white_listed}); @@ -168,7 +168,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) transfer_operation op({advanced.amount(0), nathan.id, dan.id, advanced.amount(100)}); trx.operations.push_back(op); //Fail because dan is not whitelisted. - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); account_whitelist_operation wop({asset(), account_id_type(), dan.id, account_whitelist_operation::white_listed}); trx.operations.back() = wop; @@ -187,14 +187,14 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) op.amount = advanced.amount(50); trx.operations.back() = op; //Fail because nathan is blacklisted - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); trx.operations = {asset_reserve_operation{asset(), nathan.id, advanced.amount(10)}}; //Fail because nathan is blacklisted - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); std::swap(op.from, op.to); trx.operations.back() = op; //Fail because nathan is blacklisted - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); { asset_update_operation op; @@ -221,7 +221,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_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); //Remove nathan from genesis' whitelist, add him to dan's. This should not authorize him to hold ADVANCED. wop.authorizing_account = account_id_type(); @@ -238,7 +238,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_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); trx.operations = {asset_reserve_operation{asset(), dan.id, advanced.amount(10)}}; PUSH_TX(db, trx, ~0); From 680dadf5b042f64c76eba307bb05eda7fe114d9d Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Wed, 8 Jul 2015 12:14:54 -0400 Subject: [PATCH 17/28] database_fixture: Enable verbose output only if --record-assert-trip is passed on command line --- tests/common/database_fixture.cpp | 10 ++++++++++ tests/common/database_fixture.hpp | 20 ++++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 72ccccfe..c2206243 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -48,6 +48,16 @@ database_fixture::database_fixture() : app(), db( *app.chain_database() ) { try { + int argc = boost::unit_test::framework::master_test_suite().argc; + char** argv = boost::unit_test::framework::master_test_suite().argv; + for( int i=1; i(); auto mhplugin = app.register_plugin(); delegate_pub_key = delegate_priv_key.get_public_key(); diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 39ad99f4..09e8aaf2 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -59,11 +59,13 @@ using namespace graphene::db; ("expr", #expr) \ ("exc_type", #exc_type) \ ); \ - std::cout << "GRAPHENE_REQUIRE_THROW begin " \ - << req_throw_info << std::endl; \ + if( fc::enable_record_assert_trip ) \ + std::cout << "GRAPHENE_REQUIRE_THROW begin " \ + << req_throw_info << std::endl; \ BOOST_REQUIRE_THROW( expr, exc_type ); \ - std::cout << "GRAPHENE_REQUIRE_THROW end " \ - << req_throw_info << std::endl; \ + if( fc::enable_record_assert_trip ) \ + std::cout << "GRAPHENE_REQUIRE_THROW end " \ + << req_throw_info << std::endl; \ } #define GRAPHENE_CHECK_THROW( expr, exc_type ) \ @@ -75,11 +77,13 @@ using namespace graphene::db; ("expr", #expr) \ ("exc_type", #exc_type) \ ); \ - std::cout << "GRAPHENE_CHECK_THROW begin " \ - << req_throw_info << std::endl; \ + if( fc::enable_record_assert_trip ) \ + std::cout << "GRAPHENE_CHECK_THROW begin " \ + << req_throw_info << std::endl; \ BOOST_CHECK_THROW( expr, exc_type ); \ - std::cout << "GRAPHENE_CHECK_THROW end " \ - << req_throw_info << std::endl; \ + if( fc::enable_record_assert_trip ) \ + std::cout << "GRAPHENE_CHECK_THROW end " \ + << req_throw_info << std::endl; \ } #define REQUIRE_OP_VALIDATION_FAILURE_2( op, field, value, exc_type ) \ From 8ff25b813feeb95b2b7ffde12ed95c1e47ff6065 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 7 Jul 2015 21:43:58 -0400 Subject: [PATCH 18/28] Begin implementation of new exception framework #113 --- libraries/chain/balance_evaluator.cpp | 35 +++++++---- .../include/graphene/chain/exceptions.hpp | 63 +++++++++++++++++-- tests/tests/basic_tests.cpp | 2 +- tests/tests/operation_tests2.cpp | 8 +-- 4 files changed, 86 insertions(+), 22 deletions(-) diff --git a/libraries/chain/balance_evaluator.cpp b/libraries/chain/balance_evaluator.cpp index 1a5dee52..d69003f5 100644 --- a/libraries/chain/balance_evaluator.cpp +++ b/libraries/chain/balance_evaluator.cpp @@ -7,27 +7,38 @@ void_result balance_claim_evaluator::do_evaluate(const balance_claim_operation& database& d = db(); balance = &op.balance_to_claim(d); - FC_ASSERT(op.balance_owner_key == balance->owner || + GRAPHENE_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"); + balance_claim_owner_mismatch, + "Balance owner key was specified as '${op}' but balance's actual owner is '${bal}'", + ("op", op.balance_owner_key) + ("bal", balance->owner) + ); if( !(d.get_node_properties().skip_flags & (database::skip_authority_check | database::skip_transaction_signatures)) ) FC_ASSERT(op.total_claimed.asset_id == balance->asset_type()); - if( balance->is_vesting_balance() ) { - if( !balance->vesting_policy->is_withdraw_allowed({balance->balance, - d.head_block_time(), - op.total_claimed}) ) - FC_THROW_EXCEPTION(invalid_claim_amount, - "Attempted to claim ${c} from a vesting balance with ${a} available", - ("c", op.total_claimed)("a", balance->available(d.head_block_time()))); - if( d.head_block_time() - balance->last_claim_date < fc::days(1) ) - FC_THROW_EXCEPTION(balance_claimed_too_often, - "Genesis vesting balances may not be claimed more than once per day."); + if( balance->is_vesting_balance() ) + { + GRAPHENE_ASSERT( + balance->vesting_policy->is_withdraw_allowed( + { balance->balance, + d.head_block_time(), + op.total_claimed } ), + balance_claim_invalid_claim_amount, + "Attempted to claim ${c} from a vesting balance with ${a} available", + ("c", op.total_claimed)("a", balance->available(d.head_block_time())) + ); + GRAPHENE_ASSERT( + d.head_block_time() - balance->last_claim_date >= fc::days(1), + balance_claim_claimed_too_often, + "Genesis vesting balances may not be claimed more than once per day." + ); return {}; } diff --git a/libraries/chain/include/graphene/chain/exceptions.hpp b/libraries/chain/include/graphene/chain/exceptions.hpp index f06ecb02..ebd1ff91 100644 --- a/libraries/chain/include/graphene/chain/exceptions.hpp +++ b/libraries/chain/include/graphene/chain/exceptions.hpp @@ -18,12 +18,66 @@ #pragma once #include +#include + +#define GRAPHENE_ASSERT( expr, exc_type, ... ) \ + if( !(expr) ) \ + { \ + FC_THROW_EXCEPTION( exc_type, __VA_ARGS__ ); \ + } + +#define GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( op_name ) \ + FC_DECLARE_DERIVED_EXCEPTION( \ + op_name ## _validate_exception, \ + graphene::chain::operation_validate_exception, \ + 3040000 + 100 * operation::tag< op_name ## _operation >::value, \ + #op_name "_operation validation exception" \ + ) \ + FC_DECLARE_DERIVED_EXCEPTION( \ + op_name ## _evaluate_exception, \ + graphene::chain::operation_evaluate_exception, \ + 3050000 + 100 * operation::tag< op_name ## _operation >::value, \ + #op_name "_operation evaluation exception" \ + ) + +#define GRAPHENE_DECLARE_OP_VALIDATE_EXCEPTION( exc_name, op_name, seqnum, msg ) \ + FC_DECLARE_DERIVED_EXCEPTION( \ + op_name ## _ ## exc_name, \ + graphene::chain::op_name ## _validate_exception, \ + 3040000 + 100 * operation::tag< op_name ## _operation >::value \ + + seqnum, \ + msg \ + ) + +#define GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( exc_name, op_name, seqnum, msg ) \ + FC_DECLARE_DERIVED_EXCEPTION( \ + op_name ## _ ## exc_name, \ + graphene::chain::op_name ## _evaluate_exception, \ + 3050000 + 100 * operation::tag< op_name ## _operation >::value \ + + seqnum, \ + msg \ + ) namespace graphene { namespace chain { - // registered in chain_database.cpp - FC_DECLARE_EXCEPTION( chain_exception, 30000, "Blockchain Exception" ) - FC_DECLARE_DERIVED_EXCEPTION( invalid_pts_address, graphene::chain::chain_exception, 30001, "invalid pts address" ) + FC_DECLARE_EXCEPTION( chain_exception, 3000000, "blockchain exception" ) + FC_DECLARE_DERIVED_EXCEPTION( database_query_exception, graphene::chain::chain_exception, 3010000, "database query exception" ) + FC_DECLARE_DERIVED_EXCEPTION( block_validate_exception, graphene::chain::chain_exception, 3020000, "block validation exception" ) + FC_DECLARE_DERIVED_EXCEPTION( transaction_exception, graphene::chain::chain_exception, 3030000, "transaction validation exception" ) + FC_DECLARE_DERIVED_EXCEPTION( operation_validate_exception, graphene::chain::chain_exception, 3040000, "operation validation exception" ) + FC_DECLARE_DERIVED_EXCEPTION( operation_evaluate_exception, graphene::chain::chain_exception, 3050000, "operation evaluation exception" ) + FC_DECLARE_DERIVED_EXCEPTION( utility_exception, graphene::chain::chain_exception, 3060000, "utility method exception" ) + + FC_DECLARE_DERIVED_EXCEPTION( invalid_pts_address, graphene::chain::utility_exception, 3060001, "invalid pts address" ) + FC_DECLARE_DERIVED_EXCEPTION( insufficient_feeds, graphene::chain::chain_exception, 37006, "insufficient feeds" ) + + GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( balance_claim ); + + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( claimed_too_often, balance_claim, 1, "balance claimed too often" ) + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( invalid_claim_amount, balance_claim, 2, "invalid claim amount" ) + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( owner_mismatch, balance_claim, 3, "owner mismatch" ) + + /* FC_DECLARE_DERIVED_EXCEPTION( addition_overflow, graphene::chain::chain_exception, 30002, "addition overflow" ) FC_DECLARE_DERIVED_EXCEPTION( subtraction_overflow, graphene::chain::chain_exception, 30003, "subtraction overflow" ) FC_DECLARE_DERIVED_EXCEPTION( asset_type_mismatch, graphene::chain::chain_exception, 30004, "asset/price mismatch" ) @@ -63,8 +117,6 @@ namespace graphene { namespace chain { FC_DECLARE_DERIVED_EXCEPTION( expired_transaction, graphene::chain::evaluation_error, 31010, "expired transaction" ) FC_DECLARE_DERIVED_EXCEPTION( invalid_transaction_expiration, graphene::chain::evaluation_error, 31011, "invalid transaction expiration" ) FC_DECLARE_DERIVED_EXCEPTION( oversized_transaction, graphene::chain::evaluation_error, 31012, "transaction exceeded the maximum transaction size" ) - FC_DECLARE_DERIVED_EXCEPTION( balance_claimed_too_often, graphene::chain::evaluation_error, 31013, "balance claimed too often" ) - FC_DECLARE_DERIVED_EXCEPTION( invalid_claim_amount, graphene::chain::evaluation_error, 31013, "invalid claim amount" ) FC_DECLARE_DERIVED_EXCEPTION( invalid_account_name, graphene::chain::evaluation_error, 32001, "invalid account name" ) FC_DECLARE_DERIVED_EXCEPTION( unknown_account_id, graphene::chain::evaluation_error, 32002, "unknown account id" ) @@ -111,5 +163,6 @@ namespace graphene { namespace chain { FC_DECLARE_DERIVED_EXCEPTION( price_multiplication_overflow, graphene::chain::evaluation_error, 38001, "price multiplication overflow" ) FC_DECLARE_DERIVED_EXCEPTION( price_multiplication_underflow, graphene::chain::evaluation_error, 38002, "price multiplication underflow" ) FC_DECLARE_DERIVED_EXCEPTION( price_multiplication_undefined, graphene::chain::evaluation_error, 38003, "price multiplication undefined product 0*inf" ) + */ } } // graphene::chain diff --git a/tests/tests/basic_tests.cpp b/tests/tests/basic_tests.cpp index 1b9621ce..727a0690 100644 --- a/tests/tests/basic_tests.cpp +++ b/tests/tests/basic_tests.cpp @@ -330,7 +330,7 @@ BOOST_AUTO_TEST_CASE( data_fees ) BOOST_AUTO_TEST_CASE( exceptions ) { - GRAPHENE_CHECK_THROW(FC_THROW_EXCEPTION(invalid_claim_amount, "Etc"), invalid_claim_amount); + GRAPHENE_CHECK_THROW(FC_THROW_EXCEPTION(balance_claim_invalid_claim_amount, "Etc"), balance_claim_invalid_claim_amount); } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index 49c7637d..da81c72d 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -1048,7 +1048,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) trx.sign(n_key); trx.sign(v1_key); // Attempting to claim 1 from a balance with 0 available - GRAPHENE_CHECK_THROW(db.push_transaction(trx), invalid_claim_amount); + GRAPHENE_CHECK_THROW(db.push_transaction(trx), balance_claim_invalid_claim_amount); op.balance_to_claim = vesting_balance_2.id; op.total_claimed.amount = 151; @@ -1058,7 +1058,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) trx.sign(n_key); trx.sign(v2_key); // Attempting to claim 151 from a balance with 150 available - GRAPHENE_CHECK_THROW(db.push_transaction(trx), invalid_claim_amount); + GRAPHENE_CHECK_THROW(db.push_transaction(trx), balance_claim_invalid_claim_amount); op.balance_to_claim = vesting_balance_2.id; op.total_claimed.amount = 100; @@ -1077,7 +1077,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) trx.sign(n_key); trx.sign(v2_key); // Attempting to claim twice within a day - GRAPHENE_CHECK_THROW(db.push_transaction(trx), balance_claimed_too_often); + GRAPHENE_CHECK_THROW(db.push_transaction(trx), balance_claim_claimed_too_often); db.generate_block(db.get_slot_time(1), db.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); slot = db.get_slot_at_time(vesting_balance_1.vesting_policy->begin_timestamp + 60); @@ -1103,7 +1103,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) trx.sign(n_key); trx.sign(v2_key); // Attempting to claim twice within a day - GRAPHENE_CHECK_THROW(db.push_transaction(trx), balance_claimed_too_often); + GRAPHENE_CHECK_THROW(db.push_transaction(trx), balance_claim_claimed_too_often); db.generate_block(db.get_slot_time(1), db.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); slot = db.get_slot_at_time(db.head_block_time() + fc::days(1)); From d4e4854eb69a23011c315a66bf782e8c94667a5b Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Wed, 8 Jul 2015 14:26:59 -0400 Subject: [PATCH 19/28] exceptions: Implement missing_auth exceptions --- libraries/chain/evaluator.cpp | 20 +++++++++++++++---- .../include/graphene/chain/exceptions.hpp | 5 +++++ tests/tests/uia_tests.cpp | 5 +++-- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/libraries/chain/evaluator.cpp b/libraries/chain/evaluator.cpp index a8bdb277..886db279 100644 --- a/libraries/chain/evaluator.cpp +++ b/libraries/chain/evaluator.cpp @@ -17,7 +17,9 @@ */ #include #include +#include #include + #include #include #include @@ -90,14 +92,24 @@ database& generic_evaluator::db()const { return trx_state->db(); } operation_get_required_authorities( op, other_auths ); for( auto id : active_auths ) - FC_ASSERT(verify_authority(id(db()), authority::active) || - verify_authority(id(db()), authority::owner), "", ("id", id)); + GRAPHENE_ASSERT( + verify_authority(id(db()), authority::active) || + verify_authority(id(db()), authority::owner), + tx_missing_active_auth, + "missing required active authority ${id}", ("id", id)); for( auto id : owner_auths ) - FC_ASSERT(verify_authority(id(db()), authority::owner), "", ("id", id)); + GRAPHENE_ASSERT( + verify_authority(id(db()), authority::owner), + tx_missing_owner_auth, + "missing required owner authority ${id}", ("id", id)); for( const auto& auth : other_auths ) - FC_ASSERT(trx_state->check_authority(auth), "invalid authority", ("auth",auth)("sigs",trx_state->_sigs)); + GRAPHENE_ASSERT( + trx_state->check_authority(auth), + tx_missing_other_auth, + "missing required authority ${auth}", + ("auth",auth)("sigs",trx_state->_sigs)); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/chain/include/graphene/chain/exceptions.hpp b/libraries/chain/include/graphene/chain/exceptions.hpp index ebd1ff91..933847e6 100644 --- a/libraries/chain/include/graphene/chain/exceptions.hpp +++ b/libraries/chain/include/graphene/chain/exceptions.hpp @@ -68,6 +68,11 @@ namespace graphene { namespace chain { FC_DECLARE_DERIVED_EXCEPTION( operation_evaluate_exception, graphene::chain::chain_exception, 3050000, "operation evaluation exception" ) FC_DECLARE_DERIVED_EXCEPTION( utility_exception, graphene::chain::chain_exception, 3060000, "utility method exception" ) + FC_DECLARE_DERIVED_EXCEPTION( tx_missing_active_auth, graphene::chain::transaction_exception, 3030001, "missing required active authority" ) + FC_DECLARE_DERIVED_EXCEPTION( tx_missing_owner_auth, graphene::chain::transaction_exception, 3030002, "missing required owner authority" ) + FC_DECLARE_DERIVED_EXCEPTION( tx_missing_other_auth, graphene::chain::transaction_exception, 3030003, "missing required other authority" ) + //FC_DECLARE_DERIVED_EXCEPTION( tx_irrelevant_authority, graphene::chain::transaction_exception, 3030004, "irrelevant authority" ) + FC_DECLARE_DERIVED_EXCEPTION( invalid_pts_address, graphene::chain::utility_exception, 3060001, "invalid pts address" ) FC_DECLARE_DERIVED_EXCEPTION( insufficient_feeds, graphene::chain::chain_exception, 37006, "insufficient feeds" ) diff --git a/tests/tests/uia_tests.cpp b/tests/tests/uia_tests.cpp index 7a14a1f6..9f48e045 100644 --- a/tests/tests/uia_tests.cpp +++ b/tests/tests/uia_tests.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -84,10 +85,10 @@ BOOST_AUTO_TEST_CASE( override_transfer_test ) trx.operations.push_back(otrans); BOOST_TEST_MESSAGE( "Require throwing without signature" ); - GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), tx_missing_active_auth ); BOOST_TEST_MESSAGE( "Require throwing with dan's signature" ); trx.sign( dan_private_key ); - GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), tx_missing_active_auth ); BOOST_TEST_MESSAGE( "Pass with issuer's signature" ); trx.signatures.clear(); trx.sign( sam_private_key ); From 5a01e255e2e0e672d5c707e2db55080ee85645f7 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Wed, 8 Jul 2015 14:55:49 -0400 Subject: [PATCH 20/28] Progress #17: Fix genesis witness list --- libraries/chain/db_init.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 93be6dc9..d819d836 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -424,29 +424,26 @@ void database::init_genesis(const genesis_state_type& genesis_state) }); // Create initial workers - std::for_each( genesis_state.initial_worker_candidates.begin(), genesis_state.initial_worker_candidates.end(), - [ & ]( const genesis_state_type::initial_worker_type& worker ) + std::for_each(genesis_state.initial_worker_candidates.begin(), genesis_state.initial_worker_candidates.end(), + [&](const genesis_state_type::initial_worker_type& worker) { worker_create_operation op; - op.owner = get_account_id( worker.owner_name ); + op.owner = get_account_id(worker.owner_name); op.work_begin_date = genesis_state.initial_timestamp; op.work_end_date = time_point_sec::maximum(); op.daily_pay = worker.daily_pay; op.name = "Genesis-Worker-" + worker.owner_name; - op.initializer = vesting_balance_worker_type::initializer( 0 ); + op.initializer = vesting_balance_worker_type::initializer(0); - apply_operation( genesis_eval_state, std::move( op ) ); - } ); + apply_operation(genesis_eval_state, std::move(op)); + }); // Set active witnesses modify(get_global_properties(), [&](global_property_object& p) { - auto idx = get_index_type().indices(); - for( auto itr = idx.begin(); - itr != idx.end() && p.active_witnesses.size() < genesis_state.initial_active_witnesses; - ++itr ) + for( int i = 0; i < genesis_state.initial_active_witnesses; ++i ) { - p.active_witnesses.insert(itr->id); - p.witness_accounts.insert(itr->witness_account); + p.active_witnesses.insert(i); + p.witness_accounts.insert(get(witness_id_type(i)).witness_account); } }); From 2f9e636618297557ed2ff69b7386253f1323dcfc Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Wed, 8 Jul 2015 15:00:46 -0400 Subject: [PATCH 21/28] db_maint.cpp: Avoid implementation-defined ordering when votable objects tie for votes --- libraries/chain/db_maint.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 1fd4bf98..05209ef1 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -44,7 +44,11 @@ vector> database::sort [](const ObjectType& o) { return std::cref(o); }); std::partial_sort(refs.begin(), refs.begin() + count, refs.end(), [this](const ObjectType& a, const ObjectType& b)->bool { - return _vote_tally_buffer[a.vote_id] > _vote_tally_buffer[b.vote_id]; + share_type oa_vote = _vote_tally_buffer[a.vote_id]; + share_type ob_vote = _vote_tally_buffer[b.vote_id]; + if( oa_vote != ob_vote ) + return oa_vote > ob_vote; + return a.vote_id < b.vote_id; }); refs.resize(count, refs.front()); From 6436f0142f2711cdc2a7334afc0e3b4d6fc381b8 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Wed, 8 Jul 2015 16:00:22 -0400 Subject: [PATCH 22/28] Fix witness/delegate count voting; fix unclean witness shutdown on mac --- libraries/chain/db_maint.cpp | 20 +++++++++++--------- programs/witness_node/main.cpp | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 05209ef1..10cf2693 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -112,9 +112,10 @@ void database::update_active_witnesses() share_type stake_target = _total_voting_stake / 2; share_type stake_tally = _witness_count_histogram_buffer[0]; 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]; + if( stake_target > 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, (size_t)GRAPHENE_MIN_WITNESS_COUNT)); const global_property_object& gpo = get_global_properties(); @@ -177,9 +178,10 @@ void database::update_active_delegates() uint64_t stake_target = _total_voting_stake / 2; uint64_t stake_tally = _committee_count_histogram_buffer[0]; 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]; + if( stake_target > 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, (size_t)GRAPHENE_MIN_DELEGATE_COUNT)); @@ -381,7 +383,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g uint32_t offset = id.instance(); // if they somehow managed to specify an illegal offset, ignore it. if( offset < d._vote_tally_buffer.size() ) - d._vote_tally_buffer[ offset ] += voting_stake; + d._vote_tally_buffer[offset] += voting_stake; } if( opinion_account.options.num_witness <= props.parameters.maximum_witness_count ) @@ -394,7 +396,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g // in particular, this takes care of the case where a // member was voting for a high number, then the // parameter was lowered. - d._witness_count_histogram_buffer[ offset ] += voting_stake; + d._witness_count_histogram_buffer[offset] += voting_stake; } if( opinion_account.options.num_committee <= props.parameters.maximum_committee_count ) { @@ -404,7 +406,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g // are turned into votes for maximum_committee_count. // // same rationale as for witnesses - d._committee_count_histogram_buffer[ offset ] += voting_stake; + d._committee_count_histogram_buffer[offset] += voting_stake; } d._total_voting_stake += voting_stake; diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index aad45e91..99387f31 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -119,7 +119,7 @@ int main(int argc, char** argv) { node.startup_plugins(); fc::promise::ptr exit_promise = new fc::promise("UNIX Signal Handler"); -#ifdef __unix__ +#if defined __APPLE__ || defined __unix__ fc::set_signal_handler([&exit_promise](int signal) { exit_promise->set_value(signal); }, SIGINT); From 8d3fd20db2b86ac48c70d2398f6a27398771dc99 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Wed, 8 Jul 2015 16:44:18 -0400 Subject: [PATCH 23/28] Progress #17: Fix account key genesis initialization --- libraries/chain/db_init.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index d819d836..52027015 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -261,13 +261,11 @@ void database::init_genesis(const genesis_state_type& genesis_state) cop.name = account.name; cop.registrar = GRAPHENE_TEMP_ACCOUNT; cop.owner = authority(1, account.owner_key, 1); - if( account.owner_key != account.active_key ) - { - cop.active = authority(1, account.owner_key, 1); - } else { + if( account.owner_key != account.active_key && account.active_key != public_key_type() ) + cop.active = authority(1, account.active_key, 1); + else cop.active = cop.owner; - } - cop.options.memo_key = account.owner_key; + cop.options.memo_key = account.active_key; account_id_type account_id(apply_operation(genesis_eval_state, cop).get()); if( account.is_lifetime_member ) From 9c4ac2e064ed38706fbcf11768a8f9556670eb53 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Wed, 8 Jul 2015 16:30:32 -0400 Subject: [PATCH 24/28] exceptions: Add some exceptions --- .../include/graphene/chain/exceptions.hpp | 50 +++++++++++++++++++ libraries/chain/proposal_evaluator.cpp | 18 ++++++- libraries/chain/transfer_evaluator.cpp | 24 +++++++-- .../chain/withdraw_permission_evaluator.cpp | 1 + tests/tests/authority_tests.cpp | 5 +- tests/tests/uia_tests.cpp | 4 +- 6 files changed, 93 insertions(+), 9 deletions(-) diff --git a/libraries/chain/include/graphene/chain/exceptions.hpp b/libraries/chain/include/graphene/chain/exceptions.hpp index 933847e6..5527e434 100644 --- a/libraries/chain/include/graphene/chain/exceptions.hpp +++ b/libraries/chain/include/graphene/chain/exceptions.hpp @@ -76,12 +76,62 @@ namespace graphene { namespace chain { FC_DECLARE_DERIVED_EXCEPTION( invalid_pts_address, graphene::chain::utility_exception, 3060001, "invalid pts address" ) FC_DECLARE_DERIVED_EXCEPTION( insufficient_feeds, graphene::chain::chain_exception, 37006, "insufficient feeds" ) + GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( transfer ); + + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( from_account_not_whitelisted, transfer, 1, "owner mismatch" ) + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( to_account_not_whitelisted, transfer, 2, "owner mismatch" ) + + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( limit_order_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( limit_order_cancel ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( call_order_update ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( account_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( account_update ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( account_whitelist ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( account_upgrade ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( account_transfer ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_update ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_update_bitasset ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_update_feed_producers ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_issue ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_reserve ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_fund_fee_pool ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_settle ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_global_settle ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_publish_feed ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( delegate_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( witness_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( witness_withdraw_pay ); + + GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( proposal_create ); + + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( review_period_required, proposal_create, 1, "review_period required" ) + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( review_period_insufficient, proposal_create, 2, "review_period insufficient" ) + + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( proposal_update ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( proposal_delete ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( withdraw_permission_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( withdraw_permission_update ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( withdraw_permission_claim ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( withdraw_permission_delete ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( fill_order ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( global_parameters_update ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( vesting_balance_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( vesting_balance_withdraw ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( worker_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( custom ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( assert ); + GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( balance_claim ); GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( claimed_too_often, balance_claim, 1, "balance claimed too often" ) GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( invalid_claim_amount, balance_claim, 2, "invalid claim amount" ) GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( owner_mismatch, balance_claim, 3, "owner mismatch" ) + GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( override_transfer ); + + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( not_permitted, override_transfer, 1, "not permitted" ) + /* FC_DECLARE_DERIVED_EXCEPTION( addition_overflow, graphene::chain::chain_exception, 30002, "addition overflow" ) FC_DECLARE_DERIVED_EXCEPTION( subtraction_overflow, graphene::chain::chain_exception, 30003, "subtraction overflow" ) diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index 7ff90a20..14cff105 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace graphene { namespace chain { @@ -41,8 +42,21 @@ void_result proposal_create_evaluator::do_evaluate(const proposal_create_operati operation_get_required_owner_authorities(op.op, auths); } if( auths.find(account_id_type()) != auths.end() ) - FC_ASSERT( o.review_period_seconds - && *o.review_period_seconds >= global_parameters.committee_proposal_review_period ); + { + GRAPHENE_ASSERT( + o.review_period_seconds.valid(), + proposal_create_review_period_required, + "Review period not given, but at least ${min} required", + ("min", global_parameters.committee_proposal_review_period) + ); + GRAPHENE_ASSERT( + *o.review_period_seconds >= global_parameters.committee_proposal_review_period, + proposal_create_review_period_insufficient, + "Review period of ${t} required, but at least ${min} required", + ("t", *o.review_period_seconds) + ("min", global_parameters.committee_proposal_review_period) + ); + } } for( const op_wrapper& op : o.proposed_ops ) diff --git a/libraries/chain/transfer_evaluator.cpp b/libraries/chain/transfer_evaluator.cpp index d2ef09fb..66e5724b 100644 --- a/libraries/chain/transfer_evaluator.cpp +++ b/libraries/chain/transfer_evaluator.cpp @@ -17,6 +17,7 @@ */ #include #include +#include namespace graphene { namespace chain { void_result transfer_evaluator::do_evaluate( const transfer_operation& op ) @@ -30,8 +31,20 @@ void_result transfer_evaluator::do_evaluate( const transfer_operation& 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 ) ); + GRAPHENE_ASSERT( + from_account.is_authorized_asset( 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( + to_account.is_authorized_asset( 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( fee_asset_type.options.flags & white_list ) @@ -60,7 +73,12 @@ void_result override_transfer_evaluator::do_evaluate( const override_transfer_op database& d = db(); const asset_object& asset_type = op.amount.asset_id(d); - FC_ASSERT( asset_type.can_override() ); + GRAPHENE_ASSERT( + asset_type.can_override(), + override_transfer_not_permitted, + "override_transfer not permitted for asset ${asset}", + ("asset", op.amount.asset_id) + ); FC_ASSERT( asset_type.issuer == op.issuer ); const account_object& from_account = op.from(d); diff --git a/libraries/chain/withdraw_permission_evaluator.cpp b/libraries/chain/withdraw_permission_evaluator.cpp index 086ec368..d7a33c7f 100644 --- a/libraries/chain/withdraw_permission_evaluator.cpp +++ b/libraries/chain/withdraw_permission_evaluator.cpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace graphene { namespace chain { diff --git a/tests/tests/authority_tests.cpp b/tests/tests/authority_tests.cpp index 32a3bff8..630eafc5 100644 --- a/tests/tests/authority_tests.cpp +++ b/tests/tests/authority_tests.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -384,12 +385,12 @@ BOOST_AUTO_TEST_CASE( genesis_authority ) sign(); // The review period isn't set yet. Make sure it throws. - GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception ); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx ), proposal_create_review_period_required ); pop.review_period_seconds = global_params.committee_proposal_review_period / 2; trx.operations.back() = pop; sign(); // The review period is too short. Make sure it throws. - GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception ); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx ), proposal_create_review_period_insufficient ); pop.review_period_seconds = global_params.committee_proposal_review_period; trx.operations.back() = pop; sign(); diff --git a/tests/tests/uia_tests.cpp b/tests/tests/uia_tests.cpp index 9f48e045..7dfb9c6e 100644 --- a/tests/tests/uia_tests.cpp +++ b/tests/tests/uia_tests.cpp @@ -169,7 +169,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) transfer_operation op({advanced.amount(0), nathan.id, dan.id, advanced.amount(100)}); trx.operations.push_back(op); //Fail because dan is not whitelisted. - GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), transfer_to_account_not_whitelisted ); account_whitelist_operation wop({asset(), account_id_type(), dan.id, account_whitelist_operation::white_listed}); trx.operations.back() = wop; @@ -188,7 +188,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) op.amount = advanced.amount(50); trx.operations.back() = op; //Fail because nathan is blacklisted - GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), transfer_from_account_not_whitelisted ); trx.operations = {asset_reserve_operation{asset(), nathan.id, advanced.amount(10)}}; //Fail because nathan is blacklisted GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); From d64c9154a763518556ee84faf74beb9870856a69 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Wed, 8 Jul 2015 17:39:28 -0400 Subject: [PATCH 25/28] Progress #17: Lazy load genesis state This speeds up startup for witness_node when starting on a database which is already initialized. --- libraries/app/application.cpp | 50 ++++++++++--------- libraries/chain/db_init.cpp | 2 +- libraries/chain/db_management.cpp | 29 ++--------- .../include/graphene/chain/account_object.hpp | 4 +- .../chain/include/graphene/chain/database.hpp | 34 ++++++++++++- tests/common/database_fixture.cpp | 2 +- tests/tests/block_tests.cpp | 38 +++++++------- tests/tests/operation_tests2.cpp | 2 +- 8 files changed, 86 insertions(+), 75 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 8fbebb5e..37566d5d 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -183,12 +183,14 @@ namespace detail { bool clean = !fc::exists(_data_dir / "blockchain/dblock"); fc::create_directories(_data_dir / "blockchain/dblock"); - genesis_state_type initial_state; - if( _options->count("genesis-json") ) - initial_state = fc::json::from_file(_options->at("genesis-json").as()) - .as(); - else - initial_state = create_example_genesis(); + auto initial_state = [&] { + ilog("Initializing database..."); + if( _options->count("genesis-json") ) + return fc::json::from_file(_options->at("genesis-json").as()) + .as(); + else + return create_example_genesis(); + }; if( _options->count("resync-blockchain") ) _chain_db->wipe(_data_dir / "blockchain", true); @@ -196,12 +198,12 @@ namespace detail { if( _options->count("replay-blockchain") ) { ilog("Replaying blockchain on user request."); - _chain_db->reindex(_data_dir/"blockchain", initial_state); + _chain_db->reindex(_data_dir/"blockchain", initial_state()); } else if( clean ) _chain_db->open(_data_dir / "blockchain", initial_state); else { wlog("Detected unclean shutdown. Replaying blockchain..."); - _chain_db->reindex(_data_dir / "blockchain", initial_state); + _chain_db->reindex(_data_dir / "blockchain", initial_state()); } if( _options->count("apiaccess") ) @@ -226,13 +228,13 @@ namespace detail { reset_websocket_tls_server(); } FC_CAPTURE_AND_RETHROW() } - optional< api_access_info > get_api_access_info( const string& username )const + optional< api_access_info > get_api_access_info(const string& username)const { optional< api_access_info > result; - auto it = _apiaccess.permission_map.find( username ); + auto it = _apiaccess.permission_map.find(username); if( it == _apiaccess.permission_map.end() ) { - it = _apiaccess.permission_map.find( "*" ); + it = _apiaccess.permission_map.find("*"); if( it == _apiaccess.permission_map.end() ) return result; } @@ -242,7 +244,7 @@ namespace detail { /** * If delegate has the item, the network has no need to fetch it. */ - virtual bool has_item( const net::item_id& id ) override + virtual bool has_item(const net::item_id& id) override { try { @@ -262,7 +264,7 @@ namespace detail { * * @throws exception if error validating the item, otherwise the item is safe to broadcast on. */ - virtual bool handle_block( const graphene::net::block_message& blk_msg, bool sync_mode ) override + virtual bool handle_block(const graphene::net::block_message& blk_msg, bool sync_mode) override { try { ilog("Got block #${n} from network", ("n", blk_msg.block.block_num())); try { @@ -273,7 +275,7 @@ namespace detail { } } FC_CAPTURE_AND_RETHROW( (blk_msg)(sync_mode) ) } - virtual bool handle_transaction( const graphene::net::trx_message& trx_msg, bool sync_mode ) override + virtual bool handle_transaction(const graphene::net::trx_message& trx_msg, bool sync_mode) override { try { ilog("Got transaction from network"); _chain_db->push_transaction( trx_msg.trx ); @@ -328,18 +330,18 @@ namespace detail { /** * Given the hash of the requested data, fetch the body. */ - virtual message get_item( const item_id& id ) override + virtual message get_item(const item_id& id) override { try { ilog("Request for item ${id}", ("id", id)); if( id.item_type == graphene::net::block_message_type ) { - auto opt_block = _chain_db->fetch_block_by_id( id.item_hash ); + auto opt_block = _chain_db->fetch_block_by_id(id.item_hash); if( !opt_block ) elog("Couldn't find block ${id} -- corresponding ID in our chain is ${id2}", ("id", id.item_hash)("id2", _chain_db->get_block_id_for_num(block_header::num_from_id(id.item_hash)))); FC_ASSERT( opt_block.valid() ); ilog("Serving up block #${num}", ("num", opt_block->block_num())); - return block_message( std::move(*opt_block) ); + return block_message(std::move(*opt_block)); } return trx_message( _chain_db->get_recent_transaction( id.item_hash ) ); } FC_CAPTURE_AND_RETHROW( (id) ) } @@ -364,18 +366,18 @@ namespace detail { * &c. * the last item in the list will be the hash of the most recent block on our preferred chain */ - virtual std::vector get_blockchain_synopsis( uint32_t item_type, - const graphene::net::item_hash_t& reference_point, - uint32_t number_of_blocks_after_reference_point ) override + virtual std::vector get_blockchain_synopsis(uint32_t item_type, + const graphene::net::item_hash_t& reference_point, + uint32_t number_of_blocks_after_reference_point) override { try { std::vector result; result.reserve(30); auto head_block_num = _chain_db->head_block_num(); - result.push_back( _chain_db->head_block_id() ); + result.push_back(_chain_db->head_block_id()); auto current = 1; while( current < head_block_num ) { - result.push_back( _chain_db->get_block_id_for_num( head_block_num - current ) ); + result.push_back(_chain_db->get_block_id_for_num(head_block_num - current)); current = current*2; } std::reverse( result.begin(), result.end() ); @@ -390,7 +392,7 @@ namespace detail { * @param item_count the number of items known to the node that haven't been sent to handle_item() yet. * After `item_count` more calls to handle_item(), the node will be in sync */ - virtual void sync_status( uint32_t item_type, uint32_t item_count ) override + virtual void sync_status(uint32_t item_type, uint32_t item_count) override { // any status reports to GUI go here } @@ -398,7 +400,7 @@ namespace detail { /** * Call any time the number of connected peers changes. */ - virtual void connection_count_changed( uint32_t c ) override + virtual void connection_count_changed(uint32_t c) override { // any status reports to GUI go here } diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 52027015..3101c9d0 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -248,7 +248,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) p.parameters.current_fees.set_all_fees(0); }); - create( [&](dynamic_global_property_object& p) { + create([&](dynamic_global_property_object& p) { p.time = genesis_state.initial_timestamp; p.witness_budget = 0; }); diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index 14dbba9d..0dc41e4d 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -20,6 +20,8 @@ #include +#include + namespace graphene { namespace chain { database::database() @@ -33,31 +35,10 @@ database::~database(){ _pending_block_session->commit(); } -void database::open( const fc::path& data_dir, const genesis_state_type& initial_allocation ) -{ try { - object_database::open( data_dir ); - - _block_id_to_block.open(data_dir / "database" / "block_num_to_block"); - - if( !find(global_property_id_type()) ) - { -// ilog( "Init Genesis State" ); - init_genesis(initial_allocation); - } - - _pending_block.previous = head_block_id(); - _pending_block.timestamp = head_block_time(); - - auto last_block= _block_id_to_block.last(); - if( last_block.valid() ) - _fork_db.start_block( *last_block ); - -} FC_CAPTURE_AND_RETHROW( (data_dir) ) } - void database::reindex(fc::path data_dir, const genesis_state_type& initial_allocation) { try { wipe(data_dir, false); - open(data_dir, initial_allocation); + open(data_dir, [&initial_allocation]{return initial_allocation;}); auto start = fc::time_point::now(); auto last_block = _block_id_to_block.last(); @@ -69,13 +50,13 @@ void database::reindex(fc::path data_dir, const genesis_state_type& initial_allo //_undo_db.disable(); for( uint32_t i = 1; i <= last_block_num; ++i ) { - apply_block( *_block_id_to_block.fetch_by_number(i), skip_delegate_signature | + apply_block(*_block_id_to_block.fetch_by_number(i), skip_delegate_signature | skip_transaction_signatures | skip_undo_block | skip_undo_transaction | skip_transaction_dupe_check | skip_tapos_check | - skip_authority_check ); + skip_authority_check); } //_undo_db.enable(); auto end = fc::time_point::now(); diff --git a/libraries/chain/include/graphene/chain/account_object.hpp b/libraries/chain/include/graphene/chain/account_object.hpp index 0e313160..b8ed6712 100644 --- a/libraries/chain/include/graphene/chain/account_object.hpp +++ b/libraries/chain/include/graphene/chain/account_object.hpp @@ -161,7 +161,7 @@ class database; /// The memo key is the key this account will typically use to encrypt/sign transaction memos and other non- /// validated account activities. This field is here to prevent confusion if the active authority has zero or /// multiple keys in it. - public_key_type memo_key; + public_key_type memo_key; /// If this field is set to an account ID other than 0, this account's votes will be ignored and its stake /// will be counted as voting for the referenced account's selected votes instead. account_id_type voting_account; @@ -257,7 +257,7 @@ class database; /** * @brief This secondary index will allow a reverse lookup of all accounts that a particular key or account - * is an potential signing authority. + * is an potential signing authority. */ class account_member_index : public secondary_index { diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 0f06eb89..6d791070 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -93,7 +93,19 @@ namespace graphene { namespace chain { skip_assert_evaluation = 0x400 ///< used while reindexing }; - void open(const fc::path& data_dir, const genesis_state_type& initial_allocation = genesis_state_type()); + /** + * @brief Open a database, creating a new one if necessary + * + * Opens a database in the specified directory. If no initialized database is found, genesis_loader is called + * and its return value is used as the genesis state when initializing the new database + * + * genesis_loader will not be called if an existing database is found. + * + * @param data_dir Path to open or create database in + * @param genesis_loader A callable object which returns the genesis state to initialize new databases on + */ + template + void open(const fc::path& data_dir, F&& genesis_loader); /** * @brief Rebuild object graph from block history and open detabase * @@ -477,4 +489,24 @@ namespace graphene { namespace chain { (void)l; } } + + template + void database::open(const fc::path& data_dir, F&& genesis_loader) + { try { + object_database::open(data_dir); + + _block_id_to_block.open(data_dir / "database" / "block_num_to_block"); + + if( !find(global_property_id_type()) ) + init_genesis(genesis_loader()); + + _pending_block.previous = head_block_id(); + _pending_block.timestamp = head_block_time(); + + auto last_block= _block_id_to_block.last(); + if( last_block.valid() ) + _fork_db.start_block( *last_block ); + + } FC_CAPTURE_AND_RETHROW( (data_dir) ) } + } } diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index c2206243..7c7e69ab 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -286,7 +286,7 @@ void database_fixture::open_database() { if( !data_dir ) { data_dir = fc::temp_directory(); - db.open(data_dir->path(), genesis_state); + db.open(data_dir->path(), [this]{return genesis_state;}); } } diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 69aae949..279cbbc0 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE( generate_empty_blocks ) auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); { database db; - db.open(data_dir.path(), make_genesis() ); + db.open(data_dir.path(), make_genesis ); b = db.generate_block(now, db.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); for( uint32_t i = 1; i < 200; ++i ) @@ -137,25 +137,25 @@ BOOST_AUTO_TEST_CASE( generate_empty_blocks ) BOOST_CHECK( db.head_block_id() == b.id() ); witness_id_type prev_witness = b.witness; now += db.block_interval(); - witness_id_type cur_witness = db.get_scheduled_witness( 1 ).first; + witness_id_type cur_witness = db.get_scheduled_witness(1).first; BOOST_CHECK( cur_witness != prev_witness ); - b = db.generate_block( now, cur_witness, delegate_priv_key, database::skip_nothing ); + b = db.generate_block(now, cur_witness, delegate_priv_key, database::skip_nothing); BOOST_CHECK( b.witness == cur_witness ); } db.close(); } { database db; - db.open(data_dir.path() ); + db.open(data_dir.path(), []{return genesis_state_type();}); BOOST_CHECK_EQUAL( db.head_block_num(), 200 ); for( uint32_t i = 0; i < 200; ++i ) { BOOST_CHECK( db.head_block_id() == b.id() ); witness_id_type prev_witness = b.witness; now += db.block_interval(); - witness_id_type cur_witness = db.get_scheduled_witness( 1 ).first; + witness_id_type cur_witness = db.get_scheduled_witness(1).first; BOOST_CHECK( cur_witness != prev_witness ); - b = db.generate_block( now, cur_witness, delegate_priv_key, database::skip_nothing ); + b = db.generate_block(now, cur_witness, delegate_priv_key, database::skip_nothing); } BOOST_CHECK_EQUAL( db.head_block_num(), 400 ); } @@ -171,7 +171,7 @@ BOOST_AUTO_TEST_CASE( undo_block ) fc::temp_directory data_dir; { database db; - db.open(data_dir.path(), make_genesis() ); + db.open(data_dir.path(), make_genesis); fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); @@ -211,9 +211,9 @@ BOOST_AUTO_TEST_CASE( fork_blocks ) fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); database db1; - db1.open(data_dir1.path(), make_genesis()); + db1.open(data_dir1.path(), make_genesis); database db2; - db2.open(data_dir2.path(), make_genesis()); + db2.open(data_dir2.path(), make_genesis); auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); for( uint32_t i = 0; i < 10; ++i ) @@ -276,7 +276,7 @@ BOOST_AUTO_TEST_CASE( undo_pending ) fc::temp_directory data_dir; { database db; - db.open(data_dir.path(), make_genesis()); + db.open(data_dir.path(), make_genesis); auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); public_key_type delegate_pub_key = delegate_priv_key.get_public_key(); @@ -334,8 +334,8 @@ BOOST_AUTO_TEST_CASE( switch_forks_undo_create ) dir2; database db1, db2; - db1.open(dir1.path(), make_genesis()); - db2.open(dir2.path(), make_genesis()); + db1.open(dir1.path(), make_genesis); + db2.open(dir2.path(), make_genesis); fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); @@ -392,8 +392,8 @@ BOOST_AUTO_TEST_CASE( duplicate_transactions ) dir2; database db1, db2; - db1.open(dir1.path(), make_genesis()); - db2.open(dir2.path(), make_genesis()); + db1.open(dir1.path(), make_genesis); + db2.open(dir2.path(), make_genesis); auto skip_sigs = database::skip_transaction_signatures | database::skip_authority_check; @@ -441,8 +441,8 @@ BOOST_AUTO_TEST_CASE( tapos ) dir2; database db1, db2; - db1.open(dir1.path(), make_genesis()); - db2.open(dir2.path(), make_genesis()); + db1.open(dir1.path(), make_genesis); + db2.open(dir2.path(), make_genesis); const account_object& init1 = *db1.get_index_type().indices().get().find("init1"); @@ -451,7 +451,7 @@ BOOST_AUTO_TEST_CASE( tapos ) const graphene::db::index& account_idx = db1.get_index(protocol_ids, account_object_type); now += db1.block_interval(); - auto b = db1.generate_block( now, db1.get_scheduled_witness( 1 ).first, delegate_priv_key, database::skip_nothing ); + auto b = db1.generate_block(now, db1.get_scheduled_witness( 1 ).first, delegate_priv_key, database::skip_nothing); signed_transaction trx; //This transaction must be in the next block after its reference, or it is invalid. @@ -467,10 +467,6 @@ BOOST_AUTO_TEST_CASE( tapos ) db1.push_transaction(trx); now += db1.block_interval(); b = db1.generate_block(now, db1.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); - /* - now += db1.block_interval(); - b = db1.generate_block(now, db1.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); - */ trx.clear(); trx.operations.push_back(transfer_operation({asset(), account_id_type(), nathan_id, asset(50)})); diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index da81c72d..9d25826f 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -1001,7 +1001,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) genesis_state.initial_accounts.emplace_back("n", n_key.get_public_key()); - db.open(td.path(), genesis_state); + db.open(td.path(), [this]{return genesis_state;}); const balance_object& balance = balance_id_type()(db); BOOST_CHECK_EQUAL(balance.balance.amount.value, 1); BOOST_CHECK_EQUAL(balance_id_type(1)(db).balance.amount.value, 1); From 3f6535343def893acfd71802444b39f8b3bae3c6 Mon Sep 17 00:00:00 2001 From: Vikram Rajkumar Date: Wed, 8 Jul 2015 18:10:16 -0400 Subject: [PATCH 26/28] Fix build --- tests/benchmarks/genesis_allocation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/benchmarks/genesis_allocation.cpp b/tests/benchmarks/genesis_allocation.cpp index 7c3fade4..172f5d38 100644 --- a/tests/benchmarks/genesis_allocation.cpp +++ b/tests/benchmarks/genesis_allocation.cpp @@ -63,7 +63,7 @@ BOOST_AUTO_TEST_CASE( genesis_and_persistence_bench ) { database db; - db.open(data_dir.path(), genesis_state); + db.open(data_dir.path(), [&]{return genesis_state;}); for( int i = 11; i < account_count + 11; ++i) BOOST_CHECK(db.get_balance(account_id_type(i), asset_id_type()).amount == GRAPHENE_MAX_SHARE_SUPPLY / account_count); @@ -76,7 +76,7 @@ BOOST_AUTO_TEST_CASE( genesis_and_persistence_bench ) database db; fc::time_point start_time = fc::time_point::now(); - db.open(data_dir.path()); + db.open(data_dir.path(), [&]{return genesis_state;}); ilog("Opened database in ${t} milliseconds.", ("t", (fc::time_point::now() - start_time).count() / 1000)); for( int i = 11; i < account_count + 11; ++i) From 1023ddee9295df0e773bb5309de53beb1ef17ca1 Mon Sep 17 00:00:00 2001 From: Vikram Rajkumar Date: Wed, 8 Jul 2015 18:00:33 -0400 Subject: [PATCH 27/28] Fix genesis account memo key init; #17 --- libraries/chain/db_init.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 3101c9d0..4c41e357 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -261,11 +261,16 @@ void database::init_genesis(const genesis_state_type& genesis_state) cop.name = account.name; cop.registrar = GRAPHENE_TEMP_ACCOUNT; cop.owner = authority(1, account.owner_key, 1); - if( account.owner_key != account.active_key && account.active_key != public_key_type() ) - cop.active = authority(1, account.active_key, 1); - else + if( account.active_key == public_key_type() ) + { cop.active = cop.owner; - cop.options.memo_key = account.active_key; + cop.options.memo_key = account.owner_key; + } + else + { + cop.active = authority(1, account.active_key, 1); + cop.options.memo_key = account.active_key; + } account_id_type account_id(apply_operation(genesis_eval_state, cop).get()); if( account.is_lifetime_member ) From 629d884b84eee1e7c099695daf0b6f1093646522 Mon Sep 17 00:00:00 2001 From: Vikram Rajkumar Date: Wed, 8 Jul 2015 14:27:37 -0400 Subject: [PATCH 28/28] Share some private keys for testnet balances --- .../include/graphene/chain/genesis_state.hpp | 2 +- testnet-shared-accounts.txt | 50 +++++++++++++++++++ testnet-shared-balances.txt | 41 +++++++++++++++ testnet-shared-private-keys.txt | 10 ++++ 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 testnet-shared-accounts.txt create mode 100644 testnet-shared-balances.txt create mode 100644 testnet-shared-private-keys.txt diff --git a/libraries/chain/include/graphene/chain/genesis_state.hpp b/libraries/chain/include/graphene/chain/genesis_state.hpp index 2721fa95..d8e672db 100644 --- a/libraries/chain/include/graphene/chain/genesis_state.hpp +++ b/libraries/chain/include/graphene/chain/genesis_state.hpp @@ -23,7 +23,7 @@ struct genesis_state_type { string name; public_key_type owner_key; public_key_type active_key; - bool is_lifetime_member; + bool is_lifetime_member = false; }; struct initial_asset_type { string symbol; diff --git a/testnet-shared-accounts.txt b/testnet-shared-accounts.txt new file mode 100644 index 00000000..c3777468 --- /dev/null +++ b/testnet-shared-accounts.txt @@ -0,0 +1,50 @@ + "name": "dummy0", + "owner_key": "BTS6qkMe8pHmQ4zUetLV1bbVKoQJYTNb1fSUbkQzuzpscYhonWpgk", + "active_key": "BTS6qkMe8pHmQ4zUetLV1bbVKoQJYTNb1fSUbkQzuzpscYhonWpgk", + "is_lifetime_member": true + },{ + "name": "dummy1", + "owner_key": "BTS7wXsTzBBR2QEetjrgxcSmN7Kuzey3RAzQWNNHwbPQsKYxkP6fp", + "active_key": "BTS7wXsTzBBR2QEetjrgxcSmN7Kuzey3RAzQWNNHwbPQsKYxkP6fp", + "is_lifetime_member": true + },{ + "name": "dummy2", + "owner_key": "BTS7rzifzfJxS8RWhev9aU8HDYoJi1EGwJRHG9B2fJKxnZAiF2Rsh", + "active_key": "BTS7rzifzfJxS8RWhev9aU8HDYoJi1EGwJRHG9B2fJKxnZAiF2Rsh", + "is_lifetime_member": true + },{ + "name": "dummy3", + "owner_key": "BTS6QZdcwFEFMtHsfW27YBGTv9KLaLTvgx5wgGrPHeUxDTrYEQJ2d", + "active_key": "BTS6QZdcwFEFMtHsfW27YBGTv9KLaLTvgx5wgGrPHeUxDTrYEQJ2d", + "is_lifetime_member": true + },{ + "name": "dummy4", + "owner_key": "BTS7q5MqhSP2a6CRTWaJk77ZcGdpnv14JbT4cVzbXaoAsWJoCxFJG", + "active_key": "BTS7q5MqhSP2a6CRTWaJk77ZcGdpnv14JbT4cVzbXaoAsWJoCxFJG", + "is_lifetime_member": true + },{ + "name": "dummy5", + "owner_key": "BTS5sRXxgDCnteHLUS623xtxJM5WKKVygwDMzEso6LigwxvprJqBA", + "active_key": "BTS5sRXxgDCnteHLUS623xtxJM5WKKVygwDMzEso6LigwxvprJqBA", + "is_lifetime_member": true + },{ + "name": "dummy6", + "owner_key": "BTS5V4HEQJbVbMjUWASeknQ42NT3NP9bZaygt83XMuvy6v4QMJuSP", + "active_key": "BTS5V4HEQJbVbMjUWASeknQ42NT3NP9bZaygt83XMuvy6v4QMJuSP", + "is_lifetime_member": true + },{ + "name": "dummy7", + "owner_key": "BTS86ukuPAufzKouerZf1dCxjVSmxQPA5kLwvnYEjn9GRqi5qXBop", + "active_key": "BTS86ukuPAufzKouerZf1dCxjVSmxQPA5kLwvnYEjn9GRqi5qXBop", + "is_lifetime_member": true + },{ + "name": "dummy8", + "owner_key": "BTS7Sdg3kQuz2pPT8mA8Yr3mkBe7zr6293mnBmoR36z9xxtRdiMmJ", + "active_key": "BTS7Sdg3kQuz2pPT8mA8Yr3mkBe7zr6293mnBmoR36z9xxtRdiMmJ", + "is_lifetime_member": true + },{ + "name": "dummy9", + "owner_key": "BTS5WCj1mMiiqEE4QRs7xhaFfSaiFroejUp3GuZE9wvfue9nxhPPn", + "active_key": "BTS5WCj1mMiiqEE4QRs7xhaFfSaiFroejUp3GuZE9wvfue9nxhPPn", + "is_lifetime_member": true + },{ diff --git a/testnet-shared-balances.txt b/testnet-shared-balances.txt new file mode 100644 index 00000000..dc9061fa --- /dev/null +++ b/testnet-shared-balances.txt @@ -0,0 +1,41 @@ + "initial_balances": [{ + "owner": "BTSHYhQcrjVg5kBzCoeeD38eQdncCC5pBgee", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTSPgQZg5929ht1NBdEvsGKqoQ7buRu3nKf4", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTSC9zrLXSAPUQaVmQPk1S9dMqSzT7jPqYU7", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTS93aQPtbbkXwaSjtHaREsNVcCvbfHo93aZ", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTS6RM4UfsYFPDuhbmgkvDS9ip8Kvqundvyk", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTSNVkZXdqWWSzqHVxvfetMe347is6kEkC4K", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTS5GHzWZ64Luoajqsz6JGjTKVMgWYkGV9SQ", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTSDCVRFez92bW9doRLjnFCKLJnpM58mgmMb", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTS5CCdX3JYLBptYMuCjbsezqGYzN9vG9JCu", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTSEQ3yQdr3EMDL2eRqGiceMCpoanaW16Puw", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ diff --git a/testnet-shared-private-keys.txt b/testnet-shared-private-keys.txt new file mode 100644 index 00000000..e2a8d7dd --- /dev/null +++ b/testnet-shared-private-keys.txt @@ -0,0 +1,10 @@ +5KCNDLVGqvX8p3GcMFun9sMe6XbMvycVTm4bGrkB5aZGWCbAAtr +5HvFQ1bcAWk8H1A2qXj1AqSNp93GUAb6b2w5TVfLb1jWL6yNF3f +5JSxv2kgaBSm9nGseRNhLhgEKTBmoKJ5CkgLbbk5RW4RBCNsLJC +5K5E2TQtrodDFzsqPq3oVFi9rVX15AN8sLE3iTHfVsX1b49y49J +5HxC3fwN7VDZXKVkbbX3SzCczh18Fetx8TXBfJ3z3ovDUSPKvVd +5KSr4w978PDanQDYtftarcfJVvGe4wedYb1sYbdH6HNpi15heRa +5Kan4si6qWvDVpZuqug4c6KQH4zkvDhwspaGQiFKYniJv6qji6t +5KcZri5DDsMcDp1DjNeMkZSijkWurPoAoR7gBKTnnetNQ9CpXoJ +5K5TRZyEhC6GPgi57t5FhiSMRGVTHEbwXngbBEtCA41gM8LPFhF +5KXVG4oP4Vj3RawRpta79UFAg7pWp17FGf4DnrKfkr69ELytDMv