BitShares-Core  7.0.2
BitShares blockchain node software and command-line wallet 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.empty() );
206  constexpr size_t two = 2;
207  constexpr auto vid_witness = static_cast<size_t>( vote_id_type::witness ); // 1
208  share_type stake_target = (_total_voting_stake[vid_witness]-_witness_count_histogram_buffer[0]) / two;
209 
212 
213  share_type stake_tally = 0;
214 
215  size_t witness_count = 0;
216  if( stake_target > 0 )
217  {
218  while( (witness_count < _witness_count_histogram_buffer.size() - 1)
219  && (stake_tally <= stake_target) )
220  {
221  stake_tally += _witness_count_histogram_buffer[++witness_count];
222  }
223  }
224 
225  const chain_property_object& cpo = get_chain_properties();
226 
227  witness_count = std::max( ( witness_count * two ) + 1,
228  (size_t)cpo.immutable_parameters.min_witness_count );
229  auto wits = sort_votable_objects<witness_index>( witness_count );
230 
231  const global_property_object& gpo = get_global_properties();
232 
233  auto update_witness_total_votes = [this]( const witness_object& wit ) {
234  modify( wit, [this]( witness_object& obj )
235  {
236  obj.total_votes = _vote_tally_buffer[obj.vote_id];
237  });
238  };
239 
240  if( _track_standby_votes )
241  {
242  const auto& all_witnesses = get_index_type<witness_index>().indices();
243  for( const witness_object& wit : all_witnesses )
244  {
245  update_witness_total_votes( wit );
246  }
247  }
248  else
249  {
250  for( const witness_object& wit : wits )
251  {
252  update_witness_total_votes( wit );
253  }
254  }
255 
256  // Update witness authority
257  modify( get(GRAPHENE_WITNESS_ACCOUNT), [this,&wits]( account_object& a )
258  {
259  if( head_block_time() < HARDFORK_533_TIME )
260  {
261  uint64_t total_votes = 0;
262  map<account_id_type, uint64_t> weights;
263  a.active.weight_threshold = 0;
264  a.active.clear();
265 
266  for( const witness_object& wit : wits )
267  {
268  weights.emplace(wit.witness_account, _vote_tally_buffer[wit.vote_id]);
269  total_votes += _vote_tally_buffer[wit.vote_id];
270  }
271 
272  // total_votes is 64 bits. Subtract the number of leading low bits from 64 to get the number of useful bits,
273  // then I want to keep the most significant 16 bits of what's left.
274  uint64_t votes_msb = boost::multiprecision::detail::find_msb(total_votes);
275  constexpr uint8_t bits_to_keep_minus_one = 15;
276  uint64_t bits_to_drop = (votes_msb > bits_to_keep_minus_one) ? (votes_msb - bits_to_keep_minus_one) : 0;
277  for( const auto& weight : weights )
278  {
279  // Ensure that everyone has at least one vote. Zero weights aren't allowed.
280  uint16_t votes = std::max((uint16_t)(weight.second >> bits_to_drop), uint16_t(1) );
281  a.active.account_auths[weight.first] += votes;
282  a.active.weight_threshold += votes;
283  }
284 
285  a.active.weight_threshold /= two;
286  a.active.weight_threshold += 1;
287  }
288  else
289  {
290  vote_counter vc;
291  for( const witness_object& wit : wits )
292  vc.add( wit.witness_account, _vote_tally_buffer[wit.vote_id] );
293  vc.finish( a.active );
294  }
295  } );
296 
297  modify( gpo, [&wits]( global_property_object& gp )
298  {
299  gp.active_witnesses.clear();
300  gp.active_witnesses.reserve(wits.size());
301  std::transform(wits.begin(), wits.end(),
302  std::inserter(gp.active_witnesses, gp.active_witnesses.end()),
303  [](const witness_object& w) {
304  return w.get_id();
305  });
306  });
307 
308 } FC_CAPTURE_AND_RETHROW() } // GCOVR_EXCL_LINE
309 
310 void database::update_active_committee_members()
311 { try {
312  assert( !_committee_count_histogram_buffer.empty() );
313  constexpr size_t two = 2;
314  constexpr auto vid_committee = static_cast<size_t>( vote_id_type::committee ); // 0
315  share_type stake_target = (_total_voting_stake[vid_committee]-_committee_count_histogram_buffer[0]) / two;
316 
319  share_type stake_tally = 0;
320  size_t committee_member_count = 0;
321  if( stake_target > 0 )
322  {
323  while( (committee_member_count < _committee_count_histogram_buffer.size() - 1)
324  && (stake_tally <= stake_target.value) )
325  {
326  stake_tally += _committee_count_histogram_buffer[++committee_member_count];
327  }
328  }
329 
330  const chain_property_object& cpo = get_chain_properties();
331 
332  committee_member_count = std::max( ( committee_member_count * two ) + 1,
333  (size_t)cpo.immutable_parameters.min_committee_member_count );
334  auto committee_members = sort_votable_objects<committee_member_index>( committee_member_count );
335 
336  auto update_committee_member_total_votes = [this]( const committee_member_object& cm ) {
337  modify( cm, [this]( committee_member_object& obj )
338  {
339  obj.total_votes = _vote_tally_buffer[obj.vote_id];
340  });
341  };
342 
343  if( _track_standby_votes )
344  {
345  const auto& all_committee_members = get_index_type<committee_member_index>().indices();
346  for( const committee_member_object& cm : all_committee_members )
347  {
348  update_committee_member_total_votes( cm );
349  }
350  }
351  else
352  {
353  for( const committee_member_object& cm : committee_members )
354  {
355  update_committee_member_total_votes( cm );
356  }
357  }
358 
359  // Update committee authorities
360  if( !committee_members.empty() )
361  {
362  const account_object& committee_account = get(GRAPHENE_COMMITTEE_ACCOUNT);
363  modify( committee_account, [this,&committee_members](account_object& a)
364  {
365  if( head_block_time() < HARDFORK_533_TIME )
366  {
367  uint64_t total_votes = 0;
368  map<account_id_type, uint64_t> weights;
369  a.active.weight_threshold = 0;
370  a.active.clear();
371 
372  for( const committee_member_object& cm : committee_members )
373  {
374  weights.emplace( cm.committee_member_account, _vote_tally_buffer[cm.vote_id] );
375  total_votes += _vote_tally_buffer[cm.vote_id];
376  }
377 
378  // total_votes is 64 bits.
379  // Subtract the number of leading low bits from 64 to get the number of useful bits,
380  // then I want to keep the most significant 16 bits of what's left.
381  uint64_t votes_msb = boost::multiprecision::detail::find_msb(total_votes);
382  constexpr uint8_t bits_to_keep_minus_one = 15;
383  uint64_t bits_to_drop = (votes_msb > bits_to_keep_minus_one) ? (votes_msb - bits_to_keep_minus_one) : 0;
384  for( const auto& weight : weights )
385  {
386  // Ensure that everyone has at least one vote. Zero weights aren't allowed.
387  uint16_t votes = std::max((uint16_t)(weight.second >> bits_to_drop), uint16_t(1) );
388  a.active.account_auths[weight.first] += votes;
389  a.active.weight_threshold += votes;
390  }
391 
392  a.active.weight_threshold /= two;
393  a.active.weight_threshold += 1;
394  }
395  else
396  {
397  vote_counter vc;
398  for( const committee_member_object& cm : committee_members )
399  vc.add( cm.committee_member_account, _vote_tally_buffer[cm.vote_id] );
400  vc.finish( a.active );
401  }
402  });
403  modify( get(GRAPHENE_RELAXED_COMMITTEE_ACCOUNT), [&committee_account](account_object& a)
404  {
405  a.active = committee_account.active;
406  });
407  }
408  modify( get_global_properties(), [&committee_members](global_property_object& gp)
409  {
410  gp.active_committee_members.clear();
411  std::transform(committee_members.begin(), committee_members.end(),
412  std::inserter(gp.active_committee_members, gp.active_committee_members.begin()),
413  [](const committee_member_object& d) { return d.get_id(); });
414  });
415 } FC_CAPTURE_AND_RETHROW() } // GCOVR_EXCL_LINE
416 
417 void database::initialize_budget_record( fc::time_point_sec now, budget_record& rec )const
418 {
419  const dynamic_global_property_object& dpo = get_dynamic_global_properties();
420  const asset_object& core = get_core_asset();
421  const asset_dynamic_data_object& core_dd = get_core_dynamic_data();
422 
423  rec.from_initial_reserve = core.reserved(*this);
424  rec.from_accumulated_fees = core_dd.accumulated_fees;
425  rec.from_unused_witness_budget = dpo.witness_budget;
426  rec.max_supply = core.options.max_supply;
427 
428  if( (dpo.last_budget_time == fc::time_point_sec())
429  || (now <= dpo.last_budget_time) )
430  {
431  rec.time_since_last_budget = 0;
432  return;
433  }
434 
435  int64_t dt = (now - dpo.last_budget_time).to_seconds();
436  rec.time_since_last_budget = uint64_t( dt );
437 
438  // We'll consider accumulated_fees to be reserved at the BEGINNING
439  // of the maintenance interval. However, for speed we only
440  // call modify() on the asset_dynamic_data_object once at the
441  // end of the maintenance interval. Thus the accumulated_fees
442  // are available for the budget at this point, but not included
443  // in core.reserved().
444  share_type reserve = rec.from_initial_reserve + core_dd.accumulated_fees;
445  // Similarly, we consider leftover witness_budget to be burned
446  // at the BEGINNING of the maintenance interval.
447  reserve += dpo.witness_budget;
448 
449  fc::uint128_t budget_u128 = reserve.value;
450  budget_u128 *= uint64_t(dt);
451  budget_u128 *= GRAPHENE_CORE_ASSET_CYCLE_RATE;
452  //round up to the nearest satoshi -- this is necessary to ensure
453  // there isn't an "untouchable" reserve, and we will eventually
454  // be able to use the entire reserve
455  budget_u128 += ((uint64_t(1) << GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS) - 1);
456  budget_u128 >>= GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS;
457  if( budget_u128 < static_cast<fc::uint128_t>(reserve.value) )
458  rec.total_budget = share_type(static_cast<uint64_t>(budget_u128));
459  else
460  rec.total_budget = reserve;
461 
462  return;
463 }
464 
468 void database::process_budget()
469 {
470  try
471  {
472  const global_property_object& gpo = get_global_properties();
473  const dynamic_global_property_object& dpo = get_dynamic_global_properties();
474  const asset_dynamic_data_object& core = get_core_dynamic_data();
476 
477  int64_t time_to_maint = (dpo.next_maintenance_time - now).to_seconds();
478  //
479  // The code that generates the next maintenance time should
480  // only produce a result in the future. If this assert
481  // fails, then the next maintenance time algorithm is buggy.
482  //
483  assert( time_to_maint > 0 );
484  //
485  // Code for setting chain parameters should validate
486  // block_interval > 0 (as well as the humans proposing /
487  // voting on changes to block interval).
488  //
489  assert( gpo.parameters.block_interval > 0 );
490  uint64_t blocks_to_maint = ( ( uint64_t(time_to_maint) + gpo.parameters.block_interval ) - 1 )
491  / gpo.parameters.block_interval;
492 
493  // blocks_to_maint > 0 because time_to_maint > 0,
494  // which means numerator is at least equal to block_interval
495 
496  budget_record rec;
497  initialize_budget_record( now, rec );
498  share_type available_funds = rec.total_budget;
499 
500  share_type witness_budget = gpo.parameters.witness_pay_per_block.value * blocks_to_maint;
501  rec.requested_witness_budget = witness_budget;
502  witness_budget = std::min(witness_budget, available_funds);
503  rec.witness_budget = witness_budget;
504  available_funds -= witness_budget;
505 
506  fc::uint128_t worker_budget_u128 = gpo.parameters.worker_budget_per_day.value;
507  worker_budget_u128 *= uint64_t(time_to_maint);
508  constexpr uint64_t seconds_per_day = 86400;
509  worker_budget_u128 /= seconds_per_day;
510 
511  share_type worker_budget;
512  if( worker_budget_u128 >= static_cast<fc::uint128_t>(available_funds.value) )
513  worker_budget = available_funds;
514  else
515  worker_budget = static_cast<uint64_t>(worker_budget_u128);
516  rec.worker_budget = worker_budget;
517  available_funds -= worker_budget;
518 
519  share_type leftover_worker_funds = worker_budget;
520  pay_workers(leftover_worker_funds);
521  rec.leftover_worker_funds = leftover_worker_funds;
522  available_funds += leftover_worker_funds;
523 
524  rec.supply_delta = ((( rec.witness_budget
525  + rec.worker_budget )
526  - rec.leftover_worker_funds )
527  - rec.from_accumulated_fees )
528  - rec.from_unused_witness_budget;
529 
530  modify(core, [&rec
531 #ifndef NDEBUG
532  ,&witness_budget,&worker_budget,&leftover_worker_funds,&dpo
533 #endif
534  ] ( asset_dynamic_data_object& _core )
535  {
536  _core.current_supply = (_core.current_supply + rec.supply_delta );
537 
538  assert( rec.supply_delta ==
539  witness_budget
540  + worker_budget
541  - leftover_worker_funds
542  - _core.accumulated_fees
543  - dpo.witness_budget
544  );
545  _core.accumulated_fees = 0;
546  });
547 
548  modify(dpo, [&witness_budget, &now]( dynamic_global_property_object& _dpo )
549  {
550  // Since initial witness_budget was rolled into
551  // available_funds, we replace it with witness_budget
552  // instead of adding it.
553  _dpo.witness_budget = witness_budget;
554  _dpo.last_budget_time = now;
555  });
556 
557  rec.current_supply = core.current_supply;
558  create< budget_record_object >( [this,&rec]( budget_record_object& _rec )
559  {
560  _rec.time = head_block_time();
561  _rec.record = rec;
562  });
563 
564  // available_funds is money we could spend, but don't want to.
565  // we simply let it evaporate back into the reserve.
566  }
567  FC_CAPTURE_AND_RETHROW() // GCOVR_EXCL_LINE
568 }
569 
570 template< typename Visitor >
571 void visit_special_authorities( const database& db, Visitor visit )
572 {
573  const auto& sa_idx = db.get_index_type< special_authority_index >().indices().get<by_id>();
574 
575  for( const special_authority_object& sao : sa_idx )
576  {
577  const account_object& acct = sao.account(db);
579  {
580  visit( acct, true, acct.owner_special_authority );
581  }
583  {
584  visit( acct, false, acct.active_special_authority );
585  }
586  }
587 }
588 
590 {
591  visit_special_authorities( db, [&db]( const account_object& acct, bool is_owner, const special_authority& auth )
592  {
593  if( auth.is_type< top_holders_special_authority >() )
594  {
595  // use index to grab the top N holders of the asset and vote_counter to obtain the weights
596 
597  const top_holders_special_authority& tha = auth.get< top_holders_special_authority >();
598  vote_counter vc;
599  const auto& bal_idx = db.get_index_type< account_balance_index >().indices().get< by_asset_balance >();
600  uint8_t num_needed = tha.num_top_holders;
601  if( 0 == num_needed )
602  return;
603 
604  // find accounts
605  const auto range = bal_idx.equal_range( boost::make_tuple( tha.asset ) );
606  for( const account_balance_object& bal : boost::make_iterator_range( range.first, range.second ) )
607  {
608  assert( bal.asset_type == tha.asset );
609  if( bal.owner == acct.id )
610  continue;
611  vc.add( bal.owner, bal.balance.value );
612  --num_needed;
613  if( 0 == num_needed )
614  break;
615  }
616 
617  db.modify( acct, [&vc,&is_owner]( account_object& a )
618  {
619  vc.finish( is_owner ? a.owner : a.active );
620  if( !vc.is_empty() )
621  a.top_n_control_flags |= (is_owner ? account_object::top_n_control_owner
622  : account_object::top_n_control_active);
623  } );
624  }
625  } );
626 }
627 
629  database& db,
630  uint64_t fba_id,
631  uint16_t network_pct,
632  uint16_t designated_asset_buyback_pct,
633  uint16_t designated_asset_issuer_pct
634 )
635 {
636  FC_ASSERT( ( uint32_t(network_pct) + designated_asset_buyback_pct ) + designated_asset_issuer_pct
638  const fba_accumulator_object& fba = fba_accumulator_id_type( fba_id )(db);
639  if( 0 == fba.accumulated_fba_fees )
640  return;
641 
642  const asset_dynamic_data_object& core_dd = db.get_core_dynamic_data();
643 
644  if( !fba.is_configured(db) )
645  {
646  ilog( "${n} core given to network at block ${b} due to non-configured FBA",
647  ("n", fba.accumulated_fba_fees)("b", db.head_block_time()) );
648  db.modify( core_dd, [&fba]( asset_dynamic_data_object& _core_dd )
649  {
650  _core_dd.current_supply -= fba.accumulated_fba_fees;
651  } );
652  db.modify( fba, []( fba_accumulator_object& _fba )
653  {
654  _fba.accumulated_fba_fees = 0;
655  } );
656  return;
657  }
658 
659  fc::uint128_t buyback_amount_128 = fba.accumulated_fba_fees.value;
660  buyback_amount_128 *= designated_asset_buyback_pct;
661  buyback_amount_128 /= GRAPHENE_100_PERCENT;
662  share_type buyback_amount = static_cast<uint64_t>(buyback_amount_128);
663 
664  fc::uint128_t issuer_amount_128 = fba.accumulated_fba_fees.value;
665  issuer_amount_128 *= designated_asset_issuer_pct;
666  issuer_amount_128 /= GRAPHENE_100_PERCENT;
667  share_type issuer_amount = static_cast<uint64_t>(issuer_amount_128);
668 
669  // this assert should never fail
670  FC_ASSERT( buyback_amount + issuer_amount <= fba.accumulated_fba_fees );
671 
672  share_type network_amount = fba.accumulated_fba_fees - (buyback_amount + issuer_amount);
673 
674  const asset_object& designated_asset = (*fba.designated_asset)(db);
675 
676  if( network_amount != 0 )
677  {
678  db.modify( core_dd, [&]( asset_dynamic_data_object& _core_dd )
679  {
680  _core_dd.current_supply -= network_amount;
681  } );
682  }
683 
685  vop.account_id = *designated_asset.buyback_account;
686  vop.fba_id = fba.id;
687  vop.amount = buyback_amount;
688  if( vop.amount != 0 )
689  {
690  db.adjust_balance( *designated_asset.buyback_account, asset(buyback_amount) );
691  db.push_applied_operation(vop);
692  }
693 
694  vop.account_id = designated_asset.issuer;
695  vop.fba_id = fba.id;
696  vop.amount = issuer_amount;
697  if( vop.amount != 0 )
698  {
699  db.adjust_balance( designated_asset.issuer, asset(issuer_amount) );
700  db.push_applied_operation(vop);
701  }
702 
703  db.modify( fba, []( fba_accumulator_object& _fba )
704  {
705  _fba.accumulated_fba_fees = 0;
706  } );
707 }
708 
710 {
711  constexpr uint16_t twenty = 20;
712  constexpr uint16_t twenty_percent = twenty * GRAPHENE_1_PERCENT;
713  constexpr uint16_t sixty = 60;
714  constexpr uint16_t sixty_percent = sixty * GRAPHENE_1_PERCENT;
715  split_fba_balance( db, fba_accumulator_id_transfer_to_blind , twenty_percent, sixty_percent, twenty_percent );
716  split_fba_balance( db, fba_accumulator_id_blind_transfer , twenty_percent, sixty_percent, twenty_percent );
717  split_fba_balance( db, fba_accumulator_id_transfer_from_blind, twenty_percent, sixty_percent, twenty_percent );
718 }
719 
721 {
722  const auto& bbo_idx = db.get_index_type< buyback_index >().indices().get<by_id>();
723  const auto& bal_idx = db.get_index_type< primary_index< account_balance_index > >()
724  .get_secondary_index< balances_by_account_index >();
725 
726  for( const buyback_object& bbo : bbo_idx )
727  {
728  const asset_object& asset_to_buy = bbo.asset_to_buy(db);
729  assert( asset_to_buy.buyback_account.valid() );
730 
731  const account_object& buyback_account = (*(asset_to_buy.buyback_account))(db);
732 
733  if( !buyback_account.allowed_assets.valid() )
734  {
735  wlog( "skipping buyback account ${b} at block ${n} because allowed_assets does not exist",
736  ("b", buyback_account)("n", db.head_block_num()) );
737  continue;
738  }
739 
740  for( const auto& entry : bal_idx.get_account_balances( buyback_account.get_id() ) )
741  {
742  const auto* it = entry.second;
743  asset_id_type asset_to_sell = it->asset_type;
744  share_type amount_to_sell = it->balance;
745  if( asset_to_sell == asset_to_buy.id )
746  continue;
747  if( amount_to_sell == 0 )
748  continue;
749  if( buyback_account.allowed_assets->find( asset_to_sell ) == buyback_account.allowed_assets->end() )
750  {
751  wlog( "buyback account ${b} not selling disallowed holdings of asset ${a} at block ${n}",
752  ("b", buyback_account)("a", asset_to_sell)("n", db.head_block_num()) );
753  continue;
754  }
755 
756  try
757  {
758  transaction_evaluation_state buyback_context(&db);
759  buyback_context.skip_fee_schedule_check = true;
760 
761  limit_order_create_operation create_vop;
762  create_vop.fee = asset( 0, asset_id_type() );
763  create_vop.seller = buyback_account.id;
764  create_vop.amount_to_sell = asset( amount_to_sell, asset_to_sell );
765  create_vop.min_to_receive = asset( 1, asset_to_buy.get_id() );
766  create_vop.expiration = time_point_sec::maximum();
767  create_vop.fill_or_kill = false;
768 
769  limit_order_id_type order_id{ db.apply_operation( buyback_context, create_vop ).get< object_id_type >() };
770 
771  if( db.find( order_id ) != nullptr )
772  {
773  limit_order_cancel_operation cancel_vop;
774  cancel_vop.fee = asset( 0, asset_id_type() );
775  cancel_vop.order = order_id;
776  cancel_vop.fee_paying_account = buyback_account.id;
777 
778  db.apply_operation( buyback_context, cancel_vop );
779  }
780  }
781  catch( const fc::exception& e )
782  {
783  // we can in fact get here,
784  // e.g. if asset issuer of buy/sell asset blacklists/whitelists the buyback account
785  wlog( "Skipping buyback processing selling ${as} for ${ab} for buyback account ${b} at block ${n}; "
786  "exception was ${e}",
787  ("as", asset_to_sell)("ab", asset_to_buy)("b", buyback_account)
788  ("n", db.head_block_num())("e", e.to_detail_string()) );
789  continue;
790  }
791  }
792  }
793  return;
794 }
795 
797 {
798  const auto& account_idx = db.get_index_type<account_index>().indices().get<by_id>();
800  for( const account_object& acct : account_idx )
801  {
802  try
803  {
804  transaction_evaluation_state upgrade_context(&db);
805  upgrade_context.skip_fee_schedule_check = true;
806 
807  if( acct.is_annual_member( now ) )
808  {
809  account_upgrade_operation upgrade_vop;
810  upgrade_vop.fee = asset( 0, asset_id_type() );
811  upgrade_vop.account_to_upgrade = acct.id;
812  upgrade_vop.upgrade_to_lifetime_member = true;
813  db.apply_operation( upgrade_context, upgrade_vop );
814  }
815  }
816  catch( const fc::exception& e )
817  {
818  // we can in fact get here, e.g. if asset issuer of buy/sell asset blacklists/whitelists the buyback account
819  wlog( "Skipping annual member deprecate processing for account ${a} (${an}) at block ${n}; exception was ${e}",
820  ("a", acct.id)("an", acct.name)("n", db.head_block_num())("e", e.to_detail_string()) );
821  continue;
822  }
823  }
824  return;
825 }
826 
827 void database::process_bids( const asset_bitasset_data_object& bad )
828 {
829  if( bad.is_prediction_market || bad.current_feed.settlement_price.is_null() )
830  return;
831 
832  asset_id_type to_revive_id = bad.asset_id;
833  const asset_object& to_revive = to_revive_id( *this );
834  const asset_dynamic_data_object& bdd = to_revive.dynamic_data( *this );
835 
836  if( 0 == bdd.current_supply ) // shortcut
837  {
838  _cancel_bids_and_revive_mpa( to_revive, bad );
839  return;
840  }
841 
842  bool after_hf_core_2290 = HARDFORK_CORE_2290_PASSED( get_dynamic_global_properties().next_maintenance_time );
843 
844  const auto& bid_idx = get_index_type< collateral_bid_index >().indices().get<by_price>();
845  const auto start = bid_idx.lower_bound( to_revive_id );
846  auto end = bid_idx.upper_bound( to_revive_id );
847 
848  share_type covered = 0;
849  auto itr = start;
850  auto revive_ratio = after_hf_core_2290 ? bad.current_feed.initial_collateral_ratio
851  : bad.current_feed.maintenance_collateral_ratio;
852  while( covered < bdd.current_supply && itr != end )
853  {
854  const collateral_bid_object& bid = *itr;
855  asset debt_in_bid = bid.inv_swan_price.quote;
856  if( debt_in_bid.amount > bdd.current_supply )
857  debt_in_bid.amount = bdd.current_supply;
858  asset total_collateral = debt_in_bid * bad.settlement_price;
859  total_collateral += bid.inv_swan_price.base;
860  price call_price = price::call_price( debt_in_bid, total_collateral, revive_ratio );
861  if( ~call_price >= bad.current_feed.settlement_price ) break;
862  covered += debt_in_bid.amount;
863  ++itr;
864  }
865  if( covered < bdd.current_supply ) return;
866 
867  end = itr;
868  share_type to_cover = bdd.current_supply;
869  share_type remaining_fund = bad.settlement_fund;
870  itr = start;
871  while( itr != end )
872  {
873  const collateral_bid_object& bid = *itr;
874  ++itr;
875  asset debt_in_bid = bid.inv_swan_price.quote;
876  if( debt_in_bid.amount > bdd.current_supply )
877  debt_in_bid.amount = bdd.current_supply;
878  share_type debt = debt_in_bid.amount;
879  share_type collateral = (debt_in_bid * bad.settlement_price).amount;
880  if( debt >= to_cover )
881  {
882  debt = to_cover;
883  collateral = remaining_fund;
884  }
885  to_cover -= debt;
886  remaining_fund -= collateral;
887  execute_bid( bid, debt, collateral, bad.current_feed );
888  }
889  FC_ASSERT( remaining_fund == 0 );
890  FC_ASSERT( to_cover == 0 );
891 
892  _cancel_bids_and_revive_mpa( to_revive, bad );
893 }
894 
898 {
899  // Update call_price
900  wlog( "Updating all call orders for hardfork core-343 at block ${n}", ("n",db.head_block_num()) );
901  asset_id_type current_asset;
902  const asset_bitasset_data_object* abd = nullptr;
903  // by_collateral index won't change after call_price updated, so it's safe to iterate
904  for( const auto& call_obj : db.get_index_type<call_order_index>().indices().get<by_collateral>() )
905  {
906  if( current_asset != call_obj.debt_type() ) // debt type won't be asset_id_type(), abd will always get initialized
907  {
908  current_asset = call_obj.debt_type();
909  abd = &current_asset(db).bitasset_data(db);
910  }
911  if( !abd || abd->is_prediction_market ) // nothing to do with PM's; check !abd just to be safe
912  continue;
913  db.modify( call_obj, [abd]( call_order_object& call ) {
914  call.call_price = price::call_price( call.get_debt(), call.get_collateral(),
916  });
917  }
918  wlog( "Done updating all call orders for hardfork core-343 at block ${n}", ("n",db.head_block_num()) );
919 }
920 
924 {
925  // Update call_price
926  for( const auto& call_obj : db.get_index_type<call_order_index>().indices().get<by_id>() )
927  {
928  db.modify( call_obj, []( call_order_object& call ) {
929  call.call_price.base.amount = 1;
930  call.call_price.quote.amount = 1;
931  });
932  }
933 }
934 
937 {
938  // Match call orders
939  wlog( "Matching call orders at block ${n}", ("n",db.head_block_num()) );
940  const auto& asset_idx = db.get_index_type<asset_index>().indices().get<by_type>();
941  auto itr = asset_idx.lower_bound( true );
942  auto itr_end = asset_idx.end();
943  while( itr != itr_end )
944  {
945  const asset_object& a = *itr;
946  ++itr;
947  // be here, next_maintenance_time should have been updated already
948  db.check_call_orders( a ); // allow black swan, and call orders are taker
949  }
950  wlog( "Done matching call orders at block ${n}", ("n",db.head_block_num()) );
951 }
952 
953 void database::process_bitassets()
954 {
955  time_point_sec head_time = head_block_time();
956  uint32_t head_epoch_seconds = head_time.sec_since_epoch();
957  bool after_hf_core_518 = ( head_time >= HARDFORK_CORE_518_TIME ); // clear expired feeds
958 
959  const auto& update_bitasset = [this,&head_time,head_epoch_seconds,after_hf_core_518]
960  ( asset_bitasset_data_object &o )
961  {
962  o.force_settled_volume = 0; // Reset all BitAsset force settlement volumes to zero
963 
964  // clear expired feeds if smartcoin (witness_fed or committee_fed) && check overflow
965  if( after_hf_core_518 && o.options.feed_lifetime_sec < head_epoch_seconds
966  && ( 0 != ( o.asset_id(*this).options.flags & ( witness_fed_asset | committee_fed_asset ) ) ) )
967  {
968  fc::time_point_sec calculated = head_time - o.options.feed_lifetime_sec;
969  auto itr = o.feeds.rbegin();
970  auto end = o.feeds.rend();
971  while( itr != end ) // loop feeds
972  {
973  auto feed_time = itr->second.first;
974  std::advance( itr, 1 );
975  if( feed_time < calculated )
976  o.feeds.erase( itr.base() ); // delete expired feed
977  }
978  // Note: we don't update current_feed here, and the update_expired_feeds() call is a bit too late,
979  // so theoretically there could be an inconsistency between active feeds and current_feed.
980  // And note that the next step "process_bids()" is based on current_feed.
981  }
982  };
983 
984  for( const auto& d : get_index_type<asset_bitasset_data_index>().indices() )
985  {
986  modify( d, update_bitasset );
987  if( d.is_globally_settled() )
988  process_bids(d);
989  }
990 }
991 
992 /****
993  * @brief a one-time data process to correct max_supply
994  *
995  * NOTE: while exceeding max_supply happened in mainnet, it seemed to have corrected
996  * itself before HF 1465. But this method must remain to correct some assets in testnet
997  */
999 {
1000  // for each market issued asset
1001  const auto& asset_idx = db.get_index_type<asset_index>().indices().get<by_type>();
1002  auto asset_end = asset_idx.end();
1003  for( auto asset_itr = asset_idx.lower_bound(true); asset_itr != asset_end; ++asset_itr )
1004  {
1005  const auto& current_asset = *asset_itr;
1006  graphene::chain::share_type current_supply = current_asset.dynamic_data(db).current_supply;
1007  graphene::chain::share_type max_supply = current_asset.options.max_supply;
1008  if (current_supply > max_supply && max_supply != GRAPHENE_MAX_SHARE_SUPPLY)
1009  {
1010  wlog( "Adjusting max_supply of ${asset} because current_supply (${current_supply}) is greater than ${old}.",
1011  ("asset", current_asset.symbol)
1012  ("current_supply", current_supply.value)
1013  ("old", max_supply));
1014  db.modify<asset_object>( current_asset, [current_supply](asset_object& obj) {
1015  obj.options.max_supply = graphene::chain::share_type(std::min(current_supply.value,
1017  });
1018  }
1019  }
1020 }
1021 
1022 /****
1023  * @brief a one-time data process to correct current_supply of BTS token in the BitShares mainnet
1024  */
1026 {
1027  const balance_object* bal = db.find( balance_id_type( HARDFORK_CORE_2103_BALANCE_ID ) );
1028  if( bal != nullptr && bal->balance.amount < 0 )
1029  {
1030  const asset_dynamic_data_object& ddo = bal->balance.asset_id(db).dynamic_data(db);
1032  obj.current_supply -= bal->balance.amount;
1033  });
1034  db.remove( *bal );
1035  }
1036 }
1037 
1038 static void update_bitasset_current_feeds(database& db)
1039 {
1040  for( const auto& bitasset : db.get_index_type<asset_bitasset_data_index>().indices() )
1041  {
1042  db.update_bitasset_current_feed( bitasset );
1043  }
1044 }
1045 
1046 /******
1047  * @brief one-time data process for hard fork core-868-890
1048  *
1049  * Prior to hardfork 868, switching a bitasset's shorting asset would not reset its
1050  * feeds. This method will run at the hardfork time, and erase (or nullify) feeds
1051  * that have incorrect backing assets.
1052  * https://github.com/bitshares/bitshares-core/issues/868
1053  *
1054  * Prior to hardfork 890, changing a bitasset's feed expiration time would not
1055  * trigger a median feed update. This method will run at the hardfork time, and
1056  * correct all median feed data.
1057  * https://github.com/bitshares/bitshares-core/issues/890
1058  *
1059  * @param db the database
1060  */
1061 // NOTE: Unable to remove this function for testnet nor mainnet. Unfortunately, bad
1062 // feeds were found.
1064 {
1065  // for each market issued asset
1066  const auto& asset_idx = db.get_index_type<asset_index>().indices().get<by_type>();
1067  auto asset_end = asset_idx.end();
1068  for( auto asset_itr = asset_idx.lower_bound(true); asset_itr != asset_end; ++asset_itr )
1069  {
1070  const auto& current_asset = *asset_itr;
1071  // Incorrect witness & committee feeds can simply be removed.
1072  // For non-witness-fed and non-committee-fed assets, set incorrect
1073  // feeds to price(), since we can't simply remove them. For more information:
1074  // https://github.com/bitshares/bitshares-core/pull/832#issuecomment-384112633
1075  bool is_witness_or_committee_fed = false;
1076  if ( current_asset.options.flags & ( witness_fed_asset | committee_fed_asset ) )
1077  is_witness_or_committee_fed = true;
1078 
1079  // for each feed
1080  const asset_bitasset_data_object& bitasset_data = current_asset.bitasset_data(db);
1081  auto itr = bitasset_data.feeds.begin();
1082  while( itr != bitasset_data.feeds.end() )
1083  {
1084  // If the feed is invalid
1085  if ( itr->second.second.settlement_price.quote.asset_id != bitasset_data.options.short_backing_asset
1086  && ( is_witness_or_committee_fed || itr->second.second.settlement_price != price() ) )
1087  {
1088  db.modify( bitasset_data, [&itr, is_witness_or_committee_fed]( asset_bitasset_data_object& obj )
1089  {
1090  if( is_witness_or_committee_fed )
1091  {
1092  // erase the invalid feed
1093  itr = obj.feeds.erase(itr);
1094  }
1095  else
1096  {
1097  // nullify the invalid feed
1098  obj.feeds[itr->first].second.settlement_price = price();
1099  ++itr;
1100  }
1101  });
1102  }
1103  else
1104  {
1105  // Feed is valid. Skip it.
1106  ++itr;
1107  }
1108  } // end loop of each feed
1109 
1110  // always update the median feed due to https://github.com/bitshares/bitshares-core/issues/890
1111  db.update_bitasset_current_feed( bitasset_data );
1112  // NOTE: Normally we should call check_call_orders() after called update_bitasset_current_feed(), but for
1113  // mainnet actually check_call_orders() would do nothing, so we skipped it for better performance.
1114 
1115  } // for each market issued asset
1116 }
1117 
1118 
1124 {
1125  const auto& index = db.get_index_type<custom_authority_index>().indices().get<by_expiration>();
1126  while (!index.empty() && index.begin()->valid_to < db.head_block_time())
1127  db.remove(*index.begin());
1128 }
1129 
1132 {
1133  for( const auto& ticket_obj : db.get_index_type<ticket_index>().indices().get<by_id>() )
1134  {
1135  if( ticket_obj.current_type != liquid ) // only update liquid tickets
1136  continue;
1137  db.modify( db.get_account_stats_by_owner( ticket_obj.account ), [&ticket_obj](account_statistics_object& aso) {
1138  aso.total_pol_value -= ticket_obj.value;
1139  });
1140  db.modify( ticket_obj, []( ticket_object& t ) {
1141  t.value = 0;
1142  });
1143  }
1144 }
1145 
1148 {
1149  const auto& bid_idx = db.get_index_type< collateral_bid_index >().indices().get<by_price>();
1150  auto bid_itr = bid_idx.begin();
1151  auto bid_end = bid_idx.end();
1152 
1153  asset_id_type current_asset_id;
1154  bool can_bid_collateral = true;
1155 
1156  while( bid_itr != bid_end )
1157  {
1158  const collateral_bid_object& bid = *bid_itr;
1159  ++bid_itr;
1160  if( current_asset_id != bid.inv_swan_price.quote.asset_id )
1161  {
1162  current_asset_id = bid.inv_swan_price.quote.asset_id;
1163  can_bid_collateral = current_asset_id(db).can_bid_collateral();
1164  }
1165  if( !can_bid_collateral )
1166  db.cancel_bid( bid );
1167  }
1168 
1169 }
1170 
1171 namespace detail {
1172 
1174  {
1177  };
1178 
1180  {
1181  vote_recalc_options( uint32_t f, uint32_t d, uint32_t s )
1182  : full_power_seconds(f), recalc_steps(d), seconds_per_step(s)
1183  {
1184  total_recalc_seconds = ( recalc_steps - 1 ) * seconds_per_step; // should not overflow
1185  power_percents_to_subtract.reserve( recalc_steps - 1 );
1186  for( uint32_t i = 1; i < recalc_steps; ++i )
1187  // should not overflow
1188  power_percents_to_subtract.push_back( (uint16_t)( ( GRAPHENE_100_PERCENT * i ) / recalc_steps ) );
1189  }
1190 
1192  {
1193  return { now - full_power_seconds, now - full_power_seconds - total_recalc_seconds };
1194  }
1195 
1197  uint32_t recalc_steps; // >= 1
1200  vector<uint16_t> power_percents_to_subtract;
1201 
1202  static const vote_recalc_options& witness();
1203  static const vote_recalc_options& committee();
1204  static const vote_recalc_options& worker();
1205  static const vote_recalc_options& delegator();
1206 
1207  // return the stake that is "recalced to X"
1208  uint64_t get_recalced_voting_stake( const uint64_t stake, const time_point_sec last_vote_time,
1209  const vote_recalc_times& recalc_times ) const
1210  {
1211  if( last_vote_time > recalc_times.full_power_time )
1212  return stake;
1213  if( last_vote_time <= recalc_times.zero_power_time )
1214  return 0;
1215  uint32_t diff = recalc_times.full_power_time.sec_since_epoch() - last_vote_time.sec_since_epoch();
1216  uint32_t steps_to_subtract_minus_1 = diff / seconds_per_step;
1217  fc::uint128_t stake_to_subtract( stake );
1218  stake_to_subtract *= power_percents_to_subtract[steps_to_subtract_minus_1];
1219  stake_to_subtract /= GRAPHENE_100_PERCENT;
1220  return stake - static_cast<uint64_t>(stake_to_subtract);
1221  }
1222  };
1223 
1224  const vote_recalc_options& vote_recalc_options::witness()
1225  {
1226  static const vote_recalc_options o( 360*86400, 8, 45*86400 );
1227  return o;
1228  }
1229  const vote_recalc_options& vote_recalc_options::committee()
1230  {
1231  static const vote_recalc_options o( 360*86400, 8, 45*86400 );
1232  return o;
1233  }
1234  const vote_recalc_options& vote_recalc_options::worker()
1235  {
1236  static const vote_recalc_options o( 360*86400, 8, 45*86400 );
1237  return o;
1238  }
1239  const vote_recalc_options& vote_recalc_options::delegator()
1240  {
1241  static const vote_recalc_options o( 360*86400, 8, 45*86400 );
1242  return o;
1243  }
1244 }
1245 
1246 void database::perform_chain_maintenance( const signed_block& next_block )
1247 {
1248  const auto& gpo = get_global_properties();
1249  const auto& dgpo = get_dynamic_global_properties();
1250  auto last_vote_tally_time = head_block_time();
1251 
1252  distribute_fba_balances(*this);
1253  create_buyback_orders(*this);
1254 
1255  struct vote_tally_helper {
1256  database& d;
1257  const global_property_object& props;
1258  const dynamic_global_property_object& dprops;
1259  const time_point_sec now;
1260  const bool hf2103_passed;
1261  const bool hf2262_passed;
1262  const bool pob_activated;
1263  const size_t two = 2;
1264  const size_t vid_committee = static_cast<size_t>( vote_id_type::committee ); // 0
1265  const size_t vid_witness = static_cast<size_t>( vote_id_type::witness ); // 1
1266  const size_t vid_worker = static_cast<size_t>( vote_id_type::worker ); // 2
1267 
1268  optional<detail::vote_recalc_times> witness_recalc_times;
1269  optional<detail::vote_recalc_times> committee_recalc_times;
1270  optional<detail::vote_recalc_times> worker_recalc_times;
1271  optional<detail::vote_recalc_times> delegator_recalc_times;
1272 
1273  explicit vote_tally_helper( database& db )
1274  : d(db), props( d.get_global_properties() ), dprops( d.get_dynamic_global_properties() ),
1275  now( d.head_block_time() ), hf2103_passed( HARDFORK_CORE_2103_PASSED( now ) ),
1276  hf2262_passed( HARDFORK_CORE_2262_PASSED( now ) ),
1277  pob_activated( dprops.total_pob > 0 || dprops.total_inactive > 0 )
1278  {
1279  d._vote_tally_buffer.resize( props.next_available_vote_id, 0 );
1280  d._witness_count_histogram_buffer.resize( (props.parameters.maximum_witness_count / two) + 1, 0 );
1281  d._committee_count_histogram_buffer.resize( (props.parameters.maximum_committee_count / two) + 1, 0 );
1282  d._total_voting_stake[vid_committee] = 0;
1283  d._total_voting_stake[vid_witness] = 0;
1284  if( hf2103_passed )
1285  {
1286  witness_recalc_times = detail::vote_recalc_options::witness().get_vote_recalc_times( now );
1287  committee_recalc_times = detail::vote_recalc_options::committee().get_vote_recalc_times( now );
1288  worker_recalc_times = detail::vote_recalc_options::worker().get_vote_recalc_times( now );
1289  delegator_recalc_times = detail::vote_recalc_options::delegator().get_vote_recalc_times( now );
1290  }
1291  }
1292 
1293  void operator()( const account_object& stake_account, const account_statistics_object& stats )
1294  {
1295  // PoB activation
1296  if( pob_activated && stats.total_core_pob == 0 && stats.total_core_inactive == 0 )
1297  return;
1298 
1299  if( props.parameters.count_non_member_votes || stake_account.is_member( now ) )
1300  {
1301  // There may be a difference between the account whose stake is voting and the one specifying opinions.
1302  // Usually they're the same, but if the stake account has specified a voting_account, that account is the
1303  // one specifying the opinions.
1304  bool directly_voting = ( stake_account.options.voting_account == GRAPHENE_PROXY_TO_SELF_ACCOUNT );
1305  const account_object& opinion_account = ( directly_voting ? stake_account
1306  : d.get(stake_account.options.voting_account) );
1307 
1308  std::array<uint64_t,3> voting_stake; // 0=committee, 1=witness, 2=worker, as in vote_id_type::vote_type
1309  uint64_t num_committee_voting_stake; // number of committee members
1310  voting_stake[vid_worker] = pob_activated ? 0 : stats.total_core_in_orders.value;
1311  voting_stake[vid_worker] += ( !hf2262_passed && stake_account.cashback_vb.valid() ) ?
1312  (*stake_account.cashback_vb)(d).balance.amount.value : 0;
1313  voting_stake[vid_worker] += hf2262_passed ? 0 : stats.core_in_balance.value;
1314 
1315  // voting power stats
1316  uint64_t vp_all = 0;
1317  uint64_t vp_active = 0;
1319  uint64_t vp_committee = 0;
1320  uint64_t vp_witness = 0;
1321  uint64_t vp_worker = 0;
1322 
1323  //PoB
1324  const uint64_t pol_amount = stats.total_core_pol.value;
1325  const uint64_t pol_value = stats.total_pol_value.value;
1326  const uint64_t pob_amount = stats.total_core_pob.value;
1327  const uint64_t pob_value = stats.total_pob_value.value;
1328  if( 0 == pob_amount )
1329  {
1330  voting_stake[vid_worker] += pol_value;
1331  }
1332  else if( 0 == pol_amount ) // and pob_amount > 0
1333  {
1334  if( pob_amount <= voting_stake[vid_worker] )
1335  {
1336  voting_stake[vid_worker] += ( pob_value - pob_amount );
1337  }
1338  else
1339  {
1340  auto base_value = ( static_cast<fc::uint128_t>( voting_stake[vid_worker] ) * pob_value )
1341  / pob_amount;
1342  voting_stake[vid_worker] = static_cast<uint64_t>( base_value );
1343  }
1344  }
1345  else if( pob_amount <= pol_amount ) // pob_amount > 0 && pol_amount > 0
1346  {
1347  auto base_value = ( static_cast<fc::uint128_t>( pob_value ) * pol_value ) / pol_amount;
1348  auto diff_value = ( static_cast<fc::uint128_t>( pob_amount ) * pol_value ) / pol_amount;
1349  base_value += ( pol_value - diff_value );
1350  voting_stake[vid_worker] += static_cast<uint64_t>( base_value );
1351  }
1352  else // pob_amount > pol_amount > 0
1353  {
1354  auto base_value = ( static_cast<fc::uint128_t>( pol_value ) * pob_value ) / pob_amount;
1355  fc::uint128_t diff_amount = pob_amount - pol_amount;
1356  if( diff_amount <= voting_stake[vid_worker] )
1357  {
1358  auto diff_value = ( static_cast<fc::uint128_t>( pol_amount ) * pob_value ) / pob_amount;
1359  base_value += ( pob_value - diff_value );
1360  voting_stake[vid_worker] += static_cast<uint64_t>( base_value - diff_amount );
1361  }
1362  else // diff_amount > voting_stake[vid_worker]
1363  {
1364  base_value += ( static_cast<fc::uint128_t>( voting_stake[vid_worker] ) * pob_value ) / pob_amount;
1365  voting_stake[vid_worker] = static_cast<uint64_t>( base_value );
1366  }
1367  }
1368 
1369  // Shortcut
1370  if( 0 == voting_stake[vid_worker] )
1371  return;
1372 
1373  const auto& opinion_account_stats = ( directly_voting ? stats : opinion_account.statistics( d ) );
1374 
1375  // Recalculate votes
1376  if( !hf2103_passed )
1377  {
1378  voting_stake[vid_committee] = voting_stake[vid_worker];
1379  voting_stake[vid_witness] = voting_stake[vid_worker];
1380  num_committee_voting_stake = voting_stake[vid_worker];
1381  vp_all = voting_stake[vid_worker];
1382  vp_active = voting_stake[vid_worker];
1383  vp_committee = voting_stake[vid_worker];
1384  vp_witness = voting_stake[vid_worker];
1385  vp_worker = voting_stake[vid_worker];
1386  }
1387  else
1388  {
1389  vp_all = voting_stake[vid_worker];
1390  vp_active = voting_stake[vid_worker];
1391  if( !directly_voting )
1392  {
1393  voting_stake[vid_worker] = detail::vote_recalc_options::delegator().get_recalced_voting_stake(
1394  voting_stake[vid_worker], stats.last_vote_time, *delegator_recalc_times );
1395  vp_active = voting_stake[vid_worker];
1396  }
1397  voting_stake[vid_witness] = detail::vote_recalc_options::witness().get_recalced_voting_stake(
1398  voting_stake[vid_worker], opinion_account_stats.last_vote_time, *witness_recalc_times );
1399  vp_witness = voting_stake[vid_witness];
1400  voting_stake[vid_committee] = detail::vote_recalc_options::committee().get_recalced_voting_stake(
1401  voting_stake[vid_worker], opinion_account_stats.last_vote_time, *committee_recalc_times );
1402  vp_committee = voting_stake[vid_committee];
1403  num_committee_voting_stake = voting_stake[vid_committee];
1404  if( opinion_account.num_committee_voted > 1 )
1405  voting_stake[vid_committee] /= opinion_account.num_committee_voted;
1406  voting_stake[vid_worker] = detail::vote_recalc_options::worker().get_recalced_voting_stake(
1407  voting_stake[vid_worker], opinion_account_stats.last_vote_time, *worker_recalc_times );
1408  vp_worker = voting_stake[vid_worker];
1409  }
1410 
1411  // update voting power
1412  d.modify( opinion_account_stats, [vp_all,vp_active,vp_committee,vp_witness,vp_worker,this]
1413  ( account_statistics_object& update_stats ) {
1414  if (update_stats.vote_tally_time != now)
1415  {
1416  update_stats.vp_all = vp_all;
1417  update_stats.vp_active = vp_active;
1418  update_stats.vp_committee = vp_committee;
1419  update_stats.vp_witness = vp_witness;
1420  update_stats.vp_worker = vp_worker;
1421  update_stats.vote_tally_time = now;
1422  }
1423  else
1424  {
1425  update_stats.vp_all += vp_all;
1426  update_stats.vp_active += vp_active;
1427  update_stats.vp_committee += vp_committee;
1428  update_stats.vp_witness += vp_witness;
1429  update_stats.vp_worker += vp_worker;
1430  }
1431  });
1432 
1433  for( vote_id_type id : opinion_account.options.votes )
1434  {
1435  uint32_t offset = id.instance();
1436  uint32_t type = std::min( id.type(), vote_id_type::vote_type::worker ); // cap the data
1437  // if they somehow managed to specify an illegal offset, ignore it.
1438  if( offset < d._vote_tally_buffer.size() )
1439  d._vote_tally_buffer[offset] += voting_stake[type];
1440  }
1441 
1442  // votes for a number greater than maximum_witness_count are skipped here
1443  if( voting_stake[vid_witness] > 0
1444  && opinion_account.options.num_witness <= props.parameters.maximum_witness_count )
1445  {
1446  uint16_t offset = opinion_account.options.num_witness / two;
1447  d._witness_count_histogram_buffer[offset] += voting_stake[vid_witness];
1448  }
1449  // votes for a number greater than maximum_committee_count are skipped here
1450  if( num_committee_voting_stake > 0
1451  && opinion_account.options.num_committee <= props.parameters.maximum_committee_count )
1452  {
1453  uint16_t offset = opinion_account.options.num_committee / two;
1454  d._committee_count_histogram_buffer[offset] += num_committee_voting_stake;
1455  }
1456 
1457  d._total_voting_stake[vid_committee] += num_committee_voting_stake;
1458  d._total_voting_stake[vid_witness] += voting_stake[vid_witness];
1459  }
1460  }
1461  };
1462 
1463  vote_tally_helper tally_helper(*this);
1464 
1465  perform_account_maintenance( tally_helper );
1466 
1467  struct clear_canary {
1468  explicit clear_canary(vector<uint64_t>& target): target(target){}
1469  clear_canary( const clear_canary& ) = delete;
1470  ~clear_canary() { target.clear(); }
1471  private:
1472  vector<uint64_t>& target;
1473  };
1474  clear_canary a(_witness_count_histogram_buffer);
1475  clear_canary b(_committee_count_histogram_buffer);
1476  clear_canary c(_vote_tally_buffer);
1477 
1478  update_top_n_authorities(*this);
1479  update_active_witnesses();
1480  update_active_committee_members();
1481  update_worker_votes();
1482 
1483  modify(gpo, [&dgpo](global_property_object& p) {
1484  // Remove scaling of account registration fee
1485  p.parameters.get_mutable_fees().get<account_create_operation>().basic_fee >>=
1486  p.parameters.account_fee_scale_bitshifts *
1487  (dgpo.accounts_registered_this_interval / p.parameters.accounts_per_fee_scale);
1488 
1489  if( p.pending_parameters )
1490  {
1491  p.parameters = std::move(*p.pending_parameters);
1492  p.pending_parameters.reset();
1493  }
1494  });
1495 
1496  auto next_maintenance_time = dgpo.next_maintenance_time;
1497  auto maintenance_interval = gpo.parameters.maintenance_interval;
1498 
1499  if( next_maintenance_time <= next_block.timestamp )
1500  {
1501  if( 1 == next_block.block_num() )
1502  next_maintenance_time = time_point_sec() +
1503  (((next_block.timestamp.sec_since_epoch() / maintenance_interval) + 1) * maintenance_interval);
1504  else
1505  {
1506  // We want to find the smallest k such that next_maintenance_time + k * maintenance_interval > head_block_time()
1507  // This implies k > ( head_block_time() - next_maintenance_time ) / maintenance_interval
1508  //
1509  // Let y be the right-hand side of this inequality, i.e.
1510  // y = ( head_block_time() - next_maintenance_time ) / maintenance_interval
1511  //
1512  // and let the fractional part f be y-floor(y). Clearly 0 <= f < 1.
1513  // We can rewrite f = y-floor(y) as floor(y) = y-f.
1514  //
1515  // Clearly k = floor(y)+1 has k > y as desired. Now we must
1516  // show that this is the least such k, i.e. k-1 <= y.
1517  //
1518  // But k-1 = floor(y)+1-1 = floor(y) = y-f <= y.
1519  // So this k suffices.
1520  //
1521  auto y = (head_block_time() - next_maintenance_time).to_seconds() / maintenance_interval;
1522  next_maintenance_time += (uint32_t)( (y+1) * maintenance_interval );
1523  }
1524  }
1525 
1526  if( (dgpo.next_maintenance_time < HARDFORK_613_TIME) && (next_maintenance_time >= HARDFORK_613_TIME) )
1527  deprecate_annual_members(*this);
1528 
1529  // To reset call_price of all call orders, then match by new rule, for hard fork core-343
1530  bool to_process_hf_343 = false;
1531  if( (dgpo.next_maintenance_time <= HARDFORK_CORE_343_TIME) && (next_maintenance_time > HARDFORK_CORE_343_TIME) )
1532  to_process_hf_343 = true;
1533 
1534  // Process inconsistent price feeds
1535  if( (dgpo.next_maintenance_time <= HARDFORK_CORE_868_890_TIME)
1536  && (next_maintenance_time > HARDFORK_CORE_868_890_TIME) )
1537  process_hf_868_890( *this );
1538 
1539  // To reset call_price of all call orders, then match by new rule, for hard fork core-1270
1540  bool to_process_hf_1270 = false;
1541  if( (dgpo.next_maintenance_time <= HARDFORK_CORE_1270_TIME) && (next_maintenance_time > HARDFORK_CORE_1270_TIME) )
1542  to_process_hf_1270 = true;
1543 
1544  // make sure current_supply is less than or equal to max_supply
1545  if ( dgpo.next_maintenance_time <= HARDFORK_CORE_1465_TIME && next_maintenance_time > HARDFORK_CORE_1465_TIME )
1546  process_hf_1465(*this);
1547 
1548  // Fix supply issue
1549  if ( dgpo.next_maintenance_time <= HARDFORK_CORE_2103_TIME && next_maintenance_time > HARDFORK_CORE_2103_TIME )
1550  process_hf_2103(*this);
1551 
1552  // Update tickets. Note: the new values will take effect only on the next maintenance interval
1553  if ( dgpo.next_maintenance_time <= HARDFORK_CORE_2262_TIME && next_maintenance_time > HARDFORK_CORE_2262_TIME )
1554  process_hf_2262(*this);
1555 
1556  // Cancel all collateral bids on assets which disabled collateral bidding already
1557  if ( dgpo.next_maintenance_time <= HARDFORK_CORE_2281_TIME && next_maintenance_time > HARDFORK_CORE_2281_TIME )
1558  process_hf_2281(*this);
1559 
1560  // To check call orders and potential match them with force settlements, for hard fork core-2481
1561  bool match_call_orders_for_hf_2481 = false;
1562  if( (dgpo.next_maintenance_time <= HARDFORK_CORE_2481_TIME) && (next_maintenance_time > HARDFORK_CORE_2481_TIME) )
1563  match_call_orders_for_hf_2481 = true;
1564 
1565  modify(dgpo, [last_vote_tally_time, next_maintenance_time](dynamic_global_property_object& d) {
1566  d.next_maintenance_time = next_maintenance_time;
1567  d.last_vote_tally_time = last_vote_tally_time;
1568  d.accounts_registered_this_interval = 0;
1569  });
1570 
1571  // We need to do it after updated next_maintenance_time, to apply new rules here, for hard fork core-343
1572  if( to_process_hf_343 )
1573  {
1575  match_call_orders(*this);
1576  }
1577 
1578  // We need to do it after updated next_maintenance_time, to apply new rules here, for hard fork core-1270.
1579  if( to_process_hf_1270 )
1580  {
1582  update_bitasset_current_feeds(*this);
1583  match_call_orders(*this);
1584  }
1585 
1586  // We need to do it after updated next_maintenance_time, to apply new rules here, for hard fork core-2481
1587  if( match_call_orders_for_hf_2481 )
1588  {
1589  match_call_orders(*this);
1590  }
1591 
1592  process_bitassets();
1594 
1595  // process_budget needs to run at the bottom because
1596  // it needs to know the next_maintenance_time
1597  process_budget();
1598 }
1599 
1600 } }
GRAPHENE_MAX_SHARE_SUPPLY
constexpr int64_t GRAPHENE_MAX_SHARE_SUPPLY(1000000000000000LL)
graphene::chain::buyback_object
Definition: buyback_object.hpp:43
fc::time_point_sec::sec_since_epoch
uint32_t sec_since_epoch() const
Definition: time.hpp:90
GRAPHENE_1_PERCENT
#define GRAPHENE_1_PERCENT
Definition: config.hpp:103
FC_CAPTURE_AND_RETHROW
#define FC_CAPTURE_AND_RETHROW(...)
Definition: exception.hpp:479
uint128.hpp
fba_accumulator_id.hpp
graphene::db::object::id
object_id_type id
Definition: object.hpp:69
GRAPHENE_CORE_ASSET_CYCLE_RATE
#define GRAPHENE_CORE_ASSET_CYCLE_RATE
Definition: config.hpp:51
graphene::chain::detail::vote_recalc_options::seconds_per_step
uint32_t seconds_per_step
Definition: db_maint.cpp:1198
graphene::chain::update_top_n_authorities
void update_top_n_authorities(database &db)
Definition: db_maint.cpp:589
GRAPHENE_RELAXED_COMMITTEE_ACCOUNT
#define GRAPHENE_RELAXED_COMMITTEE_ACCOUNT
Represents the current committee members.
Definition: config.hpp:144
graphene::chain::dynamic_global_property_object
Maintains global state information (committee_member list, current fees)
Definition: global_property_object.hpp:62
graphene::chain::database
tracks the blockchain state in an extensible manner
Definition: database.hpp:70
graphene::protocol::limit_order_create_operation::amount_to_sell
asset amount_to_sell
Definition: market.hpp:89
graphene::protocol::fba_distribute_operation::amount
share_type amount
Definition: fba.hpp:38
wlog
#define wlog(FORMAT,...)
Definition: logger.hpp:123
fc::exception
Used to generate a useful error report when an exception is thrown.
Definition: exception.hpp:56
graphene::chain::database::head_block_time
time_point_sec head_block_time() const
Definition: db_getter.cpp:67
graphene::chain::process_hf_2103
void process_hf_2103(database &db)
Definition: db_maint.cpp:1025
graphene::chain::process_hf_868_890
void process_hf_868_890(database &db)
Definition: db_maint.cpp:1063
asset_object.hpp
graphene::protocol::vote_id_type::witness
@ witness
Definition: vote.hpp:61
graphene::db::object_database::get
const T & get(const object_id_type &id) const
Definition: object_database.hpp:119
graphene::protocol::witness_fed_asset
@ witness_fed_asset
the bitasset is to be fed by witnesses
Definition: types.hpp:201
graphene::protocol::price
The price struct stores asset prices in the BitShares system.
Definition: asset.hpp:108
GRAPHENE_PROXY_TO_SELF_ACCOUNT
#define GRAPHENE_PROXY_TO_SELF_ACCOUNT
Represents the canonical account for specifying you will vote directly (as opposed to a proxy)
Definition: config.hpp:150
graphene::chain::transaction_evaluation_state::skip_fee_schedule_check
bool skip_fee_schedule_check
Definition: transaction_evaluation_state.hpp:50
graphene::chain::asset_bitasset_data_object::is_prediction_market
bool is_prediction_market
True if this asset implements a Prediction Market.
Definition: asset_object.hpp:291
budget_record_object.hpp
database.hpp
graphene::protocol::liquid
@ liquid
Definition: ticket.hpp:35
graphene::db::primary_index
Wraps a derived index to intercept calls to create, modify, and remove so that callbacks may be fired...
Definition: index.hpp:312
fc::static_variant
Definition: raw_fwd.hpp:27
graphene::chain::ticket_object
a ticket for governance voting
Definition: ticket_object.hpp:62
graphene::protocol::fba_distribute_operation
Definition: fba.hpp:30
graphene::chain::detail::vote_recalc_options
Definition: db_maint.cpp:1179
graphene::chain::call_order_object::get_collateral
asset get_collateral() const
Definition: market_object.hpp:143
graphene::chain::global_property_object::parameters
chain_parameters parameters
Definition: global_property_object.hpp:44
custom_authority_object.hpp
graphene::chain::detail::vote_recalc_options::get_recalced_voting_stake
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:1208
chain_property_object.hpp
graphene::chain::asset_dynamic_data_object::current_supply
share_type current_supply
The number of shares currently in existence.
Definition: asset_object.hpp:61
graphene::chain::transaction_evaluation_state
Definition: transaction_evaluation_state.hpp:37
graphene::chain::visit_special_authorities
void visit_special_authorities(const database &db, Visitor visit)
Definition: db_maint.cpp:571
GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS
#define GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS
Definition: config.hpp:52
graphene::chain::match_call_orders
void match_call_orders(database &db)
Match call orders for all bitAssets, including PMs.
Definition: db_maint.cpp:936
graphene::chain::asset_object
tracks the parameters of an asset
Definition: asset_object.hpp:75
graphene::chain::database::adjust_balance
void adjust_balance(account_id_type account, asset delta)
Adjust a particular account's balance in a given asset by a delta.
Definition: db_balance.cpp:54
graphene::chain::database::check_call_orders
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, bool mute_exceptions=false, bool skip_matching_settle_orders=false)
Definition: db_market.cpp:2079
graphene::chain::call_order_object::get_debt
asset get_debt() const
Definition: market_object.hpp:144
graphene::chain::fba_accumulator_object::designated_asset
optional< asset_id_type > designated_asset
Definition: fba_object.hpp:42
special_authority_object.hpp
graphene::chain::worker_pay_visitor::worker_pay_visitor
worker_pay_visitor(share_type pay, database &db)
Definition: db_maint.cpp:126
graphene::chain::database::get_core_asset
const asset_object & get_core_asset() const
Definition: db_getter.cpp:37
worker_object.hpp
graphene::chain::ticket_object::value
share_type value
The current value of the ticket.
Definition: ticket_object.hpp:71
graphene::chain::balance_object::balance
asset balance
Definition: balance_object.hpp:42
graphene::protocol::committee_fed_asset
@ committee_fed_asset
the bitasset is to be fed by the committee
Definition: types.hpp:202
graphene::protocol::block_header::block_num
uint32_t block_num() const
Definition: block.hpp:34
graphene::db::object_database::find
const T * find(const object_id_type &id) const
Definition: object_database.hpp:126
graphene::protocol::fba_distribute_operation::account_id
account_id_type account_id
Definition: fba.hpp:35
graphene::chain::fba_accumulator_object::is_configured
bool is_configured(const database &db) const
Definition: fba_object.cpp:31
graphene::chain::update_call_orders_hf_343
void update_call_orders_hf_343(database &db)
Definition: db_maint.cpp:897
graphene::protocol::vote_id_type::committee
@ committee
Definition: vote.hpp:60
graphene::chain::split_fba_balance
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:628
graphene::chain::delete_expired_custom_auths
void delete_expired_custom_auths(database &db)
Remove any custom active authorities whose expiration dates are in the past.
Definition: db_maint.cpp:1123
graphene::chain::detail::vote_recalc_options::recalc_steps
uint32_t recalc_steps
Definition: db_maint.cpp:1197
graphene::protocol::limit_order_create_operation::seller
account_id_type seller
Definition: market.hpp:88
graphene::chain::account_statistics_object
Definition: account_object.hpp:46
fc::days
microseconds days(int64_t d)
Definition: time.hpp:38
buyback_object.hpp
ilog
#define ilog(FORMAT,...)
Definition: logger.hpp:117
graphene::db::index::get
const object & get(object_id_type id) const
Definition: index.hpp:110
graphene::chain::database::update_bitasset_current_feed
void update_bitasset_current_feed(const asset_bitasset_data_object &bitasset, bool skip_median_update=false)
Definition: db_update.cpp:270
graphene::db::generic_index::indices
const index_type & indices() const
Definition: generic_index.hpp:115
fc::optional::valid
bool valid() const
Definition: optional.hpp:186
graphene::chain::database::cancel_bid
void cancel_bid(const collateral_bid_object &bid, bool create_virtual_op=true)
Definition: db_market.cpp:477
graphene::chain::asset_dynamic_data_object
tracks the asset information that changes frequently
Definition: asset_object.hpp:56
graphene::chain::database::get_core_dynamic_data
const asset_dynamic_data_object & get_core_dynamic_data() const
Definition: db_getter.cpp:42
graphene::chain::account_object
This class represents an account on the object graph.
Definition: account_object.hpp:180
graphene::chain::process_hf_2281
void process_hf_2281(database &db)
A one-time data process to cancel all collateral bids for assets that disabled collateral bidding alr...
Definition: db_maint.cpp:1147
graphene::chain::special_authority_object
Definition: special_authority_object.hpp:42
graphene::chain::account_object::active_special_authority
special_authority active_special_authority
Definition: account_object.hpp:268
graphene::protocol::account_upgrade_operation::account_to_upgrade
account_id_type account_to_upgrade
The account to upgrade; must not already be a lifetime member.
Definition: account.hpp:244
graphene::chain::detail::vote_recalc_times
Definition: db_maint.cpp:1173
fc::time_point_sec
Definition: time.hpp:74
graphene::protocol::asset::asset_id
asset_id_type asset_id
Definition: asset.hpp:37
graphene::chain::detail::vote_recalc_options::power_percents_to_subtract
vector< uint16_t > power_percents_to_subtract
Definition: db_maint.cpp:1200
account_object.hpp
graphene::chain::database::push_applied_operation
uint32_t push_applied_operation(const operation &op, bool is_virtual=true)
Definition: db_block.cpp:548
graphene::chain::asset_bitasset_data_index
generic_index< asset_bitasset_data_object, bitasset_data_multi_index_type > asset_bitasset_data_index
Definition: asset_object.hpp:454
graphene::chain::by_expiration
Definition: proposal_object.hpp:86
graphene::protocol::chain_parameters::maximum_committee_count
uint16_t maximum_committee_count
maximum number of active committee_members
Definition: chain_parameters.hpp:64
graphene::protocol::no_special_authority
Definition: special_authority.hpp:30
graphene::chain::detail::vote_recalc_options::total_recalc_seconds
uint32_t total_recalc_seconds
Definition: db_maint.cpp:1199
vesting_balance_object.hpp
graphene::chain::fba_accumulator_object::accumulated_fba_fees
share_type accumulated_fba_fees
Definition: fba_object.hpp:41
graphene::protocol::account_upgrade_operation::upgrade_to_lifetime_member
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:246
graphene::chain::asset_bitasset_data_object
contains properties that only apply to bitassets (market issued assets)
Definition: asset_object.hpp:255
graphene::chain::asset_bitasset_data_object::current_feed
price_feed_with_icr current_feed
This is the currently active price feed, calculated from median_feed and other parameters.
Definition: asset_object.hpp:272
graphene::chain::collateral_bid_object
bids of collateral for debt after a black swan
Definition: market_object.hpp:206
graphene::chain::dynamic_global_property_object::last_budget_time
time_point_sec last_budget_time
Definition: global_property_object.hpp:72
fc::exception::to_detail_string
std::string to_detail_string(log_level ll=log_level::all) const
Definition: exception.cpp:183
graphene::chain::fba_accumulator_id_transfer_to_blind
@ fba_accumulator_id_transfer_to_blind
Definition: fba_accumulator_id.hpp:35
graphene::chain::call_order_object::call_price
price call_price
Collateral / Debt.
Definition: market_object.hpp:153
graphene::protocol::limit_order_cancel_operation
Definition: market.hpp:145
graphene::chain::process_hf_2262
void process_hf_2262(database &db)
A one-time data process to set values of existing liquid tickets to zero.
Definition: db_maint.cpp:1131
graphene::chain::detail::vote_recalc_options::vote_recalc_options
vote_recalc_options(uint32_t f, uint32_t d, uint32_t s)
Definition: db_maint.cpp:1181
graphene::protocol::limit_order_create_operation::expiration
time_point_sec expiration
Definition: market.hpp:94
committee_member_object.hpp
graphene::protocol::block_header::timestamp
fc::time_point_sec timestamp
Definition: block.hpp:35
graphene::chain::database::get_chain_properties
const chain_property_object & get_chain_properties() const
Definition: db_getter.cpp:52
graphene::chain::database::head_block_num
uint32_t head_block_num() const
Definition: db_getter.cpp:72
graphene::protocol::chain_parameters::maximum_witness_count
uint16_t maximum_witness_count
maximum number of active witnesses
Definition: chain_parameters.hpp:63
GRAPHENE_COMMITTEE_ACCOUNT
#define GRAPHENE_COMMITTEE_ACCOUNT
Definition: config.hpp:140
graphene::protocol::limit_order_create_operation::min_to_receive
asset min_to_receive
Definition: market.hpp:90
graphene::protocol::share_type
safe< int64_t > share_type
Definition: types.hpp:309
graphene::chain::distribute_fba_balances
void distribute_fba_balances(database &db)
Definition: db_maint.cpp:709
graphene::protocol::limit_order_create_operation::fee
asset fee
Definition: market.hpp:87
fc::typelist::transform
typename impl::transform< List, Transformer >::type transform
Transform elements of a typelist.
Definition: typelist.hpp:170
graphene::chain::detail::vote_recalc_options::full_power_seconds
uint32_t full_power_seconds
Definition: db_maint.cpp:1196
graphene::protocol::top_holders_special_authority
Definition: special_authority.hpp:32
graphene::chain::account_object::owner_special_authority
special_authority owner_special_authority
Definition: account_object.hpp:267
graphene::chain::worker_pay_visitor::result_type
void result_type
Definition: db_maint.cpp:129
FC_ASSERT
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
graphene::protocol::chain_parameters::count_non_member_votes
bool count_non_member_votes
set to false to restrict voting privlegages to member accounts
Definition: chain_parameters.hpp:71
graphene::chain::fba_accumulator_id_blind_transfer
@ fba_accumulator_id_blind_transfer
Definition: fba_accumulator_id.hpp:36
graphene::chain::asset_object::issuer
account_id_type issuer
ID of the account which issued this asset.
Definition: asset_object.hpp:135
graphene::protocol::fba_distribute_operation::fba_id
object_id_type fba_id
Definition: fba.hpp:37
fc::static_variant::is_type
bool is_type() const
Definition: static_variant.hpp:332
GRAPHENE_WITNESS_ACCOUNT
#define GRAPHENE_WITNESS_ACCOUNT
Represents the current witnesses.
Definition: config.hpp:142
graphene::protocol::limit_order_cancel_operation::fee
asset fee
Definition: market.hpp:149
graphene::db::object_id_type
Definition: object_id.hpp:30
graphene::protocol::asset::amount
share_type amount
Definition: asset.hpp:36
fc::static_variant::get
X & get()
Definition: static_variant.hpp:236
graphene::chain::global_property_object::next_available_vote_id
uint32_t next_available_vote_id
Definition: global_property_object.hpp:47
graphene::protocol::price_feed::maintenance_collateral_ratio
uint16_t maintenance_collateral_ratio
Definition: asset.hpp:186
market.hpp
graphene::chain::fba_accumulator_id_transfer_from_blind
@ fba_accumulator_id_transfer_from_blind
Definition: fba_accumulator_id.hpp:37
graphene::chain::worker_pay_visitor::operator()
void operator()(W &worker) const
Definition: db_maint.cpp:131
graphene::chain::global_property_object
Maintains global state information (committee_member list, current fees)
Definition: global_property_object.hpp:40
fc::microseconds::count
int64_t count() const
Definition: time.hpp:28
graphene::protocol::account_upgrade_operation
Manage an account's membership status.
Definition: account.hpp:235
graphene::protocol::account_upgrade_operation::fee
asset fee
Definition: account.hpp:242
graphene::protocol::limit_order_cancel_operation::fee_paying_account
account_id_type fee_paying_account
Definition: market.hpp:152
graphene::chain::update_call_orders_hf_1270
void update_call_orders_hf_1270(database &db)
Definition: db_maint.cpp:923
graphene::chain::call_order_object
tracks debt and call price information
Definition: market_object.hpp:140
graphene::protocol::price::base
asset base
Definition: asset.hpp:113
graphene::protocol::limit_order_cancel_operation::order
limit_order_id_type order
Definition: market.hpp:150
graphene::chain::balance_object
Definition: balance_object.hpp:30
graphene::protocol::limit_order_create_operation
instructs the blockchain to attempt to sell one asset for another
Definition: market.hpp:72
graphene::db::generic_index
Definition: generic_index.hpp:43
graphene::chain::database::apply_operation
operation_result apply_operation(transaction_evaluation_state &eval_state, const operation &op, bool is_virtual=true)
Definition: db_block.cpp:784
graphene::chain::database::get_account_stats_by_owner
const account_statistics_object & get_account_stats_by_owner(account_id_type owner) const
Definition: db_getter.cpp:142
balance_object.hpp
graphene::db::abstract_object::get_id
object_id< SpaceID, TypeID > get_id() const
Definition: object.hpp:113
graphene::chain::worker_pay_visitor
A visitor for worker_type which calls pay_worker on the worker within.
Definition: db_maint.cpp:119
graphene::chain::fba_accumulator_object
Definition: fba_object.hpp:37
graphene::chain::database::get_global_properties
const global_property_object & get_global_properties() const
Definition: db_getter.cpp:47
fc::optional
provides stack-based nullable value similar to boost::optional
Definition: optional.hpp:20
graphene::chain::vesting_balance_type::worker
@ worker
graphene::chain::deprecate_annual_members
void deprecate_annual_members(database &db)
Definition: db_maint.cpp:796
graphene::chain::account_object::allowed_assets
optional< flat_set< asset_id_type > > allowed_assets
Definition: account_object.hpp:283
graphene::chain::global_property_object::active_committee_members
vector< committee_member_id_type > active_committee_members
Definition: global_property_object.hpp:48
graphene::protocol::asset
Definition: asset.hpp:31
market_object.hpp
graphene::protocol::signed_block
Definition: block.hpp:64
graphene::protocol::limit_order_create_operation::fill_or_kill
bool fill_or_kill
If this flag is set the entire order must be filled or the operation is rejected.
Definition: market.hpp:97
fba_object.hpp
witness_object.hpp
graphene::db::object_database::remove
void remove(const object &obj)
Definition: object_database.hpp:97
graphene::chain::asset_bitasset_data_object::feeds
flat_map< account_id_type, pair< time_point_sec, price_feed_with_icr > > feeds
Definition: asset_object.hpp:268
graphene::db::object_database::get_index_type
const IndexType & get_index_type() const
Definition: object_database.hpp:77
graphene::chain::database::get_dynamic_global_properties
const dynamic_global_property_object & get_dynamic_global_properties() const
Definition: db_getter.cpp:57
fc::safe::value
T value
Definition: safe.hpp:28
vote_count.hpp
graphene::chain::detail::vote_recalc_times::zero_power_time
time_point_sec zero_power_time
Definition: db_maint.cpp:1176
graphene::chain::detail::vote_recalc_options::get_vote_recalc_times
vote_recalc_times get_vote_recalc_times(const time_point_sec now) const
Definition: db_maint.cpp:1191
graphene::chain::asset_object::buyback_account
optional< account_id_type > buyback_account
Definition: asset_object.hpp:144
graphene::chain::detail::vote_recalc_times::full_power_time
time_point_sec full_power_time
Definition: db_maint.cpp:1175
graphene::db::index
abstract base class for accessing objects indexed in various ways.
Definition: index.hpp:70
global_property_object.hpp
graphene::protocol::bitasset_options::short_backing_asset
asset_id_type short_backing_asset
Definition: asset_ops.hpp:171
graphene::chain::vesting_balance_type::witness
@ witness
graphene::protocol::price::quote
asset quote
Definition: asset.hpp:114
GRAPHENE_100_PERCENT
#define GRAPHENE_100_PERCENT
Definition: config.hpp:102
graphene
Definition: api.cpp:48
graphene::chain::create_buyback_orders
void create_buyback_orders(database &db)
Definition: db_maint.cpp:720
ticket_object.hpp
graphene::chain::asset_bitasset_data_object::options
bitasset_options options
The tunable options for BitAssets are stored in this field.
Definition: asset_object.hpp:263
graphene::chain::process_hf_1465
void process_hf_1465(database &db)
Definition: db_maint.cpp:998
graphene::db::object_database::modify
void modify(const T &obj, const Lambda &m)
Definition: object_database.hpp:99
graphene::chain::collateral_bid_object::inv_swan_price
price inv_swan_price
Definition: market_object.hpp:215
fc::safe
Definition: safe.hpp:26