BitShares-Core  5.0.0
BitShares blockchain implementation and command-line interface software
account_object.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  */
26 
27 #include <fc/io/raw.hpp>
28 #include <fc/uint128.hpp>
29 
30 namespace graphene { namespace chain {
31 
33 {
34  if( a == 0 || p == 0 )
35  return 0;
36  if( p == GRAPHENE_100_PERCENT )
37  return a;
38 
39  fc::uint128_t r = a.value;
40  r *= p;
42  return static_cast<uint64_t>(r);
43 }
44 
46 {
47  assert(delta.asset_id == asset_type);
48  balance += delta.amount;
49  if( asset_type == asset_id_type() ) // CORE asset
50  maintenance_flag = true;
51 }
52 
54 {
55  if( pending_fees > 0 || pending_vested_fees > 0 )
56  {
57  auto pay_out_fees = [&](const account_object& account, share_type core_fee_total, bool require_vesting)
58  {
59  // Check the referrer -- if he's no longer a member, pay to the lifetime referrer instead.
60  // No need to check the registrar; registrars are required to be lifetime members.
61  if( account.referrer(d).is_basic_account(d.head_block_time()) )
62  d.modify( account, [](account_object& acc) {
63  acc.referrer = acc.lifetime_referrer;
64  });
65 
66  share_type network_cut = cut_fee(core_fee_total, account.network_fee_percentage);
67  assert( network_cut <= core_fee_total );
68 
69  share_type lifetime_cut = cut_fee(core_fee_total, account.lifetime_referrer_fee_percentage);
70  share_type referral = core_fee_total - network_cut - lifetime_cut;
71 
72  d.modify( d.get_core_dynamic_data(), [network_cut](asset_dynamic_data_object& addo) {
73  addo.accumulated_fees += network_cut;
74  });
75 
76  // Potential optimization: Skip some of this math and object lookups by special casing on the account type.
77  // For example, if the account is a lifetime member, we can skip all this and just deposit the referral to
78  // it directly.
79  share_type referrer_cut = cut_fee(referral, account.referrer_rewards_percentage);
80  share_type registrar_cut = referral - referrer_cut;
81 
82  d.deposit_cashback(d.get(account.lifetime_referrer), lifetime_cut, require_vesting);
83  d.deposit_cashback(d.get(account.referrer), referrer_cut, require_vesting);
84  d.deposit_cashback(d.get(account.registrar), registrar_cut, require_vesting);
85 
86  assert( referrer_cut + registrar_cut + network_cut + lifetime_cut == core_fee_total );
87  };
88 
89  pay_out_fees(a, pending_fees, true);
90  pay_out_fees(a, pending_vested_fees, false);
91 
92  d.modify(*this, [&](account_statistics_object& s) {
93  s.lifetime_fees_paid += pending_fees + pending_vested_fees;
94  s.pending_fees = 0;
95  s.pending_vested_fees = 0;
96  });
97  }
98 }
99 
100 void account_statistics_object::pay_fee( share_type core_fee, share_type cashback_vesting_threshold )
101 {
102  if( core_fee > cashback_vesting_threshold )
103  pending_fees += core_fee;
104  else
105  pending_vested_fees += core_fee;
106 }
107 
109 {
110  set<account_id_type> result;
111  for( auto auth : a.owner.account_auths )
112  result.insert(auth.first);
113  for( auto auth : a.active.account_auths )
114  result.insert(auth.first);
115  return result;
116 }
117 set<public_key_type, pubkey_comparator> account_member_index::get_key_members(const account_object& a)const
118 {
119  set<public_key_type, pubkey_comparator> result;
120  for( auto auth : a.owner.key_auths )
121  result.insert(auth.first);
122  for( auto auth : a.active.key_auths )
123  result.insert(auth.first);
124  result.insert( a.options.memo_key );
125  return result;
126 }
128 {
129  set<address> result;
130  for( auto auth : a.owner.address_auths )
131  result.insert(auth.first);
132  for( auto auth : a.active.address_auths )
133  result.insert(auth.first);
134  result.insert( a.options.memo_key );
135  return result;
136 }
137 
139 {
140  assert( dynamic_cast<const account_object*>(&obj) ); // for debug only
141  const account_object& a = static_cast<const account_object&>(obj);
142 
143  auto account_members = get_account_members(a);
144  for( auto item : account_members )
145  account_to_account_memberships[item].insert(obj.id);
146 
147  auto key_members = get_key_members(a);
148  for( auto item : key_members )
149  account_to_key_memberships[item].insert(obj.id);
150 
151  auto address_members = get_address_members(a);
152  for( auto item : address_members )
153  account_to_address_memberships[item].insert(obj.id);
154 }
155 
157 {
158  assert( dynamic_cast<const account_object*>(&obj) ); // for debug only
159  const account_object& a = static_cast<const account_object&>(obj);
160 
161  auto key_members = get_key_members(a);
162  for( auto item : key_members )
163  account_to_key_memberships[item].erase( obj.id );
164 
165  auto address_members = get_address_members(a);
166  for( auto item : address_members )
167  account_to_address_memberships[item].erase( obj.id );
168 
169  auto account_members = get_account_members(a);
170  for( auto item : account_members )
171  account_to_account_memberships[item].erase( obj.id );
172 }
173 
174 void account_member_index::about_to_modify(const object& before)
175 {
176  before_key_members.clear();
177  before_account_members.clear();
178  assert( dynamic_cast<const account_object*>(&before) ); // for debug only
179  const account_object& a = static_cast<const account_object&>(before);
180  before_key_members = get_key_members(a);
181  before_address_members = get_address_members(a);
182  before_account_members = get_account_members(a);
183 }
184 
185 void account_member_index::object_modified(const object& after)
186 {
187  assert( dynamic_cast<const account_object*>(&after) ); // for debug only
188  const account_object& a = static_cast<const account_object&>(after);
189 
190  {
191  set<account_id_type> after_account_members = get_account_members(a);
192  vector<account_id_type> removed; removed.reserve(before_account_members.size());
193  std::set_difference(before_account_members.begin(), before_account_members.end(),
194  after_account_members.begin(), after_account_members.end(),
195  std::inserter(removed, removed.end()));
196 
197  for( auto itr = removed.begin(); itr != removed.end(); ++itr )
198  account_to_account_memberships[*itr].erase(after.id);
199 
200  vector<object_id_type> added; added.reserve(after_account_members.size());
201  std::set_difference(after_account_members.begin(), after_account_members.end(),
202  before_account_members.begin(), before_account_members.end(),
203  std::inserter(added, added.end()));
204 
205  for( auto itr = added.begin(); itr != added.end(); ++itr )
206  account_to_account_memberships[*itr].insert(after.id);
207  }
208 
209 
210  {
211  set<public_key_type, pubkey_comparator> after_key_members = get_key_members(a);
212 
213  vector<public_key_type> removed; removed.reserve(before_key_members.size());
214  std::set_difference(before_key_members.begin(), before_key_members.end(),
215  after_key_members.begin(), after_key_members.end(),
216  std::inserter(removed, removed.end()));
217 
218  for( auto itr = removed.begin(); itr != removed.end(); ++itr )
219  account_to_key_memberships[*itr].erase(after.id);
220 
221  vector<public_key_type> added; added.reserve(after_key_members.size());
222  std::set_difference(after_key_members.begin(), after_key_members.end(),
223  before_key_members.begin(), before_key_members.end(),
224  std::inserter(added, added.end()));
225 
226  for( auto itr = added.begin(); itr != added.end(); ++itr )
227  account_to_key_memberships[*itr].insert(after.id);
228  }
229 
230  {
231  set<address> after_address_members = get_address_members(a);
232 
233  vector<address> removed; removed.reserve(before_address_members.size());
234  std::set_difference(before_address_members.begin(), before_address_members.end(),
235  after_address_members.begin(), after_address_members.end(),
236  std::inserter(removed, removed.end()));
237 
238  for( auto itr = removed.begin(); itr != removed.end(); ++itr )
239  account_to_address_memberships[*itr].erase(after.id);
240 
241  vector<address> added; added.reserve(after_address_members.size());
242  std::set_difference(after_address_members.begin(), after_address_members.end(),
243  before_address_members.begin(), before_address_members.end(),
244  std::inserter(added, added.end()));
245 
246  for( auto itr = added.begin(); itr != added.end(); ++itr )
247  account_to_address_memberships[*itr].insert(after.id);
248  }
249 
250 }
251 
252 const uint8_t balances_by_account_index::bits = 20;
253 const uint64_t balances_by_account_index::mask = (1ULL << balances_by_account_index::bits) - 1;
254 
256 {
257  const auto& abo = dynamic_cast< const account_balance_object& >( obj );
258  while( balances.size() < (abo.owner.instance.value >> bits) + 1 )
259  {
260  balances.reserve( (abo.owner.instance.value >> bits) + 1 );
261  balances.resize( balances.size() + 1 );
262  balances.back().resize( 1ULL << bits );
263  }
264  balances[abo.owner.instance.value >> bits][abo.owner.instance.value & mask][abo.asset_type] = &abo;
265 }
266 
268 {
269  const auto& abo = dynamic_cast< const account_balance_object& >( obj );
270  if( balances.size() < (abo.owner.instance.value >> bits) + 1 ) return;
271  balances[abo.owner.instance.value >> bits][abo.owner.instance.value & mask].erase( abo.asset_type );
272 }
273 
274 void balances_by_account_index::about_to_modify( const object& before )
275 {
276  ids_being_modified.emplace( before.id );
277 }
278 
280 {
281  FC_ASSERT( ids_being_modified.top() == after.id, "Modification of ID is not supported!");
282  ids_being_modified.pop();
283 }
284 
285 const map< asset_id_type, const account_balance_object* >& balances_by_account_index::get_account_balances( const account_id_type& acct )const
286 {
287  static const map< asset_id_type, const account_balance_object* > _empty;
288 
289  if( balances.size() < (acct.instance.value >> bits) + 1 ) return _empty;
290  return balances[acct.instance.value >> bits][acct.instance.value & mask];
291 }
292 
293 const account_balance_object* balances_by_account_index::get_account_balance( const account_id_type& acct, const asset_id_type& asset )const
294 {
295  if( balances.size() < (acct.instance.value >> bits) + 1 ) return nullptr;
296  const auto& mine = balances[acct.instance.value >> bits][acct.instance.value & mask];
297  const auto itr = mine.find( asset );
298  if( mine.end() == itr ) return nullptr;
299  return itr->second;
300 }
301 
302 } } // graphene::chain
303 
306  (membership_expiration_date)(registrar)(referrer)(lifetime_referrer)
307  (network_fee_percentage)(lifetime_referrer_fee_percentage)(referrer_rewards_percentage)
308  (name)(owner)(active)(options)(num_committee_voted)(statistics)
309  (whitelisting_accounts)(blacklisting_accounts)
310  (whitelisted_accounts)(blacklisted_accounts)
311  (cashback_vb)
312  (owner_special_authority)(active_special_authority)
313  (top_n_control_flags)
314  (allowed_assets)
315  )
316 
320 
323  (owner)(name)
324  (most_recent_op)
325  (total_ops)(removed_ops)
326  (total_core_in_orders)
327  (total_core_inactive)(total_core_pob)(total_core_pol)
328  (total_pob_value)(total_pol_value)
329  (core_in_balance)
330  (has_cashback_vb)
331  (is_voting)
332  (last_vote_time)
333  (vp_all)(vp_active)(vp_committee)(vp_witness)(vp_worker)
334  (vote_tally_time)
335  (lifetime_fees_paid)
336  (pending_fees)(pending_vested_fees)
337  )
338 
Tracks the balance of a single account/asset pairThis object is indexed on owner and asset_type so th...
const account_balance_object * get_account_balance(const account_id_type &acct, const asset_id_type &asset) const
void modify(const T &obj, const Lambda &m)
virtual void about_to_modify(const object &before) override
const map< asset_id_type, const account_balance_object * > & get_account_balances(const account_id_type &acct) const
This class represents an account on the object graphAccounts are the primary unit of authority on the...
tracks the blockchain state in an extensible manner
Definition: database.hpp:70
Definition: api.cpp:56
virtual void object_modified(const object &after) override
flat_map< address, weight_type > address_auths
Definition: authority.hpp:123
#define FC_REFLECT_DERIVED_NO_TYPENAME(TYPE, INHERITS, MEMBERS)
Definition: reflect.hpp:356
uint16_t network_fee_percentage
Percentage of fee which should go to network.
bool maintenance_flag
Whether need to process this balance object in maintenance interval.
const T & get(object_id_type id) const
flat_map< public_key_type, weight_type > key_auths
Definition: authority.hpp:121
virtual void object_removed(const object &obj) override
virtual void object_inserted(const object &obj) override
set< address > get_address_members(const account_object &a) const
object_id_type id
Definition: object.hpp:69
uint16_t lifetime_referrer_fee_percentage
Percentage of fee which should go to lifetime referrer.
#define GRAPHENE_100_PERCENT
Definition: config.hpp:102
virtual void object_modified(const object &after) override
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
account_id_type lifetime_referrer
The lifetime member at the top of the referral tree. Receives a percentage of referral rewards...
share_type cut_fee(share_type a, uint16_t p)
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
virtual void about_to_modify(const object &before) override
tracks the asset information that changes frequentlyBecause the asset_object is very large it doesn&#39;t...
#define GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION(type)
Definition: types.hpp:74
void pay_fee(share_type core_fee, share_type cashback_vesting_threshold)
virtual void object_inserted(const object &obj) override
set< public_key_type, pubkey_comparator > get_key_members(const account_object &a) const
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
set< account_id_type > get_account_members(const account_object &a) const
asset_id_type asset_id
Definition: asset.hpp:39
void process_fees(const account_object &a, database &d) const
Split up and pay out pending_fees and pending_vested_fees.
virtual void object_removed(const object &obj) override
void deposit_cashback(const account_object &acct, share_type amount, bool require_vesting=true)
Definition: db_balance.cpp:206
account_id_type registrar
The account that paid the fee to register this account. Receives a percentage of referral rewards...
base for all database objects
Definition: object.hpp:62
account_id_type referrer
The account credited as referring this account. Receives a percentage of referral rewards...
T value
Definition: safe.hpp:22
void adjust_balance(const asset &delta)