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