github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/runtime/dip/dip_reward.cpp (about) 1 // Copyright (C) 2018 go-nebulas authors 2 // 3 // This file is part of the go-nebulas library. 4 // 5 // the go-nebulas library is free software: you can redistribute it and/or 6 // modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation, either version 3 of the License, or 9 // (at your option) any later version. 10 // 11 // the go-nebulas library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with the go-nebulas library. If not, see 18 // <http://www.gnu.org/licenses/>. 19 // 20 21 #include "runtime/dip/dip_reward.h" 22 #include "common/configuration.h" 23 #include "common/int128_conversion.h" 24 #include "runtime/dip/dip_handler.h" 25 #include <boost/algorithm/string/replace.hpp> 26 #include <boost/foreach.hpp> 27 #include <boost/property_tree/json_parser.hpp> 28 #include <boost/property_tree/ptree.hpp> 29 30 namespace neb { 31 namespace rt { 32 namespace dip { 33 34 std::vector<std::shared_ptr<dip_info_t>> dip_reward::get_dip_reward( 35 neb::block_height_t start_block, neb::block_height_t end_block, 36 neb::block_height_t height, 37 const std::vector<std::shared_ptr<nr_info_t>> &nr_result, 38 const neb::rt::nr::transaction_db_ptr_t &tdb_ptr, 39 const neb::rt::nr::account_db_ptr_t &adb_ptr, floatxx_t alpha, 40 floatxx_t beta) { 41 42 auto it_txs = 43 tdb_ptr->read_transactions_from_db_with_duration(start_block, end_block); 44 auto txs = *it_txs; 45 LOG(INFO) << "transaction size " << txs.size(); 46 47 auto it_nr_infos = nr_result; 48 auto it_acc_to_contract_txs = 49 fs::transaction_db::read_transactions_with_address_type( 50 txs, NAS_ADDRESS_ACCOUNT_MAGIC_NUM, NAS_ADDRESS_CONTRACT_MAGIC_NUM); 51 ignore_account_transfer_contract(*it_acc_to_contract_txs, "binary"); 52 LOG(INFO) << "account to contract size " << it_acc_to_contract_txs->size(); 53 // dapp total votes 54 auto it_acc_to_contract_votes = 55 account_to_contract_votes(*it_acc_to_contract_txs, it_nr_infos); 56 LOG(INFO) << "account to contract votes " << it_acc_to_contract_votes->size(); 57 auto it_dapp_votes = dapp_votes(*it_acc_to_contract_votes); 58 LOG(INFO) << "dapp votes size " << it_dapp_votes->size(); 59 60 // bonus pool in total 61 auto dip_params_ptr = dip_handler::instance().get_dip_params(end_block + 1); 62 auto &dip_params = *dip_params_ptr; 63 address_t dip_reward_addr = to_address(dip_params.get<reward_addr>()); 64 address_t dip_coinbase_addr = to_address(dip_params.get<coinbase_addr>()); 65 66 wei_t balance = adb_ptr->get_balance(dip_reward_addr, end_block); 67 floatxx_t bonus_total = to_float<floatxx_t>(balance); 68 LOG(INFO) << "bonus total " << bonus_total; 69 // bonus_total = adb_ptr->get_normalized_value(bonus_total); 70 71 floatxx_t sum_votes(0); 72 for (auto &v : *it_dapp_votes) { 73 sum_votes += v.second * v.second; 74 } 75 LOG(INFO) << "sum votes " << sum_votes; 76 77 floatxx_t reward_sum(0); 78 std::vector<std::shared_ptr<dip_info_t>> dip_infos; 79 for (auto &v : *it_dapp_votes) { 80 std::shared_ptr<dip_info_t> info_ptr = std::make_shared<dip_info_t>(); 81 dip_info_t &info = *info_ptr; 82 info.m_contract = v.first; 83 info.m_deployer = adb_ptr->get_contract_deployer(v.first, end_block); 84 85 floatxx_t reward_in_wei = 86 v.second * v.second * 87 participate_lambda(alpha, beta, *it_acc_to_contract_txs, it_nr_infos) * 88 bonus_total / sum_votes; 89 reward_sum += reward_in_wei; 90 91 info.m_reward = neb::math::to_string(from_float(reward_in_wei)); 92 dip_infos.push_back(info_ptr); 93 } 94 LOG(INFO) << "reward sum " << reward_sum << ", bonus total " << bonus_total; 95 // assert(reward_sum <= bonus_total); 96 back_to_coinbase(dip_infos, bonus_total - reward_sum, dip_coinbase_addr); 97 LOG(INFO) << "back to coinbase"; 98 return dip_infos; 99 } 100 101 void dip_reward::back_to_coinbase( 102 std::vector<std::shared_ptr<dip_info_t>> &dip_infos, floatxx_t reward_left, 103 const address_t &dip_coinbase_addr) { 104 105 if (!dip_coinbase_addr.empty() && reward_left > 0) { 106 std::shared_ptr<dip_info_t> info = std::make_shared<dip_info_t>(); 107 info->m_deployer = dip_coinbase_addr; 108 info->m_reward = neb::math::to_string(from_float(reward_left)); 109 dip_infos.push_back(info); 110 } 111 } 112 113 void dip_reward::full_fill_meta_info( 114 const std::vector<std::pair<std::string, std::string>> &meta, 115 boost::property_tree::ptree &root) { 116 117 assert(meta.size() == 3); 118 119 for (auto &ele : meta) { 120 root.put(ele.first, ele.second); 121 } 122 } 123 124 str_uptr_t dip_reward::dip_info_to_json(const dip_ret_type &dip_ret) { 125 126 boost::property_tree::ptree root; 127 boost::property_tree::ptree arr; 128 129 const auto &meta_info_json = std::get<1>(dip_ret); 130 const auto &meta_info = neb::rt::json_to_meta_info(meta_info_json); 131 if (!meta_info.empty()) { 132 full_fill_meta_info(meta_info, root); 133 } 134 135 auto &dip_infos = std::get<2>(dip_ret); 136 if (dip_infos.empty()) { 137 boost::property_tree::ptree p; 138 arr.push_back(std::make_pair(std::string(), p)); 139 } 140 141 for (auto &info_ptr : dip_infos) { 142 auto &info = *info_ptr; 143 boost::property_tree::ptree p; 144 145 std::vector<std::pair<std::string, std::string>> kv_pair( 146 {{"address", info.m_deployer.to_base58()}, 147 {"reward", info.m_reward}, 148 {"contract", info.m_contract.to_base58()}}); 149 for (auto &ele : kv_pair) { 150 p.put(ele.first, ele.second); 151 } 152 153 arr.push_back(std::make_pair(std::string(), p)); 154 } 155 root.add_child("dips", arr); 156 157 std::stringstream ss; 158 boost::property_tree::json_parser::write_json(ss, root, false); 159 auto tmp_ptr = std::make_unique<std::string>(ss.str()); 160 boost::replace_all(*tmp_ptr, "[\"\"]", "[]"); 161 return tmp_ptr; 162 } 163 164 dip_ret_type dip_reward::json_to_dip_info(const std::string &dip_reward) { 165 166 dip_ret_type dip_ret; 167 std::get<0>(dip_ret) = 0; 168 169 boost::property_tree::ptree pt; 170 std::stringstream ss(dip_reward); 171 boost::property_tree::json_parser::read_json(ss, pt); 172 173 auto start_block = pt.get<std::string>("start_height"); 174 auto end_block = pt.get<std::string>("end_height"); 175 auto version = pt.get<std::string>("version"); 176 177 std::vector<std::pair<std::string, std::string>> meta_info; 178 meta_info.push_back(std::make_pair("start_height", start_block)); 179 meta_info.push_back(std::make_pair("end_height", end_block)); 180 meta_info.push_back(std::make_pair("version", version)); 181 std::get<1>(dip_ret) = meta_info_to_json(meta_info); 182 183 boost::property_tree::ptree dips = pt.get_child("dips"); 184 auto &infos = std::get<2>(dip_ret); 185 186 BOOST_FOREACH (boost::property_tree::ptree::value_type &v, dips) { 187 boost::property_tree::ptree nr = v.second; 188 auto info_ptr = std::make_shared<dip_info_t>(); 189 dip_info_t &info = *info_ptr; 190 neb::bytes deployer_bytes = 191 neb::bytes::from_base58(nr.get<std::string>("address")); 192 neb::bytes contract_bytes = 193 neb::bytes::from_base58(nr.get<std::string>("contract")); 194 info.m_deployer = deployer_bytes; 195 info.m_contract = contract_bytes; 196 info.m_reward = nr.get<std::string>("reward"); 197 infos.push_back(info_ptr); 198 } 199 return dip_ret; 200 } 201 202 std::unique_ptr< 203 std::unordered_map<address_t, std::unordered_map<address_t, uint32_t>>> 204 dip_reward::account_call_contract_count( 205 const std::vector<neb::fs::transaction_info_t> &txs) { 206 207 auto cnt = std::make_unique< 208 std::unordered_map<address_t, std::unordered_map<address_t, uint32_t>>>(); 209 210 for (auto &tx : txs) { 211 address_t acc_addr = tx.m_from; 212 address_t contract_addr = tx.m_to; 213 auto it = cnt->find(acc_addr); 214 215 if (it != cnt->end()) { 216 std::unordered_map<address_t, uint32_t> &tmp = it->second; 217 if (tmp.find(contract_addr) != tmp.end()) { 218 tmp[contract_addr]++; 219 } else { 220 tmp.insert(std::make_pair(contract_addr, 1)); 221 } 222 } else { 223 std::unordered_map<address_t, uint32_t> tmp; 224 tmp.insert(std::make_pair(contract_addr, 1)); 225 cnt->insert(std::make_pair(acc_addr, tmp)); 226 } 227 } 228 return cnt; 229 } 230 231 std::unique_ptr< 232 std::unordered_map<address_t, std::unordered_map<address_t, floatxx_t>>> 233 dip_reward::account_to_contract_votes( 234 const std::vector<neb::fs::transaction_info_t> &txs, 235 const std::vector<std::shared_ptr<neb::rt::nr::nr_info_t>> &nr_infos) { 236 237 auto ret = std::make_unique<std::unordered_map< 238 address_t, std::unordered_map<address_t, floatxx_t>>>(); 239 240 auto it_cnt = account_call_contract_count(txs); 241 auto cnt = *it_cnt; 242 243 for (auto &info : nr_infos) { 244 address_t addr = info->m_address; 245 floatxx_t score = info->m_nr_score; 246 247 auto it_acc = cnt.find(addr); 248 if (it_acc == cnt.end()) { 249 continue; 250 } 251 252 floatxx_t sum_votes(0); 253 for (auto &e : it_acc->second) { 254 sum_votes += e.second; 255 } 256 257 for (auto &e : it_acc->second) { 258 std::unordered_map<address_t, floatxx_t> tmp; 259 tmp.insert(std::make_pair(e.first, e.second * score / sum_votes)); 260 ret->insert(std::make_pair(addr, tmp)); 261 } 262 } 263 return ret; 264 } 265 266 std::unique_ptr<std::unordered_map<address_t, floatxx_t>> 267 dip_reward::dapp_votes(const std::unordered_map< 268 address_t, std::unordered_map<address_t, floatxx_t>> 269 &acc_contract_votes) { 270 auto ret = std::make_unique<std::unordered_map<address_t, floatxx_t>>(); 271 272 for (auto &it : acc_contract_votes) { 273 for (auto &ite : it.second) { 274 auto iter = ret->find(ite.first); 275 if (iter != ret->end()) { 276 floatxx_t &tmp = iter->second; 277 tmp += neb::math::sqrt(ite.second); 278 } else { 279 ret->insert(std::make_pair(ite.first, neb::math::sqrt(ite.second))); 280 } 281 } 282 } 283 return ret; 284 } 285 286 floatxx_t dip_reward::participate_lambda( 287 floatxx_t alpha, floatxx_t beta, 288 const std::vector<neb::fs::transaction_info_t> &txs, 289 const std::vector<std::shared_ptr<neb::rt::nr::nr_info_t>> &nr_infos) { 290 291 std::unordered_set<address_t> addr_set; 292 for (auto &tx : txs) { 293 addr_set.insert(tx.m_from); 294 } 295 296 std::vector<floatxx_t> participate_nr; 297 for (auto &info : nr_infos) { 298 address_t addr = info->m_address; 299 if (addr_set.find(addr) != addr_set.end()) { 300 participate_nr.push_back(info->m_nr_score); 301 } 302 } 303 304 floatxx_t gamma_p(0); 305 for (auto &nr : participate_nr) { 306 gamma_p += nr; 307 } 308 309 floatxx_t gamma_s(0); 310 for (auto &info : nr_infos) { 311 gamma_s += info->m_nr_score; 312 } 313 314 floatxx_t zero = softfloat_cast<uint32_t, typename floatxx_t::value_type>(0); 315 floatxx_t one = softfloat_cast<uint32_t, typename floatxx_t::value_type>(1); 316 317 if (gamma_s == zero) { 318 return zero; 319 } 320 if (gamma_p == beta * gamma_s) { 321 return one; 322 } 323 324 return math::min(one, alpha * gamma_s / (beta * gamma_s - gamma_p)); 325 } 326 327 void dip_reward::ignore_account_transfer_contract( 328 std::vector<neb::fs::transaction_info_t> &txs, const std::string &tx_type) { 329 for (auto it = txs.begin(); it != txs.end();) { 330 it = (it->m_tx_type == tx_type ? txs.erase(it) : it + 1); 331 } 332 } 333 } // namespace dip 334 } // namespace rt 335 } // namespace neb