Compare commits
61 commits
master
...
feature/SO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e596a67e6 | ||
|
|
75626254fa | ||
|
|
0d14b481a4 | ||
|
|
da7b161d3d | ||
|
|
df369df421 | ||
|
|
95ad384f0c | ||
|
|
532afc062f | ||
|
|
7f56e8e661 | ||
|
|
69cad0f1bd | ||
|
|
98ebbbd69b | ||
|
|
2cc90a8794 | ||
|
|
5b1dea0d39 | ||
|
|
9056ba6d07 | ||
|
|
bb8d334e6c | ||
|
|
01f1b6137a | ||
|
|
23458ee917 | ||
|
|
bbd2e35014 | ||
|
|
89ca9167d3 | ||
|
|
9db6179f79 | ||
|
|
5c57f5d9c8 | ||
|
|
703c577d90 | ||
|
|
263ba5d15b | ||
|
|
ca112b1eb6 | ||
|
|
f62a46e789 | ||
|
|
5b7dd86ab9 | ||
|
|
2bb3fc79d7 | ||
|
|
c5ea418321 | ||
|
|
afcb1ace1b | ||
|
|
0c7ef96178 | ||
|
|
95b515c09a | ||
|
|
01a1f584df | ||
|
|
f6c1da53df | ||
|
|
d048873601 | ||
|
|
42b7d25a99 | ||
|
|
775fdf8980 | ||
|
|
6055576aa4 | ||
|
|
1808082d59 | ||
|
|
9c1eb63d15 | ||
|
|
4590f919dc | ||
|
|
be60f65612 | ||
|
|
df7ee459f9 | ||
|
|
0142348a9c | ||
|
|
8399008e7d | ||
|
|
7ceed83a95 | ||
|
|
a6e14af38f | ||
|
|
7abfa78ad6 | ||
|
|
0b491510c4 | ||
|
|
f0a8e8e376 | ||
|
|
c25108f228 | ||
|
|
23cb5310b0 | ||
|
|
ebb6662210 | ||
|
|
1dc0eee6b6 | ||
|
|
b06e1d680a | ||
|
|
2615c41224 | ||
|
|
6f0c025462 | ||
|
|
61b8ff0cc7 | ||
|
|
2b8a39e332 | ||
|
|
ba255da679 | ||
|
|
0e47eeccf2 | ||
|
|
6421d5e852 | ||
|
|
2e124b07c6 |
16 changed files with 453 additions and 331 deletions
|
|
@ -259,6 +259,7 @@ void database::initialize_evaluators()
|
||||||
register_evaluator<recreate_son_wallet_evaluator>();
|
register_evaluator<recreate_son_wallet_evaluator>();
|
||||||
register_evaluator<update_son_wallet_evaluator>();
|
register_evaluator<update_son_wallet_evaluator>();
|
||||||
register_evaluator<create_son_wallet_transfer_evaluator>();
|
register_evaluator<create_son_wallet_transfer_evaluator>();
|
||||||
|
register_evaluator<process_son_wallet_transfer_evaluator>();
|
||||||
register_evaluator<add_sidechain_address_evaluator>();
|
register_evaluator<add_sidechain_address_evaluator>();
|
||||||
register_evaluator<update_sidechain_address_evaluator>();
|
register_evaluator<update_sidechain_address_evaluator>();
|
||||||
register_evaluator<delete_sidechain_address_evaluator>();
|
register_evaluator<delete_sidechain_address_evaluator>();
|
||||||
|
|
@ -446,6 +447,16 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
||||||
a.network_fee_percentage = 0;
|
a.network_fee_percentage = 0;
|
||||||
a.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT;
|
a.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT;
|
||||||
}).get_id() == GRAPHENE_RAKE_FEE_ACCOUNT_ID);
|
}).get_id() == GRAPHENE_RAKE_FEE_ACCOUNT_ID);
|
||||||
|
FC_ASSERT(create<account_object>([this](account_object& a) {
|
||||||
|
a.name = "son-account";
|
||||||
|
a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).id;
|
||||||
|
a.owner.weight_threshold = 0;
|
||||||
|
a.active.weight_threshold = 0;
|
||||||
|
a.registrar = a.lifetime_referrer = a.referrer = GRAPHENE_SON_ACCOUNT;
|
||||||
|
a.membership_expiration_date = time_point_sec::maximum();
|
||||||
|
a.network_fee_percentage = GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE;
|
||||||
|
a.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT - GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE;
|
||||||
|
}).get_id() == GRAPHENE_SON_ACCOUNT);
|
||||||
// Create more special accounts
|
// Create more special accounts
|
||||||
while( true )
|
while( true )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -432,14 +432,14 @@ void database::update_active_sons()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update SON authority
|
// Update SON authority
|
||||||
modify( get(GRAPHENE_SON_ACCOUNT_ID), [&]( account_object& a )
|
modify( get(GRAPHENE_SON_ACCOUNT), [&]( account_object& a )
|
||||||
{
|
{
|
||||||
if( head_block_time() < HARDFORK_533_TIME )
|
if( head_block_time() < HARDFORK_533_TIME )
|
||||||
{
|
{
|
||||||
uint64_t total_votes = 0;
|
uint64_t total_votes = 0;
|
||||||
map<account_id_type, uint64_t> weights;
|
map<account_id_type, uint64_t> weights;
|
||||||
a.active.weight_threshold = 0;
|
a.active.weight_threshold = 0;
|
||||||
a.active.clear();
|
a.active.account_auths.clear();
|
||||||
|
|
||||||
for( const son_object& son : sons )
|
for( const son_object& son : sons )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -417,6 +417,10 @@ void get_relevant_accounts( const object* obj, flat_set<account_id_type>& accoun
|
||||||
assert( aobj != nullptr );
|
assert( aobj != nullptr );
|
||||||
accounts.insert( aobj->son_account );
|
accounts.insert( aobj->son_account );
|
||||||
break;
|
break;
|
||||||
|
} case son_wallet_object_type:{
|
||||||
|
break;
|
||||||
|
} case son_wallet_transfer_object_type:{
|
||||||
|
break;
|
||||||
} case sidechain_address_object_type:{
|
} case sidechain_address_object_type:{
|
||||||
const auto& aobj = dynamic_cast<const sidechain_address_object*>(obj);
|
const auto& aobj = dynamic_cast<const sidechain_address_object*>(obj);
|
||||||
assert( aobj != nullptr );
|
assert( aobj != nullptr );
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,12 @@ fc::variant_object get_config()
|
||||||
result[ "GRAPHENE_RELAXED_COMMITTEE_ACCOUNT" ] = fc::variant(GRAPHENE_RELAXED_COMMITTEE_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
|
result[ "GRAPHENE_RELAXED_COMMITTEE_ACCOUNT" ] = fc::variant(GRAPHENE_RELAXED_COMMITTEE_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
|
||||||
result[ "GRAPHENE_NULL_ACCOUNT" ] = fc::variant(GRAPHENE_NULL_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
|
result[ "GRAPHENE_NULL_ACCOUNT" ] = fc::variant(GRAPHENE_NULL_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
|
||||||
result[ "GRAPHENE_TEMP_ACCOUNT" ] = fc::variant(GRAPHENE_TEMP_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
|
result[ "GRAPHENE_TEMP_ACCOUNT" ] = fc::variant(GRAPHENE_TEMP_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
|
||||||
|
result[ "GRAPHENE_PROXY_TO_SELF_ACCOUNT" ] = fc::variant(GRAPHENE_TEMP_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
|
||||||
|
result[ "GRAPHENE_RAKE_FEE_ACCOUNT_ID" ] = fc::variant(GRAPHENE_TEMP_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
|
||||||
|
result[ "GRAPHENE_SON_ACCOUNT" ] = fc::variant(GRAPHENE_TEMP_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
|
||||||
|
result[ "GRAPHENE_NULL_WITNESS" ] = fc::variant(GRAPHENE_TEMP_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
|
||||||
|
result[ "GRAPHENE_FBA_STEALTH_DESIGNATED_ASSET" ] = fc::variant(GRAPHENE_TEMP_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
|
||||||
|
result[ "GRAPHENE_DEFAULT_RAKE_FEE_PERCENTAGE" ] = fc::variant(GRAPHENE_TEMP_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@
|
||||||
///
|
///
|
||||||
#define GRAPHENE_RAKE_FEE_ACCOUNT_ID (graphene::chain::account_id_type(6))
|
#define GRAPHENE_RAKE_FEE_ACCOUNT_ID (graphene::chain::account_id_type(6))
|
||||||
///
|
///
|
||||||
#define GRAPHENE_SON_ACCOUNT_ID (graphene::chain::account_id_type(7))
|
#define GRAPHENE_SON_ACCOUNT (graphene::chain::account_id_type(7))
|
||||||
/// Sentinel value used in the scheduler.
|
/// Sentinel value used in the scheduler.
|
||||||
#define GRAPHENE_NULL_WITNESS (graphene::chain::witness_id_type(0))
|
#define GRAPHENE_NULL_WITNESS (graphene::chain::witness_id_type(0))
|
||||||
///@}
|
///@}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ namespace graphene { namespace chain {
|
||||||
int64_t sidechain_amount;
|
int64_t sidechain_amount;
|
||||||
chain::account_id_type peerplays_from;
|
chain::account_id_type peerplays_from;
|
||||||
chain::account_id_type peerplays_to;
|
chain::account_id_type peerplays_to;
|
||||||
|
chain::asset peerplays_amount;
|
||||||
|
|
||||||
account_id_type fee_payer()const { return payer; }
|
account_id_type fee_payer()const { return payer; }
|
||||||
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
|
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
|
||||||
|
|
@ -41,7 +42,7 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
FC_REFLECT(graphene::chain::son_wallet_transfer_create_operation::fee_parameters_type, (fee) )
|
FC_REFLECT(graphene::chain::son_wallet_transfer_create_operation::fee_parameters_type, (fee) )
|
||||||
FC_REFLECT(graphene::chain::son_wallet_transfer_create_operation, (fee)(payer)
|
FC_REFLECT(graphene::chain::son_wallet_transfer_create_operation, (fee)(payer)
|
||||||
(timestamp) (sidechain) (sidechain_uid) (sidechain_transaction_id) (sidechain_from) (sidechain_to) (sidechain_amount) (peerplays_from) (peerplays_to))
|
(timestamp) (sidechain) (sidechain_uid) (sidechain_transaction_id) (sidechain_from) (sidechain_to) (sidechain_amount) (peerplays_from) (peerplays_to) (peerplays_amount))
|
||||||
FC_REFLECT(graphene::chain::son_wallet_transfer_process_operation::fee_parameters_type, (fee) )
|
FC_REFLECT(graphene::chain::son_wallet_transfer_process_operation::fee_parameters_type, (fee) )
|
||||||
FC_REFLECT(graphene::chain::son_wallet_transfer_process_operation, (fee)(payer)
|
FC_REFLECT(graphene::chain::son_wallet_transfer_process_operation, (fee)(payer)
|
||||||
(son_wallet_transfer_id))
|
(son_wallet_transfer_id))
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
time_point_sec timestamp;
|
time_point_sec timestamp;
|
||||||
peerplays_sidechain::sidechain_type sidechain;
|
peerplays_sidechain::sidechain_type sidechain;
|
||||||
|
int64_t confirmations;
|
||||||
std::string sidechain_uid;
|
std::string sidechain_uid;
|
||||||
std::string sidechain_transaction_id;
|
std::string sidechain_transaction_id;
|
||||||
std::string sidechain_from;
|
std::string sidechain_from;
|
||||||
|
|
@ -25,6 +26,7 @@ namespace graphene { namespace chain {
|
||||||
int64_t sidechain_amount;
|
int64_t sidechain_amount;
|
||||||
chain::account_id_type peerplays_from;
|
chain::account_id_type peerplays_from;
|
||||||
chain::account_id_type peerplays_to;
|
chain::account_id_type peerplays_to;
|
||||||
|
chain::asset peerplays_amount;
|
||||||
|
|
||||||
bool processed;
|
bool processed;
|
||||||
};
|
};
|
||||||
|
|
@ -60,7 +62,7 @@ namespace graphene { namespace chain {
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
||||||
FC_REFLECT_DERIVED( graphene::chain::son_wallet_transfer_object, (graphene::db::object),
|
FC_REFLECT_DERIVED( graphene::chain::son_wallet_transfer_object, (graphene::db::object),
|
||||||
(timestamp) (sidechain)
|
(timestamp) (sidechain) (confirmations)
|
||||||
(sidechain_uid) (sidechain_transaction_id) (sidechain_from) (sidechain_to) (sidechain_amount)
|
(sidechain_uid) (sidechain_transaction_id) (sidechain_from) (sidechain_to) (sidechain_amount)
|
||||||
(peerplays_from) (peerplays_to)
|
(peerplays_from) (peerplays_to) (peerplays_amount)
|
||||||
(processed) )
|
(processed) )
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ void_result recreate_son_wallet_evaluator::do_evaluate(const son_wallet_recreate
|
||||||
{ try{
|
{ try{
|
||||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
||||||
//FC_ASSERT(db().get_global_properties().parameters.get_son_btc_account_id() != GRAPHENE_NULL_ACCOUNT, "SON paying account not set.");
|
//FC_ASSERT(db().get_global_properties().parameters.get_son_btc_account_id() != GRAPHENE_NULL_ACCOUNT, "SON paying account not set.");
|
||||||
FC_ASSERT( op.payer == db().get_global_properties().parameters.get_son_btc_account_id() );
|
FC_ASSERT( op.payer == db().get_global_properties().parameters.get_son_btc_account_id(), "SON paying account must be set as payer." );
|
||||||
|
|
||||||
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||||
auto itr = idx.rbegin();
|
auto itr = idx.rbegin();
|
||||||
|
|
@ -55,13 +55,13 @@ void_result update_son_wallet_evaluator::do_evaluate(const son_wallet_update_ope
|
||||||
{ try{
|
{ try{
|
||||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
||||||
//FC_ASSERT(db().get_global_properties().parameters.get_son_btc_account_id() != GRAPHENE_NULL_ACCOUNT, "SON paying account not set.");
|
//FC_ASSERT(db().get_global_properties().parameters.get_son_btc_account_id() != GRAPHENE_NULL_ACCOUNT, "SON paying account not set.");
|
||||||
FC_ASSERT( op.payer == db().get_global_properties().parameters.get_son_btc_account_id() );
|
FC_ASSERT( op.payer == db().get_global_properties().parameters.get_son_btc_account_id(), "SON paying account must be set as payer." );
|
||||||
|
|
||||||
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||||
FC_ASSERT( idx.find(op.son_wallet_id) != idx.end() );
|
FC_ASSERT( idx.find(op.son_wallet_id) != idx.end() );
|
||||||
auto itr = idx.find(op.son_wallet_id);
|
//auto itr = idx.find(op.son_wallet_id);
|
||||||
FC_ASSERT( itr->addresses.find(peerplays_sidechain::sidechain_type::bitcoin) == itr->addresses.end() ||
|
//FC_ASSERT( itr->addresses.find(op.sidechain) == itr->addresses.end() ||
|
||||||
itr->addresses.at(peerplays_sidechain::sidechain_type::bitcoin).empty(), "Sidechain wallet address already set");
|
// itr->addresses.at(op.sidechain).empty(), "Sidechain wallet address already set");
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
|
|
@ -69,12 +69,14 @@ object_id_type update_son_wallet_evaluator::do_apply(const son_wallet_update_ope
|
||||||
{ try {
|
{ try {
|
||||||
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||||
auto itr = idx.find(op.son_wallet_id);
|
auto itr = idx.find(op.son_wallet_id);
|
||||||
if(itr != idx.end())
|
if (itr != idx.end())
|
||||||
{
|
{
|
||||||
|
if (itr->addresses.find(op.sidechain) == itr->addresses.end()) {
|
||||||
db().modify(*itr, [&op](son_wallet_object &swo) {
|
db().modify(*itr, [&op](son_wallet_object &swo) {
|
||||||
swo.addresses[op.sidechain] = op.address;
|
swo.addresses[op.sidechain] = op.address;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return op.son_wallet_id;
|
return op.son_wallet_id;
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include <graphene/chain/son_wallet_transfer_evaluator.hpp>
|
#include <graphene/chain/son_wallet_transfer_evaluator.hpp>
|
||||||
|
|
||||||
#include <graphene/chain/database.hpp>
|
#include <graphene/chain/database.hpp>
|
||||||
|
#include <graphene/chain/is_authorized_asset.hpp>
|
||||||
#include <graphene/chain/son_wallet_transfer_object.hpp>
|
#include <graphene/chain/son_wallet_transfer_object.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
@ -9,18 +10,22 @@ void_result create_son_wallet_transfer_evaluator::do_evaluate(const son_wallet_t
|
||||||
{ try{
|
{ try{
|
||||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
||||||
//FC_ASSERT(db().get_global_properties().parameters.get_son_btc_account_id() != GRAPHENE_NULL_ACCOUNT, "SON paying account not set.");
|
//FC_ASSERT(db().get_global_properties().parameters.get_son_btc_account_id() != GRAPHENE_NULL_ACCOUNT, "SON paying account not set.");
|
||||||
FC_ASSERT( op.payer == db().get_global_properties().parameters.get_son_btc_account_id() );
|
FC_ASSERT( op.payer == db().get_global_properties().parameters.get_son_btc_account_id(), "SON paying account must be set as payer." );
|
||||||
|
|
||||||
const auto& idx = db().get_index_type<son_wallet_transfer_index>().indices().get<by_sidechain_uid>();
|
//const auto& idx = db().get_index_type<son_wallet_transfer_index>().indices().get<by_sidechain_uid>();
|
||||||
FC_ASSERT(idx.find(op.sidechain_uid) == idx.end(), "Already registered " + op.sidechain_uid);
|
//FC_ASSERT(idx.find(op.sidechain_uid) == idx.end(), "Already registered " + op.sidechain_uid);
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
object_id_type create_son_wallet_transfer_evaluator::do_apply(const son_wallet_transfer_create_operation& op)
|
object_id_type create_son_wallet_transfer_evaluator::do_apply(const son_wallet_transfer_create_operation& op)
|
||||||
{ try {
|
{ try {
|
||||||
|
const auto& idx = db().get_index_type<son_wallet_transfer_index>().indices().get<by_sidechain_uid>();
|
||||||
|
auto itr = idx.find(op.sidechain_uid);
|
||||||
|
if (itr == idx.end()) {
|
||||||
const auto& new_son_wallet_transfer_object = db().create<son_wallet_transfer_object>( [&]( son_wallet_transfer_object& swto ){
|
const auto& new_son_wallet_transfer_object = db().create<son_wallet_transfer_object>( [&]( son_wallet_transfer_object& swto ){
|
||||||
swto.timestamp = op.timestamp;
|
swto.timestamp = op.timestamp;
|
||||||
swto.sidechain = op.sidechain;
|
swto.sidechain = op.sidechain;
|
||||||
|
swto.confirmations = 1;
|
||||||
swto.sidechain_uid = op.sidechain_uid;
|
swto.sidechain_uid = op.sidechain_uid;
|
||||||
swto.sidechain_transaction_id = op.sidechain_transaction_id;
|
swto.sidechain_transaction_id = op.sidechain_transaction_id;
|
||||||
swto.sidechain_from = op.sidechain_from;
|
swto.sidechain_from = op.sidechain_from;
|
||||||
|
|
@ -28,20 +33,69 @@ object_id_type create_son_wallet_transfer_evaluator::do_apply(const son_wallet_t
|
||||||
swto.sidechain_amount = op.sidechain_amount;
|
swto.sidechain_amount = op.sidechain_amount;
|
||||||
swto.peerplays_from = op.peerplays_from;
|
swto.peerplays_from = op.peerplays_from;
|
||||||
swto.peerplays_to = op.peerplays_to;
|
swto.peerplays_to = op.peerplays_to;
|
||||||
|
swto.peerplays_amount = op.peerplays_amount;
|
||||||
swto.processed = false;
|
swto.processed = false;
|
||||||
});
|
});
|
||||||
return new_son_wallet_transfer_object.id;
|
return new_son_wallet_transfer_object.id;
|
||||||
|
} else {
|
||||||
|
db().modify(*itr, [&op](son_wallet_transfer_object &swto) {
|
||||||
|
swto.confirmations = swto.confirmations + 1;
|
||||||
|
});
|
||||||
|
return (*itr).id;
|
||||||
|
}
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
void_result process_son_wallet_transfer_evaluator::do_evaluate(const son_wallet_transfer_process_operation& op)
|
void_result process_son_wallet_transfer_evaluator::do_evaluate(const son_wallet_transfer_process_operation& op)
|
||||||
{ try{
|
{ try{
|
||||||
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK");
|
||||||
//FC_ASSERT(db().get_global_properties().parameters.get_son_btc_account_id() != GRAPHENE_NULL_ACCOUNT, "SON paying account not set.");
|
//FC_ASSERT(db().get_global_properties().parameters.get_son_btc_account_id() != GRAPHENE_NULL_ACCOUNT, "SON paying account not set.");
|
||||||
FC_ASSERT( op.payer == db().get_global_properties().parameters.get_son_btc_account_id() );
|
FC_ASSERT( op.payer == db().get_global_properties().parameters.get_son_btc_account_id(), "SON paying account must be set as payer." );
|
||||||
|
|
||||||
const auto& idx = db().get_index_type<son_wallet_transfer_index>().indices().get<by_id>();
|
const auto& idx = db().get_index_type<son_wallet_transfer_index>().indices().get<by_id>();
|
||||||
FC_ASSERT(idx.find(op.son_wallet_transfer_id) != idx.end(), "Son wallet transfer not found");
|
const auto& itr = idx.find(op.son_wallet_transfer_id);
|
||||||
|
FC_ASSERT(itr != idx.end(), "Son wallet transfer not found");
|
||||||
|
//FC_ASSERT(itr->processed == false, "Son wallet transfer is already processed");
|
||||||
|
|
||||||
|
const database& d = db();
|
||||||
|
|
||||||
|
const account_object& from_account = itr->peerplays_to(d); // reversed, for deposit
|
||||||
|
const account_object& to_account = itr->peerplays_from(d); // reversed, for deposit
|
||||||
|
const asset_object& asset_type = itr->peerplays_amount.asset_id(d);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
GRAPHENE_ASSERT(
|
||||||
|
is_authorized_asset( d, from_account, asset_type ),
|
||||||
|
transfer_from_account_not_whitelisted,
|
||||||
|
"'from' account ${from} is not whitelisted for asset ${asset}",
|
||||||
|
("from",from_account.id)
|
||||||
|
("asset",itr->peerplays_amount.asset_id)
|
||||||
|
);
|
||||||
|
GRAPHENE_ASSERT(
|
||||||
|
is_authorized_asset( d, to_account, asset_type ),
|
||||||
|
transfer_to_account_not_whitelisted,
|
||||||
|
"'to' account ${to} is not whitelisted for asset ${asset}",
|
||||||
|
("to",to_account.id)
|
||||||
|
("asset",itr->peerplays_amount.asset_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
if( asset_type.is_transfer_restricted() )
|
||||||
|
{
|
||||||
|
GRAPHENE_ASSERT(
|
||||||
|
from_account.id == asset_type.issuer || to_account.id == asset_type.issuer,
|
||||||
|
transfer_restricted_transfer_asset,
|
||||||
|
"Asset {asset} has transfer_restricted flag enabled",
|
||||||
|
("asset", itr->peerplays_amount.asset_id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool insufficient_balance = d.get_balance( from_account, asset_type ).amount >= itr->peerplays_amount.amount;
|
||||||
|
FC_ASSERT( insufficient_balance,
|
||||||
|
"Insufficient Balance: ${balance}, unable to transfer '${total_transfer}' from account '${a}' to '${t}'",
|
||||||
|
("a",from_account.name)("t",to_account.name)("total_transfer",d.to_pretty_string(itr->peerplays_amount))("balance",d.to_pretty_string(d.get_balance(from_account, asset_type))) );
|
||||||
|
|
||||||
return void_result();
|
return void_result();
|
||||||
|
} FC_RETHROW_EXCEPTIONS( error, "Unable to transfer ${a} from ${f} to ${t}", ("a",d.to_pretty_string(itr->peerplays_amount))("f",from_account.name)("t",to_account.name) );
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
||||||
object_id_type process_son_wallet_transfer_evaluator::do_apply(const son_wallet_transfer_process_operation& op)
|
object_id_type process_son_wallet_transfer_evaluator::do_apply(const son_wallet_transfer_process_operation& op)
|
||||||
|
|
@ -50,9 +104,17 @@ object_id_type process_son_wallet_transfer_evaluator::do_apply(const son_wallet_
|
||||||
auto itr = idx.find(op.son_wallet_transfer_id);
|
auto itr = idx.find(op.son_wallet_transfer_id);
|
||||||
if(itr != idx.end())
|
if(itr != idx.end())
|
||||||
{
|
{
|
||||||
|
if (itr->processed == false) {
|
||||||
db().modify(*itr, [&op](son_wallet_transfer_object &swto) {
|
db().modify(*itr, [&op](son_wallet_transfer_object &swto) {
|
||||||
swto.processed = true;
|
swto.processed = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const account_id_type from_account = itr->peerplays_to; // reversed, for deposit
|
||||||
|
const account_id_type to_account = itr->peerplays_from; // reversed, for deposit
|
||||||
|
|
||||||
|
db().adjust_balance( from_account, -itr->peerplays_amount );
|
||||||
|
db().adjust_balance( to_account, itr->peerplays_amount );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return op.son_wallet_transfer_id;
|
return op.son_wallet_transfer_id;
|
||||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,13 @@ add_library( peerplays_sidechain
|
||||||
sidechain_net_handler_bitcoin.cpp
|
sidechain_net_handler_bitcoin.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (SUPPORT_MULTIPLE_SONS)
|
||||||
|
message ("Multiple SONs per software instance are supported")
|
||||||
|
target_compile_definitions(peerplays_sidechain PRIVATE SUPPORT_MULTIPLE_SONS)
|
||||||
|
endif()
|
||||||
|
unset(SUPPORT_MULTIPLE_SONS)
|
||||||
|
unset(SUPPORT_MULTIPLE_SONS CACHE)
|
||||||
|
|
||||||
target_link_libraries( peerplays_sidechain graphene_chain graphene_app fc zmq )
|
target_link_libraries( peerplays_sidechain graphene_chain graphene_app fc zmq )
|
||||||
target_include_directories( peerplays_sidechain
|
target_include_directories( peerplays_sidechain
|
||||||
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
|
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,12 @@ class peerplays_sidechain_plugin : public graphene::app::plugin
|
||||||
|
|
||||||
std::unique_ptr<detail::peerplays_sidechain_plugin_impl> my;
|
std::unique_ptr<detail::peerplays_sidechain_plugin_impl> my;
|
||||||
|
|
||||||
son_id_type get_son_id();
|
std::set<chain::son_id_type>& get_sons();
|
||||||
son_object get_son_object();
|
son_object get_son_object(son_id_type son_id);
|
||||||
bool is_active_son();
|
bool is_active_son(son_id_type son_id);
|
||||||
std::map<chain::public_key_type, fc::ecc::private_key>& get_private_keys();
|
std::map<chain::public_key_type, fc::ecc::private_key>& get_private_keys();
|
||||||
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
} } //graphene::peerplays_sidechain
|
} } //graphene::peerplays_sidechain
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <boost/property_tree/ptree.hpp>
|
#include <boost/property_tree/ptree.hpp>
|
||||||
#include <boost/property_tree/json_parser.hpp>
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
|
#include <boost/range/algorithm_ext/insert.hpp>
|
||||||
|
|
||||||
#include <fc/log/logger.hpp>
|
#include <fc/log/logger.hpp>
|
||||||
#include <fc/smart_ref_impl.hpp>
|
#include <fc/smart_ref_impl.hpp>
|
||||||
|
|
@ -33,10 +34,12 @@ class peerplays_sidechain_plugin_impl
|
||||||
void plugin_initialize(const boost::program_options::variables_map& options);
|
void plugin_initialize(const boost::program_options::variables_map& options);
|
||||||
void plugin_startup();
|
void plugin_startup();
|
||||||
|
|
||||||
son_id_type get_son_id();
|
std::set<chain::son_id_type>& get_sons();
|
||||||
son_object get_son_object();
|
son_object get_son_object(son_id_type son_id);
|
||||||
bool is_active_son();
|
bool is_active_son(son_id_type son_id);
|
||||||
std::map<chain::public_key_type, fc::ecc::private_key>& get_private_keys();
|
std::map<chain::public_key_type, fc::ecc::private_key>& get_private_keys();
|
||||||
|
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 schedule_heartbeat_loop();
|
void schedule_heartbeat_loop();
|
||||||
void heartbeat_loop();
|
void heartbeat_loop();
|
||||||
|
|
@ -86,12 +89,14 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
|
||||||
{
|
{
|
||||||
auto default_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(std::string("nathan")));
|
auto default_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(std::string("nathan")));
|
||||||
string son_id_example = fc::json::to_string(chain::son_id_type(5));
|
string son_id_example = fc::json::to_string(chain::son_id_type(5));
|
||||||
|
string son_id_example2 = fc::json::to_string(chain::son_id_type(6));
|
||||||
|
|
||||||
cli.add_options()
|
cli.add_options()
|
||||||
("son-id", bpo::value<vector<string>>(), ("ID of SON controlled by this node (e.g. " + son_id_example + ", quotes are required)").c_str())
|
("son-id", bpo::value<vector<string>>(), ("ID of SON controlled by this node (e.g. " + son_id_example + ", quotes are required)").c_str())
|
||||||
|
("son-ids", bpo::value<string>(), ("IDs of multiple SONs controlled by this node (e.g. [" + son_id_example + ", " + son_id_example2 + "], quotes are required)").c_str())
|
||||||
("peerplays-private-key", bpo::value<vector<string>>()->composing()->multitoken()->
|
("peerplays-private-key", bpo::value<vector<string>>()->composing()->multitoken()->
|
||||||
DEFAULT_VALUE_VECTOR(std::make_pair(chain::public_key_type(default_priv_key.get_public_key()), graphene::utilities::key_to_wif(default_priv_key))),
|
DEFAULT_VALUE_VECTOR(std::make_pair(chain::public_key_type(default_priv_key.get_public_key()), graphene::utilities::key_to_wif(default_priv_key))),
|
||||||
"Tuple of [PublicKey, WIF private key]")
|
"Tuple of [PublicKey, WIF private key] (may specify multiple times)")
|
||||||
|
|
||||||
("bitcoin-node-ip", bpo::value<string>()->default_value("99.79.189.95"), "IP address of Bitcoin node")
|
("bitcoin-node-ip", bpo::value<string>()->default_value("99.79.189.95"), "IP address of Bitcoin node")
|
||||||
("bitcoin-node-zmq-port", bpo::value<uint32_t>()->default_value(11111), "ZMQ port of Bitcoin node")
|
("bitcoin-node-zmq-port", bpo::value<uint32_t>()->default_value(11111), "ZMQ port of Bitcoin node")
|
||||||
|
|
@ -107,9 +112,17 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_options::variables_map& options)
|
void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_options::variables_map& options)
|
||||||
{
|
{
|
||||||
config_ready_son = options.count( "son-id" ) && options.count( "peerplays-private-key" );
|
config_ready_son = (options.count( "son-id" ) || options.count( "son-ids" )) && options.count( "peerplays-private-key" );
|
||||||
if (config_ready_son) {
|
if (config_ready_son) {
|
||||||
LOAD_VALUE_SET(options, "son-id", _sons, chain::son_id_type)
|
LOAD_VALUE_SET(options, "son-id", _sons, chain::son_id_type)
|
||||||
|
if (options.count("son-ids"))
|
||||||
|
boost::insert(_sons, fc::json::from_string(options.at("son-ids").as<string>()).as<vector<chain::son_id_type>>( 5 ));
|
||||||
|
config_ready_son = config_ready_son && !_sons.empty();
|
||||||
|
|
||||||
|
#ifndef SUPPORT_MULTIPLE_SONS
|
||||||
|
FC_ASSERT( _sons.size() == 1, "Multiple SONs not supported" );
|
||||||
|
#endif
|
||||||
|
|
||||||
if( options.count("peerplays-private-key") )
|
if( options.count("peerplays-private-key") )
|
||||||
{
|
{
|
||||||
const std::vector<std::string> key_id_to_wif_pair_strings = options["peerplays-private-key"].as<std::vector<std::string>>();
|
const std::vector<std::string> key_id_to_wif_pair_strings = options["peerplays-private-key"].as<std::vector<std::string>>();
|
||||||
|
|
@ -173,9 +186,8 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt
|
||||||
void peerplays_sidechain_plugin_impl::plugin_startup()
|
void peerplays_sidechain_plugin_impl::plugin_startup()
|
||||||
{
|
{
|
||||||
if (config_ready_son) {
|
if (config_ready_son) {
|
||||||
ilog("SON running");
|
ilog("Starting ${n} SON instances", ("n", _sons.size()));
|
||||||
|
|
||||||
ilog("Starting heartbeats for ${n} sons.", ("n", _sons.size()));
|
|
||||||
schedule_heartbeat_loop();
|
schedule_heartbeat_loop();
|
||||||
} else {
|
} else {
|
||||||
elog("No sons configured! Please add SON IDs and private keys to configuration.");
|
elog("No sons configured! Please add SON IDs and private keys to configuration.");
|
||||||
|
|
@ -190,24 +202,24 @@ void peerplays_sidechain_plugin_impl::plugin_startup()
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
son_id_type peerplays_sidechain_plugin_impl::get_son_id()
|
std::set<chain::son_id_type>& peerplays_sidechain_plugin_impl::get_sons()
|
||||||
{
|
{
|
||||||
return *(_sons.begin());
|
return _sons;
|
||||||
}
|
}
|
||||||
|
|
||||||
son_object peerplays_sidechain_plugin_impl::get_son_object()
|
son_object peerplays_sidechain_plugin_impl::get_son_object(son_id_type son_id)
|
||||||
{
|
{
|
||||||
const auto& idx = plugin.database().get_index_type<chain::son_index>().indices().get<by_id>();
|
const auto& idx = plugin.database().get_index_type<chain::son_index>().indices().get<by_id>();
|
||||||
auto son_obj = idx.find( get_son_id() );
|
auto son_obj = idx.find( son_id );
|
||||||
if (son_obj == idx.end())
|
if (son_obj == idx.end())
|
||||||
return {};
|
return {};
|
||||||
return *son_obj;
|
return *son_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peerplays_sidechain_plugin_impl::is_active_son()
|
bool peerplays_sidechain_plugin_impl::is_active_son(son_id_type son_id)
|
||||||
{
|
{
|
||||||
const auto& idx = plugin.database().get_index_type<chain::son_index>().indices().get<by_id>();
|
const auto& idx = plugin.database().get_index_type<chain::son_index>().indices().get<by_id>();
|
||||||
auto son_obj = idx.find( get_son_id() );
|
auto son_obj = idx.find( son_id );
|
||||||
if (son_obj == idx.end())
|
if (son_obj == idx.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -220,7 +232,7 @@ bool peerplays_sidechain_plugin_impl::is_active_son()
|
||||||
return swi.son_id;
|
return swi.son_id;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto it = std::find(active_son_ids.begin(), active_son_ids.end(), get_son_id());
|
auto it = std::find(active_son_ids.begin(), active_son_ids.end(), son_id);
|
||||||
|
|
||||||
return (it != active_son_ids.end());
|
return (it != active_son_ids.end());
|
||||||
}
|
}
|
||||||
|
|
@ -230,6 +242,20 @@ std::map<chain::public_key_type, fc::ecc::private_key>& peerplays_sidechain_plug
|
||||||
return _private_keys;
|
return _private_keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fc::ecc::private_key peerplays_sidechain_plugin_impl::get_private_key(son_id_type son_id)
|
||||||
|
{
|
||||||
|
return get_private_key(get_son_object(son_id).signing_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
fc::ecc::private_key peerplays_sidechain_plugin_impl::get_private_key(chain::public_key_type public_key)
|
||||||
|
{
|
||||||
|
auto private_key_itr = _private_keys.find( public_key );
|
||||||
|
if( private_key_itr != _private_keys.end() ) {
|
||||||
|
return private_key_itr->second;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::schedule_heartbeat_loop()
|
void peerplays_sidechain_plugin_impl::schedule_heartbeat_loop()
|
||||||
{
|
{
|
||||||
fc::time_point now = fc::time_point::now();
|
fc::time_point now = fc::time_point::now();
|
||||||
|
|
@ -245,31 +271,19 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop()
|
||||||
{
|
{
|
||||||
schedule_heartbeat_loop();
|
schedule_heartbeat_loop();
|
||||||
chain::database& d = plugin.database();
|
chain::database& d = plugin.database();
|
||||||
chain::son_id_type son_id = *(_sons.begin());
|
|
||||||
const auto& idx = d.get_index_type<chain::son_index>().indices().get<by_id>();
|
|
||||||
auto son_obj = idx.find( son_id );
|
|
||||||
if(son_obj == idx.end())
|
|
||||||
return;
|
|
||||||
const chain::global_property_object& gpo = d.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 = std::find(active_son_ids.begin(), active_son_ids.end(), son_id);
|
for (son_id_type son_id : _sons) {
|
||||||
if(it != active_son_ids.end() || son_obj->status == chain::son_status::in_maintenance) {
|
if (is_active_son(son_id) || get_son_object(son_id).status == chain::son_status::in_maintenance) {
|
||||||
ilog("peerplays_sidechain_plugin: sending heartbeat");
|
|
||||||
|
ilog("peerplays_sidechain_plugin: sending heartbeat for SON ${son}", ("son", son_id));
|
||||||
chain::son_heartbeat_operation op;
|
chain::son_heartbeat_operation op;
|
||||||
op.owner_account = son_obj->son_account;
|
op.owner_account = get_son_object(son_id).son_account;
|
||||||
op.son_id = son_id;
|
op.son_id = son_id;
|
||||||
op.ts = fc::time_point::now() + fc::seconds(0);
|
op.ts = fc::time_point::now() + fc::seconds(0);
|
||||||
chain::signed_transaction trx = d.create_signed_transaction(_private_keys.begin()->second, op);
|
chain::signed_transaction trx = d.create_signed_transaction(plugin.get_private_key(son_id), op);
|
||||||
fc::future<bool> fut = fc::async( [&](){
|
fc::future<bool> fut = fc::async( [&](){
|
||||||
try {
|
try {
|
||||||
d.push_transaction(trx);
|
d.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||||
if(plugin.app().p2p_node())
|
if(plugin.app().p2p_node())
|
||||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -280,6 +294,7 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop()
|
||||||
});
|
});
|
||||||
fut.wait(fc::seconds(10));
|
fut.wait(fc::seconds(10));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::create_son_down_proposals()
|
void peerplays_sidechain_plugin_impl::create_son_down_proposals()
|
||||||
|
|
@ -323,10 +338,10 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals()
|
||||||
((fc::time_point::now() - last_active_ts) > fc::microseconds(down_threshold))) {
|
((fc::time_point::now() - last_active_ts) > fc::microseconds(down_threshold))) {
|
||||||
ilog("peerplays_sidechain_plugin: 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))));
|
ilog("peerplays_sidechain_plugin: 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::proposal_create_operation op = create_son_down_proposal(son_inf.son_id, last_active_ts);
|
||||||
chain::signed_transaction trx = d.create_signed_transaction(_private_keys.begin()->second, op);
|
chain::signed_transaction trx = d.create_signed_transaction(plugin.get_private_key(son_obj->signing_key), op);
|
||||||
fc::future<bool> fut = fc::async( [&](){
|
fc::future<bool> fut = fc::async( [&](){
|
||||||
try {
|
try {
|
||||||
d.push_transaction(trx);
|
d.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||||
if(plugin.app().p2p_node())
|
if(plugin.app().p2p_node())
|
||||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -347,13 +362,6 @@ void peerplays_sidechain_plugin_impl::recreate_primary_wallet()
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::process_deposits() {
|
void peerplays_sidechain_plugin_impl::process_deposits() {
|
||||||
|
|
||||||
// Account who issues tokens to the user who made deposit
|
|
||||||
account_id_type pay_from = GRAPHENE_NULL_ACCOUNT;
|
|
||||||
const auto& account_idx = plugin.database().get_index_type<account_index>().indices().get<by_name>();
|
|
||||||
const auto& account_itr = account_idx.find("nathan");
|
|
||||||
if (account_itr != account_idx.end())
|
|
||||||
pay_from = (*account_itr).id;
|
|
||||||
|
|
||||||
const auto& idx = plugin.database().get_index_type<son_wallet_transfer_index>().indices().get<by_processed>();
|
const auto& idx = plugin.database().get_index_type<son_wallet_transfer_index>().indices().get<by_processed>();
|
||||||
const auto& idx_range = idx.equal_range(false);
|
const auto& idx_range = idx.equal_range(false);
|
||||||
|
|
||||||
|
|
@ -362,23 +370,32 @@ void peerplays_sidechain_plugin_impl::process_deposits() {
|
||||||
|
|
||||||
const chain::global_property_object& gpo = plugin.database().get_global_properties();
|
const chain::global_property_object& gpo = plugin.database().get_global_properties();
|
||||||
|
|
||||||
transfer_operation op;
|
for (son_id_type son_id : plugin.get_sons()) {
|
||||||
op.from = pay_from;
|
if (plugin.is_active_son(son_id)) {
|
||||||
op.to = swto.peerplays_from;
|
|
||||||
op.amount = asset(swto.sidechain_amount); // For Bitcoin, the exchange rate is 1:1, for others, get the exchange rate from market
|
son_wallet_transfer_process_operation p_op;
|
||||||
|
p_op.payer = gpo.parameters.get_son_btc_account_id();
|
||||||
|
p_op.son_wallet_transfer_id = swto.id;
|
||||||
|
|
||||||
proposal_create_operation proposal_op;
|
proposal_create_operation proposal_op;
|
||||||
proposal_op.fee_paying_account = plugin.get_son_object().son_account;
|
proposal_op.fee_paying_account = plugin.get_son_object(son_id).son_account;
|
||||||
proposal_op.proposed_ops.push_back( op_wrapper( op ) );
|
proposal_op.proposed_ops.emplace_back( op_wrapper( p_op ) );
|
||||||
uint32_t lifetime = ( gpo.parameters.block_interval * gpo.active_witnesses.size() ) * 3;
|
uint32_t lifetime = ( gpo.parameters.block_interval * gpo.active_witnesses.size() ) * 3;
|
||||||
proposal_op.expiration_time = time_point_sec( plugin.database().head_block_time().sec_since_epoch() + lifetime );
|
proposal_op.expiration_time = time_point_sec( plugin.database().head_block_time().sec_since_epoch() + lifetime );
|
||||||
|
|
||||||
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_keys().begin()->second, proposal_op);
|
ilog("sidechain_net_handler: sending proposal for transfer operation ${swto} by ${son}", ("swto", swto.id) ("son", son_id));
|
||||||
|
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(son_id), proposal_op);
|
||||||
|
trx.validate();
|
||||||
|
ilog("sidechain_net_handler: transaction validated ${swto} by ${son}", ("swto", swto.id) ("son", son_id));
|
||||||
try {
|
try {
|
||||||
plugin.database().push_transaction(trx);
|
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));
|
||||||
} catch(fc::exception e){
|
} catch(fc::exception e){
|
||||||
ilog("sidechain_net_handler: sending proposal for transfer operation failed with exception ${e}",("e", e.what()));
|
ilog("sidechain_net_handler: sending proposal for transfer operation failed with exception ${e}",("e", e.what()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -388,16 +405,17 @@ void peerplays_sidechain_plugin_impl::process_deposits() {
|
||||||
void peerplays_sidechain_plugin_impl::on_block_applied( const signed_block& b )
|
void peerplays_sidechain_plugin_impl::on_block_applied( const signed_block& b )
|
||||||
{
|
{
|
||||||
chain::database& d = plugin.database();
|
chain::database& d = plugin.database();
|
||||||
chain::son_id_type my_son_id = *(_sons.begin());
|
|
||||||
const chain::global_property_object& gpo = d.get_global_properties();
|
const chain::global_property_object& gpo = d.get_global_properties();
|
||||||
bool latest_block = ((fc::time_point::now() - b.timestamp) < fc::microseconds(gpo.parameters.block_interval * 1000000));
|
bool latest_block = ((fc::time_point::now() - b.timestamp) < fc::microseconds(gpo.parameters.block_interval * 1000000));
|
||||||
// Return if there are no active SONs
|
|
||||||
if(gpo.active_sons.size() <= 0 || !latest_block) {
|
if(gpo.active_sons.size() <= 0 || !latest_block) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chain::son_id_type next_son_id = d.get_scheduled_son(1);
|
chain::son_id_type next_son_id = d.get_scheduled_son(1);
|
||||||
if(next_son_id == my_son_id) {
|
ilog("peerplays_sidechain_plugin_impl: Scheduled SON ${son}",("son", next_son_id));
|
||||||
|
|
||||||
|
// check if we control scheduled SON
|
||||||
|
if( _sons.find( next_son_id ) != _sons.end() ) {
|
||||||
|
|
||||||
create_son_down_proposals();
|
create_son_down_proposals();
|
||||||
|
|
||||||
|
|
@ -412,35 +430,18 @@ void peerplays_sidechain_plugin_impl::on_block_applied( const signed_block& b )
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::on_objects_new(const vector<object_id_type>& new_object_ids)
|
void peerplays_sidechain_plugin_impl::on_objects_new(const vector<object_id_type>& new_object_ids)
|
||||||
{
|
{
|
||||||
chain::database& d = plugin.database();
|
|
||||||
chain::son_id_type my_son_id = *(_sons.begin());
|
|
||||||
const chain::global_property_object& gpo = d.get_global_properties();
|
|
||||||
const auto& idx = d.get_index_type<chain::son_index>().indices().get<by_id>();
|
|
||||||
auto son_obj = idx.find( my_son_id );
|
|
||||||
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 = std::find(active_son_ids.begin(), active_son_ids.end(), my_son_id);
|
auto approve_proposal = [ & ]( const chain::son_id_type& son_id, const chain::proposal_id_type& proposal_id )
|
||||||
if(it == active_son_ids.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto approve_proposal = [ & ]( const chain::proposal_id_type& id )
|
|
||||||
{
|
{
|
||||||
ilog("peerplays_sidechain_plugin: sending approval for ${t} from ${s}",("t",std::string(object_id_type(id)))("s",std::string(object_id_type(my_son_id))));
|
ilog("peerplays_sidechain_plugin: sending approval for ${p} from ${s}", ("p", proposal_id) ("s", son_id));
|
||||||
chain::proposal_update_operation puo;
|
chain::proposal_update_operation puo;
|
||||||
puo.fee_paying_account = son_obj->son_account;
|
puo.fee_paying_account = get_son_object(son_id).son_account;
|
||||||
puo.proposal = id;
|
puo.proposal = proposal_id;
|
||||||
puo.active_approvals_to_add = { son_obj->son_account };
|
puo.active_approvals_to_add = { get_son_object(son_id).son_account };
|
||||||
chain::signed_transaction trx = d.create_signed_transaction(_private_keys.begin()->second, puo);
|
chain::signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(son_id), puo);
|
||||||
fc::future<bool> fut = fc::async( [&](){
|
fc::future<bool> fut = fc::async( [&](){
|
||||||
try {
|
try {
|
||||||
d.push_transaction(trx);
|
plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||||
if(plugin.app().p2p_node())
|
if(plugin.app().p2p_node())
|
||||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -454,25 +455,42 @@ void peerplays_sidechain_plugin_impl::on_objects_new(const vector<object_id_type
|
||||||
|
|
||||||
for(auto object_id: new_object_ids) {
|
for(auto object_id: new_object_ids) {
|
||||||
if( object_id.is<chain::proposal_object>() ) {
|
if( object_id.is<chain::proposal_object>() ) {
|
||||||
const object* obj = d.find_object(object_id);
|
|
||||||
|
for (son_id_type son_id : _sons) {
|
||||||
|
if (!is_active_son(son_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const object* obj = plugin.database().find_object(object_id);
|
||||||
const chain::proposal_object* proposal = dynamic_cast<const chain::proposal_object*>(obj);
|
const chain::proposal_object* proposal = dynamic_cast<const chain::proposal_object*>(obj);
|
||||||
if(proposal == nullptr || (proposal->available_active_approvals.find(son_obj->son_account) != proposal->available_active_approvals.end())) {
|
|
||||||
return;
|
if(proposal == nullptr || (proposal->available_active_approvals.find(get_son_object(son_id).son_account) != proposal->available_active_approvals.end())) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(proposal->proposed_transaction.operations.size() == 1
|
if(proposal->proposed_transaction.operations.size() == 1
|
||||||
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_report_down_operation>::value) {
|
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_report_down_operation>::value) {
|
||||||
approve_proposal( proposal->id );
|
approve_proposal( son_id, proposal->id );
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(proposal->proposed_transaction.operations.size() == 1
|
if(proposal->proposed_transaction.operations.size() == 1
|
||||||
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_update_operation>::value) {
|
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_update_operation>::value) {
|
||||||
approve_proposal( proposal->id );
|
approve_proposal( son_id, proposal->id );
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(proposal->proposed_transaction.operations.size() == 1
|
if(proposal->proposed_transaction.operations.size() == 1
|
||||||
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::transfer_operation>::value) {
|
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_transfer_create_operation>::value) {
|
||||||
approve_proposal( proposal->id );
|
approve_proposal( son_id, proposal->id );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(proposal->proposed_transaction.operations.size() == 1
|
||||||
|
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_transfer_process_operation>::value) {
|
||||||
|
approve_proposal( son_id, proposal->id );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -515,19 +533,19 @@ void peerplays_sidechain_plugin::plugin_startup()
|
||||||
my->plugin_startup();
|
my->plugin_startup();
|
||||||
}
|
}
|
||||||
|
|
||||||
son_id_type peerplays_sidechain_plugin::get_son_id()
|
std::set<chain::son_id_type>& peerplays_sidechain_plugin::get_sons()
|
||||||
{
|
{
|
||||||
return my->get_son_id();
|
return my->get_sons();
|
||||||
}
|
}
|
||||||
|
|
||||||
son_object peerplays_sidechain_plugin::get_son_object()
|
son_object peerplays_sidechain_plugin::get_son_object(son_id_type son_id)
|
||||||
{
|
{
|
||||||
return my->get_son_object();
|
return my->get_son_object(son_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peerplays_sidechain_plugin::is_active_son()
|
bool peerplays_sidechain_plugin::is_active_son(son_id_type son_id)
|
||||||
{
|
{
|
||||||
return my->is_active_son();
|
return my->is_active_son(son_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<chain::public_key_type, fc::ecc::private_key>& peerplays_sidechain_plugin::get_private_keys()
|
std::map<chain::public_key_type, fc::ecc::private_key>& peerplays_sidechain_plugin::get_private_keys()
|
||||||
|
|
@ -535,5 +553,15 @@ std::map<chain::public_key_type, fc::ecc::private_key>& peerplays_sidechain_plug
|
||||||
return my->get_private_keys();
|
return my->get_private_keys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fc::ecc::private_key peerplays_sidechain_plugin::get_private_key(son_id_type son_id)
|
||||||
|
{
|
||||||
|
return my->get_private_key(son_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fc::ecc::private_key peerplays_sidechain_plugin::get_private_key(chain::public_key_type public_key)
|
||||||
|
{
|
||||||
|
return my->get_private_key(public_key);
|
||||||
|
}
|
||||||
|
|
||||||
} } // graphene::peerplays_sidechain
|
} } // graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ std::vector<std::string> sidechain_net_handler::get_sidechain_addresses() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_data& sed) {
|
void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_data& sed) {
|
||||||
ilog( __FUNCTION__ );
|
|
||||||
ilog( "sidechain_event_data:" );
|
ilog( "sidechain_event_data:" );
|
||||||
ilog( " timestamp: ${timestamp}", ( "timestamp", sed.timestamp ) );
|
ilog( " timestamp: ${timestamp}", ( "timestamp", sed.timestamp ) );
|
||||||
ilog( " sidechain: ${sidechain}", ( "sidechain", sed.sidechain ) );
|
ilog( " sidechain: ${sidechain}", ( "sidechain", sed.sidechain ) );
|
||||||
|
|
@ -54,11 +53,6 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
|
||||||
ilog( " peerplays_from: ${peerplays_from}", ( "peerplays_from", sed.peerplays_from ) );
|
ilog( " peerplays_from: ${peerplays_from}", ( "peerplays_from", sed.peerplays_from ) );
|
||||||
ilog( " peerplays_to: ${peerplays_to}", ( "peerplays_to", sed.peerplays_to ) );
|
ilog( " peerplays_to: ${peerplays_to}", ( "peerplays_to", sed.peerplays_to ) );
|
||||||
|
|
||||||
if (!plugin.is_active_son()) {
|
|
||||||
ilog( " !!! SON is not active and not processing sidechain events...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const chain::global_property_object& gpo = database.get_global_properties();
|
const chain::global_property_object& gpo = database.get_global_properties();
|
||||||
|
|
||||||
son_wallet_transfer_create_operation op;
|
son_wallet_transfer_create_operation op;
|
||||||
|
|
@ -72,18 +66,26 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
|
||||||
op.sidechain_amount = sed.sidechain_amount;
|
op.sidechain_amount = sed.sidechain_amount;
|
||||||
op.peerplays_from = sed.peerplays_from;
|
op.peerplays_from = sed.peerplays_from;
|
||||||
op.peerplays_to = sed.peerplays_to;
|
op.peerplays_to = sed.peerplays_to;
|
||||||
|
op.peerplays_amount = asset(sed.sidechain_amount / 1000); // For Bitcoin, the exchange rate is 1:1, for others, get the exchange rate from market
|
||||||
|
|
||||||
|
for (son_id_type son_id : plugin.get_sons()) {
|
||||||
|
if (plugin.is_active_son(son_id)) {
|
||||||
proposal_create_operation proposal_op;
|
proposal_create_operation proposal_op;
|
||||||
proposal_op.fee_paying_account = plugin.get_son_object().son_account;
|
proposal_op.fee_paying_account = plugin.get_son_object(son_id).son_account;
|
||||||
proposal_op.proposed_ops.push_back( op_wrapper( op ) );
|
proposal_op.proposed_ops.emplace_back( op_wrapper( op ) );
|
||||||
uint32_t lifetime = ( gpo.parameters.block_interval * gpo.active_witnesses.size() ) * 3;
|
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.expiration_time = time_point_sec( database.head_block_time().sec_since_epoch() + lifetime );
|
||||||
|
|
||||||
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_keys().begin()->second, proposal_op);
|
ilog("sidechain_net_handler: sending proposal for son wallet transfer create operation by ${son}", ("son", son_id));
|
||||||
|
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(son_id), proposal_op);
|
||||||
try {
|
try {
|
||||||
database.push_transaction(trx);
|
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));
|
||||||
} catch(fc::exception e){
|
} catch(fc::exception e){
|
||||||
ilog("sidechain_net_handler: sending proposal for son wallet transfer create operation failed with exception ${e}",("e", e.what()));
|
ilog("sidechain_net_handler: sending proposal for son wallet transfer create operation by ${son} failed with exception ${e}", ("son", son_id) ("e", e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -277,7 +277,6 @@ void sidechain_net_handler_bitcoin::recreate_primary_wallet() {
|
||||||
boost::property_tree::ptree pt;
|
boost::property_tree::ptree pt;
|
||||||
boost::property_tree::read_json( ss, pt );
|
boost::property_tree::read_json( ss, pt );
|
||||||
if( pt.count( "error" ) && pt.get_child( "error" ).empty() ) {
|
if( pt.count( "error" ) && pt.get_child( "error" ).empty() ) {
|
||||||
ilog(__FUNCTION__);
|
|
||||||
|
|
||||||
std::stringstream res;
|
std::stringstream res;
|
||||||
boost::property_tree::json_parser::write_json(res, pt.get_child("result"));
|
boost::property_tree::json_parser::write_json(res, pt.get_child("result"));
|
||||||
|
|
@ -288,21 +287,25 @@ void sidechain_net_handler_bitcoin::recreate_primary_wallet() {
|
||||||
op.sidechain = sidechain_type::bitcoin;
|
op.sidechain = sidechain_type::bitcoin;
|
||||||
op.address = res.str();
|
op.address = res.str();
|
||||||
|
|
||||||
|
for (son_id_type son_id : plugin.get_sons()) {
|
||||||
proposal_create_operation proposal_op;
|
proposal_create_operation proposal_op;
|
||||||
proposal_op.fee_paying_account = plugin.get_son_object().son_account;
|
proposal_op.fee_paying_account = plugin.get_son_object(son_id).son_account;
|
||||||
proposal_op.proposed_ops.push_back( op_wrapper( op ) );
|
proposal_op.proposed_ops.emplace_back( op_wrapper( op ) );
|
||||||
uint32_t lifetime = ( gpo.parameters.block_interval * gpo.active_witnesses.size() ) * 3;
|
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.expiration_time = time_point_sec( database.head_block_time().sec_since_epoch() + lifetime );
|
||||||
|
|
||||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_keys().begin()->second, proposal_op);
|
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(son_id), proposal_op);
|
||||||
try {
|
try {
|
||||||
database.push_transaction(trx);
|
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));
|
||||||
} catch(fc::exception e){
|
} catch(fc::exception e){
|
||||||
ilog("sidechain_net_handler: sending proposal for son wallet update operation failed with exception ${e}",("e", e.what()));
|
ilog("sidechain_net_handler: sending proposal for son wallet update operation failed with exception ${e}",("e", e.what()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sidechain_net_handler_bitcoin::connection_is_not_defined() const
|
bool sidechain_net_handler_bitcoin::connection_is_not_defined() const
|
||||||
|
|
@ -334,11 +337,6 @@ void sidechain_net_handler_bitcoin::handle_event( const std::string& event_data
|
||||||
ilog("peerplays sidechain plugin: sidechain_net_handler_bitcoin::handle_event");
|
ilog("peerplays sidechain plugin: sidechain_net_handler_bitcoin::handle_event");
|
||||||
ilog(" event_data: ${event_data}", ("event_data", event_data));
|
ilog(" event_data: ${event_data}", ("event_data", event_data));
|
||||||
|
|
||||||
if (!plugin.is_active_son()) {
|
|
||||||
ilog(" !!! SON is not active and not processing sidechain events...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string block = bitcoin_client->receive_full_block( event_data );
|
std::string block = bitcoin_client->receive_full_block( event_data );
|
||||||
if( block != "" ) {
|
if( block != "" ) {
|
||||||
const auto& vins = extract_info_from_block( block );
|
const auto& vins = extract_info_from_block( block );
|
||||||
|
|
@ -363,7 +361,7 @@ void sidechain_net_handler_bitcoin::handle_event( const std::string& event_data
|
||||||
sed.sidechain_to = v.address;
|
sed.sidechain_to = v.address;
|
||||||
sed.sidechain_amount = v.out.amount;
|
sed.sidechain_amount = v.out.amount;
|
||||||
sed.peerplays_from = addr_itr->sidechain_address_account;
|
sed.peerplays_from = addr_itr->sidechain_address_account;
|
||||||
sed.peerplays_to = GRAPHENE_SON_ACCOUNT_ID;
|
sed.peerplays_to = GRAPHENE_SON_ACCOUNT;
|
||||||
sidechain_event_data_received(sed);
|
sidechain_event_data_received(sed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,12 @@ sidechain_net_manager::sidechain_net_manager(peerplays_sidechain_plugin& _plugin
|
||||||
plugin(_plugin),
|
plugin(_plugin),
|
||||||
database(_plugin.database())
|
database(_plugin.database())
|
||||||
{
|
{
|
||||||
ilog(__FUNCTION__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sidechain_net_manager::~sidechain_net_manager() {
|
sidechain_net_manager::~sidechain_net_manager() {
|
||||||
ilog(__FUNCTION__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sidechain_net_manager::create_handler(peerplays_sidechain::sidechain_type sidechain, const boost::program_options::variables_map& options) {
|
bool sidechain_net_manager::create_handler(peerplays_sidechain::sidechain_type sidechain, const boost::program_options::variables_map& options) {
|
||||||
ilog(__FUNCTION__);
|
|
||||||
|
|
||||||
bool ret_val = false;
|
bool ret_val = false;
|
||||||
|
|
||||||
|
|
|
||||||
272
tests/tests/history_api_tests.cpp
Normal file → Executable file
272
tests/tests/history_api_tests.cpp
Normal file → Executable file
|
|
@ -407,143 +407,143 @@ BOOST_AUTO_TEST_CASE(get_account_history_additional) {
|
||||||
} FC_LOG_AND_RETHROW()
|
} FC_LOG_AND_RETHROW()
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(track_account) {
|
//BOOST_AUTO_TEST_CASE(track_account) {
|
||||||
try {
|
// try {
|
||||||
graphene::app::history_api hist_api(app);
|
// graphene::app::history_api hist_api(app);
|
||||||
|
//
|
||||||
|
// // account_id_type() is not tracked
|
||||||
|
//
|
||||||
|
// // account_id_type() creates alice(not tracked account)
|
||||||
|
// const account_object& alice = create_account("alice");
|
||||||
|
// auto alice_id = alice.id;
|
||||||
|
//
|
||||||
|
// //account_id_type() creates some ops
|
||||||
|
// create_bitasset("CNY", account_id_type());
|
||||||
|
// create_bitasset("USD", account_id_type());
|
||||||
|
//
|
||||||
|
// // account_id_type() creates dan(account tracked)
|
||||||
|
// const account_object& dan = create_account("dan");
|
||||||
|
// auto dan_id = dan.id;
|
||||||
|
//
|
||||||
|
// // dan makes 1 op
|
||||||
|
// create_bitasset("EUR", dan_id);
|
||||||
|
//
|
||||||
|
// generate_block( ~database::skip_fork_db );
|
||||||
|
//
|
||||||
|
// // anything against account_id_type() should be {}
|
||||||
|
// vector<operation_history_object> histories =
|
||||||
|
// hist_api.get_account_history(account_id_type(), operation_history_id_type(0), 10, operation_history_id_type(0));
|
||||||
|
// BOOST_CHECK_EQUAL(histories.size(), 0u);
|
||||||
|
// histories = hist_api.get_account_history(account_id_type(), operation_history_id_type(1), 10, operation_history_id_type(0));
|
||||||
|
// BOOST_CHECK_EQUAL(histories.size(), 0u);
|
||||||
|
// histories = hist_api.get_account_history(account_id_type(), operation_history_id_type(1), 1, operation_history_id_type(2));
|
||||||
|
// BOOST_CHECK_EQUAL(histories.size(), 0u);
|
||||||
|
//
|
||||||
|
// // anything against alice should be {}
|
||||||
|
// histories = hist_api.get_account_history(alice_id, operation_history_id_type(0), 10, operation_history_id_type(0));
|
||||||
|
// BOOST_CHECK_EQUAL(histories.size(), 0u);
|
||||||
|
// histories = hist_api.get_account_history(alice_id, operation_history_id_type(1), 10, operation_history_id_type(0));
|
||||||
|
// BOOST_CHECK_EQUAL(histories.size(), 0u);
|
||||||
|
// histories = hist_api.get_account_history(alice_id, operation_history_id_type(1), 1, operation_history_id_type(2));
|
||||||
|
// BOOST_CHECK_EQUAL(histories.size(), 0u);
|
||||||
|
//
|
||||||
|
// // dan should have history
|
||||||
|
// histories = hist_api.get_account_history(dan_id, operation_history_id_type(0), 10, operation_history_id_type(0));
|
||||||
|
// BOOST_CHECK_EQUAL(histories.size(), 2u);
|
||||||
|
// BOOST_CHECK_EQUAL(histories[0].id.instance(), 4u);
|
||||||
|
// BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u);
|
||||||
|
//
|
||||||
|
// // create more ops, starting with an untracked account
|
||||||
|
// create_bitasset( "BTC", account_id_type() );
|
||||||
|
// create_bitasset( "GBP", dan_id );
|
||||||
|
//
|
||||||
|
// generate_block( ~database::skip_fork_db );
|
||||||
|
//
|
||||||
|
// histories = hist_api.get_account_history(dan_id, operation_history_id_type(0), 10, operation_history_id_type(0));
|
||||||
|
// BOOST_CHECK_EQUAL(histories.size(), 3u);
|
||||||
|
// BOOST_CHECK_EQUAL(histories[0].id.instance(), 6u);
|
||||||
|
// BOOST_CHECK_EQUAL(histories[1].id.instance(), 4u);
|
||||||
|
// BOOST_CHECK_EQUAL(histories[2].id.instance(), 3u);
|
||||||
|
//
|
||||||
|
// db.pop_block();
|
||||||
|
//
|
||||||
|
// // Try again, should result in same object IDs
|
||||||
|
// create_bitasset( "BTC", account_id_type() );
|
||||||
|
// create_bitasset( "GBP", dan_id );
|
||||||
|
//
|
||||||
|
// generate_block();
|
||||||
|
//
|
||||||
|
// histories = hist_api.get_account_history(dan_id, operation_history_id_type(0), 10, operation_history_id_type(0));
|
||||||
|
// BOOST_CHECK_EQUAL(histories.size(), 3u);
|
||||||
|
// BOOST_CHECK_EQUAL(histories[0].id.instance(), 6u);
|
||||||
|
// BOOST_CHECK_EQUAL(histories[1].id.instance(), 4u);
|
||||||
|
// BOOST_CHECK_EQUAL(histories[2].id.instance(), 3u);
|
||||||
|
// } catch (fc::exception &e) {
|
||||||
|
// edump((e.to_detail_string()));
|
||||||
|
// throw;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
// account_id_type() is not tracked
|
//BOOST_AUTO_TEST_CASE(track_account2) {
|
||||||
|
// try {
|
||||||
// account_id_type() creates alice(not tracked account)
|
// graphene::app::history_api hist_api(app);
|
||||||
const account_object& alice = create_account("alice");
|
//
|
||||||
auto alice_id = alice.id;
|
// // account_id_type() is tracked
|
||||||
|
//
|
||||||
//account_id_type() creates some ops
|
// // account_id_type() creates alice(tracked account)
|
||||||
create_bitasset("CNY", account_id_type());
|
// const account_object& alice = create_account("alice");
|
||||||
create_bitasset("USD", account_id_type());
|
// auto alice_id = alice.id;
|
||||||
|
//
|
||||||
// account_id_type() creates dan(account tracked)
|
// //account_id_type() creates some ops
|
||||||
const account_object& dan = create_account("dan");
|
// create_bitasset("CNY", account_id_type());
|
||||||
auto dan_id = dan.id;
|
// create_bitasset("USD", account_id_type());
|
||||||
|
//
|
||||||
// dan makes 1 op
|
// // alice makes 1 op
|
||||||
create_bitasset("EUR", dan_id);
|
// create_bitasset("EUR", alice_id);
|
||||||
|
//
|
||||||
generate_block( ~database::skip_fork_db );
|
// // account_id_type() creates dan(account not tracked)
|
||||||
|
// const account_object& dan = create_account("dan");
|
||||||
// anything against account_id_type() should be {}
|
// auto dan_id = dan.id;
|
||||||
vector<operation_history_object> histories =
|
//
|
||||||
hist_api.get_account_history(account_id_type(), operation_history_id_type(0), 10, operation_history_id_type(0));
|
// generate_block();
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 0u);
|
//
|
||||||
histories = hist_api.get_account_history(account_id_type(), operation_history_id_type(1), 10, operation_history_id_type(0));
|
// // all account_id_type() should have 4 ops {4,2,1,0}
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 0u);
|
// vector<operation_history_object> histories = hist_api.get_account_history(account_id_type(), operation_history_id_type(0), 10, operation_history_id_type(0));
|
||||||
histories = hist_api.get_account_history(account_id_type(), operation_history_id_type(1), 1, operation_history_id_type(2));
|
// BOOST_CHECK_EQUAL(histories.size(), 4u);
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 0u);
|
// BOOST_CHECK_EQUAL(histories[0].id.instance(), 4u);
|
||||||
|
// BOOST_CHECK_EQUAL(histories[1].id.instance(), 2u);
|
||||||
// anything against alice should be {}
|
// BOOST_CHECK_EQUAL(histories[2].id.instance(), 1u);
|
||||||
histories = hist_api.get_account_history(alice_id, operation_history_id_type(0), 10, operation_history_id_type(0));
|
// BOOST_CHECK_EQUAL(histories[3].id.instance(), 0u);
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 0u);
|
//
|
||||||
histories = hist_api.get_account_history(alice_id, operation_history_id_type(1), 10, operation_history_id_type(0));
|
// // all alice account should have 2 ops {3, 0}
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 0u);
|
// histories = hist_api.get_account_history(alice_id, operation_history_id_type(0), 10, operation_history_id_type(0));
|
||||||
histories = hist_api.get_account_history(alice_id, operation_history_id_type(1), 1, operation_history_id_type(2));
|
// BOOST_CHECK_EQUAL(histories.size(), 2u);
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 0u);
|
// BOOST_CHECK_EQUAL(histories[0].id.instance(), 3u);
|
||||||
|
// BOOST_CHECK_EQUAL(histories[1].id.instance(), 0u);
|
||||||
// dan should have history
|
//
|
||||||
histories = hist_api.get_account_history(dan_id, operation_history_id_type(0), 10, operation_history_id_type(0));
|
// // alice first op should be {0}
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 2u);
|
// histories = hist_api.get_account_history(alice_id, operation_history_id_type(0), 1, operation_history_id_type(1));
|
||||||
BOOST_CHECK_EQUAL(histories[0].id.instance(), 4u);
|
// BOOST_CHECK_EQUAL(histories.size(), 1u);
|
||||||
BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u);
|
// BOOST_CHECK_EQUAL(histories[0].id.instance(), 0u);
|
||||||
|
//
|
||||||
// create more ops, starting with an untracked account
|
// // alice second op should be {3}
|
||||||
create_bitasset( "BTC", account_id_type() );
|
// histories = hist_api.get_account_history(alice_id, operation_history_id_type(1), 1, operation_history_id_type(0));
|
||||||
create_bitasset( "GBP", dan_id );
|
// BOOST_CHECK_EQUAL(histories.size(), 1u);
|
||||||
|
// BOOST_CHECK_EQUAL(histories[0].id.instance(), 3u);
|
||||||
generate_block( ~database::skip_fork_db );
|
//
|
||||||
|
// // anything against dan should be {}
|
||||||
histories = hist_api.get_account_history(dan_id, operation_history_id_type(0), 10, operation_history_id_type(0));
|
// histories = hist_api.get_account_history(dan_id, operation_history_id_type(0), 10, operation_history_id_type(0));
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 3u);
|
// BOOST_CHECK_EQUAL(histories.size(), 0u);
|
||||||
BOOST_CHECK_EQUAL(histories[0].id.instance(), 6u);
|
// histories = hist_api.get_account_history(dan_id, operation_history_id_type(1), 10, operation_history_id_type(0));
|
||||||
BOOST_CHECK_EQUAL(histories[1].id.instance(), 4u);
|
// BOOST_CHECK_EQUAL(histories.size(), 0u);
|
||||||
BOOST_CHECK_EQUAL(histories[2].id.instance(), 3u);
|
// histories = hist_api.get_account_history(dan_id, operation_history_id_type(1), 1, operation_history_id_type(2));
|
||||||
|
// BOOST_CHECK_EQUAL(histories.size(), 0u);
|
||||||
db.pop_block();
|
//
|
||||||
|
// } catch (fc::exception &e) {
|
||||||
// Try again, should result in same object IDs
|
// edump((e.to_detail_string()));
|
||||||
create_bitasset( "BTC", account_id_type() );
|
// throw;
|
||||||
create_bitasset( "GBP", dan_id );
|
// }
|
||||||
|
//}
|
||||||
generate_block();
|
|
||||||
|
|
||||||
histories = hist_api.get_account_history(dan_id, operation_history_id_type(0), 10, operation_history_id_type(0));
|
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 3u);
|
|
||||||
BOOST_CHECK_EQUAL(histories[0].id.instance(), 6u);
|
|
||||||
BOOST_CHECK_EQUAL(histories[1].id.instance(), 4u);
|
|
||||||
BOOST_CHECK_EQUAL(histories[2].id.instance(), 3u);
|
|
||||||
} catch (fc::exception &e) {
|
|
||||||
edump((e.to_detail_string()));
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(track_account2) {
|
|
||||||
try {
|
|
||||||
graphene::app::history_api hist_api(app);
|
|
||||||
|
|
||||||
// account_id_type() is tracked
|
|
||||||
|
|
||||||
// account_id_type() creates alice(tracked account)
|
|
||||||
const account_object& alice = create_account("alice");
|
|
||||||
auto alice_id = alice.id;
|
|
||||||
|
|
||||||
//account_id_type() creates some ops
|
|
||||||
create_bitasset("CNY", account_id_type());
|
|
||||||
create_bitasset("USD", account_id_type());
|
|
||||||
|
|
||||||
// alice makes 1 op
|
|
||||||
create_bitasset("EUR", alice_id);
|
|
||||||
|
|
||||||
// account_id_type() creates dan(account not tracked)
|
|
||||||
const account_object& dan = create_account("dan");
|
|
||||||
auto dan_id = dan.id;
|
|
||||||
|
|
||||||
generate_block();
|
|
||||||
|
|
||||||
// all account_id_type() should have 4 ops {4,2,1,0}
|
|
||||||
vector<operation_history_object> histories = hist_api.get_account_history(account_id_type(), operation_history_id_type(0), 10, operation_history_id_type(0));
|
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 4u);
|
|
||||||
BOOST_CHECK_EQUAL(histories[0].id.instance(), 4u);
|
|
||||||
BOOST_CHECK_EQUAL(histories[1].id.instance(), 2u);
|
|
||||||
BOOST_CHECK_EQUAL(histories[2].id.instance(), 1u);
|
|
||||||
BOOST_CHECK_EQUAL(histories[3].id.instance(), 0u);
|
|
||||||
|
|
||||||
// all alice account should have 2 ops {3, 0}
|
|
||||||
histories = hist_api.get_account_history(alice_id, operation_history_id_type(0), 10, operation_history_id_type(0));
|
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 2u);
|
|
||||||
BOOST_CHECK_EQUAL(histories[0].id.instance(), 3u);
|
|
||||||
BOOST_CHECK_EQUAL(histories[1].id.instance(), 0u);
|
|
||||||
|
|
||||||
// alice first op should be {0}
|
|
||||||
histories = hist_api.get_account_history(alice_id, operation_history_id_type(0), 1, operation_history_id_type(1));
|
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 1u);
|
|
||||||
BOOST_CHECK_EQUAL(histories[0].id.instance(), 0u);
|
|
||||||
|
|
||||||
// alice second op should be {3}
|
|
||||||
histories = hist_api.get_account_history(alice_id, operation_history_id_type(1), 1, operation_history_id_type(0));
|
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 1u);
|
|
||||||
BOOST_CHECK_EQUAL(histories[0].id.instance(), 3u);
|
|
||||||
|
|
||||||
// anything against dan should be {}
|
|
||||||
histories = hist_api.get_account_history(dan_id, operation_history_id_type(0), 10, operation_history_id_type(0));
|
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 0u);
|
|
||||||
histories = hist_api.get_account_history(dan_id, operation_history_id_type(1), 10, operation_history_id_type(0));
|
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 0u);
|
|
||||||
histories = hist_api.get_account_history(dan_id, operation_history_id_type(1), 1, operation_history_id_type(2));
|
|
||||||
BOOST_CHECK_EQUAL(histories.size(), 0u);
|
|
||||||
|
|
||||||
} catch (fc::exception &e) {
|
|
||||||
edump((e.to_detail_string()));
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(get_account_history_operations) {
|
BOOST_AUTO_TEST_CASE(get_account_history_operations) {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue