Merge commit '9466d2096a370e15aff70842b48feeca4a941e5c' into betting

This commit is contained in:
Eric Frias 2017-06-21 14:54:05 -04:00
commit 51fb13f8ba
11 changed files with 527 additions and 167 deletions

View file

@ -36,8 +36,11 @@ To build after all dependencies are installed:
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .
make
Alternate Boost versions can be specified using the `DBOOST_ROOT` CMake argument. After building, the witness node can
be launched with:
**NOTE:** BitShares requires a [Boost](http://www.boost.org/) version in the range [1.57, 1.60]. Versions earlier than
1.57 or newer than 1.60 are NOT supported. If your system Boost version is newer, then you will need to manually build
an older version of Boost and specify it to CMake using `DBOOST_ROOT`.
After building, the witness node can be launched with:
./programs/witness_node/witness_node

2
docs

@ -1 +1 @@
Subproject commit 474c28bc7181739f25229b45b76646a693cad998
Subproject commit 981d1ef1eb35e89bb9a9423c1762427fe8ef07cc

View file

@ -1 +1 @@
2.0.170224
2.0.170328

View file

@ -173,6 +173,16 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
return _subscribe_filter.contains( i );
}
bool is_impacted_account( const flat_set<account_id_type>& accounts)
{
if( !_subscribed_accounts.size() || !accounts.size() )
return false;
return std::any_of(accounts.begin(), accounts.end(), [this](const account_id_type& account) {
return _subscribed_accounts.find(account) != _subscribed_accounts.end();
});
}
template<typename T>
void enqueue_if_subscribed_to_market(const object* obj, market_queue_type& queue, bool full_object=true)
{
@ -189,16 +199,17 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
void broadcast_updates( const vector<variant>& updates );
void broadcast_market_updates( const market_queue_type& queue);
void handle_object_changed(bool force_notify, const vector<object_id_type>& ids, std::function<const object*(object_id_type id)> find_object);
void handle_object_changed(bool force_notify, bool full_object, const vector<object_id_type>& ids, const flat_set<account_id_type>& impacted_accounts, std::function<const object*(object_id_type id)> find_object);
/** called every time a block is applied to report the objects that were changed */
void on_objects_new(const vector<object_id_type>& ids);
void on_objects_changed(const vector<object_id_type>& ids);
void on_objects_removed(const vector<object_id_type>& ids, const vector<const object*>& objs);
void on_objects_new(const vector<object_id_type>& ids, const flat_set<account_id_type>& impacted_accounts);
void on_objects_changed(const vector<object_id_type>& ids, const flat_set<account_id_type>& impacted_accounts);
void on_objects_removed(const vector<object_id_type>& ids, const vector<const object*>& objs, const flat_set<account_id_type>& impacted_accounts);
void on_applied_block();
bool _notify_remove_create = false;
mutable fc::bloom_filter _subscribe_filter;
std::set<account_id_type> _subscribed_accounts;
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;
@ -226,14 +237,14 @@ database_api::~database_api() {}
database_api_impl::database_api_impl( graphene::chain::database& db ):_db(db)
{
wlog("creating database api ${x}", ("x",int64_t(this)) );
_new_connection = _db.new_objects.connect([this](const vector<object_id_type>& ids) {
on_objects_new(ids);
_new_connection = _db.new_objects.connect([this](const vector<object_id_type>& ids, const flat_set<account_id_type>& impacted_accounts) {
on_objects_new(ids, impacted_accounts);
});
_change_connection = _db.changed_objects.connect([this](const vector<object_id_type>& ids) {
on_objects_changed(ids);
_change_connection = _db.changed_objects.connect([this](const vector<object_id_type>& ids, const flat_set<account_id_type>& impacted_accounts) {
on_objects_changed(ids, impacted_accounts);
});
_removed_connection = _db.removed_objects.connect([this](const vector<object_id_type>& ids, const vector<const object*>& objs) {
on_objects_removed(ids, objs);
_removed_connection = _db.removed_objects.connect([this](const vector<object_id_type>& ids, const vector<const object*>& objs, const flat_set<account_id_type>& impacted_accounts) {
on_objects_removed(ids, objs, impacted_accounts);
});
_applied_block_connection = _db.applied_block.connect([this](const signed_block&){ on_applied_block(); });
@ -299,10 +310,11 @@ void database_api_impl::set_subscribe_callback( std::function<void(const variant
//edump((clear_filter));
_subscribe_callback = cb;
_notify_remove_create = notify_remove_create;
_subscribed_accounts.clear();
static fc::bloom_parameters param;
param.projected_element_count = 10000;
param.false_positive_probability = 1.0/10000;
param.false_positive_probability = 1.0/100;
param.maximum_size = 1024*8*8*2;
param.compute_optimal_parameters();
_subscribe_filter = fc::bloom_filter(param);
@ -609,6 +621,8 @@ std::map<std::string, full_account> database_api_impl::get_full_accounts( const
if( subscribe )
{
FC_ASSERT( std::distance(_subscribed_accounts.begin(), _subscribed_accounts.end()) < 100 );
_subscribed_accounts.insert( account->get_id() );
subscribe_to_item( account->id );
}
@ -670,22 +684,22 @@ std::map<std::string, full_account> database_api_impl::get_full_accounts( const
[&acnt] (const call_order_object& call) {
acnt.call_orders.emplace_back(call);
});
// get assets issued by user
auto asset_range = _db.get_index_type<asset_index>().indices().get<by_issuer>().equal_range(account->id);
std::for_each(asset_range.first, asset_range.second,
[&acnt] (const asset_object& asset) {
acnt.assets.emplace_back(asset.id);
});
// get withdraws permissions
auto withdraw_range = _db.get_index_type<withdraw_permission_index>().indices().get<by_from>().equal_range(account->id);
std::for_each(withdraw_range.first, withdraw_range.second,
[&acnt] (const withdraw_permission_object& withdraw) {
acnt.withdraws.emplace_back(withdraw);
});
results[account_name_or_id] = acnt;
}
return results;
@ -1129,120 +1143,84 @@ void database_api_impl::unsubscribe_from_market(asset_id_type a, asset_id_type b
market_ticker database_api::get_ticker( const string& base, const string& quote )const
{
return my->get_ticker( base, quote );
return my->get_ticker( base, quote );
}
market_ticker database_api_impl::get_ticker( const string& base, const string& quote )const
{
auto assets = lookup_asset_symbols( {base, quote} );
FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
const auto assets = lookup_asset_symbols( {base, quote} );
FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
auto base_id = assets[0]->id;
auto quote_id = assets[1]->id;
market_ticker result;
result.base = base;
result.quote = quote;
result.latest = 0;
result.lowest_ask = 0;
result.highest_bid = 0;
result.percent_change = 0;
result.base_volume = 0;
result.quote_volume = 0;
market_ticker result;
try {
const fc::time_point_sec now = fc::time_point::now();
const fc::time_point_sec yesterday = fc::time_point_sec( now.sec_since_epoch() - 86400 );
const auto batch_size = 100;
result.base = base;
result.quote = quote;
result.base_volume = 0;
result.quote_volume = 0;
result.percent_change = 0;
result.lowest_ask = 0;
result.highest_bid = 0;
vector<market_trade> trades = get_trade_history( base, quote, now, yesterday, batch_size );
if( !trades.empty() )
{
result.latest = trades[0].price;
auto price_to_real = [&]( const share_type a, int p ) { return double( a.value ) / pow( 10, p ); };
try {
if( base_id > quote_id ) std::swap(base_id, quote_id);
uint32_t day = 86400;
auto now = fc::time_point_sec( fc::time_point::now() );
auto trades = get_trade_history( base, quote, now, fc::time_point_sec( now.sec_since_epoch() - day ), 100 );
if ( trades.size() )
{
result.latest = trades[0].price;
for ( market_trade t: trades )
{
result.base_volume += t.value;
result.quote_volume += t.amount;
}
while (trades.size() == 100)
{
trades = get_trade_history( base, quote, trades[99].date, fc::time_point_sec( now.sec_since_epoch() - day ), 100 );
for ( market_trade t: trades )
while( !trades.empty() )
{
result.base_volume += t.value;
result.quote_volume += t.amount;
for( const market_trade& t: trades )
{
result.base_volume += t.value;
result.quote_volume += t.amount;
}
trades = get_trade_history( base, quote, trades.back().date, yesterday, batch_size );
}
}
trades = get_trade_history( base, quote, trades.back().date, fc::time_point_sec(), 1 );
result.percent_change = trades.size() > 0 ? ( ( result.latest / trades.back().price ) - 1 ) * 100 : 0;
}
const auto last_trade_yesterday = get_trade_history( base, quote, yesterday, fc::time_point_sec(), 1 );
if( !last_trade_yesterday.empty() )
{
const auto price_yesterday = last_trade_yesterday[0].price;
result.percent_change = ( (result.latest / price_yesterday) - 1 ) * 100;
}
}
else
{
const auto last_trade = get_trade_history( base, quote, now, fc::time_point_sec(), 1 );
if( !last_trade.empty() )
result.latest = last_trade[0].price;
}
auto orders = get_order_book( base, quote, 1 );
if( orders.asks.size() )
result.lowest_ask = orders.asks[0].price;
if( orders.bids.size() )
result.highest_bid = orders.bids[0].price;
const auto orders = get_order_book( base, quote, 1 );
if( !orders.asks.empty() ) result.lowest_ask = orders.asks[0].price;
if( !orders.bids.empty() ) result.highest_bid = orders.bids[0].price;
} FC_CAPTURE_AND_RETHROW( (base)(quote) )
} FC_CAPTURE_AND_RETHROW( (base)(quote) )
return result;
return result;
}
market_volume database_api::get_24_volume( const string& base, const string& quote )const
{
return my->get_24_volume( base, quote );
return my->get_24_volume( base, quote );
}
market_volume database_api_impl::get_24_volume( const string& base, const string& quote )const
{
auto assets = lookup_asset_symbols( {base, quote} );
FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
const auto ticker = get_ticker( base, quote );
auto base_id = assets[0]->id;
auto quote_id = assets[1]->id;
market_volume result;
result.base = ticker.base;
result.quote = ticker.quote;
result.base_volume = ticker.base_volume;
result.quote_volume = ticker.quote_volume;
market_volume result;
result.base = base;
result.quote = quote;
result.base_volume = 0;
result.quote_volume = 0;
try {
if( base_id > quote_id ) std::swap(base_id, quote_id);
uint32_t bucket_size = 86400;
auto now = fc::time_point_sec( fc::time_point::now() );
auto trades = get_trade_history( base, quote, now, fc::time_point_sec( now.sec_since_epoch() - bucket_size ), 100 );
for ( market_trade t: trades )
{
result.base_volume += t.value;
result.quote_volume += t.amount;
}
while (trades.size() == 100)
{
trades = get_trade_history( base, quote, trades[99].date, fc::time_point_sec( now.sec_since_epoch() - bucket_size ), 100 );
for ( market_trade t: trades )
{
result.base_volume += t.value;
result.quote_volume += t.amount;
}
}
return result;
} FC_CAPTURE_AND_RETHROW( (base)(quote) )
return result;
}
order_book database_api::get_order_book( const string& base, const string& quote, unsigned limit )const
@ -1914,50 +1892,57 @@ void database_api_impl::broadcast_market_updates( const market_queue_type& queue
}
}
void database_api_impl::on_objects_removed( const vector<object_id_type>& ids, const vector<const object*>& objs )
void database_api_impl::on_objects_removed( const vector<object_id_type>& ids, const vector<const object*>& objs, const flat_set<account_id_type>& impacted_accounts)
{
handle_object_changed(_notify_remove_create, ids, [objs](object_id_type id) -> const object* {
handle_object_changed(_notify_remove_create, false, ids, impacted_accounts,
[objs](object_id_type id) -> const object* {
auto it = std::find_if(
objs.begin(), objs.end(),
[id](const object* o) {return o != nullptr && o->id == id;});
auto it = std::find_if(
objs.begin(), objs.end(),
[id](const object* o) {return o != nullptr && o->id == id;});
if (it != objs.end())
return *it;
if (it != objs.end())
return *it;
return nullptr;
});
return nullptr;
}
);
}
void database_api_impl::on_objects_new(const vector<object_id_type>& ids)
void database_api_impl::on_objects_new(const vector<object_id_type>& ids, const flat_set<account_id_type>& impacted_accounts)
{
handle_object_changed(_notify_remove_create, ids,
handle_object_changed(_notify_remove_create, true, ids, impacted_accounts,
std::bind(&object_database::find_object, &_db, std::placeholders::_1)
);
}
void database_api_impl::on_objects_changed(const vector<object_id_type>& ids)
void database_api_impl::on_objects_changed(const vector<object_id_type>& ids, const flat_set<account_id_type>& impacted_accounts)
{
handle_object_changed(false, ids,
handle_object_changed(false, true, ids, impacted_accounts,
std::bind(&object_database::find_object, &_db, std::placeholders::_1)
);
}
void database_api_impl::handle_object_changed(bool force_notify, const vector<object_id_type>& ids, std::function<const object*(object_id_type id)> find_object)
void database_api_impl::handle_object_changed(bool force_notify, bool full_object, const vector<object_id_type>& ids, const flat_set<account_id_type>& impacted_accounts, std::function<const object*(object_id_type id)> find_object)
{
if( _subscribe_callback )
{
vector<variant> updates;
for(auto id : ids)
{
const object* obj = nullptr;
if( force_notify || is_subscribed_to_item(id) )
if( force_notify || is_subscribed_to_item(id) || is_impacted_account(impacted_accounts) )
{
obj = find_object(id);
if( obj )
if( full_object )
{
updates.emplace_back( obj->to_variant() );
auto obj = find_object(id);
if( obj )
{
updates.emplace_back( obj->to_variant() );
}
}
else
{
updates.emplace_back( id );
}
}
}
@ -1973,11 +1958,11 @@ void database_api_impl::handle_object_changed(bool force_notify, const vector<ob
{
if( id.is<call_order_object>() )
{
enqueue_if_subscribed_to_market<call_order_object>( find_object(id), broadcast_queue );
enqueue_if_subscribed_to_market<call_order_object>( find_object(id), broadcast_queue, full_object );
}
else if( id.is<limit_order_object>() )
{
enqueue_if_subscribed_to_market<limit_order_object>( find_object(id), broadcast_queue );
enqueue_if_subscribed_to_market<limit_order_object>( find_object(id), broadcast_queue, full_object );
}
}

View file

@ -33,3 +33,4 @@
#include "db_market.cpp"
#include "db_update.cpp"
#include "db_witness_schedule.cpp"
#include "db_notify.cpp"

View file

@ -29,6 +29,7 @@
#include <graphene/chain/block_summary_object.hpp>
#include <graphene/chain/global_property_object.hpp>
#include <graphene/chain/operation_history_object.hpp>
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/transaction_object.hpp>
#include <graphene/chain/witness_object.hpp>
@ -544,31 +545,7 @@ void database::_apply_block( const signed_block& next_block )
notify_changed_objects();
} FC_CAPTURE_AND_RETHROW( (next_block.block_num()) ) }
void database::notify_changed_objects()
{ try {
if( _undo_db.enabled() )
{
const auto& head_undo = _undo_db.head();
vector<object_id_type> new_ids; new_ids.reserve(head_undo.new_ids.size());
for( const auto& item : head_undo.new_ids ) new_ids.push_back(item);
vector<object_id_type> changed_ids; changed_ids.reserve(head_undo.old_values.size());
for( const auto& item : head_undo.old_values ) changed_ids.push_back(item.first);
vector<object_id_type> removed_ids; removed_ids.reserve( head_undo.removed.size() );
vector<const object*> removed; removed.reserve( head_undo.removed.size() );
for( const auto& item : head_undo.removed )
{
removed_ids.emplace_back( item.first );
removed.emplace_back( item.second.get() );
}
new_objects(new_ids);
changed_objects(changed_ids);
removed_objects(removed_ids, removed);
}
} FC_CAPTURE_AND_LOG( () ) }
processed_transaction database::apply_transaction(const signed_transaction& trx, uint32_t skip)
{

View file

@ -0,0 +1,392 @@
#include <fc/container/flat.hpp>
#include <graphene/chain/protocol/authority.hpp>
#include <graphene/chain/protocol/operations.hpp>
#include <graphene/chain/protocol/transaction.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/withdraw_permission_object.hpp>
#include <graphene/chain/worker_object.hpp>
#include <graphene/chain/confidential_object.hpp>
#include <graphene/chain/market_object.hpp>
#include <graphene/chain/committee_member_object.hpp>
using namespace fc;
using namespace graphene::chain;
// TODO: Review all of these, especially no-ops
struct get_impacted_account_visitor
{
flat_set<account_id_type>& _impacted;
get_impacted_account_visitor( flat_set<account_id_type>& impact ):_impacted(impact) {}
typedef void result_type;
void operator()( const transfer_operation& op )
{
_impacted.insert( op.to );
}
void operator()( const asset_claim_fees_operation& op ){}
void operator()( const limit_order_create_operation& op ) {}
void operator()( const limit_order_cancel_operation& op )
{
_impacted.insert( op.fee_paying_account );
}
void operator()( const call_order_update_operation& op ) {}
void operator()( const fill_order_operation& op )
{
_impacted.insert( op.account_id );
}
void operator()( const account_create_operation& op )
{
_impacted.insert( op.registrar );
_impacted.insert( op.referrer );
add_authority_accounts( _impacted, op.owner );
add_authority_accounts( _impacted, op.active );
}
void operator()( const account_update_operation& op )
{
_impacted.insert( op.account );
if( op.owner )
add_authority_accounts( _impacted, *(op.owner) );
if( op.active )
add_authority_accounts( _impacted, *(op.active) );
}
void operator()( const account_whitelist_operation& op )
{
_impacted.insert( op.account_to_list );
}
void operator()( const account_upgrade_operation& op ) {}
void operator()( const account_transfer_operation& op )
{
_impacted.insert( op.new_owner );
}
void operator()( const asset_create_operation& op ) {}
void operator()( const asset_update_operation& op )
{
if( op.new_issuer )
_impacted.insert( *(op.new_issuer) );
}
void operator()( const asset_update_bitasset_operation& op ) {}
void operator()( const asset_update_feed_producers_operation& op ) {}
void operator()( const asset_issue_operation& op )
{
_impacted.insert( op.issue_to_account );
}
void operator()( const asset_reserve_operation& op ) {}
void operator()( const asset_fund_fee_pool_operation& op ) {}
void operator()( const asset_settle_operation& op ) {}
void operator()( const asset_global_settle_operation& op ) {}
void operator()( const asset_publish_feed_operation& op ) {}
void operator()( const witness_create_operation& op )
{
_impacted.insert( op.witness_account );
}
void operator()( const witness_update_operation& op )
{
_impacted.insert( op.witness_account );
}
void operator()( const proposal_create_operation& op )
{
vector<authority> other;
for( const auto& proposed_op : op.proposed_ops )
operation_get_required_authorities( proposed_op.op, _impacted, _impacted, other );
for( auto& o : other )
add_authority_accounts( _impacted, o );
}
void operator()( const proposal_update_operation& op ) {}
void operator()( const proposal_delete_operation& op ) {}
void operator()( const withdraw_permission_create_operation& op )
{
_impacted.insert( op.authorized_account );
}
void operator()( const withdraw_permission_update_operation& op )
{
_impacted.insert( op.authorized_account );
}
void operator()( const withdraw_permission_claim_operation& op )
{
_impacted.insert( op.withdraw_from_account );
}
void operator()( const withdraw_permission_delete_operation& op )
{
_impacted.insert( op.authorized_account );
}
void operator()( const committee_member_create_operation& op )
{
_impacted.insert( op.committee_member_account );
}
void operator()( const committee_member_update_operation& op )
{
_impacted.insert( op.committee_member_account );
}
void operator()( const committee_member_update_global_parameters_operation& op ) {}
void operator()( const vesting_balance_create_operation& op )
{
_impacted.insert( op.owner );
}
void operator()( const vesting_balance_withdraw_operation& op ) {}
void operator()( const worker_create_operation& op ) {}
void operator()( const custom_operation& op ) {}
void operator()( const assert_operation& op ) {}
void operator()( const balance_claim_operation& op ) {}
void operator()( const override_transfer_operation& op )
{
_impacted.insert( op.to );
_impacted.insert( op.from );
_impacted.insert( op.issuer );
}
void operator()( const transfer_to_blind_operation& op )
{
_impacted.insert( op.from );
for( const auto& out : op.outputs )
add_authority_accounts( _impacted, out.owner );
}
void operator()( const blind_transfer_operation& op )
{
for( const auto& in : op.inputs )
add_authority_accounts( _impacted, in.owner );
for( const auto& out : op.outputs )
add_authority_accounts( _impacted, out.owner );
}
void operator()( const transfer_from_blind_operation& op )
{
_impacted.insert( op.to );
for( const auto& in : op.inputs )
add_authority_accounts( _impacted, in.owner );
}
void operator()( const asset_settle_cancel_operation& op )
{
_impacted.insert( op.account );
}
void operator()( const fba_distribute_operation& op )
{
_impacted.insert( op.account_id );
}
};
void operation_get_impacted_accounts( const operation& op, flat_set<account_id_type>& result )
{
get_impacted_account_visitor vtor = get_impacted_account_visitor( result );
op.visit( vtor );
}
void transaction_get_impacted_accounts( const transaction& tx, flat_set<account_id_type>& result )
{
for( const auto& op : tx.operations )
operation_get_impacted_accounts( op, result );
}
void get_relevant_accounts( const object* obj, flat_set<account_id_type>& accounts )
{
if( obj->id.space() == protocol_ids )
{
switch( (object_type)obj->id.type() )
{
case null_object_type:
case base_object_type:
case OBJECT_TYPE_COUNT:
return;
case account_object_type:{
accounts.insert( obj->id );
break;
} case asset_object_type:{
const auto& aobj = dynamic_cast<const asset_object*>(obj);
assert( aobj != nullptr );
accounts.insert( aobj->issuer );
break;
} case force_settlement_object_type:{
const auto& aobj = dynamic_cast<const force_settlement_object*>(obj);
assert( aobj != nullptr );
accounts.insert( aobj->owner );
break;
} case committee_member_object_type:{
const auto& aobj = dynamic_cast<const committee_member_object*>(obj);
assert( aobj != nullptr );
accounts.insert( aobj->committee_member_account );
break;
} case witness_object_type:{
const auto& aobj = dynamic_cast<const witness_object*>(obj);
assert( aobj != nullptr );
accounts.insert( aobj->witness_account );
break;
} case limit_order_object_type:{
const auto& aobj = dynamic_cast<const limit_order_object*>(obj);
assert( aobj != nullptr );
accounts.insert( aobj->seller );
break;
} case call_order_object_type:{
const auto& aobj = dynamic_cast<const call_order_object*>(obj);
assert( aobj != nullptr );
accounts.insert( aobj->borrower );
break;
} case custom_object_type:{
break;
} case proposal_object_type:{
const auto& aobj = dynamic_cast<const proposal_object*>(obj);
assert( aobj != nullptr );
transaction_get_impacted_accounts( aobj->proposed_transaction, accounts );
break;
} case operation_history_object_type:{
const auto& aobj = dynamic_cast<const operation_history_object*>(obj);
assert( aobj != nullptr );
operation_get_impacted_accounts( aobj->op, accounts );
break;
} case withdraw_permission_object_type:{
const auto& aobj = dynamic_cast<const withdraw_permission_object*>(obj);
assert( aobj != nullptr );
accounts.insert( aobj->withdraw_from_account );
accounts.insert( aobj->authorized_account );
break;
} case vesting_balance_object_type:{
const auto& aobj = dynamic_cast<const vesting_balance_object*>(obj);
assert( aobj != nullptr );
accounts.insert( aobj->owner );
break;
} case worker_object_type:{
const auto& aobj = dynamic_cast<const worker_object*>(obj);
assert( aobj != nullptr );
accounts.insert( aobj->worker_account );
break;
} case balance_object_type:{
/** these are free from any accounts */
break;
}
}
}
else if( obj->id.space() == implementation_ids )
{
switch( (impl_object_type)obj->id.type() )
{
case impl_global_property_object_type:
break;
case impl_dynamic_global_property_object_type:
break;
case impl_reserved0_object_type:
break;
case impl_asset_dynamic_data_type:
break;
case impl_asset_bitasset_data_type:
break;
case impl_account_balance_object_type:{
const auto& aobj = dynamic_cast<const account_balance_object*>(obj);
assert( aobj != nullptr );
accounts.insert( aobj->owner );
break;
} case impl_account_statistics_object_type:{
const auto& aobj = dynamic_cast<const account_statistics_object*>(obj);
assert( aobj != nullptr );
accounts.insert( aobj->owner );
break;
} case impl_transaction_object_type:{
const auto& aobj = dynamic_cast<const transaction_object*>(obj);
assert( aobj != nullptr );
transaction_get_impacted_accounts( aobj->trx, accounts );
break;
} case impl_blinded_balance_object_type:{
const auto& aobj = dynamic_cast<const blinded_balance_object*>(obj);
assert( aobj != nullptr );
for( const auto& a : aobj->owner.account_auths )
accounts.insert( a.first );
break;
} case impl_block_summary_object_type:
break;
case impl_account_transaction_history_object_type:
break;
case impl_chain_property_object_type:
break;
case impl_witness_schedule_object_type:
break;
case impl_budget_record_object_type:
break;
case impl_special_authority_object_type:
break;
case impl_buyback_object_type:
break;
case impl_fba_accumulator_object_type:
break;
}
}
} // end get_relevant_accounts( const object* obj, flat_set<account_id_type>& accounts )
namespace graphene { namespace chain {
void database::notify_changed_objects()
{ try {
if( _undo_db.enabled() )
{
const auto& head_undo = _undo_db.head();
// New
if( !new_objects.empty() )
{
vector<object_id_type> new_ids; new_ids.reserve(head_undo.new_ids.size());
flat_set<account_id_type> new_accounts_impacted;
for( const auto& item : head_undo.new_ids )
{
new_ids.push_back(item);
auto obj = find_object(item);
if(obj != nullptr)
get_relevant_accounts(obj, new_accounts_impacted);
}
new_objects(new_ids, new_accounts_impacted);
}
// Changed
if( !changed_objects.empty() )
{
vector<object_id_type> changed_ids; changed_ids.reserve(head_undo.old_values.size());
flat_set<account_id_type> changed_accounts_impacted;
for( const auto& item : head_undo.old_values )
{
changed_ids.push_back(item.first);
get_relevant_accounts(item.second.get(), changed_accounts_impacted);
}
changed_objects(changed_ids, changed_accounts_impacted);
}
// Removed
if( !removed_objects.empty() )
{
vector<object_id_type> removed_ids; removed_ids.reserve( head_undo.removed.size() );
vector<const object*> removed; removed.reserve( head_undo.removed.size() );
flat_set<account_id_type> removed_accounts_impacted;
for( const auto& item : head_undo.removed )
{
removed_ids.emplace_back( item.first );
auto obj = item.second.get();
removed.emplace_back( obj );
get_relevant_accounts(obj, removed_accounts_impacted);
}
removed_objects(removed_ids, removed, removed_accounts_impacted);
}
}
} FC_CAPTURE_AND_LOG( () ) }
} }

View file

@ -193,18 +193,18 @@ namespace graphene { namespace chain {
* Emitted After a block has been applied and committed. The callback
* should not yield and should execute quickly.
*/
fc::signal<void(const vector<object_id_type>&)> new_objects;
fc::signal<void(const vector<object_id_type>&, const flat_set<account_id_type>&)> new_objects;
/**
* Emitted After a block has been applied and committed. The callback
* should not yield and should execute quickly.
*/
fc::signal<void(const vector<object_id_type>&)> changed_objects;
fc::signal<void(const vector<object_id_type>&, const flat_set<account_id_type>&)> changed_objects;
/** this signal is emitted any time an object is removed and contains a
* pointer to the last value of every object that was removed.
*/
fc::signal<void(const vector<object_id_type>&, const vector<const object*>&)> removed_objects;
fc::signal<void(const vector<object_id_type>&, const vector<const object*>&, const flat_set<account_id_type>&)> removed_objects;
//////////////////// db_witness_schedule.cpp ////////////////////

View file

@ -98,13 +98,13 @@ void debug_witness_plugin::plugin_startup()
// connect needed signals
_applied_block_conn = db.applied_block.connect([this](const graphene::chain::signed_block& b){ on_applied_block(b); });
_changed_objects_conn = db.changed_objects.connect([this](const std::vector<graphene::db::object_id_type>& ids){ on_changed_objects(ids); });
_removed_objects_conn = db.removed_objects.connect([this](const std::vector<graphene::db::object_id_type>& ids, const std::vector<const graphene::db::object*>& objs){ on_removed_objects(ids, objs); });
_changed_objects_conn = db.changed_objects.connect([this](const std::vector<graphene::db::object_id_type>& ids, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts){ on_changed_objects(ids, impacted_accounts); });
_removed_objects_conn = db.removed_objects.connect([this](const std::vector<graphene::db::object_id_type>& ids, const std::vector<const graphene::db::object*>& objs, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts){ on_removed_objects(ids, objs, impacted_accounts); });
return;
}
void debug_witness_plugin::on_changed_objects( const std::vector<graphene::db::object_id_type>& ids )
void debug_witness_plugin::on_changed_objects( const std::vector<graphene::db::object_id_type>& ids, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts )
{
if( _json_object_stream && (ids.size() > 0) )
{
@ -120,7 +120,7 @@ void debug_witness_plugin::on_changed_objects( const std::vector<graphene::db::o
}
}
void debug_witness_plugin::on_removed_objects( const std::vector<graphene::db::object_id_type>& ids, const std::vector<const graphene::db::object*> objs )
void debug_witness_plugin::on_removed_objects( const std::vector<graphene::db::object_id_type>& ids, const std::vector<const graphene::db::object*> objs, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts )
{
if( _json_object_stream )
{

View file

@ -25,8 +25,10 @@
#include <graphene/app/plugin.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <fc/thread/future.hpp>
#include <fc/container/flat.hpp>
namespace graphene { namespace debug_witness_plugin {
@ -50,8 +52,8 @@ public:
private:
void on_changed_objects( const std::vector<graphene::db::object_id_type>& ids );
void on_removed_objects( const std::vector<graphene::db::object_id_type>& ids, const std::vector<const graphene::db::object*> objs );
void on_changed_objects( const std::vector<graphene::db::object_id_type>& ids, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts );
void on_removed_objects( const std::vector<graphene::db::object_id_type>& ids, const std::vector<const graphene::db::object*> objs, const fc::flat_set<graphene::chain::account_id_type>& impacted_accounts );
void on_applied_block( const graphene::chain::signed_block& b );
boost::program_options::variables_map _options;