BitShares-Core  5.0.0
BitShares blockchain implementation and command-line interface software
db_maint.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
3  *
4  * The MIT License
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 #include <fc/uint128.hpp>
26 
28 
31 #include <graphene/chain/hardfork.hpp>
32 
50 
51 namespace graphene { namespace chain {
52 
53 template<class Index>
54 vector<std::reference_wrapper<const typename Index::object_type>> database::sort_votable_objects(size_t count) const
55 {
56  using ObjectType = typename Index::object_type;
57  const auto& all_objects = get_index_type<Index>().indices();
58  count = std::min(count, all_objects.size());
59  vector<std::reference_wrapper<const ObjectType>> refs;
60  refs.reserve(all_objects.size());
61  std::transform(all_objects.begin(), all_objects.end(),
62  std::back_inserter(refs),
63  [](const ObjectType& o) { return std::cref(o); });
64  std::partial_sort(refs.begin(), refs.begin() + count, refs.end(),
65  [this](const ObjectType& a, const ObjectType& b)->bool {
66  share_type oa_vote = _vote_tally_buffer[a.vote_id];
67  share_type ob_vote = _vote_tally_buffer[b.vote_id];
68  if( oa_vote != ob_vote )
69  return oa_vote > ob_vote;
70  return a.vote_id < b.vote_id;
71  });
72 
73  refs.resize(count, refs.front());
74  return refs;
75 }
76 
77 template<class Type>
78 void database::perform_account_maintenance(Type tally_helper)
79 {
80  const auto& bal_idx = get_index_type< account_balance_index >().indices().get< by_maintenance_flag >();
81  if( bal_idx.begin() != bal_idx.end() )
82  {
83  auto bal_itr = bal_idx.rbegin();
84  while( bal_itr->maintenance_flag )
85  {
86  const account_balance_object& bal_obj = *bal_itr;
87 
88  modify( get_account_stats_by_owner( bal_obj.owner ), [&bal_obj](account_statistics_object& aso) {
89  aso.core_in_balance = bal_obj.balance;
90  });
91 
92  modify( bal_obj, []( account_balance_object& abo ) {
93  abo.maintenance_flag = false;
94  });
95 
96  bal_itr = bal_idx.rbegin();
97  }
98  }
99 
100  const auto& stats_idx = get_index_type< account_stats_index >().indices().get< by_maintenance_seq >();
101  auto stats_itr = stats_idx.lower_bound( true );
102 
103  while( stats_itr != stats_idx.end() )
104  {
105  const account_statistics_object& acc_stat = *stats_itr;
106  const account_object& acc_obj = acc_stat.owner( *this );
107  ++stats_itr;
108 
109  if( acc_stat.has_some_core_voting() )
110  tally_helper( acc_obj, acc_stat );
111 
112  if( acc_stat.has_pending_fees() )
113  acc_stat.process_fees( acc_obj, *this );
114  }
115 
116 }
117 
120 {
121  private:
122  share_type pay;
123  database& db;
124 
125  public:
127  : pay(pay), db(db) {}
128 
129  typedef void result_type;
130  template<typename W>
131  void operator()(W& worker)const
132  {
133  worker.pay_worker(pay, db);
134  }
135 };
136 
137 void database::update_worker_votes()
138 {
139  const auto& idx = get_index_type<worker_index>().indices().get<by_account>();
140  auto itr = idx.begin();
141  auto itr_end = idx.end();
142  bool allow_negative_votes = (head_block_time() < HARDFORK_607_TIME);
143  while( itr != itr_end )
144  {
145  modify( *itr, [this,allow_negative_votes]( worker_object& obj )
146  {
147  obj.total_votes_for = _vote_tally_buffer[obj.vote_for];
148  obj.total_votes_against = allow_negative_votes ? _vote_tally_buffer[obj.vote_against] : 0;
149  });
150  ++itr;
151  }
152 }
153 
154 void database::pay_workers( share_type& budget )
155 {
156  const auto head_time = head_block_time();
157 // ilog("Processing payroll! Available budget is ${b}", ("b", budget));
158  vector<std::reference_wrapper<const worker_object>> active_workers;
159  // TODO optimization: add by_expiration index to avoid iterating through all objects
160  get_index_type<worker_index>().inspect_all_objects([head_time, &active_workers](const object& o) {
161  const worker_object& w = static_cast<const worker_object&>(o);
162  if( w.is_active(head_time) && w.approving_stake() > 0 )
163  active_workers.emplace_back(w);
164  });
165 
166  // worker with more votes is preferred
167  // if two workers exactly tie for votes, worker with lower ID is preferred
168  std::sort(active_workers.begin(), active_workers.end(), [](const worker_object& wa, const worker_object& wb) {
169  share_type wa_vote = wa.approving_stake();
170  share_type wb_vote = wb.approving_stake();
171  if( wa_vote != wb_vote )
172  return wa_vote > wb_vote;
173  return wa.id < wb.id;
174  });
175 
176  const auto last_budget_time = get_dynamic_global_properties().last_budget_time;
177  const auto passed_time_ms = head_time - last_budget_time;
178  const auto passed_time_count = passed_time_ms.count();
179  const auto day_count = fc::days(1).count();
180  for( uint32_t i = 0; i < active_workers.size() && budget > 0; ++i )
181  {
182  const worker_object& active_worker = active_workers[i];
183  share_type requested_pay = active_worker.daily_pay;
184 
185  // Note: if there is a good chance that passed_time_count == day_count,
186  // for better performance, can avoid the 128 bit calculation by adding a check.
187  // Since it's not the case on BitShares mainnet, we're not using a check here.
188  fc::uint128_t pay = requested_pay.value;
189  pay *= passed_time_count;
190  pay /= day_count;
191  requested_pay = static_cast<uint64_t>(pay);
192 
193  share_type actual_pay = std::min(budget, requested_pay);
194  //ilog(" ==> Paying ${a} to worker ${w}", ("w", active_worker.id)("a", actual_pay));
195  modify(active_worker, [&](worker_object& w) {
196  w.worker.visit(worker_pay_visitor(actual_pay, *this));
197  });
198 
199  budget -= actual_pay;
200  }
201 }
202 
203 void database::update_active_witnesses()
204 { try {
205  assert( _witness_count_histogram_buffer.size() > 0 );
206  share_type stake_target = (_total_voting_stake[1]-_witness_count_histogram_buffer[0]) / 2;
207 
210 
211  share_type stake_tally = 0;
212 
213  size_t witness_count = 0;
214  if( stake_target > 0 )
215  {
216  while( (witness_count < _witness_count_histogram_buffer.size() - 1)
217  && (stake_tally <= stake_target) )
218  {
219  stake_tally += _witness_count_histogram_buffer[++witness_count];
220  }
221  }
222 
224 
225  witness_count = std::max( witness_count*2+1, (size_t)cpo.immutable_parameters.min_witness_count );
226  auto wits = sort_votable_objects<witness_index>( witness_count );
227 
229 
230  auto update_witness_total_votes = [this]( const witness_object& wit ) {
231  modify( wit, [this]( witness_object& obj )
232  {
233  obj.total_votes = _vote_tally_buffer[obj.vote_id];
234  });
235  };
236 
237  if( _track_standby_votes )
238  {
239  const auto& all_witnesses = get_index_type<witness_index>().indices();
240  for( const witness_object& wit : all_witnesses )
241  {
242  update_witness_total_votes( wit );
243  }
244  }
245  else
246  {
247  for( const witness_object& wit : wits )
248  {
249  update_witness_total_votes( wit );
250  }
251  }
252 
253  // Update witness authority
254  modify( get(GRAPHENE_WITNESS_ACCOUNT), [this,&wits]( account_object& a )
255  {
256  if( head_block_time() < HARDFORK_533_TIME )
257  {
258  uint64_t total_votes = 0;
259  map<account_id_type, uint64_t> weights;
260  a.active.weight_threshold = 0;
261  a.active.clear();
262 
263  for( const witness_object& wit : wits )
264  {
265  weights.emplace(wit.witness_account, _vote_tally_buffer[wit.vote_id]);
266  total_votes += _vote_tally_buffer[wit.vote_id];
267  }
268 
269  // total_votes is 64 bits. Subtract the number of leading low bits from 64 to get the number of useful bits,
270  // then I want to keep the most significant 16 bits of what's left.
271  int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(total_votes)) - 15, 0);
272  for( const auto& weight : weights )
273  {
274  // Ensure that everyone has at least one vote. Zero weights aren't allowed.
275  uint16_t votes = std::max((weight.second >> bits_to_drop), uint64_t(1) );
276  a.active.account_auths[weight.first] += votes;
277  a.active.weight_threshold += votes;
278  }
279 
280  a.active.weight_threshold /= 2;
281  a.active.weight_threshold += 1;
282  }
283  else
284  {
285  vote_counter vc;
286  for( const witness_object& wit : wits )
287  vc.add( wit.witness_account, _vote_tally_buffer[wit.vote_id] );
288  vc.finish( a.active );
289  }
290  } );
291 
292  modify( gpo, [&wits]( global_property_object& gp )
293  {
294  gp.active_witnesses.clear();
295  gp.active_witnesses.reserve(wits.size());
296  std::transform(wits.begin(), wits.end(),
297  std::inserter(gp.active_witnesses, gp.active_witnesses.end()),
298  [](const witness_object& w) {
299  return w.id;
300  });
301  });
302 
304 
305 void database::update_active_committee_members()
306 { try {
307  assert( _committee_count_histogram_buffer.size() > 0 );
308  share_type stake_target = (_total_voting_stake[0]-_committee_count_histogram_buffer[0]) / 2;
309 
312  share_type stake_tally = 0;
313  size_t committee_member_count = 0;
314  if( stake_target > 0 )
315  {
316  while( (committee_member_count < _committee_count_histogram_buffer.size() - 1)
317  && (stake_tally <= stake_target.value) )
318  {
319  stake_tally += _committee_count_histogram_buffer[++committee_member_count];
320  }
321  }
322 
324 
325  committee_member_count = std::max( committee_member_count*2+1, (size_t)cpo.immutable_parameters.min_committee_member_count );
326  auto committee_members = sort_votable_objects<committee_member_index>( committee_member_count );
327 
328  auto update_committee_member_total_votes = [this]( const committee_member_object& cm ) {
329  modify( cm, [this]( committee_member_object& obj )
330  {
331  obj.total_votes = _vote_tally_buffer[obj.vote_id];
332  });
333  };
334 
335  if( _track_standby_votes )
336  {
337  const auto& all_committee_members = get_index_type<committee_member_index>().indices();
338  for( const committee_member_object& cm : all_committee_members )
339  {
340  update_committee_member_total_votes( cm );
341  }
342  }
343  else
344  {
345  for( const committee_member_object& cm : committee_members )
346  {
347  update_committee_member_total_votes( cm );
348  }
349  }
350 
351  // Update committee authorities
352  if( !committee_members.empty() )
353  {
354  const account_object& committee_account = get(GRAPHENE_COMMITTEE_ACCOUNT);
355  modify( committee_account, [this,&committee_members](account_object& a)
356  {
357  if( head_block_time() < HARDFORK_533_TIME )
358  {
359  uint64_t total_votes = 0;
360  map<account_id_type, uint64_t> weights;
361  a.active.weight_threshold = 0;
362  a.active.clear();
363 
364  for( const committee_member_object& cm : committee_members )
365  {
366  weights.emplace( cm.committee_member_account, _vote_tally_buffer[cm.vote_id] );
367  total_votes += _vote_tally_buffer[cm.vote_id];
368  }
369 
370  // total_votes is 64 bits. Subtract the number of leading low bits from 64 to get the number of useful bits,
371  // then I want to keep the most significant 16 bits of what's left.
372  int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(total_votes)) - 15, 0);
373  for( const auto& weight : weights )
374  {
375  // Ensure that everyone has at least one vote. Zero weights aren't allowed.
376  uint16_t votes = std::max((weight.second >> bits_to_drop), uint64_t(1) );
377  a.active.account_auths[weight.first] += votes;
378  a.active.weight_threshold += votes;
379  }
380 
381  a.active.weight_threshold /= 2;
382  a.active.weight_threshold += 1;
383  }
384  else
385  {
386  vote_counter vc;
387  for( const committee_member_object& cm : committee_members )
388  vc.add( cm.committee_member_account, _vote_tally_buffer[cm.vote_id] );
389  vc.finish( a.active );
390  }
391  });
392  modify( get(GRAPHENE_RELAXED_COMMITTEE_ACCOUNT), [&committee_account](account_object& a)
393  {
394  a.active = committee_account.active;
395  });
396  }
397  modify( get_global_properties(), [&committee_members](global_property_object& gp)
398  {
399  gp.active_committee_members.clear();
400  std::transform(committee_members.begin(), committee_members.end(),
401  std::inserter(gp.active_committee_members, gp.active_committee_members.begin()),
402  [](const committee_member_object& d) { return d.id; });
403  });
405 
406 void database::initialize_budget_record( fc::time_point_sec now, budget_record& rec )const
407 {
409  const asset_object& core = get_core_asset();
411 
412  rec.from_initial_reserve = core.reserved(*this);
415 
416  if( (dpo.last_budget_time == fc::time_point_sec())
417  || (now <= dpo.last_budget_time) )
418  {
419  rec.time_since_last_budget = 0;
420  return;
421  }
422 
423  int64_t dt = (now - dpo.last_budget_time).to_seconds();
424  rec.time_since_last_budget = uint64_t( dt );
425 
426  // We'll consider accumulated_fees to be reserved at the BEGINNING
427  // of the maintenance interval. However, for speed we only
428  // call modify() on the asset_dynamic_data_object once at the
429  // end of the maintenance interval. Thus the accumulated_fees
430  // are available for the budget at this point, but not included
431  // in core.reserved().
432  share_type reserve = rec.from_initial_reserve + core_dd.accumulated_fees;
433  // Similarly, we consider leftover witness_budget to be burned
434  // at the BEGINNING of the maintenance interval.
435  reserve += dpo.witness_budget;
436 
437  fc::uint128_t budget_u128 = reserve.value;
438  budget_u128 *= uint64_t(dt);
439  budget_u128 *= GRAPHENE_CORE_ASSET_CYCLE_RATE;
440  //round up to the nearest satoshi -- this is necessary to ensure
441  // there isn't an "untouchable" reserve, and we will eventually
442  // be able to use the entire reserve
443  budget_u128 += ((uint64_t(1) << GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS) - 1);
444  budget_u128 >>= GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS;
445  if( budget_u128 < static_cast<fc::uint128_t>(reserve.value) )
446  rec.total_budget = share_type(static_cast<uint64_t>(budget_u128));
447  else
448  rec.total_budget = reserve;
449 
450  return;
451 }
452 
456 void database::process_budget()
457 {
458  try
459  {
464 
465  int64_t time_to_maint = (dpo.next_maintenance_time - now).to_seconds();
466  //
467  // The code that generates the next maintenance time should
468  // only produce a result in the future. If this assert
469  // fails, then the next maintenance time algorithm is buggy.
470  //
471  assert( time_to_maint > 0 );
472  //
473  // Code for setting chain parameters should validate
474  // block_interval > 0 (as well as the humans proposing /
475  // voting on changes to block interval).
476  //
477  assert( gpo.parameters.block_interval > 0 );
478  uint64_t blocks_to_maint = (uint64_t(time_to_maint) + gpo.parameters.block_interval - 1) / gpo.parameters.block_interval;
479 
480  // blocks_to_maint > 0 because time_to_maint > 0,
481  // which means numerator is at least equal to block_interval
482 
483  budget_record rec;
484  initialize_budget_record( now, rec );
485  share_type available_funds = rec.total_budget;
486 
487  share_type witness_budget = gpo.parameters.witness_pay_per_block.value * blocks_to_maint;
488  rec.requested_witness_budget = witness_budget;
489  witness_budget = std::min(witness_budget, available_funds);
490  rec.witness_budget = witness_budget;
491  available_funds -= witness_budget;
492 
493  fc::uint128_t worker_budget_u128 = gpo.parameters.worker_budget_per_day.value;
494  worker_budget_u128 *= uint64_t(time_to_maint);
495  worker_budget_u128 /= 60*60*24;
496 
497  share_type worker_budget;
498  if( worker_budget_u128 >= static_cast<fc::uint128_t>(available_funds.value) )
499  worker_budget = available_funds;
500  else
501  worker_budget = static_cast<uint64_t>(worker_budget_u128);
502  rec.worker_budget = worker_budget;
503  available_funds -= worker_budget;
504 
505  share_type leftover_worker_funds = worker_budget;
506  pay_workers(leftover_worker_funds);
507  rec.leftover_worker_funds = leftover_worker_funds;
508  available_funds += leftover_worker_funds;
509 
510  rec.supply_delta = rec.witness_budget
511  + rec.worker_budget
515 
516  modify(core, [&]( asset_dynamic_data_object& _core )
517  {
518  _core.current_supply = (_core.current_supply + rec.supply_delta );
519 
520  assert( rec.supply_delta ==
521  witness_budget
522  + worker_budget
523  - leftover_worker_funds
524  - _core.accumulated_fees
525  - dpo.witness_budget
526  );
527  _core.accumulated_fees = 0;
528  });
529 
530  modify(dpo, [&]( dynamic_global_property_object& _dpo )
531  {
532  // Since initial witness_budget was rolled into
533  // available_funds, we replace it with witness_budget
534  // instead of adding it.
535  _dpo.witness_budget = witness_budget;
536  _dpo.last_budget_time = now;
537  });
538 
539  create< budget_record_object >( [&]( budget_record_object& _rec )
540  {
541  _rec.time = head_block_time();
542  _rec.record = rec;
543  });
544 
545  // available_funds is money we could spend, but don't want to.
546  // we simply let it evaporate back into the reserve.
547  }
549 }
550 
551 template< typename Visitor >
552 void visit_special_authorities( const database& db, Visitor visit )
553 {
554  const auto& sa_idx = db.get_index_type< special_authority_index >().indices().get<by_id>();
555 
556  for( const special_authority_object& sao : sa_idx )
557  {
558  const account_object& acct = sao.account(db);
560  {
561  visit( acct, true, acct.owner_special_authority );
562  }
564  {
565  visit( acct, false, acct.active_special_authority );
566  }
567  }
568 }
569 
571 {
573  [&]( const account_object& acct, bool is_owner, const special_authority& auth )
574  {
575  if( auth.is_type< top_holders_special_authority >() )
576  {
577  // use index to grab the top N holders of the asset and vote_counter to obtain the weights
578 
579  const top_holders_special_authority& tha = auth.get< top_holders_special_authority >();
580  vote_counter vc;
581  const auto& bal_idx = db.get_index_type< account_balance_index >().indices().get< by_asset_balance >();
582  uint8_t num_needed = tha.num_top_holders;
583  if( num_needed == 0 )
584  return;
585 
586  // find accounts
587  const auto range = bal_idx.equal_range( boost::make_tuple( tha.asset ) );
588  for( const account_balance_object& bal : boost::make_iterator_range( range.first, range.second ) )
589  {
590  assert( bal.asset_type == tha.asset );
591  if( bal.owner == acct.id )
592  continue;
593  vc.add( bal.owner, bal.balance.value );
594  --num_needed;
595  if( num_needed == 0 )
596  break;
597  }
598 
599  db.modify( acct, [&]( account_object& a )
600  {
601  vc.finish( is_owner ? a.owner : a.active );
602  if( !vc.is_empty() )
603  a.top_n_control_flags |= (is_owner ? account_object::top_n_control_owner : account_object::top_n_control_active);
604  } );
605  }
606  } );
607 }
608 
610  database& db,
611  uint64_t fba_id,
612  uint16_t network_pct,
613  uint16_t designated_asset_buyback_pct,
614  uint16_t designated_asset_issuer_pct
615 )
616 {
617  FC_ASSERT( uint32_t(network_pct) + uint32_t(designated_asset_buyback_pct) + uint32_t(designated_asset_issuer_pct) == GRAPHENE_100_PERCENT );
618  const fba_accumulator_object& fba = fba_accumulator_id_type( fba_id )(db);
619  if( fba.accumulated_fba_fees == 0 )
620  return;
621 
622  const asset_dynamic_data_object& core_dd = db.get_core_dynamic_data();
623 
624  if( !fba.is_configured(db) )
625  {
626  ilog( "${n} core given to network at block ${b} due to non-configured FBA", ("n", fba.accumulated_fba_fees)("b", db.head_block_time()) );
627  db.modify( core_dd, [&]( asset_dynamic_data_object& _core_dd )
628  {
629  _core_dd.current_supply -= fba.accumulated_fba_fees;
630  } );
631  db.modify( fba, [&]( fba_accumulator_object& _fba )
632  {
633  _fba.accumulated_fba_fees = 0;
634  } );
635  return;
636  }
637 
638  fc::uint128_t buyback_amount_128 = fba.accumulated_fba_fees.value;
639  buyback_amount_128 *= designated_asset_buyback_pct;
640  buyback_amount_128 /= GRAPHENE_100_PERCENT;
641  share_type buyback_amount = static_cast<uint64_t>(buyback_amount_128);
642 
643  fc::uint128_t issuer_amount_128 = fba.accumulated_fba_fees.value;
644  issuer_amount_128 *= designated_asset_issuer_pct;
645  issuer_amount_128 /= GRAPHENE_100_PERCENT;
646  share_type issuer_amount = static_cast<uint64_t>(issuer_amount_128);
647 
648  // this assert should never fail
649  FC_ASSERT( buyback_amount + issuer_amount <= fba.accumulated_fba_fees );
650 
651  share_type network_amount = fba.accumulated_fba_fees - (buyback_amount + issuer_amount);
652 
653  const asset_object& designated_asset = (*fba.designated_asset)(db);
654 
655  if( network_amount != 0 )
656  {
657  db.modify( core_dd, [&]( asset_dynamic_data_object& _core_dd )
658  {
659  _core_dd.current_supply -= network_amount;
660  } );
661  }
662 
664  vop.account_id = *designated_asset.buyback_account;
665  vop.fba_id = fba.id;
666  vop.amount = buyback_amount;
667  if( vop.amount != 0 )
668  {
669  db.adjust_balance( *designated_asset.buyback_account, asset(buyback_amount) );
670  db.push_applied_operation(vop);
671  }
672 
673  vop.account_id = designated_asset.issuer;
674  vop.fba_id = fba.id;
675  vop.amount = issuer_amount;
676  if( vop.amount != 0 )
677  {
678  db.adjust_balance( designated_asset.issuer, asset(issuer_amount) );
679  db.push_applied_operation(vop);
680  }
681 
682  db.modify( fba, [&]( fba_accumulator_object& _fba )
683  {
684  _fba.accumulated_fba_fees = 0;
685  } );
686 }
687 
689 {
693 }
694 
696 {
697  const auto& bbo_idx = db.get_index_type< buyback_index >().indices().get<by_id>();
698  const auto& bal_idx = db.get_index_type< primary_index< account_balance_index > >().get_secondary_index< balances_by_account_index >();
699 
700  for( const buyback_object& bbo : bbo_idx )
701  {
702  const asset_object& asset_to_buy = bbo.asset_to_buy(db);
703  assert( asset_to_buy.buyback_account.valid() );
704 
705  const account_object& buyback_account = (*(asset_to_buy.buyback_account))(db);
706 
707  if( !buyback_account.allowed_assets.valid() )
708  {
709  wlog( "skipping buyback account ${b} at block ${n} because allowed_assets does not exist", ("b", buyback_account)("n", db.head_block_num()) );
710  continue;
711  }
712 
713  for( const auto& entry : bal_idx.get_account_balances( buyback_account.id ) )
714  {
715  const auto* it = entry.second;
716  asset_id_type asset_to_sell = it->asset_type;
717  share_type amount_to_sell = it->balance;
718  if( asset_to_sell == asset_to_buy.id )
719  continue;
720  if( amount_to_sell == 0 )
721  continue;
722  if( buyback_account.allowed_assets->find( asset_to_sell ) == buyback_account.allowed_assets->end() )
723  {
724  wlog( "buyback account ${b} not selling disallowed holdings of asset ${a} at block ${n}", ("b", buyback_account)("a", asset_to_sell)("n", db.head_block_num()) );
725  continue;
726  }
727 
728  try
729  {
730  transaction_evaluation_state buyback_context(&db);
731  buyback_context.skip_fee_schedule_check = true;
732 
733  limit_order_create_operation create_vop;
734  create_vop.fee = asset( 0, asset_id_type() );
735  create_vop.seller = buyback_account.id;
736  create_vop.amount_to_sell = asset( amount_to_sell, asset_to_sell );
737  create_vop.min_to_receive = asset( 1, asset_to_buy.id );
738  create_vop.expiration = time_point_sec::maximum();
739  create_vop.fill_or_kill = false;
740 
741  limit_order_id_type order_id = db.apply_operation( buyback_context, create_vop ).get< object_id_type >();
742 
743  if( db.find( order_id ) != nullptr )
744  {
745  limit_order_cancel_operation cancel_vop;
746  cancel_vop.fee = asset( 0, asset_id_type() );
747  cancel_vop.order = order_id;
748  cancel_vop.fee_paying_account = buyback_account.id;
749 
750  db.apply_operation( buyback_context, cancel_vop );
751  }
752  }
753  catch( const fc::exception& e )
754  {
755  // we can in fact get here, e.g. if asset issuer of buy/sell asset blacklists/whitelists the buyback account
756  wlog( "Skipping buyback processing selling ${as} for ${ab} for buyback account ${b} at block ${n}; exception was ${e}",
757  ("as", asset_to_sell)("ab", asset_to_buy)("b", buyback_account)("n", db.head_block_num())("e", e.to_detail_string()) );
758  continue;
759  }
760  }
761  }
762  return;
763 }
764 
766 {
767  const auto& account_idx = db.get_index_type<account_index>().indices().get<by_id>();
769  for( const account_object& acct : account_idx )
770  {
771  try
772  {
773  transaction_evaluation_state upgrade_context(&db);
774  upgrade_context.skip_fee_schedule_check = true;
775 
776  if( acct.is_annual_member( now ) )
777  {
778  account_upgrade_operation upgrade_vop;
779  upgrade_vop.fee = asset( 0, asset_id_type() );
780  upgrade_vop.account_to_upgrade = acct.id;
781  upgrade_vop.upgrade_to_lifetime_member = true;
782  db.apply_operation( upgrade_context, upgrade_vop );
783  }
784  }
785  catch( const fc::exception& e )
786  {
787  // we can in fact get here, e.g. if asset issuer of buy/sell asset blacklists/whitelists the buyback account
788  wlog( "Skipping annual member deprecate processing for account ${a} (${an}) at block ${n}; exception was ${e}",
789  ("a", acct.id)("an", acct.name)("n", db.head_block_num())("e", e.to_detail_string()) );
790  continue;
791  }
792  }
793  return;
794 }
795 
796 void database::process_bids( const asset_bitasset_data_object& bad )
797 {
798  if( bad.is_prediction_market ) return;
799  if( bad.current_feed.settlement_price.is_null() ) return;
800 
801  asset_id_type to_revive_id = (asset( 0, bad.options.short_backing_asset ) * bad.settlement_price).asset_id;
802  const asset_object& to_revive = to_revive_id( *this );
803  const asset_dynamic_data_object& bdd = to_revive.dynamic_data( *this );
804 
805  const auto& bid_idx = get_index_type< collateral_bid_index >().indices().get<by_price>();
806  const auto start = bid_idx.lower_bound( boost::make_tuple( to_revive_id, price::max( bad.options.short_backing_asset, to_revive_id ), collateral_bid_id_type() ) );
807 
808  share_type covered = 0;
809  auto itr = start;
810  while( covered < bdd.current_supply && itr != bid_idx.end() && itr->inv_swan_price.quote.asset_id == to_revive_id )
811  {
812  const collateral_bid_object& bid = *itr;
813  asset debt_in_bid = bid.inv_swan_price.quote;
814  if( debt_in_bid.amount > bdd.current_supply )
815  debt_in_bid.amount = bdd.current_supply;
816  asset total_collateral = debt_in_bid * bad.settlement_price;
817  total_collateral += bid.inv_swan_price.base;
818  price call_price = price::call_price( debt_in_bid, total_collateral, bad.current_feed.maintenance_collateral_ratio );
819  if( ~call_price >= bad.current_feed.settlement_price ) break;
820  covered += debt_in_bid.amount;
821  ++itr;
822  }
823  if( covered < bdd.current_supply ) return;
824 
825  const auto end = itr;
826  share_type to_cover = bdd.current_supply;
827  share_type remaining_fund = bad.settlement_fund;
828  for( itr = start; itr != end; )
829  {
830  const collateral_bid_object& bid = *itr;
831  ++itr;
832  asset debt_in_bid = bid.inv_swan_price.quote;
833  if( debt_in_bid.amount > bdd.current_supply )
834  debt_in_bid.amount = bdd.current_supply;
835  share_type debt = debt_in_bid.amount;
836  share_type collateral = (debt_in_bid * bad.settlement_price).amount;
837  if( debt >= to_cover )
838  {
839  debt = to_cover;
840  collateral = remaining_fund;
841  }
842  to_cover -= debt;
843  remaining_fund -= collateral;
844  execute_bid( bid, debt, collateral, bad.current_feed );
845  }
846  FC_ASSERT( remaining_fund == 0 );
847  FC_ASSERT( to_cover == 0 );
848 
849  _cancel_bids_and_revive_mpa( to_revive, bad );
850 }
851 
855 {
856  // Update call_price
857  wlog( "Updating all call orders for hardfork core-343 at block ${n}", ("n",db.head_block_num()) );
858  asset_id_type current_asset;
859  const asset_bitasset_data_object* abd = nullptr;
860  // by_collateral index won't change after call_price updated, so it's safe to iterate
861  for( const auto& call_obj : db.get_index_type<call_order_index>().indices().get<by_collateral>() )
862  {
863  if( current_asset != call_obj.debt_type() ) // debt type won't be asset_id_type(), abd will always get initialized
864  {
865  current_asset = call_obj.debt_type();
866  abd = &current_asset(db).bitasset_data(db);
867  }
868  if( !abd || abd->is_prediction_market ) // nothing to do with PM's; check !abd just to be safe
869  continue;
870  db.modify( call_obj, [abd]( call_order_object& call ) {
871  call.call_price = price::call_price( call.get_debt(), call.get_collateral(),
873  });
874  }
875  wlog( "Done updating all call orders for hardfork core-343 at block ${n}", ("n",db.head_block_num()) );
876 }
877 
881 {
882  // Update call_price
883  for( const auto& call_obj : db.get_index_type<call_order_index>().indices().get<by_id>() )
884  {
885  db.modify( call_obj, []( call_order_object& call ) {
886  call.call_price.base.amount = 1;
887  call.call_price.quote.amount = 1;
888  });
889  }
890 }
891 
894 {
895  // Match call orders
896  wlog( "Matching call orders at block ${n}", ("n",db.head_block_num()) );
897  const auto& asset_idx = db.get_index_type<asset_index>().indices().get<by_type>();
898  auto itr = asset_idx.lower_bound( true );
899  while( itr != asset_idx.end() )
900  {
901  const asset_object& a = *itr;
902  ++itr;
903  // be here, next_maintenance_time should have been updated already
904  db.check_call_orders( a, true, false ); // allow black swan, and call orders are taker
905  }
906  wlog( "Done matching call orders at block ${n}", ("n",db.head_block_num()) );
907 }
908 
909 void database::process_bitassets()
910 {
911  time_point_sec head_time = head_block_time();
912  uint32_t head_epoch_seconds = head_time.sec_since_epoch();
913  bool after_hf_core_518 = ( head_time >= HARDFORK_CORE_518_TIME ); // clear expired feeds
914 
915  const auto update_bitasset = [this,head_time,head_epoch_seconds,after_hf_core_518]( asset_bitasset_data_object &o )
916  {
917  o.force_settled_volume = 0; // Reset all BitAsset force settlement volumes to zero
918 
919  // clear expired feeds
920  if( after_hf_core_518 )
921  {
922  const auto &asset = get( o.asset_id );
923  auto flags = asset.options.flags;
924  if ( ( flags & ( witness_fed_asset | committee_fed_asset ) ) &&
925  o.options.feed_lifetime_sec < head_epoch_seconds ) // if smartcoin && check overflow
926  {
927  fc::time_point_sec calculated = head_time - o.options.feed_lifetime_sec;
928  for( auto itr = o.feeds.rbegin(); itr != o.feeds.rend(); ) // loop feeds
929  {
930  auto feed_time = itr->second.first;
931  std::advance( itr, 1 );
932  if( feed_time < calculated )
933  o.feeds.erase( itr.base() ); // delete expired feed
934  }
935  }
936  }
937  };
938 
939  for( const auto& d : get_index_type<asset_bitasset_data_index>().indices() )
940  {
941  modify( d, update_bitasset );
942  if( d.has_settlement() )
943  process_bids(d);
944  }
945 }
946 
947 /****
948  * @brief a one-time data process to correct max_supply
949  *
950  * NOTE: while exceeding max_supply happened in mainnet, it seemed to have corrected
951  * itself before HF 1465. But this method must remain to correct some assets in testnet
952  */
954 {
955  // for each market issued asset
956  const auto& asset_idx = db.get_index_type<asset_index>().indices().get<by_type>();
957  for( auto asset_itr = asset_idx.lower_bound(true); asset_itr != asset_idx.end(); ++asset_itr )
958  {
959  const auto& current_asset = *asset_itr;
960  graphene::chain::share_type current_supply = current_asset.dynamic_data(db).current_supply;
961  graphene::chain::share_type max_supply = current_asset.options.max_supply;
962  if (current_supply > max_supply && max_supply != GRAPHENE_MAX_SHARE_SUPPLY)
963  {
964  wlog( "Adjusting max_supply of ${asset} because current_supply (${current_supply}) is greater than ${old}.",
965  ("asset", current_asset.symbol)
966  ("current_supply", current_supply.value)
967  ("old", max_supply));
968  db.modify<asset_object>( current_asset, [current_supply](asset_object& obj) {
969  obj.options.max_supply = graphene::chain::share_type(std::min(current_supply.value, GRAPHENE_MAX_SHARE_SUPPLY));
970  });
971  }
972  }
973 }
974 
975 /****
976  * @brief a one-time data process to correct current_supply of BTS token in the BitShares mainnet
977  */
979 {
980  const balance_object* bal = db.find( balance_id_type( HARDFORK_CORE_2103_BALANCE_ID ) );
981  if( bal != nullptr && bal->balance.amount < 0 )
982  {
983  const asset_dynamic_data_object& ddo = bal->balance.asset_id(db).dynamic_data(db);
985  obj.current_supply -= bal->balance.amount;
986  });
987  db.remove( *bal );
988  }
989 }
990 
992 {
993  time_point_sec head_time = db.head_block_time();
995 
996  const auto update_bitasset = [head_time, next_maint_time]( asset_bitasset_data_object &o )
997  {
998  o.update_median_feeds( head_time, next_maint_time );
999  };
1000 
1001  for( const auto& d : db.get_index_type<asset_bitasset_data_index>().indices() )
1002  {
1003  db.modify( d, update_bitasset );
1004  }
1005 }
1006 
1007 /******
1008  * @brief one-time data process for hard fork core-868-890
1009  *
1010  * Prior to hardfork 868, switching a bitasset's shorting asset would not reset its
1011  * feeds. This method will run at the hardfork time, and erase (or nullify) feeds
1012  * that have incorrect backing assets.
1013  * https://github.com/bitshares/bitshares-core/issues/868
1014  *
1015  * Prior to hardfork 890, changing a bitasset's feed expiration time would not
1016  * trigger a median feed update. This method will run at the hardfork time, and
1017  * correct all median feed data.
1018  * https://github.com/bitshares/bitshares-core/issues/890
1019  *
1020  * @param db the database
1021  * @param skip_check_call_orders true if check_call_orders() should not be called
1022  */
1023 // NOTE: Unable to remove this function for testnet nor mainnet. Unfortunately, bad
1024 // feeds were found.
1025 void process_hf_868_890( database& db, bool skip_check_call_orders )
1026 {
1027  const auto next_maint_time = db.get_dynamic_global_properties().next_maintenance_time;
1028  const auto head_time = db.head_block_time();
1029  // for each market issued asset
1030  const auto& asset_idx = db.get_index_type<asset_index>().indices().get<by_type>();
1031  for( auto asset_itr = asset_idx.lower_bound(true); asset_itr != asset_idx.end(); ++asset_itr )
1032  {
1033  const auto& current_asset = *asset_itr;
1034  // Incorrect witness & committee feeds can simply be removed.
1035  // For non-witness-fed and non-committee-fed assets, set incorrect
1036  // feeds to price(), since we can't simply remove them. For more information:
1037  // https://github.com/bitshares/bitshares-core/pull/832#issuecomment-384112633
1038  bool is_witness_or_committee_fed = false;
1039  if ( current_asset.options.flags & ( witness_fed_asset | committee_fed_asset ) )
1040  is_witness_or_committee_fed = true;
1041 
1042  // for each feed
1043  const asset_bitasset_data_object& bitasset_data = current_asset.bitasset_data(db);
1044  auto itr = bitasset_data.feeds.begin();
1045  while( itr != bitasset_data.feeds.end() )
1046  {
1047  // If the feed is invalid
1048  if ( itr->second.second.settlement_price.quote.asset_id != bitasset_data.options.short_backing_asset
1049  && ( is_witness_or_committee_fed || itr->second.second.settlement_price != price() ) )
1050  {
1051  db.modify( bitasset_data, [&itr, is_witness_or_committee_fed]( asset_bitasset_data_object& obj )
1052  {
1053  if( is_witness_or_committee_fed )
1054  {
1055  // erase the invalid feed
1056  itr = obj.feeds.erase(itr);
1057  }
1058  else
1059  {
1060  // nullify the invalid feed
1061  obj.feeds[itr->first].second.settlement_price = price();
1062  ++itr;
1063  }
1064  });
1065  }
1066  else
1067  {
1068  // Feed is valid. Skip it.
1069  ++itr;
1070  }
1071  } // end loop of each feed
1072 
1073  // always update the median feed due to https://github.com/bitshares/bitshares-core/issues/890
1074  db.modify( bitasset_data, [head_time,next_maint_time]( asset_bitasset_data_object &obj ) {
1075  obj.update_median_feeds( head_time, next_maint_time );
1076  // NOTE: Normally we should call check_call_orders() after called update_median_feeds(), but for
1077  // mainnet actually check_call_orders() would do nothing, so we skipped it for better performance.
1078  });
1079 
1080  } // for each market issued asset
1081 }
1082 
1083 
1089 {
1090  const auto& index = db.get_index_type<custom_authority_index>().indices().get<by_expiration>();
1091  while (!index.empty() && index.begin()->valid_to < db.head_block_time())
1092  db.remove(*index.begin());
1093 }
1094 
1097 {
1098  for( const auto& ticket_obj : db.get_index_type<ticket_index>().indices().get<by_id>() )
1099  {
1100  if( ticket_obj.current_type != liquid ) // only update liquid tickets
1101  continue;
1102  db.modify( db.get_account_stats_by_owner( ticket_obj.account ), [&ticket_obj](account_statistics_object& aso) {
1103  aso.total_pol_value -= ticket_obj.value;
1104  });
1105  db.modify( ticket_obj, []( ticket_object& t ) {
1106  t.value = 0;
1107  });
1108  }
1109 }
1110 
1111 namespace detail {
1112 
1114  {
1115  time_point_sec full_power_time;
1116  time_point_sec zero_power_time;
1117  };
1118 
1120  {
1121  vote_recalc_options( uint32_t f, uint32_t d, uint32_t s )
1122  : full_power_seconds(f), recalc_steps(d), seconds_per_step(s)
1123  {
1124  total_recalc_seconds = ( recalc_steps - 1 ) * seconds_per_step; // should not overflow
1125  power_percents_to_subtract.reserve( recalc_steps - 1 );
1126  for( uint32_t i = 1; i < recalc_steps; ++i )
1127  power_percents_to_subtract.push_back( GRAPHENE_100_PERCENT * i / recalc_steps ); // should not overflow
1128  }
1129 
1131  {
1132  return { now - full_power_seconds, now - full_power_seconds - total_recalc_seconds };
1133  }
1134 
1136  uint32_t recalc_steps; // >= 1
1139  vector<uint16_t> power_percents_to_subtract;
1140 
1141  static const vote_recalc_options witness();
1142  static const vote_recalc_options committee();
1143  static const vote_recalc_options worker();
1144  static const vote_recalc_options delegator();
1145 
1146  // return the stake that is "recalced to X"
1147  uint64_t get_recalced_voting_stake( const uint64_t stake, const time_point_sec last_vote_time,
1148  const vote_recalc_times& recalc_times ) const
1149  {
1150  if( last_vote_time > recalc_times.full_power_time )
1151  return stake;
1152  if( last_vote_time <= recalc_times.zero_power_time )
1153  return 0;
1154  uint32_t diff = recalc_times.full_power_time.sec_since_epoch() - last_vote_time.sec_since_epoch();
1155  uint32_t steps_to_subtract_minus_1 = diff / seconds_per_step;
1156  fc::uint128_t stake_to_subtract( stake );
1157  stake_to_subtract *= power_percents_to_subtract[steps_to_subtract_minus_1];
1158  stake_to_subtract /= GRAPHENE_100_PERCENT;
1159  return stake - static_cast<uint64_t>(stake_to_subtract);
1160  }
1161  };
1162 
1164  {
1165  static const vote_recalc_options o( 360*86400, 8, 45*86400 );
1166  return o;
1167  }
1168  const vote_recalc_options vote_recalc_options::committee()
1169  {
1170  static const vote_recalc_options o( 360*86400, 8, 45*86400 );
1171  return o;
1172  }
1174  {
1175  static const vote_recalc_options o( 360*86400, 8, 45*86400 );
1176  return o;
1177  }
1178  const vote_recalc_options vote_recalc_options::delegator()
1179  {
1180  static const vote_recalc_options o( 360*86400, 8, 45*86400 );
1181  return o;
1182  }
1183 }
1184 
1185 void database::perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props)
1186 {
1187  const auto& gpo = get_global_properties();
1188  const auto& dgpo = get_dynamic_global_properties();
1189  auto last_vote_tally_time = head_block_time();
1190 
1191  distribute_fba_balances(*this);
1192  create_buyback_orders(*this);
1193 
1194  struct vote_tally_helper {
1195  database& d;
1196  const global_property_object& props;
1197  const dynamic_global_property_object& dprops;
1198  const time_point_sec now;
1199  const bool hf2103_passed;
1200  const bool hf2262_passed;
1201  const bool pob_activated;
1202 
1203  optional<detail::vote_recalc_times> witness_recalc_times;
1204  optional<detail::vote_recalc_times> committee_recalc_times;
1205  optional<detail::vote_recalc_times> worker_recalc_times;
1206  optional<detail::vote_recalc_times> delegator_recalc_times;
1207 
1208  vote_tally_helper( database& db )
1209  : d(db), props( d.get_global_properties() ), dprops( d.get_dynamic_global_properties() ),
1210  now( d.head_block_time() ), hf2103_passed( HARDFORK_CORE_2103_PASSED( now ) ),
1211  hf2262_passed( HARDFORK_CORE_2262_PASSED( now ) ),
1212  pob_activated( dprops.total_pob > 0 || dprops.total_inactive > 0 )
1213  {
1214  d._vote_tally_buffer.resize( props.next_available_vote_id, 0 );
1215  d._witness_count_histogram_buffer.resize( props.parameters.maximum_witness_count / 2 + 1, 0 );
1216  d._committee_count_histogram_buffer.resize( props.parameters.maximum_committee_count / 2 + 1, 0 );
1217  d._total_voting_stake[0] = 0;
1218  d._total_voting_stake[1] = 0;
1219  if( hf2103_passed )
1220  {
1221  witness_recalc_times = detail::vote_recalc_options::witness().get_vote_recalc_times( now );
1222  committee_recalc_times = detail::vote_recalc_options::committee().get_vote_recalc_times( now );
1223  worker_recalc_times = detail::vote_recalc_options::worker().get_vote_recalc_times( now );
1224  delegator_recalc_times = detail::vote_recalc_options::delegator().get_vote_recalc_times( now );
1225  }
1226  }
1227 
1228  void operator()( const account_object& stake_account, const account_statistics_object& stats )
1229  {
1230  // PoB activation
1231  if( pob_activated && stats.total_core_pob == 0 && stats.total_core_inactive == 0 )
1232  return;
1233 
1234  if( props.parameters.count_non_member_votes || stake_account.is_member( now ) )
1235  {
1236  // There may be a difference between the account whose stake is voting and the one specifying opinions.
1237  // Usually they're the same, but if the stake account has specified a voting_account, that account is the
1238  // one specifying the opinions.
1239  bool directly_voting = ( stake_account.options.voting_account == GRAPHENE_PROXY_TO_SELF_ACCOUNT );
1240  const account_object& opinion_account = ( directly_voting ? stake_account
1241  : d.get(stake_account.options.voting_account) );
1242 
1243  uint64_t voting_stake[3]; // 0=committee, 1=witness, 2=worker, as in vote_id_type::vote_type
1244  uint64_t num_committee_voting_stake; // number of committee members
1245  voting_stake[2] = ( pob_activated ? 0 : stats.total_core_in_orders.value )
1246  + ( ( !hf2262_passed && stake_account.cashback_vb.valid() ) ?
1247  (*stake_account.cashback_vb)(d).balance.amount.value : 0 )
1248  + ( hf2262_passed ? 0 : stats.core_in_balance.value );
1249 
1250  // voting power stats
1251  uint64_t vp_all = 0;
1252  uint64_t vp_active = 0;
1253  uint64_t vp_committee = 0;
1254  uint64_t vp_witness = 0;
1255  uint64_t vp_worker = 0;
1256 
1257  //PoB
1258  const uint64_t pol_amount = stats.total_core_pol.value;
1259  const uint64_t pol_value = stats.total_pol_value.value;
1260  const uint64_t pob_amount = stats.total_core_pob.value;
1261  const uint64_t pob_value = stats.total_pob_value.value;
1262  if( pob_amount == 0 )
1263  {
1264  voting_stake[2] += pol_value;
1265  }
1266  else if( pol_amount == 0 ) // and pob_amount > 0
1267  {
1268  if( pob_amount <= voting_stake[2] )
1269  {
1270  voting_stake[2] += ( pob_value - pob_amount );
1271  }
1272  else
1273  {
1274  auto base_value = static_cast<fc::uint128_t>( voting_stake[2] ) * pob_value / pob_amount;
1275  voting_stake[2] = static_cast<uint64_t>( base_value );
1276  }
1277  }
1278  else if( pob_amount <= pol_amount ) // pob_amount > 0 && pol_amount > 0
1279  {
1280  auto base_value = static_cast<fc::uint128_t>( pob_value ) * pol_value / pol_amount;
1281  auto diff_value = static_cast<fc::uint128_t>( pob_amount ) * pol_value / pol_amount;
1282  base_value += ( pol_value - diff_value );
1283  voting_stake[2] += static_cast<uint64_t>( base_value );
1284  }
1285  else // pob_amount > pol_amount > 0
1286  {
1287  auto base_value = static_cast<fc::uint128_t>( pol_value ) * pob_value / pob_amount;
1288  fc::uint128_t diff_amount = pob_amount - pol_amount;
1289  if( diff_amount <= voting_stake[2] )
1290  {
1291  auto diff_value = static_cast<fc::uint128_t>( pol_amount ) * pob_value / pob_amount;
1292  base_value += ( pob_value - diff_value );
1293  voting_stake[2] += static_cast<uint64_t>( base_value - diff_amount );
1294  }
1295  else // diff_amount > voting_stake[2]
1296  {
1297  base_value += static_cast<fc::uint128_t>( voting_stake[2] ) * pob_value / pob_amount;
1298  voting_stake[2] = static_cast<uint64_t>( base_value );
1299  }
1300  }
1301 
1302  // Shortcut
1303  if( voting_stake[2] == 0 )
1304  return;
1305 
1306  const account_statistics_object& opinion_account_stats = ( directly_voting ? stats : opinion_account.statistics( d ) );
1307 
1308  // Recalculate votes
1309  if( !hf2103_passed )
1310  {
1311  voting_stake[0] = voting_stake[2];
1312  voting_stake[1] = voting_stake[2];
1313  num_committee_voting_stake = voting_stake[2];
1314  vp_all = vp_active = vp_committee = vp_witness = vp_worker = voting_stake[2];
1315  }
1316  else
1317  {
1318  vp_all = vp_active = voting_stake[2];
1319  if( !directly_voting )
1320  {
1321  vp_active = voting_stake[2] = detail::vote_recalc_options::delegator().get_recalced_voting_stake(
1322  voting_stake[2], stats.last_vote_time, *delegator_recalc_times );
1323  }
1324  vp_witness = voting_stake[1] = detail::vote_recalc_options::witness().get_recalced_voting_stake(
1325  voting_stake[2], opinion_account_stats.last_vote_time, *witness_recalc_times );
1326  vp_committee = voting_stake[0] = detail::vote_recalc_options::committee().get_recalced_voting_stake(
1327  voting_stake[2], opinion_account_stats.last_vote_time, *committee_recalc_times );
1328  num_committee_voting_stake = voting_stake[0];
1329  if( opinion_account.num_committee_voted > 1 )
1330  voting_stake[0] /= opinion_account.num_committee_voted;
1331  vp_worker = voting_stake[2] = detail::vote_recalc_options::worker().get_recalced_voting_stake(
1332  voting_stake[2], opinion_account_stats.last_vote_time, *worker_recalc_times );
1333  }
1334 
1335  // update voting power
1336  d.modify( opinion_account_stats, [=]( account_statistics_object& update_stats ) {
1337  if (update_stats.vote_tally_time != now)
1338  {
1339  update_stats.vp_all = vp_all;
1340  update_stats.vp_active = vp_active;
1341  update_stats.vp_committee = vp_committee;
1342  update_stats.vp_witness = vp_witness;
1343  update_stats.vp_worker = vp_worker;
1344  update_stats.vote_tally_time = now;
1345  }
1346  else
1347  {
1348  update_stats.vp_all += vp_all;
1349  update_stats.vp_active += vp_active;
1350  update_stats.vp_committee += vp_committee;
1351  update_stats.vp_witness += vp_witness;
1352  update_stats.vp_worker += vp_worker;
1353  // update_stats.vote_tally_time = now;
1354  }
1355  });
1356 
1357  for( vote_id_type id : opinion_account.options.votes )
1358  {
1359  uint32_t offset = id.instance();
1360  uint32_t type = std::min( id.type(), vote_id_type::vote_type::worker ); // cap the data
1361  // if they somehow managed to specify an illegal offset, ignore it.
1362  if( offset < d._vote_tally_buffer.size() )
1363  d._vote_tally_buffer[offset] += voting_stake[type];
1364  }
1365 
1366  // votes for a number greater than maximum_witness_count are skipped here
1367  if( voting_stake[1] > 0
1368  && opinion_account.options.num_witness <= props.parameters.maximum_witness_count )
1369  {
1370  uint16_t offset = opinion_account.options.num_witness / 2;
1371  d._witness_count_histogram_buffer[offset] += voting_stake[1];
1372  }
1373  // votes for a number greater than maximum_committee_count are skipped here
1374  if( num_committee_voting_stake > 0
1375  && opinion_account.options.num_committee <= props.parameters.maximum_committee_count )
1376  {
1377  uint16_t offset = opinion_account.options.num_committee / 2;
1378  d._committee_count_histogram_buffer[offset] += num_committee_voting_stake;
1379  }
1380 
1381  d._total_voting_stake[0] += num_committee_voting_stake;
1382  d._total_voting_stake[1] += voting_stake[1];
1383  }
1384  }
1385  } tally_helper(*this);
1386 
1387  perform_account_maintenance( tally_helper );
1388 
1389  struct clear_canary {
1390  clear_canary(vector<uint64_t>& target): target(target){}
1391  ~clear_canary() { target.clear(); }
1392  private:
1393  vector<uint64_t>& target;
1394  };
1395  clear_canary a(_witness_count_histogram_buffer),
1396  b(_committee_count_histogram_buffer),
1397  c(_vote_tally_buffer);
1398 
1399  update_top_n_authorities(*this);
1400  update_active_witnesses();
1401  update_active_committee_members();
1402  update_worker_votes();
1403 
1404  modify(gpo, [&dgpo](global_property_object& p) {
1405  // Remove scaling of account registration fee
1407  (dgpo.accounts_registered_this_interval / p.parameters.accounts_per_fee_scale);
1408 
1409  if( p.pending_parameters )
1410  {
1411  p.parameters = std::move(*p.pending_parameters);
1412  p.pending_parameters.reset();
1413  }
1414  });
1415 
1416  auto next_maintenance_time = dgpo.next_maintenance_time;
1417  auto maintenance_interval = gpo.parameters.maintenance_interval;
1418 
1419  if( next_maintenance_time <= next_block.timestamp )
1420  {
1421  if( next_block.block_num() == 1 )
1422  next_maintenance_time = time_point_sec() +
1423  (((next_block.timestamp.sec_since_epoch() / maintenance_interval) + 1) * maintenance_interval);
1424  else
1425  {
1426  // We want to find the smallest k such that next_maintenance_time + k * maintenance_interval > head_block_time()
1427  // This implies k > ( head_block_time() - next_maintenance_time ) / maintenance_interval
1428  //
1429  // Let y be the right-hand side of this inequality, i.e.
1430  // y = ( head_block_time() - next_maintenance_time ) / maintenance_interval
1431  //
1432  // and let the fractional part f be y-floor(y). Clearly 0 <= f < 1.
1433  // We can rewrite f = y-floor(y) as floor(y) = y-f.
1434  //
1435  // Clearly k = floor(y)+1 has k > y as desired. Now we must
1436  // show that this is the least such k, i.e. k-1 <= y.
1437  //
1438  // But k-1 = floor(y)+1-1 = floor(y) = y-f <= y.
1439  // So this k suffices.
1440  //
1441  auto y = (head_block_time() - next_maintenance_time).to_seconds() / maintenance_interval;
1442  next_maintenance_time += (y+1) * maintenance_interval;
1443  }
1444  }
1445 
1446  if( (dgpo.next_maintenance_time < HARDFORK_613_TIME) && (next_maintenance_time >= HARDFORK_613_TIME) )
1447  deprecate_annual_members(*this);
1448 
1449  // To reset call_price of all call orders, then match by new rule, for hard fork core-343
1450  bool to_update_and_match_call_orders_for_hf_343 = false;
1451  if( (dgpo.next_maintenance_time <= HARDFORK_CORE_343_TIME) && (next_maintenance_time > HARDFORK_CORE_343_TIME) )
1452  to_update_and_match_call_orders_for_hf_343 = true;
1453 
1454  // Process inconsistent price feeds
1455  if( (dgpo.next_maintenance_time <= HARDFORK_CORE_868_890_TIME) && (next_maintenance_time > HARDFORK_CORE_868_890_TIME) )
1456  process_hf_868_890( *this, to_update_and_match_call_orders_for_hf_343 );
1457 
1458  // To reset call_price of all call orders, then match by new rule, for hard fork core-1270
1459  bool to_update_and_match_call_orders_for_hf_1270 = false;
1460  if( (dgpo.next_maintenance_time <= HARDFORK_CORE_1270_TIME) && (next_maintenance_time > HARDFORK_CORE_1270_TIME) )
1461  to_update_and_match_call_orders_for_hf_1270 = true;
1462 
1463  // make sure current_supply is less than or equal to max_supply
1464  if ( dgpo.next_maintenance_time <= HARDFORK_CORE_1465_TIME && next_maintenance_time > HARDFORK_CORE_1465_TIME )
1465  process_hf_1465(*this);
1466 
1467  // Fix supply issue
1468  if ( dgpo.next_maintenance_time <= HARDFORK_CORE_2103_TIME && next_maintenance_time > HARDFORK_CORE_2103_TIME )
1469  process_hf_2103(*this);
1470 
1471  // Update tickets. Note: the new values will take effect only on the next maintenance interval
1472  if ( dgpo.next_maintenance_time <= HARDFORK_CORE_2262_TIME && next_maintenance_time > HARDFORK_CORE_2262_TIME )
1473  process_hf_2262(*this);
1474 
1475  modify(dgpo, [last_vote_tally_time, next_maintenance_time](dynamic_global_property_object& d) {
1476  d.next_maintenance_time = next_maintenance_time;
1477  d.last_vote_tally_time = last_vote_tally_time;
1479  });
1480 
1481  // We need to do it after updated next_maintenance_time, to apply new rules here, for hard fork core-343
1482  if( to_update_and_match_call_orders_for_hf_343 )
1483  {
1485  match_call_orders(*this);
1486  }
1487 
1488  // We need to do it after updated next_maintenance_time, to apply new rules here, for hard fork core-1270.
1489  if( to_update_and_match_call_orders_for_hf_1270 )
1490  {
1492  update_median_feeds(*this);
1493  match_call_orders(*this);
1494  }
1495 
1496  process_bitassets();
1498 
1499  // process_budget needs to run at the bottom because
1500  // it needs to know the next_maintenance_time
1501  process_budget();
1502 }
1503 
1504 } }
bool is_type() const
share_type approving_stake() const
share_type total_core_pol
Total amount of core token in other tickets.
bool is_active(fc::time_point_sec now) const
fc::time_point_sec timestamp
Definition: block.hpp:35
static const vote_recalc_options worker()
Definition: db_maint.cpp:1173
void modify(const T &obj, const Lambda &m)
void update_call_orders_hf_343(database &db)
Definition: db_maint.cpp:854
Wraps a derived index to intercept calls to create, modify, and remove so that callbacks may be fired...
Definition: index.hpp:309
bool upgrade_to_lifetime_member
If true, the account will be upgraded to a lifetime member; otherwise, it will add a year to the subs...
Definition: account.hpp:245
const T * find(object_id_type id) const
void adjust_balance(account_id_type account, asset delta)
Adjust a particular account&#39;s balance in a given asset by a delta.
Definition: db_balance.cpp:54
Manage an account&#39;s membership statusThis operation is used to upgrade an account to a member...
Definition: account.hpp:234
bool fill_or_kill
If this flag is set the entire order must be filled or the operation is rejected. ...
Definition: market.hpp:62
void finish(authority &out_auth)
Definition: vote_count.hpp:55
contains properties that only apply to bitassets (market issued assets)
void process_hf_868_890(database &db, bool skip_check_call_orders)
Definition: db_maint.cpp:1025
uint32_t sec_since_epoch() const
Definition: time.hpp:90
bool is_member(time_point_sec now) const
special_authority active_special_authority
uint16_t accounts_per_fee_scale
number of accounts between fee scalings
This class represents an account on the object graphAccounts are the primary unit of authority on the...
Maintains global state information (committee_member list, current fees)This is an implementation det...
tracks the blockchain state in an extensible manner
Definition: database.hpp:70
Definition: api.cpp:56
void process_hf_1465(database &db)
Definition: db_maint.cpp:953
account_id_type account_to_upgrade
The account to upgrade; must not already be a lifetime member.
Definition: account.hpp:243
#define GRAPHENE_PROXY_TO_SELF_ACCOUNT
Represents the canonical account for specifying you will vote directly (as opposed to a proxy) ...
Definition: config.hpp:135
tracks debt and call price information
Used to generate a useful error report when an exception is thrown.At each level in the stack where t...
Definition: exception.hpp:56
std::string to_detail_string(log_level ll=log_level::all) const
Definition: exception.cpp:183
const dynamic_global_property_object & get_dynamic_global_properties() const
Definition: db_getter.cpp:54
bool valid() const
Definition: optional.hpp:186
void add(Component who, uint64_t votes)
Definition: vote_count.hpp:37
uint32_t head_block_num() const
Definition: db_getter.cpp:69
optional< account_id_type > buyback_account
#define GRAPHENE_CORE_ASSET_CYCLE_RATE
Definition: config.hpp:51
immutable_chain_parameters immutable_parameters
share_type total_pol_value
Total value of tickets whose current type is not lock_forever.
uint8_t account_fee_scale_bitshifts
number of times to left bitshift account registration fee at each scaling
price call_price
Collateral / Debt.
visitor::result_type visit(visitor &v)
account_id_type issuer
ID of the account which issued this asset.
#define wlog(FORMAT,...)
Definition: logger.hpp:123
vote_recalc_options(uint32_t f, uint32_t d, uint32_t s)
Definition: db_maint.cpp:1121
bool is_null() const
Definition: asset.cpp:225
const global_property_object & get_global_properties() const
Definition: db_getter.cpp:44
#define GRAPHENE_MAX_SHARE_SUPPLY
Definition: config.hpp:38
const T & get(object_id_type id) const
uint64_t get_recalced_voting_stake(const uint64_t stake, const time_point_sec last_vote_time, const vote_recalc_times &recalc_times) const
Definition: db_maint.cpp:1147
void update_call_orders_hf_1270(database &db)
Definition: db_maint.cpp:880
void create_buyback_orders(database &db)
Definition: db_maint.cpp:695
provides stack-based nullable value similar to boost::optional
Definition: optional.hpp:20
void execute_bid(const collateral_bid_object &bid, share_type debt_covered, share_type collateral_from_fund, const price_feed &current_feed)
Definition: db_market.cpp:193
void distribute_fba_balances(database &db)
Definition: db_maint.cpp:688
worker_pay_visitor(share_type pay, database &db)
Definition: db_maint.cpp:126
void update_median_feeds(time_point_sec current_time, time_point_sec next_maintenance_time)
bool is_prediction_market
True if this asset implements a Prediction Market.
microseconds days(int64_t d)
Definition: time.hpp:38
void process_hf_2262(database &db)
A one-time data process to set values of existing liquid tickets to zero.
Definition: db_maint.cpp:1096
operation_result apply_operation(transaction_evaluation_state &eval_state, const operation &op)
Definition: db_block.cpp:754
static time_point_sec maximum()
Definition: time.hpp:86
object_id_type id
Definition: object.hpp:69
uint16_t maintenance_collateral_ratio
Definition: asset.hpp:190
share_type total_pob_value
Total value of tickets whose current type is lock_forever.
void delete_expired_custom_authorities(database &db)
Remove any custom active authorities whose expiration dates are in the past.
Definition: db_maint.cpp:1088
flat_set< vote_id_type > votes
Definition: account.hpp:58
uint32_t push_applied_operation(const operation &op)
Definition: db_block.cpp:527
The price struct stores asset prices in the BitShares system.
Definition: asset.hpp:114
uint16_t maximum_witness_count
maximum number of active witnesses
int64_t count() const
Definition: time.hpp:28
#define GRAPHENE_100_PERCENT
Definition: config.hpp:102
optional< vesting_balance_id_type > cashback_vb
time_point_sec head_block_time() const
Definition: db_getter.cpp:64
flat_map< account_id_type, weight_type > account_auths
Definition: authority.hpp:120
#define ilog(FORMAT,...)
Definition: logger.hpp:117
#define GRAPHENE_COMMITTEE_ACCOUNT
Definition: config.hpp:125
share_type total_core_inactive
Total amount of core token in inactive lock_forever tickets.
worker_type worker
ID of this worker&#39;s pay balance.
void update_median_feeds(database &db)
Definition: db_maint.cpp:991
#define FC_CAPTURE_AND_RETHROW(...)
Definition: exception.hpp:478
instructs the blockchain to attempt to sell one asset for anotherThe blockchain will atempt to sell a...
Definition: market.hpp:48
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
bool is_configured(const database &db) const
Definition: fba_object.cpp:31
const chain_property_object & get_chain_properties() const
Definition: db_getter.cpp:49
tracks the asset information that changes frequentlyBecause the asset_object is very large it doesn&#39;t...
time_point_sec last_vote_time
last time voted
bids of collateral for debt after a black swan
optional< asset_id_type > designated_asset
Definition: fba_object.hpp:44
An ID for some votable object.
Definition: vote.hpp:51
void match_call_orders(database &db)
Match call orders for all bitAssets, including PMs.
Definition: db_maint.cpp:893
static const vote_recalc_options witness()
Definition: db_maint.cpp:1163
#define GRAPHENE_RELAXED_COMMITTEE_ACCOUNT
Represents the current committee members.
Definition: config.hpp:129
const Operation::fee_parameters_type & get() const
const account_statistics_object & get_account_stats_by_owner(account_id_type owner) const
Definition: db_getter.cpp:139
uint16_t maximum_committee_count
maximum number of active committee_members
share_type accumulated_fees
fees accumulate to be paid out over time
const asset_dynamic_data_object & get_core_dynamic_data() const
Definition: db_getter.cpp:39
tracks the parameters of an assetAll assets have a globally unique symbol name that controls how they...
void deprecate_annual_members(database &db)
Definition: db_maint.cpp:765
typename impl::transform< List, Transformer >::type transform
Transform elements of a typelist.
Definition: typelist.hpp:170
share_type daily_pay
Amount in CORE this worker will be paid each day.
void operator()(W &worker) const
Definition: db_maint.cpp:131
safe< int64_t > share_type
Definition: types.hpp:247
vector< committee_member_id_type > active_committee_members
share_type witness_pay_per_block
CORE to be allocated to witnesses (per block)
the bitasset is to be fed by witnesses
Definition: types.hpp:147
const object & get(object_id_type id) const
Definition: index.hpp:111
asset_id_type asset_id
Definition: asset.hpp:39
vote_id_type vote_against
Voting ID which represents disapproval of this worker.
bitasset_options options
The tunable options for BitAssets are stored in this field.
Worker object contains the details of a blockchain worker. See The Blockchain Worker System for detai...
vote_id_type vote_for
Voting ID which represents approval of this worker.
static const vote_recalc_options committee()
Definition: db_maint.cpp:1168
A visitor for worker_type which calls pay_worker on the worker within.
Definition: db_maint.cpp:119
account_statistics_id_type statistics
uint32_t block_num() const
Definition: block.hpp:34
void update_top_n_authorities(database &db)
Definition: db_maint.cpp:570
abstract base class for accessing objects indexed in various ways.
Definition: index.hpp:71
void remove(const object &obj)
Maintains global state information (committee_member list, current fees)This is an implementation det...
bool count_non_member_votes
set to false to restrict voting privlegages to member accounts
#define GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS
Definition: config.hpp:52
share_type worker_budget_per_day
CORE to be allocated to workers (per day)
share_type current_supply
The number of shares currently in existence.
flat_map< account_id_type, pair< time_point_sec, price_feed_with_icr > > feeds
void visit_special_authorities(const database &db, Visitor visit)
Definition: db_maint.cpp:552
vote_recalc_times get_vote_recalc_times(const time_point_sec now) const
Definition: db_maint.cpp:1130
tracks information about a committee_member account.A committee_member is responsible for setting blo...
a ticket for governance voting
#define GRAPHENE_1_PERCENT
Definition: config.hpp:103
price max() const
Definition: asset.hpp:130
static price call_price(const asset &debt, const asset &collateral, uint16_t collateral_ratio)
Definition: asset.cpp:212
share_type value
The current value of the ticket.
uint16_t num_committee_voted
Pre-calculated for better performance on chain maintenance.
share_type total_core_pob
Total amount of core token in active lock_forever tickets.
share_type settlement_fund
Amount of collateral which is available for force settlement.
uint8_t block_interval
interval in seconds between blocks
const asset_dynamic_data_object & dynamic_data(const DB &db) const
static const vote_recalc_options delegator()
Definition: db_maint.cpp:1178
const IndexType & get_index_type() const
T value
Definition: safe.hpp:22
special_authority owner_special_authority
optional< chain_parameters > pending_parameters
void process_hf_2103(database &db)
Definition: db_maint.cpp:978
bool check_call_orders(const asset_object &mia, bool enable_black_swan=true, bool for_new_limit_order=false, const asset_bitasset_data_object *bitasset_ptr=nullptr)
Definition: db_market.cpp:1100
void split_fba_balance(database &db, uint64_t fba_id, uint16_t network_pct, uint16_t designated_asset_buyback_pct, uint16_t designated_asset_issuer_pct)
Definition: db_maint.cpp:609
const asset_object & get_core_asset() const
Definition: db_getter.cpp:34
#define GRAPHENE_WITNESS_ACCOUNT
Represents the current witnesses.
Definition: config.hpp:127
share_type reserved(const DB &db) const
const index_type & indices() const