Scorum
database_witness_schedule.cpp
Go to the documentation of this file.
8 
10 
11 namespace scorum {
12 namespace chain {
13 
14 namespace witness_schedule {
15 
17 {
22 };
23 
24 using schedule_type = std::vector<printable_schedule_item>;
25 
27 {
28  fc::uint128 current_virtual_time;
31 };
32 
34 {
36 
39  ret.items.reserve(wso.num_scheduled_witnesses);
40 
41  for (int ci = 0; ci < wso.num_scheduled_witnesses; ++ci)
42  {
43  const account_name_type& witness = wso.current_shuffled_witnesses[ci];
44  const auto& witness_obj = witness_service.get(witness);
45  ret.items.push_back({ witness_obj.id, witness, witness_obj.votes, witness_obj.virtual_scheduled_time });
46  }
47 
48  return ret;
49 }
50 }
51 
56 void database::update_witness_schedule()
57 {
58  database& _db = (*this);
59 
60  if ((_db.head_block_num() % SCORUM_MAX_WITNESSES) == 0)
61  {
62  block_info ctx = _db.head_block_context();
63 
64  debug_log(ctx, "update_witness_schedule");
65 
66  auto& schedule_service = _db.obtain_service<dbs_witness_schedule>();
67  auto& witness_service = _db.witness_service();
68 
69  const witness_schedule_object& wso = schedule_service.get();
70 
71  using active_witnesses_container = boost::container::flat_map<witness_id_type, account_name_type>;
72 
73  active_witnesses_container active_witnesses;
74  active_witnesses.reserve(SCORUM_MAX_WITNESSES);
75 
76  const auto& widx = _db.get_index<witness_index>().indices().get<by_vote_name>();
77 
78  for (auto itr = widx.begin(); itr != widx.end(); ++itr)
79  {
80  debug_log(ctx, "witness=${w}", ("w", *itr));
81  }
82 
83  for (auto itr = widx.begin(); itr != widx.end() && active_witnesses.size() < SCORUM_MAX_VOTED_WITNESSES; ++itr)
84  {
85  if (itr->signing_key == public_key_type())
86  {
87  continue;
88  }
89 
90  debug_log(ctx, "active=${active}", ("active", itr->owner));
91 
92  FC_ASSERT(active_witnesses.insert(std::make_pair(itr->id, itr->owner)).second);
93  _db.modify(*itr, [&](witness_object& wo) { wo.schedule = witness_object::top20; });
94  }
95 
97  fc::uint128 new_virtual_time = wso.current_virtual_time;
98 
99  const auto& schedule_idx = _db.get_index<witness_index>().indices().get<by_schedule_time>();
100  auto sitr = schedule_idx.begin();
101  std::vector<decltype(sitr)> processed_witnesses;
102 
103  for (; sitr != schedule_idx.end() && active_witnesses.size() < SCORUM_MAX_WITNESSES; ++sitr)
104  {
105  new_virtual_time = sitr->virtual_scheduled_time;
106  processed_witnesses.push_back(sitr);
107 
108  if (sitr->signing_key == public_key_type())
109  {
110  continue;
111  }
112 
113  if (active_witnesses.find(sitr->id) == active_witnesses.end())
114  {
115  FC_ASSERT(active_witnesses.insert(std::make_pair(sitr->id, sitr->owner)).second);
116  _db.modify(*sitr, [&](witness_object& wo) { wo.schedule = witness_object::timeshare; });
117 
118  debug_log(ctx, "runner=${runner}", ("runner", *sitr));
119  }
120  }
121 
122  debug_log(ctx, "number_of_active_witnesses=${active_witnesses}", ("active_witnesses", active_witnesses.size()));
123  debug_log(ctx, "max_number=${SCORUM_MAX_WITNESSES}", ("SCORUM_MAX_WITNESSES", SCORUM_MAX_WITNESSES));
124 
126  for (auto itr = processed_witnesses.begin(); itr != processed_witnesses.end(); ++itr)
127  {
128  auto new_virtual_scheduled_time
129  = new_virtual_time + VIRTUAL_SCHEDULE_LAP_LENGTH / ((*itr)->votes.value + 1);
130  if (new_virtual_scheduled_time < new_virtual_time)
131  {
133  new_virtual_time = fc::uint128();
134  _reset_witness_virtual_schedule_time();
135  break;
136  }
137  _db.modify(*(*itr), [&](witness_object& wo) {
138  wo.virtual_position = fc::uint128();
139  wo.virtual_last_update = new_virtual_time;
140  wo.virtual_scheduled_time = new_virtual_scheduled_time;
141 
142  debug_log(ctx, "update_wo=${wo}", ("wo", wo));
143  });
144  }
145 
146  schedule_service.update([&](witness_schedule_object& _wso) {
147  for (size_t i = 0; i < active_witnesses.size(); i++)
148  {
149  _wso.current_shuffled_witnesses[i] = active_witnesses.nth(i)->second;
150  }
151 
152  for (size_t i = active_witnesses.size(); i < SCORUM_MAX_WITNESSES_LIMIT; i++)
153  {
154  _wso.current_shuffled_witnesses[i] = account_name_type();
155  }
156 
157  _wso.num_scheduled_witnesses = std::max<uint8_t>(active_witnesses.size(), 1);
158 
160  auto now_hi = uint64_t(_db.head_block_time().sec_since_epoch()) << 32;
161 
162  debug_log(ctx, "head_block_time=${t}", ("t", _db.head_block_time().to_iso_string()));
163  debug_log(ctx, "now_hi=${now_hi}", ("now_hi", now_hi));
164 
165  debug_log(ctx, "before_shufle=${schedule}",
166  ("schedule", witness_schedule::get_witness_schedule(schedule_service.get(), witness_service)));
167 
168  for (uint32_t i = 0; i < _wso.num_scheduled_witnesses; ++i)
169  {
172  uint64_t k = now_hi + uint64_t(i) * 2685821657736338717ULL;
173  k ^= (k >> 12);
174  k ^= (k << 25);
175  k ^= (k >> 27);
176  k *= 2685821657736338717ULL;
177 
178  uint32_t jmax = _wso.num_scheduled_witnesses - i;
179  uint32_t j = i + k % jmax;
180  std::swap(_wso.current_shuffled_witnesses[i], _wso.current_shuffled_witnesses[j]);
181  }
182 
183  _wso.current_virtual_time = new_virtual_time;
184  });
185 
186  debug_log(ctx, "new_schedule=${schedule}",
187  ("schedule", witness_schedule::get_witness_schedule(schedule_service.get(), witness_service)));
188 
189  _update_witness_majority_version();
190  _update_witness_hardfork_version_votes();
191  _update_witness_median_props();
192  }
193 }
194 
195 void database::_reset_witness_virtual_schedule_time()
196 {
197  database& _db = (*this);
198 
199  block_info ctx = _db.head_block_context();
200 
201  debug_log(ctx, "_reset_witness_virtual_schedule_time");
202 
203  auto& schedule_service = _db.obtain_service<dbs_witness_schedule>();
204 
205  schedule_service.update([&](witness_schedule_object& o) {
206  o.current_virtual_time = fc::uint128(); // reset it 0
207  });
208 
209  const witness_schedule_object& wso = schedule_service.get();
210 
211  const auto& idx = _db.get_index<witness_index>().indices();
212  for (const auto& witness : idx)
213  {
214  _db.modify(witness, [&](witness_object& wobj) {
215  wobj.virtual_position = fc::uint128();
216  wobj.virtual_last_update = wso.current_virtual_time;
217  wobj.virtual_scheduled_time = VIRTUAL_SCHEDULE_LAP_LENGTH / (wobj.votes.value + 1);
218  });
219  }
220 }
221 
222 void database::_update_witness_median_props()
223 {
224  // clang-format off
225 
226  database& _db = (*this);
227 
228  const witness_schedule_object& wso = _db.obtain_service<dbs_witness_schedule>().get();
229  auto& witness_service = _db.witness_service();
230 
232  std::vector<const witness_object*> active;
233  active.reserve(wso.num_scheduled_witnesses);
234  for (int i = 0; i < wso.num_scheduled_witnesses; i++)
235  {
236  active.push_back(&witness_service.get(wso.current_shuffled_witnesses[i]));
237  }
238 
240  std::sort(active.begin(), active.end(), [&](const witness_object* a, const witness_object* b) {
241  return a->proposed_chain_props.account_creation_fee.amount < b->proposed_chain_props.account_creation_fee.amount;
242  });
243  asset median_account_creation_fee = active[active.size() / 2]->proposed_chain_props.account_creation_fee;
244 
246  std::sort(active.begin(), active.end(), [&](const witness_object* a, const witness_object* b) {
247  return a->proposed_chain_props.maximum_block_size < b->proposed_chain_props.maximum_block_size;
248  });
249  uint32_t median_maximum_block_size = active[active.size() / 2]->proposed_chain_props.maximum_block_size;
250 
251  _db.obtain_service<dbs_dynamic_global_property>().update([&](dynamic_global_property_object& _dgpo) {
252  _dgpo.median_chain_props.account_creation_fee = median_account_creation_fee;
253  _dgpo.median_chain_props.maximum_block_size = median_maximum_block_size;
254  });
255 
256  // clang-format on
257 }
258 
259 void database::_update_witness_majority_version()
260 {
261  database& _db = (*this);
262 
263  const witness_schedule_object& wso = _db.obtain_service<dbs_witness_schedule>().get();
264  auto& witness_service = _db.witness_service();
265 
266  flat_map<version, uint32_t, std::greater<version>> witness_versions;
267  for (uint32_t i = 0; i < wso.num_scheduled_witnesses; i++)
268  {
269  auto witness = witness_service.get(wso.current_shuffled_witnesses[i]);
270  if (witness_versions.find(witness.running_version) == witness_versions.end())
271  {
272  witness_versions[witness.running_version] = 1;
273  }
274  else
275  {
276  witness_versions[witness.running_version] += 1;
277  }
278  }
279 
280  auto majority_version = _db.obtain_service<dbs_dynamic_global_property>().get().majority_version;
281 
282  // The map should be sorted highest version to smallest, so we iterate until we hit the majority of witnesses on
283  // at least this version
284  for (auto ver_itr = witness_versions.begin(); ver_itr != witness_versions.end(); ++ver_itr)
285  {
286  auto witnesses_on_version = ver_itr->second;
287  if (witnesses_on_version >= SCORUM_HARDFORK_REQUIRED_WITNESSES)
288  {
289  majority_version = ver_itr->first;
290  break;
291  }
292  }
293 
294  _db.obtain_service<dbs_dynamic_global_property>().update(
295  [&](dynamic_global_property_object& _dgpo) { _dgpo.majority_version = majority_version; });
296 }
297 
298 void database::_update_witness_hardfork_version_votes()
299 {
300  database& _db = (*this);
301 
302  const witness_schedule_object& wso = _db.obtain_service<dbs_witness_schedule>().get();
303  auto& witness_service = _db.witness_service();
304 
305  flat_map<std::tuple<hardfork_version, time_point_sec>, uint32_t> hardfork_version_votes;
306 
307  for (uint32_t i = 0; i < wso.num_scheduled_witnesses; i++)
308  {
309  auto witness = witness_service.get(wso.current_shuffled_witnesses[i]);
310 
311  auto version_vote = std::make_tuple(witness.hardfork_version_vote, witness.hardfork_time_vote);
312  if (hardfork_version_votes.find(version_vote) == hardfork_version_votes.end())
313  {
314  hardfork_version_votes[version_vote] = 1;
315  }
316  else
317  {
318  hardfork_version_votes[version_vote] += 1;
319  }
320  }
321 
322  auto hf_itr = hardfork_version_votes.begin();
323 
324  while (hf_itr != hardfork_version_votes.end())
325  {
326  if (hf_itr->second >= SCORUM_HARDFORK_REQUIRED_WITNESSES)
327  {
328  const auto& hfp = _db.obtain_service<dbs_hardfork_property>().get();
329  if (hfp.next_hardfork != std::get<0>(hf_itr->first) || hfp.next_hardfork_time != std::get<1>(hf_itr->first))
330  {
331  _db.modify(hfp, [&](hardfork_property_object& hpo) {
332  hpo.next_hardfork = std::get<0>(hf_itr->first);
333  hpo.next_hardfork_time = std::get<1>(hf_itr->first);
334  });
335  }
336  break;
337  }
338 
339  ++hf_itr;
340  }
341 
342  // We no longer have a majority
343  if (hf_itr == hardfork_version_votes.end())
344  {
345  _db.obtain_service<dbs_hardfork_property>().update(
346  [&](hardfork_property_object& hpo) { hpo.next_hardfork = hpo.current_hardfork_version; });
347  }
348 }
349 
350 } // namespace chain
351 } // namespace scorum
352 
354  (witness_id)(witness_name)(votes)(virtual_scheduled_time))
355 
356 FC_REFLECT(scorum::chain::witness_schedule::printable_schedule, (current_virtual_time)(num_scheduled_witnesses)(items))
database(uint32_t opt)
Definition: database.cpp:168
fc::array< account_name_type, SCORUM_MAX_WITNESSES_LIMIT > current_shuffled_witnesses
#define SCORUM_MAX_VOTED_WITNESSES
Definition: config.hpp:177
#define SCORUM_HARDFORK_REQUIRED_WITNESSES
Definition: config.hpp:182
#define SCORUM_MAX_WITNESSES_LIMIT
Definition: config.hpp:180
#define SCORUM_MAX_WITNESSES
Definition: config.hpp:179
#define debug_log(CTX, FORMAT,...)
Definition: debug_log.hpp:3
FC_REFLECT(appender_args,(appender)(stream)) FC_REFLECT_DERIVED(file_appender_args
printable_schedule get_witness_schedule(const witness_schedule_object &wso, witness_service_i &witness_service)
std::vector< printable_schedule_item > schedule_type
void update(fc::flat_map< uuid_type, bet_resolved_operation > &results, const bet_data &bet, asset income, uuid_type game_uuid, bet_resolve_kind kind)
shared_multi_index_container< witness_object, indexed_by< ordered_unique< tag< by_id >, member< witness_object, witness_id_type, &witness_object::id > >, ordered_unique< tag< by_name >, member< witness_object, account_name_type, &witness_object::owner > >, ordered_unique< tag< by_vote_name >, composite_key< witness_object, member< witness_object, share_type, &witness_object::votes >, member< witness_object, account_name_type, &witness_object::owner > >, composite_key_compare< std::greater< share_type >, std::less< account_name_type > > >, ordered_unique< tag< by_schedule_time >, composite_key< witness_object, member< witness_object, fc::uint128, &witness_object::virtual_scheduled_time >, member< witness_object, witness_id_type, &witness_object::id > > > > > witness_index
dbs_service_base< witness_schedule_service_i > dbs_witness_schedule
fc::safe< share_value_type > share_type
Definition: types.hpp:73
fc::fixed_string_16 account_name_type
Definition: types.hpp:62
Definition: asset.cpp:15
virtual const witness_object & get(const account_name_type &owner) const =0