Merge branch 'feature/son-for-hive-voting' into 'develop'
SON for Hive voting See merge request PBSA/peerplays!81
This commit is contained in:
commit
9b2c60f76c
49 changed files with 1783 additions and 1135 deletions
|
|
@ -44,8 +44,6 @@ test-mainnet:
|
|||
|
||||
dockerize-mainnet:
|
||||
stage: dockerize
|
||||
dependencies:
|
||||
- test-mainnet
|
||||
variables:
|
||||
IMAGE: $CI_REGISTRY_IMAGE/mainnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
|
||||
before_script:
|
||||
|
|
@ -105,8 +103,6 @@ test-testnet:
|
|||
|
||||
dockerize-testnet:
|
||||
stage: dockerize
|
||||
dependencies:
|
||||
- test-testnet
|
||||
variables:
|
||||
IMAGE: $CI_REGISTRY_IMAGE/testnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
|
||||
before_script:
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ RUN \
|
|||
expect \
|
||||
git \
|
||||
graphviz \
|
||||
libboost1.67-all-dev \
|
||||
libboost-all-dev \
|
||||
libbz2-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libncurses-dev \
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ EXPOSE 22
|
|||
WORKDIR /home/peerplays/
|
||||
|
||||
RUN \
|
||||
wget -c 'http://sourceforge.net/projects/boost/files/boost/1.67.0/boost_1_67_0.tar.bz2/download' -O boost_1_67_0.tar.bz2 && \
|
||||
tar xjf boost_1_67_0.tar.bz2 && \
|
||||
cd boost_1_67_0/ && \
|
||||
wget -c 'https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/boost_1_71_0.tar.bz2' -O boost_1_71_0.tar.bz2 && \
|
||||
tar xjf boost_1_71_0.tar.bz2 && \
|
||||
cd boost_1_71_0/ && \
|
||||
./bootstrap.sh && \
|
||||
./b2 install
|
||||
|
||||
|
|
|
|||
|
|
@ -84,9 +84,9 @@ sudo apt-get install \
|
|||
|
||||
Install Boost libraries from source
|
||||
```
|
||||
wget -c 'http://sourceforge.net/projects/boost/files/boost/1.67.0/boost_1_67_0.tar.bz2/download' -O boost_1_67_0.tar.bz2
|
||||
tar xjf boost_1_67_0.tar.bz2
|
||||
cd boost_1_67_0/
|
||||
wget -c 'https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/boost_1_71_0.tar.bz2' -O boost_1_71_0.tar.bz2
|
||||
tar xjf boost_1_71_0.tar.bz2
|
||||
cd boost_1_71_0/
|
||||
./bootstrap.sh
|
||||
sudo ./b2 install
|
||||
```
|
||||
|
|
|
|||
|
|
@ -2083,7 +2083,8 @@ vector<variant> database_api_impl::lookup_vote_ids(const vector<vote_id_type> &v
|
|||
const auto &committee_idx = _db.get_index_type<committee_member_index>().indices().get<by_vote_id>();
|
||||
const auto &for_worker_idx = _db.get_index_type<worker_index>().indices().get<by_vote_for>();
|
||||
const auto &against_worker_idx = _db.get_index_type<worker_index>().indices().get<by_vote_against>();
|
||||
const auto &son_idx = _db.get_index_type<son_index>().indices().get<by_vote_id>();
|
||||
const auto &son_bictoin_idx = _db.get_index_type<son_index>().indices().get<by_vote_id_bitcoin>();
|
||||
const auto &son_hive_idx = _db.get_index_type<son_index>().indices().get<by_vote_id_hive>();
|
||||
|
||||
vector<variant> result;
|
||||
result.reserve(votes.size());
|
||||
|
|
@ -2119,15 +2120,22 @@ vector<variant> database_api_impl::lookup_vote_ids(const vector<vote_id_type> &v
|
|||
}
|
||||
break;
|
||||
}
|
||||
case vote_id_type::son: {
|
||||
auto itr = son_idx.find(id);
|
||||
if (itr != son_idx.end())
|
||||
case vote_id_type::son_bitcoin: {
|
||||
auto itr = son_bictoin_idx.find(id);
|
||||
if (itr != son_bictoin_idx.end())
|
||||
result.emplace_back(variant(*itr, 5));
|
||||
else
|
||||
result.emplace_back(variant());
|
||||
break;
|
||||
}
|
||||
case vote_id_type::son_hive: {
|
||||
auto itr = son_hive_idx.find(id);
|
||||
if (itr != son_hive_idx.end())
|
||||
result.emplace_back(variant(*itr, 5));
|
||||
else
|
||||
result.emplace_back(variant());
|
||||
break;
|
||||
}
|
||||
|
||||
case vote_id_type::VOTE_TYPE_COUNT:
|
||||
break; // supress unused enum value warnings
|
||||
default:
|
||||
|
|
@ -2152,12 +2160,21 @@ vector<vote_id_type> database_api_impl::get_votes_ids(const string &account_name
|
|||
votes_info database_api_impl::get_votes(const string &account_name_or_id) const {
|
||||
votes_info result;
|
||||
|
||||
const auto &votes_ids = get_votes_ids(account_name_or_id);
|
||||
const auto &committee_ids = get_votes_objects<committee_member_index, by_vote_id>(votes_ids);
|
||||
const auto &witness_ids = get_votes_objects<witness_index, by_vote_id>(votes_ids);
|
||||
const auto &for_worker_ids = get_votes_objects<worker_index, by_vote_for>(votes_ids);
|
||||
const auto &against_worker_ids = get_votes_objects<worker_index, by_vote_against>(votes_ids);
|
||||
const auto &son_ids = get_votes_objects<son_index, by_vote_id>(votes_ids, 5);
|
||||
const auto votes_ids = get_votes_ids(account_name_or_id);
|
||||
const auto committee_ids = get_votes_objects<committee_member_index, by_vote_id>(votes_ids);
|
||||
const auto witness_ids = get_votes_objects<witness_index, by_vote_id>(votes_ids);
|
||||
const auto for_worker_ids = get_votes_objects<worker_index, by_vote_for>(votes_ids);
|
||||
const auto against_worker_ids = get_votes_objects<worker_index, by_vote_against>(votes_ids);
|
||||
const auto son_ids = [this, &votes_ids]() {
|
||||
flat_map<sidechain_type, vector<variant>> son_ids;
|
||||
const auto son_bitcoin_ids = get_votes_objects<son_index, by_vote_id_bitcoin>(votes_ids, 5);
|
||||
if (!son_bitcoin_ids.empty())
|
||||
son_ids[sidechain_type::bitcoin] = std::move(son_bitcoin_ids);
|
||||
const auto son_hive_ids = get_votes_objects<son_index, by_vote_id_hive>(votes_ids, 5);
|
||||
if (!son_hive_ids.empty())
|
||||
son_ids[sidechain_type::hive] = std::move(son_hive_ids);
|
||||
return son_ids;
|
||||
}();
|
||||
|
||||
//! Fill votes info
|
||||
if (!committee_ids.empty()) {
|
||||
|
|
@ -2201,11 +2218,15 @@ votes_info database_api_impl::get_votes(const string &account_name_or_id) const
|
|||
}
|
||||
|
||||
if (!son_ids.empty()) {
|
||||
vector<votes_info_object> votes_for_sons;
|
||||
votes_for_sons.reserve(son_ids.size());
|
||||
for (const auto &son : son_ids) {
|
||||
const auto &son_obj = son.as<son_object>(6);
|
||||
votes_for_sons.emplace_back(votes_info_object{son_obj.vote_id, son_obj.id});
|
||||
flat_map<sidechain_type, vector<votes_info_object>> votes_for_sons;
|
||||
for (const auto &son_sidechain_ids : son_ids) {
|
||||
const auto &sidechain = son_sidechain_ids.first;
|
||||
const auto &sidechain_ids = son_sidechain_ids.second;
|
||||
votes_for_sons[sidechain].reserve(sidechain_ids.size());
|
||||
for (const auto &son : sidechain_ids) {
|
||||
const auto &son_obj = son.as<son_object>(6);
|
||||
votes_for_sons[sidechain].emplace_back(votes_info_object{son_obj.get_sidechain_vote_id(sidechain), son_obj.id});
|
||||
}
|
||||
}
|
||||
result.votes_for_sons = std::move(votes_for_sons);
|
||||
}
|
||||
|
|
@ -2379,12 +2400,16 @@ voters_info database_api_impl::get_voters(const string &account_name_or_id) cons
|
|||
|
||||
//! Info for son voters
|
||||
if (son_object) {
|
||||
const auto &son_voters = get_voters_by_id(son_object->vote_id);
|
||||
voters_info_object voters_for_son;
|
||||
voters_for_son.vote_id = son_object->vote_id;
|
||||
voters_for_son.voters.reserve(son_voters.size());
|
||||
for (const auto &voter : son_voters) {
|
||||
voters_for_son.voters.emplace_back(voter.get_id());
|
||||
flat_map<sidechain_type, voters_info_object> voters_for_son;
|
||||
for (const auto &vote_id : son_object->sidechain_vote_ids) {
|
||||
const auto &son_voters = get_voters_by_id(vote_id.second);
|
||||
voters_info_object voters_for_sidechain_son;
|
||||
voters_for_sidechain_son.vote_id = vote_id.second;
|
||||
voters_for_sidechain_son.voters.reserve(son_voters.size());
|
||||
for (const auto &voter : son_voters) {
|
||||
voters_for_sidechain_son.voters.emplace_back(voter.get_id());
|
||||
}
|
||||
voters_for_son[vote_id.first] = std::move(voters_for_sidechain_son);
|
||||
}
|
||||
result.voters_for_son = std::move(voters_for_son);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,8 +68,14 @@ void verify_account_votes( const database& db, const account_options& options )
|
|||
"Voted for more witnesses than currently allowed (${c})", ("c", chain_params.maximum_witness_count) );
|
||||
FC_ASSERT( options.num_committee <= chain_params.maximum_committee_count,
|
||||
"Voted for more committee members than currently allowed (${c})", ("c", chain_params.maximum_committee_count) );
|
||||
FC_ASSERT( options.num_son() <= chain_params.maximum_son_count(),
|
||||
"Voted for more sons than currently allowed (${c})", ("c", chain_params.maximum_son_count()) );
|
||||
FC_ASSERT( chain_params.extensions.value.maximum_son_count.valid() , "Invalid maximum son count" );
|
||||
FC_ASSERT( options.extensions.value.num_son.valid() , "Invalid son number" );
|
||||
for(const auto& num_sons : *options.extensions.value.num_son)
|
||||
{
|
||||
FC_ASSERT( num_sons.second <= *chain_params.extensions.value.maximum_son_count,
|
||||
"Voted for more sons than currently allowed (${c})", ("c", *chain_params.extensions.value.maximum_son_count) );
|
||||
}
|
||||
FC_ASSERT( db.find_object(options.voting_account), "Invalid proxy account specified." );
|
||||
|
||||
uint32_t max_vote_id = gpo.next_available_vote_id;
|
||||
bool has_worker_votes = false;
|
||||
|
|
|
|||
|
|
@ -705,7 +705,12 @@ void database::_apply_block( const signed_block& next_block )
|
|||
|
||||
if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM) {
|
||||
update_witness_schedule(next_block);
|
||||
if(global_props.active_sons.size() > 0) {
|
||||
bool need_to_update_son_schedule = false;
|
||||
for(const auto& active_sons : global_props.active_sons){
|
||||
if(!active_sons.second.empty())
|
||||
need_to_update_son_schedule = true;
|
||||
}
|
||||
if(need_to_update_son_schedule) {
|
||||
update_son_schedule(next_block);
|
||||
}
|
||||
}
|
||||
|
|
@ -739,10 +744,18 @@ void database::_apply_block( const signed_block& next_block )
|
|||
// TODO: figure out if we could collapse this function into
|
||||
// update_global_dynamic_data() as perhaps these methods only need
|
||||
// to be called for header validation?
|
||||
|
||||
update_maintenance_flag( maint_needed );
|
||||
if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM) {
|
||||
update_witness_schedule();
|
||||
if(global_props.active_sons.size() > 0) {
|
||||
|
||||
bool need_update_son_schedule = false;
|
||||
for(const auto& active_sidechain_type : active_sidechain_types) {
|
||||
if(global_props.active_sons.at(active_sidechain_type).size() > 0) {
|
||||
need_update_son_schedule = true;
|
||||
}
|
||||
}
|
||||
if(need_update_son_schedule) {
|
||||
update_son_schedule();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,17 +222,30 @@ std::set<son_id_type> database::get_sons_to_be_deregistered()
|
|||
|
||||
for( auto& son : son_idx )
|
||||
{
|
||||
if(son.status == son_status::in_maintenance)
|
||||
bool need_to_be_deregistered = true;
|
||||
for(const auto& status : son.statuses)
|
||||
{
|
||||
auto stats = son.statistics(*this);
|
||||
// TODO : We need to add a function that returns if we can deregister SON
|
||||
// i.e. with introduction of PW code, we have to make a decision if the SON
|
||||
// is needed for release of funds from the PW
|
||||
if(head_block_time() - stats.last_down_timestamp >= fc::seconds(get_global_properties().parameters.son_deregister_time()))
|
||||
const auto& sidechain = status.first;
|
||||
if(status.second != son_status::in_maintenance)
|
||||
need_to_be_deregistered = false;
|
||||
|
||||
if(need_to_be_deregistered)
|
||||
{
|
||||
ret.insert(son.id);
|
||||
auto stats = son.statistics(*this);
|
||||
|
||||
// TODO : We need to add a function that returns if we can deregister SON
|
||||
// i.e. with introduction of PW code, we have to make a decision if the SON
|
||||
// is needed for release of funds from the PW
|
||||
if (head_block_time() - stats.last_down_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time())) {
|
||||
need_to_be_deregistered = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(need_to_be_deregistered)
|
||||
{
|
||||
ret.insert(son.id);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -289,28 +302,51 @@ bool database::is_son_dereg_valid( son_id_type son_id )
|
|||
return false;
|
||||
}
|
||||
|
||||
return (son->status == son_status::in_maintenance &&
|
||||
(head_block_time() - son->statistics(*this).last_down_timestamp >= fc::seconds(get_global_properties().parameters.son_deregister_time())));
|
||||
bool status_son_dereg_valid = true;
|
||||
for(const auto& status : son->statuses)
|
||||
{
|
||||
const auto& sidechain = status.first;
|
||||
if(status.second != son_status::in_maintenance)
|
||||
status_son_dereg_valid = false;
|
||||
|
||||
if(status_son_dereg_valid)
|
||||
{
|
||||
if(head_block_time() - son->statistics(*this).last_down_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time()))
|
||||
{
|
||||
status_son_dereg_valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status_son_dereg_valid;
|
||||
}
|
||||
|
||||
bool database::is_son_active( son_id_type son_id )
|
||||
bool database::is_son_active( sidechain_type type, son_id_type son_id )
|
||||
{
|
||||
const auto& son_idx = get_index_type<son_index>().indices().get< by_id >();
|
||||
auto son = son_idx.find( son_id );
|
||||
if(son == son_idx.end())
|
||||
{
|
||||
if(son == son_idx.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const global_property_object& gpo = get_global_properties();
|
||||
if(!gpo.active_sons.contains(type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& gpo_as = gpo.active_sons.at(type);
|
||||
vector<son_id_type> active_son_ids;
|
||||
active_son_ids.reserve(gpo.active_sons.size());
|
||||
std::transform(gpo.active_sons.begin(), gpo.active_sons.end(),
|
||||
active_son_ids.reserve(gpo_as.size());
|
||||
std::transform(gpo_as.cbegin(), gpo_as.cend(),
|
||||
std::inserter(active_son_ids, active_son_ids.end()),
|
||||
[](const son_info& swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
|
||||
if(active_son_ids.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it_son = std::find(active_son_ids.begin(), active_son_ids.end(), son_id);
|
||||
return (it_son != active_son_ids.end());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1100,8 +1100,9 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
|||
FC_ASSERT( _p_witness_schedule_obj->id == witness_schedule_id_type() );
|
||||
|
||||
// Initialize witness schedule
|
||||
#ifndef NDEBUG
|
||||
const son_schedule_object& sso =
|
||||
|
||||
#ifndef NDEBUG
|
||||
const son_schedule_object& ssohive =
|
||||
#endif
|
||||
create<son_schedule_object>([&](son_schedule_object& _sso)
|
||||
{
|
||||
|
|
@ -1120,13 +1121,29 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
|||
|
||||
_sso.recent_slots_filled = fc::uint128::max_value();
|
||||
});
|
||||
assert( sso.id == son_schedule_id_type() );
|
||||
assert( ssohive.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::hive)) );
|
||||
|
||||
// Enable fees
|
||||
modify(get_global_properties(), [&genesis_state](global_property_object& p) {
|
||||
p.parameters.current_fees = genesis_state.initial_parameters.current_fees;
|
||||
#ifndef NDEBUG
|
||||
const son_schedule_object& ssobitcoin =
|
||||
#endif
|
||||
create<son_schedule_object>([&](son_schedule_object& _sso)
|
||||
{
|
||||
// for scheduled
|
||||
memset(_sso.rng_seed.begin(), 0, _sso.rng_seed.size());
|
||||
|
||||
witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV);
|
||||
|
||||
auto init_witnesses = get_global_properties().active_witnesses;
|
||||
|
||||
_sso.scheduler = son_scheduler();
|
||||
_sso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1);
|
||||
|
||||
|
||||
_sso.last_scheduling_block = 0;
|
||||
|
||||
_sso.recent_slots_filled = fc::uint128::max_value();
|
||||
});
|
||||
|
||||
assert( ssobitcoin.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::bitcoin)) );
|
||||
|
||||
// Create FBA counters
|
||||
create<fba_accumulator_object>([&]( fba_accumulator_object& acc )
|
||||
|
|
|
|||
|
|
@ -78,26 +78,30 @@ vector<std::reference_wrapper<const typename Index::object_type>> database::sort
|
|||
}
|
||||
|
||||
template<>
|
||||
vector<std::reference_wrapper<const son_object>> database::sort_votable_objects<son_index>(size_t count) const
|
||||
vector<std::reference_wrapper<const son_object>> database::sort_votable_objects<son_index>(sidechain_type sidechain, size_t count) const
|
||||
{
|
||||
const auto& all_sons = get_index_type<son_index>().indices().get< by_id >();
|
||||
std::vector<std::reference_wrapper<const son_object>> refs;
|
||||
for( auto& son : all_sons )
|
||||
{
|
||||
if(son.has_valid_config(head_block_time()) && son.status != son_status::deregistered)
|
||||
if(son.has_valid_config(head_block_time()) && son.statuses.at(sidechain) != son_status::deregistered)
|
||||
{
|
||||
refs.push_back(std::cref(son));
|
||||
}
|
||||
}
|
||||
count = std::min(count, refs.size());
|
||||
std::partial_sort(refs.begin(), refs.begin() + count, refs.end(),
|
||||
[this](const son_object& a, const son_object& b)->bool {
|
||||
share_type oa_vote = _vote_tally_buffer[a.vote_id];
|
||||
share_type ob_vote = _vote_tally_buffer[b.vote_id];
|
||||
[this, sidechain](const son_object& a, const son_object& b)->bool {
|
||||
FC_ASSERT(sidechain == sidechain_type::bitcoin || sidechain == sidechain_type::hive, "Unexpected sidechain type");
|
||||
|
||||
const share_type oa_vote = _vote_tally_buffer[a.get_sidechain_vote_id(sidechain)];
|
||||
const share_type ob_vote = _vote_tally_buffer[b.get_sidechain_vote_id(sidechain)];
|
||||
|
||||
if( oa_vote != ob_vote )
|
||||
return oa_vote > ob_vote;
|
||||
return a.vote_id < b.vote_id;
|
||||
});
|
||||
|
||||
return a.get_sidechain_vote_id(sidechain) < b.get_sidechain_vote_id(sidechain);
|
||||
});
|
||||
|
||||
refs.resize(count, refs.front());
|
||||
return refs;
|
||||
|
|
@ -178,222 +182,233 @@ void database::update_worker_votes()
|
|||
|
||||
void database::pay_sons()
|
||||
{
|
||||
time_point_sec now = head_block_time();
|
||||
const time_point_sec now = head_block_time();
|
||||
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
||||
// Current requirement is that we have to pay every 24 hours, so the following check
|
||||
if( dpo.son_budget.value > 0 && ((now - dpo.last_son_payout_time) >= fc::seconds(get_global_properties().parameters.son_pay_time()))) {
|
||||
assert( _son_count_histogram_buffer.size() > 0 );
|
||||
const share_type stake_target = (_total_voting_stake-_son_count_histogram_buffer[0]) / 2;
|
||||
/// accounts that vote for 0 or 1 son do not get to express an opinion on
|
||||
/// the number of sons to have (they abstain and are non-voting accounts)
|
||||
share_type stake_tally = 0;
|
||||
size_t son_count = 0;
|
||||
if( stake_target > 0 )
|
||||
if( dpo.son_budget.value > 0 && ((now - dpo.last_son_payout_time) >= fc::seconds(get_global_properties().parameters.son_pay_time())))
|
||||
{
|
||||
for(const auto& active_sidechain_type : active_sidechain_types)
|
||||
{
|
||||
while( (son_count < _son_count_histogram_buffer.size() - 1)
|
||||
&& (stake_tally <= stake_target) )
|
||||
assert( _son_count_histogram_buffer.at(active_sidechain_type).size() > 0 );
|
||||
const share_type stake_target = (_total_voting_stake-_son_count_histogram_buffer.at(active_sidechain_type)[0]) / 2;
|
||||
/// accounts that vote for 0 or 1 son do not get to express an opinion on
|
||||
/// the number of sons to have (they abstain and are non-voting accounts)
|
||||
share_type stake_tally = 0;
|
||||
size_t son_count = 0;
|
||||
if( stake_target > 0 )
|
||||
{
|
||||
stake_tally += _son_count_histogram_buffer[++son_count];
|
||||
}
|
||||
}
|
||||
const vector<std::reference_wrapper<const son_object>> sons = [this, &son_count]{
|
||||
if(head_block_time() >= HARDFORK_SON3_TIME)
|
||||
return sort_votable_objects<son_index>(std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count));
|
||||
else
|
||||
return sort_votable_objects<son_index>(get_global_properties().parameters.maximum_son_count());
|
||||
}();
|
||||
// After SON2 HF
|
||||
uint64_t total_votes = 0;
|
||||
for( const son_object& son : sons )
|
||||
{
|
||||
total_votes += _vote_tally_buffer[son.vote_id];
|
||||
}
|
||||
int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(total_votes)) - 15, 0);
|
||||
auto get_weight = [&bits_to_drop]( uint64_t son_votes ) {
|
||||
uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) );
|
||||
return weight;
|
||||
};
|
||||
// Before SON2 HF
|
||||
auto get_weight_before_son2_hf = []( uint64_t son_votes ) {
|
||||
int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(son_votes)) - 15, 0);
|
||||
uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) );
|
||||
return weight;
|
||||
};
|
||||
uint64_t weighted_total_txs_signed = 0;
|
||||
share_type son_budget = dpo.son_budget;
|
||||
get_index_type<son_stats_index>().inspect_all_objects([this, &weighted_total_txs_signed, &get_weight, &now, &get_weight_before_son2_hf](const object& o) {
|
||||
const son_statistics_object& s = static_cast<const son_statistics_object&>(o);
|
||||
const auto& idx = get_index_type<son_index>().indices().get<by_id>();
|
||||
auto son_obj = idx.find( s.owner );
|
||||
auto son_weight = get_weight(_vote_tally_buffer[son_obj->vote_id]);
|
||||
if( now < HARDFORK_SON2_TIME ) {
|
||||
son_weight = get_weight_before_son2_hf(_vote_tally_buffer[son_obj->vote_id]);
|
||||
}
|
||||
uint64_t txs_signed = 0;
|
||||
for (const auto &ts : s.txs_signed) {
|
||||
txs_signed = txs_signed + ts.second;
|
||||
}
|
||||
weighted_total_txs_signed += (txs_signed * son_weight);
|
||||
});
|
||||
|
||||
// Now pay off each SON proportional to the number of transactions signed.
|
||||
get_index_type<son_stats_index>().inspect_all_objects([this, &weighted_total_txs_signed, &dpo, &son_budget, &get_weight, &get_weight_before_son2_hf, &now](const object& o) {
|
||||
const son_statistics_object& s = static_cast<const son_statistics_object&>(o);
|
||||
uint64_t txs_signed = 0;
|
||||
for (const auto &ts : s.txs_signed) {
|
||||
txs_signed = txs_signed + ts.second;
|
||||
while( (son_count < _son_count_histogram_buffer.at(active_sidechain_type).size() - 1)
|
||||
&& (stake_tally <= stake_target) )
|
||||
{
|
||||
stake_tally += _son_count_histogram_buffer.at(active_sidechain_type)[++son_count];
|
||||
}
|
||||
}
|
||||
|
||||
if(txs_signed > 0){
|
||||
const auto sons = sort_votable_objects<son_index>(active_sidechain_type,
|
||||
(std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count))
|
||||
);
|
||||
|
||||
// After SON2 HF
|
||||
uint64_t total_votes = 0;
|
||||
for( const son_object& son : sons )
|
||||
{
|
||||
total_votes += _vote_tally_buffer[son.sidechain_vote_ids.at(active_sidechain_type)];
|
||||
}
|
||||
const int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(total_votes)) - 15, 0);
|
||||
auto get_weight = [&bits_to_drop]( uint64_t son_votes ) {
|
||||
const uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) );
|
||||
return weight;
|
||||
};
|
||||
// Before SON2 HF
|
||||
auto get_weight_before_son2_hf = []( uint64_t son_votes ) {
|
||||
const int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(son_votes)) - 15, 0);
|
||||
const uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) );
|
||||
return weight;
|
||||
};
|
||||
uint64_t weighted_total_txs_signed = 0;
|
||||
const share_type son_budget = dpo.son_budget;
|
||||
get_index_type<son_stats_index>().inspect_all_objects([this, &weighted_total_txs_signed, &get_weight, &now, &get_weight_before_son2_hf, &active_sidechain_type](const object& o) {
|
||||
const son_statistics_object& s = static_cast<const son_statistics_object&>(o);
|
||||
const auto& idx = get_index_type<son_index>().indices().get<by_id>();
|
||||
auto son_obj = idx.find( s.owner );
|
||||
auto son_weight = get_weight(_vote_tally_buffer[son_obj->vote_id]);
|
||||
if( now < HARDFORK_SON2_TIME ) {
|
||||
son_weight = get_weight_before_son2_hf(_vote_tally_buffer[son_obj->vote_id]);
|
||||
const auto son_obj = idx.find( s.owner );
|
||||
uint16_t son_weight = 0;
|
||||
if( now >= HARDFORK_SON2_TIME ) {
|
||||
son_weight += get_weight(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]);
|
||||
}
|
||||
share_type pay = (txs_signed * son_weight * son_budget.value)/weighted_total_txs_signed;
|
||||
modify( *son_obj, [&]( son_object& _son_obj)
|
||||
{
|
||||
_son_obj.pay_son_fee(pay, *this);
|
||||
});
|
||||
//Remove the amount paid out to SON from global SON Budget
|
||||
modify( dpo, [&]( dynamic_global_property_object& _dpo )
|
||||
{
|
||||
_dpo.son_budget -= pay;
|
||||
} );
|
||||
//Reset the tx counter in each son statistics object
|
||||
modify( s, [&]( son_statistics_object& _s)
|
||||
{
|
||||
for (const auto &ts : s.txs_signed) {
|
||||
_s.txs_signed.at(ts.first) = 0;
|
||||
else {
|
||||
son_weight += get_weight_before_son2_hf(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]);
|
||||
}
|
||||
const uint64_t txs_signed = s.txs_signed.contains(active_sidechain_type) ? s.txs_signed.at(active_sidechain_type) : 0;
|
||||
weighted_total_txs_signed += (txs_signed * son_weight);
|
||||
});
|
||||
|
||||
// Now pay off each SON proportional to the number of transactions signed.
|
||||
get_index_type<son_stats_index>().inspect_all_objects([this, &weighted_total_txs_signed, &dpo, &son_budget, &get_weight, &get_weight_before_son2_hf, &now, &active_sidechain_type](const object& o) {
|
||||
const son_statistics_object& s = static_cast<const son_statistics_object&>(o);
|
||||
const uint64_t txs_signed = s.txs_signed.contains(active_sidechain_type) ? s.txs_signed.at(active_sidechain_type) : 0;
|
||||
|
||||
if(txs_signed > 0){
|
||||
const auto& idx = get_index_type<son_index>().indices().get<by_id>();
|
||||
auto son_obj = idx.find( s.owner );
|
||||
uint16_t son_weight = 0;
|
||||
if( now >= HARDFORK_SON2_TIME ) {
|
||||
son_weight += get_weight(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
//Note the last son pay out time
|
||||
modify( dpo, [&]( dynamic_global_property_object& _dpo )
|
||||
{
|
||||
_dpo.last_son_payout_time = now;
|
||||
});
|
||||
else {
|
||||
son_weight += get_weight_before_son2_hf(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]);
|
||||
}
|
||||
const share_type pay = (txs_signed * son_weight * son_budget.value)/weighted_total_txs_signed;
|
||||
modify( *son_obj, [&]( son_object& _son_obj)
|
||||
{
|
||||
_son_obj.pay_son_fee(pay, *this);
|
||||
});
|
||||
//Remove the amount paid out to SON from global SON Budget
|
||||
modify( dpo, [&]( dynamic_global_property_object& _dpo )
|
||||
{
|
||||
_dpo.son_budget -= pay;
|
||||
} );
|
||||
//Reset the tx counter in each son statistics object
|
||||
modify( s, [&]( son_statistics_object& _s)
|
||||
{
|
||||
if(_s.txs_signed.contains(active_sidechain_type))
|
||||
_s.txs_signed.at(active_sidechain_type) = 0;
|
||||
});
|
||||
}
|
||||
});
|
||||
//Note the last son pay out time
|
||||
modify( dpo, [&]( dynamic_global_property_object& _dpo )
|
||||
{
|
||||
_dpo.last_son_payout_time = now;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void database::update_son_metrics(const vector<son_info>& curr_active_sons)
|
||||
void database::update_son_metrics(const flat_map<sidechain_type, vector<son_info> >& curr_active_sons)
|
||||
{
|
||||
vector<son_id_type> current_sons;
|
||||
for(const auto& curr_active_sidechain_sons : curr_active_sons) {
|
||||
const auto& sidechain = curr_active_sidechain_sons.first;
|
||||
const auto& _curr_active_sidechain_sons = curr_active_sidechain_sons.second;
|
||||
|
||||
current_sons.reserve(curr_active_sons.size());
|
||||
std::transform(curr_active_sons.begin(), curr_active_sons.end(),
|
||||
std::inserter(current_sons, current_sons.end()),
|
||||
[](const son_info &swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
vector<son_id_type> current_sons;
|
||||
|
||||
const auto& son_idx = get_index_type<son_index>().indices().get< by_id >();
|
||||
for( auto& son : son_idx )
|
||||
{
|
||||
auto& stats = son.statistics(*this);
|
||||
bool is_active_son = (std::find(current_sons.begin(), current_sons.end(), son.id) != current_sons.end());
|
||||
modify( stats, [&]( son_statistics_object& _stats )
|
||||
{
|
||||
if(is_active_son) {
|
||||
_stats.total_voted_time = _stats.total_voted_time + get_global_properties().parameters.maintenance_interval;
|
||||
}
|
||||
_stats.total_downtime += _stats.current_interval_downtime;
|
||||
_stats.current_interval_downtime = 0;
|
||||
for (const auto &str : _stats.sidechain_txs_reported) {
|
||||
_stats.sidechain_txs_reported.at(str.first) = 0;
|
||||
}
|
||||
});
|
||||
current_sons.reserve(_curr_active_sidechain_sons.size());
|
||||
std::transform(_curr_active_sidechain_sons.cbegin(), _curr_active_sidechain_sons.cend(),
|
||||
std::inserter(current_sons, current_sons.end()),
|
||||
[](const son_info &swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
|
||||
const auto &son_idx = get_index_type<son_index>().indices().get<by_id>();
|
||||
for (auto &son : son_idx) {
|
||||
auto &stats = son.statistics(*this);
|
||||
bool is_active_son = (std::find(current_sons.begin(), current_sons.end(), son.id) != current_sons.end());
|
||||
modify(stats, [&](son_statistics_object &_stats) {
|
||||
if (is_active_son) {
|
||||
_stats.total_voted_time[sidechain] = _stats.total_voted_time[sidechain] + get_global_properties().parameters.maintenance_interval;
|
||||
}
|
||||
_stats.total_downtime[sidechain] += _stats.current_interval_downtime[sidechain];
|
||||
_stats.current_interval_downtime[sidechain] = 0;
|
||||
_stats.sidechain_txs_reported[sidechain] = 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void database::update_son_statuses(const vector<son_info>& curr_active_sons, const vector<son_info>& new_active_sons)
|
||||
void database::update_son_statuses( const flat_map<sidechain_type, vector<son_info> >& curr_active_sons,
|
||||
const flat_map<sidechain_type, vector<son_info> >& new_active_sons )
|
||||
{
|
||||
vector<son_id_type> current_sons, new_sons;
|
||||
vector<son_id_type> sons_to_remove, sons_to_add;
|
||||
const auto& idx = get_index_type<son_index>().indices().get<by_id>();
|
||||
for(const auto& new_active_sidechain_sons : new_active_sons) {
|
||||
const auto& sidechain = new_active_sidechain_sons.first;
|
||||
|
||||
current_sons.reserve(curr_active_sons.size());
|
||||
std::transform(curr_active_sons.begin(), curr_active_sons.end(),
|
||||
std::inserter(current_sons, current_sons.end()),
|
||||
[](const son_info &swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
vector<son_id_type> current_sons, new_sons;
|
||||
vector<son_id_type> sons_to_remove, sons_to_add;
|
||||
const auto &idx = get_index_type<son_index>().indices().get<by_id>();
|
||||
|
||||
new_sons.reserve(new_active_sons.size());
|
||||
std::transform(new_active_sons.begin(), new_active_sons.end(),
|
||||
std::inserter(new_sons, new_sons.end()),
|
||||
[](const son_info &swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
|
||||
// find all cur_active_sons members that is not in new_active_sons
|
||||
for_each(current_sons.begin(), current_sons.end(),
|
||||
[&sons_to_remove, &new_sons](const son_id_type& si)
|
||||
{
|
||||
if(std::find(new_sons.begin(), new_sons.end(), si) ==
|
||||
new_sons.end())
|
||||
{
|
||||
sons_to_remove.push_back(si);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
for( const auto& sid : sons_to_remove )
|
||||
{
|
||||
auto son = idx.find( sid );
|
||||
if(son == idx.end()) // SON is deleted already
|
||||
continue;
|
||||
// keep maintenance status for nodes becoming inactive
|
||||
if(son->status == son_status::active)
|
||||
{
|
||||
modify( *son, [&]( son_object& obj ){
|
||||
obj.status = son_status::inactive;
|
||||
});
|
||||
if(curr_active_sons.contains(sidechain)) {
|
||||
current_sons.reserve(curr_active_sons.at(sidechain).size());
|
||||
std::transform(curr_active_sons.at(sidechain).cbegin(), curr_active_sons.at(sidechain).cend(),
|
||||
std::inserter(current_sons, current_sons.end()),
|
||||
[](const son_info &swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// find all new_active_sons members that is not in cur_active_sons
|
||||
for_each(new_sons.begin(), new_sons.end(),
|
||||
[&sons_to_add, ¤t_sons](const son_id_type& si)
|
||||
{
|
||||
if(std::find(current_sons.begin(), current_sons.end(), si) ==
|
||||
current_sons.end())
|
||||
{
|
||||
sons_to_add.push_back(si);
|
||||
}
|
||||
}
|
||||
);
|
||||
new_sons.reserve(new_active_sons.at(sidechain).size());
|
||||
std::transform(new_active_sons.at(sidechain).cbegin(), new_active_sons.at(sidechain).cend(),
|
||||
std::inserter(new_sons, new_sons.end()),
|
||||
[](const son_info &swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
|
||||
for( const auto& sid : sons_to_add )
|
||||
{
|
||||
auto son = idx.find( sid );
|
||||
FC_ASSERT(son != idx.end(), "Invalid SON in active list, id={sonid}.", ("sonid", sid));
|
||||
// keep maintenance status for new nodes
|
||||
if(son->status == son_status::inactive)
|
||||
{
|
||||
modify( *son, [&]( son_object& obj ){
|
||||
obj.status = son_status::active;
|
||||
});
|
||||
}
|
||||
}
|
||||
// find all cur_active_sons members that is not in new_active_sons
|
||||
for_each(current_sons.begin(), current_sons.end(),
|
||||
[&sons_to_remove, &new_sons](const son_id_type &si) {
|
||||
if (std::find(new_sons.begin(), new_sons.end(), si) ==
|
||||
new_sons.end()) {
|
||||
sons_to_remove.push_back(si);
|
||||
}
|
||||
});
|
||||
|
||||
ilog("New SONS");
|
||||
for(size_t i = 0; i < new_sons.size(); i++) {
|
||||
auto son = idx.find( new_sons[i] );
|
||||
if(son == idx.end()) // SON is deleted already
|
||||
for (const auto &sid : sons_to_remove) {
|
||||
auto son = idx.find(sid);
|
||||
if (son == idx.end()) // SON is deleted already
|
||||
continue;
|
||||
ilog( "${s}, status = ${ss}, total_votes = ${sv}", ("s", new_sons[i])("ss", son->status)("sv", son->total_votes) );
|
||||
// keep maintenance status for nodes becoming inactive
|
||||
if (son->statuses.at(sidechain) == son_status::active) {
|
||||
modify(*son, [&](son_object &obj) {
|
||||
obj.statuses.at(sidechain) = son_status::inactive;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// find all new_active_sons members that is not in cur_active_sons
|
||||
for_each(new_sons.begin(), new_sons.end(),
|
||||
[&sons_to_add, ¤t_sons](const son_id_type &si) {
|
||||
if (std::find(current_sons.begin(), current_sons.end(), si) ==
|
||||
current_sons.end()) {
|
||||
sons_to_add.push_back(si);
|
||||
}
|
||||
});
|
||||
|
||||
for (const auto &sid : sons_to_add) {
|
||||
auto son = idx.find(sid);
|
||||
FC_ASSERT(son != idx.end(), "Invalid SON in active list, id={sonid}.", ("sonid", sid));
|
||||
// keep maintenance status for new nodes
|
||||
if (son->statuses.at(sidechain) == son_status::inactive) {
|
||||
modify(*son, [&](son_object &obj) {
|
||||
obj.statuses.at(sidechain) = son_status::active;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ilog("New SONS for sidechain = ${sidechain}", ("sidechain", sidechain));
|
||||
for (size_t i = 0; i < new_sons.size(); i++) {
|
||||
auto son = idx.find(new_sons[i]);
|
||||
if (son == idx.end()) // SON is deleted already
|
||||
continue;
|
||||
ilog("${s}, status = ${ss}, total_votes = ${sv}", ("s", new_sons[i])("ss", son->statuses.at(sidechain))("sv", son->total_votes));
|
||||
}
|
||||
}
|
||||
|
||||
if( sons_to_remove.size() > 0 )
|
||||
{
|
||||
//! Remove inactive sons (when all sidechain inactive)
|
||||
vector<son_id_type> sons_to_remove;
|
||||
const auto &idx = get_index_type<son_index>().indices().get<by_id>();
|
||||
for(const auto& son : idx) {
|
||||
bool inactive_son = true;
|
||||
for(const auto& status : son.statuses) {
|
||||
if (status.second != son_status::inactive)
|
||||
inactive_son = false;
|
||||
}
|
||||
if (inactive_son)
|
||||
sons_to_remove.emplace_back(son.id);
|
||||
}
|
||||
if (sons_to_remove.size() > 0) {
|
||||
remove_inactive_son_proposals(sons_to_remove);
|
||||
}
|
||||
}
|
||||
|
||||
void database::update_son_wallet(const vector<son_info>& new_active_sons)
|
||||
void database::update_son_wallet(const flat_map<sidechain_type, vector<son_info> >& new_active_sons)
|
||||
{
|
||||
bool should_recreate_pw = true;
|
||||
|
||||
|
|
@ -406,8 +421,16 @@ void database::update_son_wallet(const vector<son_info>& new_active_sons)
|
|||
|
||||
bool wallet_son_sets_equal = (cur_wallet_sons.size() == new_active_sons.size());
|
||||
if (wallet_son_sets_equal) {
|
||||
for( size_t i = 0; i < cur_wallet_sons.size(); i++ ) {
|
||||
wallet_son_sets_equal = wallet_son_sets_equal && cur_wallet_sons.at(i) == new_active_sons.at(i);
|
||||
for( const auto& cur_wallet_sidechain_sons : cur_wallet_sons ) {
|
||||
const auto& sidechain = cur_wallet_sidechain_sons.first;
|
||||
const auto& _cur_wallet_sidechain_sons = cur_wallet_sidechain_sons.second;
|
||||
|
||||
wallet_son_sets_equal = wallet_son_sets_equal && (_cur_wallet_sidechain_sons.size() == new_active_sons.at(sidechain).size());
|
||||
if (wallet_son_sets_equal) {
|
||||
for (size_t i = 0; i < _cur_wallet_sidechain_sons.size(); i++) {
|
||||
wallet_son_sets_equal = wallet_son_sets_equal && (_cur_wallet_sidechain_sons.at(i) == new_active_sons.at(sidechain).at(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -420,14 +443,24 @@ void database::update_son_wallet(const vector<son_info>& new_active_sons)
|
|||
}
|
||||
}
|
||||
|
||||
should_recreate_pw = should_recreate_pw && (new_active_sons.size() >= get_chain_properties().immutable_parameters.min_son_count);
|
||||
bool should_recreate_pw_sidechain = false;
|
||||
for(const auto& new_active_sidechain_sons : new_active_sons) {
|
||||
if(new_active_sidechain_sons.second.size() >= get_chain_properties().immutable_parameters.min_son_count)
|
||||
should_recreate_pw_sidechain = true;
|
||||
}
|
||||
should_recreate_pw = should_recreate_pw && should_recreate_pw_sidechain;
|
||||
|
||||
if (should_recreate_pw) {
|
||||
// Create new son_wallet_object, to initiate wallet recreation
|
||||
create<son_wallet_object>( [&]( son_wallet_object& obj ) {
|
||||
obj.valid_from = head_block_time();
|
||||
obj.expires = time_point_sec::maximum();
|
||||
obj.sons.insert(obj.sons.end(), new_active_sons.begin(), new_active_sons.end());
|
||||
for(const auto& new_active_sidechain_sons : new_active_sons){
|
||||
const auto& sidechain = new_active_sidechain_sons.first;
|
||||
const auto& _new_active_sidechain_sons = new_active_sidechain_sons.second;
|
||||
|
||||
obj.sons[sidechain].insert(obj.sons[sidechain].end(), _new_active_sidechain_sons.cbegin(), _new_active_sidechain_sons.cend());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -684,48 +717,87 @@ void database::update_active_sons()
|
|||
}
|
||||
|
||||
assert( _son_count_histogram_buffer.size() > 0 );
|
||||
share_type stake_target = (_total_voting_stake-_son_count_histogram_buffer[0]) / 2;
|
||||
for( const auto& son_count_histogram_buffer : _son_count_histogram_buffer ){
|
||||
assert( son_count_histogram_buffer.second.size() > 0 );
|
||||
}
|
||||
|
||||
const flat_map<sidechain_type, share_type> stake_target = [this]{
|
||||
flat_map<sidechain_type, share_type> stake_target;
|
||||
for( const auto& son_count_histogram_buffer : _son_count_histogram_buffer ){
|
||||
const auto sidechain = son_count_histogram_buffer.first;
|
||||
stake_target[sidechain] = (_total_voting_stake-son_count_histogram_buffer.second[0]) / 2;
|
||||
}
|
||||
return stake_target;
|
||||
}();
|
||||
|
||||
/// accounts that vote for 0 or 1 son do not get to express an opinion on
|
||||
/// the number of sons to have (they abstain and are non-voting accounts)
|
||||
|
||||
share_type stake_tally = 0;
|
||||
|
||||
size_t son_count = 0;
|
||||
if( stake_target > 0 )
|
||||
{
|
||||
while( (son_count < _son_count_histogram_buffer.size() - 1)
|
||||
&& (stake_tally <= stake_target) )
|
||||
flat_map<sidechain_type, share_type> stake_tally = []{
|
||||
flat_map<sidechain_type, share_type> stake_tally;
|
||||
for(const auto& active_sidechain_type : active_sidechain_types){
|
||||
stake_tally[active_sidechain_type] = 0;
|
||||
}
|
||||
return stake_tally;
|
||||
}();
|
||||
flat_map<sidechain_type, size_t> son_count = []{
|
||||
flat_map<sidechain_type, size_t> son_count;
|
||||
for(const auto& active_sidechain_type : active_sidechain_types){
|
||||
son_count[active_sidechain_type] = 0;
|
||||
}
|
||||
return son_count;
|
||||
}();
|
||||
for( const auto& stake_target_sidechain : stake_target ){
|
||||
const auto sidechain = stake_target_sidechain.first;
|
||||
if( stake_target_sidechain.second > 0 )
|
||||
{
|
||||
stake_tally += _son_count_histogram_buffer[++son_count];
|
||||
while( (son_count[sidechain] < _son_count_histogram_buffer.at(sidechain).size() - 1)
|
||||
&& (stake_tally[sidechain] <= stake_target_sidechain.second) )
|
||||
{
|
||||
stake_tally[sidechain] += _son_count_histogram_buffer.at(sidechain)[ ++son_count[sidechain] ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const global_property_object& gpo = get_global_properties();
|
||||
const vector<std::reference_wrapper<const son_object>> sons = [this, &son_count]{
|
||||
if(head_block_time() >= HARDFORK_SON3_TIME)
|
||||
return sort_votable_objects<son_index>(std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count));
|
||||
else
|
||||
return sort_votable_objects<son_index>(get_global_properties().parameters.maximum_son_count());
|
||||
}();
|
||||
|
||||
const chain_property_object& cpo = get_chain_properties();
|
||||
const auto& all_sons = get_index_type<son_index>().indices();
|
||||
flat_map<sidechain_type, vector<std::reference_wrapper<const son_object> > > sons;
|
||||
for(const auto& active_sidechain_type : active_sidechain_types)
|
||||
{
|
||||
if(head_block_time() >= HARDFORK_SON3_TIME) {
|
||||
sons[active_sidechain_type] = sort_votable_objects<son_index>(active_sidechain_type,
|
||||
(std::max(son_count.at(active_sidechain_type) * 2 + 1, (size_t)cpo.immutable_parameters.min_son_count)));
|
||||
}
|
||||
else {
|
||||
sons[active_sidechain_type] = sort_votable_objects<son_index>(active_sidechain_type, get_global_properties().parameters.maximum_son_count());
|
||||
}
|
||||
}
|
||||
|
||||
auto& local_vote_buffer_ref = _vote_tally_buffer;
|
||||
for( const son_object& son : all_sons )
|
||||
{
|
||||
if(son.status == son_status::request_maintenance)
|
||||
for(const auto& status: son.statuses)
|
||||
{
|
||||
auto& stats = son.statistics(*this);
|
||||
modify( stats, [&]( son_statistics_object& _s){
|
||||
_s.last_down_timestamp = head_block_time();
|
||||
const auto& sidechain = status.first;
|
||||
if(status.second == son_status::in_maintenance)
|
||||
{
|
||||
auto &stats = son.statistics(*this);
|
||||
modify(stats, [&](son_statistics_object &_s) {
|
||||
_s.last_down_timestamp[sidechain] = head_block_time();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
modify( son, [local_vote_buffer_ref]( son_object& obj ){
|
||||
obj.total_votes = local_vote_buffer_ref[obj.vote_id];
|
||||
if(obj.status == son_status::request_maintenance)
|
||||
obj.status = son_status::in_maintenance;
|
||||
});
|
||||
for(const auto& sidechain_vote_id : obj.sidechain_vote_ids ){
|
||||
obj.total_votes[sidechain_vote_id.first] = local_vote_buffer_ref[sidechain_vote_id.second];
|
||||
}
|
||||
for(auto& status: obj.statuses)
|
||||
{
|
||||
if (status.second == son_status::request_maintenance)
|
||||
status.second = son_status::in_maintenance;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Update SON authority
|
||||
|
|
@ -733,21 +805,24 @@ void database::update_active_sons()
|
|||
{
|
||||
modify( get(gpo.parameters.son_account()), [&]( account_object& a )
|
||||
{
|
||||
set<account_id_type> account_ids;
|
||||
for(const auto& sidechain_sons : sons)
|
||||
{
|
||||
for( const son_object& son : sidechain_sons.second )
|
||||
{
|
||||
account_ids.emplace(son.son_account);
|
||||
}
|
||||
}
|
||||
|
||||
if( head_block_time() < HARDFORK_533_TIME )
|
||||
{
|
||||
map<account_id_type, uint64_t> weights;
|
||||
a.active.weight_threshold = 0;
|
||||
a.active.account_auths.clear();
|
||||
|
||||
for( const son_object& son : sons )
|
||||
{
|
||||
weights.emplace(son.son_account, uint64_t(1));
|
||||
}
|
||||
|
||||
for( const auto& weight : weights )
|
||||
for( const auto& account_id : account_ids )
|
||||
{
|
||||
// Ensure that everyone has at least one vote. Zero weights aren't allowed.
|
||||
a.active.account_auths[weight.first] += 1;
|
||||
a.active.account_auths[account_id] += 1;
|
||||
a.active.weight_threshold += 1;
|
||||
}
|
||||
|
||||
|
|
@ -758,8 +833,10 @@ void database::update_active_sons()
|
|||
else
|
||||
{
|
||||
vote_counter vc;
|
||||
for( const son_object& son : sons )
|
||||
vc.add( son.son_account, UINT64_C(1) );
|
||||
for( const auto& account_id : account_ids )
|
||||
{
|
||||
vc.add(account_id, UINT64_C(1));
|
||||
}
|
||||
vc.finish_2_3( a.active );
|
||||
}
|
||||
} );
|
||||
|
|
@ -767,22 +844,36 @@ void database::update_active_sons()
|
|||
|
||||
|
||||
// Compare current and to-be lists of active sons
|
||||
auto cur_active_sons = gpo.active_sons;
|
||||
vector<son_info> new_active_sons;
|
||||
const auto cur_active_sons = gpo.active_sons;
|
||||
flat_map<sidechain_type, vector<son_info> > new_active_sons;
|
||||
const auto &acc = get(gpo.parameters.son_account());
|
||||
for( const son_object& son : sons ) {
|
||||
son_info swi;
|
||||
swi.son_id = son.id;
|
||||
swi.weight = acc.active.account_auths.at(son.son_account);
|
||||
swi.signing_key = son.signing_key;
|
||||
swi.sidechain_public_keys = son.sidechain_public_keys;
|
||||
new_active_sons.push_back(swi);
|
||||
for( const auto& sidechain_sons : sons ){
|
||||
const auto& sidechain = sidechain_sons.first;
|
||||
const auto& sons_array = sidechain_sons.second;
|
||||
|
||||
new_active_sons[sidechain].reserve(sons_array.size());
|
||||
for( const son_object& son : sons_array ) {
|
||||
son_info swi;
|
||||
swi.son_id = son.id;
|
||||
swi.weight = acc.active.account_auths.at(son.son_account);
|
||||
swi.signing_key = son.signing_key;
|
||||
swi.public_key = son.sidechain_public_keys.at(sidechain);
|
||||
new_active_sons[sidechain].push_back(swi);
|
||||
}
|
||||
}
|
||||
|
||||
bool son_sets_equal = (cur_active_sons.size() == new_active_sons.size());
|
||||
if (son_sets_equal) {
|
||||
for( size_t i = 0; i < cur_active_sons.size(); i++ ) {
|
||||
son_sets_equal = son_sets_equal && cur_active_sons.at(i) == new_active_sons.at(i);
|
||||
for( const auto& cur_active_sidechain_sons : cur_active_sons ){
|
||||
const auto& sidechain = cur_active_sidechain_sons.first;
|
||||
const auto& _cur_active_sidechain_sons = cur_active_sidechain_sons.second;
|
||||
|
||||
son_sets_equal = son_sets_equal && (_cur_active_sidechain_sons.size() == new_active_sons.at(sidechain).size());
|
||||
if (son_sets_equal) {
|
||||
for (size_t i = 0; i < _cur_active_sidechain_sons.size(); i++) {
|
||||
son_sets_equal = son_sets_equal && (_cur_active_sidechain_sons.at(i) == new_active_sons.at(sidechain).at(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -797,28 +888,37 @@ void database::update_active_sons()
|
|||
modify(gpo, [&]( global_property_object& gp ){
|
||||
gp.active_sons.clear();
|
||||
gp.active_sons.reserve(new_active_sons.size());
|
||||
gp.active_sons.insert(gp.active_sons.end(), new_active_sons.begin(), new_active_sons.end());
|
||||
});
|
||||
for( const auto& new_active_sidechain_sons : new_active_sons ) {
|
||||
const auto& sidechain = new_active_sidechain_sons.first;
|
||||
const auto& _new_active_sidechain_sons = new_active_sidechain_sons.second;
|
||||
|
||||
const son_schedule_object& sso = son_schedule_id_type()(*this);
|
||||
modify(sso, [&](son_schedule_object& _sso)
|
||||
{
|
||||
flat_set<son_id_type> active_sons;
|
||||
active_sons.reserve(gpo.active_sons.size());
|
||||
std::transform(gpo.active_sons.begin(), gpo.active_sons.end(),
|
||||
std::inserter(active_sons, active_sons.end()),
|
||||
[](const son_info& swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
_sso.scheduler.update(active_sons);
|
||||
// similar to witness, produce schedule for sons
|
||||
if(cur_active_sons.size() == 0 && new_active_sons.size() > 0)
|
||||
{
|
||||
witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV);
|
||||
for( size_t i=0; i<new_active_sons.size(); ++i )
|
||||
_sso.scheduler.produce_schedule(rng);
|
||||
gp.active_sons[sidechain].reserve(_new_active_sidechain_sons.size());
|
||||
gp.active_sons[sidechain].insert(gp.active_sons[sidechain].end(), _new_active_sidechain_sons.cbegin(), _new_active_sidechain_sons.cend());
|
||||
}
|
||||
});
|
||||
|
||||
for(const auto& active_sidechain_type : active_sidechain_types)
|
||||
{
|
||||
const son_schedule_object& sidechain_sso = son_schedule_id_type(get_son_schedule_id(active_sidechain_type))(*this);
|
||||
modify(sidechain_sso, [&](son_schedule_object& _sso)
|
||||
{
|
||||
flat_set<son_id_type> active_sons;
|
||||
active_sons.reserve(gpo.active_sons.at(active_sidechain_type).size());
|
||||
std::transform(gpo.active_sons.at(active_sidechain_type).cbegin(), gpo.active_sons.at(active_sidechain_type).cend(),
|
||||
std::inserter(active_sons, active_sons.end()),
|
||||
[](const son_info& swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
_sso.scheduler.update(active_sons);
|
||||
// similar to witness, produce schedule for sons
|
||||
if(cur_active_sons.at(active_sidechain_type).size() == 0 && new_active_sons.at(active_sidechain_type).size() > 0)
|
||||
{
|
||||
witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV);
|
||||
for( size_t i=0; i<new_active_sons.at(active_sidechain_type).size(); ++i )
|
||||
_sso.scheduler.produce_schedule(rng);
|
||||
}
|
||||
});
|
||||
}
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
void database::initialize_budget_record( fc::time_point_sec now, budget_record& rec )const
|
||||
|
|
@ -2097,7 +2197,9 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
|
|||
d._vote_tally_buffer.resize(props.next_available_vote_id);
|
||||
d._witness_count_histogram_buffer.resize(props.parameters.maximum_witness_count / 2 + 1);
|
||||
d._committee_count_histogram_buffer.resize(props.parameters.maximum_committee_count / 2 + 1);
|
||||
d._son_count_histogram_buffer.resize(props.parameters.maximum_son_count() / 2 + 1);
|
||||
for( auto& son_count_histogram_buffer : d._son_count_histogram_buffer ){
|
||||
son_count_histogram_buffer.second.resize(props.parameters.maximum_son_count() / 2 + 1);
|
||||
}
|
||||
d._total_voting_stake = 0;
|
||||
|
||||
auto balance_type = vesting_balance_type::normal;
|
||||
|
|
@ -2197,17 +2299,21 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
|
|||
// same rationale as for witnesses
|
||||
d._committee_count_histogram_buffer[offset] += voting_stake;
|
||||
}
|
||||
if( opinion_account.options.num_son() <= props.parameters.maximum_son_count() )
|
||||
{
|
||||
uint16_t offset = std::min(size_t(opinion_account.options.num_son()/2),
|
||||
d._son_count_histogram_buffer.size() - 1);
|
||||
// votes for a number greater than maximum_son_count
|
||||
// are turned into votes for maximum_son_count.
|
||||
//
|
||||
// in particular, this takes care of the case where a
|
||||
// member was voting for a high number, then the
|
||||
// parameter was lowered.
|
||||
d._son_count_histogram_buffer[offset] += voting_stake;
|
||||
FC_ASSERT( opinion_account.options.extensions.value.num_son.valid() , "Invalid son number" );
|
||||
for(const auto& num_sidechain_son : *opinion_account.options.extensions.value.num_son) {
|
||||
const auto sidechain = num_sidechain_son.first;
|
||||
const auto& num_son = num_sidechain_son.second;
|
||||
if (num_son <= props.parameters.maximum_son_count()) {
|
||||
uint16_t offset = std::min(size_t(num_son / 2),
|
||||
d._son_count_histogram_buffer.at(sidechain).size() - 1);
|
||||
// votes for a number greater than maximum_son_count
|
||||
// are turned into votes for maximum_son_count.
|
||||
//
|
||||
// in particular, this takes care of the case where a
|
||||
// member was voting for a high number, then the
|
||||
// parameter was lowered.
|
||||
d._son_count_histogram_buffer.at(sidechain)[offset] += voting_stake;
|
||||
}
|
||||
}
|
||||
|
||||
d._total_voting_stake += voting_stake;
|
||||
|
|
@ -2222,10 +2328,20 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
|
|||
private:
|
||||
vector<uint64_t>& target;
|
||||
};
|
||||
struct clear_canary_map {
|
||||
clear_canary_map(flat_map<sidechain_type, vector<uint64_t> >& target): target(target){}
|
||||
~clear_canary_map() {
|
||||
for(auto& sidechain_target : target){
|
||||
sidechain_target.second.clear();
|
||||
}
|
||||
}
|
||||
private:
|
||||
flat_map<sidechain_type, vector<uint64_t> >& target;
|
||||
};
|
||||
clear_canary a(_witness_count_histogram_buffer),
|
||||
b(_committee_count_histogram_buffer),
|
||||
d(_son_count_histogram_buffer),
|
||||
c(_vote_tally_buffer);
|
||||
clear_canary_map d{_son_count_histogram_buffer};
|
||||
|
||||
perform_son_tasks();
|
||||
update_top_n_authorities(*this);
|
||||
|
|
|
|||
|
|
@ -74,21 +74,31 @@ witness_id_type database::get_scheduled_witness( uint32_t slot_num )const
|
|||
return wid;
|
||||
}
|
||||
|
||||
son_id_type database::get_scheduled_son( uint32_t slot_num )const
|
||||
unsigned_int database::get_son_schedule_id( sidechain_type type )const
|
||||
{
|
||||
static const map<sidechain_type, unsigned_int> schedule_map = {
|
||||
{ sidechain_type::hive, 0 },
|
||||
{ sidechain_type::bitcoin, 1 }
|
||||
};
|
||||
|
||||
return schedule_map.at(type);
|
||||
}
|
||||
|
||||
son_id_type database::get_scheduled_son( sidechain_type type, uint32_t slot_num )const
|
||||
{
|
||||
son_id_type sid;
|
||||
const global_property_object& gpo = get_global_properties();
|
||||
if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM)
|
||||
{
|
||||
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
||||
const son_schedule_object& sso = son_schedule_id_type()(*this);
|
||||
const son_schedule_object& sso = son_schedule_id_type(get_son_schedule_id(type))(*this);
|
||||
uint64_t current_aslot = dpo.current_aslot + slot_num;
|
||||
return sso.current_shuffled_sons[ current_aslot % sso.current_shuffled_sons.size() ];
|
||||
}
|
||||
if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM &&
|
||||
slot_num != 0 )
|
||||
{
|
||||
const son_schedule_object& sso = son_schedule_id_type()(*this);
|
||||
const son_schedule_object& sso = son_schedule_id_type(get_son_schedule_id(type))(*this);
|
||||
// ask the near scheduler who goes in the given slot
|
||||
bool slot_is_near = sso.scheduler.get_slot(slot_num-1, sid);
|
||||
if(! slot_is_near)
|
||||
|
|
@ -191,36 +201,41 @@ void database::update_witness_schedule()
|
|||
|
||||
void database::update_son_schedule()
|
||||
{
|
||||
const son_schedule_object& sso = son_schedule_id_type()(*this);
|
||||
const global_property_object& gpo = get_global_properties();
|
||||
|
||||
if( head_block_num() % gpo.active_sons.size() == 0 )
|
||||
for(const auto& active_sidechain_type : active_sidechain_types)
|
||||
{
|
||||
modify( sso, [&]( son_schedule_object& _sso )
|
||||
const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(active_sidechain_type)));
|
||||
if( head_block_num() % gpo.active_sons.at(active_sidechain_type).size() == 0)
|
||||
{
|
||||
_sso.current_shuffled_sons.clear();
|
||||
_sso.current_shuffled_sons.reserve( gpo.active_sons.size() );
|
||||
|
||||
for( const son_info& w : gpo.active_sons )
|
||||
_sso.current_shuffled_sons.push_back( w.son_id );
|
||||
|
||||
auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32;
|
||||
for( uint32_t i = 0; i < _sso.current_shuffled_sons.size(); ++i )
|
||||
modify( sidechain_sso, [&]( son_schedule_object& _sso )
|
||||
{
|
||||
/// High performance random generator
|
||||
/// http://xorshift.di.unimi.it/
|
||||
uint64_t k = now_hi + uint64_t(i)*2685821657736338717ULL;
|
||||
k ^= (k >> 12);
|
||||
k ^= (k << 25);
|
||||
k ^= (k >> 27);
|
||||
k *= 2685821657736338717ULL;
|
||||
_sso.current_shuffled_sons.clear();
|
||||
_sso.current_shuffled_sons.reserve( gpo.active_sons.at(active_sidechain_type).size() );
|
||||
|
||||
uint32_t jmax = _sso.current_shuffled_sons.size() - i;
|
||||
uint32_t j = i + k%jmax;
|
||||
std::swap( _sso.current_shuffled_sons[i],
|
||||
_sso.current_shuffled_sons[j] );
|
||||
}
|
||||
});
|
||||
for ( const son_info &w : gpo.active_sons.at(active_sidechain_type) ) {
|
||||
_sso.current_shuffled_sons.push_back(w.son_id);
|
||||
}
|
||||
|
||||
auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32;
|
||||
|
||||
for (uint32_t i = 0; i < _sso.current_shuffled_sons.size(); ++i)
|
||||
{
|
||||
/// High performance random generator
|
||||
/// http://xorshift.di.unimi.it/
|
||||
uint64_t k = now_hi + uint64_t(i) * 2685821657736338717ULL;
|
||||
k ^= (k >> 12);
|
||||
k ^= (k << 25);
|
||||
k ^= (k >> 27);
|
||||
k *= 2685821657736338717ULL;
|
||||
|
||||
uint32_t jmax = _sso.current_shuffled_sons.size() - i;
|
||||
uint32_t j = i + k % jmax;
|
||||
std::swap(_sso.current_shuffled_sons[i],
|
||||
_sso.current_shuffled_sons[j]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -309,7 +324,15 @@ void database::update_son_schedule(const signed_block& next_block)
|
|||
auto start = fc::time_point::now();
|
||||
const global_property_object& gpo = get_global_properties();
|
||||
const son_schedule_object& sso = get(son_schedule_id_type());
|
||||
uint32_t schedule_needs_filled = gpo.active_sons.size();
|
||||
const flat_map<sidechain_type, uint32_t> schedule_needs_filled = [&gpo]()
|
||||
{
|
||||
flat_map<sidechain_type, uint32_t> schedule_needs_filled;
|
||||
for(const auto& sidechain_active_sons : gpo.active_sons)
|
||||
{
|
||||
schedule_needs_filled[sidechain_active_sons.first] = sidechain_active_sons.second.size();
|
||||
}
|
||||
return schedule_needs_filled;
|
||||
}();
|
||||
uint32_t schedule_slot = get_slot_at_time(next_block.timestamp);
|
||||
|
||||
// We shouldn't be able to generate _pending_block with timestamp
|
||||
|
|
@ -319,48 +342,52 @@ void database::update_son_schedule(const signed_block& next_block)
|
|||
|
||||
assert( schedule_slot > 0 );
|
||||
|
||||
son_id_type first_son;
|
||||
bool slot_is_near = sso.scheduler.get_slot( schedule_slot-1, first_son );
|
||||
|
||||
son_id_type son;
|
||||
|
||||
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
||||
|
||||
assert( dpo.random.data_size() == witness_scheduler_rng::seed_length );
|
||||
assert( witness_scheduler_rng::seed_length == sso.rng_seed.size() );
|
||||
|
||||
modify(sso, [&](son_schedule_object& _sso)
|
||||
for(const auto& active_sidechain_type : active_sidechain_types)
|
||||
{
|
||||
_sso.slots_since_genesis += schedule_slot;
|
||||
witness_scheduler_rng rng(sso.rng_seed.data, _sso.slots_since_genesis);
|
||||
const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(active_sidechain_type)));
|
||||
son_id_type first_son;
|
||||
bool slot_is_near = sidechain_sso.scheduler.get_slot( schedule_slot-1, first_son );
|
||||
son_id_type son_id;
|
||||
|
||||
_sso.scheduler._min_token_count = std::max(int(gpo.active_sons.size()) / 2, 1);
|
||||
modify(sidechain_sso, [&](son_schedule_object& _sso)
|
||||
{
|
||||
_sso.slots_since_genesis += schedule_slot;
|
||||
witness_scheduler_rng rng(_sso.rng_seed.data, _sso.slots_since_genesis);
|
||||
|
||||
_sso.scheduler._min_token_count = std::max(int(gpo.active_sons.at(active_sidechain_type).size()) / 2, 1);
|
||||
|
||||
if( slot_is_near )
|
||||
{
|
||||
uint32_t drain = schedule_slot;
|
||||
while( drain > 0 )
|
||||
{
|
||||
if( _sso.scheduler.size() == 0 )
|
||||
break;
|
||||
_sso.scheduler.consume_schedule();
|
||||
--drain;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_sso.scheduler.reset_schedule( first_son );
|
||||
}
|
||||
while( !_sso.scheduler.get_slot(schedule_needs_filled.at(active_sidechain_type), son_id) )
|
||||
{
|
||||
if( _sso.scheduler.produce_schedule(rng) & emit_turn )
|
||||
memcpy(_sso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size());
|
||||
}
|
||||
_sso.last_scheduling_block = next_block.block_num();
|
||||
_sso.recent_slots_filled = (
|
||||
(_sso.recent_slots_filled << 1)
|
||||
+ 1) << (schedule_slot - 1);
|
||||
});
|
||||
}
|
||||
|
||||
if( slot_is_near )
|
||||
{
|
||||
uint32_t drain = schedule_slot;
|
||||
while( drain > 0 )
|
||||
{
|
||||
if( _sso.scheduler.size() == 0 )
|
||||
break;
|
||||
_sso.scheduler.consume_schedule();
|
||||
--drain;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_sso.scheduler.reset_schedule( first_son );
|
||||
}
|
||||
while( !_sso.scheduler.get_slot(schedule_needs_filled, son) )
|
||||
{
|
||||
if( _sso.scheduler.produce_schedule(rng) & emit_turn )
|
||||
memcpy(_sso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size());
|
||||
}
|
||||
_sso.last_scheduling_block = next_block.block_num();
|
||||
_sso.recent_slots_filled = (
|
||||
(_sso.recent_slots_filled << 1)
|
||||
+ 1) << (schedule_slot - 1);
|
||||
});
|
||||
auto end = fc::time_point::now();
|
||||
static uint64_t total_time = 0;
|
||||
static uint64_t calls = 0;
|
||||
|
|
|
|||
|
|
@ -245,7 +245,16 @@ namespace graphene { namespace chain {
|
|||
witness_id_type get_scheduled_witness(uint32_t slot_num)const;
|
||||
|
||||
/**
|
||||
* @brief Get the son scheduled for block production in a slot.
|
||||
* @brief Get son schedule id for the given sidechain_type.
|
||||
*
|
||||
* type sidechain_type we getting schedule.
|
||||
*
|
||||
* returns Id of the schedule object.
|
||||
*/
|
||||
unsigned_int get_son_schedule_id(sidechain_type type)const;
|
||||
|
||||
/**
|
||||
* @brief Get the bitcoin or hive son scheduled for block production in a slot.
|
||||
*
|
||||
* slot_num always corresponds to a time in the future.
|
||||
*
|
||||
|
|
@ -258,7 +267,7 @@ namespace graphene { namespace chain {
|
|||
*
|
||||
* Passing slot_num == 0 returns GRAPHENE_NULL_WITNESS
|
||||
*/
|
||||
son_id_type get_scheduled_son(uint32_t slot_num)const;
|
||||
son_id_type get_scheduled_son(sidechain_type type, uint32_t slot_num)const;
|
||||
|
||||
/**
|
||||
* Get the time at which the given slot occurs.
|
||||
|
|
@ -313,7 +322,7 @@ namespace graphene { namespace chain {
|
|||
fc::optional<operation> create_son_deregister_proposal( son_id_type son_id, account_id_type paying_son );
|
||||
signed_transaction create_signed_transaction( const fc::ecc::private_key& signing_private_key, const operation& op );
|
||||
bool is_son_dereg_valid( son_id_type son_id );
|
||||
bool is_son_active( son_id_type son_id );
|
||||
bool is_son_active( sidechain_type type, son_id_type son_id );
|
||||
bool is_asset_creation_allowed(const string& symbol);
|
||||
|
||||
time_point_sec head_block_time()const;
|
||||
|
|
@ -517,6 +526,9 @@ namespace graphene { namespace chain {
|
|||
template<class Index>
|
||||
vector<std::reference_wrapper<const typename Index::object_type>> sort_votable_objects(size_t count)const;
|
||||
|
||||
template<class Index>
|
||||
vector<std::reference_wrapper<const typename Index::object_type>> sort_votable_objects(sidechain_type sidechain, size_t count)const;
|
||||
|
||||
//////////////////// db_block.cpp ////////////////////
|
||||
|
||||
public:
|
||||
|
|
@ -571,13 +583,14 @@ namespace graphene { namespace chain {
|
|||
void perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props);
|
||||
void update_active_witnesses();
|
||||
void update_active_committee_members();
|
||||
void update_son_metrics( const vector<son_info>& curr_active_sons );
|
||||
void update_son_metrics( const flat_map<sidechain_type, vector<son_info> >& curr_active_sons );
|
||||
void update_active_sons();
|
||||
void remove_son_proposal( const proposal_object& proposal );
|
||||
void remove_inactive_son_down_proposals( const vector<son_id_type>& son_ids_to_remove );
|
||||
void remove_inactive_son_proposals( const vector<son_id_type>& son_ids_to_remove );
|
||||
void update_son_statuses( const vector<son_info>& cur_active_sons, const vector<son_info>& new_active_sons );
|
||||
void update_son_wallet( const vector<son_info>& new_active_sons );
|
||||
void update_son_statuses( const flat_map<sidechain_type, vector<son_info> >& curr_active_sons,
|
||||
const flat_map<sidechain_type, vector<son_info> >& new_active_sons );
|
||||
void update_son_wallet( const flat_map<sidechain_type, vector<son_info> >& new_active_sons );
|
||||
void update_worker_votes();
|
||||
|
||||
public:
|
||||
|
|
@ -616,11 +629,17 @@ namespace graphene { namespace chain {
|
|||
uint16_t _current_op_in_trx = 0;
|
||||
uint32_t _current_virtual_op = 0;
|
||||
|
||||
vector<uint64_t> _vote_tally_buffer;
|
||||
vector<uint64_t> _witness_count_histogram_buffer;
|
||||
vector<uint64_t> _committee_count_histogram_buffer;
|
||||
vector<uint64_t> _son_count_histogram_buffer;
|
||||
uint64_t _total_voting_stake;
|
||||
vector<uint64_t> _vote_tally_buffer;
|
||||
vector<uint64_t> _witness_count_histogram_buffer;
|
||||
vector<uint64_t> _committee_count_histogram_buffer;
|
||||
flat_map<sidechain_type, vector<uint64_t> > _son_count_histogram_buffer = []{
|
||||
flat_map<sidechain_type, vector<uint64_t> > son_count_histogram_buffer;
|
||||
for(const auto& active_sidechain_type : active_sidechain_types){
|
||||
son_count_histogram_buffer[active_sidechain_type] = vector<uint64_t>{};
|
||||
}
|
||||
return son_count_histogram_buffer;
|
||||
}();
|
||||
uint64_t _total_voting_stake;
|
||||
|
||||
flat_map<uint32_t,block_id_type> _checkpoints;
|
||||
|
||||
|
|
|
|||
|
|
@ -49,10 +49,18 @@ namespace graphene { namespace chain {
|
|||
chain_parameters parameters;
|
||||
optional<chain_parameters> pending_parameters;
|
||||
|
||||
uint32_t next_available_vote_id = 0;
|
||||
vector<committee_member_id_type> active_committee_members; // updated once per maintenance interval
|
||||
flat_set<witness_id_type> active_witnesses; // updated once per maintenance interval
|
||||
vector<son_info> active_sons; // updated once per maintenance interval
|
||||
uint32_t next_available_vote_id = 0;
|
||||
vector<committee_member_id_type> active_committee_members; // updated once per maintenance interval
|
||||
flat_set<witness_id_type> active_witnesses; // updated once per maintenance interval
|
||||
flat_map<sidechain_type, vector<son_info> > active_sons = []() // updated once per maintenance interval
|
||||
{
|
||||
flat_map<sidechain_type, vector<son_info> > active_sons;
|
||||
for(const auto& active_sidechain_type : active_sidechain_types)
|
||||
{
|
||||
active_sons[active_sidechain_type] = vector<son_info>();
|
||||
}
|
||||
return active_sons;
|
||||
}();
|
||||
// n.b. witness scheduling is done by witness_schedule object
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <graphene/chain/protocol/special_authority.hpp>
|
||||
#include <graphene/chain/protocol/types.hpp>
|
||||
#include <graphene/chain/protocol/vote.hpp>
|
||||
#include <graphene/chain/sidechain_defs.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
|
|
@ -39,7 +40,15 @@ namespace graphene { namespace chain {
|
|||
{
|
||||
struct ext
|
||||
{
|
||||
optional< uint16_t > num_son = 0;
|
||||
/// The number of active son members this account votes the blockchain should appoint
|
||||
/// Must not exceed the actual number of son members voted for in @ref votes
|
||||
optional< flat_map<sidechain_type, uint16_t> > num_son = []{
|
||||
flat_map<sidechain_type, uint16_t> num_son;
|
||||
for(const auto& active_sidechain_type : active_sidechain_types){
|
||||
num_son[active_sidechain_type] = 0;
|
||||
}
|
||||
return num_son;
|
||||
}();
|
||||
};
|
||||
|
||||
/// The memo key is the key this account will typically use to encrypt/sign transaction memos and other non-
|
||||
|
|
@ -57,14 +66,11 @@ namespace graphene { namespace chain {
|
|||
/// The number of active committee members this account votes the blockchain should appoint
|
||||
/// Must not exceed the actual number of committee members voted for in @ref votes
|
||||
uint16_t num_committee = 0;
|
||||
/// The number of active son members this account votes the blockchain should appoint
|
||||
/// Must not exceed the actual number of son members voted for in @ref votes
|
||||
uint16_t num_son() const { return extensions.value.num_son.valid() ? *extensions.value.num_son : 0; }
|
||||
/// This is the list of vote IDs this account votes for. The weight of these votes is determined by this
|
||||
/// account's balance of core asset.
|
||||
flat_set<vote_id_type> votes;
|
||||
extension< ext > extensions;
|
||||
|
||||
|
||||
/// Whether this account is voting
|
||||
inline bool is_voting() const
|
||||
{
|
||||
|
|
@ -249,7 +255,7 @@ namespace graphene { namespace chain {
|
|||
*/
|
||||
struct account_upgrade_operation : public base_operation
|
||||
{
|
||||
struct fee_parameters_type {
|
||||
struct fee_parameters_type {
|
||||
uint64_t membership_annual_fee = 2000 * GRAPHENE_BLOCKCHAIN_PRECISION;
|
||||
uint64_t membership_lifetime_fee = 10000 * GRAPHENE_BLOCKCHAIN_PRECISION; ///< the cost to upgrade to a lifetime member
|
||||
};
|
||||
|
|
@ -294,7 +300,7 @@ namespace graphene { namespace chain {
|
|||
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT(graphene::chain::account_options::ext, (num_son) )
|
||||
FC_REFLECT(graphene::chain::account_options::ext, (num_son))
|
||||
FC_REFLECT(graphene::chain::account_options, (memo_key)(voting_account)(num_witness)(num_committee)(votes)(extensions))
|
||||
// FC_REFLECT_TYPENAME( graphene::chain::account_whitelist_operation::account_listing)
|
||||
FC_REFLECT_ENUM( graphene::chain::account_whitelist_operation::account_listing,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace graphene { namespace chain {
|
|||
asset fee;
|
||||
account_id_type payer;
|
||||
|
||||
vector<son_info> sons;
|
||||
flat_map<sidechain_type, vector<son_info> > sons;
|
||||
|
||||
account_id_type fee_payer()const { return payer; }
|
||||
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
|
||||
|
|
|
|||
|
|
@ -59,7 +59,8 @@ struct vote_id_type
|
|||
committee,
|
||||
witness,
|
||||
worker,
|
||||
son,
|
||||
son_bitcoin,
|
||||
son_hive,
|
||||
VOTE_TYPE_COUNT
|
||||
};
|
||||
|
||||
|
|
@ -144,7 +145,7 @@ void from_variant( const fc::variant& var, graphene::chain::vote_id_type& vo, ui
|
|||
|
||||
FC_REFLECT_TYPENAME( fc::flat_set<graphene::chain::vote_id_type> )
|
||||
|
||||
FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(son)(VOTE_TYPE_COUNT) )
|
||||
FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(son_bitcoin)(son_hive)(VOTE_TYPE_COUNT) )
|
||||
FC_REFLECT( graphene::chain::vote_id_type, (content) )
|
||||
|
||||
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vote_id_type )
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace graphene { namespace chain {
|
|||
time_point_sec expires;
|
||||
|
||||
sidechain_address_object() :
|
||||
sidechain(sidechain_type::bitcoin),
|
||||
sidechain(sidechain_type::bitcoin), //! FIXME - bitcoin ???
|
||||
deposit_public_key(""),
|
||||
deposit_address(""),
|
||||
withdraw_public_key(""),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
|
@ -13,12 +14,14 @@ enum class sidechain_type {
|
|||
hive
|
||||
};
|
||||
|
||||
static const std::set<sidechain_type> active_sidechain_types = {sidechain_type::bitcoin, sidechain_type::hive};
|
||||
|
||||
} }
|
||||
|
||||
FC_REFLECT_ENUM(graphene::chain::sidechain_type,
|
||||
(unknown)
|
||||
(bitcoin)
|
||||
(ethereum)
|
||||
(eos)
|
||||
(hive)
|
||||
(peerplays) )
|
||||
(unknown)
|
||||
(bitcoin)
|
||||
(ethereum)
|
||||
(eos)
|
||||
(hive)
|
||||
(peerplays) )
|
||||
|
|
@ -14,26 +14,15 @@ namespace graphene { namespace chain {
|
|||
son_id_type son_id;
|
||||
weight_type weight = 0;
|
||||
public_key_type signing_key;
|
||||
flat_map<sidechain_type, string> sidechain_public_keys;
|
||||
string public_key;
|
||||
|
||||
bool operator==(const son_info& rhs) {
|
||||
bool operator==(const son_info& rhs) const {
|
||||
bool son_sets_equal =
|
||||
(son_id == rhs.son_id) &&
|
||||
(weight == rhs.weight) &&
|
||||
(signing_key == rhs.signing_key) &&
|
||||
(sidechain_public_keys.size() == rhs.sidechain_public_keys.size());
|
||||
(public_key == rhs.public_key);
|
||||
|
||||
if (son_sets_equal) {
|
||||
bool sidechain_public_keys_equal = true;
|
||||
for (size_t i = 0; i < sidechain_public_keys.size(); i++) {
|
||||
const auto lhs_scpk = sidechain_public_keys.nth(i);
|
||||
const auto rhs_scpk = rhs.sidechain_public_keys.nth(i);
|
||||
sidechain_public_keys_equal = sidechain_public_keys_equal &&
|
||||
(lhs_scpk->first == rhs_scpk->first) &&
|
||||
(lhs_scpk->second == rhs_scpk->second);
|
||||
}
|
||||
son_sets_equal = son_sets_equal && sidechain_public_keys_equal;
|
||||
}
|
||||
return son_sets_equal;
|
||||
}
|
||||
};
|
||||
|
|
@ -44,4 +33,4 @@ FC_REFLECT( graphene::chain::son_info,
|
|||
(son_id)
|
||||
(weight)
|
||||
(signing_key)
|
||||
(sidechain_public_keys) )
|
||||
(public_key) )
|
||||
|
|
|
|||
|
|
@ -35,15 +35,15 @@ namespace graphene { namespace chain {
|
|||
// Transactions signed since the last son payouts
|
||||
flat_map<sidechain_type, uint64_t> txs_signed;
|
||||
// Total Voted Active time i.e. duration selected as part of voted active SONs
|
||||
uint64_t total_voted_time = 0;
|
||||
flat_map<sidechain_type, uint64_t> total_voted_time;
|
||||
// Total Downtime barring the current down time in seconds, used for stats to present to user
|
||||
uint64_t total_downtime = 0;
|
||||
flat_map<sidechain_type, uint64_t> total_downtime;
|
||||
// Current Interval Downtime since last maintenance
|
||||
uint64_t current_interval_downtime = 0;
|
||||
flat_map<sidechain_type, uint64_t> current_interval_downtime;
|
||||
// Down timestamp, if son status is in_maintenance use this
|
||||
fc::time_point_sec last_down_timestamp;
|
||||
flat_map<sidechain_type, fc::time_point_sec> last_down_timestamp;
|
||||
// Last Active heartbeat timestamp
|
||||
fc::time_point_sec last_active_timestamp;
|
||||
flat_map<sidechain_type, fc::time_point_sec> last_active_timestamp;
|
||||
// Deregistered Timestamp
|
||||
fc::time_point_sec deregistered_timestamp;
|
||||
// Total sidechain transactions reported by SON network while SON was active
|
||||
|
|
@ -64,23 +64,36 @@ namespace graphene { namespace chain {
|
|||
static const uint8_t type_id = son_object_type;
|
||||
|
||||
account_id_type son_account;
|
||||
vote_id_type vote_id;
|
||||
uint64_t total_votes = 0;
|
||||
flat_map<sidechain_type, vote_id_type> sidechain_vote_ids;
|
||||
flat_map<sidechain_type, uint64_t> total_votes;
|
||||
string url;
|
||||
vesting_balance_id_type deposit;
|
||||
public_key_type signing_key;
|
||||
vesting_balance_id_type pay_vb;
|
||||
son_statistics_id_type statistics;
|
||||
son_status status = son_status::inactive;
|
||||
flat_map<sidechain_type, son_status> statuses = []()
|
||||
{
|
||||
flat_map<sidechain_type, son_status> statuses;
|
||||
for(const auto& active_sidechain_type : active_sidechain_types)
|
||||
{
|
||||
statuses[active_sidechain_type] = son_status::inactive;
|
||||
}
|
||||
return statuses;
|
||||
}();
|
||||
flat_map<sidechain_type, string> sidechain_public_keys;
|
||||
|
||||
void pay_son_fee(share_type pay, database& db);
|
||||
bool has_valid_config()const;
|
||||
bool has_valid_config(time_point_sec head_block_time)const;
|
||||
|
||||
inline vote_id_type get_sidechain_vote_id(sidechain_type sidechain) const { return sidechain_vote_ids.at(sidechain); }
|
||||
inline vote_id_type get_bitcoin_vote_id() const { return get_sidechain_vote_id(sidechain_type::bitcoin); }
|
||||
inline vote_id_type get_hive_vote_id() const { return get_sidechain_vote_id(sidechain_type::hive); }
|
||||
};
|
||||
|
||||
struct by_account;
|
||||
struct by_vote_id;
|
||||
struct by_vote_id_bitcoin;
|
||||
struct by_vote_id_hive;
|
||||
using son_multi_index_type = multi_index_container<
|
||||
son_object,
|
||||
indexed_by<
|
||||
|
|
@ -90,8 +103,11 @@ namespace graphene { namespace chain {
|
|||
ordered_unique< tag<by_account>,
|
||||
member<son_object, account_id_type, &son_object::son_account>
|
||||
>,
|
||||
ordered_unique< tag<by_vote_id>,
|
||||
member<son_object, vote_id_type, &son_object::vote_id>
|
||||
ordered_unique< tag<by_vote_id_bitcoin>,
|
||||
const_mem_fun<son_object, vote_id_type, &son_object::get_bitcoin_vote_id>
|
||||
>,
|
||||
ordered_unique< tag<by_vote_id_hive>,
|
||||
const_mem_fun<son_object, vote_id_type, &son_object::get_hive_vote_id>
|
||||
>
|
||||
>
|
||||
>;
|
||||
|
|
@ -117,14 +133,14 @@ FC_REFLECT_ENUM(graphene::chain::son_status, (inactive)(active)(request_maintena
|
|||
|
||||
FC_REFLECT_DERIVED( graphene::chain::son_object, (graphene::db::object),
|
||||
(son_account)
|
||||
(vote_id)
|
||||
(sidechain_vote_ids)
|
||||
(total_votes)
|
||||
(url)
|
||||
(deposit)
|
||||
(signing_key)
|
||||
(pay_vb)
|
||||
(statistics)
|
||||
(status)
|
||||
(statuses)
|
||||
(sidechain_public_keys)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace graphene { namespace chain {
|
|||
time_point_sec expires;
|
||||
|
||||
flat_map<sidechain_type, string> addresses;
|
||||
vector<son_info> sons;
|
||||
flat_map<sidechain_type, vector<son_info> > sons;
|
||||
};
|
||||
|
||||
struct by_valid_from;
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ namespace graphene { namespace chain {
|
|||
* @ingroup object
|
||||
*/
|
||||
struct voters_info {
|
||||
optional<voters_info_object> voters_for_committee_member;
|
||||
optional<voters_info_object> voters_for_witness;
|
||||
optional<vector<voters_info_object> > voters_for_workers;
|
||||
optional<vector<voters_info_object> > voters_against_workers;
|
||||
optional<voters_info_object> voters_for_son;
|
||||
optional<voters_info_object> voters_for_committee_member;
|
||||
optional<voters_info_object> voters_for_witness;
|
||||
optional<vector<voters_info_object> > voters_for_workers;
|
||||
optional<vector<voters_info_object> > voters_against_workers;
|
||||
optional<flat_map<sidechain_type, voters_info_object> > voters_for_son;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
@ -37,4 +37,4 @@ FC_REFLECT( graphene::chain::voters_info,
|
|||
(voters_for_witness)
|
||||
(voters_for_workers)
|
||||
(voters_against_workers)
|
||||
(voters_for_son) )
|
||||
(voters_for_son))
|
||||
|
|
@ -19,11 +19,11 @@ namespace graphene { namespace chain {
|
|||
* @ingroup object
|
||||
*/
|
||||
struct votes_info {
|
||||
optional< vector< votes_info_object > > votes_for_committee_members;
|
||||
optional< vector< votes_info_object > > votes_for_witnesses;
|
||||
optional< vector< votes_info_object > > votes_for_workers;
|
||||
optional< vector< votes_info_object > > votes_against_workers;
|
||||
optional< vector< votes_info_object > > votes_for_sons;
|
||||
optional< vector< votes_info_object > > votes_for_committee_members;
|
||||
optional< vector< votes_info_object > > votes_for_witnesses;
|
||||
optional< vector< votes_info_object > > votes_for_workers;
|
||||
optional< vector< votes_info_object > > votes_against_workers;
|
||||
optional< flat_map<sidechain_type, vector< votes_info_object > > > votes_for_sons;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
@ -37,4 +37,4 @@ FC_REFLECT( graphene::chain::votes_info,
|
|||
(votes_for_witnesses)
|
||||
(votes_for_workers)
|
||||
(votes_against_workers)
|
||||
(votes_for_sons) )
|
||||
(votes_for_sons))
|
||||
|
|
@ -96,7 +96,7 @@ class son_schedule_object : public graphene::db::abstract_object<son_schedule_ob
|
|||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_son_schedule_object_type;
|
||||
|
||||
vector< son_id_type > current_shuffled_sons;
|
||||
vector<son_id_type > current_shuffled_sons;
|
||||
|
||||
son_scheduler scheduler;
|
||||
uint32_t last_scheduling_block;
|
||||
|
|
|
|||
|
|
@ -162,8 +162,12 @@ class generic_witness_scheduler
|
|||
_schedule.pop_front();
|
||||
|
||||
auto it = _lame_duck.find( result );
|
||||
if( it != _lame_duck.end() )
|
||||
_lame_duck.erase( it );
|
||||
if( it != _lame_duck.end() ) {
|
||||
set< WitnessID > removal_set;
|
||||
removal_set.insert(*it);
|
||||
remove_all( removal_set );
|
||||
_lame_duck.erase(it);
|
||||
}
|
||||
if( debug ) check_invariant();
|
||||
return result;
|
||||
}
|
||||
|
|
@ -389,7 +393,7 @@ class generic_witness_scheduler
|
|||
// scheduled
|
||||
std::deque < WitnessID > _schedule;
|
||||
|
||||
// in _schedule, but not to be replaced
|
||||
// in _schedule, but must be removed
|
||||
set< WitnessID > _lame_duck;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -174,22 +174,27 @@ void account_options::validate() const
|
|||
{
|
||||
auto needed_witnesses = num_witness;
|
||||
auto needed_committee = num_committee;
|
||||
auto needed_sons = num_son();
|
||||
FC_ASSERT( extensions.value.num_son.valid() , "Invalid son number" );
|
||||
flat_map<sidechain_type, uint16_t> needed_sons = *extensions.value.num_son;
|
||||
|
||||
for( vote_id_type id : votes )
|
||||
if( id.type() == vote_id_type::witness && needed_witnesses )
|
||||
--needed_witnesses;
|
||||
else if ( id.type() == vote_id_type::committee && needed_committee )
|
||||
--needed_committee;
|
||||
else if ( id.type() == vote_id_type::son && needed_sons )
|
||||
--needed_sons;
|
||||
else if ( id.type() == vote_id_type::son_bitcoin && needed_sons[sidechain_type::bitcoin] )
|
||||
--needed_sons[sidechain_type::bitcoin];
|
||||
else if ( id.type() == vote_id_type::son_hive && needed_sons[sidechain_type::hive] )
|
||||
--needed_sons[sidechain_type::hive];
|
||||
|
||||
FC_ASSERT( needed_witnesses == 0,
|
||||
"May not specify fewer witnesses than the number voted for.");
|
||||
FC_ASSERT( needed_committee == 0,
|
||||
"May not specify fewer committee members than the number voted for.");
|
||||
FC_ASSERT( needed_sons == 0,
|
||||
"May not specify fewer SONs than the number voted for.");
|
||||
FC_ASSERT( needed_sons[sidechain_type::bitcoin] == 0,
|
||||
"May not specify fewer Bitcoin SONs than the number voted for.");
|
||||
FC_ASSERT( needed_sons[sidechain_type::hive] == 0,
|
||||
"May not specify fewer Hive SONs than the number voted for.");
|
||||
}
|
||||
|
||||
void affiliate_reward_distribution::validate() const
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ void_result update_sidechain_address_evaluator::do_evaluate(const sidechain_addr
|
|||
{ try {
|
||||
const auto& sidx = db().get_index_type<son_index>().indices().get<by_account>();
|
||||
const auto& son_obj = sidx.find(op.payer);
|
||||
FC_ASSERT( son_obj != sidx.end() && db().is_son_active(son_obj->id), "Non active SON trying to update deposit address object" );
|
||||
FC_ASSERT( son_obj != sidx.end() && db().is_son_active(op.sidechain, son_obj->id), "Non active SON trying to update deposit address object" );
|
||||
const auto& sdpke_idx = db().get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_public_key_and_expires>();
|
||||
FC_ASSERT( op.deposit_address.valid() && op.deposit_public_key.valid() && op.deposit_address_data.valid(), "Update operation by SON is not valid");
|
||||
FC_ASSERT( (*op.deposit_address).length() > 0 && (*op.deposit_public_key).length() > 0 && (*op.deposit_address_data).length() > 0, "SON should create a valid deposit address with valid deposit public key");
|
||||
|
|
|
|||
|
|
@ -38,14 +38,17 @@ void_result create_son_evaluator::do_evaluate(const son_create_operation& op)
|
|||
|
||||
object_id_type create_son_evaluator::do_apply(const son_create_operation& op)
|
||||
{ try {
|
||||
vote_id_type vote_id;
|
||||
db().modify(db().get_global_properties(), [&vote_id](global_property_object& p) {
|
||||
vote_id = get_next_vote_id(p, vote_id_type::son);
|
||||
vote_id_type vote_id_bitcoin;
|
||||
vote_id_type vote_id_hive;
|
||||
db().modify(db().get_global_properties(), [&vote_id_bitcoin, &vote_id_hive](global_property_object& p) {
|
||||
vote_id_bitcoin = get_next_vote_id(p, vote_id_type::son_bitcoin);
|
||||
vote_id_hive = get_next_vote_id(p, vote_id_type::son_hive);
|
||||
});
|
||||
|
||||
const auto& new_son_object = db().create<son_object>( [&]( son_object& obj ){
|
||||
obj.son_account = op.owner_account;
|
||||
obj.vote_id = vote_id;
|
||||
obj.sidechain_vote_ids[sidechain_type::bitcoin] = vote_id_bitcoin;
|
||||
obj.sidechain_vote_ids[sidechain_type::hive] = vote_id_hive;
|
||||
obj.url = op.url;
|
||||
obj.deposit = op.deposit;
|
||||
obj.signing_key = op.signing_key;
|
||||
|
|
@ -94,7 +97,8 @@ object_id_type update_son_evaluator::do_apply(const son_update_operation& op)
|
|||
if(op.new_signing_key.valid()) so.signing_key = *op.new_signing_key;
|
||||
if(op.new_sidechain_public_keys.valid()) so.sidechain_public_keys = *op.new_sidechain_public_keys;
|
||||
if(op.new_pay_vb.valid()) so.pay_vb = *op.new_pay_vb;
|
||||
if(so.status == son_status::deregistered) so.status = son_status::inactive;
|
||||
for(auto& status : so.statuses)
|
||||
if(status.second == son_status::deregistered) status.second = son_status::inactive;
|
||||
});
|
||||
}
|
||||
return op.son_id;
|
||||
|
|
@ -127,7 +131,8 @@ void_result deregister_son_evaluator::do_apply(const son_deregister_operation& o
|
|||
});
|
||||
|
||||
db().modify(*son, [&op](son_object &so) {
|
||||
so.status = son_status::deregistered;
|
||||
for(auto& status : so.statuses)
|
||||
status.second = son_status::deregistered;
|
||||
});
|
||||
|
||||
auto stats_obj = ss_idx.find(son->statistics);
|
||||
|
|
@ -144,18 +149,28 @@ void_result son_heartbeat_evaluator::do_evaluate(const son_heartbeat_operation&
|
|||
{ try {
|
||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); // can be removed after HF date pass
|
||||
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
|
||||
auto itr = idx.find(op.son_id);
|
||||
const auto itr = idx.find(op.son_id);
|
||||
FC_ASSERT( itr != idx.end() );
|
||||
FC_ASSERT(itr->son_account == op.owner_account);
|
||||
auto stats = itr->statistics( db() );
|
||||
// Inactive SONs need not send heartbeats
|
||||
FC_ASSERT((itr->status == son_status::active) || (itr->status == son_status::in_maintenance) || (itr->status == son_status::request_maintenance), "Inactive SONs need not send heartbeats");
|
||||
bool status_need_to_send_heartbeats = false;
|
||||
for(const auto& status : itr->statuses)
|
||||
{
|
||||
if( (status.second == son_status::active) || (status.second == son_status::in_maintenance) || (status.second == son_status::request_maintenance) )
|
||||
status_need_to_send_heartbeats = true;
|
||||
}
|
||||
FC_ASSERT(status_need_to_send_heartbeats, "Inactive SONs need not send heartbeats");
|
||||
// Account for network delays
|
||||
fc::time_point_sec min_ts = db().head_block_time() - fc::seconds(5 * db().block_interval());
|
||||
// Account for server ntp sync difference
|
||||
fc::time_point_sec max_ts = db().head_block_time() + fc::seconds(5 * db().block_interval());
|
||||
FC_ASSERT(op.ts > stats.last_active_timestamp, "Heartbeat sent without waiting minimum time");
|
||||
FC_ASSERT(op.ts > stats.last_down_timestamp, "Heartbeat sent is invalid can't be <= last down timestamp");
|
||||
for(const auto& active_sidechain_type : active_sidechain_types) {
|
||||
if(stats.last_active_timestamp.contains(active_sidechain_type))
|
||||
FC_ASSERT(op.ts > stats.last_active_timestamp.at(active_sidechain_type), "Heartbeat sent for sidechain = ${sidechain} without waiting minimum time", ("sidechain", active_sidechain_type));
|
||||
if(stats.last_down_timestamp.contains(active_sidechain_type))
|
||||
FC_ASSERT(op.ts > stats.last_down_timestamp.at(active_sidechain_type), "Heartbeat sent for sidechain = ${sidechain} is invalid can't be <= last down timestamp", ("sidechain", active_sidechain_type));
|
||||
}
|
||||
FC_ASSERT(op.ts >= min_ts, "Heartbeat ts is behind the min threshold");
|
||||
FC_ASSERT(op.ts <= max_ts, "Heartbeat ts is above the max threshold");
|
||||
return void_result();
|
||||
|
|
@ -164,44 +179,48 @@ void_result son_heartbeat_evaluator::do_evaluate(const son_heartbeat_operation&
|
|||
object_id_type son_heartbeat_evaluator::do_apply(const son_heartbeat_operation& op)
|
||||
{ try {
|
||||
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
|
||||
auto itr = idx.find(op.son_id);
|
||||
const auto itr = idx.find(op.son_id);
|
||||
if(itr != idx.end())
|
||||
{
|
||||
const global_property_object& gpo = db().get_global_properties();
|
||||
vector<son_id_type> active_son_ids;
|
||||
active_son_ids.reserve(gpo.active_sons.size());
|
||||
std::transform(gpo.active_sons.begin(), gpo.active_sons.end(),
|
||||
std::inserter(active_son_ids, active_son_ids.end()),
|
||||
[](const son_info& swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
|
||||
auto it_son = std::find(active_son_ids.begin(), active_son_ids.end(), op.son_id);
|
||||
bool is_son_active = true;
|
||||
for(const auto& active_sidechain_sons : gpo.active_sons) {
|
||||
const auto& sidechain = active_sidechain_sons.first;
|
||||
const auto& active_sons = active_sidechain_sons.second;
|
||||
|
||||
if(it_son == active_son_ids.end()) {
|
||||
is_son_active = false;
|
||||
}
|
||||
vector<son_id_type> active_son_ids;
|
||||
active_son_ids.reserve(active_sons.size());
|
||||
std::transform(active_sons.cbegin(), active_sons.cend(),
|
||||
std::inserter(active_son_ids, active_son_ids.end()),
|
||||
[](const son_info &swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
|
||||
if(itr->status == son_status::in_maintenance) {
|
||||
db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso )
|
||||
{
|
||||
sso.current_interval_downtime += op.ts.sec_since_epoch() - sso.last_down_timestamp.sec_since_epoch();
|
||||
sso.last_active_timestamp = op.ts;
|
||||
} );
|
||||
const auto it_son = std::find(active_son_ids.begin(), active_son_ids.end(), op.son_id);
|
||||
bool is_son_active = true;
|
||||
|
||||
db().modify(*itr, [&is_son_active](son_object &so) {
|
||||
if(is_son_active) {
|
||||
so.status = son_status::active;
|
||||
} else {
|
||||
so.status = son_status::inactive;
|
||||
}
|
||||
});
|
||||
} else if ((itr->status == son_status::active) || (itr->status == son_status::request_maintenance)) {
|
||||
db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso )
|
||||
{
|
||||
sso.last_active_timestamp = op.ts;
|
||||
} );
|
||||
if (it_son == active_son_ids.end()) {
|
||||
is_son_active = false;
|
||||
}
|
||||
|
||||
if (itr->statuses.at(sidechain) == son_status::in_maintenance) {
|
||||
db().modify(itr->statistics(db()), [&](son_statistics_object &sso) {
|
||||
sso.current_interval_downtime[sidechain] += op.ts.sec_since_epoch() - sso.last_down_timestamp.at(sidechain).sec_since_epoch();
|
||||
sso.last_active_timestamp[sidechain] = op.ts;
|
||||
});
|
||||
|
||||
db().modify(*itr, [&is_son_active, &sidechain](son_object &so) {
|
||||
if (is_son_active) {
|
||||
so.statuses[sidechain] = son_status::active;
|
||||
} else {
|
||||
so.statuses[sidechain] = son_status::inactive;
|
||||
}
|
||||
});
|
||||
} else if ((itr->statuses.at(sidechain) == son_status::active) || (itr->statuses.at(sidechain) == son_status::request_maintenance)) {
|
||||
db().modify(itr->statistics(db()), [&](son_statistics_object &sso) {
|
||||
sso.last_active_timestamp[sidechain] = op.ts;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return op.son_id;
|
||||
|
|
@ -213,29 +232,40 @@ void_result son_report_down_evaluator::do_evaluate(const son_report_down_operati
|
|||
FC_ASSERT(op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer.");
|
||||
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
|
||||
FC_ASSERT( idx.find(op.son_id) != idx.end() );
|
||||
auto itr = idx.find(op.son_id);
|
||||
auto stats = itr->statistics( db() );
|
||||
FC_ASSERT(itr->status == son_status::active || itr->status == son_status::request_maintenance, "Inactive/Deregistered/in_maintenance SONs cannot be reported on as down");
|
||||
FC_ASSERT(op.down_ts >= stats.last_active_timestamp, "down_ts should be greater than last_active_timestamp");
|
||||
const auto itr = idx.find(op.son_id);
|
||||
const auto stats = itr->statistics( db() );
|
||||
bool status_need_to_report_down = false;
|
||||
for(const auto& status : itr->statuses)
|
||||
{
|
||||
if( (status.second == son_status::active) || (status.second == son_status::request_maintenance) )
|
||||
status_need_to_report_down = true;
|
||||
}
|
||||
FC_ASSERT(status_need_to_report_down, "Inactive/Deregistered/in_maintenance SONs cannot be reported on as down");
|
||||
for(const auto& active_sidechain_type : active_sidechain_types) {
|
||||
FC_ASSERT(op.down_ts >= stats.last_active_timestamp.at(active_sidechain_type), "sidechain = ${sidechain} down_ts should be greater than last_active_timestamp", ("sidechain", active_sidechain_type));
|
||||
}
|
||||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
object_id_type son_report_down_evaluator::do_apply(const son_report_down_operation& op)
|
||||
{ try {
|
||||
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
|
||||
auto itr = idx.find(op.son_id);
|
||||
const auto itr = idx.find(op.son_id);
|
||||
if(itr != idx.end())
|
||||
{
|
||||
if ((itr->status == son_status::active) || (itr->status == son_status::request_maintenance)) {
|
||||
db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso )
|
||||
{
|
||||
sso.last_down_timestamp = op.down_ts;
|
||||
});
|
||||
for( const auto& status : itr->statuses ) {
|
||||
const auto& sidechain = status.first;
|
||||
|
||||
db().modify(*itr, [&op](son_object &so) {
|
||||
so.status = son_status::in_maintenance;
|
||||
});
|
||||
}
|
||||
if ((status.second == son_status::active) || (status.second == son_status::request_maintenance)) {
|
||||
db().modify(*itr, [&sidechain](son_object &so) {
|
||||
so.statuses[sidechain] = son_status::in_maintenance;
|
||||
});
|
||||
|
||||
db().modify(itr->statistics(db()), [&](son_statistics_object &sso) {
|
||||
sso.last_down_timestamp[sidechain] = op.down_ts;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return op.son_id;
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
|
@ -249,9 +279,19 @@ void_result son_maintenance_evaluator::do_evaluate(const son_maintenance_operati
|
|||
FC_ASSERT( itr != idx.end() );
|
||||
// Inactive SONs can't go to maintenance, toggle between active and request_maintenance states
|
||||
if(op.request_type == son_maintenance_request_type::request_maintenance) {
|
||||
FC_ASSERT(itr->status == son_status::active, "Inactive SONs can't request for maintenance");
|
||||
} else if(op.request_type == son_maintenance_request_type::cancel_request_maintenance) {
|
||||
FC_ASSERT(itr->status == son_status::request_maintenance, "Only maintenance requested SONs can cancel the request");
|
||||
bool status_active = false;
|
||||
for(const auto& status : itr->statuses) {
|
||||
if( (status.second == son_status::active) )
|
||||
status_active = true;
|
||||
}
|
||||
FC_ASSERT(status_active, "Inactive SONs can't request for maintenance");
|
||||
} else if(op.request_type == son_maintenance_request_type::cancel_request_maintenance) {
|
||||
bool status_request_maintenance = false;
|
||||
for(const auto& status : itr->statuses) {
|
||||
if( (status.second == son_status::request_maintenance) )
|
||||
status_request_maintenance = true;
|
||||
}
|
||||
FC_ASSERT(status_request_maintenance, "Only maintenance requested SONs can cancel the request");
|
||||
} else {
|
||||
FC_ASSERT(false, "Invalid maintenance operation");
|
||||
}
|
||||
|
|
@ -264,15 +304,33 @@ object_id_type son_maintenance_evaluator::do_apply(const son_maintenance_operati
|
|||
auto itr = idx.find(op.son_id);
|
||||
if(itr != idx.end())
|
||||
{
|
||||
if(itr->status == son_status::active && op.request_type == son_maintenance_request_type::request_maintenance) {
|
||||
db().modify(*itr, [](son_object &so) {
|
||||
so.status = son_status::request_maintenance;
|
||||
});
|
||||
} else if(itr->status == son_status::request_maintenance && op.request_type == son_maintenance_request_type::cancel_request_maintenance) {
|
||||
db().modify(*itr, [](son_object &so) {
|
||||
so.status = son_status::active;
|
||||
});
|
||||
}
|
||||
bool status_active = false;
|
||||
for(const auto& status : itr->statuses) {
|
||||
if( (status.second == son_status::active) )
|
||||
status_active = true;
|
||||
}
|
||||
if(status_active && op.request_type == son_maintenance_request_type::request_maintenance) {
|
||||
db().modify(*itr, [](son_object &so) {
|
||||
for(auto& status : so.statuses) {
|
||||
status.second = son_status::request_maintenance;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
bool status_request_maintenance = false;
|
||||
for(const auto& status : itr->statuses) {
|
||||
if( (status.second == son_status::request_maintenance) )
|
||||
status_request_maintenance = true;
|
||||
}
|
||||
if(status_request_maintenance && op.request_type == son_maintenance_request_type::cancel_request_maintenance) {
|
||||
db().modify(*itr, [](son_object &so) {
|
||||
for(auto& status : so.statuses) {
|
||||
status.second = son_status::active;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return op.son_id;
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ void_result create_son_wallet_deposit_evaluator::do_evaluate(const son_wallet_de
|
|||
const auto &swdo_idx = db().get_index_type<son_wallet_deposit_index>().indices().get<by_sidechain_uid>();
|
||||
const auto swdo = swdo_idx.find(op.sidechain_uid);
|
||||
if (swdo == swdo_idx.end()) {
|
||||
auto &gpo = db().get_global_properties();
|
||||
const auto &gpo = db().get_global_properties();
|
||||
bool expected = false;
|
||||
for (auto &si : gpo.active_sons) {
|
||||
for (auto &si : gpo.active_sons.at(op.sidechain)) {
|
||||
if (op.son_id == si.son_id) {
|
||||
expected = true;
|
||||
break;
|
||||
|
|
@ -78,8 +78,8 @@ object_id_type create_son_wallet_deposit_evaluator::do_apply(const son_wallet_de
|
|||
swdo.peerplays_to = op.peerplays_to;
|
||||
swdo.peerplays_asset = op.peerplays_asset;
|
||||
|
||||
auto &gpo = db().get_global_properties();
|
||||
for (auto &si : gpo.active_sons) {
|
||||
const auto &gpo = db().get_global_properties();
|
||||
for (auto &si : gpo.active_sons.at(op.sidechain)) {
|
||||
swdo.expected_reports.insert(std::make_pair(si.son_id, si.weight));
|
||||
|
||||
auto stats_itr = db().get_index_type<son_stats_index>().indices().get<by_owner>().find(si.son_id);
|
||||
|
|
@ -142,11 +142,11 @@ void_result process_son_wallet_deposit_evaluator::do_evaluate(const son_wallet_d
|
|||
{ try{
|
||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
||||
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
|
||||
FC_ASSERT(db().get_global_properties().active_sons.size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present");
|
||||
|
||||
const auto& idx = db().get_index_type<son_wallet_deposit_index>().indices().get<by_id>();
|
||||
const auto& itr = idx.find(op.son_wallet_deposit_id);
|
||||
FC_ASSERT(itr != idx.end(), "Son wallet deposit not found");
|
||||
FC_ASSERT(db().get_global_properties().active_sons.at(itr->sidechain).size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present");
|
||||
FC_ASSERT(!itr->processed, "Son wallet deposit is already processed");
|
||||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
|
|
|||
|
|
@ -20,8 +20,16 @@ void_result recreate_son_wallet_evaluator::do_evaluate(const son_wallet_recreate
|
|||
|
||||
bool son_sets_equal = (cur_wallet_sons.size() == new_wallet_sons.size());
|
||||
if (son_sets_equal) {
|
||||
for( size_t i = 0; i < cur_wallet_sons.size(); i++ ) {
|
||||
son_sets_equal = son_sets_equal && cur_wallet_sons.at(i) == new_wallet_sons.at(i);
|
||||
for( const auto& cur_wallet_sidechain_sons : cur_wallet_sons ) {
|
||||
const auto& sidechain = cur_wallet_sidechain_sons.first;
|
||||
const auto& _cur_wallet_sidechain_sons = cur_wallet_sidechain_sons.second;
|
||||
|
||||
son_sets_equal = son_sets_equal && (_cur_wallet_sidechain_sons.size() == new_wallet_sons.at(sidechain).size());
|
||||
if (son_sets_equal) {
|
||||
for (size_t i = 0; i < cur_wallet_sons.size(); i++) {
|
||||
son_sets_equal = son_sets_equal && _cur_wallet_sidechain_sons.at(i) == new_wallet_sons.at(sidechain).at(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,15 +23,15 @@ void_result create_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_w
|
|||
const auto &swwo_idx = db().get_index_type<son_wallet_withdraw_index>().indices().get<by_peerplays_uid>();
|
||||
const auto swwo = swwo_idx.find(op.peerplays_uid);
|
||||
if (swwo == swwo_idx.end()) {
|
||||
auto &gpo = db().get_global_properties();
|
||||
const auto &gpo = db().get_global_properties();
|
||||
bool expected = false;
|
||||
for (auto &si : gpo.active_sons) {
|
||||
for (auto &si : gpo.active_sons.at(op.sidechain)) {
|
||||
if (op.son_id == si.son_id) {
|
||||
expected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
FC_ASSERT(expected, "Only active SON can create deposit");
|
||||
FC_ASSERT(expected, "Only active SON can create withdraw");
|
||||
} else {
|
||||
bool exactly_the_same = true;
|
||||
exactly_the_same = exactly_the_same && (swwo->sidechain == op.sidechain);
|
||||
|
|
@ -76,8 +76,8 @@ object_id_type create_son_wallet_withdraw_evaluator::do_apply(const son_wallet_w
|
|||
swwo.withdraw_currency = op.withdraw_currency;
|
||||
swwo.withdraw_amount = op.withdraw_amount;
|
||||
|
||||
auto &gpo = db().get_global_properties();
|
||||
for (auto &si : gpo.active_sons) {
|
||||
const auto &gpo = db().get_global_properties();
|
||||
for (auto &si : gpo.active_sons.at(op.sidechain)) {
|
||||
swwo.expected_reports.insert(std::make_pair(si.son_id, si.weight));
|
||||
|
||||
auto stats_itr = db().get_index_type<son_stats_index>().indices().get<by_owner>().find(si.son_id);
|
||||
|
|
@ -140,11 +140,11 @@ void_result process_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_
|
|||
{ try{
|
||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
||||
FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." );
|
||||
FC_ASSERT(db().get_global_properties().active_sons.size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present");
|
||||
|
||||
const auto& idx = db().get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
|
||||
const auto& itr = idx.find(op.son_wallet_withdraw_id);
|
||||
FC_ASSERT(itr != idx.end(), "Son wallet withdraw not found");
|
||||
FC_ASSERT(db().get_global_properties().active_sons.at(itr->sidechain).size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present");
|
||||
FC_ASSERT(!itr->processed, "Son wallet withdraw is already processed");
|
||||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ file(GLOB_RECURSE HEADERS "include/graphene/peerplays_sidechain/*.hpp")
|
|||
add_library( peerplays_sidechain
|
||||
peerplays_sidechain_plugin.cpp
|
||||
sidechain_api.cpp
|
||||
sidechain_net_manager.cpp
|
||||
sidechain_net_handler_factory.cpp
|
||||
sidechain_net_handler.cpp
|
||||
sidechain_net_handler_bitcoin.cpp
|
||||
sidechain_net_handler_hive.cpp
|
||||
|
|
|
|||
|
|
@ -13,16 +13,18 @@ class peerplays_sidechain_plugin_impl;
|
|||
}
|
||||
|
||||
struct son_proposal_type {
|
||||
son_proposal_type(int op, son_id_type son, object_id_type object) :
|
||||
son_proposal_type(int op, sidechain_type sid, son_id_type son, object_id_type object) :
|
||||
op_type(op),
|
||||
sidechain(sid),
|
||||
son_id(son),
|
||||
object_id(object) {
|
||||
}
|
||||
int op_type;
|
||||
sidechain_type sidechain;
|
||||
son_id_type son_id;
|
||||
object_id_type object_id;
|
||||
bool operator<(const son_proposal_type &other) const {
|
||||
return std::tie(op_type, son_id, object_id) < std::tie(other.op_type, other.son_id, other.object_id);
|
||||
return std::tie(op_type, sidechain, son_id, object_id) < std::tie(other.op_type, other.sidechain, other.son_id, other.object_id);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -42,15 +44,15 @@ public:
|
|||
std::unique_ptr<detail::peerplays_sidechain_plugin_impl> my;
|
||||
|
||||
std::set<chain::son_id_type> &get_sons();
|
||||
const son_id_type get_current_son_id();
|
||||
const son_object get_current_son_object();
|
||||
const son_id_type get_current_son_id(sidechain_type sidechain);
|
||||
const son_object get_current_son_object(sidechain_type sidechain);
|
||||
const son_object get_son_object(son_id_type son_id);
|
||||
bool is_active_son(son_id_type son_id);
|
||||
bool is_active_son(sidechain_type sidechain, son_id_type son_id);
|
||||
bool is_son_deregistered(son_id_type son_id);
|
||||
fc::ecc::private_key get_private_key(son_id_type son_id);
|
||||
fc::ecc::private_key get_private_key(chain::public_key_type public_key);
|
||||
void log_son_proposal_retry(int op_type, object_id_type object_id);
|
||||
bool can_son_participate(int op_type, object_id_type object_id);
|
||||
void log_son_proposal_retry(sidechain_type sidechain, int op_type, object_id_type object_id);
|
||||
bool can_son_participate(sidechain_type sidechain, int op_type, object_id_type object_id);
|
||||
std::map<sidechain_type, std::vector<std::string>> get_son_listener_log();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <graphene/chain/sidechain_defs.hpp>
|
||||
#include <graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp>
|
||||
#include <graphene/peerplays_sidechain/sidechain_net_handler.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
namespace graphene { namespace peerplays_sidechain {
|
||||
|
||||
class sidechain_net_handler_factory {
|
||||
public:
|
||||
sidechain_net_handler_factory(peerplays_sidechain_plugin &_plugin);
|
||||
|
||||
std::unique_ptr<sidechain_net_handler> create_handler(sidechain_type sidechain, const boost::program_options::variables_map &options) const;
|
||||
|
||||
private:
|
||||
peerplays_sidechain_plugin &plugin;
|
||||
};
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <graphene/chain/sidechain_defs.hpp>
|
||||
#include <graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp>
|
||||
#include <graphene/peerplays_sidechain/sidechain_net_handler.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
namespace graphene { namespace peerplays_sidechain {
|
||||
|
||||
class sidechain_net_manager {
|
||||
public:
|
||||
sidechain_net_manager(peerplays_sidechain_plugin &_plugin);
|
||||
virtual ~sidechain_net_manager();
|
||||
|
||||
bool create_handler(sidechain_type sidechain, const boost::program_options::variables_map &options);
|
||||
void process_proposals();
|
||||
void process_active_sons_change();
|
||||
void create_deposit_addresses();
|
||||
void process_deposits();
|
||||
void process_withdrawals();
|
||||
void process_sidechain_transactions();
|
||||
void send_sidechain_transactions();
|
||||
void settle_sidechain_transactions();
|
||||
|
||||
std::map<sidechain_type, std::vector<std::string>> get_son_listener_log();
|
||||
|
||||
private:
|
||||
peerplays_sidechain_plugin &plugin;
|
||||
graphene::chain::database &database;
|
||||
std::vector<std::unique_ptr<sidechain_net_handler>> net_handlers;
|
||||
|
||||
void on_applied_block(const signed_block &b);
|
||||
};
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/range/algorithm_ext/insert.hpp>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
|
||||
#include <fc/log/logger.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
|
|
@ -11,7 +13,7 @@
|
|||
#include <graphene/chain/son_wallet_object.hpp>
|
||||
#include <graphene/chain/son_wallet_withdraw_object.hpp>
|
||||
#include <graphene/peerplays_sidechain/sidechain_api.hpp>
|
||||
#include <graphene/peerplays_sidechain/sidechain_net_manager.hpp>
|
||||
#include <graphene/peerplays_sidechain/sidechain_net_handler_factory.hpp>
|
||||
#include <graphene/utilities/key_conversion.hpp>
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
|
@ -33,36 +35,36 @@ public:
|
|||
void plugin_shutdown();
|
||||
|
||||
std::set<chain::son_id_type> &get_sons();
|
||||
const son_id_type get_current_son_id();
|
||||
const son_object get_current_son_object();
|
||||
const son_id_type get_current_son_id(sidechain_type sidechain);
|
||||
const son_object get_current_son_object(sidechain_type sidechain);
|
||||
const son_object get_son_object(son_id_type son_id);
|
||||
bool is_active_son(son_id_type son_id);
|
||||
bool is_active_son(sidechain_type sidechain, son_id_type son_id);
|
||||
bool is_son_deregistered(son_id_type son_id);
|
||||
bool is_son_deregister_op_valid(const chain::operation &op);
|
||||
bool is_son_down_op_valid(const chain::operation &op);
|
||||
bool is_valid_son_proposal(const chain::proposal_object &proposal);
|
||||
fc::ecc::private_key get_private_key(son_id_type son_id);
|
||||
fc::ecc::private_key get_private_key(chain::public_key_type public_key);
|
||||
void log_son_proposal_retry(int op_type, object_id_type object_id);
|
||||
bool can_son_participate(int op_type, object_id_type object_id);
|
||||
void log_son_proposal_retry(sidechain_type sidechain, int op_type, object_id_type object_id);
|
||||
bool can_son_participate(sidechain_type sidechain, int op_type, object_id_type object_id);
|
||||
std::map<sidechain_type, std::vector<std::string>> get_son_listener_log();
|
||||
|
||||
void schedule_heartbeat_loop();
|
||||
void heartbeat_loop();
|
||||
void schedule_son_processing();
|
||||
void son_processing();
|
||||
void approve_proposals();
|
||||
void create_son_down_proposals();
|
||||
void create_son_deregister_proposals();
|
||||
void son_processing(sidechain_type sidechain);
|
||||
void approve_proposals(sidechain_type sidechain);
|
||||
void create_son_down_proposals(sidechain_type sidechain);
|
||||
void create_son_deregister_proposals(sidechain_type sidechain);
|
||||
|
||||
void process_proposals();
|
||||
void process_active_sons_change();
|
||||
void create_deposit_addresses();
|
||||
void process_deposits();
|
||||
void process_withdrawals();
|
||||
void process_sidechain_transactions();
|
||||
void send_sidechain_transactions();
|
||||
void settle_sidechain_transactions();
|
||||
void process_proposals(sidechain_type sidechain);
|
||||
void process_active_sons_change(sidechain_type sidechain);
|
||||
void create_deposit_addresses(sidechain_type sidechain);
|
||||
void process_deposits(sidechain_type sidechain);
|
||||
void process_withdrawals(sidechain_type sidechain);
|
||||
void process_sidechain_transactions(sidechain_type sidechain);
|
||||
void send_sidechain_transactions(sidechain_type sidechain);
|
||||
void settle_sidechain_transactions(sidechain_type sidechain);
|
||||
|
||||
private:
|
||||
peerplays_sidechain_plugin &plugin;
|
||||
|
|
@ -80,15 +82,19 @@ private:
|
|||
bool sidechain_enabled_hive;
|
||||
bool sidechain_enabled_peerplays;
|
||||
|
||||
son_id_type current_son_id;
|
||||
std::map<sidechain_type, son_id_type> current_son_id;
|
||||
std::mutex current_son_id_mutex;
|
||||
std::mutex access_db_mutex;
|
||||
std::mutex access_approve_prop_mutex;
|
||||
std::mutex access_son_down_prop_mutex;
|
||||
|
||||
std::unique_ptr<peerplays_sidechain::sidechain_net_manager> net_manager;
|
||||
std::map<sidechain_type, std::unique_ptr<sidechain_net_handler>> net_handlers;
|
||||
std::set<chain::son_id_type> sons;
|
||||
std::map<chain::public_key_type, fc::ecc::private_key> private_keys;
|
||||
fc::future<void> _heartbeat_task;
|
||||
fc::future<void> _son_processing_task;
|
||||
std::map<sidechain_type, std::future<void>> _son_processing_task;
|
||||
std::map<son_proposal_type, uint16_t> son_retry_count;
|
||||
uint16_t retries_threshold;
|
||||
uint16_t retries_threshold = 150;
|
||||
|
||||
bool first_block_skipped;
|
||||
void on_applied_block(const signed_block &b);
|
||||
|
|
@ -105,8 +111,20 @@ peerplays_sidechain_plugin_impl::peerplays_sidechain_plugin_impl(peerplays_sidec
|
|||
sidechain_enabled_ethereum(false),
|
||||
sidechain_enabled_hive(false),
|
||||
sidechain_enabled_peerplays(false),
|
||||
current_son_id(son_id_type(std::numeric_limits<uint32_t>().max())),
|
||||
net_manager(nullptr),
|
||||
current_son_id([] {
|
||||
std::map<sidechain_type, son_id_type> current_son_id;
|
||||
for (const auto &active_sidechain_type : active_sidechain_types) {
|
||||
current_son_id.emplace(active_sidechain_type, son_id_type(std::numeric_limits<uint32_t>().max()));
|
||||
}
|
||||
return current_son_id;
|
||||
}()),
|
||||
net_handlers([] {
|
||||
std::map<sidechain_type, std::unique_ptr<sidechain_net_handler>> net_handlers;
|
||||
for (const auto &active_sidechain_type : active_sidechain_types) {
|
||||
net_handlers.emplace(active_sidechain_type, nullptr);
|
||||
}
|
||||
return net_handlers;
|
||||
}()),
|
||||
first_block_skipped(false) {
|
||||
}
|
||||
|
||||
|
|
@ -121,8 +139,10 @@ peerplays_sidechain_plugin_impl::~peerplays_sidechain_plugin_impl() {
|
|||
}
|
||||
|
||||
try {
|
||||
if (_son_processing_task.valid())
|
||||
_son_processing_task.cancel_and_wait(__FUNCTION__);
|
||||
for (const auto &active_sidechain_type : active_sidechain_types) {
|
||||
if (_son_processing_task.count(active_sidechain_type) != 0 && _son_processing_task.at(active_sidechain_type).valid())
|
||||
_son_processing_task.at(active_sidechain_type).wait();
|
||||
}
|
||||
} catch (fc::canceled_exception &) {
|
||||
//Expected exception. Move along.
|
||||
} catch (fc::exception &e) {
|
||||
|
|
@ -262,10 +282,10 @@ void peerplays_sidechain_plugin_impl::plugin_startup() {
|
|||
elog("No sons configured! Please add SON IDs and private keys to configuration.");
|
||||
}
|
||||
|
||||
net_manager = std::unique_ptr<sidechain_net_manager>(new sidechain_net_manager(plugin));
|
||||
sidechain_net_handler_factory net_handler_factory(plugin);
|
||||
|
||||
if (sidechain_enabled_bitcoin && config_ready_bitcoin) {
|
||||
net_manager->create_handler(sidechain_type::bitcoin, options);
|
||||
net_handlers.at(sidechain_type::bitcoin) = net_handler_factory.create_handler(sidechain_type::bitcoin, options);
|
||||
ilog("Bitcoin sidechain handler running");
|
||||
}
|
||||
|
||||
|
|
@ -275,12 +295,12 @@ void peerplays_sidechain_plugin_impl::plugin_startup() {
|
|||
//}
|
||||
|
||||
if (sidechain_enabled_hive && config_ready_hive) {
|
||||
net_manager->create_handler(sidechain_type::hive, options);
|
||||
net_handlers.at(sidechain_type::hive) = net_handler_factory.create_handler(sidechain_type::hive, options);
|
||||
ilog("Hive sidechain handler running");
|
||||
}
|
||||
|
||||
if (sidechain_enabled_peerplays && config_ready_peerplays) {
|
||||
net_manager->create_handler(sidechain_type::peerplays, options);
|
||||
net_handlers.at(sidechain_type::peerplays) = net_handler_factory.create_handler(sidechain_type::peerplays, options);
|
||||
ilog("Peerplays sidechain handler running");
|
||||
}
|
||||
|
||||
|
|
@ -296,12 +316,13 @@ std::set<chain::son_id_type> &peerplays_sidechain_plugin_impl::get_sons() {
|
|||
return sons;
|
||||
}
|
||||
|
||||
const son_id_type peerplays_sidechain_plugin_impl::get_current_son_id() {
|
||||
return current_son_id;
|
||||
const son_id_type peerplays_sidechain_plugin_impl::get_current_son_id(sidechain_type sidechain) {
|
||||
const std::lock_guard<std::mutex> lock(current_son_id_mutex);
|
||||
return current_son_id.at(sidechain);
|
||||
}
|
||||
|
||||
const son_object peerplays_sidechain_plugin_impl::get_current_son_object() {
|
||||
return get_son_object(current_son_id);
|
||||
const son_object peerplays_sidechain_plugin_impl::get_current_son_object(sidechain_type sidechain) {
|
||||
return get_son_object(get_current_son_id(sidechain));
|
||||
}
|
||||
|
||||
const son_object peerplays_sidechain_plugin_impl::get_son_object(son_id_type son_id) {
|
||||
|
|
@ -312,16 +333,15 @@ const son_object peerplays_sidechain_plugin_impl::get_son_object(son_id_type son
|
|||
return *son_obj;
|
||||
}
|
||||
|
||||
bool peerplays_sidechain_plugin_impl::is_active_son(son_id_type son_id) {
|
||||
bool peerplays_sidechain_plugin_impl::is_active_son(sidechain_type sidechain, son_id_type son_id) {
|
||||
const auto &idx = plugin.database().get_index_type<chain::son_index>().indices().get<by_id>();
|
||||
auto son_obj = idx.find(son_id);
|
||||
if (son_obj == idx.end())
|
||||
return false;
|
||||
|
||||
const chain::global_property_object &gpo = plugin.database().get_global_properties();
|
||||
vector<son_id_type> active_son_ids;
|
||||
active_son_ids.reserve(gpo.active_sons.size());
|
||||
std::transform(gpo.active_sons.begin(), gpo.active_sons.end(),
|
||||
set<son_id_type> active_son_ids;
|
||||
std::transform(gpo.active_sons.at(sidechain).cbegin(), gpo.active_sons.at(sidechain).cend(),
|
||||
std::inserter(active_son_ids, active_son_ids.end()),
|
||||
[](const son_info &swi) {
|
||||
return swi.son_id;
|
||||
|
|
@ -338,7 +358,13 @@ bool peerplays_sidechain_plugin_impl::is_son_deregistered(son_id_type son_id) {
|
|||
if (son_obj == idx.end())
|
||||
return true;
|
||||
|
||||
if (son_obj->status == chain::son_status::deregistered) {
|
||||
bool status_deregistered = true;
|
||||
for (const auto &status : son_obj->statuses) {
|
||||
if ((status.second != son_status::deregistered))
|
||||
status_deregistered = false;
|
||||
}
|
||||
|
||||
if (status_deregistered) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -362,13 +388,23 @@ bool peerplays_sidechain_plugin_impl::is_son_down_op_valid(const chain::operatio
|
|||
}
|
||||
auto stats = son_obj->statistics(d);
|
||||
fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval;
|
||||
fc::time_point_sec last_active_ts = ((stats.last_active_timestamp > last_maintenance_time) ? stats.last_active_timestamp : last_maintenance_time);
|
||||
int64_t down_threshold = gpo.parameters.son_down_time();
|
||||
if (((son_obj->status == chain::son_status::active) || (son_obj->status == chain::son_status::request_maintenance)) &&
|
||||
((fc::time_point::now() - last_active_ts) > fc::seconds(down_threshold))) {
|
||||
return true;
|
||||
|
||||
bool status_son_down_op_valid = true;
|
||||
for (const auto &status : son_obj->statuses) {
|
||||
if ((status.second != son_status::active) && (status.second != son_status::request_maintenance))
|
||||
status_son_down_op_valid = false;
|
||||
}
|
||||
return false;
|
||||
if (status_son_down_op_valid) {
|
||||
for (const auto &active_sidechain_type : active_sidechain_types) {
|
||||
fc::time_point_sec last_active_ts = ((stats.last_active_timestamp.at(active_sidechain_type) > last_maintenance_time) ? stats.last_active_timestamp.at(active_sidechain_type) : last_maintenance_time);
|
||||
if (((fc::time_point::now() - last_active_ts) <= fc::seconds(down_threshold))) {
|
||||
status_son_down_op_valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status_son_down_op_valid;
|
||||
}
|
||||
|
||||
fc::ecc::private_key peerplays_sidechain_plugin_impl::get_private_key(son_id_type son_id) {
|
||||
|
|
@ -400,7 +436,23 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop() {
|
|||
chain::database &d = plugin.database();
|
||||
|
||||
for (son_id_type son_id : sons) {
|
||||
if (is_active_son(son_id) || get_son_object(son_id).status == chain::son_status::in_maintenance) {
|
||||
const auto &son_obj = get_son_object(son_id);
|
||||
|
||||
//! Check that son is in_maintenance
|
||||
bool status_in_maintenance = false;
|
||||
for (const auto &status : son_obj.statuses) {
|
||||
if ((status.second == son_status::in_maintenance))
|
||||
status_in_maintenance = true;
|
||||
}
|
||||
|
||||
//! Check that son is active (at least for one sidechain_type)
|
||||
bool is_son_active = false;
|
||||
for (const auto &active_sidechain_type : active_sidechain_types) {
|
||||
if (is_active_son(active_sidechain_type, son_id))
|
||||
is_son_active = true;
|
||||
}
|
||||
|
||||
if (is_son_active || status_in_maintenance) {
|
||||
|
||||
ilog("Sending heartbeat for SON ${son}", ("son", son_id));
|
||||
chain::son_heartbeat_operation op;
|
||||
|
|
@ -426,19 +478,23 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop() {
|
|||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::schedule_son_processing() {
|
||||
fc::time_point now = fc::time_point::now();
|
||||
int64_t time_to_next_son_processing = 500000;
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
static const int64_t time_to_next_son_processing = 500000;
|
||||
|
||||
fc::time_point next_wakeup(now + fc::microseconds(time_to_next_son_processing));
|
||||
const auto next_wakeup = now + std::chrono::microseconds(time_to_next_son_processing);
|
||||
|
||||
_son_processing_task = fc::schedule([this] {
|
||||
son_processing();
|
||||
},
|
||||
next_wakeup, "SON Processing");
|
||||
for (const auto &active_sidechain_type : active_sidechain_types) {
|
||||
_son_processing_task[active_sidechain_type] = std::async(std::launch::async, [this, next_wakeup, active_sidechain_type] {
|
||||
std::this_thread::sleep_until(next_wakeup);
|
||||
son_processing(active_sidechain_type);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::son_processing() {
|
||||
if (plugin.database().get_global_properties().active_sons.size() <= 0) {
|
||||
void peerplays_sidechain_plugin_impl::son_processing(sidechain_type sidechain) {
|
||||
//! Check whether we have active SONs
|
||||
if (plugin.database().get_global_properties().active_sons.count(sidechain) == 0 ||
|
||||
plugin.database().get_global_properties().active_sons.at(sidechain).empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -448,50 +504,55 @@ void peerplays_sidechain_plugin_impl::son_processing() {
|
|||
// return; // Not synced
|
||||
//}
|
||||
|
||||
fc::time_point now_fine = fc::time_point::now();
|
||||
fc::time_point_sec now = now_fine - fc::milliseconds(3000);
|
||||
const fc::time_point now_fine = fc::time_point::now();
|
||||
const fc::time_point_sec now = now_fine - fc::milliseconds(3000);
|
||||
if (plugin.database().head_block_time() < now) {
|
||||
return; // Not synced
|
||||
}
|
||||
|
||||
chain::son_id_type scheduled_son_id = plugin.database().get_scheduled_son(1);
|
||||
ilog("Scheduled SON: ${scheduled_son_id} Now: ${now} ",
|
||||
("scheduled_son_id", scheduled_son_id)("now", now));
|
||||
//! Get scheduled_son_id according to sidechain_type
|
||||
const chain::son_id_type scheduled_son_id = plugin.database().get_scheduled_son(sidechain, 1);
|
||||
ilog("Scheduled SON: ${scheduled_son_id} Sidechain: ${sidechain} Now: ${now}",
|
||||
("scheduled_son_id", scheduled_son_id)("sidechain", sidechain)("now", now));
|
||||
|
||||
for (son_id_type son_id : plugin.get_sons()) {
|
||||
if (plugin.is_son_deregistered(son_id)) {
|
||||
continue;
|
||||
}
|
||||
current_son_id = son_id;
|
||||
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(current_son_id_mutex);
|
||||
current_son_id.at(sidechain) = son_id;
|
||||
}
|
||||
|
||||
// These tasks are executed by
|
||||
// - All active SONs, no matter if scheduled
|
||||
// - All previously active SONs
|
||||
approve_proposals();
|
||||
process_proposals();
|
||||
process_sidechain_transactions();
|
||||
approve_proposals(sidechain);
|
||||
process_proposals(sidechain);
|
||||
process_sidechain_transactions(sidechain);
|
||||
|
||||
if (plugin.is_active_son(son_id)) {
|
||||
if (plugin.is_active_son(sidechain, son_id)) {
|
||||
// Tasks that are executed by scheduled and active SON only
|
||||
if (current_son_id == scheduled_son_id) {
|
||||
if (get_current_son_id(sidechain) == scheduled_son_id) {
|
||||
|
||||
create_son_down_proposals();
|
||||
create_son_down_proposals(sidechain);
|
||||
|
||||
create_son_deregister_proposals();
|
||||
create_son_deregister_proposals(sidechain);
|
||||
|
||||
process_active_sons_change();
|
||||
process_active_sons_change(sidechain);
|
||||
|
||||
create_deposit_addresses();
|
||||
create_deposit_addresses(sidechain);
|
||||
|
||||
process_deposits();
|
||||
process_deposits(sidechain);
|
||||
|
||||
process_withdrawals();
|
||||
process_withdrawals(sidechain);
|
||||
|
||||
process_sidechain_transactions();
|
||||
process_sidechain_transactions(sidechain);
|
||||
|
||||
send_sidechain_transactions();
|
||||
send_sidechain_transactions(sidechain);
|
||||
|
||||
settle_sidechain_transactions();
|
||||
settle_sidechain_transactions(sidechain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -514,8 +575,8 @@ bool peerplays_sidechain_plugin_impl::is_valid_son_proposal(const chain::proposa
|
|||
return false;
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::log_son_proposal_retry(int op_type, object_id_type object_id) {
|
||||
son_proposal_type prop_type(op_type, get_current_son_id(), object_id);
|
||||
void peerplays_sidechain_plugin_impl::log_son_proposal_retry(sidechain_type sidechain, int op_type, object_id_type object_id) {
|
||||
son_proposal_type prop_type(op_type, sidechain, get_current_son_id(sidechain), object_id);
|
||||
auto itr = son_retry_count.find(prop_type);
|
||||
if (itr != son_retry_count.end()) {
|
||||
itr->second++;
|
||||
|
|
@ -524,18 +585,27 @@ void peerplays_sidechain_plugin_impl::log_son_proposal_retry(int op_type, object
|
|||
}
|
||||
}
|
||||
|
||||
bool peerplays_sidechain_plugin_impl::can_son_participate(int op_type, object_id_type object_id) {
|
||||
son_proposal_type prop_type(op_type, get_current_son_id(), object_id);
|
||||
bool peerplays_sidechain_plugin_impl::can_son_participate(sidechain_type sidechain, int op_type, object_id_type object_id) {
|
||||
son_proposal_type prop_type(op_type, sidechain, get_current_son_id(sidechain), object_id);
|
||||
auto itr = son_retry_count.find(prop_type);
|
||||
return (itr == son_retry_count.end() || itr->second < retries_threshold);
|
||||
}
|
||||
|
||||
std::map<sidechain_type, std::vector<std::string>> peerplays_sidechain_plugin_impl::get_son_listener_log() {
|
||||
return net_manager->get_son_listener_log();
|
||||
std::map<sidechain_type, std::vector<std::string>> result;
|
||||
for (const auto &active_sidechain_type : active_sidechain_types) {
|
||||
result.emplace(active_sidechain_type, net_handlers.at(active_sidechain_type)->get_son_listener_log());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::approve_proposals() {
|
||||
|
||||
void peerplays_sidechain_plugin_impl::approve_proposals(sidechain_type sidechain) {
|
||||
// prevent approving duplicate proposals with lock for parallel execution.
|
||||
// We can have the same propsals, but in the case of parallel execution we can run
|
||||
// into problem of approving the same propsal since it might happens that previous
|
||||
// approved proposal didn't have time or chance to populate the list of available
|
||||
// active proposals which is consulted here in the code.
|
||||
std::lock_guard<std::mutex> lck(access_approve_prop_mutex);
|
||||
auto check_approve_proposal = [&](const chain::son_id_type &son_id, const chain::proposal_object &proposal) {
|
||||
if (!is_valid_son_proposal(proposal)) {
|
||||
return;
|
||||
|
|
@ -549,6 +619,7 @@ void peerplays_sidechain_plugin_impl::approve_proposals() {
|
|||
fc::future<bool> fut = fc::async([&]() {
|
||||
try {
|
||||
trx.validate();
|
||||
std::lock_guard<std::mutex> lck(access_db_mutex);
|
||||
plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
if (plugin.app().p2p_node())
|
||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||
|
|
@ -568,7 +639,6 @@ void peerplays_sidechain_plugin_impl::approve_proposals() {
|
|||
}
|
||||
|
||||
for (const auto proposal_id : proposals) {
|
||||
|
||||
const object *obj = plugin.database().find_object(proposal_id);
|
||||
const chain::proposal_object *proposal_ptr = dynamic_cast<const chain::proposal_object *>(obj);
|
||||
if (proposal_ptr == nullptr) {
|
||||
|
|
@ -576,15 +646,16 @@ void peerplays_sidechain_plugin_impl::approve_proposals() {
|
|||
}
|
||||
const proposal_object proposal = *proposal_ptr;
|
||||
|
||||
if (proposal.available_active_approvals.find(get_current_son_object().son_account) != proposal.available_active_approvals.end()) {
|
||||
if (proposal.available_active_approvals.find(get_current_son_object(sidechain).son_account) != proposal.available_active_approvals.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
check_approve_proposal(get_current_son_id(), proposal);
|
||||
check_approve_proposal(get_current_son_id(sidechain), proposal);
|
||||
}
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::create_son_down_proposals() {
|
||||
void peerplays_sidechain_plugin_impl::create_son_down_proposals(sidechain_type sidechain) {
|
||||
std::lock_guard<std::mutex> lck(access_son_down_prop_mutex);
|
||||
auto create_son_down_proposal = [&](chain::son_id_type son_id, fc::time_point_sec last_active_ts) {
|
||||
chain::database &d = plugin.database();
|
||||
const chain::global_property_object &gpo = d.get_global_properties();
|
||||
|
|
@ -595,7 +666,7 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals() {
|
|||
son_down_op.down_ts = last_active_ts;
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = get_current_son_object().son_account;
|
||||
proposal_op.fee_paying_account = get_current_son_object(sidechain).son_account;
|
||||
proposal_op.proposed_ops.emplace_back(op_wrapper(son_down_op));
|
||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||
proposal_op.expiration_time = time_point_sec(d.head_block_time().sec_since_epoch() + lifetime);
|
||||
|
|
@ -607,24 +678,32 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals() {
|
|||
const chain::dynamic_global_property_object &dgpo = d.get_dynamic_global_properties();
|
||||
const auto &idx = d.get_index_type<chain::son_index>().indices().get<by_id>();
|
||||
std::set<son_id_type> sons_being_reported_down = d.get_sons_being_reported_down();
|
||||
chain::son_id_type my_son_id = get_current_son_id();
|
||||
for (auto son_inf : gpo.active_sons) {
|
||||
chain::son_id_type my_son_id = get_current_son_id(sidechain);
|
||||
|
||||
//! Fixme - check this part of the code
|
||||
for (auto son_inf : gpo.active_sons.at(sidechain)) {
|
||||
if (my_son_id == son_inf.son_id || (sons_being_reported_down.find(son_inf.son_id) != sons_being_reported_down.end())) {
|
||||
continue;
|
||||
}
|
||||
auto son_obj = idx.find(son_inf.son_id);
|
||||
auto stats = son_obj->statistics(d);
|
||||
fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval;
|
||||
fc::time_point_sec last_active_ts = ((stats.last_active_timestamp > last_maintenance_time) ? stats.last_active_timestamp : last_maintenance_time);
|
||||
fc::time_point_sec last_active_ts = ((stats.last_active_timestamp.at(sidechain) > last_maintenance_time) ? stats.last_active_timestamp.at(sidechain) : last_maintenance_time);
|
||||
int64_t down_threshold = gpo.parameters.son_down_time();
|
||||
if (((son_obj->status == chain::son_status::active) || (son_obj->status == chain::son_status::request_maintenance)) &&
|
||||
((fc::time_point::now() - last_active_ts) > fc::seconds(down_threshold))) {
|
||||
|
||||
bool status_son_down_valid = true;
|
||||
for (const auto &status : son_obj->statuses) {
|
||||
if ((status.second != son_status::active) && (status.second != son_status::request_maintenance))
|
||||
status_son_down_valid = false;
|
||||
}
|
||||
if ((status_son_down_valid) && ((fc::time_point::now() - last_active_ts) > fc::seconds(down_threshold))) {
|
||||
ilog("Sending son down proposal for ${t} from ${s}", ("t", std::string(object_id_type(son_obj->id)))("s", std::string(object_id_type(my_son_id))));
|
||||
chain::proposal_create_operation op = create_son_down_proposal(son_inf.son_id, last_active_ts);
|
||||
chain::signed_transaction trx = d.create_signed_transaction(plugin.get_private_key(get_son_object(my_son_id).signing_key), op);
|
||||
fc::future<bool> fut = fc::async([&]() {
|
||||
try {
|
||||
trx.validate();
|
||||
std::lock_guard<std::mutex> lck(access_db_mutex);
|
||||
d.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
if (plugin.app().p2p_node())
|
||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||
|
|
@ -639,10 +718,10 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals() {
|
|||
}
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::create_son_deregister_proposals() {
|
||||
void peerplays_sidechain_plugin_impl::create_son_deregister_proposals(sidechain_type sidechain) {
|
||||
chain::database &d = plugin.database();
|
||||
std::set<son_id_type> sons_to_be_dereg = d.get_sons_to_be_deregistered();
|
||||
chain::son_id_type my_son_id = get_current_son_id();
|
||||
chain::son_id_type my_son_id = get_current_son_id(sidechain);
|
||||
|
||||
if (sons_to_be_dereg.size() > 0) {
|
||||
// We shouldn't raise proposals for the SONs for which a de-reg
|
||||
|
|
@ -660,6 +739,7 @@ void peerplays_sidechain_plugin_impl::create_son_deregister_proposals() {
|
|||
fc::future<bool> fut = fc::async([&]() {
|
||||
try {
|
||||
trx.validate();
|
||||
std::lock_guard<std::mutex> lck(access_db_mutex);
|
||||
d.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
if (plugin.app().p2p_node())
|
||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||
|
|
@ -676,36 +756,36 @@ void peerplays_sidechain_plugin_impl::create_son_deregister_proposals() {
|
|||
}
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::process_proposals() {
|
||||
net_manager->process_proposals();
|
||||
void peerplays_sidechain_plugin_impl::process_proposals(sidechain_type sidechain) {
|
||||
net_handlers.at(sidechain)->process_proposals();
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::process_active_sons_change() {
|
||||
net_manager->process_active_sons_change();
|
||||
void peerplays_sidechain_plugin_impl::process_active_sons_change(sidechain_type sidechain) {
|
||||
net_handlers.at(sidechain)->process_active_sons_change();
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::create_deposit_addresses() {
|
||||
net_manager->create_deposit_addresses();
|
||||
void peerplays_sidechain_plugin_impl::create_deposit_addresses(sidechain_type sidechain) {
|
||||
net_handlers.at(sidechain)->create_deposit_addresses();
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::process_deposits() {
|
||||
net_manager->process_deposits();
|
||||
void peerplays_sidechain_plugin_impl::process_deposits(sidechain_type sidechain) {
|
||||
net_handlers.at(sidechain)->process_deposits();
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::process_withdrawals() {
|
||||
net_manager->process_withdrawals();
|
||||
void peerplays_sidechain_plugin_impl::process_withdrawals(sidechain_type sidechain) {
|
||||
net_handlers.at(sidechain)->process_withdrawals();
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::process_sidechain_transactions() {
|
||||
net_manager->process_sidechain_transactions();
|
||||
void peerplays_sidechain_plugin_impl::process_sidechain_transactions(sidechain_type sidechain) {
|
||||
net_handlers.at(sidechain)->process_sidechain_transactions();
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::send_sidechain_transactions() {
|
||||
net_manager->send_sidechain_transactions();
|
||||
void peerplays_sidechain_plugin_impl::send_sidechain_transactions(sidechain_type sidechain) {
|
||||
net_handlers.at(sidechain)->send_sidechain_transactions();
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::settle_sidechain_transactions() {
|
||||
net_manager->settle_sidechain_transactions();
|
||||
void peerplays_sidechain_plugin_impl::settle_sidechain_transactions(sidechain_type sidechain) {
|
||||
net_handlers.at(sidechain)->settle_sidechain_transactions();
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::on_applied_block(const signed_block &b) {
|
||||
|
|
@ -758,20 +838,20 @@ std::set<chain::son_id_type> &peerplays_sidechain_plugin::get_sons() {
|
|||
return my->get_sons();
|
||||
}
|
||||
|
||||
const son_id_type peerplays_sidechain_plugin::get_current_son_id() {
|
||||
return my->get_current_son_id();
|
||||
const son_id_type peerplays_sidechain_plugin::get_current_son_id(sidechain_type sidechain) {
|
||||
return my->get_current_son_id(sidechain);
|
||||
}
|
||||
|
||||
const son_object peerplays_sidechain_plugin::get_current_son_object() {
|
||||
return my->get_current_son_object();
|
||||
const son_object peerplays_sidechain_plugin::get_current_son_object(sidechain_type sidechain) {
|
||||
return my->get_current_son_object(sidechain);
|
||||
}
|
||||
|
||||
const son_object peerplays_sidechain_plugin::get_son_object(son_id_type son_id) {
|
||||
return my->get_son_object(son_id);
|
||||
}
|
||||
|
||||
bool peerplays_sidechain_plugin::is_active_son(son_id_type son_id) {
|
||||
return my->is_active_son(son_id);
|
||||
bool peerplays_sidechain_plugin::is_active_son(sidechain_type sidechain, son_id_type son_id) {
|
||||
return my->is_active_son(sidechain, son_id);
|
||||
}
|
||||
|
||||
bool peerplays_sidechain_plugin::is_son_deregistered(son_id_type son_id) {
|
||||
|
|
@ -786,12 +866,12 @@ fc::ecc::private_key peerplays_sidechain_plugin::get_private_key(chain::public_k
|
|||
return my->get_private_key(public_key);
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin::log_son_proposal_retry(int op_type, object_id_type object_id) {
|
||||
my->log_son_proposal_retry(op_type, object_id);
|
||||
void peerplays_sidechain_plugin::log_son_proposal_retry(sidechain_type sidechain, int op_type, object_id_type object_id) {
|
||||
my->log_son_proposal_retry(sidechain, op_type, object_id);
|
||||
}
|
||||
|
||||
bool peerplays_sidechain_plugin::can_son_participate(int op_type, object_id_type object_id) {
|
||||
return my->can_son_participate(op_type, object_id);
|
||||
bool peerplays_sidechain_plugin::can_son_participate(sidechain_type sidechain, int op_type, object_id_type object_id) {
|
||||
return my->can_son_participate(sidechain, op_type, object_id);
|
||||
}
|
||||
|
||||
std::map<sidechain_type, std::vector<std::string>> peerplays_sidechain_plugin::get_son_listener_log() {
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
|
|||
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HIVE") == 0)) ||
|
||||
enable_peerplays_asset_deposits);
|
||||
|
||||
bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain == sidechain_type::peerplays) &&
|
||||
bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain == sidechain) && //! Fixme -> sidechain_type::peerplays
|
||||
((sed.sidechain_currency == object_id_to_string(gpo.parameters.btc_asset())) ||
|
||||
(sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset())) ||
|
||||
(sed.sidechain_currency == object_id_to_string(gpo.parameters.hive_asset())));
|
||||
|
|
@ -191,7 +191,7 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
|
|||
if (deposit_condition) {
|
||||
|
||||
for (son_id_type son_id : plugin.get_sons()) {
|
||||
if (plugin.is_active_son(son_id)) {
|
||||
if (plugin.is_active_son(sidechain, son_id)) {
|
||||
|
||||
son_wallet_deposit_create_operation op;
|
||||
op.payer = plugin.get_son_object(son_id).son_account;
|
||||
|
|
@ -253,7 +253,7 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
|
|||
}
|
||||
|
||||
for (son_id_type son_id : plugin.get_sons()) {
|
||||
if (plugin.is_active_son(son_id)) {
|
||||
if (plugin.is_active_son(sidechain, son_id)) {
|
||||
|
||||
son_wallet_withdraw_create_operation op;
|
||||
op.payer = plugin.get_son_object(son_id).son_account;
|
||||
|
|
@ -297,7 +297,7 @@ void sidechain_net_handler::process_proposals() {
|
|||
const auto po = idx.find(proposal_id);
|
||||
if (po != idx.end()) {
|
||||
|
||||
if (po->available_active_approvals.find(plugin.get_current_son_object().son_account) != po->available_active_approvals.end()) {
|
||||
if (po->available_active_approvals.find(plugin.get_current_son_object(sidechain).son_account) != po->available_active_approvals.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -380,12 +380,12 @@ void sidechain_net_handler::process_proposals() {
|
|||
elog("==================================================");
|
||||
}
|
||||
|
||||
if (should_process && (op_idx_0 == chain::operation::tag<chain::sidechain_transaction_sign_operation>::value || plugin.can_son_participate(op_idx_0, object_id))) {
|
||||
if (should_process && (op_idx_0 == chain::operation::tag<chain::sidechain_transaction_sign_operation>::value || plugin.can_son_participate(sidechain, op_idx_0, object_id))) {
|
||||
bool should_approve = process_proposal(*po);
|
||||
if (should_approve) {
|
||||
if (approve_proposal(po->id, plugin.get_current_son_id())) {
|
||||
if (approve_proposal(po->id, plugin.get_current_son_id(sidechain))) {
|
||||
if (op_idx_0 != chain::operation::tag<chain::sidechain_transaction_sign_operation>::value) {
|
||||
plugin.log_son_proposal_retry(op_idx_0, object_id);
|
||||
plugin.log_son_proposal_retry(sidechain, op_idx_0, object_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -399,14 +399,14 @@ void sidechain_net_handler::process_active_sons_change() {
|
|||
}
|
||||
|
||||
void sidechain_net_handler::create_deposit_addresses() {
|
||||
if (database.get_global_properties().active_sons.size() < database.get_chain_properties().immutable_parameters.min_son_count) {
|
||||
if (database.get_global_properties().active_sons.at(sidechain).size() < database.get_chain_properties().immutable_parameters.min_son_count) {
|
||||
return;
|
||||
}
|
||||
process_sidechain_addresses();
|
||||
}
|
||||
|
||||
void sidechain_net_handler::process_deposits() {
|
||||
if (database.get_global_properties().active_sons.size() < database.get_chain_properties().immutable_parameters.min_son_count) {
|
||||
if (database.get_global_properties().active_sons.at(sidechain).size() < database.get_chain_properties().immutable_parameters.min_son_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -414,7 +414,7 @@ void sidechain_net_handler::process_deposits() {
|
|||
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, true, false));
|
||||
|
||||
std::for_each(idx_range.first, idx_range.second, [&](const son_wallet_deposit_object &swdo) {
|
||||
if (swdo.id == object_id_type(0, 0, 0) || !plugin.can_son_participate(chain::operation::tag<chain::son_wallet_deposit_process_operation>::value, swdo.id)) {
|
||||
if (swdo.id == object_id_type(0, 0, 0) || !plugin.can_son_participate(sidechain, chain::operation::tag<chain::son_wallet_deposit_process_operation>::value, swdo.id)) {
|
||||
return;
|
||||
}
|
||||
//Ignore the deposits which are not valid anymore, considered refunds.
|
||||
|
|
@ -436,12 +436,12 @@ void sidechain_net_handler::process_deposits() {
|
|||
wlog("Deposit not processed: ${swdo}", ("swdo", swdo));
|
||||
return;
|
||||
}
|
||||
plugin.log_son_proposal_retry(chain::operation::tag<chain::son_wallet_deposit_process_operation>::value, swdo.id);
|
||||
plugin.log_son_proposal_retry(sidechain, chain::operation::tag<chain::son_wallet_deposit_process_operation>::value, swdo.id);
|
||||
});
|
||||
}
|
||||
|
||||
void sidechain_net_handler::process_withdrawals() {
|
||||
if (database.get_global_properties().active_sons.size() < database.get_chain_properties().immutable_parameters.min_son_count) {
|
||||
if (database.get_global_properties().active_sons.at(sidechain).size() < database.get_chain_properties().immutable_parameters.min_son_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -449,7 +449,7 @@ void sidechain_net_handler::process_withdrawals() {
|
|||
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, true, false));
|
||||
|
||||
std::for_each(idx_range.first, idx_range.second, [&](const son_wallet_withdraw_object &swwo) {
|
||||
if (swwo.id == object_id_type(0, 0, 0) || !plugin.can_son_participate(chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value, swwo.id)) {
|
||||
if (swwo.id == object_id_type(0, 0, 0) || !plugin.can_son_participate(sidechain, chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value, swwo.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -461,7 +461,7 @@ void sidechain_net_handler::process_withdrawals() {
|
|||
wlog("Withdraw not processed: ${swwo}", ("swwo", swwo));
|
||||
return;
|
||||
}
|
||||
plugin.log_son_proposal_retry(chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value, swwo.id);
|
||||
plugin.log_son_proposal_retry(sidechain, chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value, swwo.id);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -470,7 +470,7 @@ void sidechain_net_handler::process_sidechain_transactions() {
|
|||
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, sidechain_transaction_status::valid));
|
||||
|
||||
std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) {
|
||||
if ((sto.id == object_id_type(0, 0, 0)) || !signer_expected(sto, plugin.get_current_son_id())) {
|
||||
if ((sto.id == object_id_type(0, 0, 0)) || !signer_expected(sto, plugin.get_current_son_id(sidechain))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -485,13 +485,13 @@ void sidechain_net_handler::process_sidechain_transactions() {
|
|||
|
||||
const chain::global_property_object &gpo = database.get_global_properties();
|
||||
sidechain_transaction_sign_operation sts_op;
|
||||
sts_op.signer = plugin.get_current_son_id();
|
||||
sts_op.signer = plugin.get_current_son_id(sidechain);
|
||||
sts_op.payer = gpo.parameters.son_account();
|
||||
sts_op.sidechain_transaction_id = sto.id;
|
||||
sts_op.signature = processed_sidechain_tx;
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
|
||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
||||
proposal_op.proposed_ops.emplace_back(sts_op);
|
||||
|
|
@ -500,7 +500,7 @@ void sidechain_net_handler::process_sidechain_transactions() {
|
|||
return;
|
||||
}
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
|
||||
try {
|
||||
trx.validate();
|
||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
|
|
@ -531,11 +531,11 @@ void sidechain_net_handler::send_sidechain_transactions() {
|
|||
}
|
||||
|
||||
sidechain_transaction_send_operation sts_op;
|
||||
sts_op.payer = plugin.get_current_son_object().son_account;
|
||||
sts_op.payer = plugin.get_current_son_object(sidechain).son_account;
|
||||
sts_op.sidechain_transaction_id = sto.id;
|
||||
sts_op.sidechain_transaction = sidechain_transaction;
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), sts_op);
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), sts_op);
|
||||
try {
|
||||
trx.validate();
|
||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
|
|
@ -560,7 +560,7 @@ void sidechain_net_handler::settle_sidechain_transactions() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!plugin.can_son_participate(chain::operation::tag<chain::sidechain_transaction_settle_operation>::value, sto.object_id)) {
|
||||
if (!plugin.can_son_participate(sidechain, chain::operation::tag<chain::sidechain_transaction_settle_operation>::value, sto.object_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -577,7 +577,7 @@ void sidechain_net_handler::settle_sidechain_transactions() {
|
|||
const chain::global_property_object &gpo = database.get_global_properties();
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
|
||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
||||
|
||||
|
|
@ -605,13 +605,13 @@ void sidechain_net_handler::settle_sidechain_transactions() {
|
|||
}
|
||||
}
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
|
||||
try {
|
||||
trx.validate();
|
||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
if (plugin.app().p2p_node())
|
||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||
plugin.log_son_proposal_retry(chain::operation::tag<chain::sidechain_transaction_settle_operation>::value, sto.object_id);
|
||||
plugin.log_son_proposal_retry(sidechain, chain::operation::tag<chain::sidechain_transaction_settle_operation>::value, sto.object_id);
|
||||
} catch (fc::exception &e) {
|
||||
elog("Sending proposal for sidechain transaction settle operation failed with exception ${e}", ("e", e.what()));
|
||||
}
|
||||
|
|
@ -673,7 +673,7 @@ void sidechain_net_handler::on_applied_block(const signed_block &b) {
|
|||
sidechain_event_data sed;
|
||||
sed.timestamp = database.head_block_time();
|
||||
sed.block_num = database.head_block_num();
|
||||
sed.sidechain = sidechain_type::peerplays;
|
||||
sed.sidechain = sidechain; //! Fixme -> sidechain_type::peerplays
|
||||
sed.sidechain_uid = sidechain_uid;
|
||||
sed.sidechain_transaction_id = trx.id().str();
|
||||
sed.sidechain_from = sidechain_from;
|
||||
|
|
|
|||
|
|
@ -417,7 +417,7 @@ sidechain_net_handler_bitcoin::~sidechain_net_handler_bitcoin() {
|
|||
|
||||
bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) {
|
||||
|
||||
// ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id()));
|
||||
//ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id(sidechain)));
|
||||
|
||||
bool should_approve = false;
|
||||
|
||||
|
|
@ -451,8 +451,8 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
|
|||
const auto swo = idx.find(swo_id);
|
||||
if (swo != idx.end()) {
|
||||
|
||||
auto active_sons = gpo.active_sons;
|
||||
vector<son_info> wallet_sons = swo->sons;
|
||||
const auto &active_sons = gpo.active_sons.at(sidechain);
|
||||
vector<son_info> wallet_sons = swo->sons.at(sidechain);
|
||||
|
||||
bool son_sets_equal = (active_sons.size() == wallet_sons.size());
|
||||
|
||||
|
|
@ -463,10 +463,10 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
|
|||
}
|
||||
|
||||
if (son_sets_equal) {
|
||||
auto active_sons = gpo.active_sons;
|
||||
const auto &active_sons = gpo.active_sons.at(sidechain);
|
||||
vector<string> son_pubkeys_bitcoin;
|
||||
for (const son_info &si : active_sons) {
|
||||
son_pubkeys_bitcoin.push_back(si.sidechain_public_keys.at(sidechain_type::bitcoin));
|
||||
son_pubkeys_bitcoin.push_back(si.public_key);
|
||||
}
|
||||
|
||||
string reply_str = create_primary_wallet_address(active_sons);
|
||||
|
|
@ -676,7 +676,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
|
|||
|
||||
read_transaction_data(sto->transaction, tx_hex, in_amounts, redeem_script);
|
||||
bitcoin_transaction tx = unpack(parse_hex(tx_hex));
|
||||
bitcoin::bytes pubkey = parse_hex(son->sidechain_public_keys.at(sidechain_type::bitcoin));
|
||||
bitcoin::bytes pubkey = parse_hex(son->sidechain_public_keys.at(sidechain));
|
||||
vector<bitcoin::bytes> sigs = read_byte_arrays_from_string(signature);
|
||||
for (size_t i = 0; i < tx.vin.size(); i++) {
|
||||
const auto &sighash_str = get_signature_hash(tx, parse_hex(redeem_script), static_cast<int64_t>(in_amounts[i]), i, 1, true).str();
|
||||
|
|
@ -706,8 +706,8 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() {
|
|||
const auto &active_sw = swi.rbegin();
|
||||
if (active_sw != swi.rend()) {
|
||||
|
||||
if ((active_sw->addresses.find(sidechain_type::bitcoin) == active_sw->addresses.end()) ||
|
||||
(active_sw->addresses.at(sidechain_type::bitcoin).empty())) {
|
||||
if ((active_sw->addresses.find(sidechain) == active_sw->addresses.end()) ||
|
||||
(active_sw->addresses.at(sidechain).empty())) {
|
||||
|
||||
if (proposal_exists(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) {
|
||||
return;
|
||||
|
|
@ -715,19 +715,19 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() {
|
|||
|
||||
const chain::global_property_object &gpo = database.get_global_properties();
|
||||
|
||||
auto active_sons = gpo.active_sons;
|
||||
const auto &active_sons = gpo.active_sons.at(sidechain);
|
||||
string reply_str = create_primary_wallet_address(active_sons);
|
||||
|
||||
std::stringstream active_pw_ss(reply_str);
|
||||
boost::property_tree::ptree active_pw_pt;
|
||||
boost::property_tree::read_json(active_pw_ss, active_pw_pt);
|
||||
if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) {
|
||||
if (!plugin.can_son_participate(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) {
|
||||
if (!plugin.can_son_participate(sidechain, chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
|
||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
||||
|
||||
|
|
@ -737,7 +737,7 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() {
|
|||
son_wallet_update_operation swu_op;
|
||||
swu_op.payer = gpo.parameters.son_account();
|
||||
swu_op.son_wallet_id = active_sw->id;
|
||||
swu_op.sidechain = sidechain_type::bitcoin;
|
||||
swu_op.sidechain = sidechain;
|
||||
swu_op.address = res.str();
|
||||
|
||||
proposal_op.proposed_ops.emplace_back(swu_op);
|
||||
|
|
@ -752,18 +752,18 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() {
|
|||
stc_op.object_id = prev_sw->id;
|
||||
stc_op.sidechain = sidechain;
|
||||
stc_op.transaction = tx_str;
|
||||
stc_op.signers = prev_sw->sons;
|
||||
stc_op.signers = prev_sw->sons.at(sidechain);
|
||||
proposal_op.proposed_ops.emplace_back(stc_op);
|
||||
}
|
||||
}
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
|
||||
try {
|
||||
trx.validate();
|
||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
if (plugin.app().p2p_node())
|
||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||
plugin.log_son_proposal_retry(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id);
|
||||
plugin.log_son_proposal_retry(sidechain, chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id);
|
||||
} catch (fc::exception &e) {
|
||||
elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what()));
|
||||
return;
|
||||
|
|
@ -778,9 +778,8 @@ void sidechain_net_handler_bitcoin::process_sidechain_addresses() {
|
|||
|
||||
const chain::global_property_object &gpo = database.get_global_properties();
|
||||
std::vector<std::pair<fc::ecc::public_key, uint16_t>> pubkeys;
|
||||
for (auto &son : gpo.active_sons) {
|
||||
std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin);
|
||||
auto pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str)));
|
||||
for (auto &son : gpo.active_sons.at(sidechain)) {
|
||||
auto pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(son.public_key)));
|
||||
pubkeys.push_back(std::make_pair(pubkey, son.weight));
|
||||
}
|
||||
|
||||
|
|
@ -800,7 +799,7 @@ void sidechain_net_handler_bitcoin::process_sidechain_addresses() {
|
|||
|
||||
if (addr.get_address() != sao.deposit_address) {
|
||||
sidechain_address_update_operation op;
|
||||
op.payer = plugin.get_current_son_object().son_account;
|
||||
op.payer = plugin.get_current_son_object(sidechain).son_account;
|
||||
op.sidechain_address_id = sao.id;
|
||||
op.sidechain_address_account = sao.sidechain_address_account;
|
||||
op.sidechain = sao.sidechain;
|
||||
|
|
@ -810,7 +809,7 @@ void sidechain_net_handler_bitcoin::process_sidechain_addresses() {
|
|||
op.withdraw_public_key = sao.withdraw_public_key;
|
||||
op.withdraw_address = sao.withdraw_address;
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op);
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), op);
|
||||
try {
|
||||
trx.validate();
|
||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
|
|
@ -842,7 +841,7 @@ bool sidechain_net_handler_bitcoin::process_deposit(const son_wallet_deposit_obj
|
|||
const chain::global_property_object &gpo = database.get_global_properties();
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
|
||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
||||
|
||||
|
|
@ -856,10 +855,10 @@ bool sidechain_net_handler_bitcoin::process_deposit(const son_wallet_deposit_obj
|
|||
stc_op.object_id = swdo.id;
|
||||
stc_op.sidechain = sidechain;
|
||||
stc_op.transaction = tx_str;
|
||||
stc_op.signers = gpo.active_sons;
|
||||
stc_op.signers = gpo.active_sons.at(sidechain);
|
||||
proposal_op.proposed_ops.emplace_back(stc_op);
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
|
||||
try {
|
||||
trx.validate();
|
||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
|
|
@ -886,7 +885,7 @@ bool sidechain_net_handler_bitcoin::process_withdrawal(const son_wallet_withdraw
|
|||
const chain::global_property_object &gpo = database.get_global_properties();
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
|
||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
||||
|
||||
|
|
@ -900,10 +899,10 @@ bool sidechain_net_handler_bitcoin::process_withdrawal(const son_wallet_withdraw
|
|||
stc_op.object_id = swwo.id;
|
||||
stc_op.sidechain = sidechain;
|
||||
stc_op.transaction = tx_str;
|
||||
stc_op.signers = gpo.active_sons;
|
||||
stc_op.signers = gpo.active_sons.at(sidechain);
|
||||
proposal_op.proposed_ops.emplace_back(stc_op);
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
|
||||
try {
|
||||
trx.validate();
|
||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
|
|
@ -951,8 +950,7 @@ bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain
|
|||
using namespace bitcoin;
|
||||
std::vector<std::pair<fc::ecc::public_key, uint16_t>> pubkey_weights;
|
||||
for (auto si : sto.signers) {
|
||||
std::string pub_key_str = si.sidechain_public_keys.at(sidechain_type::bitcoin);
|
||||
auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str)));
|
||||
auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(si.public_key)));
|
||||
pubkey_weights.push_back(std::make_pair(pub_key, si.weight));
|
||||
}
|
||||
btc_weighted_multisig_address addr(pubkey_weights, network_type);
|
||||
|
|
@ -1001,8 +999,7 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const s
|
|||
|
||||
std::vector<std::pair<fc::ecc::public_key, uint16_t>> pubkey_weights;
|
||||
for (auto &son : son_pubkeys) {
|
||||
std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin);
|
||||
auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str)));
|
||||
auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(son.public_key)));
|
||||
pubkey_weights.push_back(std::make_pair(pub_key, son.weight));
|
||||
}
|
||||
|
||||
|
|
@ -1019,7 +1016,7 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const s
|
|||
|
||||
std::string sidechain_net_handler_bitcoin::create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address) {
|
||||
|
||||
const auto &address_data = prev_swo.addresses.find(sidechain_type::bitcoin);
|
||||
const auto &address_data = prev_swo.addresses.find(sidechain);
|
||||
if (address_data == prev_swo.addresses.end()) {
|
||||
return "";
|
||||
}
|
||||
|
|
@ -1070,12 +1067,12 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_transaction(con
|
|||
std::string sidechain_net_handler_bitcoin::create_deposit_transaction(const son_wallet_deposit_object &swdo) {
|
||||
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||
auto obj = idx.rbegin();
|
||||
if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) {
|
||||
if (obj == idx.rend() || obj->addresses.find(sidechain) == obj->addresses.end()) {
|
||||
return "";
|
||||
}
|
||||
// Get redeem script for deposit address
|
||||
std::string redeem_script = get_redeemscript_for_userdeposit(swdo.sidechain_from);
|
||||
std::string pw_address_json = obj->addresses.find(sidechain_type::bitcoin)->second;
|
||||
std::string pw_address_json = obj->addresses.find(sidechain)->second;
|
||||
|
||||
std::stringstream ss(pw_address_json);
|
||||
boost::property_tree::ptree json;
|
||||
|
|
@ -1117,11 +1114,11 @@ std::string sidechain_net_handler_bitcoin::create_deposit_transaction(const son_
|
|||
std::string sidechain_net_handler_bitcoin::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) {
|
||||
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||
auto obj = idx.rbegin();
|
||||
if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) {
|
||||
if (obj == idx.rend() || obj->addresses.find(sidechain) == obj->addresses.end()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string pw_address_json = obj->addresses.find(sidechain_type::bitcoin)->second;
|
||||
std::string pw_address_json = obj->addresses.find(sidechain)->second;
|
||||
|
||||
std::stringstream ss(pw_address_json);
|
||||
boost::property_tree::ptree json;
|
||||
|
|
@ -1186,7 +1183,7 @@ std::string sidechain_net_handler_bitcoin::create_transaction(const std::vector<
|
|||
|
||||
std::string sidechain_net_handler_bitcoin::sign_transaction(const sidechain_transaction_object &sto) {
|
||||
using namespace bitcoin;
|
||||
std::string pubkey = plugin.get_current_son_object().sidechain_public_keys.at(sidechain);
|
||||
std::string pubkey = plugin.get_current_son_object(sidechain).sidechain_public_keys.at(sidechain);
|
||||
std::string prvkey = get_private_key(pubkey);
|
||||
std::vector<uint64_t> in_amounts;
|
||||
std::string tx_hex;
|
||||
|
|
@ -1302,14 +1299,13 @@ std::string sidechain_net_handler_bitcoin::get_redeemscript_for_userdeposit(cons
|
|||
|
||||
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||
auto obj = idx.rbegin();
|
||||
if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) {
|
||||
if (obj == idx.rend() || obj->addresses.find(sidechain) == obj->addresses.end()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::vector<std::pair<fc::ecc::public_key, uint16_t>> pubkey_weights;
|
||||
for (auto &son : obj->sons) {
|
||||
std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin);
|
||||
auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str)));
|
||||
for (auto &son : obj->sons.at(sidechain)) {
|
||||
auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(son.public_key)));
|
||||
pubkey_weights.push_back(std::make_pair(pub_key, son.weight));
|
||||
}
|
||||
auto user_pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(addr_itr->deposit_public_key)));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
#include <graphene/peerplays_sidechain/sidechain_net_handler_factory.hpp>
|
||||
|
||||
#include <graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp>
|
||||
#include <graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp>
|
||||
#include <graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp>
|
||||
|
||||
namespace graphene { namespace peerplays_sidechain {
|
||||
|
||||
sidechain_net_handler_factory::sidechain_net_handler_factory(peerplays_sidechain_plugin &_plugin) :
|
||||
plugin(_plugin) {
|
||||
}
|
||||
|
||||
std::unique_ptr<sidechain_net_handler> sidechain_net_handler_factory::create_handler(sidechain_type sidechain, const boost::program_options::variables_map &options) const {
|
||||
switch (sidechain) {
|
||||
case sidechain_type::bitcoin: {
|
||||
return std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_bitcoin(plugin, options));
|
||||
}
|
||||
case sidechain_type::hive: {
|
||||
return std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_hive(plugin, options));
|
||||
}
|
||||
case sidechain_type::peerplays: {
|
||||
return std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_peerplays(plugin, options));
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
@ -180,7 +180,7 @@ sidechain_net_handler_hive::~sidechain_net_handler_hive() {
|
|||
}
|
||||
|
||||
bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) {
|
||||
//ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id()));
|
||||
//ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id(sidechain)));
|
||||
|
||||
bool should_approve = false;
|
||||
|
||||
|
|
@ -213,8 +213,8 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) {
|
|||
const auto swo = idx.find(swo_id);
|
||||
if (swo != idx.end()) {
|
||||
|
||||
auto active_sons = gpo.active_sons;
|
||||
vector<son_info> wallet_sons = swo->sons;
|
||||
auto active_sons = gpo.active_sons.at(sidechain);
|
||||
vector<son_info> wallet_sons = swo->sons.at(sidechain);
|
||||
|
||||
bool son_sets_equal = (active_sons.size() == wallet_sons.size());
|
||||
|
||||
|
|
@ -251,7 +251,7 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) {
|
|||
uint32_t total_weight = 0;
|
||||
for (const auto &wallet_son : wallet_sons) {
|
||||
total_weight = total_weight + wallet_son.weight;
|
||||
account_auths[wallet_son.sidechain_public_keys.at(sidechain)] = wallet_son.weight;
|
||||
account_auths[wallet_son.public_key] = wallet_son.weight;
|
||||
}
|
||||
|
||||
std::string memo_key = node_rpc_client->get_account_memo_key("son-account");
|
||||
|
|
@ -487,12 +487,12 @@ void sidechain_net_handler_hive::process_primary_wallet() {
|
|||
|
||||
const chain::global_property_object &gpo = database.get_global_properties();
|
||||
|
||||
auto active_sons = gpo.active_sons;
|
||||
const auto &active_sons = gpo.active_sons.at(sidechain);
|
||||
fc::flat_map<std::string, uint16_t> account_auths;
|
||||
uint32_t total_weight = 0;
|
||||
for (const auto &active_son : active_sons) {
|
||||
total_weight = total_weight + active_son.weight;
|
||||
account_auths[active_son.sidechain_public_keys.at(sidechain)] = active_son.weight;
|
||||
account_auths[active_son.public_key] = active_son.weight;
|
||||
}
|
||||
|
||||
std::string memo_key = node_rpc_client->get_account_memo_key("son-account");
|
||||
|
|
@ -530,7 +530,7 @@ void sidechain_net_handler_hive::process_primary_wallet() {
|
|||
}
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
|
||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
||||
|
||||
|
|
@ -547,11 +547,11 @@ void sidechain_net_handler_hive::process_primary_wallet() {
|
|||
stc_op.object_id = active_sw->id;
|
||||
stc_op.sidechain = sidechain;
|
||||
stc_op.transaction = tx_str;
|
||||
stc_op.signers = gpo.active_sons;
|
||||
stc_op.signers = gpo.active_sons.at(sidechain);
|
||||
|
||||
proposal_op.proposed_ops.emplace_back(stc_op);
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
|
||||
try {
|
||||
trx.validate();
|
||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
|
|
@ -575,7 +575,7 @@ void sidechain_net_handler_hive::process_sidechain_addresses() {
|
|||
if (sao.expires == time_point_sec::maximum()) {
|
||||
if (sao.deposit_address == "") {
|
||||
sidechain_address_update_operation op;
|
||||
op.payer = plugin.get_current_son_object().son_account;
|
||||
op.payer = plugin.get_current_son_object(sidechain).son_account;
|
||||
op.sidechain_address_id = sao.id;
|
||||
op.sidechain_address_account = sao.sidechain_address_account;
|
||||
op.sidechain = sao.sidechain;
|
||||
|
|
@ -585,7 +585,7 @@ void sidechain_net_handler_hive::process_sidechain_addresses() {
|
|||
op.withdraw_public_key = sao.withdraw_public_key;
|
||||
op.withdraw_address = sao.withdraw_address;
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op);
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), op);
|
||||
try {
|
||||
trx.validate();
|
||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
|
|
@ -617,7 +617,7 @@ bool sidechain_net_handler_hive::process_deposit(const son_wallet_deposit_object
|
|||
}
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
|
||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
||||
|
||||
|
|
@ -633,7 +633,7 @@ bool sidechain_net_handler_hive::process_deposit(const son_wallet_deposit_object
|
|||
ai_op.issue_to_account = swdo.peerplays_from;
|
||||
proposal_op.proposed_ops.emplace_back(ai_op);
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
|
||||
try {
|
||||
trx.validate();
|
||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
|
|
@ -690,7 +690,7 @@ bool sidechain_net_handler_hive::process_withdrawal(const son_wallet_withdraw_ob
|
|||
//=====
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
|
||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
||||
|
||||
|
|
@ -704,10 +704,10 @@ bool sidechain_net_handler_hive::process_withdrawal(const son_wallet_withdraw_ob
|
|||
stc_op.object_id = swwo.id;
|
||||
stc_op.sidechain = sidechain;
|
||||
stc_op.transaction = tx_str;
|
||||
stc_op.signers = gpo.active_sons;
|
||||
stc_op.signers = gpo.active_sons.at(sidechain);
|
||||
proposal_op.proposed_ops.emplace_back(stc_op);
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
|
||||
try {
|
||||
trx.validate();
|
||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
|
|
@ -730,7 +730,7 @@ std::string sidechain_net_handler_hive::process_sidechain_transaction(const side
|
|||
std::string chain_id_str = node_rpc_client->get_chain_id();
|
||||
const hive::chain_id_type chain_id(chain_id_str);
|
||||
|
||||
fc::optional<fc::ecc::private_key> privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain)));
|
||||
fc::optional<fc::ecc::private_key> privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object(sidechain).sidechain_public_keys.at(sidechain)));
|
||||
signature_type st = htrx.sign(*privkey, chain_id);
|
||||
|
||||
std::stringstream ss_st;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ sidechain_net_handler_peerplays::~sidechain_net_handler_peerplays() {
|
|||
|
||||
bool sidechain_net_handler_peerplays::process_proposal(const proposal_object &po) {
|
||||
|
||||
ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id()));
|
||||
ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id(sidechain)));
|
||||
|
||||
bool should_approve = false;
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ void sidechain_net_handler_peerplays::process_sidechain_addresses() {
|
|||
if (sao.expires == time_point_sec::maximum()) {
|
||||
if (sao.deposit_address == "") {
|
||||
sidechain_address_update_operation op;
|
||||
op.payer = plugin.get_current_son_object().son_account;
|
||||
op.payer = plugin.get_current_son_object(sidechain).son_account;
|
||||
op.sidechain_address_id = sao.id;
|
||||
op.sidechain_address_account = sao.sidechain_address_account;
|
||||
op.sidechain = sao.sidechain;
|
||||
|
|
@ -150,7 +150,7 @@ void sidechain_net_handler_peerplays::process_sidechain_addresses() {
|
|||
op.withdraw_public_key = sao.withdraw_public_key;
|
||||
op.withdraw_address = sao.withdraw_address;
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op);
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), op);
|
||||
try {
|
||||
trx.validate();
|
||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
|
|
@ -197,15 +197,15 @@ bool sidechain_net_handler_peerplays::process_deposit(const son_wallet_deposit_o
|
|||
stc_op.object_id = swdo.id;
|
||||
stc_op.sidechain = sidechain;
|
||||
stc_op.transaction = tx_str;
|
||||
stc_op.signers = gpo.active_sons;
|
||||
stc_op.signers = gpo.active_sons.at(sidechain);
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
|
||||
proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account;
|
||||
proposal_op.proposed_ops.emplace_back(stc_op);
|
||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op);
|
||||
try {
|
||||
trx.validate();
|
||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
|
|
@ -230,7 +230,7 @@ std::string sidechain_net_handler_peerplays::process_sidechain_transaction(const
|
|||
signed_transaction trx;
|
||||
fc::raw::unpack(ss_trx, trx, 1000);
|
||||
|
||||
fc::optional<fc::ecc::private_key> privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain)));
|
||||
fc::optional<fc::ecc::private_key> privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object(sidechain).sidechain_public_keys.at(sidechain)));
|
||||
signature_type st = trx.sign(*privkey, database.get_chain_id());
|
||||
|
||||
std::stringstream ss_st;
|
||||
|
|
|
|||
|
|
@ -1,112 +0,0 @@
|
|||
#include <graphene/peerplays_sidechain/sidechain_net_manager.hpp>
|
||||
|
||||
#include <fc/log/logger.hpp>
|
||||
#include <graphene/chain/son_wallet_object.hpp>
|
||||
#include <graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp>
|
||||
#include <graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp>
|
||||
#include <graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp>
|
||||
|
||||
namespace graphene { namespace peerplays_sidechain {
|
||||
|
||||
sidechain_net_manager::sidechain_net_manager(peerplays_sidechain_plugin &_plugin) :
|
||||
plugin(_plugin),
|
||||
database(_plugin.database()) {
|
||||
|
||||
//database.applied_block.connect([&](const signed_block &b) {
|
||||
// on_applied_block(b);
|
||||
//});
|
||||
}
|
||||
|
||||
sidechain_net_manager::~sidechain_net_manager() {
|
||||
}
|
||||
|
||||
bool sidechain_net_manager::create_handler(sidechain_type sidechain, const boost::program_options::variables_map &options) {
|
||||
|
||||
bool ret_val = false;
|
||||
|
||||
switch (sidechain) {
|
||||
case sidechain_type::bitcoin: {
|
||||
std::unique_ptr<sidechain_net_handler> h = std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_bitcoin(plugin, options));
|
||||
net_handlers.push_back(std::move(h));
|
||||
ret_val = true;
|
||||
break;
|
||||
}
|
||||
case sidechain_type::hive: {
|
||||
std::unique_ptr<sidechain_net_handler> h = std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_hive(plugin, options));
|
||||
net_handlers.push_back(std::move(h));
|
||||
ret_val = true;
|
||||
break;
|
||||
}
|
||||
case sidechain_type::peerplays: {
|
||||
std::unique_ptr<sidechain_net_handler> h = std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_peerplays(plugin, options));
|
||||
net_handlers.push_back(std::move(h));
|
||||
ret_val = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
void sidechain_net_manager::process_proposals() {
|
||||
for (size_t i = 0; i < net_handlers.size(); i++) {
|
||||
net_handlers.at(i)->process_proposals();
|
||||
}
|
||||
}
|
||||
|
||||
void sidechain_net_manager::process_active_sons_change() {
|
||||
for (size_t i = 0; i < net_handlers.size(); i++) {
|
||||
net_handlers.at(i)->process_active_sons_change();
|
||||
}
|
||||
}
|
||||
|
||||
void sidechain_net_manager::create_deposit_addresses() {
|
||||
for (size_t i = 0; i < net_handlers.size(); i++) {
|
||||
net_handlers.at(i)->create_deposit_addresses();
|
||||
}
|
||||
}
|
||||
|
||||
void sidechain_net_manager::process_deposits() {
|
||||
for (size_t i = 0; i < net_handlers.size(); i++) {
|
||||
net_handlers.at(i)->process_deposits();
|
||||
}
|
||||
}
|
||||
|
||||
void sidechain_net_manager::process_withdrawals() {
|
||||
for (size_t i = 0; i < net_handlers.size(); i++) {
|
||||
net_handlers.at(i)->process_withdrawals();
|
||||
}
|
||||
}
|
||||
|
||||
void sidechain_net_manager::process_sidechain_transactions() {
|
||||
for (size_t i = 0; i < net_handlers.size(); i++) {
|
||||
net_handlers.at(i)->process_sidechain_transactions();
|
||||
}
|
||||
}
|
||||
|
||||
void sidechain_net_manager::send_sidechain_transactions() {
|
||||
for (size_t i = 0; i < net_handlers.size(); i++) {
|
||||
net_handlers.at(i)->send_sidechain_transactions();
|
||||
}
|
||||
}
|
||||
|
||||
void sidechain_net_manager::settle_sidechain_transactions() {
|
||||
for (size_t i = 0; i < net_handlers.size(); i++) {
|
||||
net_handlers.at(i)->settle_sidechain_transactions();
|
||||
}
|
||||
}
|
||||
|
||||
std::map<sidechain_type, std::vector<std::string>> sidechain_net_manager::get_son_listener_log() {
|
||||
std::map<sidechain_type, std::vector<std::string>> result;
|
||||
for (size_t i = 0; i < net_handlers.size(); i++) {
|
||||
result[net_handlers.at(i)->get_sidechain()] = net_handlers.at(i)->get_son_listener_log();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void sidechain_net_manager::on_applied_block(const signed_block &b) {
|
||||
}
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
@ -1610,6 +1610,7 @@ class wallet_api
|
|||
*
|
||||
* @param voting_account the name or id of the account who is voting with their shares
|
||||
* @param son the name or id of the SONs' owner account
|
||||
* @param sidechain the name of the sidechain
|
||||
* @param approve true if you wish to vote in favor of that SON, false to
|
||||
* remove your vote in favor of that SON
|
||||
* @param broadcast true if you wish to broadcast the transaction
|
||||
|
|
@ -1617,6 +1618,7 @@ class wallet_api
|
|||
*/
|
||||
signed_transaction vote_for_son(string voting_account,
|
||||
string son,
|
||||
sidechain_type sidechain,
|
||||
bool approve,
|
||||
bool broadcast = false);
|
||||
|
||||
|
|
@ -1640,6 +1642,8 @@ class wallet_api
|
|||
* @param sons_to_reject the names or ids of the SONs owner accounts you wish
|
||||
* to reject (these will be removed from the list of SONs
|
||||
* you currently approve). This list can be empty.
|
||||
* @param sidechain the name of the sidechain
|
||||
*
|
||||
* @param desired_number_of_sons the number of SONs you believe the network
|
||||
* should have. You must vote for at least this many
|
||||
* SONs. You can set this to 0 to abstain from
|
||||
|
|
@ -1650,6 +1654,7 @@ class wallet_api
|
|||
signed_transaction update_son_votes(string voting_account,
|
||||
std::vector<std::string> sons_to_approve,
|
||||
std::vector<std::string> sons_to_reject,
|
||||
sidechain_type sidechain,
|
||||
uint16_t desired_number_of_sons,
|
||||
bool broadcast = false);
|
||||
|
||||
|
|
|
|||
|
|
@ -2230,69 +2230,99 @@ public:
|
|||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (owner_account) ) }
|
||||
|
||||
//! Fixme - do we need to specify sidechain_type as params here?
|
||||
map<string, son_id_type> list_active_sons()
|
||||
{ try {
|
||||
global_property_object gpo = get_global_properties();
|
||||
vector<son_id_type> son_ids;
|
||||
son_ids.reserve(gpo.active_sons.size());
|
||||
std::transform(gpo.active_sons.begin(), gpo.active_sons.end(),
|
||||
std::inserter(son_ids, son_ids.end()),
|
||||
[](const son_info& swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
std::vector<fc::optional<son_object>> son_objects = _remote_db->get_sons(son_ids);
|
||||
vector<std::string> owners;
|
||||
for(auto obj: son_objects)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string acc_id = account_id_to_string(obj->son_account);
|
||||
owners.push_back(acc_id);
|
||||
}
|
||||
vector< optional< account_object> > accs = _remote_db->get_accounts(owners);
|
||||
std::remove_if(son_objects.begin(), son_objects.end(),
|
||||
[](const fc::optional<son_object>& obj) -> bool { return obj.valid(); });
|
||||
map<string, son_id_type> result;
|
||||
std::transform(accs.begin(), accs.end(), son_objects.begin(),
|
||||
std::inserter(result, result.end()),
|
||||
[](fc::optional<account_object>& acct, fc::optional<son_object> son) {
|
||||
FC_ASSERT(acct, "Invalid active SONs list in global properties.");
|
||||
return std::make_pair<string, son_id_type>(string(acct->name), std::move(son->id));
|
||||
});
|
||||
return result;
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
map<son_id_type, string> get_son_network_status()
|
||||
{ try {
|
||||
global_property_object gpo = get_global_properties();
|
||||
vector<son_id_type> son_ids;
|
||||
son_ids.reserve(gpo.active_sons.size());
|
||||
std::transform(gpo.active_sons.begin(), gpo.active_sons.end(),
|
||||
std::inserter(son_ids, son_ids.end()),
|
||||
[](const son_info& swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
|
||||
map<son_id_type, string> result;
|
||||
std::vector<fc::optional<son_object>> son_objects = _remote_db->get_sons(son_ids);
|
||||
for(auto son_obj: son_objects) {
|
||||
string status;
|
||||
if (son_obj) {
|
||||
son_statistics_object sso = get_object(son_obj->statistics);
|
||||
if (sso.last_active_timestamp + fc::seconds(gpo.parameters.son_heartbeat_frequency()) > time_point::now()) {
|
||||
status = "OK, regular SON heartbeat";
|
||||
} else {
|
||||
if (sso.last_active_timestamp + fc::seconds(gpo.parameters.son_down_time()) > time_point::now()) {
|
||||
status = "OK, irregular SON heartbeat, but not triggering SON down proposal";
|
||||
} else {
|
||||
status = "NOT OK, irregular SON heartbeat, triggering SON down proposal";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = "NOT OK, invalid SON id";
|
||||
const global_property_object& gpo = get_global_properties();
|
||||
set<son_id_type> son_ids_set;
|
||||
for(const auto& active_sidechain_type : active_sidechain_types)
|
||||
{
|
||||
std::transform(gpo.active_sons.at(active_sidechain_type).cbegin(), gpo.active_sons.at(active_sidechain_type).cend(),
|
||||
std::inserter(son_ids_set, son_ids_set.end()),
|
||||
[](const son_info &swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
}
|
||||
result[son_obj->id] = status;
|
||||
vector<son_id_type> son_ids;
|
||||
son_ids.reserve(son_ids_set.size());
|
||||
for(const auto& son_id : son_ids_set)
|
||||
{
|
||||
son_ids.emplace_back(son_id);
|
||||
}
|
||||
|
||||
std::vector<fc::optional<son_object>> son_objects = _remote_db->get_sons(son_ids);
|
||||
vector<std::string> owners;
|
||||
for(auto obj: son_objects)
|
||||
{
|
||||
std::string acc_id = account_id_to_string(obj->son_account);
|
||||
owners.push_back(acc_id);
|
||||
}
|
||||
vector< optional< account_object> > accs = _remote_db->get_accounts(owners);
|
||||
std::remove_if(son_objects.begin(), son_objects.end(),
|
||||
[](const fc::optional<son_object>& obj) -> bool { return obj.valid(); });
|
||||
map<string, son_id_type> result;
|
||||
std::transform(accs.begin(), accs.end(), son_objects.begin(),
|
||||
std::inserter(result, result.end()),
|
||||
[](fc::optional<account_object>& acct, fc::optional<son_object> son) {
|
||||
FC_ASSERT(acct, "Invalid active SONs list in global properties.");
|
||||
return std::make_pair<string, son_id_type>(string(acct->name), std::move(son->id));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
FC_CAPTURE_AND_RETHROW()
|
||||
}
|
||||
|
||||
//! Fixme - do we need to specify sidechain_type as params here?
|
||||
map<son_id_type, string> get_son_network_status()
|
||||
{
|
||||
try
|
||||
{
|
||||
const global_property_object& gpo = get_global_properties();
|
||||
|
||||
set<son_id_type> son_ids_set;
|
||||
for(const auto& active_sidechain_type : active_sidechain_types) {
|
||||
std::transform(gpo.active_sons.at(active_sidechain_type).cbegin(), gpo.active_sons.at(active_sidechain_type).cend(),
|
||||
std::inserter(son_ids_set, son_ids_set.end()),
|
||||
[](const son_info &swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
}
|
||||
vector<son_id_type> son_ids;
|
||||
son_ids.reserve(son_ids_set.size());
|
||||
std::transform(son_ids_set.cbegin(), son_ids_set.cend(),
|
||||
std::inserter(son_ids, son_ids.end()),
|
||||
[](const son_id_type& sit) {
|
||||
return sit;
|
||||
});
|
||||
|
||||
map<son_id_type, string> result;
|
||||
std::vector<fc::optional<son_object>> son_objects = _remote_db->get_sons(son_ids);
|
||||
for(auto son_obj: son_objects) {
|
||||
string status;
|
||||
if (son_obj) {
|
||||
son_statistics_object sso = get_object(son_obj->statistics);
|
||||
for(const auto& active_sidechain_type : active_sidechain_types) {
|
||||
if (sso.last_active_timestamp.at(active_sidechain_type) + fc::seconds(gpo.parameters.son_heartbeat_frequency()) > time_point::now()) {
|
||||
status = "[OK, regular SON heartbeat for sidechain " + std::to_string(static_cast<unsigned int>(active_sidechain_type)) + "] ";
|
||||
} else {
|
||||
if (sso.last_active_timestamp.at(active_sidechain_type) + fc::seconds(gpo.parameters.son_down_time()) > time_point::now()) {
|
||||
status = "[OK, irregular SON heartbeat, but not triggering SON down proposal for sidechain " + std::to_string(static_cast<unsigned int>(active_sidechain_type)) + "] ";
|
||||
} else {
|
||||
status = "[NOT OK, irregular SON heartbeat, triggering SON down proposal for sidechain " + std::to_string(static_cast<unsigned int>(active_sidechain_type)) + "] ";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = "NOT OK, invalid SON id";
|
||||
}
|
||||
result[son_obj->id] = status;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW()
|
||||
}
|
||||
|
||||
optional<son_wallet_object> get_active_son_wallet()
|
||||
{ try {
|
||||
|
|
@ -2800,6 +2830,7 @@ public:
|
|||
|
||||
signed_transaction vote_for_son(string voting_account,
|
||||
string son,
|
||||
sidechain_type sidechain,
|
||||
bool approve,
|
||||
bool broadcast /* = false */)
|
||||
{ try {
|
||||
|
|
@ -2813,19 +2844,20 @@ public:
|
|||
account_object voting_account_object = get_account(voting_account);
|
||||
account_id_type son_account_id = get_account_id(son);
|
||||
fc::optional<son_object> son_obj = _remote_db->get_son_by_account_id(son_account_id);
|
||||
if (!son_obj)
|
||||
FC_THROW("Account ${son} is not registered as a son", ("son", son));
|
||||
FC_ASSERT(son_obj, "Account ${son} is not registered as a son", ("son", son));
|
||||
FC_ASSERT(sidechain == sidechain_type::bitcoin || sidechain == sidechain_type::hive, "Unexpected sidechain type");
|
||||
|
||||
if (approve)
|
||||
{
|
||||
auto insert_result = voting_account_object.options.votes.insert(son_obj->vote_id);
|
||||
auto insert_result = voting_account_object.options.votes.insert(son_obj->get_sidechain_vote_id(sidechain));
|
||||
if (!insert_result.second)
|
||||
FC_THROW("Account ${account} was already voting for son ${son}", ("account", voting_account)("son", son));
|
||||
FC_THROW("Account ${account} has already voted for son ${son} for sidechain ${sidechain}", ("account", voting_account)("son", son)("sidechain", sidechain));
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->vote_id);
|
||||
unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->get_sidechain_vote_id(sidechain));
|
||||
if (!votes_removed)
|
||||
FC_THROW("Account ${account} is already not voting for son ${son}", ("account", voting_account)("son", son));
|
||||
FC_THROW("Account ${account} has already unvoted for son ${son} for sidechain ${sidechain}", ("account", voting_account)("son", son)("sidechain", sidechain));
|
||||
}
|
||||
account_update_operation account_update_op;
|
||||
account_update_op.account = voting_account_object.id;
|
||||
|
|
@ -2842,6 +2874,7 @@ public:
|
|||
signed_transaction update_son_votes(string voting_account,
|
||||
std::vector<std::string> sons_to_approve,
|
||||
std::vector<std::string> sons_to_reject,
|
||||
sidechain_type sidechain,
|
||||
uint16_t desired_number_of_sons,
|
||||
bool broadcast /* = false */)
|
||||
{ try {
|
||||
|
|
@ -2857,9 +2890,10 @@ public:
|
|||
{
|
||||
account_id_type son_owner_account_id = get_account_id(son);
|
||||
fc::optional<son_object> son_obj = _remote_db->get_son_by_account_id(son_owner_account_id);
|
||||
if (!son_obj)
|
||||
FC_THROW("Account ${son} is not registered as a SON", ("son", son));
|
||||
auto insert_result = voting_account_object.options.votes.insert(son_obj->vote_id);
|
||||
FC_ASSERT(son_obj, "Account ${son} is not registered as a son", ("son", son));
|
||||
FC_ASSERT(sidechain == sidechain_type::bitcoin || sidechain == sidechain_type::hive, "Unexpected sidechain type");
|
||||
|
||||
auto insert_result = voting_account_object.options.votes.insert(son_obj->get_sidechain_vote_id(sidechain));
|
||||
if (!insert_result.second)
|
||||
FC_THROW("Account ${account} was already voting for SON ${son}", ("account", voting_account)("son", son));
|
||||
}
|
||||
|
|
@ -2867,13 +2901,15 @@ public:
|
|||
{
|
||||
account_id_type son_owner_account_id = get_account_id(son);
|
||||
fc::optional<son_object> son_obj = _remote_db->get_son_by_account_id(son_owner_account_id);
|
||||
if (!son_obj)
|
||||
FC_THROW("Account ${son} is not registered as a SON", ("son", son));
|
||||
unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->vote_id);
|
||||
FC_ASSERT(son_obj, "Account ${son} is not registered as a son", ("son", son));
|
||||
FC_ASSERT(sidechain == sidechain_type::bitcoin || sidechain == sidechain_type::hive, "Unexpected sidechain type");
|
||||
|
||||
unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->get_sidechain_vote_id(sidechain));
|
||||
if (!votes_removed)
|
||||
FC_THROW("Account ${account} is already not voting for SON ${son}", ("account", voting_account)("son", son));
|
||||
}
|
||||
voting_account_object.options.extensions.value.num_son = desired_number_of_sons;
|
||||
FC_ASSERT( voting_account_object.options.extensions.value.num_son.valid() , "Invalid son number" );
|
||||
(*voting_account_object.options.extensions.value.num_son)[sidechain] = desired_number_of_sons;
|
||||
|
||||
account_update_operation account_update_op;
|
||||
account_update_op.account = voting_account_object.id;
|
||||
|
|
@ -5428,19 +5464,21 @@ signed_transaction wallet_api::vote_for_committee_member(string voting_account,
|
|||
|
||||
signed_transaction wallet_api::vote_for_son(string voting_account,
|
||||
string son,
|
||||
sidechain_type sidechain,
|
||||
bool approve,
|
||||
bool broadcast /* = false */)
|
||||
{
|
||||
return my->vote_for_son(voting_account, son, approve, broadcast);
|
||||
return my->vote_for_son(voting_account, son, sidechain, approve, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::update_son_votes(string voting_account,
|
||||
std::vector<std::string> sons_to_approve,
|
||||
std::vector<std::string> sons_to_reject,
|
||||
sidechain_type sidechain,
|
||||
uint16_t desired_number_of_sons,
|
||||
bool broadcast /* = false */)
|
||||
{
|
||||
return my->update_son_votes(voting_account, sons_to_approve, sons_to_reject, desired_number_of_sons, broadcast);
|
||||
return my->update_son_votes(voting_account, sons_to_approve, sons_to_reject, sidechain, desired_number_of_sons, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::sidechain_deposit_transaction( const string &son_name_or_id,
|
||||
|
|
|
|||
|
|
@ -138,10 +138,18 @@ BOOST_AUTO_TEST_CASE( create_sons )
|
|||
auto son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
BOOST_CHECK(son1_obj.son_account == con.wallet_api_ptr->get_account_id("son1account"));
|
||||
BOOST_CHECK_EQUAL(son1_obj.url, "http://son1");
|
||||
BOOST_CHECK_EQUAL(son1_obj.sidechain_public_keys[sidechain_type::bitcoin], "bitcoin_address 1");
|
||||
BOOST_CHECK_EQUAL(son1_obj.sidechain_public_keys[sidechain_type::hive], "hive account 1");
|
||||
BOOST_CHECK_EQUAL(son1_obj.get_sidechain_vote_id(sidechain_type::bitcoin).instance(), 22);
|
||||
BOOST_CHECK_EQUAL(son1_obj.get_sidechain_vote_id(sidechain_type::hive).instance(), 23);
|
||||
|
||||
auto son2_obj = con.wallet_api_ptr->get_son("son2account");
|
||||
BOOST_CHECK(son2_obj.son_account == con.wallet_api_ptr->get_account_id("son2account"));
|
||||
BOOST_CHECK_EQUAL(son2_obj.url, "http://son2");
|
||||
BOOST_CHECK_EQUAL(son2_obj.sidechain_public_keys[sidechain_type::bitcoin], "bitcoin_address 2");
|
||||
BOOST_CHECK_EQUAL(son2_obj.sidechain_public_keys[sidechain_type::hive], "hive account 2");
|
||||
BOOST_CHECK_EQUAL(son2_obj.get_sidechain_vote_id(sidechain_type::bitcoin).instance(), 24);
|
||||
BOOST_CHECK_EQUAL(son2_obj.get_sidechain_vote_id(sidechain_type::hive).instance(), 25);
|
||||
|
||||
} catch( fc::exception& e ) {
|
||||
BOOST_TEST_MESSAGE("SON cli wallet tests exception");
|
||||
|
|
@ -172,6 +180,10 @@ BOOST_AUTO_TEST_CASE( cli_update_son )
|
|||
auto son_data = con.wallet_api_ptr->get_son("sonmember");
|
||||
BOOST_CHECK(son_data.url == "http://sonmember");
|
||||
BOOST_CHECK(son_data.son_account == sonmember_acct.get_id());
|
||||
BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::bitcoin], "bitcoin_address 1");
|
||||
BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::hive], "hive account 1");
|
||||
BOOST_CHECK_EQUAL(son_data.get_sidechain_vote_id(sidechain_type::bitcoin).instance(), 22);
|
||||
BOOST_CHECK_EQUAL(son_data.get_sidechain_vote_id(sidechain_type::hive).instance(), 23);
|
||||
|
||||
// update SON
|
||||
sidechain_public_keys.clear();
|
||||
|
|
@ -181,6 +193,8 @@ BOOST_AUTO_TEST_CASE( cli_update_son )
|
|||
con.wallet_api_ptr->update_son("sonmember", "http://sonmember_updated", "", sidechain_public_keys, true);
|
||||
son_data = con.wallet_api_ptr->get_son("sonmember");
|
||||
BOOST_CHECK(son_data.url == "http://sonmember_updated");
|
||||
BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::bitcoin], "bitcoin_address 2");
|
||||
BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::hive], "hive account 2");
|
||||
|
||||
// update SON signing key
|
||||
sidechain_public_keys.clear();
|
||||
|
|
@ -221,8 +235,11 @@ BOOST_AUTO_TEST_CASE( son_voting )
|
|||
son_object son2_obj;
|
||||
signed_transaction vote_son1_tx;
|
||||
signed_transaction vote_son2_tx;
|
||||
uint64_t son1_start_votes, son1_end_votes;
|
||||
uint64_t son2_start_votes, son2_end_votes;
|
||||
flat_map<sidechain_type, uint64_t> son1_start_votes, son1_end_votes;
|
||||
flat_map<sidechain_type, uint64_t> son2_start_votes, son2_end_votes;
|
||||
|
||||
//! Get nathan account
|
||||
const auto nathan_account_object = con.wallet_api_ptr->get_account("nathan");
|
||||
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
son1_start_votes = son1_obj.total_votes;
|
||||
|
|
@ -232,85 +249,101 @@ BOOST_AUTO_TEST_CASE( son_voting )
|
|||
con.wallet_api_ptr->create_vesting_balance("nathan", "1000", "1.3.0", vesting_balance_type::gpos, true);
|
||||
// Vote for a son1account
|
||||
BOOST_TEST_MESSAGE("Voting for son1account");
|
||||
vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", true, true);
|
||||
vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::bitcoin, true, true);
|
||||
vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::hive, true, true);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Verify that the vote is there
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
son1_end_votes = son1_obj.total_votes;
|
||||
BOOST_CHECK(son1_end_votes > son1_start_votes);
|
||||
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] > son1_start_votes[sidechain_type::bitcoin]);
|
||||
BOOST_CHECK(son1_end_votes[sidechain_type::hive] > son1_start_votes[sidechain_type::hive]);
|
||||
|
||||
// Vote for a son2account
|
||||
BOOST_TEST_MESSAGE("Voting for son2account");
|
||||
vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", true, true);
|
||||
vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::bitcoin, true, true);
|
||||
vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::hive, true, true);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Verify that the vote is there
|
||||
son2_obj = con.wallet_api_ptr->get_son("son2account");
|
||||
son2_end_votes = son2_obj.total_votes;
|
||||
BOOST_CHECK(son2_end_votes > son2_start_votes);
|
||||
|
||||
//! Get nathan account
|
||||
const auto nathan_account_object = con.wallet_api_ptr->get_account("nathan");
|
||||
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] > son2_start_votes[sidechain_type::bitcoin]);
|
||||
BOOST_CHECK(son2_end_votes[sidechain_type::hive] > son2_start_votes[sidechain_type::hive]);
|
||||
|
||||
//! Check son1account voters
|
||||
auto voters_for_son1account = con.wallet_api_ptr->get_voters("son1account");
|
||||
BOOST_REQUIRE(voters_for_son1account.voters_for_son);
|
||||
BOOST_CHECK_EQUAL(voters_for_son1account.voters_for_son->voters.size(), 1);
|
||||
BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account.voters_for_son->voters[0].instance, nathan_account_object.id.instance());
|
||||
auto voters_for_son1account = con.wallet_api_ptr->get_voters("son1account").voters_for_son;
|
||||
BOOST_REQUIRE(voters_for_son1account);
|
||||
BOOST_REQUIRE_EQUAL(voters_for_son1account->at(sidechain_type::bitcoin).voters.size(), 1);
|
||||
BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::bitcoin).voters[0].instance, nathan_account_object.id.instance());
|
||||
BOOST_REQUIRE_EQUAL(voters_for_son1account->at(sidechain_type::hive).voters.size(), 1);
|
||||
BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::hive).voters[0].instance, nathan_account_object.id.instance());
|
||||
|
||||
//! Check son2account voters
|
||||
auto voters_for_son2account = con.wallet_api_ptr->get_voters("son2account");
|
||||
BOOST_REQUIRE(voters_for_son2account.voters_for_son);
|
||||
BOOST_CHECK_EQUAL(voters_for_son2account.voters_for_son->voters.size(), 1);
|
||||
BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account.voters_for_son->voters[0].instance, nathan_account_object.id.instance());
|
||||
auto voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son;
|
||||
BOOST_REQUIRE(voters_for_son2account);
|
||||
BOOST_REQUIRE_EQUAL(voters_for_son2account->at(sidechain_type::bitcoin).voters.size(), 1);
|
||||
BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::bitcoin).voters[0].instance, nathan_account_object.id.instance());
|
||||
BOOST_REQUIRE_EQUAL(voters_for_son2account->at(sidechain_type::hive).voters.size(), 1);
|
||||
BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::hive).voters[0].instance, nathan_account_object.id.instance());
|
||||
|
||||
//! Check votes of nathan
|
||||
auto nathan_votes = con.wallet_api_ptr->get_votes("nathan");
|
||||
BOOST_REQUIRE(nathan_votes.votes_for_sons);
|
||||
BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons->size(), 2);
|
||||
BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons->at(0).id.instance(), son1_obj.id.instance());
|
||||
BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons->at(1).id.instance(), son2_obj.id.instance());
|
||||
auto nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
|
||||
BOOST_REQUIRE(nathan_votes_for_son);
|
||||
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).size(), 2);
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(0).id.instance(), son1_obj.id.instance());
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(1).id.instance(), son2_obj.id.instance());
|
||||
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 2);
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son1_obj.id.instance());
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(1).id.instance(), son2_obj.id.instance());
|
||||
|
||||
// Withdraw vote for a son1account
|
||||
BOOST_TEST_MESSAGE("Withdraw vote for a son1account");
|
||||
vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", false, true);
|
||||
vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::bitcoin, false, true);
|
||||
vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::hive, false, true);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Verify that the vote is removed
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
son1_end_votes = son1_obj.total_votes;
|
||||
BOOST_CHECK(son1_end_votes == son1_start_votes);
|
||||
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]);
|
||||
BOOST_CHECK(son1_end_votes[sidechain_type::hive] == son1_start_votes[sidechain_type::hive]);
|
||||
|
||||
//! Check son1account voters
|
||||
voters_for_son1account = con.wallet_api_ptr->get_voters("son1account");
|
||||
BOOST_REQUIRE(voters_for_son1account.voters_for_son);
|
||||
BOOST_CHECK_EQUAL(voters_for_son1account.voters_for_son->voters.size(), 0);
|
||||
voters_for_son1account = con.wallet_api_ptr->get_voters("son1account").voters_for_son;
|
||||
BOOST_REQUIRE(voters_for_son1account);
|
||||
BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::bitcoin).voters.size(), 0);
|
||||
BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::hive).voters.size(), 0);
|
||||
|
||||
//! Check votes of nathan
|
||||
nathan_votes = con.wallet_api_ptr->get_votes("nathan");
|
||||
BOOST_REQUIRE(nathan_votes.votes_for_sons);
|
||||
BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons->size(), 1);
|
||||
BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons->at(0).id.instance(), son2_obj.id.instance());
|
||||
nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
|
||||
BOOST_REQUIRE(nathan_votes_for_son);
|
||||
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).size(), 1);
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(0).id.instance(), son2_obj.id.instance());
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 1);
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son2_obj.id.instance());
|
||||
|
||||
// Withdraw vote for a son2account
|
||||
BOOST_TEST_MESSAGE("Withdraw vote for a son2account");
|
||||
vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", false, true);
|
||||
vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::bitcoin, false, true);
|
||||
vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::hive, false, true);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Verify that the vote is removed
|
||||
son2_obj = con.wallet_api_ptr->get_son("son2account");
|
||||
son2_end_votes = son2_obj.total_votes;
|
||||
BOOST_CHECK(son2_end_votes == son2_start_votes);
|
||||
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] == son2_start_votes[sidechain_type::bitcoin]);
|
||||
BOOST_CHECK(son2_end_votes[sidechain_type::hive] == son2_start_votes[sidechain_type::hive]);
|
||||
|
||||
//! Check son2account voters
|
||||
voters_for_son2account = con.wallet_api_ptr->get_voters("son2account");
|
||||
BOOST_REQUIRE(voters_for_son2account.voters_for_son);
|
||||
BOOST_CHECK_EQUAL(voters_for_son2account.voters_for_son->voters.size(), 0);
|
||||
voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son;
|
||||
BOOST_REQUIRE(voters_for_son2account);
|
||||
BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::bitcoin).voters.size(), 0);
|
||||
BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::hive).voters.size(), 0);
|
||||
|
||||
//! Check votes of nathan
|
||||
nathan_votes = con.wallet_api_ptr->get_votes("nathan");
|
||||
BOOST_CHECK(!nathan_votes.votes_for_sons.valid());
|
||||
nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
|
||||
BOOST_CHECK(!nathan_votes_for_son);
|
||||
|
||||
} catch( fc::exception& e ) {
|
||||
BOOST_TEST_MESSAGE("SON cli wallet tests exception");
|
||||
|
|
@ -363,7 +396,8 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture )
|
|||
con.wallet_api_ptr->create_vesting_balance("sonaccount" + fc::to_pretty_string(i), "500", "1.3.0", vesting_balance_type::gpos, true);
|
||||
|
||||
std::string name = "sonaccount" + fc::to_pretty_string(i);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name, name, true, true);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::bitcoin, true, true);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::hive, true, true);
|
||||
}
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
|
|
@ -371,37 +405,46 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture )
|
|||
{
|
||||
std::string name1 = "sonaccount" + fc::to_pretty_string(i);
|
||||
std::string name2 = "sonaccount" + fc::to_pretty_string(i + 1);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, true, true);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::bitcoin, true, true);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true);
|
||||
}
|
||||
gpo = con.wallet_api_ptr->get_global_properties();
|
||||
BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size());
|
||||
BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).size());
|
||||
BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size());
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
gpo = con.wallet_api_ptr->get_global_properties();
|
||||
BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size());
|
||||
BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).size());
|
||||
BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size());
|
||||
|
||||
for(unsigned int i = 0; i < son_number - 1; i++)
|
||||
{
|
||||
std::string name1 = "sonaccount" + fc::to_pretty_string(i + 2);
|
||||
std::string name2 = "sonaccount" + fc::to_pretty_string(i);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, true, true);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::bitcoin, true, true);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true);
|
||||
}
|
||||
gpo = con.wallet_api_ptr->get_global_properties();
|
||||
BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size());
|
||||
BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).size());
|
||||
BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size());
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
gpo = con.wallet_api_ptr->get_global_properties();
|
||||
BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size());
|
||||
BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).size());
|
||||
BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size());
|
||||
|
||||
for(unsigned int i = 0; i < son_number - 2; i++)
|
||||
{
|
||||
std::string name1 = "sonaccount" + fc::to_pretty_string(i + 3);
|
||||
std::string name2 = "sonaccount" + fc::to_pretty_string(i);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, true, true);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::bitcoin, true, true);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true);
|
||||
}
|
||||
gpo = con.wallet_api_ptr->get_global_properties();
|
||||
BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size());
|
||||
BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).size());
|
||||
BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size());
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
BOOST_CHECK(gpo.active_sons.size() == son_number);
|
||||
BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).size() == son_number);
|
||||
BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == son_number);
|
||||
|
||||
} catch( fc::exception& e ) {
|
||||
BOOST_TEST_MESSAGE("SON cli wallet tests exception");
|
||||
|
|
@ -466,8 +509,11 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
|
|||
|
||||
son_object son1_obj;
|
||||
son_object son2_obj;
|
||||
uint64_t son1_start_votes, son1_end_votes;
|
||||
uint64_t son2_start_votes, son2_end_votes;
|
||||
flat_map<sidechain_type, uint64_t> son1_start_votes, son1_end_votes;
|
||||
flat_map<sidechain_type, uint64_t> son2_start_votes, son2_end_votes;
|
||||
|
||||
//! Get nathan account
|
||||
const auto nathan_account_object = con.wallet_api_ptr->get_account("nathan");
|
||||
|
||||
// Get votes at start
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
|
|
@ -485,114 +531,189 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
|
|||
accepted.push_back("son1account");
|
||||
accepted.push_back("son2account");
|
||||
con.wallet_api_ptr->create_vesting_balance("nathan", "1000", "1.3.0", vesting_balance_type::gpos, true);
|
||||
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 2, true);
|
||||
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
|
||||
sidechain_type::bitcoin, 2, true);
|
||||
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
|
||||
sidechain_type::hive, 2, true);
|
||||
generate_block();
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Verify the votes
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
son1_end_votes = son1_obj.total_votes;
|
||||
BOOST_CHECK(son1_end_votes > son1_start_votes);
|
||||
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] > son1_start_votes[sidechain_type::bitcoin]);
|
||||
son1_start_votes = son1_end_votes;
|
||||
son2_obj = con.wallet_api_ptr->get_son("son2account");
|
||||
son2_end_votes = son2_obj.total_votes;
|
||||
BOOST_CHECK(son2_end_votes > son2_start_votes);
|
||||
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] > son2_start_votes[sidechain_type::bitcoin]);
|
||||
son2_start_votes = son2_end_votes;
|
||||
|
||||
//! Check son1account voters
|
||||
auto voters_for_son1account = con.wallet_api_ptr->get_voters("son1account").voters_for_son;
|
||||
BOOST_REQUIRE(voters_for_son1account);
|
||||
BOOST_REQUIRE_EQUAL(voters_for_son1account->at(sidechain_type::bitcoin).voters.size(), 1);
|
||||
BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::bitcoin).voters[0].instance, nathan_account_object.id.instance());
|
||||
BOOST_REQUIRE_EQUAL(voters_for_son1account->at(sidechain_type::hive).voters.size(), 1);
|
||||
BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::hive).voters[0].instance, nathan_account_object.id.instance());
|
||||
|
||||
//! Check son2account voters
|
||||
auto voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son;
|
||||
BOOST_REQUIRE(voters_for_son2account);
|
||||
BOOST_REQUIRE_EQUAL(voters_for_son2account->at(sidechain_type::bitcoin).voters.size(), 1);
|
||||
BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::bitcoin).voters[0].instance, nathan_account_object.id.instance());
|
||||
BOOST_REQUIRE_EQUAL(voters_for_son2account->at(sidechain_type::hive).voters.size(), 1);
|
||||
BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::hive).voters[0].instance, nathan_account_object.id.instance());
|
||||
|
||||
//! Check votes of nathan
|
||||
auto nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
|
||||
BOOST_REQUIRE(nathan_votes_for_son);
|
||||
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).size(), 2);
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(0).id.instance(), son1_obj.id.instance());
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(1).id.instance(), son2_obj.id.instance());
|
||||
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 2);
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son1_obj.id.instance());
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(1).id.instance(), son2_obj.id.instance());
|
||||
|
||||
// Withdraw vote for SON 1
|
||||
accepted.clear();
|
||||
rejected.clear();
|
||||
rejected.push_back("son1account");
|
||||
con.wallet_api_ptr->create_vesting_balance("nathan", "1000", "1.3.0", vesting_balance_type::gpos, true);
|
||||
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 1, true);
|
||||
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
|
||||
sidechain_type::bitcoin, 1, true);
|
||||
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
|
||||
sidechain_type::hive, 1, true);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Verify the votes
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
son1_end_votes = son1_obj.total_votes;
|
||||
BOOST_CHECK(son1_end_votes < son1_start_votes);
|
||||
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] < son1_start_votes[sidechain_type::bitcoin]);
|
||||
son1_start_votes = son1_end_votes;
|
||||
son2_obj = con.wallet_api_ptr->get_son("son2account");
|
||||
// voice distribution changed, SON2 now has all voices
|
||||
son2_end_votes = son2_obj.total_votes;
|
||||
BOOST_CHECK((son2_end_votes > son2_start_votes)); // nathan spent funds for vb, it has different voting power
|
||||
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] > son2_start_votes[sidechain_type::bitcoin]); // nathan spent funds for vb, it has different voting power
|
||||
son2_start_votes = son2_end_votes;
|
||||
|
||||
//! Check son1account voters
|
||||
voters_for_son1account = con.wallet_api_ptr->get_voters("son1account").voters_for_son;
|
||||
BOOST_REQUIRE(voters_for_son1account);
|
||||
BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::bitcoin).voters.size(), 0);
|
||||
BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::hive).voters.size(), 0);
|
||||
|
||||
//! Check votes of nathan
|
||||
nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
|
||||
BOOST_REQUIRE(nathan_votes_for_son);
|
||||
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).size(), 1);
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(0).id.instance(), son2_obj.id.instance());
|
||||
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 1);
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son2_obj.id.instance());
|
||||
|
||||
// Try to reject incorrect SON
|
||||
accepted.clear();
|
||||
rejected.clear();
|
||||
rejected.push_back("son1accnt");
|
||||
BOOST_CHECK_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 1, true), fc::exception);
|
||||
BOOST_CHECK_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
|
||||
sidechain_type::bitcoin, 1, true), fc::exception);
|
||||
BOOST_CHECK_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
|
||||
sidechain_type::hive, 1, true), fc::exception);
|
||||
generate_block();
|
||||
|
||||
// Verify the votes
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
son1_end_votes = son1_obj.total_votes;
|
||||
BOOST_CHECK(son1_end_votes == son1_start_votes);
|
||||
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]);
|
||||
son1_start_votes = son1_end_votes;
|
||||
son2_obj = con.wallet_api_ptr->get_son("son2account");
|
||||
son2_end_votes = son2_obj.total_votes;
|
||||
BOOST_CHECK(son2_end_votes == son2_start_votes);
|
||||
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] == son2_start_votes[sidechain_type::bitcoin]);
|
||||
son2_start_votes = son2_end_votes;
|
||||
|
||||
//! Check votes of nathan
|
||||
nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
|
||||
BOOST_REQUIRE(nathan_votes_for_son);
|
||||
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).size(), 1);
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(0).id.instance(), son2_obj.id.instance());
|
||||
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 1);
|
||||
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son2_obj.id.instance());
|
||||
|
||||
// Reject SON2
|
||||
accepted.clear();
|
||||
rejected.clear();
|
||||
rejected.push_back("son2account");
|
||||
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 0, true);
|
||||
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
|
||||
sidechain_type::bitcoin, 0, true);
|
||||
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
|
||||
sidechain_type::hive, 0, true);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Verify the votes
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
son1_end_votes = son1_obj.total_votes;
|
||||
BOOST_CHECK(son1_end_votes == son1_start_votes);
|
||||
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]);
|
||||
son1_start_votes = son1_end_votes;
|
||||
son2_obj = con.wallet_api_ptr->get_son("son2account");
|
||||
son2_end_votes = son2_obj.total_votes;
|
||||
BOOST_CHECK(son2_end_votes < son2_start_votes);
|
||||
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] < son2_start_votes[sidechain_type::bitcoin]);
|
||||
son2_start_votes = son2_end_votes;
|
||||
|
||||
//! Check son2account voters
|
||||
voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son;
|
||||
BOOST_REQUIRE(voters_for_son2account);
|
||||
BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::bitcoin).voters.size(), 0);
|
||||
BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::hive).voters.size(), 0);
|
||||
|
||||
//! Check votes of nathan
|
||||
nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
|
||||
BOOST_REQUIRE(!nathan_votes_for_son);
|
||||
|
||||
// Try to accept and reject the same SON
|
||||
accepted.clear();
|
||||
rejected.clear();
|
||||
rejected.push_back("son1accnt");
|
||||
accepted.push_back("son1accnt");
|
||||
BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 1, true), fc::exception);
|
||||
BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
|
||||
sidechain_type::bitcoin, 1, true), fc::exception);
|
||||
BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
|
||||
sidechain_type::hive, 1, true), fc::exception);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Verify the votes
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
son1_end_votes = son1_obj.total_votes;
|
||||
BOOST_CHECK(son1_end_votes == son1_start_votes);
|
||||
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]);
|
||||
son1_start_votes = son1_end_votes;
|
||||
son2_obj = con.wallet_api_ptr->get_son("son2account");
|
||||
son2_end_votes = son2_obj.total_votes;
|
||||
BOOST_CHECK(son2_end_votes == son2_start_votes);
|
||||
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] == son2_start_votes[sidechain_type::bitcoin]);
|
||||
son2_start_votes = son2_end_votes;
|
||||
|
||||
//! Check votes of nathan
|
||||
nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
|
||||
BOOST_REQUIRE(!nathan_votes_for_son);
|
||||
|
||||
// Try to accept and reject empty lists
|
||||
accepted.clear();
|
||||
rejected.clear();
|
||||
BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 1, true), fc::exception);
|
||||
BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
|
||||
sidechain_type::bitcoin, 1, true), fc::exception);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Verify the votes
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
son1_end_votes = son1_obj.total_votes;
|
||||
BOOST_CHECK(son1_end_votes == son1_start_votes);
|
||||
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]);
|
||||
son1_start_votes = son1_end_votes;
|
||||
son2_obj = con.wallet_api_ptr->get_son("son2account");
|
||||
son2_end_votes = son2_obj.total_votes;
|
||||
BOOST_CHECK(son2_end_votes == son2_start_votes);
|
||||
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] == son2_start_votes[sidechain_type::bitcoin]);
|
||||
son2_start_votes = son2_end_votes;
|
||||
|
||||
//! Check votes of nathan
|
||||
nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
|
||||
BOOST_REQUIRE(!nathan_votes_for_son);
|
||||
|
||||
} catch( fc::exception& e ) {
|
||||
BOOST_TEST_MESSAGE("SON cli wallet tests exception");
|
||||
edump((e.to_detail_string()));
|
||||
|
|
@ -607,7 +728,8 @@ BOOST_AUTO_TEST_CASE( related_functions )
|
|||
try
|
||||
{
|
||||
global_property_object gpo = con.wallet_api_ptr->get_global_properties();
|
||||
BOOST_CHECK(gpo.active_sons.size() == 0);
|
||||
BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).size() == 0);
|
||||
BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == 0);
|
||||
|
||||
flat_map<sidechain_type, string> sidechain_public_keys;
|
||||
|
||||
|
|
@ -624,7 +746,8 @@ BOOST_AUTO_TEST_CASE( related_functions )
|
|||
sth.create_son("son2account", "http://son2", sidechain_public_keys);
|
||||
|
||||
gpo = con.wallet_api_ptr->get_global_properties();
|
||||
BOOST_CHECK(gpo.active_sons.size() == 2);
|
||||
BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).size() == 2);
|
||||
BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == 2);
|
||||
|
||||
} catch( fc::exception& e ) {
|
||||
BOOST_TEST_MESSAGE("SON cli wallet tests exception");
|
||||
|
|
@ -670,7 +793,8 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture )
|
|||
for(unsigned int i = 1; i < son_number + 1; i++)
|
||||
{
|
||||
std::string name = "sonaccount" + fc::to_pretty_string(i);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name, name, true, true);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::bitcoin, true, true);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::hive, true, true);
|
||||
}
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
|
|
@ -678,13 +802,16 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture )
|
|||
{
|
||||
std::string name1 = "sonaccount" + fc::to_pretty_string(i);
|
||||
std::string name2 = "sonaccount" + fc::to_pretty_string(i + 1);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, true, true);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::bitcoin, true, true);
|
||||
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true);
|
||||
}
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
gpo = con.wallet_api_ptr->get_global_properties();
|
||||
BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size());
|
||||
BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).size());
|
||||
BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size());
|
||||
|
||||
BOOST_CHECK(gpo.active_sons.size() == son_number);
|
||||
BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).size() == son_number);
|
||||
BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == son_number);
|
||||
|
||||
map<string, son_id_type> active_sons = con.wallet_api_ptr->list_active_sons();
|
||||
BOOST_CHECK(active_sons.size() == son_number);
|
||||
|
|
@ -737,12 +864,14 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
|
|||
con.wallet_api_ptr->transfer(
|
||||
"nathan", "sonaccount" + fc::to_pretty_string(i), "1000", "1.3.0", "Here are some CORE tokens for your new account", true );
|
||||
con.wallet_api_ptr->create_vesting_balance("sonaccount" + fc::to_pretty_string(i), "500", "1.3.0", vesting_balance_type::gpos, true);
|
||||
con.wallet_api_ptr->vote_for_son("sonaccount" + fc::to_pretty_string(i), name, true, true);
|
||||
con.wallet_api_ptr->vote_for_son("sonaccount" + fc::to_pretty_string(i), name, sidechain_type::bitcoin, true, true);
|
||||
con.wallet_api_ptr->vote_for_son("sonaccount" + fc::to_pretty_string(i), name, sidechain_type::hive, true, true);
|
||||
}
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
son_object son_obj = con.wallet_api_ptr->get_son(name);
|
||||
BOOST_CHECK(son_obj.status == son_status::active);
|
||||
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::active);
|
||||
BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::active);
|
||||
|
||||
// put SON in maintenance mode
|
||||
con.wallet_api_ptr->request_son_maintenance(name, true);
|
||||
|
|
@ -750,7 +879,8 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
|
|||
|
||||
// check SON is in request_maintenance
|
||||
son_obj = con.wallet_api_ptr->get_son(name);
|
||||
BOOST_CHECK(son_obj.status == son_status::request_maintenance);
|
||||
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::request_maintenance);
|
||||
BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::request_maintenance);
|
||||
|
||||
// restore SON activity
|
||||
con.wallet_api_ptr->cancel_request_son_maintenance(name, true);
|
||||
|
|
@ -758,7 +888,8 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
|
|||
|
||||
// check SON is active
|
||||
son_obj = con.wallet_api_ptr->get_son(name);
|
||||
BOOST_CHECK(son_obj.status == son_status::active);
|
||||
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::active);
|
||||
BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::active);
|
||||
|
||||
// put SON in maintenance mode
|
||||
con.wallet_api_ptr->request_son_maintenance(name, true);
|
||||
|
|
@ -766,14 +897,16 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
|
|||
|
||||
// check SON is in request_maintenance
|
||||
son_obj = con.wallet_api_ptr->get_son(name);
|
||||
BOOST_CHECK(son_obj.status == son_status::request_maintenance);
|
||||
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::request_maintenance);
|
||||
BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::request_maintenance);
|
||||
|
||||
// process maintenance
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// check SON is in maintenance
|
||||
son_obj = con.wallet_api_ptr->get_son(name);
|
||||
BOOST_CHECK(son_obj.status == son_status::in_maintenance);
|
||||
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::in_maintenance);
|
||||
BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::in_maintenance);
|
||||
|
||||
|
||||
} catch( fc::exception& e ) {
|
||||
|
|
|
|||
|
|
@ -1040,14 +1040,9 @@ BOOST_FIXTURE_TEST_CASE( hardfork_son2_time, database_fixture )
|
|||
|
||||
generate_blocks(HARDFORK_SON3_TIME);
|
||||
// after this hardfork maximum son account should not reset the value
|
||||
// on 7 after maintenance interval anymore. It must be GRAPHENE_DEFAULT_MAX_SONS
|
||||
// on 7 after maintenance interval anymore. It must be HARDFORK_SON2_TIME
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maximum_son_count(), GRAPHENE_DEFAULT_MAX_SONS);
|
||||
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block();
|
||||
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maximum_son_count(), 15);
|
||||
|
||||
} FC_LOG_AND_RETHROW() }
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE( pop_block_twice, database_fixture )
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <graphene/chain/son_object.hpp>
|
||||
#include <graphene/chain/sidechain_address_object.hpp>
|
||||
#include <graphene/chain/sidechain_defs.hpp>
|
||||
#include <graphene/chain/vesting_balance_object.hpp>
|
||||
|
||||
using namespace graphene::chain;
|
||||
using namespace graphene::chain::test;
|
||||
|
|
@ -63,9 +64,134 @@ BOOST_AUTO_TEST_CASE( sidechain_address_update_test ) {
|
|||
|
||||
INVOKE(sidechain_address_add_test);
|
||||
|
||||
GET_ACTOR(alice);
|
||||
generate_block();
|
||||
|
||||
//! ----- BEGIN CREATE SON bob -----
|
||||
|
||||
ACTORS((bob));
|
||||
|
||||
upgrade_to_lifetime_member(bob);
|
||||
|
||||
transfer( committee_account, bob_id, asset( 1000*GRAPHENE_BLOCKCHAIN_PRECISION ) );
|
||||
|
||||
set_expiration(db, trx);
|
||||
std::string test_url = "https://create_son_test";
|
||||
|
||||
// create deposit vesting
|
||||
vesting_balance_id_type deposit;
|
||||
{
|
||||
vesting_balance_create_operation op;
|
||||
op.creator = bob_id;
|
||||
op.owner = bob_id;
|
||||
op.amount = asset(10*GRAPHENE_BLOCKCHAIN_PRECISION);
|
||||
op.balance_type = vesting_balance_type::son;
|
||||
op.policy = dormant_vesting_policy_initializer {};
|
||||
trx.clear();
|
||||
trx.operations.push_back(op);
|
||||
|
||||
// amount in the son balance need to be at least 50
|
||||
GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception );
|
||||
|
||||
op.amount = asset(50*GRAPHENE_BLOCKCHAIN_PRECISION);
|
||||
trx.clear();
|
||||
|
||||
trx.operations.push_back(op);
|
||||
processed_transaction ptx = PUSH_TX(db, trx, ~0);
|
||||
deposit = ptx.operation_results[0].get<object_id_type>();
|
||||
|
||||
auto deposit_vesting = db.get<vesting_balance_object>(ptx.operation_results[0].get<object_id_type>());
|
||||
|
||||
BOOST_CHECK_EQUAL(deposit(db).balance.amount.value, 50*GRAPHENE_BLOCKCHAIN_PRECISION);
|
||||
auto now = db.head_block_time();
|
||||
BOOST_CHECK_EQUAL(deposit(db).is_withdraw_allowed(now, asset(50*GRAPHENE_BLOCKCHAIN_PRECISION)), false); // cant withdraw
|
||||
}
|
||||
generate_block();
|
||||
set_expiration(db, trx);
|
||||
|
||||
// create payment normal vesting
|
||||
vesting_balance_id_type payment ;
|
||||
{
|
||||
vesting_balance_create_operation op;
|
||||
op.creator = bob_id;
|
||||
op.owner = bob_id;
|
||||
op.amount = asset(1*GRAPHENE_BLOCKCHAIN_PRECISION);
|
||||
op.balance_type = vesting_balance_type::normal;
|
||||
op.policy = linear_vesting_policy_initializer {};
|
||||
op.validate();
|
||||
|
||||
trx.clear();
|
||||
trx.operations.push_back(op);
|
||||
trx.validate();
|
||||
processed_transaction ptx = PUSH_TX(db, trx, ~0);
|
||||
trx.clear();
|
||||
payment = ptx.operation_results[0].get<object_id_type>();
|
||||
}
|
||||
|
||||
generate_block();
|
||||
set_expiration(db, trx);
|
||||
|
||||
// bob became son
|
||||
{
|
||||
flat_map<sidechain_type, string> sidechain_public_keys;
|
||||
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin address";
|
||||
sidechain_public_keys[sidechain_type::hive] = "hive address";
|
||||
|
||||
son_create_operation op;
|
||||
op.owner_account = bob_id;
|
||||
op.url = test_url;
|
||||
op.deposit = deposit;
|
||||
op.pay_vb = payment;
|
||||
op.signing_key = bob_public_key;
|
||||
op.sidechain_public_keys = sidechain_public_keys;
|
||||
|
||||
trx.clear();
|
||||
trx.operations.push_back(op);
|
||||
sign(trx, bob_private_key);
|
||||
PUSH_TX(db, trx, ~0);
|
||||
trx.clear();
|
||||
}
|
||||
generate_block();
|
||||
|
||||
{
|
||||
const auto &idx = db.get_index_type<son_index>().indices().get<by_account>();
|
||||
BOOST_REQUIRE(idx.size() == 1);
|
||||
auto obj = idx.find(bob_id);
|
||||
BOOST_REQUIRE(obj != idx.end());
|
||||
BOOST_CHECK(obj->url == test_url);
|
||||
BOOST_CHECK(obj->signing_key == bob_public_key);
|
||||
BOOST_CHECK(obj->sidechain_public_keys.at(sidechain_type::bitcoin) == "bitcoin address");
|
||||
BOOST_CHECK(obj->deposit.instance == deposit.instance.value);
|
||||
BOOST_CHECK(obj->pay_vb.instance == payment.instance.value);
|
||||
}
|
||||
|
||||
// Note payment time just to generate enough blocks to make budget
|
||||
const auto block_interval = db.get_global_properties().parameters.block_interval;
|
||||
auto pay_fee_time = db.head_block_time().sec_since_epoch();
|
||||
generate_block();
|
||||
// Do maintenance from the upcoming block
|
||||
auto schedule_maint = [&]()
|
||||
{
|
||||
db.modify( db.get_dynamic_global_properties(), [&]( dynamic_global_property_object& _dpo )
|
||||
{
|
||||
_dpo.next_maintenance_time = db.head_block_time() + 1;
|
||||
} );
|
||||
};
|
||||
|
||||
// Generate enough blocks to make budget
|
||||
while( db.head_block_time().sec_since_epoch() - pay_fee_time < 100 * block_interval )
|
||||
{
|
||||
generate_block();
|
||||
}
|
||||
|
||||
// Enough blocks generated schedule maintenance now
|
||||
schedule_maint();
|
||||
// This block triggers maintenance
|
||||
generate_block();
|
||||
|
||||
//! ----- END CREATE SON bob -----
|
||||
|
||||
GET_ACTOR(alice);
|
||||
|
||||
const auto& idx = db.get_index_type<sidechain_address_index>().indices().get<by_account_and_sidechain_and_expires>();
|
||||
BOOST_REQUIRE( idx.size() == 1 );
|
||||
auto obj = idx.find( boost::make_tuple( alice_id, sidechain_type::bitcoin, time_point_sec::maximum() ) );
|
||||
|
|
@ -77,19 +203,7 @@ BOOST_AUTO_TEST_CASE( sidechain_address_update_test ) {
|
|||
std::string new_withdraw_address = "withdraw_address";
|
||||
|
||||
generate_block();
|
||||
auto& son = db.create<son_object>( [&]( son_object& sobj )
|
||||
{
|
||||
sobj.son_account = bob_id;
|
||||
sobj.statistics = db.create<son_statistics_object>([&](son_statistics_object& s){s.owner = sobj.id;}).id;
|
||||
});
|
||||
generate_block();
|
||||
db.modify( db.get_global_properties(), [&]( global_property_object& _gpo )
|
||||
{
|
||||
son_info sinfo;
|
||||
sinfo.son_id = son.id;
|
||||
_gpo.active_sons.push_back(sinfo);
|
||||
});
|
||||
generate_block();
|
||||
set_expiration(db, trx);
|
||||
{
|
||||
BOOST_TEST_MESSAGE("Send sidechain_address_update_operation");
|
||||
trx.clear();
|
||||
|
|
|
|||
|
|
@ -193,12 +193,14 @@ try {
|
|||
// Modify SON's status to active
|
||||
db.modify( *obj, [&]( son_object& _s)
|
||||
{
|
||||
_s.status = son_status::in_maintenance;
|
||||
_s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance;
|
||||
_s.statuses[sidechain_type::hive] = son_status::in_maintenance;
|
||||
});
|
||||
|
||||
db.modify( *son_stats_obj, [&]( son_statistics_object& _s)
|
||||
{
|
||||
_s.last_down_timestamp = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time());
|
||||
_s.last_down_timestamp[sidechain_type::bitcoin] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time());
|
||||
_s.last_down_timestamp[sidechain_type::hive] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time());
|
||||
});
|
||||
|
||||
auto deposit_vesting = db.get<vesting_balance_object>(vesting_balance_id_type(0));
|
||||
|
|
@ -218,7 +220,8 @@ try {
|
|||
generate_block();
|
||||
|
||||
BOOST_REQUIRE( idx.size() == 1 );
|
||||
BOOST_REQUIRE( obj->status == son_status::deregistered );
|
||||
BOOST_REQUIRE( obj->statuses.at(sidechain_type::bitcoin) == son_status::deregistered );
|
||||
BOOST_REQUIRE( obj->statuses.at(sidechain_type::hive) == son_status::deregistered );
|
||||
BOOST_REQUIRE( son_stats_obj->deregistered_timestamp == now );
|
||||
|
||||
deposit_vesting = db.get<vesting_balance_object>(vesting_balance_id_type(0));
|
||||
|
|
@ -604,12 +607,14 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
|
|||
// Modify SON's status to active
|
||||
db.modify( *obj, [&]( son_object& _s)
|
||||
{
|
||||
_s.status = son_status::active;
|
||||
_s.statuses[sidechain_type::bitcoin] = son_status::active;
|
||||
_s.statuses[sidechain_type::hive] = son_status::active;
|
||||
});
|
||||
|
||||
db.modify( *son_stats_obj, [&]( son_statistics_object& _s)
|
||||
{
|
||||
_s.last_down_timestamp = fc::time_point_sec(db.head_block_time());
|
||||
_s.last_down_timestamp[sidechain_type::bitcoin] = fc::time_point_sec(db.head_block_time());
|
||||
_s.last_down_timestamp[sidechain_type::hive] = fc::time_point_sec(db.head_block_time());
|
||||
});
|
||||
|
||||
{
|
||||
|
|
@ -626,7 +631,8 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
|
|||
PUSH_TX( db, trx, ~0);
|
||||
generate_block();
|
||||
trx.clear();
|
||||
BOOST_CHECK( obj->status == son_status::request_maintenance);
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::request_maintenance);
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::request_maintenance);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -643,16 +649,20 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
|
|||
PUSH_TX( db, trx, ~0);
|
||||
generate_block();
|
||||
trx.clear();
|
||||
BOOST_CHECK( obj->status == son_status::active);
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::active);
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active);
|
||||
}
|
||||
|
||||
// Modify SON's status to in_maintenance
|
||||
db.modify( *obj, [&]( son_object& _s)
|
||||
{
|
||||
_s.status = son_status::in_maintenance;
|
||||
_s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance;
|
||||
_s.statuses[sidechain_type::hive] = son_status::in_maintenance;
|
||||
});
|
||||
|
||||
uint64_t downtime = 0;
|
||||
flat_map<sidechain_type, uint64_t> downtime;
|
||||
downtime[sidechain_type::bitcoin] = 0;
|
||||
downtime[sidechain_type::hive] = 0;
|
||||
|
||||
{
|
||||
generate_block();
|
||||
|
|
@ -668,16 +678,21 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
|
|||
PUSH_TX( db, trx, ~0);
|
||||
generate_block();
|
||||
trx.clear();
|
||||
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime, op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch());
|
||||
downtime += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch();
|
||||
BOOST_CHECK( obj->status == son_status::inactive);
|
||||
BOOST_CHECK( son_stats_obj->last_active_timestamp == op.ts);
|
||||
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::bitcoin), op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::bitcoin).sec_since_epoch());
|
||||
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::hive), op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::hive).sec_since_epoch());
|
||||
downtime[sidechain_type::bitcoin] += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::bitcoin).sec_since_epoch();
|
||||
downtime[sidechain_type::hive] += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::hive).sec_since_epoch();
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::inactive);
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::inactive);
|
||||
BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::bitcoin) == op.ts);
|
||||
BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::hive) == op.ts);
|
||||
}
|
||||
|
||||
// Modify SON's status to in_maintenance
|
||||
db.modify( *obj, [&]( son_object& _s)
|
||||
{
|
||||
_s.status = son_status::in_maintenance;
|
||||
_s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance;
|
||||
_s.statuses[sidechain_type::hive] = son_status::in_maintenance;
|
||||
});
|
||||
|
||||
// SON is selected as one of the active SONs
|
||||
|
|
@ -685,7 +700,8 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
|
|||
{
|
||||
son_info son_inf;
|
||||
son_inf.son_id = son_id_type(0);
|
||||
_gpo.active_sons.push_back(son_inf);
|
||||
_gpo.active_sons[sidechain_type::bitcoin].push_back(son_inf);
|
||||
_gpo.active_sons[sidechain_type::hive].push_back(son_inf);
|
||||
});
|
||||
|
||||
{
|
||||
|
|
@ -702,10 +718,15 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
|
|||
PUSH_TX( db, trx, ~0);
|
||||
generate_block();
|
||||
trx.clear();
|
||||
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime, downtime + op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch());
|
||||
downtime += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch();
|
||||
BOOST_CHECK( obj->status == son_status::active);
|
||||
BOOST_CHECK( son_stats_obj->last_active_timestamp == op.ts);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::bitcoin), downtime.at(sidechain_type::bitcoin) + op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::bitcoin).sec_since_epoch());
|
||||
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::hive), downtime.at(sidechain_type::hive) + op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::hive).sec_since_epoch());
|
||||
downtime[sidechain_type::bitcoin] += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::bitcoin).sec_since_epoch();
|
||||
downtime[sidechain_type::hive] += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::hive).sec_since_epoch();
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::active);
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active);
|
||||
BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::bitcoin) == op.ts);
|
||||
BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::hive) == op.ts);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -722,9 +743,12 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
|
|||
PUSH_TX( db, trx, ~0);
|
||||
generate_block();
|
||||
trx.clear();
|
||||
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime, downtime);
|
||||
BOOST_CHECK( obj->status == son_status::active);
|
||||
BOOST_CHECK( son_stats_obj->last_active_timestamp == op.ts);
|
||||
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::bitcoin), downtime.at(sidechain_type::bitcoin));
|
||||
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::hive), downtime.at(sidechain_type::hive));
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::active);
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active);
|
||||
BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::bitcoin) == op.ts);
|
||||
BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::hive) == op.ts);
|
||||
}
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
|
@ -749,7 +773,8 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) {
|
|||
auto son_stats_obj = sidx.find( obj->statistics );
|
||||
BOOST_REQUIRE( son_stats_obj != sidx.end() );
|
||||
|
||||
BOOST_CHECK( obj->status == son_status::active);
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::active);
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active);
|
||||
|
||||
{
|
||||
// Check that transaction fails if down_ts < last_active_timestamp
|
||||
|
|
@ -758,7 +783,7 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) {
|
|||
son_report_down_operation op;
|
||||
op.payer = db.get_global_properties().parameters.son_account();
|
||||
op.son_id = son_id_type(0);
|
||||
op.down_ts = fc::time_point_sec(son_stats_obj->last_active_timestamp - fc::seconds(1));
|
||||
op.down_ts = fc::time_point_sec(son_stats_obj->last_active_timestamp.at(sidechain_type::bitcoin) - fc::seconds(1));
|
||||
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
|
|
@ -775,7 +800,7 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) {
|
|||
son_report_down_operation op;
|
||||
op.payer = alice_id;
|
||||
op.son_id = son_id_type(0);
|
||||
op.down_ts = son_stats_obj->last_active_timestamp;
|
||||
op.down_ts = son_stats_obj->last_active_timestamp.at(sidechain_type::bitcoin);
|
||||
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
|
|
@ -792,7 +817,7 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) {
|
|||
son_report_down_operation op;
|
||||
op.payer = db.get_global_properties().parameters.son_account();
|
||||
op.son_id = son_id_type(0);
|
||||
op.down_ts = son_stats_obj->last_active_timestamp;
|
||||
op.down_ts = son_stats_obj->last_active_timestamp.at(sidechain_type::bitcoin);
|
||||
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
|
|
@ -801,8 +826,10 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) {
|
|||
generate_block();
|
||||
trx.clear();
|
||||
|
||||
BOOST_CHECK( obj->status == son_status::in_maintenance);
|
||||
BOOST_CHECK( son_stats_obj->last_down_timestamp == op.down_ts);
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::in_maintenance);
|
||||
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::in_maintenance);
|
||||
BOOST_CHECK( son_stats_obj->last_down_timestamp.at(sidechain_type::bitcoin) == op.down_ts);
|
||||
BOOST_CHECK( son_stats_obj->last_down_timestamp.at(sidechain_type::hive) == op.down_ts);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -812,7 +839,7 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) {
|
|||
son_report_down_operation op;
|
||||
op.payer = db.get_global_properties().parameters.son_account();
|
||||
op.son_id = son_id_type(0);
|
||||
op.down_ts = son_stats_obj->last_active_timestamp;
|
||||
op.down_ts = son_stats_obj->last_active_timestamp.at(sidechain_type::bitcoin);
|
||||
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
|
|
|
|||
|
|
@ -154,13 +154,14 @@ BOOST_AUTO_TEST_CASE( son_wallet_recreate_test ) {
|
|||
|
||||
op.payer = db.get_global_properties().parameters.son_account();
|
||||
|
||||
//! Fixme - add hive tests
|
||||
{
|
||||
son_info si;
|
||||
si.son_id = son_id_type(0);
|
||||
si.weight = 1000;
|
||||
si.signing_key = alice_public_key;
|
||||
si.sidechain_public_keys[sidechain_type::bitcoin] = "";
|
||||
op.sons.push_back(si);
|
||||
si.public_key = "";
|
||||
op.sons[sidechain_type::bitcoin].push_back(si);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -168,8 +169,8 @@ BOOST_AUTO_TEST_CASE( son_wallet_recreate_test ) {
|
|||
si.son_id = son_id_type(1);
|
||||
si.weight = 1000;
|
||||
si.signing_key = bob_public_key;
|
||||
si.sidechain_public_keys[sidechain_type::bitcoin] = "";
|
||||
op.sons.push_back(si);
|
||||
si.public_key = "";
|
||||
op.sons[sidechain_type::bitcoin].push_back(si);
|
||||
}
|
||||
|
||||
trx.operations.push_back(op);
|
||||
|
|
|
|||
Loading…
Reference in a new issue