github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/test/runtime/nr/gtest_nebulas_rank.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 "common/common.h"
    22  #include "runtime/nr/impl/nebulas_rank.h"
    23  #include "runtime/util.h"
    24  #include <gtest/gtest.h>
    25  #include <random>
    26  #define PRECESION 1e-5
    27  
    28  template <typename T> T precesion(const T &x, float pre = PRECESION) {
    29    return std::fabs(T(x * pre));
    30  }
    31  
    32  TEST(test_runtime_nebulas_rank, split_transactions_by_block_interval) {
    33    std::vector<neb::fs::transaction_info_t> txs;
    34    auto ret =
    35        neb::rt::nr::nebulas_rank::split_transactions_by_block_interval(txs);
    36    EXPECT_TRUE(ret->empty());
    37  
    38    neb::fs::transaction_info_t tx;
    39    txs.push_back(tx);
    40    ret = neb::rt::nr::nebulas_rank::split_transactions_by_block_interval(txs, 0);
    41    EXPECT_TRUE(ret->empty());
    42  
    43    ret = neb::rt::nr::nebulas_rank::split_transactions_by_block_interval(txs, 1);
    44    EXPECT_TRUE(!ret->empty());
    45  
    46    txs.clear();
    47    std::random_device rd;
    48    std::mt19937 mt(rd());
    49    std::uniform_int_distribution<> dis(0, std::numeric_limits<int16_t>::max());
    50  
    51    //  block interval default 128
    52    int32_t txs_size = dis(mt);
    53    for (int32_t i = 0; i < txs_size; i++) {
    54      tx.m_height = i;
    55      txs.push_back(tx);
    56    }
    57    ret = neb::rt::nr::nebulas_rank::split_transactions_by_block_interval(txs);
    58    size_t actual_txs_size = 0;
    59    for (auto &ele : *ret) {
    60      actual_txs_size += ele.size();
    61    }
    62    EXPECT_EQ(txs_size, actual_txs_size);
    63    for (size_t i = 0; i < ret->size() - 1; i++) {
    64      auto cur_last = (*ret)[i].back();
    65      auto next_first = (*ret)[i + 1].front();
    66      EXPECT_TRUE(cur_last.m_height <= next_first.m_height);
    67    }
    68    for (auto &row : *ret) {
    69      for (size_t i = 0; i < row.size() - 1; i++) {
    70        EXPECT_TRUE(row[i].m_height <= row[i + 1].m_height);
    71      }
    72    }
    73    ret->pop_back();
    74    for (auto &ele : *ret) {
    75      EXPECT_EQ(ele.size(), 128);
    76    }
    77  
    78    // block interval 100
    79    txs.clear();
    80    txs_size = dis(mt);
    81    for (int32_t i = 0; i < txs_size; i++) {
    82      tx.m_height = i;
    83      txs.push_back(tx);
    84    }
    85    neb::block_height_t block_interval = 100;
    86    ret = neb::rt::nr::nebulas_rank::split_transactions_by_block_interval(
    87        txs, block_interval);
    88    actual_txs_size = 0;
    89    for (auto &ele : *ret) {
    90      actual_txs_size += ele.size();
    91    }
    92    EXPECT_EQ(txs_size, actual_txs_size);
    93    for (size_t i = 0; i < ret->size() - 1; i++) {
    94      auto cur_last = (*ret)[i].back();
    95      auto next_first = (*ret)[i + 1].front();
    96      EXPECT_TRUE(cur_last.m_height <= next_first.m_height);
    97    }
    98    for (auto &row : *ret) {
    99      for (size_t i = 0; i < row.size() - 1; i++) {
   100        EXPECT_TRUE(row[i].m_height <= row[i + 1].m_height);
   101      }
   102    }
   103    ret->pop_back();
   104    for (auto &ele : *ret) {
   105      EXPECT_EQ(ele.size(), block_interval);
   106    }
   107  
   108    // block interval random
   109    txs.clear();
   110    txs_size = dis(mt);
   111    for (int32_t i = 0; i < txs_size; i++) {
   112      tx.m_height = i;
   113      txs.push_back(tx);
   114    }
   115    block_interval = std::sqrt(txs_size);
   116    ret = neb::rt::nr::nebulas_rank::split_transactions_by_block_interval(
   117        txs, block_interval);
   118    actual_txs_size = 0;
   119    for (auto &ele : *ret) {
   120      actual_txs_size += ele.size();
   121    }
   122    EXPECT_EQ(txs_size, actual_txs_size);
   123    for (size_t i = 0; i < ret->size() - 1; i++) {
   124      auto cur_last = (*ret)[i].back();
   125      auto next_first = (*ret)[i + 1].front();
   126      EXPECT_TRUE(cur_last.m_height <= next_first.m_height);
   127    }
   128    for (auto &row : *ret) {
   129      for (size_t i = 0; i < row.size() - 1; i++) {
   130        EXPECT_TRUE(row[i].m_height <= row[i + 1].m_height);
   131      }
   132    }
   133    ret->pop_back();
   134    for (auto &ele : *ret) {
   135      EXPECT_EQ(ele.size(), block_interval);
   136    }
   137  }
   138  
   139  TEST(test_runtime_nebulas_rank, filter_empty_transactions_this_interval) {
   140    std::vector<std::vector<neb::fs::transaction_info_t>> txs;
   141    neb::rt::nr::nebulas_rank::filter_empty_transactions_this_interval(txs);
   142    EXPECT_TRUE(txs.empty());
   143  
   144    std::vector<neb::fs::transaction_info_t> tx;
   145    txs.push_back(tx);
   146    EXPECT_TRUE(!txs.empty());
   147    neb::rt::nr::nebulas_rank::filter_empty_transactions_this_interval(txs);
   148    EXPECT_TRUE(txs.empty());
   149  
   150    neb::fs::transaction_info_t info;
   151    tx.push_back(info);
   152    txs.push_back(tx);
   153    EXPECT_TRUE(!txs.empty());
   154    neb::rt::nr::nebulas_rank::filter_empty_transactions_this_interval(txs);
   155    EXPECT_TRUE(!txs.empty());
   156  
   157    txs.clear();
   158    std::random_device rd;
   159    std::mt19937 mt(rd());
   160    std::uniform_int_distribution<> dis(0, 1 << 12);
   161  
   162    int32_t empty_ratio = dis(mt);
   163    int32_t empty_size = 0;
   164    int32_t not_empty_size = 0;
   165    int32_t txs_size = dis(mt);
   166  
   167    for (int32_t i = 0; i < txs_size; i++) {
   168      auto tmp = dis(mt);
   169      if (tmp < empty_ratio) {
   170        std::vector<neb::fs::transaction_info_t> tx;
   171        txs.push_back(tx);
   172        empty_size++;
   173      } else {
   174        neb::fs::transaction_info_t info;
   175        std::vector<neb::fs::transaction_info_t> tx;
   176        tx.push_back(info);
   177        txs.push_back(tx);
   178        not_empty_size++;
   179      }
   180    }
   181    EXPECT_EQ(txs_size, empty_size + not_empty_size);
   182    neb::rt::nr::nebulas_rank::filter_empty_transactions_this_interval(txs);
   183    EXPECT_EQ(txs.size(), not_empty_size);
   184  }
   185  
   186  std::unique_ptr<std::vector<neb::fs::transaction_info_t>>
   187  gen_transactions(std::vector<int32_t> &addr_set) {
   188    size_t ch_size = 'z' - 'a';
   189    std::random_device rd;
   190    std::mt19937 mt(rd());
   191    std::uniform_int_distribution<> dis(0, ch_size);
   192    size_t txs_size = dis(mt) * dis(mt);
   193    txs_size++;
   194    addr_set = std::vector<int32_t>(ch_size + 1);
   195  
   196    auto ret = std::make_unique<std::vector<neb::fs::transaction_info_t>>();
   197    for (size_t i = 0; i < txs_size; i++) {
   198      char ch_s = 'a' + dis(mt);
   199      char ch_t = 'a' + dis(mt);
   200  
   201      addr_set[ch_s - 'a'] = 1;
   202      addr_set[ch_t - 'a'] = 1;
   203  
   204      neb::fs::transaction_info_t info;
   205      info.m_height = dis(mt);
   206      info.m_from = neb::to_address(std::string(1, ch_s));
   207      info.m_to = neb::to_address(std::string(1, ch_t));
   208      info.m_tx_value = dis(mt);
   209      info.m_timestamp = dis(mt);
   210      ret->push_back(info);
   211    }
   212    return ret;
   213  }
   214  
   215  bool check_for_transaction_graph(
   216      const neb::rt::transaction_graph_ptr_t &tg_ptr,
   217      const std::vector<neb::fs::transaction_info_t> &txs) {
   218  
   219    auto g = tg_ptr->internal_graph();
   220    neb::rt::transaction_graph::viterator_t vi, vi_end;
   221    for (boost::tie(vi, vi_end) = boost::vertices(g); vi != vi_end; vi++) {
   222      neb::rt::transaction_graph::oeiterator_t oei, oei_end;
   223      for (boost::tie(oei, oei_end) = boost::out_edges(*vi, g); oei != oei_end;
   224           oei++) {
   225        auto source = boost::source(*oei, g);
   226        auto target = boost::target(*oei, g);
   227        auto ss = neb::to_address(boost::get(boost::vertex_name_t(), g, source));
   228        auto tt = neb::to_address(boost::get(boost::vertex_name_t(), g, target));
   229        neb::wei_t w = boost::get(boost::edge_weight_t(), g, *oei);
   230        int64_t ts = boost::get(boost::edge_timestamp_t(), g, *oei);
   231  
   232        for (auto &tx : txs) {
   233          if (ss == tx.m_from && tt == tx.m_to && w == tx.m_tx_value &&
   234              ts == tx.m_timestamp) {
   235            return true;
   236          }
   237        }
   238      }
   239    }
   240    return false;
   241  }
   242  
   243  TEST(test_runtime_nebulas_rank, build_graph_from_transactions) {
   244    std::vector<int32_t> addr_set;
   245    auto txs_ptr = gen_transactions(addr_set);
   246    auto ret = neb::rt::nr::nebulas_rank::build_graph_from_transactions(*txs_ptr);
   247    bool is_found = check_for_transaction_graph(std::move(ret), *txs_ptr);
   248    EXPECT_TRUE(is_found);
   249  }
   250  
   251  TEST(test_runtime_nebulas_rank, build_transaction_graphs) {
   252    std::random_device rd;
   253    std::mt19937 mt(rd());
   254    std::uniform_int_distribution<> dis(0, 1 << 10);
   255    int32_t txs_v_size = dis(mt);
   256  
   257    std::vector<std::vector<neb::fs::transaction_info_t>> txs_v;
   258    for (int32_t i = 0; i < txs_v_size; i++) {
   259      std::vector<int32_t> addr_set;
   260      auto txs_ptr = gen_transactions(addr_set);
   261      txs_v.push_back(*txs_ptr);
   262    }
   263    auto ret = neb::rt::nr::nebulas_rank::build_transaction_graphs(txs_v);
   264    auto &g_v = *ret;
   265  
   266    for (int32_t i = 0; i < txs_v_size; i++) {
   267      bool is_found = check_for_transaction_graph(std::move(g_v[i]), txs_v[i]);
   268      EXPECT_TRUE(is_found);
   269    }
   270  }
   271  
   272  TEST(test_runtime_nebulas_rank, get_max_height_this_block_interval) {
   273    std::vector<neb::fs::transaction_info_t> txs;
   274    auto ret = neb::rt::nr::nebulas_rank::get_max_height_this_block_interval(txs);
   275    EXPECT_EQ(0, ret);
   276  
   277    std::vector<int32_t> addr_set;
   278    auto tmp = gen_transactions(addr_set);
   279    txs = *tmp;
   280    std::sort(txs.begin(), txs.end(),
   281              [](const neb::fs::transaction_info_t &info1,
   282                 const neb::fs::transaction_info_t &info2) {
   283                return info1.m_height < info2.m_height;
   284              });
   285    ret = neb::rt::nr::nebulas_rank::get_max_height_this_block_interval(txs);
   286    EXPECT_EQ(ret, txs.back().m_height);
   287  }
   288  
   289  TEST(test_runtime_nebulas_rank, get_normal_accounts) {
   290    std::vector<int32_t> addr_set;
   291    auto txs_ptr = gen_transactions(addr_set);
   292    auto ret = neb::rt::nr::nebulas_rank::get_normal_accounts(*txs_ptr);
   293  
   294    int32_t addr_sum = 0;
   295    for (size_t i = 0; i < addr_set.size(); i++) {
   296      if (addr_set[i]) {
   297        char ch = 'a' + i;
   298        auto addr = neb::to_address(std::string(1, ch));
   299        EXPECT_TRUE(ret->find(addr) != ret->end());
   300        addr_sum += addr_set[i];
   301      }
   302    }
   303    EXPECT_EQ(addr_sum, ret->size());
   304  }
   305  
   306  TEST(test_runtime_nebulas_rank, f_account_weight) {
   307    auto tmp_func = [](float in_val, float out_val) {
   308      float pi = std::acos(-1.0);
   309      float atan_val = (in_val == 0 ? pi / 2 : std::atan(out_val / in_val));
   310      float in_out_sum = in_val + out_val;
   311      float tmp = std::sin(pi / 4.0 - atan_val);
   312      float ret = in_out_sum * std::exp((-2.0) * tmp * tmp);
   313      return ret;
   314    };
   315  
   316    std::random_device rd;
   317    std::mt19937 mt(rd());
   318    std::uniform_int_distribution<> dis(0, std::numeric_limits<int16_t>::max());
   319  
   320    for (int32_t i = 0; i < 1000; i++) {
   321      auto in_val = dis(mt);
   322      auto out_val = dis(mt);
   323      auto expect_ret = tmp_func(in_val, out_val);
   324      auto actual_ret =
   325          neb::rt::nr::nebulas_rank::f_account_weight(in_val, out_val);
   326      EXPECT_TRUE(neb::math::abs(actual_ret, neb::floatxx_t(expect_ret)) <
   327                  precesion(expect_ret, 1e1));
   328    }
   329  }
   330  
   331  TEST(test_runtime_nebulas_rank, f_accout_rank) {
   332    auto tmp_func = [](int64_t a, int64_t b, int64_t c, int64_t d, float theta,
   333                       float mu, float lambda, float S, float R) {
   334      auto gamma = std::pow(theta * R / (R + mu), lambda);
   335      auto ret = (S / (1.0 + std::pow(a / S, 1.0 / b))) * gamma;
   336      return ret;
   337    };
   338  
   339    int64_t a = 100;
   340    int64_t b = 2;
   341    int64_t c = 6;
   342    int64_t d = -9;
   343    float theta = 1.0;
   344    float mu = 1.0;
   345    float lambda = 2.0;
   346  
   347    std::random_device rd;
   348    std::mt19937 mt(rd());
   349    std::uniform_int_distribution<> dis(0, std::numeric_limits<int32_t>::max());
   350  
   351    for (int32_t i = 0; i < 10; i++) {
   352      auto S = dis(mt);
   353      auto R = dis(mt);
   354      auto expect_ret = tmp_func(a, b, c, d, theta, mu, lambda, S, R);
   355      auto actual_ret = neb::rt::nr::nebulas_rank::f_account_rank(
   356          a, b, c, d, theta, mu, lambda, S, R);
   357      EXPECT_TRUE(neb::math::abs(actual_ret, neb::floatxx_t(expect_ret)) <
   358                  precesion(expect_ret, 1e2));
   359    }
   360  }
   361  
   362  TEST(test_runtime_nebulas_rank, get_account_balance_median) {
   363    std::unordered_set<neb::address_t> accounts;
   364    std::vector<std::vector<neb::fs::transaction_info_t>> txs;
   365    neb::rt::nr::account_db_ptr_t db_ptr;
   366    auto ret = neb::rt::nr::nebulas_rank::get_account_balance_median(accounts,
   367                                                                     txs, db_ptr);
   368    EXPECT_TRUE(ret->empty());
   369  }
   370  
   371  TEST(test_runtime_nebulas_rank, get_account_weight) {
   372    std::unordered_map<neb::address_t, neb::rt::in_out_val_t> in_out_vals;
   373    neb::rt::nr::account_db_ptr_t db_ptr;
   374    auto ret = neb::rt::nr::nebulas_rank::get_account_weight(in_out_vals, db_ptr);
   375    EXPECT_TRUE(ret->empty());
   376  }
   377  
   378  TEST(test_runtime_nebulas_rank, get_account_rank) {
   379    std::unordered_map<neb::address_t, neb::floatxx_t> acc_m;
   380    std::unordered_map<neb::address_t, neb::floatxx_t> acc_w;
   381    neb::rt::nr::rank_params_t rp;
   382    auto ret = neb::rt::nr::nebulas_rank::get_account_rank(acc_m, acc_w, rp);
   383    EXPECT_TRUE(ret->empty());
   384  
   385    acc_m.insert(std::make_pair(neb::to_address("a"), neb::floatxx_t(1)));
   386    ret = neb::rt::nr::nebulas_rank::get_account_rank(acc_m, acc_w, rp);
   387    EXPECT_TRUE(ret->empty());
   388  
   389    acc_m.clear();
   390    acc_w.insert(std::make_pair(neb::to_address("a"), neb::floatxx_t(1)));
   391    ret = neb::rt::nr::nebulas_rank::get_account_rank(acc_m, acc_w, rp);
   392    EXPECT_TRUE(ret->empty());
   393  
   394    rp = neb::rt::nr::rank_params_t{
   395        100, 2, 6, -9, neb::floatxx_t(1), neb::floatxx_t(1), neb::floatxx_t(2)};
   396    acc_m.insert(std::make_pair(neb::to_address("a"), neb::floatxx_t(1)));
   397    ret = neb::rt::nr::nebulas_rank::get_account_rank(acc_m, acc_w, rp);
   398    EXPECT_TRUE(!ret->empty());
   399    EXPECT_EQ(ret->size(), 1);
   400    EXPECT_EQ(ret->begin()->first, neb::to_address("a"));
   401  
   402    auto tmp = neb::rt::nr::nebulas_rank::f_account_rank(
   403        100, 2, 6, -9, neb::floatxx_t(1), neb::floatxx_t(1), neb::floatxx_t(2),
   404        neb::floatxx_t(1), neb::floatxx_t(1));
   405    EXPECT_TRUE(ret->begin()->second == tmp);
   406  }
   407  
   408  TEST(test_runtime_nebulas_rank, full_fill_meta_info) {
   409    std::vector<std::pair<std::string, std::string>> meta(
   410        {{"start_height", std::to_string(1)},
   411         {"end_height", std::to_string(2)},
   412         {"version", std::to_string(3)}});
   413    boost::property_tree::ptree pt;
   414    neb::rt::nr::nebulas_rank::full_fill_meta_info(meta, pt);
   415    EXPECT_EQ(pt.get<uint64_t>("start_height"), 1);
   416    EXPECT_EQ(pt.get<uint64_t>("end_height"), 2);
   417    EXPECT_EQ(pt.get<uint64_t>("version"), 3);
   418  }
   419  
   420  TEST(test_runtime_nebulas_rank, convert_nr_info_to_ptree) {
   421    neb::rt::nr::nr_info_t info;
   422    boost::property_tree::ptree pt;
   423    neb::rt::nr::nebulas_rank::convert_nr_info_to_ptree(info, pt);
   424  }
   425  
   426  TEST(test_runtime_nebulas_rank, json_seri_deseri) {
   427    std::random_device rd;
   428    std::mt19937 mt(rd());
   429    std::uniform_int_distribution<> dis(0, std::numeric_limits<int16_t>::max());
   430  
   431    std::vector<std::shared_ptr<neb::rt::nr::nr_info_t>> infos;
   432    std::vector<std::pair<std::string, std::string>> meta(
   433        {{"start_height", std::to_string(dis(mt))},
   434         {"end_height", std::to_string(dis(mt))},
   435         {"version", std::to_string(dis(mt))}});
   436    int32_t infos_size = std::sqrt(dis(mt));
   437    for (int32_t i = 0; i < infos_size; i++) {
   438      auto info_ptr =
   439          std::shared_ptr<neb::rt::nr::nr_info_t>(new neb::rt::nr::nr_info_t{
   440              uint32_t(std::sqrt(dis(mt))), dis(mt), neb::floatxx_t(dis(mt)),
   441              neb::floatxx_t(dis(mt)), neb::floatxx_t(dis(mt))});
   442      infos.push_back(info_ptr);
   443    }
   444  
   445    neb::rt::nr::nr_ret_type nr_ret;
   446    std::get<0>(nr_ret) = 1;
   447    std::get<1>(nr_ret) = neb::rt::meta_info_to_json(meta);
   448    std::get<2>(nr_ret) = infos;
   449    auto str_ptr = neb::rt::nr::nebulas_rank::nr_info_to_json(nr_ret);
   450    nr_ret = neb::rt::nr::nebulas_rank::json_to_nr_info(*str_ptr);
   451    auto &info_v = std::get<2>(nr_ret);
   452    EXPECT_EQ(infos_size, info_v.size());
   453  
   454    for (int32_t i = 0; i < infos_size; i++) {
   455      EXPECT_EQ(infos[i]->m_address, info_v[i]->m_address);
   456      EXPECT_EQ(infos[i]->m_median, info_v[i]->m_median);
   457      EXPECT_EQ(infos[i]->m_weight, info_v[i]->m_weight);
   458      EXPECT_EQ(infos[i]->m_nr_score, info_v[i]->m_nr_score);
   459    }
   460  }
   461