From 6b1b794ff4138b3b0ab8661b7edc18ac8a2249ef Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Tue, 13 Oct 2015 18:19:07 -0400 Subject: [PATCH 1/8] prevent excessive saving of wallet backups --- libraries/wallet/wallet.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 2f6ba926..836c45a0 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2694,11 +2694,12 @@ bool wallet_api::import_account_keys( string filename, string password, string s const auto plain_text = fc::aes_decrypt( password_hash, encrypted_key ); const auto private_key = fc::raw::unpack( plain_text ); - import_key( dest_account_name, string( graphene::utilities::key_to_wif( private_key ) ) ); + my->import_key( dest_account_name, string( graphene::utilities::key_to_wif( private_key ) ) ); } return true; } + save_wallet_file(); FC_ASSERT( found_account ); From 546755484add874700f67aae2cb64b21e3bd30b3 Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Thu, 15 Oct 2015 12:07:44 -0400 Subject: [PATCH 2/8] Fix bug where updated DB version causes crash on restart --- libraries/chain/db_management.cpp | 38 ------------------------------- 1 file changed, 38 deletions(-) diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index 2a1ce4b8..7aa14eae 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -111,31 +111,6 @@ void database::open( { try { - auto is_new = [&]() -> bool - { - // directory doesn't exist - if( !fc::exists( data_dir ) ) - return true; - // if directory exists but is empty, return true; else false. - return ( fc::directory_iterator( data_dir ) == fc::directory_iterator() ); - }; - - auto is_outdated = [&]() -> bool - { - if( !fc::exists( data_dir / "db_version" ) ) - return true; - std::string version_str; - fc::read_file_contents( data_dir / "db_version", version_str ); - return (version_str != GRAPHENE_CURRENT_DB_VERSION); - }; - - if( (!is_new()) && is_outdated() ) - { - ilog( "Old database version detected, reindex is required" ); - wipe( data_dir, false ); - fc::remove_all( data_dir / "db_version" ); - } - object_database::open(data_dir); _block_id_to_block.open(data_dir / "database" / "block_num_to_block"); @@ -153,19 +128,6 @@ void database::open( FC_ASSERT( head_block_num() == 0, "last block ID does not match current chain state" ); } } - - // doing this down here helps ensure that DB will be wiped - // if any of the above steps were interrupted on a previous run - if( !fc::exists( data_dir / "db_version" ) ) - { - std::ofstream db_version( - (data_dir / "db_version").generic_string().c_str(), - std::ios::out | std::ios::binary | std::ios::trunc ); - std::string version_string = GRAPHENE_CURRENT_DB_VERSION; - db_version.write( version_string.c_str(), version_string.size() ); - db_version.close(); - } - //idump((head_block_id())(head_block_num())); } FC_CAPTURE_LOG_AND_RETHROW( (data_dir) ) From 9870b5db0ab2ffb88525342c514087392a4b6098 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Wed, 14 Oct 2015 10:09:31 -0400 Subject: [PATCH 3/8] reflect_util.hpp: Fix reflection, make propose_fee_change work as intended --- .../include/graphene/wallet/reflect_util.hpp | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/libraries/wallet/include/graphene/wallet/reflect_util.hpp b/libraries/wallet/include/graphene/wallet/reflect_util.hpp index 962b0347..5fefd81e 100644 --- a/libraries/wallet/include/graphene/wallet/reflect_util.hpp +++ b/libraries/wallet/include/graphene/wallet/reflect_util.hpp @@ -53,16 +53,34 @@ struct static_variant_map_visitor int which; }; +template< typename StaticVariant > +struct from_which_visitor +{ + typedef StaticVariant result_type; + + template< typename Member > // Member is member of static_variant + result_type operator()( const Member& dummy ) + { + Member result; + from_variant( v, result ); + return result; // converted from StaticVariant to Result automatically due to return type + } + + const variant& v; + + from_which_visitor( const variant& _v ) : v(_v) {} +}; + } // namespace impl template< typename T > T from_which_variant( int which, const variant& v ) { // Parse a variant for a known which() - T result; - result.set_which( which ); - from_variant( v, result ); - return result; + T dummy; + dummy.set_which( which ); + impl::from_which_visitor< T > vtor(v); + return dummy.visit( vtor ); } template From 6b469528a152340ceb779b9740b19f4f1cd1b511 Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Tue, 13 Oct 2015 09:29:48 -0400 Subject: [PATCH 4/8] remove all hardfork checks leftover from testnet --- libraries/chain/asset_evaluator.cpp | 167 +++------------------------- libraries/chain/db_block.cpp | 11 +- libraries/chain/db_init.cpp | 3 - libraries/chain/db_maint.cpp | 7 +- 4 files changed, 18 insertions(+), 170 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index 725ee39a..967f4410 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -30,62 +30,11 @@ namespace graphene { namespace chain { -/** - * Valid symbols can contain [A-Z0-9], and '.' - * They must start with [A, Z] - * They must end with [A, Z] - * They can contain a maximum of one '.' - */ -bool is_valid_symbol_old( const string& symbol ) -{ - if( symbol.size() < GRAPHENE_MIN_ASSET_SYMBOL_LENGTH ) - return false; - - if( symbol.size() > GRAPHENE_MAX_ASSET_SYMBOL_LENGTH ) - return false; - - if( !isalpha( symbol.front() ) ) - return false; - - if( !isalpha( symbol.back() ) ) - return false; - - bool dot_already_present = false; - for( const auto c : symbol ) - { - if( (isalpha( c ) || isdigit(c)) && isupper( c ) ) - continue; - - if( c == '.' ) - { - if( dot_already_present ) - return false; - - dot_already_present = true; - continue; - } - - return false; - } - - return true; -} - void_result asset_create_evaluator::do_evaluate( const asset_create_operation& op ) { try { database& d = db(); -#ifdef _MSC_VER -# pragma message ("WARNING:HARDFORK remove this check after HARDFORK_359_TIME and rename is_valid_symbol_old -> is_valid_symbol") -#else -# warning HARDFORK remove this check after HARDFORK_359_TIME and rename is_valid_symbol_old -> is_valid_symbol -#endif - if( d.head_block_time() <= HARDFORK_359_TIME ) - { - FC_ASSERT( is_valid_symbol_old( op.symbol ) ); - } - const auto& chain_parameters = d.get_global_properties().parameters; FC_ASSERT( op.common_options.whitelist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities ); FC_ASSERT( op.common_options.blacklist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities ); @@ -514,100 +463,25 @@ void_result asset_publish_feeds_evaluator::do_evaluate(const asset_publish_feed_ const asset_bitasset_data_object& bitasset = base.bitasset_data(d); FC_ASSERT( !bitasset.has_settlement(), "No further feeds may be published after a settlement event" ); -#ifdef _MSC_VER -# pragma message ("WARNING: Remove this check when starting a new network") -#else -# warning Remove this check when starting a new network -#endif - if( d.head_block_time() <= HARDFORK_357_TIME ) + // + // many of these checks should be moved to price_feed.validate() + // or the operation validator when new network is started + // + if( !o.feed.core_exchange_rate.is_null() ) { - FC_ASSERT(o.feed.settlement_price.quote.asset_id == bitasset.options.short_backing_asset); - - try - { - // these two changes should go in price_feed::validate() when creating new network - if( !o.feed.core_exchange_rate.is_null() ) - { - o.feed.core_exchange_rate.validate(); - } - if( (!o.feed.settlement_price.is_null()) && (!o.feed.core_exchange_rate.is_null()) ) - { - if( o.feed.settlement_price.base.asset_id == o.feed.core_exchange_rate.base.asset_id ) - { - // uncrossed feed, this is the form we expect - FC_ASSERT( o.feed.settlement_price.base.asset_id == o.feed.core_exchange_rate.base.asset_id ); - FC_ASSERT( o.feed.settlement_price.quote.asset_id == o.feed.core_exchange_rate.quote.asset_id ); - } - else - { - // crossed feed, your feed script needs to be fixed - FC_ASSERT( o.feed.settlement_price.base.asset_id == o.feed.core_exchange_rate.quote.asset_id ); - FC_ASSERT( o.feed.settlement_price.quote.asset_id == o.feed.core_exchange_rate.base.asset_id ); - /* - wlog( "${aname} feed pub with crossed prices by ${name} in block ${n}", - ("aname", base.symbol) - ("n", d.head_block_num()+1) - ("name", o.publisher(d).name) - ); - */ - } - } - - if( !o.feed.is_for( o.asset_id ) ) - { - wlog( "${aname} feed pub with wrong asset by ${name} in block ${n}", - ("aname", base.symbol) - ("n", d.head_block_num()+1) - ("name", o.publisher(d).name) - ); - } - } - catch( const fc::exception& e ) - { - wlog( "${aname} feed pub with invalid price feed by ${name} in block ${n}", - ("aname", base.symbol) - ("n", d.head_block_num()+1) - ("name", o.publisher(d).name) - ); - wdump( (e) ); - } - -#ifdef _MSC_VER -# pragma message ("WARNING: Remove this check when starting a new network") -#else -# warning Remove this check when starting a new network -#endif - if( d.head_block_num() > 59300 ) - { - FC_ASSERT( - (base.symbol != "SEK") - && (base.symbol != "SILVER") - && (base.symbol != "RUB") - && (base.symbol != "GBP") - ); - } + o.feed.core_exchange_rate.validate(); } - else + if( (!o.feed.settlement_price.is_null()) && (!o.feed.core_exchange_rate.is_null()) ) { - // - // many of these checks should be moved to price_feed.validate() - // or the operation validator when new network is started - // - if( !o.feed.core_exchange_rate.is_null() ) - { - o.feed.core_exchange_rate.validate(); - } - if( (!o.feed.settlement_price.is_null()) && (!o.feed.core_exchange_rate.is_null()) ) - { - FC_ASSERT( o.feed.settlement_price.base.asset_id == o.feed.core_exchange_rate.base.asset_id ); - FC_ASSERT( o.feed.settlement_price.quote.asset_id == o.feed.core_exchange_rate.quote.asset_id ); - } - - FC_ASSERT( !o.feed.settlement_price.is_null() ); - FC_ASSERT( !o.feed.core_exchange_rate.is_null() ); - FC_ASSERT( o.feed.settlement_price.quote.asset_id == bitasset.options.short_backing_asset ); - FC_ASSERT( o.feed.is_for( o.asset_id ) ); + FC_ASSERT( o.feed.settlement_price.base.asset_id == o.feed.core_exchange_rate.base.asset_id ); + FC_ASSERT( o.feed.settlement_price.quote.asset_id == o.feed.core_exchange_rate.quote.asset_id ); } + + FC_ASSERT( !o.feed.settlement_price.is_null() ); + FC_ASSERT( !o.feed.core_exchange_rate.is_null() ); + FC_ASSERT( o.feed.settlement_price.quote.asset_id == bitasset.options.short_backing_asset ); + FC_ASSERT( o.feed.is_for( o.asset_id ) ); + //Verify that the publisher is authoritative to publish a feed if( base.options.flags & witness_fed_asset ) { @@ -628,17 +502,6 @@ void_result asset_publish_feeds_evaluator::do_evaluate(const asset_publish_feed_ void_result asset_publish_feeds_evaluator::do_apply(const asset_publish_feed_operation& o) { try { -#ifdef _MSC_VER -# pragma message ("WARNING: Remove this check when preparing for new network release") -#else -# warning Remove this check when preparing for new network release -#endif - if( !o.feed.is_for( o.asset_id ) ) - { - wlog( "Ignoring bad feed" ); - return void_result(); - } - database& d = db(); const asset_object& base = o.asset_id(d); diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 6aafdf2a..24549246 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -647,15 +647,8 @@ const witness_object& database::validate_block_header( uint32_t skip, const sign witness_id_type scheduled_witness = get_scheduled_witness( slot_num ); -#ifdef _MSC_VER -# pragma message ("WARNING: remove this hardfork check for next release") -#else -# warning remove this hardfork check for next release -#endif - if( next_block.block_num() > 58500 ) { - FC_ASSERT( next_block.witness == scheduled_witness, "Witness produced block at wrong time", - ("block witness",next_block.witness)("scheduled",scheduled_witness)("slot_num",slot_num) ); - } + FC_ASSERT( next_block.witness == scheduled_witness, "Witness produced block at wrong time", + ("block witness",next_block.witness)("scheduled",scheduled_witness)("slot_num",slot_num) ); } return witness; diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index e27add8a..2d06aa94 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -502,9 +502,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) a.options.description = asset.description; a.precision = asset.precision; string issuer_name = asset.issuer_name; -#warning Remove this check doing real network, change BitAsset owners to be committee-account in genesis. - if( issuer_name == "witness-account" ) - issuer_name = "committee-account"; a.issuer = get_account_id(issuer_name); a.options.max_supply = asset.max_supply; a.options.flags = witness_fed_asset; diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 69a04892..807254a9 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -63,12 +63,7 @@ vector> database::sort template void database::perform_account_maintenance(std::tuple helpers) { -#ifdef _MSC_VER -# pragma message ("WARNING: switch to this for next release: const auto& idx = get_index_type().indices().get();") -#else -# warning switch to this for next release: const auto& idx = get_index_type().indices().get(); -#endif - const auto& idx = get_index_type().indices(); + const auto& idx = get_index_type().indices().get(); for( const account_object& a : idx ) detail::for_each(helpers, a, detail::gen_seq()); } From 704f943181ba114bd1f5aba68a585dbc2d62bec8 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Thu, 15 Oct 2015 17:53:19 -0400 Subject: [PATCH 5/8] address.cpp: Don't special-case BTS prefix --- libraries/chain/protocol/address.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/chain/protocol/address.cpp b/libraries/chain/protocol/address.cpp index 3526969a..a7beb1de 100644 --- a/libraries/chain/protocol/address.cpp +++ b/libraries/chain/protocol/address.cpp @@ -39,10 +39,6 @@ namespace graphene { bool address::is_valid( const std::string& base58str, const std::string& prefix ) { - // TODO: This is temporary for testing - if( prefix == GRAPHENE_ADDRESS_PREFIX && is_valid( base58str, "BTS" ) ) - return true; - const size_t prefix_len = prefix.size(); if( base58str.size() <= prefix_len ) return false; From 0e41933003385902e6f5640eab3c4bd88a6954eb Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Thu, 15 Oct 2015 17:59:46 -0400 Subject: [PATCH 6/8] asset_evaluator.cpp: Implement TODO, move feed validation checks from evaluate() to validate() --- libraries/chain/asset_evaluator.cpp | 17 ----------------- libraries/chain/protocol/asset_ops.cpp | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index 967f4410..10770624 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -463,24 +463,7 @@ void_result asset_publish_feeds_evaluator::do_evaluate(const asset_publish_feed_ const asset_bitasset_data_object& bitasset = base.bitasset_data(d); FC_ASSERT( !bitasset.has_settlement(), "No further feeds may be published after a settlement event" ); - // - // many of these checks should be moved to price_feed.validate() - // or the operation validator when new network is started - // - if( !o.feed.core_exchange_rate.is_null() ) - { - o.feed.core_exchange_rate.validate(); - } - if( (!o.feed.settlement_price.is_null()) && (!o.feed.core_exchange_rate.is_null()) ) - { - FC_ASSERT( o.feed.settlement_price.base.asset_id == o.feed.core_exchange_rate.base.asset_id ); - FC_ASSERT( o.feed.settlement_price.quote.asset_id == o.feed.core_exchange_rate.quote.asset_id ); - } - - FC_ASSERT( !o.feed.settlement_price.is_null() ); - FC_ASSERT( !o.feed.core_exchange_rate.is_null() ); FC_ASSERT( o.feed.settlement_price.quote.asset_id == bitasset.options.short_backing_asset ); - FC_ASSERT( o.feed.is_for( o.asset_id ) ); //Verify that the publisher is authoritative to publish a feed if( base.options.flags & witness_fed_asset ) diff --git a/libraries/chain/protocol/asset_ops.cpp b/libraries/chain/protocol/asset_ops.cpp index 87d3cec7..b73a0b82 100644 --- a/libraries/chain/protocol/asset_ops.cpp +++ b/libraries/chain/protocol/asset_ops.cpp @@ -127,6 +127,21 @@ void asset_publish_feed_operation::validate()const { FC_ASSERT( fee.amount >= 0 ); feed.validate(); + + // maybe some of these could be moved to feed.validate() + if( !feed.core_exchange_rate.is_null() ) + { + feed.core_exchange_rate.validate(); + } + if( (!feed.settlement_price.is_null()) && (!feed.core_exchange_rate.is_null()) ) + { + FC_ASSERT( feed.settlement_price.base.asset_id == feed.core_exchange_rate.base.asset_id ); + FC_ASSERT( feed.settlement_price.quote.asset_id == feed.core_exchange_rate.quote.asset_id ); + } + + FC_ASSERT( !feed.settlement_price.is_null() ); + FC_ASSERT( !feed.core_exchange_rate.is_null() ); + FC_ASSERT( feed.is_for( asset_id ) ); } void asset_reserve_operation::validate()const From 5cd73f5683721e179e923256f7bc84f808cbbd77 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 20 Oct 2015 11:16:57 -0400 Subject: [PATCH 7/8] account_object.cpp: Get rid of no-ops --- libraries/chain/account_object.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/libraries/chain/account_object.cpp b/libraries/chain/account_object.cpp index 80ae9e68..79729638 100644 --- a/libraries/chain/account_object.cpp +++ b/libraries/chain/account_object.cpp @@ -97,17 +97,11 @@ void account_statistics_object::process_fees(const account_object& a, database& assert( referrer_cut + registrar_cut + accumulated + reserveed + lifetime_cut == core_fee_total ); }; - share_type vesting_fee_subtotal(pending_fees); - share_type vested_fee_subtotal(pending_vested_fees); - share_type vesting_cashback, vested_cashback; + pay_out_fees(a, pending_fees, true); + pay_out_fees(a, pending_vested_fees, false); - pay_out_fees(a, vesting_fee_subtotal, true); - d.deposit_cashback(a, vesting_cashback, true); - pay_out_fees(a, vested_fee_subtotal, false); - d.deposit_cashback(a, vested_cashback, false); - - d.modify(*this, [vested_fee_subtotal, vesting_fee_subtotal](account_statistics_object& s) { - s.lifetime_fees_paid += vested_fee_subtotal + vesting_fee_subtotal; + d.modify(*this, [&](account_statistics_object& s) { + s.lifetime_fees_paid += pending_fees + pending_vested_fees; s.pending_fees = 0; s.pending_vested_fees = 0; }); From 4c09d6b8ed350ff5c7546e2c3fd15d0e6699daf2 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 20 Oct 2015 11:17:21 -0400 Subject: [PATCH 8/8] cli_wallet: Implement worker creation and voting --- .../wallet/include/graphene/wallet/wallet.hpp | 52 +++++++ libraries/wallet/wallet.cpp | 138 ++++++++++++++++++ 2 files changed, 190 insertions(+) diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 2d53e32d..aec9c63a 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -216,6 +216,13 @@ struct approval_delta vector key_approvals_to_remove; }; +struct worker_vote_delta +{ + flat_set vote_for; + flat_set vote_against; + flat_set vote_abstain; +}; + struct signed_block_with_info : public signed_block { signed_block_with_info( const signed_block& block ); @@ -1124,6 +1131,43 @@ class wallet_api string block_signing_key, bool broadcast = false); + + /** + * Create a worker object. + * + * @param owner_account The account which owns the worker and will be paid + * @param work_begin_date When the work begins + * @param work_end_date When the work ends + * @param daily_pay Amount of pay per day (NOT per maint interval) + * @param name Any text + * @param url Any text + * @param worker_settings {"type" : "burn"|"refund"|"vesting", "pay_vesting_period_days" : x} + * @param broadcast true if you wish to broadcast the transaction. + */ + signed_transaction create_worker( + string owner_account, + time_point_sec work_begin_date, + time_point_sec work_end_date, + share_type daily_pay, + string name, + string url, + variant worker_settings, + bool broadcast = false + ); + + /** + * Update your votes for a worker + * + * @param account The account which will pay the fee and update votes. + * @param worker_vote_delta {"vote_for" : [...], "vote_against" : [...], "vote_abstain" : [...]} + * @param broadcast true if you wish to broadcast the transaction. + */ + signed_transaction update_worker_votes( + string account, + worker_vote_delta delta, + bool broadcast = false + ); + /** * Get information about a vesting balance object. * @@ -1380,6 +1424,12 @@ FC_REFLECT( graphene::wallet::approval_delta, (key_approvals_to_remove) ) +FC_REFLECT( graphene::wallet::worker_vote_delta, + (vote_for) + (vote_against) + (vote_abstain) +) + FC_REFLECT_DERIVED( graphene::wallet::signed_block_with_info, (graphene::chain::signed_block), (block_id)(signing_key) ) @@ -1440,6 +1490,8 @@ FC_API( graphene::wallet::wallet_api, (list_committee_members) (create_witness) (update_witness) + (create_worker) + (update_worker_votes) (get_vesting_balances) (withdraw_vesting) (vote_for_committee_member) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 836c45a0..8880a6fc 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1407,6 +1407,122 @@ public: return sign_transaction( tx, broadcast ); } FC_CAPTURE_AND_RETHROW( (witness_name)(url)(block_signing_key)(broadcast) ) } + template + static WorkerInit _create_worker_initializer( const variant& worker_settings ) + { + WorkerInit result; + from_variant( worker_settings, result ); + return result; + } + + signed_transaction create_worker( + string owner_account, + time_point_sec work_begin_date, + time_point_sec work_end_date, + share_type daily_pay, + string name, + string url, + variant worker_settings, + bool broadcast + ) + { + worker_initializer init; + std::string wtype = worker_settings["type"].get_string(); + + // TODO: Use introspection to do this dispatch + if( wtype == "burn" ) + init = _create_worker_initializer< burn_worker_initializer >( worker_settings ); + else if( wtype == "refund" ) + init = _create_worker_initializer< refund_worker_initializer >( worker_settings ); + else if( wtype == "vesting" ) + init = _create_worker_initializer< vesting_balance_worker_initializer >( worker_settings ); + else + { + FC_ASSERT( false, "unknown worker[\"type\"] value" ); + } + + worker_create_operation op; + op.owner = get_account( owner_account ).id; + op.work_begin_date = work_begin_date; + op.work_end_date = work_end_date; + op.daily_pay = daily_pay; + op.name = name; + op.url = url; + op.initializer = init; + + signed_transaction tx; + tx.operations.push_back( op ); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees ); + tx.validate(); + + return sign_transaction( tx, broadcast ); + } + + signed_transaction update_worker_votes( + string account, + worker_vote_delta delta, + bool broadcast + ) + { + account_object acct = get_account( account ); + account_update_operation op; + + // you could probably use a faster algorithm for this, but flat_set is fast enough :) + flat_set< worker_id_type > merged; + merged.reserve( delta.vote_for.size() + delta.vote_against.size() + delta.vote_abstain.size() ); + for( const worker_id_type& wid : delta.vote_for ) + { + bool inserted = merged.insert( wid ).second; + FC_ASSERT( inserted, "worker ${wid} specified multiple times", ("wid", wid) ); + } + for( const worker_id_type& wid : delta.vote_against ) + { + bool inserted = merged.insert( wid ).second; + FC_ASSERT( inserted, "worker ${wid} specified multiple times", ("wid", wid) ); + } + for( const worker_id_type& wid : delta.vote_abstain ) + { + bool inserted = merged.insert( wid ).second; + FC_ASSERT( inserted, "worker ${wid} specified multiple times", ("wid", wid) ); + } + + // should be enforced by FC_ASSERT's above + assert( merged.size() == delta.vote_for.size() + delta.vote_against.size() + delta.vote_abstain.size() ); + + vector< object_id_type > query_ids; + for( const worker_id_type& wid : merged ) + query_ids.push_back( wid ); + + flat_set new_votes( acct.options.votes ); + + fc::variants objects = _remote_db->get_objects( query_ids ); + for( const variant& obj : objects ) + { + worker_object wo; + from_variant( obj, wo ); + new_votes.erase( wo.vote_for ); + new_votes.erase( wo.vote_against ); + if( delta.vote_for.find( wo.id ) != delta.vote_for.end() ) + new_votes.insert( wo.vote_for ); + else if( delta.vote_against.find( wo.id ) != delta.vote_against.end() ) + new_votes.insert( wo.vote_against ); + else + assert( delta.vote_abstain.find( wo.id ) != delta.vote_abstain.end() ); + } + + account_update_operation update_op; + update_op.account = acct.id; + update_op.new_options = acct.options; + update_op.new_options->votes = new_votes; + + signed_transaction tx; + tx.operations.push_back( update_op ); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees ); + tx.validate(); + + return sign_transaction( tx, broadcast ); + } + vector< vesting_balance_object_with_info > get_vesting_balances( string account_name ) { try { fc::optional vbid = maybe_id( account_name ); @@ -2864,6 +2980,28 @@ signed_transaction wallet_api::create_witness(string owner_account, return my->create_witness(owner_account, url, broadcast); } +signed_transaction wallet_api::create_worker( + string owner_account, + time_point_sec work_begin_date, + time_point_sec work_end_date, + share_type daily_pay, + string name, + string url, + variant worker_settings, + bool broadcast /* = false */) +{ + return my->create_worker( owner_account, work_begin_date, work_end_date, + daily_pay, name, url, worker_settings, broadcast ); +} + +signed_transaction wallet_api::update_worker_votes( + string owner_account, + worker_vote_delta delta, + bool broadcast /* = false */) +{ + return my->update_worker_votes( owner_account, delta, broadcast ); +} + signed_transaction wallet_api::update_witness( string witness_name, string url,