diff --git a/CMakeLists.txt b/CMakeLists.txt index daacda9a0c5..e49f6dd0907 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 2) set(VERSION_MINOR 0) -set(VERSION_PATCH 2) +set(VERSION_PATCH 3) if(VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") @@ -126,6 +126,11 @@ FIND_PACKAGE(Boost 1.67 REQUIRED COMPONENTS locale iostreams) +# Some new stdlibc++s will #error on ; a problem for boost pre-1.69 +if( APPLE AND UNIX ) + add_definitions(-DBOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +endif() + if( WIN32 ) message( STATUS "Configuring EOSIO on WIN32") diff --git a/Docker/README.md b/Docker/README.md index 5be2cbe6a1f..b5228e17bbc 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -20,10 +20,10 @@ cd bos/Docker docker build . -t boscore/bos -s BOS ``` -The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v2.0.2 tag, you could do the following: +The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v2.0.3 tag, you could do the following: ```bash -docker build -t boscore/bos:v2.0.2 --build-arg branch=v2.0.2 . +docker build -t boscore/bos:v2.0.3 --build-arg branch=v2.0.3 . ``` @@ -198,4 +198,6 @@ The `blocks` data are stored under `--data-dir` by default, and the wallet files ### About MongoDB Plugin -Currently, the mongodb plugin is disabled in `config.ini` by default, you have to change it manually in `config.ini` or you can mount a `config.ini` file to `/opt/eosio/bin/data-dir/config.ini` in the docker-compose file. \ No newline at end of file +Currently, the mongodb plugin is disabled in `config.ini` by default, you have to change it manually in `config.ini` or you can mount a `config.ini` file to `/opt/eosio/bin/data-dir/config.ini` in the docker-compose file. + + diff --git a/README.md b/README.md index 5b750a0c335..0b90a01c333 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # BOSCore - Born for DApps. Born for Usability. -## BOSCore Version: v2.0.2 -### Basic EOSIO Version: v1.6.2 +## BOSCore Version: v2.0.3 +### Basic EOSIO Version: v1.6.4 (support REX) # Background The emergence of EOS has brought new imagination to the blockchain. In just a few months since the main network was launched, the version has undergone dozens of upgrades, not only the stability has been greatly improved, but also the new functions have been gradually realized. The node team is also actively involved in building the EOSIO ecosystem. What is even more exciting is that EOS has attracted more and more development teams. There are already hundreds of DApp running on the EOS main network. The transaction volume and circulation market value far exceed Ethereum, and the space for development is growing broader. @@ -23,21 +23,11 @@ As BOS continues to develop, developer rewards will be appropriately adjusted to 2. [Developer Telegram Group](https://t.me/BOSDevelopers) 3. [Community Telegram Group](https://t.me/boscorecommunity) 4. [WhitePaper](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper.md) -5. [白皮书](https://github.com/boscore/Documentation/blob/master/zh-CN/BOSCoreTechnicalWhitePaper.md) +5. [白皮书](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper_zh.md) ## Start 1. Build from code : `bash ./eosio_build.sh -s BOS` 2. Docker Style,check [Docker](./Docker/README.md) -3. Mac OS X Brew install and uninstall -#### Mac OS X Brew Install -```sh -$ brew tap boscore/bos -$ brew install bos -``` -#### Mac OS X Brew Uninstall -```sh -$ brew remove bos -``` ## BOSCore Workflow BOSCore encourage community developer actively participate in contributing the code, members should follow the workflow below. @@ -65,3 +55,5 @@ BOSCore bases on EOSIO, so you can also referer: [EOSIO Developer Portal](https://developers.eos.io). + + diff --git a/README_CN.md b/README_CN.md index e5f71c517eb..23b9199068f 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,7 +1,7 @@ # BOSCore - 更可用的链,为DApp而生。 -## BOSCore Version: v2.0.2 -### Basic EOSIO Version: v1.6.2 +## BOSCore Version: v2.0.3 +### Basic EOSIO Version: v1.6.4 (support REX) # 背景 EOS的出现给区块链带来了新的想象力,主网启动短短几个月以来,版本经历了几十次升级,不仅稳定性得到了很大提高,并且新功能也逐步实现,各个节点团队也积极参与建设EOSIO生态。让人更加兴奋的是,EOS已经吸引了越来越多的开发团队,当前已经有数百个DApp在EOS主网上面运行,其交易量和流通市值远超以太坊,可发展的空间愈来愈广阔。 @@ -23,21 +23,11 @@ BOS链的代码完全由社区贡献并维护,每个生态参与者都可以 2. [Developer Telegram Group](https://t.me/BOSDevelopers) 3. [Community Telegram Group](https://t.me/boscorecommunity) 4. [WhitePaper](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper.md) -5. [白皮书](https://github.com/boscore/Documentation/blob/master/zh-CN/BOSCoreTechnicalWhitePaper.md) +5. [白皮书](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper_zh.md) ## 开始 1. 源码直接编译: `bash ./eosio_build.sh -s BOS` 2. Docker方式部署,参看 [Docker](./Docker/README.md) -3. Mac OS X Brew 安装 和 卸载 -#### Mac OS X Brew 安装 -```sh -$ brew tap boscore/bos -$ brew install bos -``` -#### Mac OS X Brew 卸载 -```sh -$ brew remove bos -``` ## BOSCore 开发流程 BOSCore 鼓励社区开发者参与代码贡献,社区成员应当遵循以下工作流: @@ -65,3 +55,4 @@ BOSCore是基于EOSIO技术的扩展,所以EOSIO的相关资料也可以参考 [EOSIO 开发者门户](https://developers.eos.io). + diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 72975fd4bf9..2a5581a1c20 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -430,14 +430,7 @@ struct controller_impl { void clear_all_undo() { // Rewind the database to the last irreversible block - db.with_write_lock([&] { - db.undo_all(); - /* - FC_ASSERT(db.revision() == self.head_block_num(), - "Chainbase revision does not match head block num", - ("rev", db.revision())("head_block", self.head_block_num())); - */ - }); + db.undo_all(); } void add_contract_tables_to_snapshot( const snapshot_writer_ptr& snapshot ) const { @@ -1149,6 +1142,9 @@ struct controller_impl { transaction_trace_ptr trace; try { auto start = fc::time_point::now(); + const bool check_auth = !self.skip_auth_check() && !trx->implicit; + // call recover keys so that trx->sig_cpu_usage is set correctly + const flat_set& recovered_keys = check_auth ? trx->recover_keys( chain_id ) : flat_set(); if( !explicit_billed_cpu_time ) { fc::microseconds already_consumed_time( EOS_PERCENT(trx->sig_cpu_usage.count(), conf.sig_cpu_bill_pct) ); @@ -1180,15 +1176,13 @@ struct controller_impl { } trx_context.delay = fc::seconds(trn.delay_sec); - if( !self.skip_auth_check() && !trx->implicit ) { + if( check_auth ) { authorization.check_authorization( trn.actions, - trx->recover_keys( chain_id ), + recovered_keys, {}, trx_context.delay, - [](){} - /*std::bind(&transaction_context::add_cpu_usage_and_check_time, &trx_context, - std::placeholders::_1)*/, + [&trx_context](){ trx_context.checktime(); }, false ); } @@ -1945,6 +1939,7 @@ void controller::abort_block() { boost::asio::thread_pool& controller::get_thread_pool() { return my->thread_pool; + } std::future controller::create_block_state_future( const signed_block_ptr& b ) { diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 889eefb9ed0..8161a7119cf 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -593,9 +593,6 @@ namespace eosio { const string peer_name(); - void txn_send_pending(const vector& ids); - void txn_send(const vector& txn_lis); - void blk_send_branch(); void blk_send(const block_id_type& blkid); void stop_send(); @@ -742,6 +739,7 @@ namespace eosio { void rejected_block(const block_id_type& id); void recv_block(const connection_ptr& conn, const block_id_type& msg, uint32_t bnum); + void expire_blocks( uint32_t bnum ); void recv_transaction(const connection_ptr& conn, const transaction_id_type& id); void recv_notice(const connection_ptr& conn, const notice_message& msg, bool generated); @@ -848,27 +846,6 @@ namespace eosio { fc_dlog(logger, "canceling wait on ${p}", ("p",peer_name())); cancel_wait(); if( read_delay_timer ) read_delay_timer->cancel(); - pending_message_buffer.reset(); - } - - void connection::txn_send_pending(const vector& ids) { - const std::set known_ids(ids.cbegin(), ids.cend()); - my_impl->expire_local_txns(); - for(auto tx = my_impl->local_txns.begin(); tx != my_impl->local_txns.end(); ++tx ){ - const bool found = known_ids.find( tx->id ) != known_ids.cend(); - if( !found ) { - queue_write( tx->serialized_txn, true, []( boost::system::error_code ec, std::size_t ) {} ); - } - } - } - - void connection::txn_send(const vector& ids) { - for(const auto& t : ids) { - auto tx = my_impl->local_txns.get().find(t); - if( tx != my_impl->local_txns.end() ) { - queue_write( tx->serialized_txn, true, []( boost::system::error_code ec, std::size_t ) {} ); - } - } } void connection::blk_send_branch() { @@ -1697,11 +1674,23 @@ namespace eosio { } void dispatch_manager::rejected_block(const block_id_type& id) { - fc_dlog(logger,"not sending rejected transaction ${tid}",("tid",id)); + fc_dlog( logger, "rejected block ${id}", ("id", id) ); auto range = received_blocks.equal_range(id); received_blocks.erase(range.first, range.second); } + void dispatch_manager::expire_blocks( uint32_t lib_num ) { + for( auto i = received_blocks.begin(); i != received_blocks.end(); ) { + const block_id_type& blk_id = i->first; + uint32_t blk_num = block_header::num_from_id( blk_id ); + if( blk_num <= lib_num ) { + i = received_blocks.erase( i ); + } else { + ++i; + } + } + } + void dispatch_manager::bcast_transaction(const transaction_metadata_ptr& ptrx) { std::set skips; const auto& id = ptrx->id; @@ -1926,6 +1915,7 @@ namespace eosio { auto current_endpoint = *endpoint_itr; ++endpoint_itr; c->connecting = true; + c->pending_message_buffer.reset(); connection_wptr weak_conn = c; c->socket->async_connect( current_endpoint, [weak_conn, endpoint_itr, this] ( const boost::system::error_code& err ) { auto c = weak_conn.lock(); @@ -2129,7 +2119,7 @@ namespace eosio { conn->pending_message_buffer.get_buffer_sequence_for_boost_async_read(), completion_handler, [this,weak_conn]( boost::system::error_code ec, std::size_t bytes_transferred ) { auto conn = weak_conn.lock(); - if (!conn) { + if (!conn || !conn->socket || !conn->socket->is_open()) { return; } @@ -2490,17 +2480,6 @@ namespace eosio { break; } case catch_up : { - if( msg.known_trx.pending > 0) { - // plan to get all except what we already know about. - req.req_trx.mode = catch_up; - send_req = true; - size_t known_sum = local_txns.size(); - if( known_sum ) { - for( const auto& t : local_txns.get() ) { - req.req_trx.ids.push_back( t.id ); - } - } - } break; } case normal: { @@ -2558,14 +2537,17 @@ namespace eosio { switch (msg.req_trx.mode) { case catch_up : - c->txn_send_pending(msg.req_trx.ids); - break; - case normal : - c->txn_send(msg.req_trx.ids); break; case none : if(msg.req_blocks.mode == none) c->stop_send(); + // no break + case normal : + if( !msg.req_trx.ids.empty() ) { + elog( "Invalid request_message, req_trx.ids.size ${s}", ("s", msg.req_trx.ids.size()) ); + close(c); + return; + } break; default:; } @@ -2693,6 +2675,7 @@ namespace eosio { } else { sync_master->rejected_block(c, blk_num); + dispatcher->rejected_block( blk_id ); } } @@ -2754,6 +2737,7 @@ namespace eosio { controller& cc = chain_plug->chain(); uint32_t lib = cc.last_irreversible_block_num(); + dispatcher->expire_blocks( lib ); for ( auto &c : connections ) { auto &stale_txn = c->trx_state.get(); stale_txn.erase( stale_txn.lower_bound(1), stale_txn.upper_bound(lib) ); diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index e1047613e24..f0ac7a53937 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -438,9 +438,11 @@ bytes json_or_file_to_bin( const account_name& account, const action_name& actio void print_action_tree( const fc::variant& action ) { print_action( action ); - const auto& inline_traces = action["inline_traces"].get_array(); - for( const auto& t : inline_traces ) { - print_action_tree( t ); + if( action.get_object().contains( "inline_traces" ) ) { + const auto& inline_traces = action["inline_traces"].get_array(); + for( const auto& t : inline_traces ) { + print_action_tree( t ); + } } } @@ -448,12 +450,13 @@ void print_result( const fc::variant& result ) { try { if (result.is_object() && result.get_object().contains("processed")) { const auto& processed = result["processed"]; const auto& transaction_id = processed["id"].as_string(); - string status = processed["receipt"].is_object() ? processed["receipt"]["status"].as_string() : "failed"; + string status = "failed"; int64_t net = -1; int64_t cpu = -1; if( processed.get_object().contains( "receipt" )) { const auto& receipt = processed["receipt"]; if( receipt.is_object()) { + status = receipt["status"].as_string(); net = receipt["net_usage_words"].as_int64() * 8; cpu = receipt["cpu_usage_us"].as_int64(); } @@ -1616,6 +1619,405 @@ struct canceldelay_subcommand { } }; +struct deposit_subcommand { + string owner_str; + string amount_str; + const name act_name{ N(deposit) }; + + deposit_subcommand(CLI::App* actionRoot) { + auto deposit = actionRoot->add_subcommand("deposit", localized("Deposit into owner's REX fund by transfering from owner's liquid token balance")); + deposit->add_option("owner", owner_str, localized("Account which owns the REX fund"))->required(); + deposit->add_option("amount", amount_str, localized("Amount to be deposited into REX fund"))->required(); + add_standard_transaction_options(deposit, "owner@active"); + deposit->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("owner", owner_str) + ("amount", amount_str); + auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct withdraw_subcommand { + string owner_str; + string amount_str; + const name act_name{ N(withdraw) }; + + withdraw_subcommand(CLI::App* actionRoot) { + auto withdraw = actionRoot->add_subcommand("withdraw", localized("Withdraw from owner's REX fund by transfering to owner's liquid token balance")); + withdraw->add_option("owner", owner_str, localized("Account which owns the REX fund"))->required(); + withdraw->add_option("amount", amount_str, localized("Amount to be withdrawn from REX fund"))->required(); + add_standard_transaction_options(withdraw, "owner@active"); + withdraw->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("owner", owner_str) + ("amount", amount_str); + auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct buyrex_subcommand { + string from_str; + string amount_str; + const name act_name{ N(buyrex) }; + + buyrex_subcommand(CLI::App* actionRoot) { + auto buyrex = actionRoot->add_subcommand("buyrex", localized("Buy REX using tokens in owner's REX fund")); + buyrex->add_option("from", from_str, localized("Account buying REX tokens"))->required(); + buyrex->add_option("amount", amount_str, localized("Amount to be taken from REX fund and used in buying REX"))->required(); + add_standard_transaction_options(buyrex, "from@active"); + buyrex->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("from", from_str) + ("amount", amount_str); + auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct lendrex_subcommand { + string from_str; + string amount_str; + const name act_name1{ N(deposit) }; + const name act_name2{ N(buyrex) }; + + lendrex_subcommand(CLI::App* actionRoot) { + auto lendrex = actionRoot->add_subcommand("lendrex", localized("Deposit tokens to REX fund and use the tokens to buy REX")); + lendrex->add_option("from", from_str, localized("Account buying REX tokens"))->required(); + lendrex->add_option("amount", amount_str, localized("Amount of liquid tokens to be used in buying REX"))->required(); + add_standard_transaction_options(lendrex, "from@active"); + lendrex->set_callback([this] { + fc::variant act_payload1 = fc::mutable_variant_object() + ("owner", from_str) + ("amount", amount_str); + fc::variant act_payload2 = fc::mutable_variant_object() + ("from", from_str) + ("amount", amount_str); + auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name1, act_payload1), + create_action(accountPermissions, config::system_account_name, act_name2, act_payload2)}); + }); + } +}; + +struct unstaketorex_subcommand { + string owner_str; + string receiver_str; + string from_net_str; + string from_cpu_str; + const name act_name{ N(unstaketorex) }; + + unstaketorex_subcommand(CLI::App* actionRoot) { + auto unstaketorex = actionRoot->add_subcommand("unstaketorex", localized("Buy REX using staked tokens")); + unstaketorex->add_option("owner", owner_str, localized("Account buying REX tokens"))->required(); + unstaketorex->add_option("receiver", receiver_str, localized("Account that tokens have been staked to"))->required(); + unstaketorex->add_option("from_net", from_net_str, localized("Amount to be unstaked from CPU resources and used in REX purchase"))->required(); + unstaketorex->add_option("from_cpu", from_cpu_str, localized("Amount to be unstaked from Net resources and used in REX purchase"))->required(); + add_standard_transaction_options(unstaketorex, "owner@active"); + unstaketorex->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("owner", owner_str) + ("receiver", receiver_str) + ("from_net", from_net_str) + ("from_cpu", from_cpu_str); + auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct sellrex_subcommand { + string from_str; + string rex_str; + const name act_name{ N(sellrex) }; + + sellrex_subcommand(CLI::App* actionRoot) { + auto sellrex = actionRoot->add_subcommand("sellrex", localized("Sell REX tokens")); + sellrex->add_option("from", from_str, localized("Account selling REX tokens"))->required(); + sellrex->add_option("rex", rex_str, localized("Amount of REX tokens to be sold"))->required(); + add_standard_transaction_options(sellrex, "from@active"); + sellrex->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("from", from_str) + ("rex", rex_str); + auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct cancelrexorder_subcommand { + string owner_str; + const name act_name{ N(cnclrexorder) }; + + cancelrexorder_subcommand(CLI::App* actionRoot) { + auto cancelrexorder = actionRoot->add_subcommand("cancelrexorder", localized("Cancel queued REX sell order if one exists")); + cancelrexorder->add_option("owner", owner_str, localized("Owner account of sell order"))->required(); + add_standard_transaction_options(cancelrexorder, "owner@active"); + cancelrexorder->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object()("owner", owner_str); + auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct rentcpu_subcommand { + string from_str; + string receiver_str; + string loan_payment_str; + string loan_fund_str; + const name act_name{ N(rentcpu) }; + + rentcpu_subcommand(CLI::App* actionRoot) { + auto rentcpu = actionRoot->add_subcommand("rentcpu", localized("Rent CPU bandwidth for 30 days")); + rentcpu->add_option("from", from_str, localized("Account paying rent fees"))->required(); + rentcpu->add_option("receiver", receiver_str, localized("Account to whom rented CPU bandwidth is staked"))->required(); + rentcpu->add_option("loan_payment", loan_payment_str, localized("Loan fee to be paid, used to calculate amount of rented bandwidth"))->required(); + rentcpu->add_option("loan_fund", loan_fund_str, localized("Loan fund to be used in automatic renewal, can be 0 tokens"))->required(); + add_standard_transaction_options(rentcpu, "from@active"); + rentcpu->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("from", from_str) + ("receiver", receiver_str) + ("loan_payment", loan_payment_str) + ("loan_fund", loan_fund_str); + auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct rentnet_subcommand { + string from_str; + string receiver_str; + string loan_payment_str; + string loan_fund_str; + const name act_name{ N(rentnet) }; + + rentnet_subcommand(CLI::App* actionRoot) { + auto rentnet = actionRoot->add_subcommand("rentnet", localized("Rent Network bandwidth for 30 days")); + rentnet->add_option("from", from_str, localized("Account paying rent fees"))->required(); + rentnet->add_option("receiver", receiver_str, localized("Account to whom rented Network bandwidth is staked"))->required(); + rentnet->add_option("loan_payment", loan_payment_str, localized("Loan fee to be paid, used to calculate amount of rented bandwidth"))->required(); + rentnet->add_option("loan_fund", loan_fund_str, localized("Loan fund to be used in automatic renewal, can be 0 tokens"))->required(); + add_standard_transaction_options(rentnet, "from@active"); + rentnet->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("from", from_str) + ("receiver", receiver_str) + ("loan_payment", loan_payment_str) + ("loan_fund", loan_fund_str); + auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct fundcpuloan_subcommand { + string from_str; + string loan_num_str; + string payment_str; + const name act_name{ N(fundcpuloan) }; + + fundcpuloan_subcommand(CLI::App* actionRoot) { + auto fundcpuloan = actionRoot->add_subcommand("fundcpuloan", localized("Deposit into a CPU loan fund")); + fundcpuloan->add_option("from", from_str, localized("Loan owner"))->required(); + fundcpuloan->add_option("loan_num", loan_num_str, localized("Loan ID"))->required(); + fundcpuloan->add_option("payment", payment_str, localized("Amount to be deposited"))->required(); + add_standard_transaction_options(fundcpuloan, "from@active"); + fundcpuloan->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("from", from_str) + ("loan_num", loan_num_str) + ("payment", payment_str); + auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct fundnetloan_subcommand { + string from_str; + string loan_num_str; + string payment_str; + const name act_name{ N(fundnetloan) }; + + fundnetloan_subcommand(CLI::App* actionRoot) { + auto fundnetloan = actionRoot->add_subcommand("fundnetloan", localized("Deposit into a Network loan fund")); + fundnetloan->add_option("from", from_str, localized("Loan owner"))->required(); + fundnetloan->add_option("loan_num", loan_num_str, localized("Loan ID"))->required(); + fundnetloan->add_option("payment", payment_str, localized("Amount to be deposited"))->required(); + add_standard_transaction_options(fundnetloan, "from@active"); + fundnetloan->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("from", from_str) + ("loan_num", loan_num_str) + ("payment", payment_str); + auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct defcpuloan_subcommand { + string from_str; + string loan_num_str; + string amount_str; + const name act_name{ N(defcpuloan) }; + + defcpuloan_subcommand(CLI::App* actionRoot) { + auto defcpuloan = actionRoot->add_subcommand("defundcpuloan", localized("Withdraw from a CPU loan fund")); + defcpuloan->add_option("from", from_str, localized("Loan owner"))->required(); + defcpuloan->add_option("loan_num", loan_num_str, localized("Loan ID"))->required(); + defcpuloan->add_option("amount", amount_str, localized("Amount to be withdrawn"))->required(); + add_standard_transaction_options(defcpuloan, "from@active"); + defcpuloan->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("from", from_str) + ("loan_num", loan_num_str) + ("amount", amount_str); + auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct defnetloan_subcommand { + string from_str; + string loan_num_str; + string amount_str; + const name act_name{ N(defnetloan) }; + + defnetloan_subcommand(CLI::App* actionRoot) { + auto defnetloan = actionRoot->add_subcommand("defundnetloan", localized("Withdraw from a Network loan fund")); + defnetloan->add_option("from", from_str, localized("Loan owner"))->required(); + defnetloan->add_option("loan_num", loan_num_str, localized("Loan ID"))->required(); + defnetloan->add_option("amount", amount_str, localized("Amount to be withdrawn"))->required(); + add_standard_transaction_options(defnetloan, "from@active"); + defnetloan->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("from", from_str) + ("loan_num", loan_num_str) + ("amount", amount_str); + auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct mvtosavings_subcommand { + string owner_str; + string rex_str; + const name act_name{ N(mvtosavings) }; + + mvtosavings_subcommand(CLI::App* actionRoot) { + auto mvtosavings = actionRoot->add_subcommand("mvtosavings", localized("Move REX tokens to savings bucket")); + mvtosavings->add_option("owner", owner_str, localized("REX owner"))->required(); + mvtosavings->add_option("rex", rex_str, localized("Amount of REX to be moved to savings bucket"))->required(); + add_standard_transaction_options(mvtosavings, "owner@active"); + mvtosavings->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("owner", owner_str) + ("rex", rex_str); + auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct mvfrsavings_subcommand { + string owner_str; + string rex_str; + const name act_name{ N(mvfrsavings) }; + + mvfrsavings_subcommand(CLI::App* actionRoot) { + auto mvfrsavings = actionRoot->add_subcommand("mvfromsavings", localized("Move REX tokens out of savings bucket")); + mvfrsavings->add_option("owner", owner_str, localized("REX owner"))->required(); + mvfrsavings->add_option("rex", rex_str, localized("Amount of REX to be moved out of savings bucket"))->required(); + add_standard_transaction_options(mvfrsavings, "owner@active"); + mvfrsavings->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("owner", owner_str) + ("rex", rex_str); + auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct updaterex_subcommand { + string owner_str; + const name act_name{ N(updaterex) }; + + updaterex_subcommand(CLI::App* actionRoot) { + auto updaterex = actionRoot->add_subcommand("updaterex", localized("Update REX owner vote stake and vote weight")); + updaterex->add_option("owner", owner_str, localized("REX owner"))->required(); + add_standard_transaction_options(updaterex, "owner@active"); + updaterex->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object()("owner", owner_str); + auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct consolidate_subcommand { + string owner_str; + const name act_name{ N(consolidate) }; + + consolidate_subcommand(CLI::App* actionRoot) { + auto consolidate = actionRoot->add_subcommand("consolidate", localized("Consolidate REX maturity buckets into one that matures in 4 days")); + consolidate->add_option("owner", owner_str, localized("REX owner"))->required(); + add_standard_transaction_options(consolidate, "owner@active"); + consolidate->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object()("owner", owner_str); + auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct rexexec_subcommand { + string user_str; + string max_str; + const name act_name{ N(rexexec) }; + + rexexec_subcommand(CLI::App* actionRoot) { + auto rexexec = actionRoot->add_subcommand("rexexec", localized("Perform REX maintenance by processing expired loans and unfilled sell orders")); + rexexec->add_option("user", user_str, localized("User executing the action"))->required(); + rexexec->add_option("max", max_str, localized("Maximum number of CPU loans, Network loans, and sell orders to be processed"))->required(); + add_standard_transaction_options(rexexec, "user@active"); + rexexec->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object() + ("user", user_str) + ("max", max_str); + auto accountPermissions = get_account_permissions(tx_permission, {user_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + +struct closerex_subcommand { + string owner_str; + const name act_name{ N(closerex) }; + + closerex_subcommand(CLI::App* actionRoot) { + auto closerex = actionRoot->add_subcommand("closerex", localized("Delete unused REX-related user table entries")); + closerex->add_option("owner", owner_str, localized("REX owner"))->required(); + add_standard_transaction_options(closerex, "owner@active"); + closerex->set_callback([this] { + fc::variant act_payload = fc::mutable_variant_object()("owner", owner_str); + auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); + }); + } +}; + void get_account( const string& accountName, const string& coresym, bool json_format ) { fc::variant json; if (coresym.empty()) { @@ -3481,6 +3883,28 @@ int main( int argc, char** argv ) { auto cancelDelay = canceldelay_subcommand(system); + auto rex = system->add_subcommand("rex", localized("Actions related to REX (the resource exchange)")); + rex->require_subcommand(); + auto deposit = deposit_subcommand(rex); + auto withdraw = withdraw_subcommand(rex); + auto buyrex = buyrex_subcommand(rex); + auto lendrex = lendrex_subcommand(rex); + auto unstaketorex = unstaketorex_subcommand(rex); + auto sellrex = sellrex_subcommand(rex); + auto cancelrexorder = cancelrexorder_subcommand(rex); + auto mvtosavings = mvtosavings_subcommand(rex); + auto mvfromsavings = mvfrsavings_subcommand(rex); + auto rentcpu = rentcpu_subcommand(rex); + auto rentnet = rentnet_subcommand(rex); + auto fundcpuloan = fundcpuloan_subcommand(rex); + auto fundnetloan = fundnetloan_subcommand(rex); + auto defcpuloan = defcpuloan_subcommand(rex); + auto defnetloan = defnetloan_subcommand(rex); + auto consolidate = consolidate_subcommand(rex); + auto updaterex = updaterex_subcommand(rex); + auto rexexec = rexexec_subcommand(rex); + auto closerex = closerex_subcommand(rex); + try { app.parse(argc, argv); } catch (const CLI::ParseError &e) {