Scorum
registration_pool_evaluator.cpp
Go to the documentation of this file.
2 
4 
11 
15 
16 namespace scorum {
17 namespace chain {
18 
20 
22 {
23 public:
24  registration_pool_evaluator_impl(data_service_factory_i& services)
25  : _account_registration_bonus_service(services.account_registration_bonus_service())
26  , _dprops_service(services.dynamic_global_property_service())
27  , _account_service(services.account_service())
28  , _registration_pool_service(services.registration_pool_service())
29  , _registration_committee_service(services.registration_committee_service())
30  {
31  }
32 
34  {
36 
37  asset per_reg = calculate_amount_by_schedule(pool);
38  FC_ASSERT(per_reg.amount > 0, "Invalid schedule. Zero bonus return.");
39 
40  // return value <= per_reg
41  per_reg = take_actually_amount(pool, per_reg);
42 
43  FC_ASSERT(per_reg.amount > 0, "Nothing to allocate.");
44 
45  if (committee_member != account_name_type())
46  {
47  validate_bandwidth(pool, committee_member, _registration_committee_service.get_member(committee_member),
48  per_reg);
49  }
50 
52 
54 
55  return per_reg;
56  }
57 
58  void register_account_bonus(const account_name_type& new_account, const asset& bonus)
59  {
61 
62  FC_ASSERT(bonus.amount > 0, "No bonus to register.");
63 
64  _account_registration_bonus_service.create([&](account_registration_bonus_object& a) {
65  a.account = new_account;
66  a.bonus += asset(bonus.amount, SP_SYMBOL);
67  a.expires = _dprops_service.head_block_time() + SCORUM_EXPIRATON_FOR_REGISTRATION_BONUS.to_seconds();
68  });
69  }
70 
71 private:
72  asset calculate_amount_by_schedule(const registration_pool_object& pool)
73  {
74  FC_ASSERT(!pool.schedule_items.empty(), "Invalid schedule.");
75 
76  // find position in schedule
77  std::size_t ci = 0;
78  uint64_t allocated_rest = pool.already_allocated_count;
79  auto it = pool.schedule_items.begin();
80  for (; it != pool.schedule_items.end(); ++it, ++ci)
81  {
82  uint64_t item_users_limit = (*it).users;
83 
84  if (allocated_rest >= item_users_limit)
85  {
86  allocated_rest -= item_users_limit;
87  }
88  else
89  {
90  break;
91  }
92  }
93 
94  if (it == pool.schedule_items.end())
95  {
96  // no more schedule items (out of schedule),
97  // use last stage to calculate bonus
98  --it;
99  }
100 
101  using schedule_item_type = registration_pool_object::schedule_item;
102  const schedule_item_type& current_item = (*it);
103  return (pool.maximum_bonus * scorum::utils::make_fraction(current_item.bonus_percent, 100));
104  }
105 
106  asset take_actually_amount(const registration_pool_object& pool, const asset& balance)
107  {
108  FC_ASSERT(balance.amount > 0, "Invalid balance.");
109 
110  asset ret(0, SCORUM_SYMBOL);
111 
112  if (pool.balance.amount > 0 && balance <= pool.balance)
113  {
114  ret = balance;
115  }
116  else
117  {
118  ret = pool.balance;
119  }
120 
121  return ret;
122  }
123 
124  void check_bandwidth(const registration_pool_object& pool,
125  const account_name_type& member_name,
126  uint32_t pass_blocks,
127  const asset& allocated_cash)
128  {
129  share_type limit_per_member = (share_type)(pass_blocks + 1);
131  FC_ASSERT(allocated_cash <= (pool.maximum_bonus
132  * scorum::utils::make_fraction(
134  "Committee member '${1}' reaches cash limit.", ("1", member_name));
135  }
136 
137  void validate_bandwidth(const registration_pool_object& pool,
138  const account_name_type& member_name,
139  const registration_committee_member_object& member,
140  const asset& amount)
141  {
142  const dynamic_global_property_object& dprops = _dprops_service.get();
143  uint32_t head_block_num = dprops.head_block_number;
144 
145  uint32_t last_allocated_block = member.last_allocated_block;
146  FC_ASSERT(last_allocated_block <= head_block_num);
147 
148  uint32_t pass_blocks = 0;
149  if (last_allocated_block > 0)
150  {
151  pass_blocks = head_block_num - last_allocated_block;
152  }
153 
154  last_allocated_block = head_block_num;
155 
156  // move floating window position
157  uint32_t per_n_block_remain = member.per_n_block_remain;
158  if (pass_blocks > per_n_block_remain)
159  {
160  per_n_block_remain = 0;
161  }
162  else if (pass_blocks > 0)
163  {
164  per_n_block_remain -= pass_blocks;
165  }
166 
167  asset already_allocated_cash(0, SCORUM_SYMBOL);
168  asset allocated_cash = member.already_allocated_cash;
169  if (per_n_block_remain > 0)
170  {
171  allocated_cash += amount;
172  already_allocated_cash = allocated_cash;
173  }
174  else
175  {
176  allocated_cash = asset(0, SCORUM_SYMBOL); // to prevent checking at the begining of floating window
177  already_allocated_cash = amount;
179  }
180 
181  check_bandwidth(pool, member_name, pass_blocks, allocated_cash);
182 
183  auto modifier = [=](registration_committee_member_object& m) {
184  m.last_allocated_block = last_allocated_block;
185  m.per_n_block_remain = per_n_block_remain;
186  m.already_allocated_cash = already_allocated_cash;
187  };
188 
190  }
191 
192  account_registration_bonus_service_i& _account_registration_bonus_service;
193  dynamic_global_property_service_i& _dprops_service;
194 
195 public:
199 };
200 
201 //
202 
204  : evaluator_impl<data_service_factory_i, registration_pool_evaluator>(services)
205  , _impl(new registration_pool_evaluator_impl(services))
206  , _hardfork_svc(services.hardfork_property_service())
207 {
208 }
209 
211 {
212 }
213 
215 {
216  _impl->_account_service.check_account_existence(o.creator);
217 
218  _impl->_account_service.check_account_existence(o.owner.account_auths);
219 
220  _impl->_account_service.check_account_existence(o.active.account_auths);
221 
222  _impl->_account_service.check_account_existence(o.posting.account_auths);
223 
224  FC_ASSERT(_impl->_registration_committee_service.is_exists(o.creator), "Account '${1}' is not committee member.",
225  ("1", o.creator));
226 
227  if (_hardfork_svc.has_hardfork(SCORUM_HARDFORK_0_3))
228  {
229  // This is temporary solution until we implement new registration algorithm in the next hardfork
230  // Required SP for making transactions would be delegated manualy offchain
231  _impl->_account_service.create_account(o.new_account_name, o.creator, o.memo_key, o.json_metadata, o.owner,
232  o.active, o.posting, asset(0, SCORUM_SYMBOL));
233  }
234  else
235  {
236  FC_ASSERT(_impl->_registration_pool_service.is_exists(), "Registration pool is not initialized.");
237 
238  FC_ASSERT(_impl->_registration_pool_service.get().balance.amount > 0, "Registration pool is exhausted.");
239 
240  asset bonus = _impl->allocate_cash(o.creator);
241 
242  _impl->_account_service.create_account_with_bonus(o.new_account_name, o.creator, o.memo_key, o.json_metadata,
243  o.owner, o.active, o.posting, bonus);
244  _impl->register_account_bonus(o.new_account_name, bonus);
245  }
246 }
247 
248 //
249 
251  data_service_factory_i& services, const account_object& beneficiary)
252  : _services(services)
253  , _beneficiary(beneficiary)
254 {
255 }
256 
258 {
259  return _services;
260 }
261 
263 {
264  return _beneficiary;
265 }
266 
268 {
270 
271  asset bonus = impl.allocate_cash();
272  account_service_i& account_service = ctx.services().account_service();
273 
274  account_service.create_scorumpower(ctx.beneficiary(), bonus);
275  impl.register_account_bonus(ctx.beneficiary().name, bonus);
276 }
277 }
278 }
give_bonus_from_registration_pool_task_context(data_service_factory_i &services, const account_object &beneficiary)
void on_apply(give_bonus_from_registration_pool_task_context &ctx)
registration_pool_evaluator_impl(data_service_factory_i &services)
registration_committee_service_i & _registration_committee_service
asset allocate_cash(const account_name_type &committee_member=account_name_type())
void register_account_bonus(const account_name_type &new_account, const asset &bonus)
registration_pool_evaluator(data_service_factory_i &services)
fc::shared_vector< schedule_item > schedule_items
#define SCORUM_REGISTRATION_BONUS_LIMIT_PER_MEMBER_N_BLOCK
Definition: config.hpp:166
#define SP_SYMBOL
Definition: config.hpp:104
#define SCORUM_SYMBOL
Definition: config.hpp:102
#define SCORUM_REGISTRATION_BONUS_LIMIT_PER_MEMBER_PER_N_BLOCK
Definition: config.hpp:164
fc::safe< share_value_type > share_type
Definition: types.hpp:73
fc::fixed_string_16 account_name_type
Definition: types.hpp:62
Definition: asset.cpp:15
virtual const asset create_scorumpower(const account_object &to_account, const asset &scorum)=0
virtual void check_account_existence(const account_name_type &, const optional< const char * > &context_type_name=optional< const char * >()) const =0
virtual const object_type & get() const =0
virtual const object_type & create(const modifier_type &modifier)=0
virtual fc::time_point_sec head_block_time() const =0
virtual bool has_hardfork(uint32_t hardfork) const =0
virtual const registration_committee_member_object & get_member(const account_name_type &) const =0
virtual void update_member_info(const registration_committee_member_object &, const member_info_modifier_type &modifier)=0
virtual void decrease_balance(const asset &amount)=0
Creates new account by registration committee.
share_type amount
Definition: asset.hpp:31
account_authority_map account_auths
Definition: authority.hpp:55