From 4e4a3ca86d5d3482dfac85182e69f33c49e62fa9 Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Wed, 22 Aug 2018 18:00:27 -0400 Subject: [PATCH 1/2] Consolidated Security Fixes for 1.2.1 - add setalimits to eosio.system to allow management of resource limits for accounts that were instantiated prior to the resource markets - migrate inline transfer of bidname refunds to a deferred transaction with a manual failsafe action Co-authored-by: Bucky Kittinger Co-authored-by: Anton Perkov --- eosio.system/abi/eosio.system.abi | 32 ++++++++++++-- .../include/eosio.system/eosio.system.hpp | 12 +++++ eosio.system/src/delegate_bandwidth.cpp | 3 +- eosio.system/src/eosio.system.cpp | 44 +++++++++++++++++-- eosio.system/src/producer_pay.cpp | 4 +- 5 files changed, 83 insertions(+), 12 deletions(-) diff --git a/eosio.system/abi/eosio.system.abi b/eosio.system/abi/eosio.system.abi index 4e30369a7..5445473af 100644 --- a/eosio.system/abi/eosio.system.abi +++ b/eosio.system/abi/eosio.system.abi @@ -39,6 +39,13 @@ {"name":"newname", "type":"account_name"}, {"name":"bid", "type":"asset"} ] + },{ + "name": "bidrefund", + "base": "", + "fields": [ + {"name":"bidder", "type":"account_name"}, + {"name":"newname", "type":"account_name"} + ] },{ "name": "permission_level_weight", "base": "", @@ -410,7 +417,7 @@ {"name":"quote", "type":"connector"} ] }, { - "name": "namebid_info", + "name": "name_bid", "base": "", "fields": [ {"name":"newname", "type":"account_name"}, @@ -418,7 +425,14 @@ {"name":"high_bid", "type":"int64"}, {"name":"last_bid_time", "type":"uint64"} ] - } + }, { + "name": "bid_refund", + "base": "", + "fields": [ + {"name":"bidder", "type":"account_name"}, + {"name":"amount", "type":"asset"} + ] + } ], "actions": [{ "name": "newaccount", @@ -496,6 +510,10 @@ "name": "bidname", "type": "bidname", "ricardian_contract": "" + },{ + "name": "bidrefund", + "type": "bidrefund", + "ricardian_contract": "" },{ "name": "unregprod", "type": "unregprod", @@ -591,11 +609,17 @@ "key_types" : ["uint64"] },{ "name": "namebids", - "type": "namebid_info", + "type": "name_bid", "index_type": "i64", "key_names" : ["newname"], "key_types" : ["account_name"] - } + },{ + "name": "bidrefunds", + "type": "bid_refund", + "index_type": "i64", + "key_names" : ["bidder"], + "key_types" : ["account_name"] + } ], "ricardian_clauses": [], "abi_extensions": [] diff --git a/eosio.system/include/eosio.system/eosio.system.hpp b/eosio.system/include/eosio.system/eosio.system.hpp index 659d8c815..57d771b2c 100644 --- a/eosio.system/include/eosio.system/eosio.system.hpp +++ b/eosio.system/include/eosio.system/eosio.system.hpp @@ -30,10 +30,18 @@ namespace eosiosystem { uint64_t by_high_bid()const { return static_cast(-high_bid); } }; + struct bid_refund { + account_name bidder; + asset amount; + + auto primary_key() const { return bidder; } + }; + typedef eosio::multi_index< N(namebids), name_bid, indexed_by > > name_bid_table; + typedef eosio::multi_index< N(bidrefunds), bid_refund> bid_refund_table; struct eosio_global_state : eosio::blockchain_parameters { uint64_t free_ram()const { return max_ram_size - total_ram_bytes_reserved; } @@ -161,6 +169,7 @@ namespace eosiosystem { void onblock( block_timestamp timestamp, account_name producer ); // const block_header& header ); /// only parse first 3 fields of block header + void setalimits( account_name act, int64_t ram, int64_t net, int64_t cpu ); // functions defined in delegate_bandwidth.cpp /** @@ -235,6 +244,9 @@ namespace eosiosystem { void rmvproducer( account_name producer ); void bidname( account_name bidder, account_name newname, asset bid ); + + void bidrefund( account_name bidder, account_name newname ); + private: // Implementation details: diff --git a/eosio.system/src/delegate_bandwidth.cpp b/eosio.system/src/delegate_bandwidth.cpp index 667a2c127..edede0e5b 100644 --- a/eosio.system/src/delegate_bandwidth.cpp +++ b/eosio.system/src/delegate_bandwidth.cpp @@ -156,7 +156,6 @@ namespace eosiosystem { set_resource_limits( res_itr->owner, res_itr->ram_bytes + ram_gift_bytes, res_itr->net_weight.amount, res_itr->cpu_weight.amount ); } - /** * The system contract now buys and sells RAM allocations at prevailing market prices. * This may result in traders buying RAM today in anticipation of potential shortages @@ -422,7 +421,7 @@ namespace eosiosystem { // allow people to get their tokens earlier than the 3 day delay if the unstake happened immediately after many // consecutive missed blocks. - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.stake),N(active)}, + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {{N(eosio.stake),N(active)},{req->owner,N(active)}}, { N(eosio.stake), req->owner, req->net_amount + req->cpu_amount, std::string("unstake") } ); refunds_tbl.erase( req ); diff --git a/eosio.system/src/eosio.system.cpp b/eosio.system/src/eosio.system.cpp index 4d7c5f501..59a27abd6 100644 --- a/eosio.system/src/eosio.system.cpp +++ b/eosio.system/src/eosio.system.cpp @@ -119,6 +119,14 @@ namespace eosiosystem { require_auth( _self ); set_privileged( account, ispriv ); } + + void system_contract::setalimits( account_name account, int64_t ram, int64_t net, int64_t cpu ) { + require_auth( N(eosio) ); + user_resources_table userres( _self, account ); + auto ritr = userres.find( account ); + eosio_assert( ritr == userres.end(), "only supports unlimited accounts" ); + set_resource_limits(account, ram, net, cpu); + } void system_contract::rmvproducer( account_name producer ) { require_auth( _self ); @@ -158,9 +166,27 @@ namespace eosiosystem { eosio_assert( bid.amount - current->high_bid > (current->high_bid / 10), "must increase bid by 10%" ); eosio_assert( current->high_bidder != bidder, "account is already highest bidder" ); - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.names),N(active)}, - { N(eosio.names), current->high_bidder, asset(current->high_bid), - std::string("refund bid on name ")+(name{newname}).to_string() } ); + bid_refund_table refunds_table(_self, newname); + + auto it = refunds_table.find( current->high_bidder ); + if ( it != refunds_table.end() ) { + refunds_table.modify( it, 0, [&](auto& r) { + r.amount += asset( current->high_bid, system_token_symbol ); + }); + } else { + refunds_table.emplace( bidder, [&](auto& r) { + r.bidder = current->high_bidder; + r.amount = asset( current->high_bid, system_token_symbol ); + }); + } + + action a( {N(eosio),N(active)}, N(eosio), N(bidrefund), std::make_tuple( current->high_bidder, newname ) ); + transaction t; + t.actions.push_back( std::move(a) ); + t.delay_sec = 0; + uint128_t deferred_id = (uint128_t(newname) << 64) | current->high_bidder; + cancel_deferred( deferred_id ); + t.send( deferred_id, bidder ); bids.modify( current, bidder, [&]( auto& b ) { b.high_bidder = bidder; @@ -170,6 +196,16 @@ namespace eosiosystem { } } + void system_contract::bidrefund( account_name bidder, account_name newname ) { + bid_refund_table refunds_table(_self, newname); + auto it = refunds_table.find( bidder ); + eosio_assert( it != refunds_table.end(), "refund not found" ); + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {{N(eosio.names),N(active)},{bidder,N(active)}}, + { N(eosio.names), bidder, asset(it->amount), + std::string("refund bid on name ")+(name{newname}).to_string() } ); + refunds_table.erase( it ); + } + /** * Called after a new account is created. This code enforces resource-limits rules * for new accounts as well as new account naming conventions. @@ -224,7 +260,7 @@ EOSIO_ABI( eosiosystem::system_contract, // native.hpp (newaccount definition is actually in eosio.system.cpp) (newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(canceldelay)(onerror) // eosio.system.cpp - (setram)(setramrate)(setparams)(setpriv)(rmvproducer)(bidname) + (setram)(setramrate)(setparams)(setpriv)(setalimits)(rmvproducer)(bidname)(bidrefund) // delegate_bandwidth.cpp (buyrambytes)(buyram)(sellram)(delegatebw)(undelegatebw)(refund) // voting.cpp diff --git a/eosio.system/src/producer_pay.cpp b/eosio.system/src/producer_pay.cpp index e661be740..37706027a 100644 --- a/eosio.system/src/producer_pay.cpp +++ b/eosio.system/src/producer_pay.cpp @@ -133,11 +133,11 @@ namespace eosiosystem { }); if( producer_per_block_pay > 0 ) { - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.bpay),N(active)}, + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {{N(eosio.bpay),N(active)},{owner,N(active)}}, { N(eosio.bpay), owner, asset(producer_per_block_pay), std::string("producer block pay") } ); } if( producer_per_vote_pay > 0 ) { - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.vpay),N(active)}, + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {{N(eosio.vpay),N(active)},{owner,N(active)}}, { N(eosio.vpay), owner, asset(producer_per_vote_pay), std::string("producer vote pay") } ); } } From 55f8062fd03491527260ada1e838adcc1de27741 Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Fri, 24 Aug 2018 11:59:33 -0400 Subject: [PATCH 2/2] bump version to 1.2.1 --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3061de8f1..20f90a6d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.5) -project(eosio_contracts VERSION 1.2.0) +project(eosio_contracts VERSION 1.2.1) set(EOSIO_DEPENDENCY "1.1") set(EOSIO_WASMSDK_DEPENDENCY "1.1") diff --git a/README.md b/README.md index b27fdc4b8..1c8da8a0f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # eosio.contracts -## Version : 1.2.0 +## Version : 1.2.1 The design of the EOSIO blockchain calls for a number of smart contracts that are run at a privileged permission level in order to support functions such as block producer registration and voting, token staking for CPU and network bandwidth, RAM purchasing, multi-sig, etc. These smart contracts are referred to as the system, token, msig and sudo contracts.