Merge branch 'master' of github.com:cryptonomex/graphene
This commit is contained in:
commit
cf7a67ec76
11 changed files with 2054 additions and 1518 deletions
2
docs
2
docs
|
|
@ -1 +1 @@
|
|||
Subproject commit c004ae42a72d86bbc6c7e8d065deed284fd093a5
|
||||
Subproject commit cdc8ea8133a999afef8051700a4ce8edb0988ec4
|
||||
|
|
@ -4,6 +4,7 @@ file(GLOB EGENESIS_HEADERS "../egenesis/include/graphene/app/*.hpp")
|
|||
add_library( graphene_app
|
||||
api.cpp
|
||||
application.cpp
|
||||
database_api.cpp
|
||||
impacted.cpp
|
||||
plugin.cpp
|
||||
${HEADERS}
|
||||
|
|
|
|||
|
|
@ -35,519 +35,6 @@
|
|||
|
||||
namespace graphene { namespace app {
|
||||
|
||||
database_api::database_api(graphene::chain::database& db):_db(db)
|
||||
{
|
||||
wlog("creating database api ${x}", ("x",int64_t(this)) );
|
||||
_change_connection = _db.changed_objects.connect([this](const vector<object_id_type>& ids) {
|
||||
on_objects_changed(ids);
|
||||
});
|
||||
_removed_connection = _db.removed_objects.connect([this](const vector<const object*>& objs) {
|
||||
on_objects_removed(objs);
|
||||
});
|
||||
_applied_block_connection = _db.applied_block.connect([this](const signed_block&){ on_applied_block(); });
|
||||
|
||||
_pending_trx_connection = _db.on_pending_transaction.connect([this](const signed_transaction& trx ){
|
||||
if( _pending_trx_callback ) _pending_trx_callback( fc::variant(trx) );
|
||||
});
|
||||
}
|
||||
|
||||
database_api::~database_api()
|
||||
{
|
||||
elog("freeing database api ${x}", ("x",int64_t(this)) );
|
||||
}
|
||||
|
||||
void database_api::set_subscribe_callback( std::function<void(const variant&)> cb, bool clear_filter )
|
||||
{
|
||||
edump((clear_filter));
|
||||
_subscribe_callback = cb;
|
||||
if( clear_filter || !cb )
|
||||
{
|
||||
static fc::bloom_parameters param;
|
||||
param.projected_element_count = 10000;
|
||||
param.false_positive_probability = 1.0/10000;
|
||||
param.maximum_size = 1024*8*8*2;
|
||||
param.compute_optimal_parameters();
|
||||
_subscribe_filter = fc::bloom_filter(param);
|
||||
}
|
||||
}
|
||||
|
||||
fc::variants database_api::get_objects(const vector<object_id_type>& ids)const
|
||||
{
|
||||
if( _subscribe_callback ) {
|
||||
for( auto id : ids )
|
||||
{
|
||||
if( id.type() == operation_history_object_type && id.space() == protocol_ids ) continue;
|
||||
if( id.type() == impl_account_transaction_history_object_type && id.space() == implementation_ids ) continue;
|
||||
|
||||
this->subscribe_to_item( id );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elog( "getObjects without subscribe callback??" );
|
||||
}
|
||||
|
||||
fc::variants result;
|
||||
result.reserve(ids.size());
|
||||
|
||||
std::transform(ids.begin(), ids.end(), std::back_inserter(result),
|
||||
[this](object_id_type id) -> fc::variant {
|
||||
if(auto obj = _db.find_object(id))
|
||||
return obj->to_variant();
|
||||
return {};
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
optional<block_header> database_api::get_block_header(uint32_t block_num) const
|
||||
{
|
||||
auto result = _db.fetch_block_by_number(block_num);
|
||||
if(result)
|
||||
return *result;
|
||||
return {};
|
||||
}
|
||||
|
||||
optional<signed_block> database_api::get_block(uint32_t block_num)const
|
||||
{
|
||||
return _db.fetch_block_by_number(block_num);
|
||||
}
|
||||
processed_transaction database_api::get_transaction(uint32_t block_num, uint32_t trx_num)const
|
||||
{
|
||||
auto opt_block = _db.fetch_block_by_number(block_num);
|
||||
FC_ASSERT( opt_block );
|
||||
FC_ASSERT( opt_block->transactions.size() > trx_num );
|
||||
return opt_block->transactions[trx_num];
|
||||
}
|
||||
|
||||
vector<optional<account_object>> database_api::lookup_account_names(const vector<string>& account_names)const
|
||||
{
|
||||
const auto& accounts_by_name = _db.get_index_type<account_index>().indices().get<by_name>();
|
||||
vector<optional<account_object> > result;
|
||||
result.reserve(account_names.size());
|
||||
std::transform(account_names.begin(), account_names.end(), std::back_inserter(result),
|
||||
[&accounts_by_name](const string& name) -> optional<account_object> {
|
||||
auto itr = accounts_by_name.find(name);
|
||||
return itr == accounts_by_name.end()? optional<account_object>() : *itr;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<optional<asset_object>> database_api::lookup_asset_symbols(const vector<string>& symbols_or_ids)const
|
||||
{
|
||||
const auto& assets_by_symbol = _db.get_index_type<asset_index>().indices().get<by_symbol>();
|
||||
vector<optional<asset_object> > result;
|
||||
result.reserve(symbols_or_ids.size());
|
||||
std::transform(symbols_or_ids.begin(), symbols_or_ids.end(), std::back_inserter(result),
|
||||
[this, &assets_by_symbol](const string& symbol_or_id) -> optional<asset_object> {
|
||||
if( !symbol_or_id.empty() && std::isdigit(symbol_or_id[0]) )
|
||||
{
|
||||
auto ptr = _db.find(variant(symbol_or_id).as<asset_id_type>());
|
||||
return ptr == nullptr? optional<asset_object>() : *ptr;
|
||||
}
|
||||
auto itr = assets_by_symbol.find(symbol_or_id);
|
||||
return itr == assets_by_symbol.end()? optional<asset_object>() : *itr;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
chain_property_object database_api::get_chain_properties()const
|
||||
{
|
||||
return _db.get(chain_property_id_type());
|
||||
}
|
||||
|
||||
global_property_object database_api::get_global_properties()const
|
||||
{
|
||||
return _db.get(global_property_id_type());
|
||||
}
|
||||
|
||||
fc::variant_object database_api::get_config()const
|
||||
{
|
||||
return get_config();
|
||||
}
|
||||
|
||||
chain_id_type database_api::get_chain_id()const
|
||||
{
|
||||
return _db.get_chain_id();
|
||||
}
|
||||
|
||||
dynamic_global_property_object database_api::get_dynamic_global_properties()const
|
||||
{
|
||||
return _db.get(dynamic_global_property_id_type());
|
||||
}
|
||||
|
||||
|
||||
vector<optional<account_object>> database_api::get_accounts(const vector<account_id_type>& account_ids)const
|
||||
{
|
||||
vector<optional<account_object>> result; result.reserve(account_ids.size());
|
||||
std::transform(account_ids.begin(), account_ids.end(), std::back_inserter(result),
|
||||
[this](account_id_type id) -> optional<account_object> {
|
||||
if(auto o = _db.find(id))
|
||||
{
|
||||
subscribe_to_item( id );
|
||||
return *o;
|
||||
}
|
||||
return {};
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<optional<asset_object>> database_api::get_assets(const vector<asset_id_type>& asset_ids)const
|
||||
{
|
||||
vector<optional<asset_object>> result; result.reserve(asset_ids.size());
|
||||
std::transform(asset_ids.begin(), asset_ids.end(), std::back_inserter(result),
|
||||
[this](asset_id_type id) -> optional<asset_object> {
|
||||
if(auto o = _db.find(id))
|
||||
{
|
||||
subscribe_to_item( id );
|
||||
return *o;
|
||||
}
|
||||
return {};
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t database_api::get_account_count()const
|
||||
{
|
||||
return _db.get_index_type<account_index>().indices().size();
|
||||
}
|
||||
|
||||
map<string,account_id_type> database_api::lookup_accounts(const string& lower_bound_name, uint32_t limit)const
|
||||
{
|
||||
FC_ASSERT( limit <= 1000 );
|
||||
const auto& accounts_by_name = _db.get_index_type<account_index>().indices().get<by_name>();
|
||||
map<string,account_id_type> result;
|
||||
|
||||
for( auto itr = accounts_by_name.lower_bound(lower_bound_name);
|
||||
limit-- && itr != accounts_by_name.end();
|
||||
++itr )
|
||||
{
|
||||
result.insert(make_pair(itr->name, itr->get_id()));
|
||||
if( limit == 1 )
|
||||
subscribe_to_item( itr->get_id() );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::map<std::string, full_account> database_api::get_full_accounts( const vector<std::string>& names_or_ids, bool subscribe)
|
||||
{
|
||||
idump((names_or_ids));
|
||||
std::map<std::string, full_account> results;
|
||||
|
||||
for (const std::string& account_name_or_id : names_or_ids)
|
||||
{
|
||||
const account_object* account = nullptr;
|
||||
if (std::isdigit(account_name_or_id[0]))
|
||||
account = _db.find(fc::variant(account_name_or_id).as<account_id_type>());
|
||||
else
|
||||
{
|
||||
const auto& idx = _db.get_index_type<account_index>().indices().get<by_name>();
|
||||
auto itr = idx.find(account_name_or_id);
|
||||
if (itr != idx.end())
|
||||
account = &*itr;
|
||||
}
|
||||
if (account == nullptr)
|
||||
continue;
|
||||
|
||||
if( subscribe )
|
||||
{
|
||||
ilog( "subscribe to ${id}", ("id",account->name) );
|
||||
subscribe_to_item( account->id );
|
||||
}
|
||||
|
||||
// fc::mutable_variant_object full_account;
|
||||
full_account acnt;
|
||||
acnt.account = *account;
|
||||
acnt.statistics = account->statistics(_db);
|
||||
acnt.registrar_name = account->registrar(_db).name;
|
||||
acnt.referrer_name = account->referrer(_db).name;
|
||||
acnt.lifetime_referrer_name = account->lifetime_referrer(_db).name;
|
||||
acnt.votes = lookup_vote_ids( vector<vote_id_type>(account->options.votes.begin(),account->options.votes.end()) );
|
||||
|
||||
// Add the account itself, its statistics object, cashback balance, and referral account names
|
||||
/*
|
||||
full_account("account", *account)("statistics", account->statistics(_db))
|
||||
("registrar_name", account->registrar(_db).name)("referrer_name", account->referrer(_db).name)
|
||||
("lifetime_referrer_name", account->lifetime_referrer(_db).name);
|
||||
*/
|
||||
if (account->cashback_vb)
|
||||
{
|
||||
acnt.cashback_balance = account->cashback_balance(_db);
|
||||
}
|
||||
// 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 );
|
||||
if( required_approvals_itr != proposals_by_account._account_to_proposals.end() )
|
||||
{
|
||||
acnt.proposals.reserve( required_approvals_itr->second.size() );
|
||||
for( auto proposal_id : required_approvals_itr->second )
|
||||
acnt.proposals.push_back( proposal_id(_db) );
|
||||
}
|
||||
|
||||
|
||||
// Add the account's balances
|
||||
auto balance_range = _db.get_index_type<account_balance_index>().indices().get<by_account>().equal_range(account->id);
|
||||
//vector<account_balance_object> balances;
|
||||
std::for_each(balance_range.first, balance_range.second,
|
||||
[&acnt](const account_balance_object& balance) {
|
||||
acnt.balances.emplace_back(balance);
|
||||
});
|
||||
|
||||
// Add the account's vesting balances
|
||||
auto vesting_range = _db.get_index_type<vesting_balance_index>().indices().get<by_account>().equal_range(account->id);
|
||||
std::for_each(vesting_range.first, vesting_range.second,
|
||||
[&acnt](const vesting_balance_object& balance) {
|
||||
acnt.vesting_balances.emplace_back(balance);
|
||||
});
|
||||
|
||||
// Add the account's orders
|
||||
auto order_range = _db.get_index_type<limit_order_index>().indices().get<by_account>().equal_range(account->id);
|
||||
std::for_each(order_range.first, order_range.second,
|
||||
[&acnt] (const limit_order_object& order) {
|
||||
acnt.limit_orders.emplace_back(order);
|
||||
});
|
||||
auto call_range = _db.get_index_type<call_order_index>().indices().get<by_account>().equal_range(account->id);
|
||||
std::for_each(call_range.first, call_range.second,
|
||||
[&acnt] (const call_order_object& call) {
|
||||
acnt.call_orders.emplace_back(call);
|
||||
});
|
||||
results[account_name_or_id] = acnt;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
vector<asset> database_api::get_account_balances(account_id_type acnt, const flat_set<asset_id_type>& assets)const
|
||||
{
|
||||
vector<asset> result;
|
||||
if (assets.empty())
|
||||
{
|
||||
// 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>();
|
||||
auto range = balance_index.indices().get<by_account>().equal_range(acnt);
|
||||
for (const account_balance_object& balance : boost::make_iterator_range(range.first, range.second))
|
||||
result.push_back(asset(balance.get_balance()));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.reserve(assets.size());
|
||||
|
||||
std::transform(assets.begin(), assets.end(), std::back_inserter(result),
|
||||
[this, acnt](asset_id_type id) { return _db.get_balance(acnt, id); });
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<asset> database_api::get_named_account_balances(const std::string& name, const flat_set<asset_id_type>& assets) const
|
||||
{
|
||||
const auto& accounts_by_name = _db.get_index_type<account_index>().indices().get<by_name>();
|
||||
auto itr = accounts_by_name.find(name);
|
||||
FC_ASSERT( itr != accounts_by_name.end() );
|
||||
return get_account_balances(itr->get_id(), assets);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the limit orders for both sides of the book for the two assets specified up to limit number on each side.
|
||||
*/
|
||||
vector<limit_order_object> database_api::get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const
|
||||
{
|
||||
const auto& limit_order_idx = _db.get_index_type<limit_order_index>();
|
||||
const auto& limit_price_idx = limit_order_idx.indices().get<by_price>();
|
||||
|
||||
vector<limit_order_object> result;
|
||||
|
||||
uint32_t count = 0;
|
||||
auto limit_itr = limit_price_idx.lower_bound(price::max(a,b));
|
||||
auto limit_end = limit_price_idx.upper_bound(price::min(a,b));
|
||||
while(limit_itr != limit_end && count < limit)
|
||||
{
|
||||
result.push_back(*limit_itr);
|
||||
++limit_itr;
|
||||
++count;
|
||||
}
|
||||
count = 0;
|
||||
limit_itr = limit_price_idx.lower_bound(price::max(b,a));
|
||||
limit_end = limit_price_idx.upper_bound(price::min(b,a));
|
||||
while(limit_itr != limit_end && count < limit)
|
||||
{
|
||||
result.push_back(*limit_itr);
|
||||
++limit_itr;
|
||||
++count;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<call_order_object> database_api::get_call_orders(asset_id_type a, uint32_t limit)const
|
||||
{
|
||||
const auto& call_index = _db.get_index_type<call_order_index>().indices().get<by_price>();
|
||||
const asset_object& mia = _db.get(a);
|
||||
price index_price = price::min(mia.bitasset_data(_db).options.short_backing_asset, mia.get_id());
|
||||
|
||||
return vector<call_order_object>(call_index.lower_bound(index_price.min()),
|
||||
call_index.lower_bound(index_price.max()));
|
||||
}
|
||||
|
||||
vector<force_settlement_object> database_api::get_settle_orders(asset_id_type a, uint32_t limit)const
|
||||
{
|
||||
const auto& settle_index = _db.get_index_type<force_settlement_index>().indices().get<by_expiration>();
|
||||
const asset_object& mia = _db.get(a);
|
||||
return vector<force_settlement_object>(settle_index.lower_bound(mia.get_id()),
|
||||
settle_index.upper_bound(mia.get_id()));
|
||||
}
|
||||
|
||||
vector<asset_object> database_api::list_assets(const string& lower_bound_symbol, uint32_t limit)const
|
||||
{
|
||||
FC_ASSERT( limit <= 100 );
|
||||
const auto& assets_by_symbol = _db.get_index_type<asset_index>().indices().get<by_symbol>();
|
||||
vector<asset_object> result;
|
||||
result.reserve(limit);
|
||||
|
||||
auto itr = assets_by_symbol.lower_bound(lower_bound_symbol);
|
||||
|
||||
if( lower_bound_symbol == "" )
|
||||
itr = assets_by_symbol.begin();
|
||||
|
||||
while(limit-- && itr != assets_by_symbol.end())
|
||||
result.emplace_back(*itr++);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fc::optional<committee_member_object> database_api::get_committee_member_by_account(account_id_type account) const
|
||||
{
|
||||
const auto& idx = _db.get_index_type<committee_member_index>().indices().get<by_account>();
|
||||
auto itr = idx.find(account);
|
||||
if( itr != idx.end() )
|
||||
return *itr;
|
||||
return {};
|
||||
}
|
||||
|
||||
fc::optional<witness_object> database_api::get_witness_by_account(account_id_type account) const
|
||||
{
|
||||
const auto& idx = _db.get_index_type<witness_index>().indices().get<by_account>();
|
||||
auto itr = idx.find(account);
|
||||
if( itr != idx.end() )
|
||||
return *itr;
|
||||
return {};
|
||||
}
|
||||
vector<variant> database_api::lookup_vote_ids( const vector<vote_id_type>& votes )const
|
||||
{
|
||||
FC_ASSERT( votes.size() < 100, "Only 100 votes can be queried at a time" );
|
||||
|
||||
const auto& witness_idx = _db.get_index_type<witness_index>().indices().get<by_vote_id>();
|
||||
const auto& committee_idx = _db.get_index_type<committee_member_index>().indices().get<by_vote_id>();
|
||||
|
||||
vector<variant> result;
|
||||
result.reserve( votes.size() );
|
||||
for( auto id : votes )
|
||||
{
|
||||
switch( id.type() )
|
||||
{
|
||||
case vote_id_type::committee:
|
||||
{
|
||||
auto itr = committee_idx.find( id );
|
||||
if( itr != committee_idx.end() )
|
||||
result.emplace_back( variant( *itr ) );
|
||||
else
|
||||
result.emplace_back( variant() );
|
||||
break;
|
||||
}
|
||||
case vote_id_type::witness:
|
||||
{
|
||||
auto itr = witness_idx.find( id );
|
||||
if( itr != witness_idx.end() )
|
||||
result.emplace_back( variant( *itr ) );
|
||||
else
|
||||
result.emplace_back( variant() );
|
||||
break;
|
||||
}
|
||||
case vote_id_type::worker:
|
||||
break;
|
||||
case vote_id_type::VOTE_TYPE_COUNT: break; // supress unused enum value warnings
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t database_api::get_witness_count()const
|
||||
{
|
||||
return _db.get_index_type<witness_index>().indices().size();
|
||||
}
|
||||
|
||||
map<string, witness_id_type> database_api::lookup_witness_accounts(const string& lower_bound_name, uint32_t limit)const
|
||||
{
|
||||
FC_ASSERT( limit <= 1000 );
|
||||
const auto& witnesses_by_id = _db.get_index_type<witness_index>().indices().get<by_id>();
|
||||
|
||||
// we want to order witnesses by account name, but that name is in the account object
|
||||
// so the witness_index doesn't have a quick way to access it.
|
||||
// get all the names and look them all up, sort them, then figure out what
|
||||
// records to return. This could be optimized, but we expect the
|
||||
// number of witnesses to be few and the frequency of calls to be rare
|
||||
std::map<std::string, witness_id_type> witnesses_by_account_name;
|
||||
for (const witness_object& witness : witnesses_by_id)
|
||||
if (auto account_iter = _db.find(witness.witness_account))
|
||||
if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name
|
||||
witnesses_by_account_name.insert(std::make_pair(account_iter->name, witness.id));
|
||||
|
||||
auto end_iter = witnesses_by_account_name.begin();
|
||||
while (end_iter != witnesses_by_account_name.end() && limit--)
|
||||
++end_iter;
|
||||
witnesses_by_account_name.erase(end_iter, witnesses_by_account_name.end());
|
||||
return witnesses_by_account_name;
|
||||
}
|
||||
|
||||
map<string, committee_member_id_type> database_api::lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const
|
||||
{
|
||||
FC_ASSERT( limit <= 1000 );
|
||||
const auto& committee_members_by_id = _db.get_index_type<committee_member_index>().indices().get<by_id>();
|
||||
|
||||
// we want to order committee_members by account name, but that name is in the account object
|
||||
// so the committee_member_index doesn't have a quick way to access it.
|
||||
// get all the names and look them all up, sort them, then figure out what
|
||||
// records to return. This could be optimized, but we expect the
|
||||
// number of committee_members to be few and the frequency of calls to be rare
|
||||
std::map<std::string, committee_member_id_type> committee_members_by_account_name;
|
||||
for (const committee_member_object& committee_member : committee_members_by_id)
|
||||
if (auto account_iter = _db.find(committee_member.committee_member_account))
|
||||
if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name
|
||||
committee_members_by_account_name.insert(std::make_pair(account_iter->name, committee_member.id));
|
||||
|
||||
auto end_iter = committee_members_by_account_name.begin();
|
||||
while (end_iter != committee_members_by_account_name.end() && limit--)
|
||||
++end_iter;
|
||||
committee_members_by_account_name.erase(end_iter, committee_members_by_account_name.end());
|
||||
return committee_members_by_account_name;
|
||||
}
|
||||
|
||||
vector<optional<witness_object>> database_api::get_witnesses(const vector<witness_id_type>& witness_ids)const
|
||||
{
|
||||
vector<optional<witness_object>> result; result.reserve(witness_ids.size());
|
||||
std::transform(witness_ids.begin(), witness_ids.end(), std::back_inserter(result),
|
||||
[this](witness_id_type id) -> optional<witness_object> {
|
||||
if(auto o = _db.find(id))
|
||||
return *o;
|
||||
return {};
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<optional<committee_member_object>> database_api::get_committee_members(const vector<committee_member_id_type>& committee_member_ids)const
|
||||
{
|
||||
vector<optional<committee_member_object>> result; result.reserve(committee_member_ids.size());
|
||||
std::transform(committee_member_ids.begin(), committee_member_ids.end(), std::back_inserter(result),
|
||||
[this](committee_member_id_type id) -> optional<committee_member_object> {
|
||||
if(auto o = _db.find(id))
|
||||
return *o;
|
||||
return {};
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
login_api::login_api(application& a)
|
||||
:_app(a)
|
||||
{
|
||||
|
|
@ -811,184 +298,6 @@ namespace graphene { namespace app {
|
|||
return result;
|
||||
} // end get_relevant_accounts( obj )
|
||||
|
||||
|
||||
void database_api::broadcast_updates( const vector<variant>& updates )
|
||||
{
|
||||
if( updates.size() ) {
|
||||
auto capture_this = shared_from_this();
|
||||
fc::async([capture_this,updates](){
|
||||
capture_this->_subscribe_callback( fc::variant(updates) );
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void database_api::on_objects_removed( const vector<const object*>& objs )
|
||||
{
|
||||
/// we need to ensure the database_api is not deleted for the life of the async operation
|
||||
if( _subscribe_callback )
|
||||
{
|
||||
vector<variant> updates;
|
||||
updates.reserve(objs.size());
|
||||
|
||||
for( auto obj : objs )
|
||||
updates.emplace_back( obj->id );
|
||||
broadcast_updates( updates );
|
||||
}
|
||||
|
||||
if( _market_subscriptions.size() )
|
||||
{
|
||||
map< pair<asset_id_type, asset_id_type>, vector<variant> > broadcast_queue;
|
||||
for( const auto& obj : objs )
|
||||
{
|
||||
const limit_order_object* order = dynamic_cast<const limit_order_object*>(obj);
|
||||
if( order )
|
||||
{
|
||||
auto sub = _market_subscriptions.find( order->get_market() );
|
||||
if( sub != _market_subscriptions.end() )
|
||||
broadcast_queue[order->get_market()].emplace_back( order->id );
|
||||
}
|
||||
}
|
||||
if( broadcast_queue.size() )
|
||||
{
|
||||
auto capture_this = shared_from_this();
|
||||
fc::async([capture_this,this,broadcast_queue](){
|
||||
for( const auto& item : broadcast_queue )
|
||||
{
|
||||
auto sub = _market_subscriptions.find(item.first);
|
||||
if( sub != _market_subscriptions.end() )
|
||||
sub->second( fc::variant(item.second ) );
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void database_api::on_objects_changed(const vector<object_id_type>& ids)
|
||||
{
|
||||
vector<variant> updates;
|
||||
map< pair<asset_id_type, asset_id_type>, vector<variant> > market_broadcast_queue;
|
||||
|
||||
for(auto id : ids)
|
||||
{
|
||||
const object* obj = nullptr;
|
||||
if( _subscribe_callback )
|
||||
{
|
||||
obj = _db.find_object( id );
|
||||
if( obj )
|
||||
{
|
||||
updates.emplace_back( obj->to_variant() );
|
||||
}
|
||||
else
|
||||
{
|
||||
updates.emplace_back(id); // send just the id to indicate removal
|
||||
}
|
||||
}
|
||||
|
||||
if( _market_subscriptions.size() )
|
||||
{
|
||||
if( !_subscribe_callback )
|
||||
obj = _db.find_object( id );
|
||||
if( obj )
|
||||
{
|
||||
const limit_order_object* order = dynamic_cast<const limit_order_object*>(obj);
|
||||
if( order )
|
||||
{
|
||||
auto sub = _market_subscriptions.find( order->get_market() );
|
||||
if( sub != _market_subscriptions.end() )
|
||||
market_broadcast_queue[order->get_market()].emplace_back( order->id );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto capture_this = shared_from_this();
|
||||
|
||||
/// pushing the future back / popping the prior future if it is complete.
|
||||
/// if a connection hangs then this could get backed up and result in
|
||||
/// a failure to exit cleanly.
|
||||
fc::async([capture_this,this,updates,market_broadcast_queue](){
|
||||
if( _subscribe_callback ) _subscribe_callback( updates );
|
||||
|
||||
for( const auto& item : market_broadcast_queue )
|
||||
{
|
||||
auto sub = _market_subscriptions.find(item.first);
|
||||
if( sub != _market_subscriptions.end() )
|
||||
sub->second( fc::variant(item.second ) );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** note: this method cannot yield because it is called in the middle of
|
||||
* apply a block.
|
||||
*/
|
||||
void database_api::on_applied_block()
|
||||
{
|
||||
if (_block_applied_callback)
|
||||
{
|
||||
auto capture_this = shared_from_this();
|
||||
block_id_type block_id = _db.head_block_id();
|
||||
fc::async([this,capture_this,block_id](){
|
||||
_block_applied_callback(fc::variant(block_id));
|
||||
});
|
||||
}
|
||||
|
||||
if(_market_subscriptions.size() == 0)
|
||||
return;
|
||||
|
||||
const auto& ops = _db.get_applied_operations();
|
||||
map< std::pair<asset_id_type,asset_id_type>, vector<pair<operation, operation_result>> > subscribed_markets_ops;
|
||||
for(const auto& op : ops)
|
||||
{
|
||||
std::pair<asset_id_type,asset_id_type> market;
|
||||
switch(op.op.which())
|
||||
{
|
||||
/* This is sent via the object_changed callback
|
||||
case operation::tag<limit_order_create_operation>::value:
|
||||
market = op.op.get<limit_order_create_operation>().get_market();
|
||||
break;
|
||||
*/
|
||||
case operation::tag<fill_order_operation>::value:
|
||||
market = op.op.get<fill_order_operation>().get_market();
|
||||
break;
|
||||
/*
|
||||
case operation::tag<limit_order_cancel_operation>::value:
|
||||
*/
|
||||
default: break;
|
||||
}
|
||||
if(_market_subscriptions.count(market))
|
||||
subscribed_markets_ops[market].push_back(std::make_pair(op.op, op.result));
|
||||
}
|
||||
/// we need to ensure the database_api is not deleted for the life of the async operation
|
||||
auto capture_this = shared_from_this();
|
||||
fc::async([this,capture_this,subscribed_markets_ops](){
|
||||
for(auto item : subscribed_markets_ops)
|
||||
{
|
||||
auto itr = _market_subscriptions.find(item.first);
|
||||
if(itr != _market_subscriptions.end())
|
||||
itr->second(fc::variant(item.second));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void database_api::subscribe_to_market(std::function<void(const variant&)> callback, asset_id_type a, asset_id_type b)
|
||||
{
|
||||
if(a > b) std::swap(a,b);
|
||||
FC_ASSERT(a != b);
|
||||
_market_subscriptions[ std::make_pair(a,b) ] = callback;
|
||||
}
|
||||
|
||||
void database_api::unsubscribe_from_market(asset_id_type a, asset_id_type b)
|
||||
{
|
||||
if(a > b) std::swap(a,b);
|
||||
FC_ASSERT(a != b);
|
||||
_market_subscriptions.erase(std::make_pair(a,b));
|
||||
}
|
||||
|
||||
std::string database_api::get_transaction_hex(const signed_transaction& trx)const
|
||||
{
|
||||
return fc::to_hex(fc::raw::pack(trx));
|
||||
}
|
||||
|
||||
vector<operation_history_object> history_api::get_account_history(account_id_type account, operation_history_id_type stop, unsigned limit, operation_history_id_type start) const
|
||||
{
|
||||
FC_ASSERT(_app.chain_database());
|
||||
|
|
@ -1011,7 +320,6 @@ namespace graphene { namespace app {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
flat_set<uint32_t> history_api::get_market_history_buckets()const
|
||||
{
|
||||
auto hist = _app.get_plugin<market_history_plugin>( "market_history" );
|
||||
|
|
@ -1043,268 +351,4 @@ namespace graphene { namespace app {
|
|||
return result;
|
||||
} FC_CAPTURE_AND_RETHROW( (a)(b)(bucket_seconds)(start)(end) ) }
|
||||
|
||||
/**
|
||||
* @return all accounts that referr to the key or account id in their owner or active authorities.
|
||||
*/
|
||||
vector<account_id_type> database_api::get_account_references( account_id_type account_id )const
|
||||
{
|
||||
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_account_memberships.find(account_id);
|
||||
vector<account_id_type> result;
|
||||
|
||||
if( itr != refs.account_to_account_memberships.end() )
|
||||
{
|
||||
result.reserve( itr->second.size() );
|
||||
for( auto item : itr->second ) result.push_back(item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* @return all accounts that referr to the key or account id in their owner or active authorities.
|
||||
*/
|
||||
vector<vector<account_id_type>> database_api::get_key_references( vector<public_key_type> keys )const
|
||||
{
|
||||
wdump( (keys) );
|
||||
vector< vector<account_id_type> > final_result;
|
||||
final_result.reserve(keys.size());
|
||||
|
||||
for( auto& key : keys )
|
||||
{
|
||||
|
||||
address a1( pts_address(key, false, 56) );
|
||||
address a2( pts_address(key, true, 56) );
|
||||
address a3( pts_address(key, false, 0) );
|
||||
address a4( pts_address(key, true, 0) );
|
||||
address a5( key );
|
||||
|
||||
subscribe_to_item( key );
|
||||
subscribe_to_item( a1 );
|
||||
subscribe_to_item( a2 );
|
||||
subscribe_to_item( a3 );
|
||||
subscribe_to_item( a4 );
|
||||
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;
|
||||
|
||||
for( auto& a : {a1,a2,a3,a4,a5} )
|
||||
{
|
||||
auto itr = refs.account_to_address_memberships.find(a);
|
||||
if( itr != refs.account_to_address_memberships.end() )
|
||||
{
|
||||
result.reserve( itr->second.size() );
|
||||
for( auto item : itr->second )
|
||||
{
|
||||
wdump((a)(item)(item(_db).name));
|
||||
result.push_back(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( itr != refs.account_to_key_memberships.end() )
|
||||
{
|
||||
result.reserve( itr->second.size() );
|
||||
for( auto item : itr->second ) result.push_back(item);
|
||||
}
|
||||
final_result.emplace_back( std::move(result) );
|
||||
}
|
||||
|
||||
for( auto i : final_result )
|
||||
subscribe_to_item(i);
|
||||
|
||||
return final_result;
|
||||
}
|
||||
|
||||
/** TODO: add secondary index that will accelerate this process */
|
||||
vector<proposal_object> database_api::get_proposed_transactions( account_id_type id )const
|
||||
{
|
||||
const auto& idx = _db.get_index_type<proposal_index>();
|
||||
vector<proposal_object> result;
|
||||
|
||||
idx.inspect_all_objects( [&](const object& obj){
|
||||
const proposal_object& p = static_cast<const proposal_object&>(obj);
|
||||
if( p.required_active_approvals.find( id ) != p.required_active_approvals.end() )
|
||||
result.push_back(p);
|
||||
else if ( p.required_owner_approvals.find( id ) != p.required_owner_approvals.end() )
|
||||
result.push_back(p);
|
||||
else if ( p.available_active_approvals.find( id ) != p.available_active_approvals.end() )
|
||||
result.push_back(p);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<call_order_object> database_api::get_margin_positions( const account_id_type& id )const
|
||||
{ try {
|
||||
const auto& idx = _db.get_index_type<call_order_index>();
|
||||
const auto& aidx = idx.indices().get<by_account>();
|
||||
auto start = aidx.lower_bound( boost::make_tuple( id, 0 ) );
|
||||
auto end = aidx.lower_bound( boost::make_tuple( id+1, 0 ) );
|
||||
vector<call_order_object> result;
|
||||
while( start != end )
|
||||
{
|
||||
result.push_back(*start);
|
||||
++start;
|
||||
}
|
||||
return result;
|
||||
} FC_CAPTURE_AND_RETHROW( (id) ) }
|
||||
|
||||
|
||||
vector<asset> database_api::get_vested_balances( const vector<balance_id_type>& objs )const
|
||||
{ try {
|
||||
vector<asset> result;
|
||||
result.reserve( objs.size() );
|
||||
auto now = _db.head_block_time();
|
||||
for( auto obj : objs )
|
||||
result.push_back( obj(_db).available( now ) );
|
||||
return result;
|
||||
} FC_CAPTURE_AND_RETHROW( (objs) ) }
|
||||
|
||||
vector<vesting_balance_object> database_api::get_vesting_balances( account_id_type account_id )const
|
||||
{
|
||||
try
|
||||
{
|
||||
vector<vesting_balance_object> result;
|
||||
auto vesting_range = _db.get_index_type<vesting_balance_index>().indices().get<by_account>().equal_range(account_id);
|
||||
std::for_each(vesting_range.first, vesting_range.second,
|
||||
[&result](const vesting_balance_object& balance) {
|
||||
result.emplace_back(balance);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW( (account_id) );
|
||||
}
|
||||
|
||||
vector<balance_object> database_api::get_balance_objects( const vector<address>& addrs )const
|
||||
{ try {
|
||||
const auto& bal_idx = _db.get_index_type<balance_index>();
|
||||
const auto& by_owner_idx = bal_idx.indices().get<by_owner>();
|
||||
|
||||
vector<balance_object> result;
|
||||
|
||||
for( const auto& owner : addrs )
|
||||
{
|
||||
subscribe_to_item( owner );
|
||||
auto itr = by_owner_idx.lower_bound( boost::make_tuple( owner, asset_id_type(0) ) );
|
||||
while( itr != by_owner_idx.end() && itr->owner == owner )
|
||||
{
|
||||
result.push_back( *itr );
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} FC_CAPTURE_AND_RETHROW( (addrs) ) }
|
||||
|
||||
set<public_key_type> database_api::get_required_signatures( const signed_transaction& trx, const flat_set<public_key_type>& available_keys )const
|
||||
{
|
||||
wdump((trx)(available_keys));
|
||||
auto result = trx.get_required_signatures( _db.get_chain_id(),
|
||||
available_keys,
|
||||
[&]( account_id_type id ){ return &id(_db).active; },
|
||||
[&]( account_id_type id ){ return &id(_db).owner; },
|
||||
_db.get_global_properties().parameters.max_authority_depth );
|
||||
wdump((result));
|
||||
return result;
|
||||
}
|
||||
set<public_key_type> database_api::get_potential_signatures( const signed_transaction& trx )const
|
||||
{
|
||||
wdump((trx));
|
||||
set<public_key_type> result;
|
||||
trx.get_required_signatures( _db.get_chain_id(),
|
||||
flat_set<public_key_type>(),
|
||||
[&]( account_id_type id ){
|
||||
const auto& auth = id(_db).active;
|
||||
for( const auto& k : auth.get_keys() )
|
||||
result.insert(k);
|
||||
return &auth; },
|
||||
[&]( account_id_type id ){
|
||||
const auto& auth = id(_db).owner;
|
||||
for( const auto& k : auth.get_keys() )
|
||||
result.insert(k);
|
||||
return &auth;
|
||||
},
|
||||
_db.get_global_properties().parameters.max_authority_depth );
|
||||
|
||||
wdump((result));
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Validates a transaction against the current state without broadcast it on the network.
|
||||
*/
|
||||
processed_transaction database_api::validate_transaction( const signed_transaction& trx )const
|
||||
{
|
||||
return _db.validate_transaction(trx);
|
||||
}
|
||||
|
||||
bool database_api::verify_authority( const signed_transaction& trx )const
|
||||
{
|
||||
trx.verify_authority( _db.get_chain_id(),
|
||||
[&]( account_id_type id ){ return &id(_db).active; },
|
||||
[&]( account_id_type id ){ return &id(_db).owner; },
|
||||
_db.get_global_properties().parameters.max_authority_depth );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool database_api::verify_account_authority( const string& name_or_id, const flat_set<public_key_type>& keys )const
|
||||
{
|
||||
FC_ASSERT( name_or_id.size() > 0);
|
||||
const account_object* account = nullptr;
|
||||
if (std::isdigit(name_or_id[0]))
|
||||
account = _db.find(fc::variant(name_or_id).as<account_id_type>());
|
||||
else
|
||||
{
|
||||
const auto& idx = _db.get_index_type<account_index>().indices().get<by_name>();
|
||||
auto itr = idx.find(name_or_id);
|
||||
if (itr != idx.end())
|
||||
account = &*itr;
|
||||
}
|
||||
FC_ASSERT( account, "no such account" );
|
||||
|
||||
|
||||
/// reuse trx.verify_authority by creating a dummy transfer
|
||||
signed_transaction trx;
|
||||
transfer_operation op;
|
||||
op.from = account->id;
|
||||
trx.operations.emplace_back(op);
|
||||
|
||||
return verify_authority( trx );
|
||||
}
|
||||
|
||||
vector<blinded_balance_object> database_api::get_blinded_balances( const flat_set<commitment_type>& commitments )const
|
||||
{
|
||||
vector<blinded_balance_object> result; result.reserve(commitments.size());
|
||||
const auto& bal_idx = _db.get_index_type<blinded_balance_index>();
|
||||
const auto& by_commitment_idx = bal_idx.indices().get<by_commitment>();
|
||||
for( const auto& c : commitments )
|
||||
{
|
||||
auto itr = by_commitment_idx.find( c );
|
||||
if( itr != by_commitment_idx.end() )
|
||||
result.push_back( *itr );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<asset> database_api::get_required_fees( const vector<operation>& ops, asset_id_type id )const
|
||||
{
|
||||
vector<asset> result;
|
||||
result.reserve(ops.size());
|
||||
const asset_object& a = id(_db);
|
||||
for( const auto& op : ops )
|
||||
result.push_back( _db.current_fee_schedule().calculate_fee( op, a.options.core_exchange_rate ) );
|
||||
return result;
|
||||
}
|
||||
|
||||
optional<account_object> database_api::get_account_by_name( string name )const
|
||||
{
|
||||
const auto& idx = _db.get_index_type<account_index>().indices().get<by_name>();
|
||||
auto itr = idx.find(name);
|
||||
if (itr != idx.end())
|
||||
return *itr;
|
||||
return optional<account_object>();
|
||||
}
|
||||
|
||||
} } // graphene::app
|
||||
|
|
|
|||
1495
libraries/app/database_api.cpp
Normal file
1495
libraries/app/database_api.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -17,398 +17,32 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include <graphene/app/full_account.hpp>
|
||||
#include <graphene/app/database_api.hpp>
|
||||
|
||||
#include <graphene/chain/protocol/types.hpp>
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/balance_object.hpp>
|
||||
#include <graphene/chain/chain_property_object.hpp>
|
||||
#include <graphene/chain/committee_member_object.hpp>
|
||||
#include <graphene/chain/market_evaluator.hpp>
|
||||
#include <graphene/chain/operation_history_object.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
|
||||
#include <graphene/chain/confidential_evaluator.hpp>
|
||||
|
||||
#include <graphene/market_history/market_history_plugin.hpp>
|
||||
|
||||
#include <graphene/net/node.hpp>
|
||||
|
||||
#include <fc/api.hpp>
|
||||
#include <fc/bloom_filter.hpp>
|
||||
#include <fc/optional.hpp>
|
||||
#include <fc/network/ip.hpp>
|
||||
|
||||
#include <boost/container/flat_set.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace graphene { namespace app {
|
||||
using namespace graphene::chain;
|
||||
using namespace graphene::market_history;
|
||||
using namespace std;
|
||||
|
||||
class application;
|
||||
|
||||
/**
|
||||
* @brief The database_api class implements the RPC API for the chain database.
|
||||
*
|
||||
* This API exposes accessors on the database which query state tracked by a blockchain validating node. This API is
|
||||
* read-only; all modifications to the database must be performed via transactions. Transactions are broadcast via
|
||||
* the @ref network_broadcast_api.
|
||||
*/
|
||||
class database_api : public std::enable_shared_from_this<database_api>
|
||||
{
|
||||
public:
|
||||
database_api(graphene::chain::database& db);
|
||||
~database_api();
|
||||
/**
|
||||
* @brief Get the objects corresponding to the provided IDs
|
||||
* @param ids IDs of the objects to retrieve
|
||||
* @return The objects retrieved, in the order they are mentioned in ids
|
||||
*
|
||||
* If any of the provided IDs does not map to an object, a null variant is returned in its position.
|
||||
*/
|
||||
fc::variants get_objects(const vector<object_id_type>& ids)const;
|
||||
/**
|
||||
* @brief Retrieve a block header
|
||||
* @param block_num Height of the block whose header should be returned
|
||||
* @return header of the referenced block, or null if no matching block was found
|
||||
*/
|
||||
optional<block_header> get_block_header(uint32_t block_num)const;
|
||||
/**
|
||||
* @brief Retrieve a full, signed block
|
||||
* @param block_num Height of the block to be returned
|
||||
* @return the referenced block, or null if no matching block was found
|
||||
*/
|
||||
optional<signed_block> get_block(uint32_t block_num)const;
|
||||
|
||||
/**
|
||||
* @brief used to fetch an individual transaction.
|
||||
*/
|
||||
processed_transaction get_transaction( uint32_t block_num, uint32_t trx_in_block )const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve the @ref chain_property_object associated with the chain
|
||||
*/
|
||||
chain_property_object get_chain_properties()const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve the current @ref global_property_object
|
||||
*/
|
||||
global_property_object get_global_properties()const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve compile-time constants
|
||||
*/
|
||||
fc::variant_object get_config()const;
|
||||
|
||||
/**
|
||||
* @brief Get the chain ID
|
||||
*/
|
||||
chain_id_type get_chain_id()const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve the current @ref dynamic_global_property_object
|
||||
*/
|
||||
dynamic_global_property_object get_dynamic_global_properties()const;
|
||||
/**
|
||||
* @brief Get a list of accounts by ID
|
||||
* @param account_ids IDs of the accounts to retrieve
|
||||
* @return The accounts corresponding to the provided IDs
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<account_object>> get_accounts(const vector<account_id_type>& account_ids)const;
|
||||
/**
|
||||
* @brief Get a list of assets by ID
|
||||
* @param asset_ids IDs of the assets to retrieve
|
||||
* @return The assets corresponding to the provided IDs
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<asset_object>> get_assets(const vector<asset_id_type>& asset_ids)const;
|
||||
/**
|
||||
* @brief Get a list of accounts by name
|
||||
* @param account_names Names of the accounts to retrieve
|
||||
* @return The accounts holding the provided names
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<account_object>> lookup_account_names(const vector<string>& account_names)const;
|
||||
optional<account_object> get_account_by_name( string name )const;
|
||||
|
||||
/**
|
||||
* @brief Get a list of assets by symbol
|
||||
* @param asset_symbols Symbols or stringified IDs of the assets to retrieve
|
||||
* @return The assets corresponding to the provided symbols or IDs
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<asset_object>> lookup_asset_symbols(const vector<string>& symbols_or_ids)const;
|
||||
|
||||
/**
|
||||
* @brief Get an account's balances in various assets
|
||||
* @param id ID of the account to get balances for
|
||||
* @param assets IDs of the assets to get balances of; if empty, get all assets account has a balance in
|
||||
* @return Balances of the account
|
||||
*/
|
||||
vector<asset> get_account_balances(account_id_type id, const flat_set<asset_id_type>& assets)const;
|
||||
/// Semantically equivalent to @ref get_account_balances, but takes a name instead of an ID.
|
||||
vector<asset> get_named_account_balances(const std::string& name, const flat_set<asset_id_type>& assets)const;
|
||||
/**
|
||||
* @brief Get the total number of accounts registered with the blockchain
|
||||
*/
|
||||
uint64_t get_account_count()const;
|
||||
/**
|
||||
* @brief Get names and IDs for registered accounts
|
||||
* @param lower_bound_name Lower bound of the first name to return
|
||||
* @param limit Maximum number of results to return -- must not exceed 1000
|
||||
* @return Map of account names to corresponding IDs
|
||||
*/
|
||||
map<string,account_id_type> lookup_accounts(const string& lower_bound_name, uint32_t limit)const;
|
||||
|
||||
/**
|
||||
* @brief Fetch all objects relevant to the specified accounts and subscribe to updates
|
||||
* @param callback Function to call with updates
|
||||
* @param names_or_ids Each item must be the name or ID of an account to retrieve
|
||||
* @return Map of string from @ref names_or_ids to the corresponding account
|
||||
*
|
||||
* This function fetches all relevant objects for the given accounts, and subscribes to updates to the given
|
||||
* accounts. If any of the strings in @ref names_or_ids cannot be tied to an account, that input will be
|
||||
* ignored. All other accounts will be retrieved and subscribed.
|
||||
*
|
||||
*/
|
||||
std::map<string,full_account> get_full_accounts( const vector<string>& names_or_ids, bool subscribe );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get limit orders in a given market
|
||||
* @param a ID of asset being sold
|
||||
* @param b ID of asset being purchased
|
||||
* @param limit Maximum number of orders to retrieve
|
||||
* @return The limit orders, ordered from least price to greatest
|
||||
*/
|
||||
vector<limit_order_object> get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const;
|
||||
/**
|
||||
* @brief Get call orders in a given asset
|
||||
* @param a ID of asset being called
|
||||
* @param limit Maximum number of orders to retrieve
|
||||
* @return The call orders, ordered from earliest to be called to latest
|
||||
*/
|
||||
vector<call_order_object> get_call_orders(asset_id_type a, uint32_t limit)const;
|
||||
/**
|
||||
* @brief Get forced settlement orders in a given asset
|
||||
* @param a ID of asset being settled
|
||||
* @param limit Maximum number of orders to retrieve
|
||||
* @return The settle orders, ordered from earliest settlement date to latest
|
||||
*/
|
||||
vector<force_settlement_object> get_settle_orders(asset_id_type a, uint32_t limit)const;
|
||||
|
||||
/**
|
||||
* @brief Get assets alphabetically by symbol name
|
||||
* @param lower_bound_symbol Lower bound of symbol names to retrieve
|
||||
* @param limit Maximum number of assets to fetch (must not exceed 100)
|
||||
* @return The assets found
|
||||
*/
|
||||
vector<asset_object> list_assets(const string& lower_bound_symbol, uint32_t limit)const;
|
||||
|
||||
/**
|
||||
* @brief Get the committee_member owned by a given account
|
||||
* @param account The ID of the account whose committee_member should be retrieved
|
||||
* @return The committee_member object, or null if the account does not have a committee_member
|
||||
*/
|
||||
fc::optional<committee_member_object> get_committee_member_by_account(account_id_type account)const;
|
||||
/**
|
||||
* @brief Get the witness owned by a given account
|
||||
* @param account The ID of the account whose witness should be retrieved
|
||||
* @return The witness object, or null if the account does not have a witness
|
||||
*/
|
||||
fc::optional<witness_object> get_witness_by_account(account_id_type account)const;
|
||||
|
||||
/**
|
||||
* @brief Given a set of votes, return the objects they are voting for.
|
||||
*
|
||||
* This will be a mixture of committee_member_object, witness_objects, and worker_objects
|
||||
*
|
||||
* The results will be in the same order as the votes. Null will be returned for
|
||||
* any vote ids that are not found.
|
||||
*/
|
||||
vector<variant> lookup_vote_ids( const vector<vote_id_type>& votes )const;
|
||||
|
||||
/**
|
||||
* @brief Get the total number of witnesses registered with the blockchain
|
||||
*/
|
||||
uint64_t get_witness_count()const;
|
||||
|
||||
/**
|
||||
* @brief Get names and IDs for registered witnesses
|
||||
* @param lower_bound_name Lower bound of the first name to return
|
||||
* @param limit Maximum number of results to return -- must not exceed 1000
|
||||
* @return Map of witness names to corresponding IDs
|
||||
*/
|
||||
map<string, witness_id_type> lookup_witness_accounts(const string& lower_bound_name, uint32_t limit)const;
|
||||
|
||||
/**
|
||||
* @brief Get names and IDs for registered committee_members
|
||||
* @param lower_bound_name Lower bound of the first name to return
|
||||
* @param limit Maximum number of results to return -- must not exceed 1000
|
||||
* @return Map of committee_member names to corresponding IDs
|
||||
*/
|
||||
map<string, committee_member_id_type> lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const;
|
||||
|
||||
/**
|
||||
* @brief Get a list of witnesses by ID
|
||||
* @param witness_ids IDs of the witnesses to retrieve
|
||||
* @return The witnesses corresponding to the provided IDs
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<witness_object>> get_witnesses(const vector<witness_id_type>& witness_ids)const;
|
||||
|
||||
/**
|
||||
* @brief Get a list of committee_members by ID
|
||||
* @param committee_member_ids IDs of the committee_members to retrieve
|
||||
* @return The committee_members corresponding to the provided IDs
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<committee_member_object>> get_committee_members(const vector<committee_member_id_type>& committee_member_ids)const;
|
||||
|
||||
/**
|
||||
* @brief Request notification when the active orders in the market between two assets changes
|
||||
* @param callback Callback method which is called when the market changes
|
||||
* @param a First asset ID
|
||||
* @param b Second asset ID
|
||||
*
|
||||
* Callback will be passed a variant containing a vector<pair<operation, operation_result>>. The vector will
|
||||
* contain, in order, the operations which changed the market, and their results.
|
||||
*/
|
||||
void subscribe_to_market(std::function<void(const variant&)> callback,
|
||||
asset_id_type a, asset_id_type b);
|
||||
/**
|
||||
* @brief Unsubscribe from updates to a given market
|
||||
* @param a First asset ID
|
||||
* @param b Second asset ID
|
||||
*/
|
||||
void unsubscribe_from_market(asset_id_type a, asset_id_type b);
|
||||
/**
|
||||
* @brief Stop receiving any notifications
|
||||
*
|
||||
* This unsubscribes from all subscribed markets and objects.
|
||||
*/
|
||||
void cancel_all_subscriptions()
|
||||
{ set_subscribe_callback( std::function<void(const fc::variant&)>(), true); _market_subscriptions.clear(); }
|
||||
|
||||
/// @brief Get a hexdump of the serialized binary form of a transaction
|
||||
std::string get_transaction_hex(const signed_transaction& trx)const;
|
||||
|
||||
/**
|
||||
* @return the set of proposed transactions relevant to the specified account id.
|
||||
*/
|
||||
vector<proposal_object> get_proposed_transactions( account_id_type id )const;
|
||||
|
||||
/**
|
||||
* @return all accounts that referr to the key or account id in their owner or active authorities.
|
||||
*/
|
||||
vector<account_id_type> get_account_references( account_id_type account_id )const;
|
||||
vector<vector<account_id_type>> get_key_references( vector<public_key_type> key )const;
|
||||
|
||||
/**
|
||||
* @return all open margin positions for a given account id.
|
||||
*/
|
||||
vector<call_order_object> get_margin_positions( const account_id_type& id )const;
|
||||
|
||||
/** @return all unclaimed balance objects for a set of addresses */
|
||||
vector<balance_object> get_balance_objects( const vector<address>& addrs )const;
|
||||
|
||||
vector<asset> get_vested_balances( const vector<balance_id_type>& objs )const;
|
||||
|
||||
vector<vesting_balance_object> get_vesting_balances( account_id_type account_id )const;
|
||||
|
||||
/**
|
||||
* This API will take a partially signed transaction and a set of public keys that the owner has the ability to sign for
|
||||
* and return the minimal subset of public keys that should add signatures to the transaction.
|
||||
*/
|
||||
set<public_key_type> get_required_signatures( const signed_transaction& trx, const flat_set<public_key_type>& available_keys )const;
|
||||
|
||||
/**
|
||||
* This method will return the set of all public keys that could possibly sign for a given transaction. This call can
|
||||
* be used by wallets to filter their set of public keys to just the relevant subset prior to calling @ref get_required_signatures
|
||||
* to get the minimum subset.
|
||||
*/
|
||||
set<public_key_type> get_potential_signatures( const signed_transaction& trx )const;
|
||||
|
||||
/**
|
||||
* @return true of the @ref trx has all of the required signatures, otherwise throws an exception
|
||||
*/
|
||||
bool verify_authority( const signed_transaction& trx )const;
|
||||
|
||||
/**
|
||||
* @return true if the signers have enough authority to authorize an account
|
||||
*/
|
||||
bool verify_account_authority( const string& name_or_id, const flat_set<public_key_type>& signers )const;
|
||||
|
||||
/**
|
||||
* Validates a transaction against the current state without broadcast it on the network.
|
||||
*/
|
||||
processed_transaction validate_transaction( const signed_transaction& trx )const;
|
||||
|
||||
|
||||
/**
|
||||
* @return the set of blinded balance objects by commitment ID
|
||||
*/
|
||||
vector<blinded_balance_object> get_blinded_balances( const flat_set<commitment_type>& commitments )const;
|
||||
|
||||
|
||||
/**
|
||||
* For each operation calculate the required fee in the specified asset type. If the asset type does
|
||||
* not have a valid core_exchange_rate
|
||||
*/
|
||||
vector<asset> get_required_fees( const vector<operation>& ops, asset_id_type id = asset_id_type() )const;
|
||||
|
||||
void set_subscribe_callback( std::function<void(const variant&)> cb, bool clear_filter );
|
||||
void set_pending_transaction_callback( std::function<void(const variant&)> cb ){ _pending_trx_callback = cb; }
|
||||
void set_block_applied_callback( std::function<void(const variant& block_id)> cb ){ _block_applied_callback = cb; }
|
||||
private:
|
||||
template<typename T>
|
||||
void subscribe_to_item( const T& i )const
|
||||
{
|
||||
auto vec = fc::raw::pack(i);
|
||||
if( !_subscribe_callback ) return;
|
||||
|
||||
if( !is_subscribed_to_item(i) )
|
||||
{
|
||||
idump((i));
|
||||
_subscribe_filter.insert( vec.data(), vec.size() );//(vecconst char*)&i, sizeof(i) );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool is_subscribed_to_item( const T& i )const
|
||||
{
|
||||
if( !_subscribe_callback ) return false;
|
||||
return true;
|
||||
return _subscribe_filter.contains( i );
|
||||
}
|
||||
void broadcast_updates( const vector<variant>& updates );
|
||||
|
||||
/** called every time a block is applied to report the objects that were changed */
|
||||
void on_objects_changed(const vector<object_id_type>& ids);
|
||||
void on_objects_removed(const vector<const object*>& objs);
|
||||
void on_applied_block();
|
||||
|
||||
mutable fc::bloom_filter _subscribe_filter;
|
||||
std::function<void(const fc::variant&)> _subscribe_callback;
|
||||
std::function<void(const fc::variant&)> _pending_trx_callback;
|
||||
std::function<void(const fc::variant&)> _block_applied_callback;
|
||||
|
||||
boost::signals2::scoped_connection _change_connection;
|
||||
boost::signals2::scoped_connection _removed_connection;
|
||||
boost::signals2::scoped_connection _applied_block_connection;
|
||||
boost::signals2::scoped_connection _pending_trx_connection;
|
||||
map< pair<asset_id_type,asset_id_type>, std::function<void(const variant&)> > _market_subscriptions;
|
||||
graphene::chain::database& _db;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The history_api class implements the RPC API for account history
|
||||
*
|
||||
|
|
@ -558,59 +192,6 @@ namespace graphene { namespace app {
|
|||
FC_REFLECT( graphene::app::network_broadcast_api::transaction_confirmation,
|
||||
(id)(block_num)(trx_num)(trx) )
|
||||
|
||||
FC_API(graphene::app::database_api,
|
||||
(get_objects)
|
||||
(get_block_header)
|
||||
(get_block)
|
||||
(get_transaction)
|
||||
(get_chain_properties)
|
||||
(get_global_properties)
|
||||
(get_chain_id)
|
||||
(get_dynamic_global_properties)
|
||||
(get_accounts)
|
||||
(get_assets)
|
||||
(lookup_account_names)
|
||||
(get_account_by_name)
|
||||
(get_account_count)
|
||||
(lookup_accounts)
|
||||
(get_full_accounts)
|
||||
(get_account_balances)
|
||||
(get_named_account_balances)
|
||||
(lookup_asset_symbols)
|
||||
(get_limit_orders)
|
||||
(get_call_orders)
|
||||
(get_settle_orders)
|
||||
(list_assets)
|
||||
(get_committee_member_by_account)
|
||||
(get_witnesses)
|
||||
(get_committee_members)
|
||||
(get_witness_by_account)
|
||||
(lookup_vote_ids)
|
||||
(get_witness_count)
|
||||
(lookup_witness_accounts)
|
||||
(lookup_committee_member_accounts)
|
||||
(subscribe_to_market)
|
||||
(unsubscribe_from_market)
|
||||
(cancel_all_subscriptions)
|
||||
(get_transaction_hex)
|
||||
(get_proposed_transactions)
|
||||
(get_account_references)
|
||||
(get_key_references)
|
||||
(get_margin_positions)
|
||||
(get_balance_objects)
|
||||
(get_vested_balances)
|
||||
(get_vesting_balances)
|
||||
(get_required_signatures)
|
||||
(get_potential_signatures)
|
||||
(verify_authority)
|
||||
(verify_account_authority)
|
||||
(get_blinded_balances)
|
||||
(get_required_fees)
|
||||
(set_subscribe_callback)
|
||||
(set_pending_transaction_callback)
|
||||
(set_block_applied_callback)
|
||||
(validate_transaction)
|
||||
)
|
||||
FC_API(graphene::app::history_api,
|
||||
(get_account_history)
|
||||
(get_market_history)
|
||||
|
|
|
|||
537
libraries/app/include/graphene/app/database_api.hpp
Normal file
537
libraries/app/include/graphene/app/database_api.hpp
Normal file
|
|
@ -0,0 +1,537 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <graphene/app/full_account.hpp>
|
||||
|
||||
#include <graphene/chain/protocol/types.hpp>
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/balance_object.hpp>
|
||||
#include <graphene/chain/chain_property_object.hpp>
|
||||
#include <graphene/chain/committee_member_object.hpp>
|
||||
#include <graphene/chain/market_evaluator.hpp>
|
||||
#include <graphene/chain/operation_history_object.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
#include <graphene/chain/confidential_evaluator.hpp>
|
||||
|
||||
#include <fc/api.hpp>
|
||||
#include <fc/optional.hpp>
|
||||
#include <fc/variant_object.hpp>
|
||||
|
||||
#include <fc/network/ip.hpp>
|
||||
|
||||
#include <boost/container/flat_set.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace graphene { namespace app {
|
||||
|
||||
using namespace graphene::chain;
|
||||
using namespace std;
|
||||
|
||||
class database_api_impl;
|
||||
|
||||
/**
|
||||
* @brief The database_api class implements the RPC API for the chain database.
|
||||
*
|
||||
* This API exposes accessors on the database which query state tracked by a blockchain validating node. This API is
|
||||
* read-only; all modifications to the database must be performed via transactions. Transactions are broadcast via
|
||||
* the @ref network_broadcast_api.
|
||||
*/
|
||||
class database_api
|
||||
{
|
||||
public:
|
||||
database_api(graphene::chain::database& db);
|
||||
~database_api();
|
||||
|
||||
/////////////
|
||||
// Objects //
|
||||
/////////////
|
||||
|
||||
/**
|
||||
* @brief Get the objects corresponding to the provided IDs
|
||||
* @param ids IDs of the objects to retrieve
|
||||
* @return The objects retrieved, in the order they are mentioned in ids
|
||||
*
|
||||
* If any of the provided IDs does not map to an object, a null variant is returned in its position.
|
||||
*/
|
||||
fc::variants get_objects(const vector<object_id_type>& ids)const;
|
||||
|
||||
///////////////////
|
||||
// Subscriptions //
|
||||
///////////////////
|
||||
|
||||
void set_subscribe_callback( std::function<void(const variant&)> cb, bool clear_filter );
|
||||
void set_pending_transaction_callback( std::function<void(const variant&)> cb );
|
||||
void set_block_applied_callback( std::function<void(const variant& block_id)> cb );
|
||||
/**
|
||||
* @brief Stop receiving any notifications
|
||||
*
|
||||
* This unsubscribes from all subscribed markets and objects.
|
||||
*/
|
||||
void cancel_all_subscriptions();
|
||||
|
||||
/////////////////////////////
|
||||
// Blocks and transactions //
|
||||
/////////////////////////////
|
||||
|
||||
/**
|
||||
* @brief Retrieve a block header
|
||||
* @param block_num Height of the block whose header should be returned
|
||||
* @return header of the referenced block, or null if no matching block was found
|
||||
*/
|
||||
optional<block_header> get_block_header(uint32_t block_num)const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve a full, signed block
|
||||
* @param block_num Height of the block to be returned
|
||||
* @return the referenced block, or null if no matching block was found
|
||||
*/
|
||||
optional<signed_block> get_block(uint32_t block_num)const;
|
||||
|
||||
/**
|
||||
* @brief used to fetch an individual transaction.
|
||||
*/
|
||||
processed_transaction get_transaction( uint32_t block_num, uint32_t trx_in_block )const;
|
||||
|
||||
/////////////
|
||||
// Globals //
|
||||
/////////////
|
||||
|
||||
/**
|
||||
* @brief Retrieve the @ref chain_property_object associated with the chain
|
||||
*/
|
||||
chain_property_object get_chain_properties()const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve the current @ref global_property_object
|
||||
*/
|
||||
global_property_object get_global_properties()const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve compile-time constants
|
||||
*/
|
||||
fc::variant_object get_config()const;
|
||||
|
||||
/**
|
||||
* @brief Get the chain ID
|
||||
*/
|
||||
chain_id_type get_chain_id()const;
|
||||
|
||||
/**
|
||||
* @brief Retrieve the current @ref dynamic_global_property_object
|
||||
*/
|
||||
dynamic_global_property_object get_dynamic_global_properties()const;
|
||||
|
||||
//////////
|
||||
// Keys //
|
||||
//////////
|
||||
|
||||
vector<vector<account_id_type>> get_key_references( vector<public_key_type> key )const;
|
||||
|
||||
//////////////
|
||||
// Accounts //
|
||||
//////////////
|
||||
|
||||
/**
|
||||
* @brief Get a list of accounts by ID
|
||||
* @param account_ids IDs of the accounts to retrieve
|
||||
* @return The accounts corresponding to the provided IDs
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<account_object>> get_accounts(const vector<account_id_type>& account_ids)const;
|
||||
|
||||
/**
|
||||
* @brief Fetch all objects relevant to the specified accounts and subscribe to updates
|
||||
* @param callback Function to call with updates
|
||||
* @param names_or_ids Each item must be the name or ID of an account to retrieve
|
||||
* @return Map of string from @ref names_or_ids to the corresponding account
|
||||
*
|
||||
* This function fetches all relevant objects for the given accounts, and subscribes to updates to the given
|
||||
* accounts. If any of the strings in @ref names_or_ids cannot be tied to an account, that input will be
|
||||
* ignored. All other accounts will be retrieved and subscribed.
|
||||
*
|
||||
*/
|
||||
std::map<string,full_account> get_full_accounts( const vector<string>& names_or_ids, bool subscribe );
|
||||
|
||||
optional<account_object> get_account_by_name( string name )const;
|
||||
|
||||
/**
|
||||
* @return all accounts that referr to the key or account id in their owner or active authorities.
|
||||
*/
|
||||
vector<account_id_type> get_account_references( account_id_type account_id )const;
|
||||
|
||||
/**
|
||||
* @brief Get a list of accounts by name
|
||||
* @param account_names Names of the accounts to retrieve
|
||||
* @return The accounts holding the provided names
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<account_object>> lookup_account_names(const vector<string>& account_names)const;
|
||||
|
||||
/**
|
||||
* @brief Get names and IDs for registered accounts
|
||||
* @param lower_bound_name Lower bound of the first name to return
|
||||
* @param limit Maximum number of results to return -- must not exceed 1000
|
||||
* @return Map of account names to corresponding IDs
|
||||
*/
|
||||
map<string,account_id_type> lookup_accounts(const string& lower_bound_name, uint32_t limit)const;
|
||||
|
||||
//////////////
|
||||
// Balances //
|
||||
//////////////
|
||||
|
||||
/**
|
||||
* @brief Get an account's balances in various assets
|
||||
* @param id ID of the account to get balances for
|
||||
* @param assets IDs of the assets to get balances of; if empty, get all assets account has a balance in
|
||||
* @return Balances of the account
|
||||
*/
|
||||
vector<asset> get_account_balances(account_id_type id, const flat_set<asset_id_type>& assets)const;
|
||||
|
||||
/// Semantically equivalent to @ref get_account_balances, but takes a name instead of an ID.
|
||||
vector<asset> get_named_account_balances(const std::string& name, const flat_set<asset_id_type>& assets)const;
|
||||
|
||||
/** @return all unclaimed balance objects for a set of addresses */
|
||||
vector<balance_object> get_balance_objects( const vector<address>& addrs )const;
|
||||
|
||||
vector<asset> get_vested_balances( const vector<balance_id_type>& objs )const;
|
||||
|
||||
vector<vesting_balance_object> get_vesting_balances( account_id_type account_id )const;
|
||||
|
||||
/**
|
||||
* @brief Get the total number of accounts registered with the blockchain
|
||||
*/
|
||||
uint64_t get_account_count()const;
|
||||
|
||||
////////////
|
||||
// Assets //
|
||||
////////////
|
||||
|
||||
/**
|
||||
* @brief Get a list of assets by ID
|
||||
* @param asset_ids IDs of the assets to retrieve
|
||||
* @return The assets corresponding to the provided IDs
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<asset_object>> get_assets(const vector<asset_id_type>& asset_ids)const;
|
||||
|
||||
/**
|
||||
* @brief Get assets alphabetically by symbol name
|
||||
* @param lower_bound_symbol Lower bound of symbol names to retrieve
|
||||
* @param limit Maximum number of assets to fetch (must not exceed 100)
|
||||
* @return The assets found
|
||||
*/
|
||||
vector<asset_object> list_assets(const string& lower_bound_symbol, uint32_t limit)const;
|
||||
|
||||
/**
|
||||
* @brief Get a list of assets by symbol
|
||||
* @param asset_symbols Symbols or stringified IDs of the assets to retrieve
|
||||
* @return The assets corresponding to the provided symbols or IDs
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<asset_object>> lookup_asset_symbols(const vector<string>& symbols_or_ids)const;
|
||||
|
||||
/////////////////////
|
||||
// Markets / feeds //
|
||||
/////////////////////
|
||||
|
||||
/**
|
||||
* @brief Get limit orders in a given market
|
||||
* @param a ID of asset being sold
|
||||
* @param b ID of asset being purchased
|
||||
* @param limit Maximum number of orders to retrieve
|
||||
* @return The limit orders, ordered from least price to greatest
|
||||
*/
|
||||
vector<limit_order_object> get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const;
|
||||
|
||||
/**
|
||||
* @brief Get call orders in a given asset
|
||||
* @param a ID of asset being called
|
||||
* @param limit Maximum number of orders to retrieve
|
||||
* @return The call orders, ordered from earliest to be called to latest
|
||||
*/
|
||||
vector<call_order_object> get_call_orders(asset_id_type a, uint32_t limit)const;
|
||||
|
||||
/**
|
||||
* @brief Get forced settlement orders in a given asset
|
||||
* @param a ID of asset being settled
|
||||
* @param limit Maximum number of orders to retrieve
|
||||
* @return The settle orders, ordered from earliest settlement date to latest
|
||||
*/
|
||||
vector<force_settlement_object> get_settle_orders(asset_id_type a, uint32_t limit)const;
|
||||
|
||||
/**
|
||||
* @return all open margin positions for a given account id.
|
||||
*/
|
||||
vector<call_order_object> get_margin_positions( const account_id_type& id )const;
|
||||
|
||||
/**
|
||||
* @brief Request notification when the active orders in the market between two assets changes
|
||||
* @param callback Callback method which is called when the market changes
|
||||
* @param a First asset ID
|
||||
* @param b Second asset ID
|
||||
*
|
||||
* Callback will be passed a variant containing a vector<pair<operation, operation_result>>. The vector will
|
||||
* contain, in order, the operations which changed the market, and their results.
|
||||
*/
|
||||
void subscribe_to_market(std::function<void(const variant&)> callback,
|
||||
asset_id_type a, asset_id_type b);
|
||||
|
||||
/**
|
||||
* @brief Unsubscribe from updates to a given market
|
||||
* @param a First asset ID
|
||||
* @param b Second asset ID
|
||||
*/
|
||||
void unsubscribe_from_market(asset_id_type a, asset_id_type b);
|
||||
|
||||
///////////////
|
||||
// Witnesses //
|
||||
///////////////
|
||||
|
||||
/**
|
||||
* @brief Get a list of witnesses by ID
|
||||
* @param witness_ids IDs of the witnesses to retrieve
|
||||
* @return The witnesses corresponding to the provided IDs
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<witness_object>> get_witnesses(const vector<witness_id_type>& witness_ids)const;
|
||||
|
||||
/**
|
||||
* @brief Get the witness owned by a given account
|
||||
* @param account The ID of the account whose witness should be retrieved
|
||||
* @return The witness object, or null if the account does not have a witness
|
||||
*/
|
||||
fc::optional<witness_object> get_witness_by_account(account_id_type account)const;
|
||||
|
||||
/**
|
||||
* @brief Get names and IDs for registered witnesses
|
||||
* @param lower_bound_name Lower bound of the first name to return
|
||||
* @param limit Maximum number of results to return -- must not exceed 1000
|
||||
* @return Map of witness names to corresponding IDs
|
||||
*/
|
||||
map<string, witness_id_type> lookup_witness_accounts(const string& lower_bound_name, uint32_t limit)const;
|
||||
|
||||
/**
|
||||
* @brief Get the total number of witnesses registered with the blockchain
|
||||
*/
|
||||
uint64_t get_witness_count()const;
|
||||
|
||||
///////////////////////
|
||||
// Committee members //
|
||||
///////////////////////
|
||||
|
||||
/**
|
||||
* @brief Get a list of committee_members by ID
|
||||
* @param committee_member_ids IDs of the committee_members to retrieve
|
||||
* @return The committee_members corresponding to the provided IDs
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<committee_member_object>> get_committee_members(const vector<committee_member_id_type>& committee_member_ids)const;
|
||||
|
||||
/**
|
||||
* @brief Get the committee_member owned by a given account
|
||||
* @param account The ID of the account whose committee_member should be retrieved
|
||||
* @return The committee_member object, or null if the account does not have a committee_member
|
||||
*/
|
||||
fc::optional<committee_member_object> get_committee_member_by_account(account_id_type account)const;
|
||||
|
||||
/**
|
||||
* @brief Get names and IDs for registered committee_members
|
||||
* @param lower_bound_name Lower bound of the first name to return
|
||||
* @param limit Maximum number of results to return -- must not exceed 1000
|
||||
* @return Map of committee_member names to corresponding IDs
|
||||
*/
|
||||
map<string, committee_member_id_type> lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const;
|
||||
|
||||
///////////
|
||||
// Votes //
|
||||
///////////
|
||||
|
||||
/**
|
||||
* @brief Given a set of votes, return the objects they are voting for.
|
||||
*
|
||||
* This will be a mixture of committee_member_object, witness_objects, and worker_objects
|
||||
*
|
||||
* The results will be in the same order as the votes. Null will be returned for
|
||||
* any vote ids that are not found.
|
||||
*/
|
||||
vector<variant> lookup_vote_ids( const vector<vote_id_type>& votes )const;
|
||||
|
||||
////////////////////////////
|
||||
// Authority / validation //
|
||||
////////////////////////////
|
||||
|
||||
/// @brief Get a hexdump of the serialized binary form of a transaction
|
||||
std::string get_transaction_hex(const signed_transaction& trx)const;
|
||||
|
||||
/**
|
||||
* This API will take a partially signed transaction and a set of public keys that the owner has the ability to sign for
|
||||
* and return the minimal subset of public keys that should add signatures to the transaction.
|
||||
*/
|
||||
set<public_key_type> get_required_signatures( const signed_transaction& trx, const flat_set<public_key_type>& available_keys )const;
|
||||
|
||||
/**
|
||||
* This method will return the set of all public keys that could possibly sign for a given transaction. This call can
|
||||
* be used by wallets to filter their set of public keys to just the relevant subset prior to calling @ref get_required_signatures
|
||||
* to get the minimum subset.
|
||||
*/
|
||||
set<public_key_type> get_potential_signatures( const signed_transaction& trx )const;
|
||||
|
||||
/**
|
||||
* @return true of the @ref trx has all of the required signatures, otherwise throws an exception
|
||||
*/
|
||||
bool verify_authority( const signed_transaction& trx )const;
|
||||
|
||||
/**
|
||||
* @return true if the signers have enough authority to authorize an account
|
||||
*/
|
||||
bool verify_account_authority( const string& name_or_id, const flat_set<public_key_type>& signers )const;
|
||||
|
||||
/**
|
||||
* Validates a transaction against the current state without broadcasting it on the network.
|
||||
*/
|
||||
processed_transaction validate_transaction( const signed_transaction& trx )const;
|
||||
|
||||
/**
|
||||
* For each operation calculate the required fee in the specified asset type. If the asset type does
|
||||
* not have a valid core_exchange_rate
|
||||
*/
|
||||
vector<asset> get_required_fees( const vector<operation>& ops, asset_id_type id )const;
|
||||
|
||||
///////////////////////////
|
||||
// Proposed transactions //
|
||||
///////////////////////////
|
||||
|
||||
/**
|
||||
* @return the set of proposed transactions relevant to the specified account id.
|
||||
*/
|
||||
vector<proposal_object> get_proposed_transactions( account_id_type id )const;
|
||||
|
||||
//////////////////////
|
||||
// Blinded balances //
|
||||
//////////////////////
|
||||
|
||||
/**
|
||||
* @return the set of blinded balance objects by commitment ID
|
||||
*/
|
||||
vector<blinded_balance_object> get_blinded_balances( const flat_set<commitment_type>& commitments )const;
|
||||
|
||||
private:
|
||||
std::shared_ptr< database_api_impl > my;
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
FC_API(graphene::app::database_api,
|
||||
// Objects
|
||||
(get_objects)
|
||||
|
||||
// Subscriptions
|
||||
(set_subscribe_callback)
|
||||
(set_pending_transaction_callback)
|
||||
(set_block_applied_callback)
|
||||
(cancel_all_subscriptions)
|
||||
|
||||
// Blocks and transactions
|
||||
(get_block_header)
|
||||
(get_block)
|
||||
(get_transaction)
|
||||
|
||||
// Globals
|
||||
(get_chain_properties)
|
||||
(get_global_properties)
|
||||
(get_config)
|
||||
(get_chain_id)
|
||||
(get_dynamic_global_properties)
|
||||
|
||||
// Keys
|
||||
(get_key_references)
|
||||
|
||||
// Accounts
|
||||
(get_accounts)
|
||||
(get_full_accounts)
|
||||
(get_account_by_name)
|
||||
(get_account_references)
|
||||
(lookup_account_names)
|
||||
(lookup_accounts)
|
||||
(get_account_count)
|
||||
|
||||
// Balances
|
||||
(get_account_balances)
|
||||
(get_named_account_balances)
|
||||
(get_balance_objects)
|
||||
(get_vested_balances)
|
||||
(get_vesting_balances)
|
||||
|
||||
// Assets
|
||||
(get_assets)
|
||||
(list_assets)
|
||||
(lookup_asset_symbols)
|
||||
|
||||
// Markets / feeds
|
||||
(get_limit_orders)
|
||||
(get_call_orders)
|
||||
(get_settle_orders)
|
||||
(get_margin_positions)
|
||||
(subscribe_to_market)
|
||||
(unsubscribe_from_market)
|
||||
|
||||
// Witnesses
|
||||
(get_witnesses)
|
||||
(get_witness_by_account)
|
||||
(lookup_witness_accounts)
|
||||
(get_witness_count)
|
||||
|
||||
// Committee members
|
||||
(get_committee_members)
|
||||
(get_committee_member_by_account)
|
||||
(lookup_committee_member_accounts)
|
||||
|
||||
// Votes
|
||||
(lookup_vote_ids)
|
||||
|
||||
// Authority / validation
|
||||
(get_transaction_hex)
|
||||
(get_required_signatures)
|
||||
(get_potential_signatures)
|
||||
(verify_authority)
|
||||
(verify_account_authority)
|
||||
(validate_transaction)
|
||||
(get_required_fees)
|
||||
|
||||
// Proposed transactions
|
||||
(get_proposed_transactions)
|
||||
|
||||
// Blinded balances
|
||||
(get_blinded_balances)
|
||||
)
|
||||
|
|
@ -588,7 +588,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
|||
|
||||
// Set active witnesses
|
||||
modify(get_global_properties(), [&](global_property_object& p) {
|
||||
for( int i = 1; i <= genesis_state.initial_active_witnesses; ++i )
|
||||
for( uint32_t i = 1; i <= genesis_state.initial_active_witnesses; ++i )
|
||||
{
|
||||
p.active_witnesses.insert(i);
|
||||
p.witness_accounts.insert(get(witness_id_type(i)).witness_account);
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ void database::pay_workers( share_type& budget )
|
|||
return wa.id < wb.id;
|
||||
});
|
||||
|
||||
for( int i = 0; i < active_workers.size() && budget > 0; ++i )
|
||||
for( uint32_t i = 0; i < active_workers.size() && budget > 0; ++i )
|
||||
{
|
||||
const worker_object& active_worker = active_workers[i];
|
||||
share_type requested_pay = active_worker.daily_pay;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,12 @@ namespace graphene { namespace chain {
|
|||
|
||||
explicit operator std::string()const; ///< converts to base58 + checksum
|
||||
|
||||
friend size_t hash_value( const address& v ) { return *((size_t*)&v.addr._hash[2]); }
|
||||
friend size_t hash_value( const address& v ) {
|
||||
const void* tmp = static_cast<const void*>(v.addr._hash+2);
|
||||
|
||||
const size_t* tmp2 = reinterpret_cast<const size_t*>(tmp);
|
||||
return *tmp2;
|
||||
}
|
||||
fc::ripemd160 addr;
|
||||
};
|
||||
inline bool operator == ( const address& a, const address& b ) { return a.addr == b.addr; }
|
||||
|
|
|
|||
|
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/transaction_evaluation_state.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/committee_member_object.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/exceptions.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
/*
|
||||
bool transaction_evaluation_state::check_authority( const account_object& account, authority::classification auth_class, int depth )
|
||||
{
|
||||
if( (!_is_proposed_trx) && (_db->get_node_properties().skip_flags & database::skip_authority_check) )
|
||||
return true;
|
||||
if( (!_is_proposed_trx) && (_db->get_node_properties().skip_flags & database::skip_transaction_signatures) )
|
||||
return true;
|
||||
if( account.get_id() == GRAPHENE_TEMP_ACCOUNT ||
|
||||
approved_by.find(make_pair(account.id, auth_class)) != approved_by.end() )
|
||||
return true;
|
||||
|
||||
FC_ASSERT( account.id.instance() != 0 || _is_proposed_trx, "", ("account",account)("is_proposed",_is_proposed_trx) );
|
||||
|
||||
bool valid = false;
|
||||
switch( auth_class )
|
||||
{
|
||||
case authority::owner:
|
||||
valid = check_authority( account.owner, auth_class, depth );
|
||||
break;
|
||||
case authority::active:
|
||||
valid = check_authority( account.active, auth_class, depth );
|
||||
break;
|
||||
default:
|
||||
FC_ASSERT( false, "Invalid Account Auth Class" );
|
||||
};
|
||||
if( valid )
|
||||
approved_by.insert( std::make_pair(account.id, auth_class) );
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool transaction_evaluation_state::check_authority( const authority& au, authority::classification auth_class, int depth )
|
||||
{ try {
|
||||
if( (!_is_proposed_trx) && (_db->get_node_properties().skip_flags & database::skip_authority_check) )
|
||||
return true;
|
||||
if( (!_is_proposed_trx) && (_db->get_node_properties().skip_flags & database::skip_transaction_signatures) )
|
||||
return true;
|
||||
|
||||
uint32_t total_weight = 0;
|
||||
|
||||
for( const auto& key : au.key_auths )
|
||||
{
|
||||
if( signed_by( key.first ) )
|
||||
{
|
||||
total_weight += key.second;
|
||||
if( total_weight >= au.weight_threshold )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for( const auto& key : au.address_auths )
|
||||
{
|
||||
if( signed_by( key.first ) )
|
||||
{
|
||||
total_weight += key.second;
|
||||
if( total_weight >= au.weight_threshold )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for( const auto& auth : au.account_auths )
|
||||
{
|
||||
if( approved_by.find( std::make_pair(auth.first,auth_class) ) != approved_by.end() )
|
||||
{
|
||||
total_weight += auth.second;
|
||||
if( total_weight >= au.weight_threshold )
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( depth == GRAPHENE_MAX_SIG_CHECK_DEPTH )
|
||||
{
|
||||
//elog("Failing authority verification due to recursion depth.");
|
||||
return false;
|
||||
}
|
||||
const account_object& acnt = auth.first(*_db);
|
||||
if( check_authority( acnt, auth_class, depth + 1 ) )
|
||||
{
|
||||
approved_by.insert( std::make_pair(acnt.id,auth_class) );
|
||||
total_weight += auth.second;
|
||||
if( total_weight >= au.weight_threshold )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total_weight >= au.weight_threshold;
|
||||
} FC_CAPTURE_AND_RETHROW( (au)(auth_class)(depth) ) }
|
||||
|
||||
bool transaction_evaluation_state::signed_by(const public_key_type& k)
|
||||
{
|
||||
auto itr = _sigs.find(k);
|
||||
return itr != _sigs.end() && (itr->second = true);
|
||||
}
|
||||
|
||||
bool transaction_evaluation_state::signed_by(const address& k)
|
||||
{
|
||||
for( auto itr = _sigs.begin(); itr != _sigs.end(); ++itr )
|
||||
if( itr->first == k ) return itr->second = true;
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
} } // namespace graphene::chain
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 19e42ac4c41d0a2bbdc8094c2efeed5e28e0ed75
|
||||
Subproject commit 483b348878f284c474511db05e120466ffbfc132
|
||||
Loading…
Reference in a new issue