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