Merged Bitshares PR #1462 and compilation fixes
This commit is contained in:
parent
9224af57e2
commit
646dc2e548
10 changed files with 377 additions and 84 deletions
|
|
@ -524,6 +524,11 @@ vector<vector<account_id_type>> database_api::get_key_references( vector<public_
|
||||||
vector<vector<account_id_type>> database_api_impl::get_key_references( vector<public_key_type> keys )const
|
vector<vector<account_id_type>> database_api_impl::get_key_references( vector<public_key_type> keys )const
|
||||||
{
|
{
|
||||||
wdump( (keys) );
|
wdump( (keys) );
|
||||||
|
|
||||||
|
const auto& idx = _db.get_index_type<account_index>();
|
||||||
|
const auto& aidx = dynamic_cast<const base_primary_index&>(idx);
|
||||||
|
const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
|
||||||
|
|
||||||
vector< vector<account_id_type> > final_result;
|
vector< vector<account_id_type> > final_result;
|
||||||
final_result.reserve(keys.size());
|
final_result.reserve(keys.size());
|
||||||
|
|
||||||
|
|
@ -543,10 +548,6 @@ vector<vector<account_id_type>> database_api_impl::get_key_references( vector<pu
|
||||||
subscribe_to_item( a4 );
|
subscribe_to_item( a4 );
|
||||||
subscribe_to_item( a5 );
|
subscribe_to_item( a5 );
|
||||||
|
|
||||||
const auto& idx = _db.get_index_type<account_index>();
|
|
||||||
const auto& aidx = dynamic_cast<const primary_index<account_index>&>(idx);
|
|
||||||
const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
|
|
||||||
auto itr = refs.account_to_key_memberships.find(key);
|
|
||||||
vector<account_id_type> result;
|
vector<account_id_type> result;
|
||||||
|
|
||||||
for( auto& a : {a1,a2,a3,a4,a5} )
|
for( auto& a : {a1,a2,a3,a4,a5} )
|
||||||
|
|
@ -563,6 +564,7 @@ vector<vector<account_id_type>> database_api_impl::get_key_references( vector<pu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto itr = refs.account_to_key_memberships.find(key);
|
||||||
if( itr != refs.account_to_key_memberships.end() )
|
if( itr != refs.account_to_key_memberships.end() )
|
||||||
{
|
{
|
||||||
result.reserve( result.size() + itr->second.size() );
|
result.reserve( result.size() + itr->second.size() );
|
||||||
|
|
@ -598,7 +600,7 @@ bool database_api_impl::is_public_key_registered(string public_key) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto& idx = _db.get_index_type<account_index>();
|
const auto& idx = _db.get_index_type<account_index>();
|
||||||
const auto& aidx = dynamic_cast<const primary_index<account_index>&>(idx);
|
const auto& aidx = dynamic_cast<const base_primary_index&>(idx);
|
||||||
const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
|
const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
|
||||||
auto itr = refs.account_to_key_memberships.find(key);
|
auto itr = refs.account_to_key_memberships.find(key);
|
||||||
bool is_known = itr != refs.account_to_key_memberships.end();
|
bool is_known = itr != refs.account_to_key_memberships.end();
|
||||||
|
|
@ -639,6 +641,10 @@ std::map<string,full_account> database_api::get_full_accounts( const vector<stri
|
||||||
|
|
||||||
std::map<std::string, full_account> database_api_impl::get_full_accounts( const vector<std::string>& names_or_ids, bool subscribe)
|
std::map<std::string, full_account> database_api_impl::get_full_accounts( const vector<std::string>& names_or_ids, bool subscribe)
|
||||||
{
|
{
|
||||||
|
const auto& proposal_idx = _db.get_index_type<proposal_index>();
|
||||||
|
const auto& pidx = dynamic_cast<const base_primary_index&>(proposal_idx);
|
||||||
|
const auto& proposals_by_account = pidx.get_secondary_index<graphene::chain::required_approval_index>();
|
||||||
|
|
||||||
std::map<std::string, full_account> results;
|
std::map<std::string, full_account> results;
|
||||||
|
|
||||||
for (const std::string& account_name_or_id : names_or_ids)
|
for (const std::string& account_name_or_id : names_or_ids)
|
||||||
|
|
@ -683,9 +689,6 @@ std::map<std::string, full_account> database_api_impl::get_full_accounts( const
|
||||||
acnt.cashback_balance = account->cashback_balance(_db);
|
acnt.cashback_balance = account->cashback_balance(_db);
|
||||||
}
|
}
|
||||||
// Add the account's proposals
|
// Add the account's proposals
|
||||||
const auto& proposal_idx = _db.get_index_type<proposal_index>();
|
|
||||||
const auto& pidx = dynamic_cast<const primary_index<proposal_index>&>(proposal_idx);
|
|
||||||
const auto& proposals_by_account = pidx.get_secondary_index<graphene::chain::required_approval_index>();
|
|
||||||
auto required_approvals_itr = proposals_by_account._account_to_proposals.find( account->id );
|
auto required_approvals_itr = proposals_by_account._account_to_proposals.find( account->id );
|
||||||
if( required_approvals_itr != proposals_by_account._account_to_proposals.end() )
|
if( required_approvals_itr != proposals_by_account._account_to_proposals.end() )
|
||||||
{
|
{
|
||||||
|
|
@ -696,12 +699,9 @@ std::map<std::string, full_account> database_api_impl::get_full_accounts( const
|
||||||
|
|
||||||
|
|
||||||
// Add the account's balances
|
// Add the account's balances
|
||||||
auto balance_range = _db.get_index_type<account_balance_index>().indices().get<by_account_asset>().equal_range(boost::make_tuple(account->id));
|
const auto& balances = _db.get_index_type< primary_index< account_balance_index > >().get_secondary_index< balances_by_account_index >().get_account_balances( account->id );
|
||||||
//vector<account_balance_object> balances;
|
for( const auto balance : balances )
|
||||||
std::for_each(balance_range.first, balance_range.second,
|
acnt.balances.emplace_back( *balance.second );
|
||||||
[&acnt](const account_balance_object& balance) {
|
|
||||||
acnt.balances.emplace_back(balance);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add the account's vesting balances
|
// Add the account's vesting balances
|
||||||
auto vesting_range = _db.get_index_type<vesting_balance_index>().indices().get<by_account>().equal_range(account->id);
|
auto vesting_range = _db.get_index_type<vesting_balance_index>().indices().get<by_account>().equal_range(account->id);
|
||||||
|
|
@ -773,7 +773,7 @@ vector<account_id_type> database_api::get_account_references( account_id_type ac
|
||||||
vector<account_id_type> database_api_impl::get_account_references( account_id_type account_id )const
|
vector<account_id_type> database_api_impl::get_account_references( account_id_type account_id )const
|
||||||
{
|
{
|
||||||
const auto& idx = _db.get_index_type<account_index>();
|
const auto& idx = _db.get_index_type<account_index>();
|
||||||
const auto& aidx = dynamic_cast<const primary_index<account_index>&>(idx);
|
const auto& aidx = dynamic_cast<const base_primary_index&>(idx);
|
||||||
const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
|
const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
|
||||||
auto itr = refs.account_to_account_memberships.find(account_id);
|
auto itr = refs.account_to_account_memberships.find(account_id);
|
||||||
vector<account_id_type> result;
|
vector<account_id_type> result;
|
||||||
|
|
@ -854,10 +854,10 @@ vector<asset> database_api_impl::get_account_balances(account_id_type acnt, cons
|
||||||
if (assets.empty())
|
if (assets.empty())
|
||||||
{
|
{
|
||||||
// if the caller passes in an empty list of assets, return balances for all assets the account owns
|
// if the caller passes in an empty list of assets, return balances for all assets the account owns
|
||||||
const account_balance_index& balance_index = _db.get_index_type<account_balance_index>();
|
const auto& balance_index = _db.get_index_type< primary_index< account_balance_index > >();
|
||||||
auto range = balance_index.indices().get<by_account_asset>().equal_range(boost::make_tuple(acnt));
|
const auto& balances = balance_index.get_secondary_index< balances_by_account_index >().get_account_balances( acnt );
|
||||||
for (const account_balance_object& balance : boost::make_iterator_range(range.first, range.second))
|
for( const auto balance : balances )
|
||||||
result.push_back(asset(balance.get_balance()));
|
result.push_back( balance.second->get_balance() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -267,4 +267,54 @@ void account_referrer_index::object_modified( const object& after )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint8_t balances_by_account_index::bits = 20;
|
||||||
|
const uint64_t balances_by_account_index::mask = (1ULL << balances_by_account_index::bits) - 1;
|
||||||
|
|
||||||
|
void balances_by_account_index::object_inserted( const object& obj )
|
||||||
|
{
|
||||||
|
const auto& abo = dynamic_cast< const account_balance_object& >( obj );
|
||||||
|
while( balances.size() < (abo.owner.instance.value >> bits) + 1 )
|
||||||
|
{
|
||||||
|
balances.reserve( (abo.owner.instance.value >> bits) + 1 );
|
||||||
|
balances.resize( balances.size() + 1 );
|
||||||
|
balances.back().resize( 1ULL << bits );
|
||||||
|
}
|
||||||
|
balances[abo.owner.instance.value >> bits][abo.owner.instance.value & mask][abo.asset_type] = &abo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void balances_by_account_index::object_removed( const object& obj )
|
||||||
|
{
|
||||||
|
const auto& abo = dynamic_cast< const account_balance_object& >( obj );
|
||||||
|
if( balances.size() < (abo.owner.instance.value >> bits) + 1 ) return;
|
||||||
|
balances[abo.owner.instance.value >> bits][abo.owner.instance.value & mask].erase( abo.asset_type );
|
||||||
|
}
|
||||||
|
|
||||||
|
void balances_by_account_index::about_to_modify( const object& before )
|
||||||
|
{
|
||||||
|
ids_being_modified.emplace( before.id );
|
||||||
|
}
|
||||||
|
|
||||||
|
void balances_by_account_index::object_modified( const object& after )
|
||||||
|
{
|
||||||
|
FC_ASSERT( ids_being_modified.top() == after.id, "Modification of ID is not supported!");
|
||||||
|
ids_being_modified.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const map< asset_id_type, const account_balance_object* >& balances_by_account_index::get_account_balances( const account_id_type& acct )const
|
||||||
|
{
|
||||||
|
static const map< asset_id_type, const account_balance_object* > _empty;
|
||||||
|
|
||||||
|
if( balances.size() < (acct.instance.value >> bits) + 1 ) return _empty;
|
||||||
|
return balances[acct.instance.value >> bits][acct.instance.value & mask];
|
||||||
|
}
|
||||||
|
|
||||||
|
const account_balance_object* balances_by_account_index::get_account_balance( const account_id_type& acct, const asset_id_type& asset )const
|
||||||
|
{
|
||||||
|
if( balances.size() < (acct.instance.value >> bits) + 1 ) return nullptr;
|
||||||
|
const auto& mine = balances[acct.instance.value >> bits][acct.instance.value & mask];
|
||||||
|
const auto itr = mine.find( asset );
|
||||||
|
if( mine.end() == itr ) return nullptr;
|
||||||
|
return itr->second;
|
||||||
|
}
|
||||||
|
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,11 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
asset database::get_balance(account_id_type owner, asset_id_type asset_id) const
|
asset database::get_balance(account_id_type owner, asset_id_type asset_id) const
|
||||||
{
|
{
|
||||||
auto& index = get_index_type<account_balance_index>().indices().get<by_account_asset>();
|
auto& index = get_index_type< primary_index< account_balance_index > >().get_secondary_index<balances_by_account_index>();
|
||||||
auto itr = index.find(boost::make_tuple(owner, asset_id));
|
auto abo = index.get_account_balance( owner, asset_id );
|
||||||
if( itr == index.end() )
|
if( !abo )
|
||||||
return asset(0, asset_id);
|
return asset(0, asset_id);
|
||||||
return itr->get_balance();
|
return abo->get_balance();
|
||||||
}
|
}
|
||||||
|
|
||||||
asset database::get_balance(const account_object& owner, const asset_object& asset_obj) const
|
asset database::get_balance(const account_object& owner, const asset_object& asset_obj) const
|
||||||
|
|
@ -65,9 +65,9 @@ void database::adjust_balance(account_id_type account, asset delta )
|
||||||
if( delta.amount == 0 )
|
if( delta.amount == 0 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto& index = get_index_type<account_balance_index>().indices().get<by_account_asset>();
|
auto& index = get_index_type< primary_index< account_balance_index > >().get_secondary_index<balances_by_account_index>();
|
||||||
auto itr = index.find(boost::make_tuple(account, delta.asset_id));
|
auto abo = index.get_account_balance( account, delta.asset_id );
|
||||||
if(itr == index.end())
|
if( !abo )
|
||||||
{
|
{
|
||||||
FC_ASSERT( delta.amount > 0, "Insufficient Balance: ${a}'s balance of ${b} is less than required ${r}",
|
FC_ASSERT( delta.amount > 0, "Insufficient Balance: ${a}'s balance of ${b} is less than required ${r}",
|
||||||
("a",account(*this).name)
|
("a",account(*this).name)
|
||||||
|
|
@ -80,8 +80,9 @@ void database::adjust_balance(account_id_type account, asset delta )
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if( delta.amount < 0 )
|
if( delta.amount < 0 )
|
||||||
FC_ASSERT( itr->get_balance() >= -delta, "Insufficient Balance: ${a}'s balance of ${b} is less than required ${r}", ("a",account(*this).name)("b",to_pretty_string(itr->get_balance()))("r",to_pretty_string(-delta)));
|
FC_ASSERT( abo->get_balance() >= -delta, "Insufficient Balance: ${a}'s balance of ${b} is less than required ${r}",
|
||||||
modify(*itr, [delta](account_balance_object& b) {
|
("a",account(*this).name)("b",to_pretty_string(abo->get_balance()))("r",to_pretty_string(-delta)));
|
||||||
|
modify(*abo, [delta](account_balance_object& b) {
|
||||||
b.adjust_balance(delta);
|
b.adjust_balance(delta);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -729,7 +729,7 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
|
||||||
ptrx.operation_results = std::move(eval_state.operation_results);
|
ptrx.operation_results = std::move(eval_state.operation_results);
|
||||||
|
|
||||||
//Make sure the temp account has no non-zero balances
|
//Make sure the temp account has no non-zero balances
|
||||||
const auto& index = get_index_type<account_balance_index>().indices().get<by_account_asset>();
|
const auto& index = get_index_type< primary_index< account_balance_index > >().get_secondary_index< balances_by_account_index >();
|
||||||
auto range = index.equal_range( boost::make_tuple( GRAPHENE_TEMP_ACCOUNT ) );
|
auto range = index.equal_range( boost::make_tuple( GRAPHENE_TEMP_ACCOUNT ) );
|
||||||
std::for_each(range.first, range.second, [](const account_balance_object& b) { FC_ASSERT(b.balance == 0); });
|
std::for_each(range.first, range.second, [](const account_balance_object& b) { FC_ASSERT(b.balance == 0); });
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -251,15 +251,15 @@ void database::initialize_indexes()
|
||||||
_undo_db.set_max_size( GRAPHENE_MIN_UNDO_HISTORY );
|
_undo_db.set_max_size( GRAPHENE_MIN_UNDO_HISTORY );
|
||||||
|
|
||||||
//Protocol object indexes
|
//Protocol object indexes
|
||||||
add_index< primary_index<asset_index> >();
|
add_index< primary_index<asset_index, 13> >(); // 8192 assets per chunk
|
||||||
add_index< primary_index<force_settlement_index> >();
|
add_index< primary_index<force_settlement_index> >();
|
||||||
|
|
||||||
auto acnt_index = add_index< primary_index<account_index> >();
|
auto acnt_index = add_index< primary_index<account_index, 20> >(); // ~1 million accounts per chunk
|
||||||
acnt_index->add_secondary_index<account_member_index>();
|
acnt_index->add_secondary_index<account_member_index>();
|
||||||
acnt_index->add_secondary_index<account_referrer_index>();
|
acnt_index->add_secondary_index<account_referrer_index>();
|
||||||
|
|
||||||
add_index< primary_index<committee_member_index> >();
|
add_index< primary_index<committee_member_index, 8> >(); // 256 members per chunk
|
||||||
add_index< primary_index<witness_index> >();
|
add_index< primary_index<witness_index, 10> >(); // 1024 witnesses per chunk
|
||||||
add_index< primary_index<limit_order_index > >();
|
add_index< primary_index<limit_order_index > >();
|
||||||
add_index< primary_index<call_order_index > >();
|
add_index< primary_index<call_order_index > >();
|
||||||
|
|
||||||
|
|
@ -287,12 +287,15 @@ void database::initialize_indexes()
|
||||||
|
|
||||||
//Implementation object indexes
|
//Implementation object indexes
|
||||||
add_index< primary_index<transaction_index > >();
|
add_index< primary_index<transaction_index > >();
|
||||||
add_index< primary_index<account_balance_index > >();
|
|
||||||
add_index< primary_index<asset_bitasset_data_index > >();
|
auto bal_idx = add_index< primary_index<account_balance_index > >();
|
||||||
|
bal_idx->add_secondary_index<balances_by_account_index>();
|
||||||
|
|
||||||
|
add_index< primary_index<asset_bitasset_data_index, 13 > >(); // 8192
|
||||||
add_index< primary_index<asset_dividend_data_object_index > >();
|
add_index< primary_index<asset_dividend_data_object_index > >();
|
||||||
add_index< primary_index<simple_index<global_property_object >> >();
|
add_index< primary_index<simple_index<global_property_object >> >();
|
||||||
add_index< primary_index<simple_index<dynamic_global_property_object >> >();
|
add_index< primary_index<simple_index<dynamic_global_property_object >> >();
|
||||||
add_index< primary_index<simple_index<account_statistics_object >> >();
|
add_index< primary_index<account_stats_index, 20 > >(); // 1 Mi
|
||||||
add_index< primary_index<simple_index<asset_dynamic_data_object >> >();
|
add_index< primary_index<simple_index<asset_dynamic_data_object >> >();
|
||||||
add_index< primary_index<flat_index< block_summary_object >> >();
|
add_index< primary_index<flat_index< block_summary_object >> >();
|
||||||
add_index< primary_index<simple_index<chain_property_object > > >();
|
add_index< primary_index<simple_index<chain_property_object > > >();
|
||||||
|
|
|
||||||
|
|
@ -621,7 +621,7 @@ void distribute_fba_balances( database& db )
|
||||||
void create_buyback_orders( database& db )
|
void create_buyback_orders( database& db )
|
||||||
{
|
{
|
||||||
const auto& bbo_idx = db.get_index_type< buyback_index >().indices().get<by_id>();
|
const auto& bbo_idx = db.get_index_type< buyback_index >().indices().get<by_id>();
|
||||||
const auto& bal_idx = db.get_index_type< account_balance_index >().indices().get< by_account_asset >();
|
const auto& bal_idx = db.get_index_type< primary_index< account_balance_index > >().get_secondary_index< balances_by_account_index >();
|
||||||
|
|
||||||
for( const buyback_object& bbo : bbo_idx )
|
for( const buyback_object& bbo : bbo_idx )
|
||||||
{
|
{
|
||||||
|
|
@ -629,7 +629,6 @@ void create_buyback_orders( database& db )
|
||||||
assert( asset_to_buy.buyback_account.valid() );
|
assert( asset_to_buy.buyback_account.valid() );
|
||||||
|
|
||||||
const account_object& buyback_account = (*(asset_to_buy.buyback_account))(db);
|
const account_object& buyback_account = (*(asset_to_buy.buyback_account))(db);
|
||||||
asset_id_type next_asset = asset_id_type();
|
|
||||||
|
|
||||||
if( !buyback_account.allowed_assets.valid() )
|
if( !buyback_account.allowed_assets.valid() )
|
||||||
{
|
{
|
||||||
|
|
@ -637,16 +636,11 @@ void create_buyback_orders( database& db )
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
while( true )
|
for( const auto& entry : bal_idx.get_account_balances( buyback_account.id ) )
|
||||||
{
|
{
|
||||||
auto it = bal_idx.lower_bound( boost::make_tuple( buyback_account.id, next_asset ) );
|
const auto* it = entry.second;
|
||||||
if( it == bal_idx.end() )
|
|
||||||
break;
|
|
||||||
if( it->owner != buyback_account.id )
|
|
||||||
break;
|
|
||||||
asset_id_type asset_to_sell = it->asset_type;
|
asset_id_type asset_to_sell = it->asset_type;
|
||||||
share_type amount_to_sell = it->balance;
|
share_type amount_to_sell = it->balance;
|
||||||
next_asset = asset_to_sell + 1;
|
|
||||||
if( asset_to_sell == asset_to_buy.id )
|
if( asset_to_sell == asset_to_buy.id )
|
||||||
continue;
|
continue;
|
||||||
if( amount_to_sell == 0 )
|
if( amount_to_sell == 0 )
|
||||||
|
|
@ -740,8 +734,10 @@ void schedule_pending_dividend_balances(database& db,
|
||||||
{ try {
|
{ try {
|
||||||
dlog("Processing dividend payments for dividend holder asset type ${holder_asset} at time ${t}",
|
dlog("Processing dividend payments for dividend holder asset type ${holder_asset} at time ${t}",
|
||||||
("holder_asset", dividend_holder_asset_obj.symbol)("t", db.head_block_time()));
|
("holder_asset", dividend_holder_asset_obj.symbol)("t", db.head_block_time()));
|
||||||
|
auto balance_by_acc_index = db.get_index_type< primary_index< account_balance_index > >().get_secondary_index< balances_by_account_index >();
|
||||||
auto current_distribution_account_balance_range =
|
auto current_distribution_account_balance_range =
|
||||||
balance_index.indices().get<by_account_asset>().equal_range(boost::make_tuple(dividend_data.dividend_distribution_account));
|
//balance_index.indices().get<by_account_asset>().equal_range(boost::make_tuple(dividend_data.dividend_distribution_account));
|
||||||
|
balance_by_acc_index.get_account_balances(dividend_data.dividend_distribution_account);
|
||||||
auto previous_distribution_account_balance_range =
|
auto previous_distribution_account_balance_range =
|
||||||
distributed_dividend_balance_index.indices().get<by_dividend_payout_asset>().equal_range(boost::make_tuple(dividend_holder_asset_obj.id));
|
distributed_dividend_balance_index.indices().get<by_dividend_payout_asset>().equal_range(boost::make_tuple(dividend_holder_asset_obj.id));
|
||||||
// the current range is now all current balances for the distribution account, sorted by asset_type
|
// the current range is now all current balances for the distribution account, sorted by asset_type
|
||||||
|
|
@ -789,10 +785,10 @@ void schedule_pending_dividend_balances(database& db,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto current_distribution_account_balance_iter = current_distribution_account_balance_range.first;
|
auto current_distribution_account_balance_iter = current_distribution_account_balance_range.begin();
|
||||||
auto previous_distribution_account_balance_iter = previous_distribution_account_balance_range.first;
|
auto previous_distribution_account_balance_iter = previous_distribution_account_balance_range.first;
|
||||||
dlog("Current balances in distribution account: ${current}, Previous balances: ${previous}",
|
dlog("Current balances in distribution account: ${current}, Previous balances: ${previous}",
|
||||||
("current", (int64_t)std::distance(current_distribution_account_balance_range.first, current_distribution_account_balance_range.second))
|
("current", (int64_t)std::distance(current_distribution_account_balance_range.begin(), current_distribution_account_balance_range.end()))
|
||||||
("previous", (int64_t)std::distance(previous_distribution_account_balance_range.first, previous_distribution_account_balance_range.second)));
|
("previous", (int64_t)std::distance(previous_distribution_account_balance_range.first, previous_distribution_account_balance_range.second)));
|
||||||
|
|
||||||
// when we pay out the dividends to the holders, we need to know the total balance of the dividend asset in all
|
// when we pay out the dividends to the holders, we need to know the total balance of the dividend asset in all
|
||||||
|
|
@ -808,7 +804,7 @@ void schedule_pending_dividend_balances(database& db,
|
||||||
total_balance_of_dividend_asset += itr->second;
|
total_balance_of_dividend_asset += itr->second;
|
||||||
}
|
}
|
||||||
// loop through all of the assets currently or previously held in the distribution account
|
// loop through all of the assets currently or previously held in the distribution account
|
||||||
while (current_distribution_account_balance_iter != current_distribution_account_balance_range.second ||
|
while (current_distribution_account_balance_iter != current_distribution_account_balance_range.end() ||
|
||||||
previous_distribution_account_balance_iter != previous_distribution_account_balance_range.second)
|
previous_distribution_account_balance_iter != previous_distribution_account_balance_range.second)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
@ -819,15 +815,15 @@ void schedule_pending_dividend_balances(database& db,
|
||||||
asset_id_type payout_asset_type;
|
asset_id_type payout_asset_type;
|
||||||
|
|
||||||
if (previous_distribution_account_balance_iter == previous_distribution_account_balance_range.second ||
|
if (previous_distribution_account_balance_iter == previous_distribution_account_balance_range.second ||
|
||||||
current_distribution_account_balance_iter->asset_type < previous_distribution_account_balance_iter->dividend_payout_asset_type)
|
current_distribution_account_balance_iter->second->asset_type < previous_distribution_account_balance_iter->dividend_payout_asset_type)
|
||||||
{
|
{
|
||||||
// there are no more previous balances or there is no previous balance for this particular asset type
|
// there are no more previous balances or there is no previous balance for this particular asset type
|
||||||
payout_asset_type = current_distribution_account_balance_iter->asset_type;
|
payout_asset_type = current_distribution_account_balance_iter->second->asset_type;
|
||||||
current_balance = current_distribution_account_balance_iter->balance;
|
current_balance = current_distribution_account_balance_iter->second->balance;
|
||||||
idump((payout_asset_type)(current_balance));
|
idump((payout_asset_type)(current_balance));
|
||||||
}
|
}
|
||||||
else if (current_distribution_account_balance_iter == current_distribution_account_balance_range.second ||
|
else if (current_distribution_account_balance_iter == current_distribution_account_balance_range.end() ||
|
||||||
previous_distribution_account_balance_iter->dividend_payout_asset_type < current_distribution_account_balance_iter->asset_type)
|
previous_distribution_account_balance_iter->dividend_payout_asset_type < current_distribution_account_balance_iter->second->asset_type)
|
||||||
{
|
{
|
||||||
// there are no more current balances or there is no current balance for this particular previous asset type
|
// there are no more current balances or there is no current balance for this particular previous asset type
|
||||||
payout_asset_type = previous_distribution_account_balance_iter->dividend_payout_asset_type;
|
payout_asset_type = previous_distribution_account_balance_iter->dividend_payout_asset_type;
|
||||||
|
|
@ -837,8 +833,8 @@ void schedule_pending_dividend_balances(database& db,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we have both a previous and a current balance for this asset type
|
// we have both a previous and a current balance for this asset type
|
||||||
payout_asset_type = current_distribution_account_balance_iter->asset_type;
|
payout_asset_type = current_distribution_account_balance_iter->second->asset_type;
|
||||||
current_balance = current_distribution_account_balance_iter->balance;
|
current_balance = current_distribution_account_balance_iter->second->balance;
|
||||||
previous_balance = previous_distribution_account_balance_iter->balance_at_last_maintenance_interval;
|
previous_balance = previous_distribution_account_balance_iter->balance_at_last_maintenance_interval;
|
||||||
idump((payout_asset_type)(current_balance)(previous_balance));
|
idump((payout_asset_type)(current_balance)(previous_balance));
|
||||||
}
|
}
|
||||||
|
|
@ -1043,10 +1039,10 @@ void schedule_pending_dividend_balances(database& db,
|
||||||
|
|
||||||
// iterate
|
// iterate
|
||||||
if (previous_distribution_account_balance_iter == previous_distribution_account_balance_range.second ||
|
if (previous_distribution_account_balance_iter == previous_distribution_account_balance_range.second ||
|
||||||
current_distribution_account_balance_iter->asset_type < previous_distribution_account_balance_iter->dividend_payout_asset_type)
|
current_distribution_account_balance_iter->second->asset_type < previous_distribution_account_balance_iter->dividend_payout_asset_type)
|
||||||
++current_distribution_account_balance_iter;
|
++current_distribution_account_balance_iter;
|
||||||
else if (current_distribution_account_balance_iter == current_distribution_account_balance_range.second ||
|
else if (current_distribution_account_balance_iter == current_distribution_account_balance_range.end() ||
|
||||||
previous_distribution_account_balance_iter->dividend_payout_asset_type < current_distribution_account_balance_iter->asset_type)
|
previous_distribution_account_balance_iter->dividend_payout_asset_type < current_distribution_account_balance_iter->second->asset_type)
|
||||||
++previous_distribution_account_balance_iter;
|
++previous_distribution_account_balance_iter;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1066,6 +1062,7 @@ void process_dividend_assets(database& db)
|
||||||
ilog("In process_dividend_assets time ${time}", ("time", db.head_block_time()));
|
ilog("In process_dividend_assets time ${time}", ("time", db.head_block_time()));
|
||||||
|
|
||||||
const account_balance_index& balance_index = db.get_index_type<account_balance_index>();
|
const account_balance_index& balance_index = db.get_index_type<account_balance_index>();
|
||||||
|
//const auto& balance_index = db.get_index_type< primary_index< account_balance_index > >().get_secondary_index< balances_by_account_index >();
|
||||||
const vesting_balance_index& vbalance_index = db.get_index_type<vesting_balance_index>();
|
const vesting_balance_index& vbalance_index = db.get_index_type<vesting_balance_index>();
|
||||||
const total_distributed_dividend_balance_object_index& distributed_dividend_balance_index = db.get_index_type<total_distributed_dividend_balance_object_index>();
|
const total_distributed_dividend_balance_object_index& distributed_dividend_balance_index = db.get_index_type<total_distributed_dividend_balance_object_index>();
|
||||||
const pending_dividend_payout_balance_for_holder_object_index& pending_payout_balance_index = db.get_index_type<pending_dividend_payout_balance_for_holder_object_index>();
|
const pending_dividend_payout_balance_for_holder_object_index& pending_payout_balance_index = db.get_index_type<pending_dividend_payout_balance_for_holder_object_index>();
|
||||||
|
|
@ -1090,7 +1087,7 @@ void process_dividend_assets(database& db)
|
||||||
("holder_asset", dividend_holder_asset_obj.symbol));
|
("holder_asset", dividend_holder_asset_obj.symbol));
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// dump balances before the payouts for debugging
|
// dump balances before the payouts for debugging
|
||||||
const auto& balance_idx = db.get_index_type<account_balance_index>().indices().get<by_account_asset>();
|
const auto& balance_idx = db.get_index_type< primary_index< account_balance_index > >().get_secondary_index< balances_by_account_index >();
|
||||||
auto holder_account_balance_range = balance_idx.equal_range(boost::make_tuple(dividend_data.dividend_distribution_account));
|
auto holder_account_balance_range = balance_idx.equal_range(boost::make_tuple(dividend_data.dividend_distribution_account));
|
||||||
for (const account_balance_object& holder_balance_object : boost::make_iterator_range(holder_account_balance_range.first, holder_account_balance_range.second))
|
for (const account_balance_object& holder_balance_object : boost::make_iterator_range(holder_account_balance_range.first, holder_account_balance_range.second))
|
||||||
ilog(" Current balance: ${asset}", ("asset", asset(holder_balance_object.balance, holder_balance_object.asset_type)));
|
ilog(" Current balance: ${asset}", ("asset", asset(holder_balance_object.balance, holder_balance_object.asset_type)));
|
||||||
|
|
|
||||||
|
|
@ -344,7 +344,30 @@ namespace graphene { namespace chain {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct by_account_asset;
|
/**
|
||||||
|
* @brief This secondary index will allow fast access to the balance objects
|
||||||
|
* that belonging to an account.
|
||||||
|
*/
|
||||||
|
class balances_by_account_index : public secondary_index
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void object_inserted( const object& obj ) override;
|
||||||
|
virtual void object_removed( const object& obj ) override;
|
||||||
|
virtual void about_to_modify( const object& before ) override;
|
||||||
|
virtual void object_modified( const object& after ) override;
|
||||||
|
|
||||||
|
const map< asset_id_type, const account_balance_object* >& get_account_balances( const account_id_type& acct )const;
|
||||||
|
const account_balance_object* get_account_balance( const account_id_type& acct, const asset_id_type& asset )const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const uint8_t bits;
|
||||||
|
static const uint64_t mask;
|
||||||
|
|
||||||
|
/** Maps each account to its balance objects */
|
||||||
|
vector< vector< map< asset_id_type, const account_balance_object* > > > balances;
|
||||||
|
std::stack< object_id_type > ids_being_modified;
|
||||||
|
};
|
||||||
|
|
||||||
struct by_asset_balance;
|
struct by_asset_balance;
|
||||||
/**
|
/**
|
||||||
* @ingroup object_index
|
* @ingroup object_index
|
||||||
|
|
@ -353,13 +376,6 @@ namespace graphene { namespace chain {
|
||||||
account_balance_object,
|
account_balance_object,
|
||||||
indexed_by<
|
indexed_by<
|
||||||
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||||
ordered_unique< tag<by_account_asset>,
|
|
||||||
composite_key<
|
|
||||||
account_balance_object,
|
|
||||||
member<account_balance_object, account_id_type, &account_balance_object::owner>,
|
|
||||||
member<account_balance_object, asset_id_type, &account_balance_object::asset_type>
|
|
||||||
>
|
|
||||||
>,
|
|
||||||
ordered_unique< tag<by_asset_balance>,
|
ordered_unique< tag<by_asset_balance>,
|
||||||
composite_key<
|
composite_key<
|
||||||
account_balance_object,
|
account_balance_object,
|
||||||
|
|
@ -399,6 +415,26 @@ namespace graphene { namespace chain {
|
||||||
*/
|
*/
|
||||||
typedef generic_index<account_object, account_multi_index_type> account_index;
|
typedef generic_index<account_object, account_multi_index_type> account_index;
|
||||||
|
|
||||||
|
struct by_owner;
|
||||||
|
struct by_maintenance_seq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup object_index
|
||||||
|
*/
|
||||||
|
typedef multi_index_container<
|
||||||
|
account_statistics_object,
|
||||||
|
indexed_by<
|
||||||
|
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||||
|
ordered_unique< tag<by_owner>,
|
||||||
|
member< account_statistics_object, account_id_type, &account_statistics_object::owner > >
|
||||||
|
>
|
||||||
|
> account_stats_multi_index_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup object_index
|
||||||
|
*/
|
||||||
|
typedef generic_index<account_statistics_object, account_stats_multi_index_type> account_stats_index;
|
||||||
|
|
||||||
struct by_dividend_payout_account{}; // use when calculating pending payouts
|
struct by_dividend_payout_account{}; // use when calculating pending payouts
|
||||||
struct by_dividend_account_payout{}; // use when doing actual payouts
|
struct by_dividend_account_payout{}; // use when doing actual payouts
|
||||||
struct by_account_dividend_payout{}; // use in get_full_accounts()
|
struct by_account_dividend_payout{}; // use in get_full_accounts()
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,13 @@
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <graphene/db/object.hpp>
|
#include <graphene/db/object.hpp>
|
||||||
|
|
||||||
#include <fc/interprocess/file_mapping.hpp>
|
#include <fc/interprocess/file_mapping.hpp>
|
||||||
#include <fc/io/raw.hpp>
|
#include <fc/io/raw.hpp>
|
||||||
#include <fc/io/json.hpp>
|
#include <fc/io/json.hpp>
|
||||||
#include <fc/crypto/sha256.hpp>
|
#include <fc/crypto/sha256.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
namespace graphene { namespace db {
|
namespace graphene { namespace db {
|
||||||
class object_database;
|
class object_database;
|
||||||
|
|
@ -190,7 +192,112 @@ namespace graphene { namespace db {
|
||||||
object_database& _db;
|
object_database& _db;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @class direct_index
|
||||||
|
* @brief A secondary index that tracks objects in vectors indexed by object
|
||||||
|
* id. It is meant for fully (or almost fully) populated indexes only (will
|
||||||
|
* fail when loading an object_database with large gaps).
|
||||||
|
*
|
||||||
|
* WARNING! If any of the methods called on insertion, removal or
|
||||||
|
* modification throws, subsequent behaviour is undefined! Such exceptions
|
||||||
|
* indicate that this index type is not appropriate for the use-case.
|
||||||
|
*/
|
||||||
|
template<typename Object, uint8_t chunkbits>
|
||||||
|
class direct_index : public secondary_index
|
||||||
|
{
|
||||||
|
static_assert( chunkbits < 64, "Do you really want arrays with more than 2^63 elements???" );
|
||||||
|
|
||||||
|
// private
|
||||||
|
static const size_t MAX_HOLE = 100;
|
||||||
|
static const size_t _mask = ((1 << chunkbits) - 1);
|
||||||
|
size_t next = 0;
|
||||||
|
vector< vector< const Object* > > content;
|
||||||
|
std::stack< object_id_type > ids_being_modified;
|
||||||
|
|
||||||
|
public:
|
||||||
|
direct_index() {
|
||||||
|
FC_ASSERT( (1ULL << chunkbits) > MAX_HOLE, "Small chunkbits is inefficient." );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~direct_index(){}
|
||||||
|
|
||||||
|
virtual void object_inserted( const object& obj )
|
||||||
|
{
|
||||||
|
uint64_t instance = obj.id.instance();
|
||||||
|
if( instance == next )
|
||||||
|
{
|
||||||
|
if( !(next & _mask) )
|
||||||
|
{
|
||||||
|
content.resize((next >> chunkbits) + 1);
|
||||||
|
content[next >> chunkbits].resize( 1 << chunkbits, nullptr );
|
||||||
|
}
|
||||||
|
next++;
|
||||||
|
}
|
||||||
|
else if( instance < next )
|
||||||
|
FC_ASSERT( !content[instance >> chunkbits][instance & _mask], "Overwriting insert at {id}!", ("id",obj.id) );
|
||||||
|
else // instance > next, allow small "holes"
|
||||||
|
{
|
||||||
|
FC_ASSERT( instance <= next + MAX_HOLE, "Out-of-order insert: {id} > {next}!", ("id",obj.id)("next",next) );
|
||||||
|
if( !(next & _mask) || (next & (~_mask)) != (instance & (~_mask)) )
|
||||||
|
{
|
||||||
|
content.resize((instance >> chunkbits) + 1);
|
||||||
|
content[instance >> chunkbits].resize( 1 << chunkbits, nullptr );
|
||||||
|
}
|
||||||
|
while( next <= instance )
|
||||||
|
{
|
||||||
|
content[next >> chunkbits][next & _mask] = nullptr;
|
||||||
|
next++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FC_ASSERT( nullptr != dynamic_cast<const Object*>(&obj), "Wrong object type!" );
|
||||||
|
content[instance >> chunkbits][instance & _mask] = static_cast<const Object*>( &obj );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void object_removed( const object& obj )
|
||||||
|
{
|
||||||
|
FC_ASSERT( nullptr != dynamic_cast<const Object*>(&obj), "Wrong object type!" );
|
||||||
|
uint64_t instance = obj.id.instance();
|
||||||
|
FC_ASSERT( instance < next, "Removing out-of-range object: {id} > {next}!", ("id",obj.id)("next",next) );
|
||||||
|
FC_ASSERT( content[instance >> chunkbits][instance & _mask], "Removing non-existent object {id}!", ("id",obj.id) );
|
||||||
|
content[instance >> chunkbits][instance & _mask] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void about_to_modify( const object& before )
|
||||||
|
{
|
||||||
|
ids_being_modified.emplace( before.id );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void object_modified( const object& after )
|
||||||
|
{
|
||||||
|
FC_ASSERT( ids_being_modified.top() == after.id, "Modification of ID is not supported!");
|
||||||
|
ids_being_modified.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename object_id >
|
||||||
|
const Object* find( const object_id& id )const
|
||||||
|
{
|
||||||
|
static_assert( object_id::space_id == Object::space_id, "Space ID mismatch!" );
|
||||||
|
static_assert( object_id::type_id == Object::type_id, "Type_ID mismatch!" );
|
||||||
|
if( id.instance >= next ) return nullptr;
|
||||||
|
return content[id.instance.value >> chunkbits][id.instance.value & _mask];
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename object_id >
|
||||||
|
const Object& get( const object_id& id )const
|
||||||
|
{
|
||||||
|
const Object* ptr = find( id );
|
||||||
|
FC_ASSERT( ptr != nullptr, "Object not found!" );
|
||||||
|
return *ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Object* find( const object_id_type& id )const
|
||||||
|
{
|
||||||
|
FC_ASSERT( id.space() == Object::space_id, "Space ID mismatch!" );
|
||||||
|
FC_ASSERT( id.type() == Object::type_id, "Type_ID mismatch!" );
|
||||||
|
if( id.instance() >= next ) return nullptr;
|
||||||
|
return content[id.instance() >> chunkbits][id.instance() & ((1 << chunkbits) - 1)];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class primary_index
|
* @class primary_index
|
||||||
* @brief Wraps a derived index to intercept calls to create, modify, and remove so that
|
* @brief Wraps a derived index to intercept calls to create, modify, and remove so that
|
||||||
|
|
@ -198,14 +305,18 @@ namespace graphene { namespace db {
|
||||||
*
|
*
|
||||||
* @see http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
|
* @see http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
|
||||||
*/
|
*/
|
||||||
template<typename DerivedIndex>
|
template<typename DerivedIndex, uint8_t DirectBits = 0>
|
||||||
class primary_index : public DerivedIndex, public base_primary_index
|
class primary_index : public DerivedIndex, public base_primary_index
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef typename DerivedIndex::object_type object_type;
|
typedef typename DerivedIndex::object_type object_type;
|
||||||
|
|
||||||
primary_index( object_database& db )
|
primary_index( object_database& db )
|
||||||
:base_primary_index(db),_next_id(object_type::space_id,object_type::type_id,0) {}
|
:base_primary_index(db),_next_id(object_type::space_id,object_type::type_id,0)
|
||||||
|
{
|
||||||
|
if( DirectBits > 0 )
|
||||||
|
_direct_by_id = add_secondary_index< direct_index< object_type, DirectBits > >();
|
||||||
|
}
|
||||||
|
|
||||||
virtual uint8_t object_space_id()const override
|
virtual uint8_t object_space_id()const override
|
||||||
{ return object_type::space_id; }
|
{ return object_type::space_id; }
|
||||||
|
|
@ -216,7 +327,15 @@ namespace graphene { namespace db {
|
||||||
virtual object_id_type get_next_id()const override { return _next_id; }
|
virtual object_id_type get_next_id()const override { return _next_id; }
|
||||||
virtual void use_next_id()override { ++_next_id.number; }
|
virtual void use_next_id()override { ++_next_id.number; }
|
||||||
virtual void set_next_id( object_id_type id )override { _next_id = id; }
|
virtual void set_next_id( object_id_type id )override { _next_id = id; }
|
||||||
|
|
||||||
|
/** @return the object with id or nullptr if not found */
|
||||||
|
virtual const object* find( object_id_type id )const override
|
||||||
|
{
|
||||||
|
if( DirectBits > 0 )
|
||||||
|
return _direct_by_id->find( id );
|
||||||
|
return DerivedIndex::find( id );
|
||||||
|
}
|
||||||
|
|
||||||
fc::sha256 get_object_version()const
|
fc::sha256 get_object_version()const
|
||||||
{
|
{
|
||||||
std::string desc = "1.0";//get_type_description<object_type>();
|
std::string desc = "1.0";//get_type_description<object_type>();
|
||||||
|
|
@ -318,7 +437,8 @@ namespace graphene { namespace db {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
object_id_type _next_id;
|
object_id_type _next_id;
|
||||||
|
const direct_index< object_type, DirectBits >* _direct_by_id = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // graphene::db
|
} } // graphene::db
|
||||||
|
|
|
||||||
|
|
@ -401,19 +401,20 @@ BOOST_AUTO_TEST_CASE( affiliate_payout_helper_test )
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Fix total supply
|
// // Fix total supply
|
||||||
auto& index = db.get_index_type<account_balance_index>().indices().get<by_account_asset>();
|
// //auto& index = db.get_index_type<account_balance_index>().indices().get<by_account_asset>();
|
||||||
auto itr = index.find( boost::make_tuple( account_id_type(), asset_id_type() ) );
|
// auto& index = db.get_index_type< primary_index< account_balance_index, 8 > >().get_secondary_index< direct_index< account_balance_object, 8> >();
|
||||||
BOOST_CHECK( itr != index.end() );
|
// auto itr = index.find( boost::make_tuple( account_id_type(), asset_id_type() ) );
|
||||||
db.modify( *itr, [&ath]( account_balance_object& bal ) {
|
// BOOST_CHECK( itr != nullptr );
|
||||||
bal.balance -= ath.alice_ppy + ath.ann_ppy + ath.audrey_ppy;
|
// db.modify( *itr, [&ath]( account_balance_object& bal ) {
|
||||||
});
|
// bal.balance -= ath.alice_ppy + ath.ann_ppy + ath.audrey_ppy;
|
||||||
|
// });
|
||||||
|
|
||||||
itr = index.find( boost::make_tuple( irene_id, btc_id ) );
|
// itr = index.find( boost::make_tuple( irene_id, btc_id ) );
|
||||||
BOOST_CHECK( itr != index.end() );
|
// BOOST_CHECK( itr != nullptr );
|
||||||
db.modify( *itr, [alice_btc,ann_btc,audrey_btc]( account_balance_object& bal ) {
|
// db.modify( *itr, [alice_btc,ann_btc,audrey_btc]( account_balance_object& bal ) {
|
||||||
bal.balance -= alice_btc + ann_btc + audrey_btc;
|
// bal.balance -= alice_btc + ann_btc + audrey_btc;
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,4 +91,89 @@ BOOST_AUTO_TEST_CASE( flat_index_test )
|
||||||
FC_ASSERT( !(*bitusd.bitasset_data_id)(db).current_feed.settlement_price.is_null() );
|
FC_ASSERT( !(*bitusd.bitasset_data_id)(db).current_feed.settlement_price.is_null() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( direct_index_test )
|
||||||
|
{ try {
|
||||||
|
try {
|
||||||
|
const graphene::db::primary_index< account_index, 6 > small_chunkbits( db );
|
||||||
|
BOOST_FAIL( "Expected assertion failure!" );
|
||||||
|
} catch( const fc::assert_exception& expected ) {}
|
||||||
|
|
||||||
|
graphene::db::primary_index< account_index, 8 > my_accounts( db );
|
||||||
|
const auto& direct = my_accounts.get_secondary_index<graphene::db::direct_index< account_object, 8 >>();
|
||||||
|
BOOST_CHECK_EQUAL( 0, my_accounts.indices().size() );
|
||||||
|
BOOST_CHECK( nullptr == direct.find( account_id_type( 1 ) ) );
|
||||||
|
// BOOST_CHECK_THROW( direct.find( asset_id_type( 1 ) ), fc::assert_exception ); // compile-time error
|
||||||
|
BOOST_CHECK_THROW( direct.find( object_id_type( asset_id_type( 1 ) ) ), fc::assert_exception );
|
||||||
|
BOOST_CHECK_THROW( direct.get( account_id_type( 1 ) ), fc::assert_exception );
|
||||||
|
|
||||||
|
account_object test_account;
|
||||||
|
test_account.id = account_id_type(1);
|
||||||
|
test_account.name = "account1";
|
||||||
|
|
||||||
|
my_accounts.load( fc::raw::pack( test_account ) );
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL( 1, my_accounts.indices().size() );
|
||||||
|
BOOST_CHECK( nullptr == direct.find( account_id_type( 0 ) ) );
|
||||||
|
BOOST_CHECK( nullptr == direct.find( account_id_type( 2 ) ) );
|
||||||
|
BOOST_CHECK( nullptr != direct.find( account_id_type( 1 ) ) );
|
||||||
|
BOOST_CHECK_EQUAL( test_account.name, direct.get( test_account.id ).name );
|
||||||
|
|
||||||
|
// The following assumes that MAX_HOLE = 100
|
||||||
|
test_account.id = account_id_type(102);
|
||||||
|
test_account.name = "account102";
|
||||||
|
// highest insert was 1, direct.next is 2 => 102 is highest allowed instance
|
||||||
|
my_accounts.load( fc::raw::pack( test_account ) );
|
||||||
|
BOOST_CHECK_EQUAL( test_account.name, direct.get( test_account.id ).name );
|
||||||
|
|
||||||
|
// direct.next is now 103, but index sequence counter is 0
|
||||||
|
my_accounts.create( [] ( object& o ) {
|
||||||
|
account_object& acct = dynamic_cast< account_object& >( o );
|
||||||
|
BOOST_CHECK_EQUAL( 0, acct.id.instance() );
|
||||||
|
acct.name = "account0";
|
||||||
|
} );
|
||||||
|
|
||||||
|
test_account.id = account_id_type(50);
|
||||||
|
test_account.name = "account50";
|
||||||
|
my_accounts.load( fc::raw::pack( test_account ) );
|
||||||
|
|
||||||
|
// can handle nested modification
|
||||||
|
my_accounts.modify( direct.get( account_id_type(0) ), [&direct,&my_accounts] ( object& outer ) {
|
||||||
|
account_object& _outer = dynamic_cast< account_object& >( outer );
|
||||||
|
my_accounts.modify( direct.get( account_id_type(50) ), [] ( object& inner ) {
|
||||||
|
account_object& _inner = dynamic_cast< account_object& >( inner );
|
||||||
|
_inner.referrer = account_id_type(102);
|
||||||
|
});
|
||||||
|
_outer.options.voting_account = GRAPHENE_PROXY_TO_SELF_ACCOUNT;
|
||||||
|
});
|
||||||
|
|
||||||
|
// direct.next is still 103, so 204 is not allowed
|
||||||
|
test_account.id = account_id_type(204);
|
||||||
|
test_account.name = "account204";
|
||||||
|
GRAPHENE_REQUIRE_THROW( my_accounts.load( fc::raw::pack( test_account ) ), fc::assert_exception );
|
||||||
|
// This is actually undefined behaviour. The object has been inserted into
|
||||||
|
// the primary index, but the secondary has refused to insert it!
|
||||||
|
BOOST_CHECK_EQUAL( 5, my_accounts.indices().size() );
|
||||||
|
|
||||||
|
uint32_t count = 0;
|
||||||
|
for( uint32_t i = 0; i < 250; i++ )
|
||||||
|
{
|
||||||
|
const account_object* aptr = dynamic_cast< const account_object* >( my_accounts.find( account_id_type( i ) ) );
|
||||||
|
if( aptr )
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
BOOST_CHECK( aptr->id.instance() == 0 || aptr->id.instance() == 1
|
||||||
|
|| aptr->id.instance() == 50 || aptr->id.instance() == 102 );
|
||||||
|
BOOST_CHECK_EQUAL( i, aptr->id.instance() );
|
||||||
|
BOOST_CHECK_EQUAL( "account" + std::to_string( i ), aptr->name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL( count, my_accounts.indices().size() - 1 );
|
||||||
|
|
||||||
|
GRAPHENE_REQUIRE_THROW( my_accounts.modify( direct.get( account_id_type( 1 ) ), [] ( object& acct ) {
|
||||||
|
acct.id = account_id_type(2);
|
||||||
|
}), fc::assert_exception );
|
||||||
|
// This is actually undefined behaviour. The object has been modified, but
|
||||||
|
// but the secondary has not updated its representation
|
||||||
|
} FC_LOG_AND_RETHROW() }
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue