Compare commits

...

16 commits

Author SHA1 Message Date
hirunda
983859c997 Add external estimate fee query 2022-10-09 22:45:34 +02:00
hirunda
5318637519 Add external estimate fee query 2022-10-07 01:41:51 +02:00
hirunda
3fa3ff200b Align wallet name config with develop changes 2022-09-27 20:56:13 +02:00
Davor Hirunda
52b40fd6c0 Merge branch 'revert-1a160275' into 'feature/libbitcoin-son'
Revert "Merge branch 'develop' into feature/libbitcoin-son"

See merge request PBSA/peerplays!156
2022-09-23 23:21:17 +00:00
Davor Hirunda
42250d6666 Revert "Merge branch 'develop' into feature/libbitcoin-son" 2022-09-23 23:21:17 +00:00
Davor Hirunda
8fbe62b4cf Merge branch 'revert-f7aab6a8' into 'feature/libbitcoin-son'
Revert "Back importmulti for bitcoind"

See merge request PBSA/peerplays!155
2022-09-23 23:19:31 +00:00
Davor Hirunda
68e944f89a Revert "Back importmulti for bitcoind" 2022-09-23 23:19:31 +00:00
hirunda
f7aab6a8b8 Back importmulti for bitcoind 2022-09-23 01:16:51 +02:00
hirunda
1a16027523 Merge branch 'develop' into feature/libbitcoin-son 2022-09-22 22:49:55 +02:00
hirunda
7b2a3fab97 Libbitcoin client 2022-09-22 21:21:08 +02:00
hirunda
9b047ae703 Resolving bug with vout wrong sequence 2022-09-22 01:21:15 +02:00
hirunda
6b67fe76a8 libbitcoin client and bitcoind 2022-09-20 01:06:33 +02:00
hirunda
6aee0c6f82 Moving json transaction parsing
Moving json transaction parsing in

getrawtransaction and forming btc_tx object
2022-09-09 00:07:53 +02:00
hirunda
a47498f642 libbitcoin client work in progress 2022-09-06 14:12:01 +02:00
serkixenos
789c0547cf Merge branch 'feature/417/Add_support_in_bitcoin_for_P2SH-P2WSH_address_format' into 'feature/libbitcoin-son'
Add support for P2SH-P2WSH address format

See merge request PBSA/peerplays!140
2022-09-05 13:27:27 +00:00
Davor Hirunda
3e0a21bde7 Add support for P2SH-P2WSH address format 2022-09-05 13:27:26 +00:00
71 changed files with 1534 additions and 3666 deletions

View file

@ -5,7 +5,6 @@ add_subdirectory( egenesis )
add_subdirectory( fc ) add_subdirectory( fc )
add_subdirectory( net ) add_subdirectory( net )
add_subdirectory( plugins ) add_subdirectory( plugins )
add_subdirectory( sha3 )
add_subdirectory( time ) add_subdirectory( time )
add_subdirectory( utilities ) add_subdirectory( utilities )
add_subdirectory( wallet ) add_subdirectory( wallet )

View file

@ -917,8 +917,7 @@ void application::initialize(const fc::path &data_dir, const boost::program_opti
wanted.insert("accounts_list"); wanted.insert("accounts_list");
wanted.insert("affiliate_stats"); wanted.insert("affiliate_stats");
} }
if (!wanted.count("delayed_node") && !wanted.count("witness")) // explicitly requested delayed_node functionality suppresses witness functions wanted.insert("witness");
wanted.insert("witness");
wanted.insert("bookie"); wanted.insert("bookie");
int es_ah_conflict_counter = 0; int es_ah_conflict_counter = 0;
@ -950,7 +949,7 @@ void application::startup() {
} }
std::shared_ptr<abstract_plugin> application::get_plugin(const string &name) const { std::shared_ptr<abstract_plugin> application::get_plugin(const string &name) const {
return is_plugin_enabled(name) ? my->_active_plugins[name] : nullptr; return my->_active_plugins[name];
} }
bool application::is_plugin_enabled(const string &name) const { bool application::is_plugin_enabled(const string &name) const {

View file

@ -184,10 +184,6 @@ public:
fc::optional<son_object> get_son_by_account(const std::string account_id_or_name) const; fc::optional<son_object> get_son_by_account(const std::string account_id_or_name) const;
map<string, son_id_type> lookup_son_accounts(const string &lower_bound_name, uint32_t limit) const; map<string, son_id_type> lookup_son_accounts(const string &lower_bound_name, uint32_t limit) const;
uint64_t get_son_count() const; uint64_t get_son_count() const;
flat_map<sidechain_type, vector<son_info>> get_active_sons();
vector<son_info> get_active_sons_by_sidechain(sidechain_type sidechain);
map<sidechain_type, map<son_id_type, string>> get_son_network_status();
map<son_id_type, string> get_son_network_status_by_sidechain(sidechain_type sidechain);
// SON wallets // SON wallets
optional<son_wallet_object> get_active_son_wallet(); optional<son_wallet_object> get_active_son_wallet();
@ -1852,80 +1848,6 @@ uint64_t database_api_impl::get_son_count() const {
return _db.get_index_type<son_index>().indices().size(); return _db.get_index_type<son_index>().indices().size();
} }
flat_map<sidechain_type, vector<son_info>> database_api::get_active_sons() {
return my->get_active_sons();
}
flat_map<sidechain_type, vector<son_info>> database_api_impl::get_active_sons() {
return get_global_properties().active_sons;
}
vector<son_info> database_api::get_active_sons_by_sidechain(sidechain_type sidechain) {
return my->get_active_sons_by_sidechain(sidechain);
}
vector<son_info> database_api_impl::get_active_sons_by_sidechain(sidechain_type sidechain) {
const global_property_object &gpo = get_global_properties();
vector<son_info> result;
if (gpo.active_sons.find(sidechain) != gpo.active_sons.end()) {
result = gpo.active_sons.at(sidechain);
}
return result;
}
map<sidechain_type, map<son_id_type, string>> database_api::get_son_network_status() {
return my->get_son_network_status();
}
map<sidechain_type, map<son_id_type, string>> database_api_impl::get_son_network_status() {
map<sidechain_type, map<son_id_type, string>> result;
for (auto active_sidechain_type : active_sidechain_types) {
result[active_sidechain_type] = get_son_network_status_by_sidechain(active_sidechain_type);
}
return result;
}
map<son_id_type, string> database_api::get_son_network_status_by_sidechain(sidechain_type sidechain) {
return my->get_son_network_status_by_sidechain(sidechain);
}
map<son_id_type, string> database_api_impl::get_son_network_status_by_sidechain(sidechain_type sidechain) {
const global_property_object &gpo = get_global_properties();
map<son_id_type, string> result;
if (gpo.active_sons.find(sidechain) != gpo.active_sons.end()) {
for (const auto si : gpo.active_sons.at(sidechain)) {
const auto son_obj = si.son_id(_db);
const auto sso = son_obj.statistics(_db);
string status;
if (sso.last_active_timestamp.find(sidechain) != sso.last_active_timestamp.end()) {
if (sso.last_active_timestamp.at(sidechain) + fc::seconds(gpo.parameters.son_heartbeat_frequency()) > time_point::now()) {
status = "OK, regular SON heartbeat";
} else {
if (sso.last_active_timestamp.at(sidechain) + 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 = "No heartbeats sent";
}
result[si.son_id] = status;
}
}
return result;
}
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// // // //
// SON Wallets // // SON Wallets //
@ -2163,7 +2085,6 @@ vector<variant> database_api_impl::lookup_vote_ids(const vector<vote_id_type> &v
const auto &against_worker_idx = _db.get_index_type<worker_index>().indices().get<by_vote_against>(); const auto &against_worker_idx = _db.get_index_type<worker_index>().indices().get<by_vote_against>();
const auto &son_bictoin_idx = _db.get_index_type<son_index>().indices().get<by_vote_id_bitcoin>(); 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>(); const auto &son_hive_idx = _db.get_index_type<son_index>().indices().get<by_vote_id_hive>();
const auto &son_ethereum_idx = _db.get_index_type<son_index>().indices().get<by_vote_id_ethereum>();
vector<variant> result; vector<variant> result;
result.reserve(votes.size()); result.reserve(votes.size());
@ -2215,14 +2136,6 @@ vector<variant> database_api_impl::lookup_vote_ids(const vector<vote_id_type> &v
result.emplace_back(variant()); result.emplace_back(variant());
break; break;
} }
case vote_id_type::son_ethereum: {
auto itr = son_ethereum_idx.find(id);
if (itr != son_ethereum_idx.end())
result.emplace_back(variant(*itr, 5));
else
result.emplace_back(variant());
break;
}
case vote_id_type::VOTE_TYPE_COUNT: case vote_id_type::VOTE_TYPE_COUNT:
break; // supress unused enum value warnings break; // supress unused enum value warnings
default: default:
@ -2260,9 +2173,6 @@ votes_info database_api_impl::get_votes(const string &account_name_or_id) const
const auto son_hive_ids = get_votes_objects<son_index, by_vote_id_hive>(votes_ids, 5); const auto son_hive_ids = get_votes_objects<son_index, by_vote_id_hive>(votes_ids, 5);
if (!son_hive_ids.empty()) if (!son_hive_ids.empty())
son_ids[sidechain_type::hive] = std::move(son_hive_ids); son_ids[sidechain_type::hive] = std::move(son_hive_ids);
const auto son_ethereum_ids = get_votes_objects<son_index, by_vote_id_ethereum>(votes_ids, 5);
if (!son_ethereum_ids.empty())
son_ids[sidechain_type::ethereum] = std::move(son_ethereum_ids);
return son_ids; return son_ids;
}(); }();

View file

@ -675,32 +675,6 @@ public:
*/ */
uint64_t get_son_count() const; uint64_t get_son_count() const;
/**
* @brief Get list of active sons
* @return List of active SONs
*/
flat_map<sidechain_type, vector<son_info>> get_active_sons();
/**
* @brief Get list of active sons
* @param sidechain Sidechain type [bitcoin|ethereum|hive]
* @return List of active SONs
*/
vector<son_info> get_active_sons_by_sidechain(sidechain_type sidechain);
/**
* @brief Get SON network status
* @return SON network status description for a given sidechain type
*/
map<sidechain_type, map<son_id_type, string>> get_son_network_status();
/**
* @brief Get SON network status
* @param sidechain Sidechain type [bitcoin|ethereum|hive]
* @return SON network status description for a given sidechain type
*/
map<son_id_type, string> get_son_network_status_by_sidechain(sidechain_type sidechain);
///////////////////////// /////////////////////////
// SON Wallets // // SON Wallets //
///////////////////////// /////////////////////////
@ -1175,10 +1149,6 @@ FC_API(graphene::app::database_api,
(get_son_by_account) (get_son_by_account)
(lookup_son_accounts) (lookup_son_accounts)
(get_son_count) (get_son_count)
(get_active_sons)
(get_active_sons_by_sidechain)
(get_son_network_status)
(get_son_network_status_by_sidechain)
// SON wallets // SON wallets
(get_active_son_wallet) (get_active_son_wallet)

View file

@ -1101,6 +1101,28 @@ void database::init_genesis(const genesis_state_type& genesis_state)
// Initialize witness schedule // Initialize witness schedule
#ifndef NDEBUG
const son_schedule_object& ssohive =
#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( ssohive.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::hive)) );
#ifndef NDEBUG #ifndef NDEBUG
const son_schedule_object& ssobitcoin = const son_schedule_object& ssobitcoin =
#endif #endif
@ -1111,10 +1133,11 @@ void database::init_genesis(const genesis_state_type& genesis_state)
witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV);
auto init_bitcoin_sons = get_global_properties().active_sons.at(sidechain_type::bitcoin); auto init_witnesses = get_global_properties().active_witnesses;
_sso.scheduler = son_scheduler(); _sso.scheduler = son_scheduler();
_sso.scheduler._min_token_count = std::max(int(init_bitcoin_sons.size()) / 2, 1); _sso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1);
_sso.last_scheduling_block = 0; _sso.last_scheduling_block = 0;
@ -1122,48 +1145,6 @@ void database::init_genesis(const genesis_state_type& genesis_state)
}); });
assert( ssobitcoin.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::bitcoin)) ); assert( ssobitcoin.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::bitcoin)) );
#ifndef NDEBUG
const son_schedule_object& ssoethereum =
#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_ethereum_sons = get_global_properties().active_sons.at(sidechain_type::ethereum);
_sso.scheduler = son_scheduler();
_sso.scheduler._min_token_count = std::max(int(init_ethereum_sons.size()) / 2, 1);
_sso.last_scheduling_block = 0;
_sso.recent_slots_filled = fc::uint128::max_value();
});
assert( ssoethereum.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::ethereum)) );
#ifndef NDEBUG
const son_schedule_object& ssohive =
#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_hive_sons = get_global_properties().active_sons.at(sidechain_type::hive);
_sso.scheduler = son_scheduler();
_sso.scheduler._min_token_count = std::max(int(init_hive_sons.size()) / 2, 1);
_sso.last_scheduling_block = 0;
_sso.recent_slots_filled = fc::uint128::max_value();
});
assert( ssohive.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::hive)) );
// Create FBA counters // Create FBA counters
create<fba_accumulator_object>([&]( fba_accumulator_object& acc ) create<fba_accumulator_object>([&]( fba_accumulator_object& acc )
{ {

View file

@ -92,10 +92,7 @@ vector<std::reference_wrapper<const son_object>> database::sort_votable_objects<
count = std::min(count, refs.size()); count = std::min(count, refs.size());
std::partial_sort(refs.begin(), refs.begin() + count, refs.end(), std::partial_sort(refs.begin(), refs.begin() + count, refs.end(),
[this, sidechain](const son_object& a, const son_object& b)->bool { [this, sidechain](const son_object& a, const son_object& b)->bool {
FC_ASSERT(sidechain == sidechain_type::bitcoin || FC_ASSERT(sidechain == sidechain_type::bitcoin || sidechain == sidechain_type::hive, "Unexpected sidechain type");
sidechain == sidechain_type::ethereum ||
sidechain == sidechain_type::hive,
"Unexpected sidechain type");
const share_type oa_vote = _vote_tally_buffer[a.get_sidechain_vote_id(sidechain)]; 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)]; const share_type ob_vote = _vote_tally_buffer[b.get_sidechain_vote_id(sidechain)];
@ -721,9 +718,7 @@ void database::update_active_sons()
assert( _son_count_histogram_buffer.size() > 0 ); assert( _son_count_histogram_buffer.size() > 0 );
for( const auto& son_count_histogram_buffer : _son_count_histogram_buffer ){ for( const auto& son_count_histogram_buffer : _son_count_histogram_buffer ){
#ifndef NDEBUG
assert( son_count_histogram_buffer.second.size() > 0 ); assert( son_count_histogram_buffer.second.size() > 0 );
#endif
} }
const flat_map<sidechain_type, share_type> stake_target = [this]{ const flat_map<sidechain_type, share_type> stake_target = [this]{
@ -2049,7 +2044,7 @@ void database::perform_son_tasks()
}); });
} }
// create BTC asset here because son_account is the issuer of the BTC // create BTC asset here because son_account is the issuer of the BTC
if (gpo.parameters.btc_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_TIME) if (gpo.parameters.btc_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_TIME)
{ {
const asset_dynamic_data_object& dyn_asset = const asset_dynamic_data_object& dyn_asset =
create<asset_dynamic_data_object>([](asset_dynamic_data_object& a) { create<asset_dynamic_data_object>([](asset_dynamic_data_object& a) {
@ -2068,7 +2063,7 @@ void database::perform_son_tasks()
asset_issuer_permission_flags::override_authority; asset_issuer_permission_flags::override_authority;
a.options.core_exchange_rate.base.amount = 100000; a.options.core_exchange_rate.base.amount = 100000;
a.options.core_exchange_rate.base.asset_id = asset_id_type(0); a.options.core_exchange_rate.base.asset_id = asset_id_type(0);
a.options.core_exchange_rate.quote.amount = 2500; a.options.core_exchange_rate.quote.amount = 2500; // CoinMarketCap approx value
a.options.core_exchange_rate.quote.asset_id = a.id; a.options.core_exchange_rate.quote.asset_id = a.id;
a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty
a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set
@ -2082,42 +2077,8 @@ void database::perform_son_tasks()
gpo.pending_parameters->extensions.value.btc_asset = btc_asset.get_id(); gpo.pending_parameters->extensions.value.btc_asset = btc_asset.get_id();
}); });
} }
// create ETH asset here because son_account is the issuer of the ETH
if (gpo.parameters.eth_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME)
{
const asset_dynamic_data_object& dyn_asset =
create<asset_dynamic_data_object>([](asset_dynamic_data_object& a) {
a.current_supply = 0;
});
const asset_object& eth_asset =
create<asset_object>( [&gpo, &dyn_asset]( asset_object& a ) {
a.symbol = "ETH";
a.precision = 8;
a.issuer = gpo.parameters.son_account();
a.options.max_supply = GRAPHENE_MAX_SHARE_SUPPLY;
a.options.market_fee_percent = 500; // 5%
a.options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK;
a.options.flags = asset_issuer_permission_flags::charge_market_fee |
asset_issuer_permission_flags::override_authority;
a.options.core_exchange_rate.base.amount = 100000;
a.options.core_exchange_rate.base.asset_id = asset_id_type(0);
a.options.core_exchange_rate.quote.amount = 2500;
a.options.core_exchange_rate.quote.asset_id = a.id;
a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty
a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set
a.options.whitelist_markets.clear(); // might be traded with
a.options.blacklist_markets.clear(); // might not be traded with
a.dynamic_asset_data_id = dyn_asset.id;
});
modify( gpo, [&eth_asset]( global_property_object& gpo ) {
gpo.parameters.extensions.value.eth_asset = eth_asset.get_id();
if( gpo.pending_parameters )
gpo.pending_parameters->extensions.value.eth_asset = eth_asset.get_id();
});
}
// create HBD asset here because son_account is the issuer of the HBD // create HBD asset here because son_account is the issuer of the HBD
if (gpo.parameters.hbd_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_HIVE_TIME) if (gpo.parameters.hbd_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_HIVE_TIME)
{ {
const asset_dynamic_data_object& dyn_asset = const asset_dynamic_data_object& dyn_asset =
create<asset_dynamic_data_object>([](asset_dynamic_data_object& a) { create<asset_dynamic_data_object>([](asset_dynamic_data_object& a) {
@ -2136,7 +2097,7 @@ void database::perform_son_tasks()
asset_issuer_permission_flags::override_authority; asset_issuer_permission_flags::override_authority;
a.options.core_exchange_rate.base.amount = 100000; a.options.core_exchange_rate.base.amount = 100000;
a.options.core_exchange_rate.base.asset_id = asset_id_type(0); a.options.core_exchange_rate.base.asset_id = asset_id_type(0);
a.options.core_exchange_rate.quote.amount = 2500; a.options.core_exchange_rate.quote.amount = 2500; // CoinMarketCap approx value
a.options.core_exchange_rate.quote.asset_id = a.id; a.options.core_exchange_rate.quote.asset_id = a.id;
a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty
a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set
@ -2170,7 +2131,7 @@ void database::perform_son_tasks()
asset_issuer_permission_flags::override_authority; asset_issuer_permission_flags::override_authority;
a.options.core_exchange_rate.base.amount = 100000; a.options.core_exchange_rate.base.amount = 100000;
a.options.core_exchange_rate.base.asset_id = asset_id_type(0); a.options.core_exchange_rate.base.asset_id = asset_id_type(0);
a.options.core_exchange_rate.quote.amount = 2500; a.options.core_exchange_rate.quote.amount = 2500; // CoinMarketCap approx value
a.options.core_exchange_rate.quote.asset_id = a.id; a.options.core_exchange_rate.quote.asset_id = a.id;
a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty
a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set
@ -2452,17 +2413,14 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
p.pending_parameters->extensions.value.hbd_asset = p.parameters.extensions.value.hbd_asset; p.pending_parameters->extensions.value.hbd_asset = p.parameters.extensions.value.hbd_asset;
if( !p.pending_parameters->extensions.value.hive_asset.valid() ) if( !p.pending_parameters->extensions.value.hive_asset.valid() )
p.pending_parameters->extensions.value.hive_asset = p.parameters.extensions.value.hive_asset; p.pending_parameters->extensions.value.hive_asset = p.parameters.extensions.value.hive_asset;
if( !p.pending_parameters->extensions.value.eth_asset.valid() )
p.pending_parameters->extensions.value.eth_asset = p.parameters.extensions.value.eth_asset;
// the following parameters are not allowed to be changed. So take what is in global property // the following parameters are not allowed to be changed. So take what is in global property
p.pending_parameters->extensions.value.gpos_period_start = p.parameters.extensions.value.gpos_period_start;
p.pending_parameters->extensions.value.son_account = p.parameters.extensions.value.son_account;
p.pending_parameters->extensions.value.btc_asset = p.parameters.extensions.value.btc_asset;
p.pending_parameters->extensions.value.maximum_son_count = p.parameters.extensions.value.maximum_son_count;
p.pending_parameters->extensions.value.hbd_asset = p.parameters.extensions.value.hbd_asset;
p.pending_parameters->extensions.value.hive_asset = p.parameters.extensions.value.hive_asset; p.pending_parameters->extensions.value.hive_asset = p.parameters.extensions.value.hive_asset;
p.pending_parameters->extensions.value.eth_asset = p.parameters.extensions.value.eth_asset; p.pending_parameters->extensions.value.hbd_asset = p.parameters.extensions.value.hbd_asset;
p.pending_parameters->extensions.value.maximum_son_count = p.parameters.extensions.value.maximum_son_count;
p.pending_parameters->extensions.value.btc_asset = p.parameters.extensions.value.btc_asset;
p.pending_parameters->extensions.value.son_account = p.parameters.extensions.value.son_account;
p.pending_parameters->extensions.value.gpos_period_start = p.parameters.extensions.value.gpos_period_start;
p.parameters = std::move(*p.pending_parameters); p.parameters = std::move(*p.pending_parameters);
p.pending_parameters.reset(); p.pending_parameters.reset();

View file

@ -77,9 +77,8 @@ witness_id_type database::get_scheduled_witness( uint32_t slot_num )const
unsigned_int database::get_son_schedule_id( sidechain_type type )const unsigned_int database::get_son_schedule_id( sidechain_type type )const
{ {
static const map<sidechain_type, unsigned_int> schedule_map = { static const map<sidechain_type, unsigned_int> schedule_map = {
{ sidechain_type::bitcoin, 0 }, { sidechain_type::hive, 0 },
{ sidechain_type::ethereum, 1 }, { sidechain_type::bitcoin, 1 }
{ sidechain_type::hive, 2 }
}; };
return schedule_map.at(type); return schedule_map.at(type);
@ -323,10 +322,8 @@ void database::update_witness_schedule(const signed_block& next_block)
void database::update_son_schedule(const signed_block& next_block) void database::update_son_schedule(const signed_block& next_block)
{ {
auto start = fc::time_point::now(); auto start = fc::time_point::now();
#ifndef NDEBUG
const son_schedule_object& sso = get(son_schedule_id_type());
#endif
const global_property_object& gpo = get_global_properties(); const global_property_object& gpo = get_global_properties();
const son_schedule_object& sso = get(son_schedule_id_type());
const flat_map<sidechain_type, uint32_t> schedule_needs_filled = [&gpo]() const flat_map<sidechain_type, uint32_t> schedule_needs_filled = [&gpo]()
{ {
flat_map<sidechain_type, uint32_t> schedule_needs_filled; flat_map<sidechain_type, uint32_t> schedule_needs_filled;

View file

@ -1,7 +0,0 @@
#ifndef HARDFORK_SON_FOR_ETHEREUM_TIME
#ifdef BUILD_PEERPLAYS_TESTNET
#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2022-07-01T00:00:00"))
#else
#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2022-07-01T00:00:00"))
#endif
#endif

View file

@ -70,7 +70,6 @@ namespace graphene { namespace chain {
optional < uint16_t > maximum_son_count = GRAPHENE_DEFAULT_MAX_SONS; ///< maximum number of active SONS optional < uint16_t > maximum_son_count = GRAPHENE_DEFAULT_MAX_SONS; ///< maximum number of active SONS
optional < asset_id_type > hbd_asset = asset_id_type(); optional < asset_id_type > hbd_asset = asset_id_type();
optional < asset_id_type > hive_asset = asset_id_type(); optional < asset_id_type > hive_asset = asset_id_type();
optional < asset_id_type > eth_asset = asset_id_type();
}; };
struct chain_parameters struct chain_parameters
@ -221,9 +220,6 @@ namespace graphene { namespace chain {
inline asset_id_type hive_asset() const { inline asset_id_type hive_asset() const {
return extensions.value.hive_asset.valid() ? *extensions.value.hive_asset : asset_id_type(); return extensions.value.hive_asset.valid() ? *extensions.value.hive_asset : asset_id_type();
} }
inline asset_id_type eth_asset() const {
return extensions.value.eth_asset.valid() ? *extensions.value.eth_asset : asset_id_type();
}
private: private:
static void safe_copy(chain_parameters& to, const chain_parameters& from); static void safe_copy(chain_parameters& to, const chain_parameters& from);
}; };
@ -261,7 +257,6 @@ FC_REFLECT( graphene::chain::parameter_extension,
(maximum_son_count) (maximum_son_count)
(hbd_asset) (hbd_asset)
(hive_asset) (hive_asset)
(eth_asset)
) )
FC_REFLECT( graphene::chain::chain_parameters, FC_REFLECT( graphene::chain::chain_parameters,

View file

@ -61,7 +61,6 @@ struct vote_id_type
worker, worker,
son_bitcoin, son_bitcoin,
son_hive, son_hive,
son_ethereum,
VOTE_TYPE_COUNT VOTE_TYPE_COUNT
}; };
@ -146,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_TYPENAME( fc::flat_set<graphene::chain::vote_id_type> )
FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(son_bitcoin)(son_hive)(son_ethereum)(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) ) FC_REFLECT( graphene::chain::vote_id_type, (content) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vote_id_type ) GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vote_id_type )

View file

@ -14,7 +14,7 @@ enum class sidechain_type {
hive hive
}; };
static const std::set<sidechain_type> active_sidechain_types = {sidechain_type::bitcoin, sidechain_type::ethereum, sidechain_type::hive}; static const std::set<sidechain_type> active_sidechain_types = {sidechain_type::bitcoin, sidechain_type::hive};
} } } }

View file

@ -89,13 +89,11 @@ namespace graphene { namespace chain {
inline vote_id_type get_sidechain_vote_id(sidechain_type sidechain) const { return sidechain_vote_ids.at(sidechain); } 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_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); } inline vote_id_type get_hive_vote_id() const { return get_sidechain_vote_id(sidechain_type::hive); }
inline vote_id_type get_ethereum_vote_id() const { return get_sidechain_vote_id(sidechain_type::ethereum); }
}; };
struct by_account; struct by_account;
struct by_vote_id_bitcoin; struct by_vote_id_bitcoin;
struct by_vote_id_hive; struct by_vote_id_hive;
struct by_vote_id_ethereum;
using son_multi_index_type = multi_index_container< using son_multi_index_type = multi_index_container<
son_object, son_object,
indexed_by< indexed_by<
@ -110,9 +108,6 @@ namespace graphene { namespace chain {
>, >,
ordered_unique< tag<by_vote_id_hive>, ordered_unique< tag<by_vote_id_hive>,
const_mem_fun<son_object, vote_id_type, &son_object::get_hive_vote_id> const_mem_fun<son_object, vote_id_type, &son_object::get_hive_vote_id>
>,
ordered_unique< tag<by_vote_id_ethereum>,
const_mem_fun<son_object, vote_id_type, &son_object::get_ethereum_vote_id>
> >
> >
>; >;

View file

@ -186,8 +186,6 @@ void account_options::validate() const
--needed_sons[sidechain_type::bitcoin]; --needed_sons[sidechain_type::bitcoin];
else if ( id.type() == vote_id_type::son_hive && needed_sons[sidechain_type::hive] ) else if ( id.type() == vote_id_type::son_hive && needed_sons[sidechain_type::hive] )
--needed_sons[sidechain_type::hive]; --needed_sons[sidechain_type::hive];
else if ( id.type() == vote_id_type::son_ethereum && needed_sons[sidechain_type::ethereum] )
--needed_sons[sidechain_type::ethereum];
FC_ASSERT( needed_witnesses == 0, FC_ASSERT( needed_witnesses == 0,
"May not specify fewer witnesses than the number voted for."); "May not specify fewer witnesses than the number voted for.");
@ -197,8 +195,6 @@ void account_options::validate() const
"May not specify fewer Bitcoin SONs than the number voted for."); "May not specify fewer Bitcoin SONs than the number voted for.");
FC_ASSERT( needed_sons[sidechain_type::hive] == 0, FC_ASSERT( needed_sons[sidechain_type::hive] == 0,
"May not specify fewer Hive SONs than the number voted for."); "May not specify fewer Hive SONs than the number voted for.");
FC_ASSERT( needed_sons[sidechain_type::ethereum] == 0,
"May not specify fewer Ethereum SONs than the number voted for.");
} }
void affiliate_reward_distribution::validate() const void affiliate_reward_distribution::validate() const

View file

@ -40,18 +40,15 @@ object_id_type create_son_evaluator::do_apply(const son_create_operation& op)
{ try { { try {
vote_id_type vote_id_bitcoin; vote_id_type vote_id_bitcoin;
vote_id_type vote_id_hive; vote_id_type vote_id_hive;
vote_id_type vote_id_ethereum; db().modify(db().get_global_properties(), [&vote_id_bitcoin, &vote_id_hive](global_property_object& p) {
db().modify(db().get_global_properties(), [&vote_id_bitcoin, &vote_id_hive, &vote_id_ethereum](global_property_object& p) {
vote_id_bitcoin = get_next_vote_id(p, vote_id_type::son_bitcoin); 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); vote_id_hive = get_next_vote_id(p, vote_id_type::son_hive);
vote_id_ethereum = get_next_vote_id(p, vote_id_type::son_ethereum);
}); });
const auto& new_son_object = db().create<son_object>( [&]( son_object& obj ){ const auto& new_son_object = db().create<son_object>( [&]( son_object& obj ){
obj.son_account = op.owner_account; obj.son_account = op.owner_account;
obj.sidechain_vote_ids[sidechain_type::bitcoin] = vote_id_bitcoin; obj.sidechain_vote_ids[sidechain_type::bitcoin] = vote_id_bitcoin;
obj.sidechain_vote_ids[sidechain_type::hive] = vote_id_hive; obj.sidechain_vote_ids[sidechain_type::hive] = vote_id_hive;
obj.sidechain_vote_ids[sidechain_type::ethereum] = vote_id_ethereum;
obj.url = op.url; obj.url = op.url;
obj.deposit = op.deposit; obj.deposit = op.deposit;
obj.signing_key = op.signing_key; obj.signing_key = op.signing_key;

View file

@ -20,10 +20,6 @@ namespace graphene { namespace chain {
retval = retval && retval = retval &&
(sidechain_public_keys.find( sidechain_type::hive ) != sidechain_public_keys.end()) && (sidechain_public_keys.find( sidechain_type::hive ) != sidechain_public_keys.end()) &&
(sidechain_public_keys.at(sidechain_type::hive).length() > 0); (sidechain_public_keys.at(sidechain_type::hive).length() > 0);
retval = retval &&
(sidechain_public_keys.find( sidechain_type::ethereum ) != sidechain_public_keys.end()) &&
(sidechain_public_keys.at(sidechain_type::ethereum).length() > 0);
} }
return retval; return retval;

View file

@ -47,3 +47,4 @@ namespace graphene { namespace net {
const core_message_type_enum get_current_connections_reply_message::type = core_message_type_enum::get_current_connections_reply_message_type; const core_message_type_enum get_current_connections_reply_message::type = core_message_type_enum::get_current_connections_reply_message_type;
} } // graphene::net } } // graphene::net

View file

@ -23,8 +23,6 @@
*/ */
#pragma once #pragma once
#include <stddef.h>
#define GRAPHENE_NET_PROTOCOL_VERSION 106 #define GRAPHENE_NET_PROTOCOL_VERSION 106
/** /**
@ -112,6 +110,3 @@
#define GRAPHENE_NET_MAX_NESTED_OBJECTS (250) #define GRAPHENE_NET_MAX_NESTED_OBJECTS (250)
#define MAXIMUM_PEERDB_SIZE 1000 #define MAXIMUM_PEERDB_SIZE 1000
constexpr size_t MAX_BLOCKS_TO_HANDLE_AT_ONCE = 200;
constexpr size_t MAX_SYNC_BLOCKS_TO_PREFETCH = 10 * MAX_BLOCKS_TO_HANDLE_AT_ONCE;

View file

@ -61,7 +61,7 @@ namespace graphene { namespace net {
class node_delegate class node_delegate
{ {
public: public:
virtual ~node_delegate() = default; virtual ~node_delegate(){}
/** /**
* If delegate has the item, the network has no need to fetch it. * If delegate has the item, the network has no need to fetch it.
@ -71,9 +71,7 @@ namespace graphene { namespace net {
/** /**
* @brief Called when a new block comes in from the network * @brief Called when a new block comes in from the network
* *
* @param blk_msg the message which contains the block
* @param sync_mode true if the message was fetched through the sync process, false during normal operation * @param sync_mode true if the message was fetched through the sync process, false during normal operation
* @param contained_transaction_msg_ids container for the transactions to write back into
* @returns true if this message caused the blockchain to switch forks, false if it did not * @returns true if this message caused the blockchain to switch forks, false if it did not
* *
* @throws exception if error validating the item, otherwise the item is * @throws exception if error validating the item, otherwise the item is
@ -197,7 +195,7 @@ namespace graphene { namespace net {
{ {
public: public:
node(const std::string& user_agent); node(const std::string& user_agent);
virtual ~node(); ~node();
void close(); void close();
@ -215,34 +213,11 @@ namespace graphene { namespace net {
*/ */
void add_node( const fc::ip::endpoint& ep ); void add_node( const fc::ip::endpoint& ep );
/*****
* @brief add a list of nodes to seed the p2p network
* @param seeds a vector of url strings
*/
void add_seed_nodes( std::vector<std::string> seeds );
/****
* @brief add a node to seed the p2p network
* @param in the url as a string
*/
void add_seed_node( const std::string& in);
/** /**
* Attempt to connect to the specified endpoint immediately. * Attempt to connect to the specified endpoint immediately.
*/ */
virtual void connect_to_endpoint( const fc::ip::endpoint& ep ); virtual void connect_to_endpoint( const fc::ip::endpoint& ep );
/**
* @brief Helper to convert a string to a collection of endpoints
*
* This converts a string (i.e. "bitshares.eu:665535" to a collection of endpoints.
* NOTE: Throws an exception if not in correct format or was unable to resolve URL.
*
* @param in the incoming string
* @returns a vector of endpoints
*/
static std::vector<fc::ip::endpoint> resolve_string_to_ip_endpoints( const std::string& in );
/** /**
* Specifies the network interface and port upon which incoming * Specifies the network interface and port upon which incoming
* connections should be accepted. * connections should be accepted.

View file

@ -62,7 +62,6 @@ namespace graphene { namespace net
class peer_connection_delegate class peer_connection_delegate
{ {
public: public:
virtual ~peer_connection_delegate() = default;
virtual void on_message(peer_connection* originating_peer, virtual void on_message(peer_connection* originating_peer,
const message& received_message) = 0; const message& received_message) = 0;
virtual void on_connection_closed(peer_connection* originating_peer) = 0; virtual void on_connection_closed(peer_connection* originating_peer) = 0;
@ -126,7 +125,7 @@ namespace graphene { namespace net
* it is sitting on the queue * it is sitting on the queue
*/ */
virtual size_t get_size_in_queue() = 0; virtual size_t get_size_in_queue() = 0;
virtual ~queued_message() = default; virtual ~queued_message() {}
}; };
/* when you queue up a 'real_queued_message', a full copy of the message is /* when you queue up a 'real_queued_message', a full copy of the message is

View file

@ -97,7 +97,7 @@ namespace graphene { namespace net {
{ {
public: public:
peer_database(); peer_database();
virtual ~peer_database(); ~peer_database();
void open(const fc::path& databaseFilename); void open(const fc::path& databaseFilename);
void close(); void close();

View file

@ -72,7 +72,6 @@
#include <fc/io/raw_fwd.hpp> #include <fc/io/raw_fwd.hpp>
#include <fc/network/rate_limiting.hpp> #include <fc/network/rate_limiting.hpp>
#include <fc/network/ip.hpp> #include <fc/network/ip.hpp>
#include <fc/network/resolve.hpp>
#include <graphene/net/node.hpp> #include <graphene/net/node.hpp>
#include <graphene/net/peer_database.hpp> #include <graphene/net/peer_database.hpp>
@ -556,10 +555,6 @@ namespace graphene { namespace net { namespace detail {
fc::future<void> _bandwidth_monitor_loop_done; fc::future<void> _bandwidth_monitor_loop_done;
fc::future<void> _dump_node_status_task_done; fc::future<void> _dump_node_status_task_done;
/// Used by the task that checks whether addresses of seed nodes have been updated
/// @{
boost::container::flat_set<std::string> _seed_nodes;
fc::future<void> _update_seed_nodes_loop_done;
/* We have two alternate paths through the schedule_peer_for_deletion code -- one that /* We have two alternate paths through the schedule_peer_for_deletion code -- one that
* uses a mutex to prevent one fiber from adding items to the queue while another is deleting * uses a mutex to prevent one fiber from adding items to the queue while another is deleting
@ -733,11 +728,6 @@ namespace graphene { namespace net { namespace detail {
void listen_to_p2p_network(); void listen_to_p2p_network();
void connect_to_p2p_network(); void connect_to_p2p_network();
void add_node( const fc::ip::endpoint& ep ); void add_node( const fc::ip::endpoint& ep );
void add_seed_node( const std::string& in);
void add_seed_nodes( std::vector<std::string> seeds );
void resolve_seed_node_and_add( const std::string& seed_string );
void update_seed_nodes_task();
void schedule_next_update_seed_nodes_task();
void initiate_connect_to(const peer_connection_ptr& peer); void initiate_connect_to(const peer_connection_ptr& peer);
void connect_to_endpoint(const fc::ip::endpoint& ep); void connect_to_endpoint(const fc::ip::endpoint& ep);
void listen_on_endpoint(const fc::ip::endpoint& ep , bool wait_if_not_available); void listen_on_endpoint(const fc::ip::endpoint& ep , bool wait_if_not_available);
@ -4767,68 +4757,6 @@ namespace graphene { namespace net { namespace detail {
_potential_peer_db.update_entry(updated_peer_record); _potential_peer_db.update_entry(updated_peer_record);
trigger_p2p_network_connect_loop(); trigger_p2p_network_connect_loop();
} }
void node_impl::add_seed_node(const std::string& endpoint_string)
{
VERIFY_CORRECT_THREAD();
_seed_nodes.insert( endpoint_string );
resolve_seed_node_and_add( endpoint_string );
}
void node_impl::resolve_seed_node_and_add(const std::string& endpoint_string)
{
VERIFY_CORRECT_THREAD();
std::vector<fc::ip::endpoint> endpoints;
ilog("Resolving seed node ${endpoint}", ("endpoint", endpoint_string));
try
{
endpoints = graphene::net::node::resolve_string_to_ip_endpoints(endpoint_string);
}
catch(...)
{
wlog( "Unable to resolve endpoint during attempt to add seed node ${ep}", ("ep", endpoint_string) );
}
for (const fc::ip::endpoint& endpoint : endpoints)
{
ilog("Adding seed node ${endpoint}", ("endpoint", endpoint));
add_node(endpoint);
}
}
void node_impl::update_seed_nodes_task()
{
VERIFY_CORRECT_THREAD();
try
{
dlog("Starting an iteration of update_seed_nodes loop.");
for( const std::string& endpoint_string : _seed_nodes )
{
resolve_seed_node_and_add( endpoint_string );
}
dlog("Done an iteration of update_seed_nodes loop.");
}
catch (const fc::canceled_exception&)
{
ilog( "update_seed_nodes_task canceled" );
throw;
}
FC_CAPTURE_AND_LOG( (_seed_nodes) )
schedule_next_update_seed_nodes_task();
}
void node_impl::schedule_next_update_seed_nodes_task()
{
VERIFY_CORRECT_THREAD();
if( _node_is_shutting_down )
return;
if( _update_seed_nodes_loop_done.valid() && _update_seed_nodes_loop_done.canceled() )
return;
_update_seed_nodes_loop_done = fc::schedule( [this]() { update_seed_nodes_task(); },
fc::time_point::now() + fc::hours(3),
"update_seed_nodes_loop" );
}
void node_impl::initiate_connect_to(const peer_connection_ptr& new_peer) void node_impl::initiate_connect_to(const peer_connection_ptr& new_peer)
{ {
@ -5368,11 +5296,6 @@ namespace graphene { namespace net { namespace detail {
INVOKE_IN_IMPL(add_node, ep); INVOKE_IN_IMPL(add_node, ep);
} }
void node::add_seed_node(const std::string& in)
{
INVOKE_IN_IMPL(add_seed_node, in);
}
void node::connect_to_endpoint( const fc::ip::endpoint& remote_endpoint ) void node::connect_to_endpoint( const fc::ip::endpoint& remote_endpoint )
{ {
INVOKE_IN_IMPL(connect_to_endpoint, remote_endpoint); INVOKE_IN_IMPL(connect_to_endpoint, remote_endpoint);
@ -5754,45 +5677,5 @@ namespace graphene { namespace net { namespace detail {
#undef INVOKE_AND_COLLECT_STATISTICS #undef INVOKE_AND_COLLECT_STATISTICS
} // end namespace detail } // end namespace detail
std::vector<fc::ip::endpoint> node::resolve_string_to_ip_endpoints(const std::string& in)
{
try
{
std::string::size_type colon_pos = in.find(':');
if (colon_pos == std::string::npos)
FC_THROW("Missing required port number in endpoint string \"${endpoint_string}\"",
("endpoint_string", in));
std::string port_string = in.substr(colon_pos + 1);
try
{
uint16_t port = boost::lexical_cast<uint16_t>(port_string);
std::string hostname = in.substr(0, colon_pos);
std::vector<fc::ip::endpoint> endpoints = fc::resolve(hostname, port);
if (endpoints.empty())
FC_THROW_EXCEPTION( fc::unknown_host_exception,
"The host name can not be resolved: ${hostname}",
("hostname", hostname) );
return endpoints;
}
catch (const boost::bad_lexical_cast&)
{
FC_THROW("Bad port: ${port}", ("port", port_string));
}
}
FC_CAPTURE_AND_RETHROW((in))
}
void node::add_seed_nodes(std::vector<std::string> seeds)
{
for(const std::string& endpoint_string : seeds )
{
try {
add_seed_node(endpoint_string);
} catch( const fc::exception& e ) {
wlog( "caught exception ${e} while adding seed node ${endpoint}",
("e", e.to_detail_string())("endpoint", endpoint_string) );
}
}
}
} } // end namespace graphene::net } } // end namespace graphene::net

View file

@ -50,8 +50,7 @@ namespace graphene { namespace net {
indexed_by<ordered_non_unique<tag<last_seen_time_index>, indexed_by<ordered_non_unique<tag<last_seen_time_index>,
member<potential_peer_record, member<potential_peer_record,
fc::time_point_sec, fc::time_point_sec,
&potential_peer_record::last_seen_time>, &potential_peer_record::last_seen_time> >,
std::greater<fc::time_point_sec> >,
hashed_unique<tag<endpoint_index>, hashed_unique<tag<endpoint_index>,
member<potential_peer_record, member<potential_peer_record,
fc::ip::endpoint, fc::ip::endpoint,

View file

@ -63,24 +63,8 @@ void delayed_node_plugin::plugin_set_program_options(bpo::options_description& c
void delayed_node_plugin::connect() void delayed_node_plugin::connect()
{ {
fc::http::websocket_connection_ptr con; my->client_connection = std::make_shared<fc::rpc::websocket_api_connection>(my->client.connect(my->remote_endpoint), GRAPHENE_MAX_NESTED_OBJECTS);
try
{
con = my->client.connect(my->remote_endpoint);
}
catch( const fc::exception& e )
{
wlog("Error while connecting: ${e}", ("e", e.to_detail_string()));
connection_failed();
return;
}
my->client_connection = std::make_shared<fc::rpc::websocket_api_connection>(
con, GRAPHENE_NET_MAX_NESTED_OBJECTS );
my->database_api = my->client_connection->get_remote_api<graphene::app::database_api>(0); my->database_api = my->client_connection->get_remote_api<graphene::app::database_api>(0);
my->database_api->set_block_applied_callback([this]( const fc::variant& block_id )
{
fc::from_variant( block_id, my->last_received_remote_head, GRAPHENE_MAX_NESTED_OBJECTS );
} );
my->client_connection_closed = my->client_connection->closed.connect([this] { my->client_connection_closed = my->client_connection->closed.connect([this] {
connection_failed(); connection_failed();
}); });
@ -89,9 +73,7 @@ void delayed_node_plugin::connect()
void delayed_node_plugin::plugin_initialize(const boost::program_options::variables_map& options) void delayed_node_plugin::plugin_initialize(const boost::program_options::variables_map& options)
{ {
FC_ASSERT(options.count("trusted-node") > 0); FC_ASSERT(options.count("trusted-node") > 0);
ilog("delayed_node_plugin: plugin_initialize() begin");
my->remote_endpoint = "ws://" + options.at("trusted-node").as<std::string>(); my->remote_endpoint = "ws://" + options.at("trusted-node").as<std::string>();
ilog("delayed_node_plugin: plugin_initialize() end");
} }
void delayed_node_plugin::sync_with_trusted_node() void delayed_node_plugin::sync_with_trusted_node()
@ -118,11 +100,8 @@ void delayed_node_plugin::sync_with_trusted_node()
while( remote_dpo.last_irreversible_block_num > db.head_block_num() ) while( remote_dpo.last_irreversible_block_num > db.head_block_num() )
{ {
fc::optional<graphene::chain::signed_block> block = my->database_api->get_block( db.head_block_num()+1 ); fc::optional<graphene::chain::signed_block> block = my->database_api->get_block( db.head_block_num()+1 );
// TODO: during sync, decouple requesting blocks from preprocessing + applying them
FC_ASSERT(block, "Trusted node claims it has blocks it doesn't actually have."); FC_ASSERT(block, "Trusted node claims it has blocks it doesn't actually have.");
ilog("Pushing block #${n}", ("n", block->block_num())); ilog("Pushing block #${n}", ("n", block->block_num()));
// timur: failed to merge from bitshares, API n/a in peerplays
// db.precompute_parallel( *block, graphene::chain::database::skip_nothing ).wait();
db.push_block(*block); db.push_block(*block);
synced_blocks++; synced_blocks++;
} }
@ -157,12 +136,24 @@ void delayed_node_plugin::plugin_startup()
mainloop(); mainloop();
}); });
connect(); try
{
connect();
my->database_api->set_block_applied_callback([this]( const fc::variant& block_id )
{
fc::from_variant( block_id, my->last_received_remote_head, GRAPHENE_MAX_NESTED_OBJECTS );
} );
return;
}
catch (const fc::exception& e)
{
elog("Error during connection: ${e}", ("e", e.to_detail_string()));
}
fc::async([this]{connection_failed();});
} }
void delayed_node_plugin::connection_failed() void delayed_node_plugin::connection_failed()
{ {
my->last_received_remote_head = my->last_processed_remote_head;
elog("Connection to trusted node failed; retrying in 5 seconds..."); elog("Connection to trusted node failed; retrying in 5 seconds...");
fc::schedule([this]{connect();}, fc::time_point::now() + fc::seconds(5)); fc::schedule([this]{connect();}, fc::time_point::now() + fc::seconds(5));
} }

10
libraries/plugins/peerplays_sidechain/CMakeLists.txt Executable file → Normal file
View file

@ -6,7 +6,6 @@ add_library( peerplays_sidechain
sidechain_net_handler_factory.cpp sidechain_net_handler_factory.cpp
sidechain_net_handler.cpp sidechain_net_handler.cpp
sidechain_net_handler_bitcoin.cpp sidechain_net_handler_bitcoin.cpp
sidechain_net_handler_ethereum.cpp
sidechain_net_handler_hive.cpp sidechain_net_handler_hive.cpp
sidechain_net_handler_peerplays.cpp sidechain_net_handler_peerplays.cpp
bitcoin/bech32.cpp bitcoin/bech32.cpp
@ -16,13 +15,10 @@ add_library( peerplays_sidechain
bitcoin/segwit_addr.cpp bitcoin/segwit_addr.cpp
bitcoin/utils.cpp bitcoin/utils.cpp
bitcoin/sign_bitcoin_transaction.cpp bitcoin/sign_bitcoin_transaction.cpp
bitcoin/libbitcoin_client.cpp
bitcoin/estimate_fee_external.cpp
common/rpc_client.cpp common/rpc_client.cpp
common/utils.cpp common/utils.cpp
ethereum/encoders.cpp
ethereum/decoders.cpp
ethereum/transaction.cpp
ethereum/types.cpp
ethereum/utils.cpp
hive/asset.cpp hive/asset.cpp
hive/operations.cpp hive/operations.cpp
hive/transaction.cpp hive/transaction.cpp
@ -42,7 +38,7 @@ endif()
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS) unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS)
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE) unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE)
target_link_libraries( peerplays_sidechain PRIVATE graphene_plugin sha3 zmq ) target_link_libraries( peerplays_sidechain PRIVATE curl graphene_plugin zmq bitcoin-system bitcoin-protocol bitcoin-client bitcoin-explorer )
target_include_directories( peerplays_sidechain target_include_directories( peerplays_sidechain
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )

View file

@ -242,12 +242,12 @@ bytes btc_multisig_segwit_address::get_address_bytes(const bytes &script_hash) {
} }
btc_weighted_multisig_address::btc_weighted_multisig_address(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data, btc_weighted_multisig_address::btc_weighted_multisig_address(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
network ntype) { network ntype, payment_type type) {
network_type = ntype; network_type = ntype;
this->type = type;
create_redeem_script(keys_data); create_redeem_script(keys_data);
create_witness_script(); create_witness_script();
create_segwit_address(); create_segwit_address();
type = payment_type::P2WSH;
} }
void btc_weighted_multisig_address::create_redeem_script(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data) { void btc_weighted_multisig_address::create_redeem_script(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data) {
@ -278,26 +278,43 @@ void btc_weighted_multisig_address::create_witness_script() {
script_builder builder; script_builder builder;
builder << op::_0; builder << op::_0;
builder << fc::sha256::hash(redeem_script_.data(), redeem_script_.size()); builder << fc::sha256::hash(redeem_script_.data(), redeem_script_.size());
witness_script_ = builder; witness_script_ = builder;
} }
void btc_weighted_multisig_address::create_segwit_address() { void btc_weighted_multisig_address::create_segwit_address() {
std::string hrp; std::string hrp;
address_types byte_version;
switch (network_type) { switch (network_type) {
case (network::mainnet): case (network::mainnet):
hrp = "bc"; hrp = "bc";
byte_version = address_types::MAINNET_SCRIPT;
break; break;
case (network::testnet): case (network::testnet):
hrp = "tb"; hrp = "tb";
byte_version = address_types::TESTNET_SCRIPT;
break; break;
case (network::regtest): case (network::regtest):
hrp = "bcrt"; hrp = "bcrt";
byte_version = address_types::TESTNET_SCRIPT;
break; break;
} }
fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size());
std::vector<uint8_t> hash_data(sh.data(), sh.data() + sh.data_size()); if (type == payment_type::P2WSH) {
address = segwit_addr::encode(hrp, 0, hash_data); fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size());
std::vector<uint8_t> hash_data(sh.data(), sh.data() + sh.data_size());
address = segwit_addr::encode(hrp, 0, hash_data);
} else if (type == payment_type::P2SH_WSH) {
fc::sha256 hash256 = fc::sha256::hash(&witness_script_[0], witness_script_.size());
fc::ripemd160 hash160 = fc::ripemd160::hash(hash256.data(), hash256.data_size());
raw_address = bytes(hash160.data(), hash160.data() + hash160.data_size());
bytes address_bytes(1, byte_version); // 1 byte version
address_bytes.insert(address_bytes.end(), raw_address.begin(), raw_address.end());
fc::sha256 hash256_1 = fc::sha256::hash(fc::sha256::hash(address_bytes.data(), address_bytes.size()));
address_bytes.insert(address_bytes.end(), hash256_1.data(), hash256_1.data() + 4); // 4 byte checksum
address = fc::to_base58(address_bytes);
} else {
wlog("Unsupported payment type of address");
}
} }
btc_one_or_m_of_n_multisig_address::btc_one_or_m_of_n_multisig_address(const fc::ecc::public_key &user_key_data, btc_one_or_m_of_n_multisig_address::btc_one_or_m_of_n_multisig_address(const fc::ecc::public_key &user_key_data,
@ -353,12 +370,12 @@ void btc_one_or_m_of_n_multisig_address::create_segwit_address() {
btc_one_or_weighted_multisig_address::btc_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, btc_one_or_weighted_multisig_address::btc_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data,
const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
bitcoin_address::network ntype) { bitcoin_address::network ntype, payment_type type) {
network_type = ntype; network_type = ntype;
this->type = type;
create_redeem_script(user_key_data, keys_data); create_redeem_script(user_key_data, keys_data);
create_witness_script(); create_witness_script();
create_segwit_address(); create_segwit_address();
type = payment_type::P2WSH;
} }
void btc_one_or_weighted_multisig_address::create_redeem_script(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data) { void btc_one_or_weighted_multisig_address::create_redeem_script(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data) {
@ -398,20 +415,39 @@ void btc_one_or_weighted_multisig_address::create_witness_script() {
void btc_one_or_weighted_multisig_address::create_segwit_address() { void btc_one_or_weighted_multisig_address::create_segwit_address() {
std::string hrp; std::string hrp;
address_types byte_version;
switch (network_type) { switch (network_type) {
case (network::mainnet): case (network::mainnet):
byte_version = address_types::MAINNET_SCRIPT;
hrp = "bc"; hrp = "bc";
break; break;
case (network::testnet): case (network::testnet):
byte_version = address_types::TESTNET_SCRIPT;
hrp = "tb"; hrp = "tb";
break; break;
case (network::regtest): case (network::regtest):
byte_version = address_types::TESTNET_SCRIPT;
hrp = "bcrt"; hrp = "bcrt";
break; break;
} }
fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size());
std::vector<uint8_t> hash_data(sh.data(), sh.data() + sh.data_size()); if (type == payment_type::P2WSH) {
address = segwit_addr::encode(hrp, 0, hash_data); fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size());
std::vector<uint8_t> hash_data(sh.data(), sh.data() + sh.data_size());
address = segwit_addr::encode(hrp, 0, hash_data);
} else if (type == payment_type::P2SH_WSH) {
fc::sha256 hash256 = fc::sha256::hash(&witness_script_[0], witness_script_.size());
fc::ripemd160 hash160 = fc::ripemd160::hash(hash256.data(), hash256.data_size());
raw_address = bytes(hash160.data(), hash160.data() + hash160.data_size());
bytes address_bytes(1, byte_version); // 1 byte version test net
address_bytes.insert(address_bytes.end(), raw_address.begin(), raw_address.end());
fc::sha256 hash256_1 = fc::sha256::hash(fc::sha256::hash(address_bytes.data(), address_bytes.size()));
address_bytes.insert(address_bytes.end(), hash256_1.data(), hash256_1.data() + 4); // 4 byte checksum
address = fc::to_base58(address_bytes);
} else {
elog("Unsupported payment type of address");
}
} }
btc_timelocked_one_or_weighted_multisig_address::btc_timelocked_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, uint32_t latency, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data, bitcoin_address::network ntype) : btc_timelocked_one_or_weighted_multisig_address::btc_timelocked_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, uint32_t latency, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data, bitcoin_address::network ntype) :

View file

@ -0,0 +1,155 @@
#include <graphene/peerplays_sidechain/bitcoin/estimate_fee_external.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <fc/log/logger.hpp>
#include <iostream>
namespace graphene {
namespace peerplays_sidechain {
static size_t writeFunction(void *ptr, size_t size, size_t nmemb, std::string *data) {
data->append((char *)ptr, size * nmemb);
return size * nmemb;
}
estimate_fee_external::estimate_fee_external() {
curl = curl_easy_init();
}
estimate_fee_external::~estimate_fee_external() {
curl_easy_cleanup(curl);
}
uint64_t estimate_fee_external::get_fee_external(uint16_t target_block) {
this->target_block = target_block;
for (auto &url_fee_parser : url_get_fee_parsers) {
response = get_response(url_fee_parser.first);
uint64_t fee = url_fee_parser.second();
if (fee != 0) {
return fee;
}
}
return 0;
}
std::string estimate_fee_external::get_response(std::string url) {
std::string response;
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(curl, CURLOPT_USERPWD, "user:pass");
curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/7.42.0");
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_perform(curl);
}
return response;
}
uint64_t estimate_fee_external::parse_and_get_fee_1() {
//"https://www.bitgo.com/api/v2/btc/tx/fee"
uint64_t founded_fee = 0;
if (response.empty()) {
return founded_fee;
}
std::stringstream response_ss(response);
boost::property_tree::ptree response_pt;
boost::property_tree::read_json(response_ss, response_pt);
for (const auto &tx_child : response_pt.get_child("feeByBlockTarget")) {
const auto &block_num = tx_child.first.data();
const auto &fee = tx_child.second.data();
founded_fee = std::stoi(fee);
if (std::stoi(block_num) > target_block) {
return founded_fee;
}
}
return founded_fee;
}
uint64_t estimate_fee_external::parse_and_get_fee_2() {
// https://bitcoiner.live/api/fees/estimates/latest
uint64_t founded_fee = 0;
if (response.empty()) {
return founded_fee;
}
std::stringstream response_ss(response);
boost::property_tree::ptree response_pt;
boost::property_tree::read_json(response_ss, response_pt);
for (const auto &tx_child : response_pt.get_child("estimates")) {
const auto &time_str = tx_child.first.data();
auto time = std::stoi(time_str);
auto block_num = time / 10;
if (tx_child.second.count("sat_per_vbyte")) {
auto founded_fee_str = tx_child.second.get_child("sat_per_vbyte").data();
founded_fee = std::stoi(founded_fee_str) * 1000;
}
if (block_num > target_block) {
return founded_fee;
}
}
return founded_fee;
}
uint64_t estimate_fee_external::parse_and_get_fee_3() {
// https://api.blockchain.info/mempool/fees
if (response.empty()) {
return 0;
}
std::stringstream response_ss(response);
boost::property_tree::ptree response_pt;
boost::property_tree::read_json(response_ss, response_pt);
if (response_pt.get_child("limits").count("min") && response_pt.get_child("limits").count("max")) {
auto limits_min_str = response_pt.get_child("limits.min").data();
auto limits_max_str = response_pt.get_child("limits.max").data();
auto limits_min = std::stoi(limits_min_str);
auto limits_max = std::stoi(limits_max_str);
auto priority_max = (limits_max - (limits_min - 1)) / 2;
if (response_pt.count("regular") && response_pt.count("priority")) {
auto regular_str = response_pt.get_child("regular").data();
auto priority_str = response_pt.get_child("priority").data();
auto regular = std::stoi(regular_str);
auto priority = std::stoi(priority_str);
if (target_block > priority_max) {
return regular * 1000;
} else {
return priority * 1000;
}
}
}
return 0;
}
}} // namespace graphene::peerplays_sidechain

View file

@ -0,0 +1,156 @@
#include <graphene/peerplays_sidechain/bitcoin/libbitcoin_client.hpp>
#include <system_error>
#include <bitcoin/explorer/config/transaction.hpp>
#include <bitcoin/system/config/hash256.hpp>
#include <boost/xpressive/xpressive.hpp>
#include <fc/crypto/hex.hpp>
#include <fc/log/logger.hpp>
namespace graphene { namespace peerplays_sidechain {
libbitcoin_client::libbitcoin_client(std::string url) :
obelisk_client(LIBBITCOIN_SERVER_TIMEOUT, LIBBITCOIN_SERVER_RETRIES) {
std::string reg_expr = "^((?P<Protocol>https|http|tcp):\\/\\/)?(?P<Host>[a-zA-Z0-9\\-\\.]+)(:(?P<Port>\\d{1,5}))?(?P<Target>\\/.+)?";
boost::xpressive::sregex sr = boost::xpressive::sregex::compile(reg_expr);
boost::xpressive::smatch sm;
if (boost::xpressive::regex_search(url, sm, sr)) {
protocol = sm["Protocol"];
if (protocol.empty()) {
protocol = "tcp";
}
host = sm["Host"];
if (host.empty()) {
host + "localhost";
}
port = sm["Port"];
if (port.empty()) {
port = "9091";
}
}
uint16_t port_num = std::stoi(port);
std::string final_url = protocol + "://" + host;
libbitcoin::config::endpoint address(final_url, port_num);
libbitcoin::client::connection_type connection;
connection.retries = LIBBITCOIN_SERVER_RETRIES;
connection.server = address;
if (!obelisk_client.connect(connection)) {
elog("Can't connect libbitcoin for url: ${url}", ("url", final_url));
}
is_connected = true;
}
std::string libbitcoin_client::send_transaction(std::string tx) {
std::string res;
auto error_handler = [&](const std::error_code &ec) {
elog("error on sending bitcoin transaction ${error_code}", ("error_code", ec.message()));
};
auto result_handler = [&](libbitcoin::code result_code) {
ilog("result code on sending transaction ${result_code}", ("result_code", result_code.message()));
res = std::to_string(result_code.value());
};
libbitcoin::explorer::config::transaction transaction(tx);
libbitcoin::chain::transaction trx;
// This validates the tx, submits it to local tx pool, and notifies peers.
obelisk_client.transaction_pool_broadcast(error_handler, result_handler, transaction);
obelisk_client.wait();
return res;
}
libbitcoin::chain::output::list libbitcoin_client::get_transaction(std::string tx_id, std::string &tx_hash, uint32_t &confirmitions) {
libbitcoin::chain::output::list outs;
auto error_handler = [&](const std::error_code &ec) {
elog("error on fetch_trx_by_hash: ${hash} ${error_code}", ("hash", tx_id)("error_code", ec.message()));
};
auto transaction_handler = [&](const libbitcoin::chain::transaction &tx_handler) {
tx_hash = libbitcoin::config::hash256(tx_handler.hash(false)).to_string();
// TODO try to find this value (confirmitions)
confirmitions = 1;
outs = tx_handler.outputs();
};
libbitcoin::hash_digest hash = libbitcoin::config::hash256(tx_id);
// obelisk_client.blockchain_fetch_transaction (error_handler, transaction_handler,hash);
obelisk_client.blockchain_fetch_transaction2(error_handler, transaction_handler, hash);
obelisk_client.wait();
return outs;
}
std::vector<list_unspent_replay> libbitcoin_client::listunspent(std::string address, double amount) {
std::vector<list_unspent_replay> result;
auto error_handler = [&](const std::error_code &ec) {
elog("error on list_unspent ${error_code}", ("error_code", ec.message()));
};
auto replay_handler = [&](const libbitcoin::chain::points_value &points) {
for (auto &point : points.points) {
list_unspent_replay output;
output.hash = libbitcoin::config::hash256(point.hash()).to_string();
output.value = point.value();
output.index = point.index();
result.emplace_back(output);
}
};
libbitcoin::wallet::payment_address payment_address(address);
uint64_t satoshi = 100000000 * amount;
obelisk_client.blockchain_fetch_unspent_outputs(error_handler,
replay_handler, payment_address, satoshi, libbitcoin::wallet::select_outputs::algorithm::individual);
obelisk_client.wait();
return result;
}
bool libbitcoin_client::get_is_test_net() {
bool result = false;
auto error_handler = [&](const std::error_code &ec) {
elog("error on fetching genesis block ${error_code}", ("error_code", ec.message()));
};
auto block_header_handler = [&](const libbitcoin::chain::header &block_header) {
std::string hash_str = libbitcoin::config::hash256(block_header.hash()).to_string();
if (hash_str == GENESIS_TESTNET_HASH || hash_str == GENESIS_REGTEST_HASH) {
result = true;
}
};
obelisk_client.blockchain_fetch_block_header(error_handler, block_header_handler, 0);
obelisk_client.wait();
return result;
}
}
} // namespace graphene::peerplays_sidechain

View file

@ -2,20 +2,23 @@
#include <regex> #include <regex>
#include <sstream> #include <sstream>
#include <string>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/xpressive/xpressive.hpp>
#include <boost/asio/buffers_iterator.hpp> #include <boost/asio/buffers_iterator.hpp>
#include <boost/asio/connect.hpp> #include <boost/asio/connect.hpp>
#include <boost/asio/ssl/error.hpp> #include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp> #include <boost/asio/ssl/stream.hpp>
#include <boost/beast/http.hpp> #include <boost/beast/http.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/xpressive/xpressive.hpp>
#include <curl/curl.h>
#include <fc/crypto/base64.hpp>
#include <fc/log/logger.hpp> #include <fc/log/logger.hpp>
#include <graphene/peerplays_sidechain/common/utils.hpp>
namespace graphene { namespace peerplays_sidechain { namespace graphene { namespace peerplays_sidechain {
rpc_client::rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls) : rpc_client::rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls) :
@ -52,8 +55,7 @@ rpc_client::rpc_client(std::string _url, std::string _user, std::string _passwor
target = "/"; target = "/";
} }
authorization = "Basic " + base64_encode(user + ":" + password); authorization = "Basic " + fc::base64_encode(user + ":" + password);
results = resolver.resolve(host, port); results = resolver.resolve(host, port);
} else { } else {

View file

@ -1,50 +1,8 @@
#include <graphene/peerplays_sidechain/common/utils.hpp> #include <graphene/peerplays_sidechain/common/utils.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
namespace graphene { namespace peerplays_sidechain {
const std::string base64_padding[] = {"", "==", "="};
std::string base64_encode(const std::string &s) {
using namespace boost::archive::iterators;
typedef base64_from_binary<transform_width<const char *, 6, 8>> base64_enc;
std::stringstream os;
std::copy(base64_enc(s.c_str()), base64_enc(s.c_str() + s.size()), std::ostream_iterator<char>(os));
os << base64_padding[s.size() % 3];
return os.str();
}
std::string base64_decode(const std::string &s) {
using namespace boost::archive::iterators;
typedef transform_width<binary_from_base64<const char *>, 8, 6> base64_dec;
std::stringstream os;
unsigned int size = s.size();
if (size && s[size - 1] == '=') {
--size;
if (size && s[size - 1] == '=')
--size;
}
if (size == 0)
return std::string();
std::copy(base64_dec(s.data()), base64_dec(s.data() + size), std::ostream_iterator<char>(os));
return os.str();
}
std::string object_id_to_string(graphene::chain::object_id_type id) { std::string object_id_to_string(graphene::chain::object_id_type id) {
std::string object_id = fc::to_string(id.space()) + "." + std::string object_id = fc::to_string(id.space()) + "." +
fc::to_string(id.type()) + "." + fc::to_string(id.type()) + "." +
fc::to_string(id.instance()); fc::to_string(id.instance());
return object_id; return object_id;
} }
}} // namespace graphene::peerplays_sidechain

View file

@ -1,224 +0,0 @@
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
#include <fc/exception/exception.hpp>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
//! rlp_decoder
namespace {
const signed char p_util_hexdigit[256] =
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
}
std::vector<std::string> rlp_decoder::decode(const std::string &str) {
size_t consumed = 0;
const auto raw_vec = parse_hex(str);
const std::vector<std::string> rlp_array = decode_rlp(raw_vec.data(), raw_vec.size(), consumed);
std::vector<std::string> result_array;
for (const auto &rlp : decode_rlp(raw_vec.data(), raw_vec.size(), consumed)) {
result_array.emplace_back(bytes2hex(rlp));
}
return result_array;
}
std::vector<std::string> rlp_decoder::decode_rlp(const unsigned char *raw, size_t len, size_t &consumed) {
std::vector<std::string> rlp_result;
consumed = 0;
const unsigned char *end = raw + len;
const size_t prefixlen = 1;
unsigned char ch = *raw;
if (len < 1) {
return rlp_result;
}
// Case 1: [prefix is 1-byte data buffer]
if (ch <= 0x7f) {
const unsigned char *tok_start = raw;
const unsigned char *tok_end = tok_start + prefixlen;
FC_ASSERT(tok_end <= end);
// parsing done; assign data buffer value.
const std::vector<unsigned char> buf{tok_start, tok_end};
rlp_result.emplace_back(buf.cbegin(), buf.cend());
consumed = buf.size();
}
// Case 2: [prefix, including buffer length][data]
else if ((ch >= 0x80) && (ch <= 0xb7)) {
const size_t blen = ch - 0x80;
const size_t expected = prefixlen + blen;
if (len < expected)
return std::vector<std::string>{};
const unsigned char *tok_start = raw + 1;
const unsigned char *tok_end = tok_start + blen;
FC_ASSERT(tok_end <= end);
// require minimal encoding
if ((blen == 1) && (tok_start[0] <= 0x7f))
return std::vector<std::string>{};
// parsing done; assign data buffer value.
const std::vector<unsigned char> buf{tok_start, tok_end};
rlp_result.emplace_back(buf.cbegin(), buf.cend());
consumed = expected;
}
// Case 3: [prefix][buffer length][data]
else if ((ch >= 0xb8) && (ch <= 0xbf)) {
const size_t uintlen = ch - 0xb7;
size_t expected = prefixlen + uintlen;
if (len < expected)
return std::vector<std::string>{};
FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen);
const unsigned char *tok_start = raw + prefixlen;
if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes
return std::vector<std::string>{};
// read buffer length
const uint64_t slen = to_int(tok_start, uintlen);
// validate buffer length, including possible addition overflows.
expected = prefixlen + uintlen + slen;
if ((slen < (RLP_listStart - RLP_bufferLenStart - RLP_maxUintLen)) || (expected > len) || (slen > len))
return std::vector<std::string>{};
// parsing done; assign data buffer value.
tok_start = raw + prefixlen + uintlen;
const unsigned char *tok_end = tok_start + slen;
const std::vector<unsigned char> buf{tok_start, tok_end};
rlp_result.emplace_back(buf.cbegin(), buf.cend());
consumed = expected;
}
// Case 4: [prefix][list]
else if ((ch >= 0xc0) && (ch <= 0xf7)) {
const size_t payloadlen = ch - 0xc0;
const size_t expected = prefixlen + payloadlen;
// read list payload
const auto array = decode_array(raw, len, 0, payloadlen);
rlp_result.insert(rlp_result.end(), array.cbegin(), array.cend());
consumed = expected;
}
// Case 5: [prefix][list length][list]
else {
FC_ASSERT((ch >= 0xf8) && (ch <= 0xff));
const size_t uintlen = ch - 0xf7;
const size_t expected = prefixlen + uintlen;
if (len < expected)
return std::vector<std::string>{};
FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen);
const unsigned char *tok_start = raw + prefixlen;
if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes
return std::vector<std::string>{};
// read list length
const size_t payloadlen = to_int(tok_start, uintlen);
// special requirement for non-immediate length
if (payloadlen < (0x100 - RLP_listStart - RLP_maxUintLen))
return std::vector<std::string>{};
// read list payload
const auto array = decode_array(raw, len, uintlen, payloadlen);
rlp_result.insert(rlp_result.end(), array.cbegin(), array.cend());
consumed = prefixlen + uintlen + payloadlen;
}
return rlp_result;
}
std::vector<std::string> rlp_decoder::decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen) {
std::vector<std::string> rlp_result;
const size_t prefixlen = 1;
// validate list length, including possible addition overflows.
const size_t expected = prefixlen + uintlen + payloadlen;
if ((expected > len) || (payloadlen > len))
return std::vector<std::string>{};
size_t child_len = payloadlen;
const unsigned char *list_ent = raw + prefixlen + uintlen;
// recursively read until payloadlen bytes parsed, or error
while (child_len > 0) {
size_t child_consumed = 0;
const auto val = decode_rlp(list_ent, child_len, child_consumed);
rlp_result.insert(rlp_result.end(), val.cbegin(), val.cend());
list_ent += child_consumed;
child_len -= child_consumed;
}
return rlp_result;
}
uint64_t rlp_decoder::to_int(const unsigned char *raw, size_t len) {
if (len == 0)
return 0;
else if (len == 1)
return *raw;
else
return (raw[len - 1]) + (to_int(raw, len - 1) * 256);
}
std::vector<unsigned char> rlp_decoder::parse_hex(const std::string &str) {
return parse_hex(str.c_str());
}
std::vector<unsigned char> rlp_decoder::parse_hex(const char *psz) {
// convert hex dump to vector
std::vector<unsigned char> vch;
while (true) {
while (isspace(*psz))
psz++;
signed char c = hex_digit(*psz++);
if (c == (signed char)-1)
break;
unsigned char n = (c << 4);
c = hex_digit(*psz++);
if (c == (signed char)-1)
break;
n |= c;
vch.push_back(n);
}
return vch;
}
signed char rlp_decoder::hex_digit(char c) {
return p_util_hexdigit[(unsigned char)c];
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,102 +0,0 @@
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <boost/algorithm/hex.hpp>
#include <boost/format.hpp>
#include <stdlib.h>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
//! base_encoder
std::string base_encoder::encode_uint256(boost::multiprecision::uint256_t value) {
return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str();
}
std::string base_encoder::encode_address(const std::string &value) {
return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str();
}
std::string base_encoder::encode_string(const std::string &value) {
std::string data = (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value.size())).str();
data += boost::algorithm::hex(value) + std::string((64 - value.size() * 2 % 64), '0');
return data;
}
//! update_owners_encoder
std::string update_owners_encoder::encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id) const {
std::string data = "0x" + function_signature;
data += base_encoder::encode_uint256(64);
data += base_encoder::encode_uint256((owners_weights.size() * 2 + 3) * 32);
data += base_encoder::encode_uint256(owners_weights.size());
for (const auto &owner : owners_weights) {
data += base_encoder::encode_address(owner.first);
data += base_encoder::encode_uint256(owner.second);
}
data += base_encoder::encode_string(object_id);
return data;
}
//! withdrawal_encoder
std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) const {
std::string data = "0x" + function_signature;
data += base_encoder::encode_address(to);
data += base_encoder::encode_uint256(amount);
data += base_encoder::encode_uint256(32 * 3);
data += base_encoder::encode_string(object_id);
return data;
}
//! rlp_encoder
std::string rlp_encoder::encode(const std::string &s) {
return encode_rlp(hex2bytes(s));
}
std::string rlp_encoder::encode_length(int len, int offset) {
if (len < 56) {
std::string temp;
temp = (char)(len + offset);
return temp;
} else {
const std::string hexLength = to_hex(len);
const int lLength = hexLength.size() / 2;
const std::string fByte = to_hex(offset + 55 + lLength);
return hex2bytes(fByte + hexLength);
}
}
std::string rlp_encoder::hex2bytes(const std::string &s) {
std::string dest;
dest.resize(s.size() / 2);
hex2bin(s.c_str(), &dest[0]);
return dest;
}
std::string rlp_encoder::encode_rlp(const std::string &s) {
if (s.size() == 1 && (unsigned char)s[0] < 128)
return s;
else
return encode_length(s.size(), 128) + s;
}
int rlp_encoder::char2int(char input) {
if (input >= '0' && input <= '9')
return input - '0';
if (input >= 'A' && input <= 'F')
return input - 'A' + 10;
if (input >= 'a' && input <= 'f')
return input - 'a' + 10;
return -1;
}
void rlp_encoder::hex2bin(const char *src, char *target) {
while (*src && src[1]) {
*(target++) = char2int(*src) * 16 + char2int(src[1]);
src += 2;
}
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,229 +0,0 @@
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
#include <boost/algorithm/hex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <secp256k1_recovery.h>
#include <sha3/sha3.h>
#include <fc/crypto/elliptic.hpp>
#include <fc/crypto/hex.hpp>
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
const secp256k1_context *eth_context() {
static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
return ctx;
}
//! transaction
base_transaction::base_transaction(const std::string &raw_tx) {
}
//! transaction
transaction::transaction(const std::string &raw_tx) :
base_transaction{raw_tx} {
deserialize(raw_tx);
}
const transaction &transaction::sign(const std::string &private_key) const {
return *this;
}
std::string transaction::serialize() const {
boost::property_tree::ptree pt;
pt.put("from", from);
pt.put("to", to);
pt.put("data", data);
std::stringstream ss;
boost::property_tree::json_parser::write_json(ss, pt);
return ss.str();
}
void transaction::deserialize(const std::string &raw_tx) {
std::stringstream ss_tx(raw_tx);
boost::property_tree::ptree tx_json;
boost::property_tree::read_json(ss_tx, tx_json);
if (tx_json.count("from"))
from = tx_json.get<std::string>("from");
if (tx_json.count("to"))
to = tx_json.get<std::string>("to");
if (tx_json.count("data"))
data = tx_json.get<std::string>("data");
}
//! raw_transaction
raw_transaction::raw_transaction(const std::string &raw_tx) :
base_transaction{raw_tx} {
deserialize(raw_tx);
}
bytes raw_transaction::hash() const {
bytes hash;
hash.resize(32);
const auto transaction_string = boost::algorithm::unhex(remove_0x(serialize()));
keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data());
return hash;
}
signed_transaction raw_transaction::sign(const std::string &private_key) const {
//! Prepare signed transaction
signed_transaction tr;
tr.nonce = nonce;
tr.gas_price = gas_price;
tr.gas_limit = gas_limit;
tr.to = to;
tr.value = value;
tr.data = data;
const bytes priv_key = parse_hex(private_key);
int recid = 0;
secp256k1_ecdsa_recoverable_signature sig;
FC_ASSERT(secp256k1_ecdsa_sign_recoverable(eth_context(), &sig, (const unsigned char *)hash().data(), (const unsigned char *)priv_key.data(), NULL, NULL));
fc::ecc::compact_signature result;
FC_ASSERT(secp256k1_ecdsa_recoverable_signature_serialize_compact(eth_context(), (unsigned char *)result.begin() + 1, &recid, &sig));
bytes r;
for (int i = 1; i < 33; i++)
r.emplace_back((char)result.at(i));
bytes v = bytes{char(recid + from_hex<int>(chain_id) * 2 + 35)};
bytes s;
for (int i = 33; i < 65; i++)
s.emplace_back((char)result.at(i));
tr.r = fc::to_hex((char *)&r[0], r.size());
tr.v = fc::to_hex((char *)&v[0], v.size());
tr.s = fc::to_hex((char *)&s[0], s.size());
return tr;
}
std::string raw_transaction::serialize() const {
const std::string serialized = rlp_encoder::encode(remove_0x(nonce)) +
rlp_encoder::encode(remove_0x(gas_price)) +
rlp_encoder::encode(remove_0x(gas_limit)) +
rlp_encoder::encode(remove_0x(to)) +
rlp_encoder::encode(remove_0x(value)) +
rlp_encoder::encode(remove_0x(data)) +
rlp_encoder::encode(remove_0x(chain_id)) +
rlp_encoder::encode("") +
rlp_encoder::encode("");
return add_0x(bytes2hex(rlp_encoder::encode_length(serialized.size(), 192) + serialized));
}
void raw_transaction::deserialize(const std::string &raw_tx) {
const auto rlp_array = rlp_decoder::decode(remove_0x(raw_tx));
FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format");
nonce = !rlp_array.at(0).empty() ? add_0x(rlp_array.at(0)) : add_0x("0");
boost::algorithm::to_lower(nonce);
gas_price = add_0x(rlp_array.at(1));
boost::algorithm::to_lower(gas_price);
gas_limit = add_0x(rlp_array.at(2));
boost::algorithm::to_lower(gas_limit);
to = add_0x(rlp_array.at(3));
boost::algorithm::to_lower(to);
value = !rlp_array.at(4).empty() ? add_0x(rlp_array.at(4)) : add_0x("0");
boost::algorithm::to_lower(value);
data = !rlp_array.at(5).empty() ? add_0x(rlp_array.at(5)) : "";
boost::algorithm::to_lower(data);
chain_id = add_0x(rlp_array.at(6));
boost::algorithm::to_lower(chain_id);
}
//! signed_transaction
signed_transaction::signed_transaction(const std::string &raw_tx) :
base_transaction{raw_tx} {
deserialize(raw_tx);
}
std::string signed_transaction::recover(const std::string &chain_id) const {
fc::ecc::compact_signature input64;
fc::from_hex(r, (char *)&input64.at(1), 32);
fc::from_hex(v, (char *)&input64.at(0), 1);
int recid = input64.at(0) - from_hex<int>(chain_id) * 2 - 35;
fc::from_hex(s, (char *)&input64.at(33), 32);
secp256k1_ecdsa_recoverable_signature sig;
FC_ASSERT(secp256k1_ecdsa_recoverable_signature_parse_compact(eth_context(), &sig, (const unsigned char *)&input64.data[1], recid));
raw_transaction tr;
tr.nonce = nonce;
tr.gas_price = gas_price;
tr.gas_limit = gas_limit;
tr.to = to;
tr.value = value;
tr.data = data;
tr.chain_id = chain_id;
secp256k1_pubkey rawPubkey;
FC_ASSERT(secp256k1_ecdsa_recover(eth_context(), &rawPubkey, &sig, (const unsigned char *)tr.hash().data()));
std::array<uint8_t, 65> pubkey;
size_t biglen = 65;
FC_ASSERT(secp256k1_ec_pubkey_serialize(eth_context(), pubkey.data(), &biglen, &rawPubkey, SECP256K1_EC_UNCOMPRESSED));
const std::string out = std::string(pubkey.begin(), pubkey.end()).substr(1);
bytes hash;
hash.resize(32);
keccak_256((const unsigned char *)out.data(), out.size(), (unsigned char *)hash.data());
return add_0x(fc::to_hex((char *)&hash[0], hash.size()).substr(24));
}
std::string signed_transaction::serialize() const {
const std::string serialized = rlp_encoder::encode(remove_0x(nonce)) +
rlp_encoder::encode(remove_0x(gas_price)) +
rlp_encoder::encode(remove_0x(gas_limit)) +
rlp_encoder::encode(remove_0x(to)) +
rlp_encoder::encode(remove_0x(value)) +
rlp_encoder::encode(remove_0x(data)) +
rlp_encoder::encode(remove_0x(v)) +
rlp_encoder::encode(remove_0x(r)) +
rlp_encoder::encode(remove_0x(s));
return add_0x(bytes2hex(rlp_encoder::encode_length(serialized.size(), 192) + serialized));
}
void signed_transaction::deserialize(const std::string &raw_tx) {
const auto rlp_array = rlp_decoder::decode(remove_0x(raw_tx));
FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format");
nonce = !rlp_array.at(0).empty() ? add_0x(rlp_array.at(0)) : add_0x("0");
boost::algorithm::to_lower(nonce);
gas_price = add_0x(rlp_array.at(1));
boost::algorithm::to_lower(gas_price);
gas_limit = add_0x(rlp_array.at(2));
boost::algorithm::to_lower(gas_limit);
to = add_0x(rlp_array.at(3));
boost::algorithm::to_lower(to);
value = !rlp_array.at(4).empty() ? add_0x(rlp_array.at(4)) : add_0x("0");
boost::algorithm::to_lower(value);
data = !rlp_array.at(5).empty() ? add_0x(rlp_array.at(5)) : "";
boost::algorithm::to_lower(data);
v = add_0x(rlp_array.at(6));
boost::algorithm::to_lower(v);
r = add_0x(rlp_array.at(7));
boost::algorithm::to_lower(r);
s = add_0x(rlp_array.at(8));
boost::algorithm::to_lower(s);
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,5 +0,0 @@
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,52 +0,0 @@
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
#include <fc/crypto/hex.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
bytes parse_hex(const std::string &str) {
bytes vec(str.size() / 2);
fc::from_hex(str, vec.data(), vec.size());
return vec;
}
std::string bytes2hex(const std::string &s) {
std::string dest;
for (const auto &i : s)
dest += uchar2Hex((unsigned char)i);
return dest;
}
std::string uchar2Hex(unsigned char n) {
std::string dest;
dest.resize(2);
sprintf(&dest[0], "%X", n);
if (n < (unsigned char)16) {
dest[1] = dest[0];
dest[0] = '0';
}
return dest;
}
std::string add_0x(const std::string &s) {
if (s.size() > 1) {
if (s.substr(0, 2) == "0x")
return s;
}
return "0x" + s;
}
std::string remove_0x(const std::string &s) {
if (s.size() > 1) {
if (s.substr(0, 2) == "0x")
return s.substr(2);
}
return s;
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -8,6 +8,14 @@ using namespace graphene::chain;
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
const bytes op_num = {0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}; // OP_1 - OP_15 const bytes op_num = {0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}; // OP_1 - OP_15
enum address_types { MAINNET_SCRIPT = 5,
TESTNET_SCRIPT = 196 };
enum script_op {
OP_0 = 0x00,
OP_PUSH = 0x20,
OP_SIZE_34 = 0x22
};
class bitcoin_address { class bitcoin_address {
@ -96,9 +104,6 @@ private:
void create_address(); void create_address();
public: public:
enum address_types { MAINNET_SCRIPT = 5,
TESTNET_SCRIPT = 196 };
enum { OP_0 = 0x00, enum { OP_0 = 0x00,
OP_EQUAL = 0x87, OP_EQUAL = 0x87,
OP_HASH160 = 0xa9, OP_HASH160 = 0xa9,
@ -145,7 +150,7 @@ public:
btc_weighted_multisig_address() = default; btc_weighted_multisig_address() = default;
btc_weighted_multisig_address(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data, btc_weighted_multisig_address(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
network network_type = network::regtest); network network_type = network::regtest, payment_type type = payment_type::P2SH_WSH);
bytes get_redeem_script() const { bytes get_redeem_script() const {
return redeem_script_; return redeem_script_;
@ -190,7 +195,7 @@ class btc_one_or_weighted_multisig_address : public bitcoin_address {
public: public:
btc_one_or_weighted_multisig_address() = default; btc_one_or_weighted_multisig_address() = default;
btc_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data, btc_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
network network_type = network::regtest); network network_type = network::regtest, payment_type type = payment_type::P2SH_WSH);
bytes get_redeem_script() const { bytes get_redeem_script() const {
return redeem_script_; return redeem_script_;
} }

View file

@ -0,0 +1,36 @@
#pragma once
#include <curl/curl.h>
#include <functional>
#include <map>
typedef std::function<uint64_t()> get_fee_func_type;
namespace graphene { namespace peerplays_sidechain {
class estimate_fee_external {
public:
estimate_fee_external();
~estimate_fee_external();
uint64_t get_fee_external(uint16_t target_block);
private:
std::string get_response(std::string url);
// Here add your custom parser for external url. Take care of incremental name
// and populate the list of url_parsers bellow paired with the function
uint64_t parse_and_get_fee_1();
uint64_t parse_and_get_fee_2();
uint64_t parse_and_get_fee_3();
const std::map<std::string, get_fee_func_type> url_get_fee_parsers{
{"https://www.bitgo.com/api/v2/btc/tx/fee", std::bind(&estimate_fee_external::parse_and_get_fee_1, this)},
{"https://bitcoiner.live/api/fees/estimates/latest", std::bind(&estimate_fee_external::parse_and_get_fee_2, this)},
{"https://api.blockchain.info/mempool/fees", std::bind(&estimate_fee_external::parse_and_get_fee_3, this)}};
std::string response;
uint16_t target_block;
CURL *curl{nullptr};
};
}} // namespace graphene::peerplays_sidechain

View file

@ -0,0 +1,47 @@
#pragma once
#include <bitcoin/client/obelisk_client.hpp>
#include <bitcoin/client/socket_stream.hpp>
#include <bitcoin/system/chain/block.hpp>
#include <boost/signals2.hpp>
#define LIBBITCOIN_SERVER_TIMEOUT (10)
#define LIBBITCOIN_SERVER_RETRIES (100)
#define GENESIS_MAINNET_HASH "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
#define GENESIS_TESTNET_HASH "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
#define GENESIS_REGTEST_HASH "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
namespace graphene { namespace peerplays_sidechain {
typedef std::function<void(const libbitcoin::chain::block &)>
block_update_handler;
struct list_unspent_replay {
std::string hash;
uint64_t value;
uint32_t index;
};
class libbitcoin_client {
public:
libbitcoin_client(std::string url);
std::string send_transaction(const std::string tx);
libbitcoin::chain::output::list get_transaction(std::string tx_id, std::string &tx_hash, uint32_t &confirmitions);
std::vector<list_unspent_replay> listunspent(std::string address, double amount);
bool get_is_test_net();
private:
libbitcoin::client::obelisk_client obelisk_client;
libbitcoin::protocol::zmq::identifier id;
std::string protocol;
std::string host;
std::string port;
std::string url;
bool is_connected = false;
};
}} // namespace graphene::peerplays_sidechain

View file

@ -23,16 +23,15 @@ protected:
std::string send_post_request(std::string method, std::string params, bool show_log); std::string send_post_request(std::string method, std::string params, bool show_log);
std::string url; std::string url;
std::string user;
std::string password;
bool debug_rpc_calls;
std::string protocol; std::string protocol;
std::string host; std::string host;
std::string port; std::string port;
std::string target; std::string target;
std::string authorization; std::string authorization;
std::string user;
std::string password;
bool debug_rpc_calls;
uint32_t request_id; uint32_t request_id;
private: private:

View file

@ -2,11 +2,4 @@
#include <graphene/chain/protocol/asset.hpp> #include <graphene/chain/protocol/asset.hpp>
namespace graphene { namespace peerplays_sidechain {
std::string base64_encode(const std::string &s);
std::string base64_decode(const std::string &s);
std::string object_id_to_string(graphene::chain::object_id_type id); std::string object_id_to_string(graphene::chain::object_id_type id);
}} // namespace graphene::peerplays_sidechain

View file

@ -1,28 +0,0 @@
#pragma once
#include <string>
#include <vector>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
class rlp_decoder {
private:
enum RLP_constants {
RLP_maxUintLen = 8,
RLP_bufferLenStart = 0x80,
RLP_listStart = 0xc0,
};
public:
static std::vector<std::string> decode(const std::string &str);
private:
static std::vector<std::string> decode_rlp(const unsigned char *raw, size_t len, size_t &consumed);
static std::vector<std::string> decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen);
static uint64_t to_int(const unsigned char *raw, size_t len);
static std::vector<unsigned char> parse_hex(const std::string &str);
static std::vector<unsigned char> parse_hex(const char *psz);
static signed char hex_digit(char c);
};
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,73 +0,0 @@
#pragma once
#include <boost/multiprecision/cpp_int.hpp>
#include <string>
#include <vector>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
class base_encoder {
public:
static std::string encode_uint256(boost::multiprecision::uint256_t value);
static std::string encode_address(const std::string &value);
static std::string encode_string(const std::string &value);
};
class update_owners_encoder {
public:
const std::string function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string)
std::string encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id) const;
};
class withdrawal_encoder {
public:
const std::string function_signature = "e088747b"; //! withdraw(address,uint256,string)
std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) const;
};
class rlp_encoder {
public:
static std::string encode(const std::string &s);
static std::string encode_length(int len, int offset);
static std::string hex2bytes(const std::string &s);
private:
static std::string encode_rlp(const std::string &s);
static int char2int(char input);
static void hex2bin(const char *src, char *target);
};
/*class ethereum_function_call_encoder {
public:
enum operation_t {
OPERATION_CALL,
OPERATION_DELEGATE_CALL
};
static constexpr const char *const default_prev_addr = "0000000000000000000000000000000000000001";
std::string encode_function_signature(const std::string &function_signature);
std::string encode_address(const std::string &addr);
std::string encode_uint256(const std::string &value);
std::string encode_uint8(uint8_t value);
std::string encode_bytes(const std::string &values);
};
class safe_transaction_encoder {
public:
static constexpr const char *const default_safe_tx_gas = "0";
static constexpr const char *const default_data_gas = "0";
static constexpr const char *const default_gas_price = "0";
static constexpr const char *const default_gas_token = "0000000000000000000000000000000000000000";
static constexpr const char *const default_refund_receiver = "0000000000000000000000000000000000000000";
std::string create_safe_address(const std::vector<std::string> &owner_addresses, uint32_t threshold);
std::string build_transaction(const std::string &safe_account_addr, const std::string &value, const std::string &data, uint8_t operation, const std::string &safeTxGas, const std::string &dataGas, const std::string &gasPrice, const std::string &gasToken, const std::string &refundReceiver);
private:
ethereum_function_call_encoder m_ethereum_function_call_encoder;
};*/
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,163 +0,0 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
class base_transaction {
public:
base_transaction() = default;
base_transaction(const std::string &raw_tx);
virtual std::string serialize() const = 0;
virtual void deserialize(const std::string &raw_tx) = 0;
};
class transaction : base_transaction {
public:
std::string from;
std::string to;
std::string data;
transaction() = default;
transaction(const std::string &raw_tx);
const transaction &sign(const std::string &private_key) const;
virtual std::string serialize() const override;
virtual void deserialize(const std::string &raw_tx) override;
};
class signed_transaction;
class raw_transaction : base_transaction {
public:
std::string nonce;
std::string gas_price;
std::string gas_limit;
std::string to;
std::string value;
std::string data;
std::string chain_id;
raw_transaction() = default;
raw_transaction(const std::string &raw_tx);
bytes hash() const;
signed_transaction sign(const std::string &private_key) const;
virtual std::string serialize() const override;
virtual void deserialize(const std::string &raw_tx) override;
};
class signed_transaction : base_transaction {
public:
std::string nonce;
std::string gas_price;
std::string gas_limit;
std::string to;
std::string value;
std::string data;
std::string v;
std::string r;
std::string s;
signed_transaction() = default;
signed_transaction(const std::string &raw_tx);
std::string recover(const std::string &chain_id) const;
virtual std::string serialize() const override;
virtual void deserialize(const std::string &raw_tx) override;
};
}}} // namespace graphene::peerplays_sidechain::ethereum
// Example 1
//{
// "blockHash": "0x64a6706ecaf5a97b7f3e047abb20ff223ce82c6994d80e68fdb1fdfb38d0209c",
// "blockNumber": "0xe5827c",
// "from": "0x8614c67e085f2334010f2a28e806c6f1cc176d12",
// "gas": "0x38822",
// "gasPrice": "0xce42cba69",
// "maxFeePerGas": "0xddb4d8d16",
// "maxPriorityFeePerGas": "0x3b9aca00",
// "hash": "0xeac92ea09fa8eb3ca2fb0d156cceb38ae69d4345869d41e8e49d5ecbcbb622dc",
// "input": "0x5ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde03121500000000000000000000000000000000000000000000000000000000",
// "nonce": "0x32",
// "to": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45",
// "transactionIndex": "0xb6",
// "value": "0x2514d9d7d7d8000",
// "type": "0x2",
// "accessList": [],
// "chainId": "0x1",
// "v": "0x1",
// "r": "0x2f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28c",
// "s": "0x782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14"
//}
//
//"0xf9021332850ce42cba69830388229468b3465833fb72a70ecdf485e0e4c7bd8665fc458802514d9d7d7d8000b901a45ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde0312150000000000000000000000000000000000000000000000000000000001a02f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28ca0782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14"
//
//{
// "nonce": 50,
// "gasPrice": {
// "_hex": "0x0ce42cba69"
// },
// "gasLimit": {
// "_hex": "0x038822"
// },
// "to": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45",
// "value": {
// "_hex": "0x02514d9d7d7d8000"
// },
// "data": "0x5ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde03121500000000000000000000000000000000000000000000000000000000",
// "v": 1,
// "r": "0x2f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28c",
// "s": "0x782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14"
//}
// Example 2
//{
// "blockHash": "0xe2ae3afd86dc7343c7fb753441447a0a51bb19499325ad6e278256f0cd1b5894",
// "blockNumber": "0xe58271",
// "from": "0xb895ade6d337fbb8cb97f2ea7da43106c7f5cc26",
// "gas": "0x5208",
// "gasPrice": "0xe6f3b322e",
// "maxFeePerGas": "0x1322455fd3",
// "maxPriorityFeePerGas": "0x53724e00",
// "hash": "0xed29b56e52ad2d452e25b8ec70c37f59d935cd6d0f8fe8e83b256f3ffdfd3fce",
// "input": "0x",
// "nonce": "0x37",
// "to": "0x176386b6ffc469ac049f9ec1f6cc0efd1d09b373",
// "transactionIndex": "0x8a",
// "value": "0x4563918244f40000",
// "type": "0x2",
// "accessList": [],
// "chainId": "0x1",
// "v": "0x0",
// "r": "0xdcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4c",
// "s": "0x28c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a"
//}
//
//"0xf86c37850e6f3b322e82520894176386b6ffc469ac049f9ec1f6cc0efd1d09b373884563918244f400008000a0dcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4ca028c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a"
//
//{
// "nonce": 55,
// "gasPrice": {
// "_hex": "0x0e6f3b322e"
// },
// "gasLimit": {
// "_hex": "0x5208"
// },
// "to": "0x176386b6ffc469ac049f9ec1f6cc0efd1d09b373",
// "value": {
// "_hex": "0x4563918244f40000"
// },
// "data": "0x",
// "v": 0,
// "r": "0xdcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4c",
// "s": "0x28c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a"
//}

View file

@ -1,12 +0,0 @@
#pragma once
#include <boost/multiprecision/cpp_int.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
typedef uint64_t chain_id_type;
typedef uint64_t network_id_type;
using bytes = std::vector<char>;
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,37 +0,0 @@
#pragma once
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
bytes parse_hex(const std::string &str);
std::string bytes2hex(const std::string &s);
std::string uchar2Hex(unsigned char n);
std::string add_0x(const std::string &s);
std::string remove_0x(const std::string &s);
template <typename T>
std::string to_hex(const T &val) {
std::stringstream stream;
stream << std::hex << val;
std::string result(stream.str());
if (result.size() % 2)
result = "0" + result;
return result;
}
template <typename T>
T from_hex(const std::string &s) {
T val;
std::stringstream stream;
stream << std::hex << s;
stream >> val;
return val;
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -57,6 +57,7 @@ protected:
sidechain_type sidechain; sidechain_type sidechain;
bool debug_rpc_calls; bool debug_rpc_calls;
bool use_bitcoind_client;
std::map<std::string, std::string> private_keys; std::map<std::string, std::string> private_keys;

View file

@ -2,6 +2,7 @@
#include <graphene/peerplays_sidechain/common/rpc_client.hpp> #include <graphene/peerplays_sidechain/common/rpc_client.hpp>
#include <graphene/peerplays_sidechain/sidechain_net_handler.hpp> #include <graphene/peerplays_sidechain/sidechain_net_handler.hpp>
#include <graphene/peerplays_sidechain/bitcoin/libbitcoin_client.hpp>
#include <string> #include <string>
#include <thread> #include <thread>
@ -13,6 +14,7 @@
#include <fc/network/http/connection.hpp> #include <fc/network/http/connection.hpp>
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_address.hpp> #include <graphene/peerplays_sidechain/bitcoin/bitcoin_address.hpp>
#include <graphene/peerplays_sidechain/bitcoin/estimate_fee_external.hpp>
namespace graphene { namespace peerplays_sidechain { namespace graphene { namespace peerplays_sidechain {
@ -23,7 +25,27 @@ public:
uint64_t amount_; uint64_t amount_;
}; };
class bitcoin_rpc_client : public rpc_client { class btc_txin {
public:
std::vector<std::string> tx_address;
uint64_t tx_amount;
uint64_t tx_vout;
};
class btc_tx {
public:
std::string tx_txid;
uint32_t tx_confirmations;
std::vector<btc_txin> tx_in_list;
};
class block_data {
public:
std::string block_hash;
libbitcoin::chain::block block;
};
class bitcoin_client_base {
public: public:
enum class multi_type { enum class multi_type {
script, script,
@ -41,14 +63,28 @@ public:
std::string label; std::string label;
}; };
virtual uint64_t estimatesmartfee(uint16_t conf_target = 128) = 0;
virtual std::vector<info_for_vin> getblock(const block_data &block, int32_t verbosity = 2) = 0;
virtual btc_tx getrawtransaction(const std::string &txid, const bool verbose = false) = 0;
virtual void getnetworkinfo() {;};
virtual std::string getblockchaininfo() = 0;
virtual std::vector<btc_txout> listunspent_by_address_and_amount(const std::string &address, double transfer_amount, const uint32_t minconf = 1, const uint32_t maxconf = 9999999) = 0;
virtual std::string sendrawtransaction(const std::string &tx_hex) = 0;
virtual void importmulti(const std::vector<multi_params> &address_or_script_array, const bool rescan = true){;};
virtual std::string loadwallet(const std::string &filename) { return ""; };
virtual std::string walletlock() { return ""; };
virtual bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60) { return false; };
};
class bitcoin_rpc_client : public bitcoin_client_base, public rpc_client {
public:
public: public:
bitcoin_rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls); bitcoin_rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls);
std::string createwallet(const std::string &wallet_name);
uint64_t estimatesmartfee(uint16_t conf_target = 128); uint64_t estimatesmartfee(uint16_t conf_target = 128);
std::string getblock(const std::string &block_hash, int32_t verbosity = 2); std::vector<info_for_vin> getblock(const block_data &block, int32_t verbosity = 2);
std::string getrawtransaction(const std::string &txid, const bool verbose = false); btc_tx getrawtransaction(const std::string &txid, const bool verbose = false);
std::string getnetworkinfo(); void getnetworkinfo();
std::string getblockchaininfo(); std::string getblockchaininfo();
void importmulti(const std::vector<multi_params> &address_or_script_array, const bool rescan = true); void importmulti(const std::vector<multi_params> &address_or_script_array, const bool rescan = true);
std::vector<btc_txout> listunspent(const uint32_t minconf = 1, const uint32_t maxconf = 9999999); std::vector<btc_txout> listunspent(const uint32_t minconf = 1, const uint32_t maxconf = 9999999);
@ -60,35 +96,74 @@ public:
private: private:
std::string ip; std::string ip;
uint32_t rpc_port;
std::string user; std::string user;
std::string password; std::string password;
std::string wallet_name; std::string wallet;
std::string wallet_password; std::string wallet_password;
uint32_t bitcoin_major_version;
};
class bitcoin_libbitcoin_client : public bitcoin_client_base, public libbitcoin_client {
public:
bitcoin_libbitcoin_client(std::string url);
uint64_t estimatesmartfee(uint16_t conf_target = 128);
std::vector<info_for_vin> getblock(const block_data &block, int32_t verbosity = 2);
btc_tx getrawtransaction(const std::string &txid, const bool verbose = false);
std::string getblockchaininfo();
std::vector<btc_txout> listunspent_by_address_and_amount(const std::string &address, double transfer_amount, const uint32_t minconf = 1, const uint32_t maxconf = 9999999);
std::string sendrawtransaction(const std::string &tx_hex);
private:
bool is_test_net = false;
std::unique_ptr<estimate_fee_external> estimate_fee_ext;
}; };
// ============================================================================= // =============================================================================
class zmq_listener { class zmq_listener_base {
public:
virtual ~zmq_listener_base(){};
zmq_listener_base(std::string _ip, uint32_t _zmq) {
ip = _ip;
zmq_port = _zmq;
stopped = false;
};
virtual void start() = 0;
boost::signals2::signal<void(const block_data &)> event_received;
protected:
std::string ip;
uint32_t zmq_port;
std::atomic_bool stopped;
std::thread thr;
};
class zmq_listener : public zmq_listener_base {
public: public:
zmq_listener(std::string _ip, uint32_t _zmq); zmq_listener(std::string _ip, uint32_t _zmq);
virtual ~zmq_listener(); virtual ~zmq_listener();
void start(); void start();
boost::signals2::signal<void(const std::string &)> event_received;
private: private:
void handle_zmq(); void handle_zmq();
std::vector<zmq::message_t> receive_multipart(); std::vector<zmq::message_t> receive_multipart();
std::string ip;
uint32_t zmq_port;
zmq::context_t ctx; zmq::context_t ctx;
zmq::socket_t socket; zmq::socket_t socket;
};
std::atomic_bool stopped; class zmq_listener_libbitcoin : public zmq_listener_base {
std::thread thr; public:
zmq_listener_libbitcoin(std::string _ip, uint32_t _zmq);
virtual ~zmq_listener_libbitcoin();
void start();
private:
void handle_block();
libbitcoin::protocol::zmq::context context;
libbitcoin::protocol::zmq::socket socket;
libbitcoin::protocol::zmq::poller poller;
}; };
// ============================================================================= // =============================================================================
@ -108,21 +183,21 @@ public:
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
private: private:
std::string ip; std::string bitcoin_node_ip;
uint32_t zmq_port; std::string libbitcoin_server_ip;
uint32_t libbitcoin_zmq_port;
uint32_t bitcoin_node_zmq_port;
uint32_t rpc_port; uint32_t rpc_port;
std::string rpc_user; std::string rpc_user;
std::string rpc_password; std::string rpc_password;
std::string wallet_name; std::string wallet_name;
std::string wallet_password; std::string wallet_password;
std::unique_ptr<bitcoin_rpc_client> bitcoin_client; std::unique_ptr<bitcoin_client_base> bitcoin_client;
std::unique_ptr<zmq_listener> listener; std::unique_ptr<zmq_listener_base> listener;
fc::future<void> on_changed_objects_task; fc::future<void> on_changed_objects_task;
bitcoin::bitcoin_address::network network_type; bitcoin::bitcoin_address::network network_type;
uint32_t bitcoin_major_version;
std::mutex event_handler_mutex; std::mutex event_handler_mutex;
typedef std::lock_guard<decltype(event_handler_mutex)> scoped_lock; typedef std::lock_guard<decltype(event_handler_mutex)> scoped_lock;
@ -137,9 +212,8 @@ private:
std::string sign_transaction(const sidechain_transaction_object &sto); std::string sign_transaction(const sidechain_transaction_object &sto);
std::string send_transaction(const sidechain_transaction_object &sto); std::string send_transaction(const sidechain_transaction_object &sto);
void handle_event(const std::string &event_data); void handle_event(const block_data &event_data);
std::string get_redeemscript_for_userdeposit(const std::string &user_address); std::string get_redeemscript_for_userdeposit(const std::string &user_address);
std::vector<info_for_vin> extract_info_from_block(const std::string &_block);
void on_changed_objects(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts); void on_changed_objects(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts);
void on_changed_objects_cb(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts); void on_changed_objects_cb(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts);
}; };

View file

@ -1,75 +0,0 @@
#pragma once
#include <graphene/peerplays_sidechain/sidechain_net_handler.hpp>
#include <string>
#include <boost/signals2.hpp>
#include <graphene/peerplays_sidechain/common/rpc_client.hpp>
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
namespace graphene { namespace peerplays_sidechain {
class ethereum_rpc_client : public rpc_client {
public:
ethereum_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls);
std::string admin_node_info();
std::string eth_get_block_by_number(std::string block_number, bool full_block);
std::string eth_get_logs(std::string wallet_contract_address);
std::string net_version();
std::string eth_get_transaction_count(const std::string &params);
std::string eth_gas_price();
std::string get_chain_id();
std::string get_network_id();
std::string get_nonce(const std::string &address);
std::string get_gas_price();
std::string get_gas_limit();
std::string eth_send_transaction(const std::string &params);
std::string eth_send_raw_transaction(const std::string &params);
std::string eth_get_transaction_receipt(const std::string &params);
};
class sidechain_net_handler_ethereum : public sidechain_net_handler {
public:
sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options);
virtual ~sidechain_net_handler_ethereum();
bool process_proposal(const proposal_object &po);
void process_primary_wallet();
void process_sidechain_addresses();
bool process_deposit(const son_wallet_deposit_object &swdo);
bool process_withdrawal(const son_wallet_withdraw_object &swwo);
std::string process_sidechain_transaction(const sidechain_transaction_object &sto);
std::string send_sidechain_transaction(const sidechain_transaction_object &sto);
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
private:
std::string rpc_url;
std::string rpc_user;
std::string rpc_password;
std::string wallet_contract_address;
ethereum_rpc_client *rpc_client;
ethereum::chain_id_type chain_id;
ethereum::network_id_type network_id;
std::string create_primary_wallet_transaction(const std::vector<son_info> &son_pubkeys, const std::string &object_id);
std::string create_deposit_transaction(const son_wallet_deposit_object &swdo);
std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo);
std::string sign_transaction(const sidechain_transaction_object &sto);
uint64_t last_block_received;
fc::future<void> _listener_task;
boost::signals2::signal<void(const std::string &)> event_received;
void schedule_ethereum_listener();
void ethereum_listener_loop();
void handle_event(const std::string &event_data);
};
}} // namespace graphene::peerplays_sidechain

View file

@ -6,14 +6,15 @@
#include <boost/signals2.hpp> #include <boost/signals2.hpp>
#include <fc/network/http/connection.hpp>
#include <graphene/peerplays_sidechain/common/rpc_client.hpp> #include <graphene/peerplays_sidechain/common/rpc_client.hpp>
#include <graphene/peerplays_sidechain/hive/types.hpp> #include <graphene/peerplays_sidechain/hive/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace graphene { namespace peerplays_sidechain {
class hive_rpc_client : public rpc_client { class hive_node_rpc_client : public rpc_client {
public: public:
hive_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); hive_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls);
std::string account_history_api_get_transaction(std::string transaction_id); std::string account_history_api_get_transaction(std::string transaction_id);
std::string block_api_get_block(uint32_t block_number); std::string block_api_get_block(uint32_t block_number);
@ -47,12 +48,10 @@ public:
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
private: private:
std::string rpc_url; std::string node_rpc_url;
std::string rpc_user; std::string node_rpc_user;
std::string rpc_password; std::string node_rpc_password;
std::string wallet_account_name; hive_node_rpc_client *node_rpc_client;
hive_rpc_client *rpc_client;
hive::chain_id_type chain_id; hive::chain_id_type chain_id;
hive::network network_type; hive::network network_type;

View file

@ -165,6 +165,7 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
cli.add_options()("sidechain-retry-threshold", bpo::value<uint16_t>()->default_value(150), "Sidechain retry throttling threshold"); cli.add_options()("sidechain-retry-threshold", bpo::value<uint16_t>()->default_value(150), "Sidechain retry throttling threshold");
cli.add_options()("debug-rpc-calls", bpo::value<bool>()->default_value(false), "Outputs RPC calls to console"); cli.add_options()("debug-rpc-calls", bpo::value<bool>()->default_value(false), "Outputs RPC calls to console");
cli.add_options()("use-bitcoind-client", bpo::value<bool>()->default_value(false), "Use bitcoind client instead of libbitcoin client");
cli.add_options()("bitcoin-sidechain-enabled", bpo::value<bool>()->default_value(false), "Bitcoin sidechain handler enabled"); cli.add_options()("bitcoin-sidechain-enabled", bpo::value<bool>()->default_value(false), "Bitcoin sidechain handler enabled");
cli.add_options()("bitcoin-node-ip", bpo::value<string>()->default_value("127.0.0.1"), "IP address of Bitcoin node"); cli.add_options()("bitcoin-node-ip", bpo::value<string>()->default_value("127.0.0.1"), "IP address of Bitcoin node");
@ -172,24 +173,18 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
cli.add_options()("bitcoin-node-rpc-port", bpo::value<uint32_t>()->default_value(8332), "RPC port of Bitcoin node"); cli.add_options()("bitcoin-node-rpc-port", bpo::value<uint32_t>()->default_value(8332), "RPC port of Bitcoin node");
cli.add_options()("bitcoin-node-rpc-user", bpo::value<string>()->default_value("1"), "Bitcoin RPC user"); cli.add_options()("bitcoin-node-rpc-user", bpo::value<string>()->default_value("1"), "Bitcoin RPC user");
cli.add_options()("bitcoin-node-rpc-password", bpo::value<string>()->default_value("1"), "Bitcoin RPC password"); cli.add_options()("bitcoin-node-rpc-password", bpo::value<string>()->default_value("1"), "Bitcoin RPC password");
cli.add_options()("bitcoin-wallet-name", bpo::value<string>(), "Bitcoin wallet name"); cli.add_options()("libbitcoin-server-ip", bpo::value<string>()->default_value("127.0.0.1"), "Libbitcoin server IP address");
cli.add_options()("libbitcoin-server-zmq-port", bpo::value<uint32_t>()->default_value(9093), "ZMQ port of libbitcoin server");
cli.add_options()("bitcoin-wallet-name", bpo::value<string>(), "Bitcoin wallet");
cli.add_options()("bitcoin-wallet-password", bpo::value<string>(), "Bitcoin wallet password"); cli.add_options()("bitcoin-wallet-password", bpo::value<string>(), "Bitcoin wallet password");
cli.add_options()("bitcoin-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")), cli.add_options()("bitcoin-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")),
"Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)"); "Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)");
cli.add_options()("ethereum-sidechain-enabled", bpo::value<bool>()->default_value(false), "Ethereum sidechain handler enabled");
cli.add_options()("ethereum-node-rpc-url", bpo::value<string>()->default_value("127.0.0.1:8545"), "Ethereum node RPC URL [http[s]://]host[:port]");
cli.add_options()("ethereum-node-rpc-user", bpo::value<string>(), "Ethereum RPC user");
cli.add_options()("ethereum-node-rpc-password", bpo::value<string>(), "Ethereum RPC password");
cli.add_options()("ethereum-wallet-contract-address", bpo::value<string>(), "Ethereum wallet contract address");
cli.add_options()("ethereum-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", "9bedac2bd8fe2a6f6528e066c67fc8ac0622e96828d40c0e820d83c5bd2b0589")),
"Tuple of [Ethereum public key, Ethereum private key] (may specify multiple times)");
cli.add_options()("hive-sidechain-enabled", bpo::value<bool>()->default_value(false), "Hive sidechain handler enabled"); cli.add_options()("hive-sidechain-enabled", bpo::value<bool>()->default_value(false), "Hive sidechain handler enabled");
cli.add_options()("hive-node-rpc-url", bpo::value<string>()->default_value("127.0.0.1:28090"), "Hive node RPC URL [http[s]://]host[:port]"); cli.add_options()("hive-node-rpc-url", bpo::value<string>()->default_value("127.0.0.1:28090"), "Hive node RPC URL [http[s]://]host[:port]");
cli.add_options()("hive-node-rpc-user", bpo::value<string>(), "Hive node RPC user"); cli.add_options()("hive-node-rpc-user", bpo::value<string>(), "Hive node RPC user");
cli.add_options()("hive-node-rpc-password", bpo::value<string>(), "Hive node RPC password"); cli.add_options()("hive-node-rpc-password", bpo::value<string>(), "Hive node RPC password");
cli.add_options()("hive-wallet-account-name", bpo::value<string>(), "Hive wallet account name");
cli.add_options()("hive-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", "5JNHfZYKGaomSFvd4NUdQ9qMcEAC43kujbfjueTHpVapX1Kzq2n")), cli.add_options()("hive-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", "5JNHfZYKGaomSFvd4NUdQ9qMcEAC43kujbfjueTHpVapX1Kzq2n")),
"Tuple of [Hive public key, Hive private key] (may specify multiple times)"); "Tuple of [Hive public key, Hive private key] (may specify multiple times)");
@ -237,42 +232,49 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt
} }
sidechain_enabled_bitcoin = options.at("bitcoin-sidechain-enabled").as<bool>(); sidechain_enabled_bitcoin = options.at("bitcoin-sidechain-enabled").as<bool>();
config_ready_bitcoin = options.count("bitcoin-node-ip") && config_ready_bitcoin = (((options.count("libbitcoin-server-ip") && options.count("libbitcoin-server-zmq-port")) ||
options.count("bitcoin-node-zmq-port") && options.count("bitcoin-node-rpc-port") && (options.count("bitcoin-node-ip") && options.count("bitcoin-node-zmq-port") &&
options.count("bitcoin-node-rpc-user") && options.count("bitcoin-node-rpc-password") && options.count("bitcoin-node-rpc-port") && options.count("bitcoin-node-rpc-user") &&
options.count("bitcoin-wallet-name") && options.count("bitcoin-wallet-password") && options.count("bitcoin-node-rpc-password"))) &&
options.count("bitcoin-private-key"); /*options.count("bitcoin-wallet") && options.count("bitcoin-wallet-password") &&*/
if (sidechain_enabled_bitcoin && !config_ready_bitcoin) { options.count("bitcoin-private-key"));
if (!config_ready_bitcoin) {
wlog("Haven't set up Bitcoin sidechain parameters"); wlog("Haven't set up Bitcoin sidechain parameters");
} }
sidechain_enabled_ethereum = options.at("ethereum-sidechain-enabled").as<bool>(); //sidechain_enabled_ethereum = options.at("ethereum-sidechain-enabled").as<bool>();
config_ready_ethereum = options.count("ethereum-node-rpc-url") && //config_ready_ethereum = options.count("ethereum-node-ip") &&
/*options.count("ethereum-node-rpc-user") && options.count("ethereum-node-rpc-password") &&*/ // options.count("ethereum-address") &&
options.count("ethereum-wallet-contract-address") && // options.count("ethereum-public-key") && options.count("ethereum-private-key");
options.count("ethereum-private-key"); //if (!config_ready_ethereum) {
if (sidechain_enabled_ethereum && !config_ready_ethereum) { // wlog("Haven't set up Ethereum sidechain parameters");
wlog("Haven't set up Ethereum sidechain parameters"); //}
}
sidechain_enabled_hive = options.at("hive-sidechain-enabled").as<bool>(); sidechain_enabled_hive = options.at("hive-sidechain-enabled").as<bool>();
config_ready_hive = options.count("hive-node-rpc-url") && config_ready_hive = options.count("hive-node-rpc-url") &&
/*options.count("hive-node-rpc-user") && options.count("hive-node-rpc-password") &&*/ /*options.count("hive-node-rpc-user") && options.count("hive-node-rpc-password") &&*/
options.count("hive-wallet-account-name") &&
options.count("hive-private-key"); options.count("hive-private-key");
if (sidechain_enabled_hive && !config_ready_hive) { if (!config_ready_hive) {
wlog("Haven't set up Hive sidechain parameters"); wlog("Haven't set up Hive sidechain parameters");
} }
#ifdef ENABLE_PEERPLAYS_ASSET_DEPOSITS #ifdef ENABLE_PEERPLAYS_ASSET_DEPOSITS
sidechain_enabled_peerplays = true; sidechain_enabled_peerplays = true; //options.at("peerplays-sidechain-enabled").as<bool>();
#else #else
sidechain_enabled_peerplays = false; sidechain_enabled_peerplays = false;
#endif #endif
config_ready_peerplays = true; config_ready_peerplays = true;
if (sidechain_enabled_peerplays && !config_ready_peerplays) { if (!config_ready_peerplays) {
wlog("Haven't set up Peerplays sidechain parameters"); wlog("Haven't set up Peerplays sidechain parameters");
} }
if (!(config_ready_bitcoin &&
/*config_ready_ethereum &&*/
config_ready_hive &&
config_ready_peerplays)) {
wlog("Haven't set up any sidechain parameters");
throw;
}
} }
void peerplays_sidechain_plugin_impl::plugin_startup() { void peerplays_sidechain_plugin_impl::plugin_startup() {
@ -292,10 +294,10 @@ void peerplays_sidechain_plugin_impl::plugin_startup() {
ilog("Bitcoin sidechain handler running"); ilog("Bitcoin sidechain handler running");
} }
if (sidechain_enabled_ethereum && config_ready_ethereum) { //if (sidechain_enabled_ethereum && config_ready_ethereum) {
net_handlers.at(sidechain_type::ethereum) = net_handler_factory.create_handler(sidechain_type::ethereum, options); // net_manager->create_handler(sidechain_type::ethereum, options);
ilog("Ethereum sidechain handler running"); // ilog("Ethereum sidechain handler running");
} //}
if (sidechain_enabled_hive && config_ready_hive) { if (sidechain_enabled_hive && config_ready_hive) {
net_handlers.at(sidechain_type::hive) = net_handler_factory.create_handler(sidechain_type::hive, options); net_handlers.at(sidechain_type::hive) = net_handler_factory.create_handler(sidechain_type::hive, options);

View file

@ -172,21 +172,18 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
#ifdef ENABLE_PEERPLAYS_ASSET_DEPOSITS #ifdef ENABLE_PEERPLAYS_ASSET_DEPOSITS
//enable_peerplays_asset_deposits = (sed.sidechain == sidechain_type::peerplays) && //enable_peerplays_asset_deposits = (sed.sidechain == sidechain_type::peerplays) &&
// (sed.sidechain_currency.compare("BTC") != 0) && // (sed.sidechain_currency.compare("BTC") != 0) &&
// (sed.sidechain_currency.compare("ETH") != 0) &&
// (sed.sidechain_currency.compare("HBD") != 0) && // (sed.sidechain_currency.compare("HBD") != 0) &&
// (sed.sidechain_currency.compare("HIVE") != 0); // (sed.sidechain_currency.compare("HIVE") != 0);
#endif #endif
bool deposit_condition = (sed.peerplays_to == gpo.parameters.son_account()) && bool deposit_condition = (sed.peerplays_to == gpo.parameters.son_account()) &&
(((sed.sidechain == sidechain_type::bitcoin) && (sed.sidechain_currency.compare("BTC") == 0)) || (((sed.sidechain == sidechain_type::bitcoin) && (sed.sidechain_currency.compare("BTC") == 0)) ||
((sed.sidechain == sidechain_type::ethereum) && (sed.sidechain_currency.compare("ETH") == 0)) ||
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HBD") == 0)) || ((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HBD") == 0)) ||
((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HIVE") == 0)) || ((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HIVE") == 0)) ||
enable_peerplays_asset_deposits); enable_peerplays_asset_deposits);
bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain == sidechain) && //! Fixme -> 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.btc_asset())) ||
(sed.sidechain_currency == object_id_to_string(gpo.parameters.eth_asset())) ||
(sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset())) || (sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset())) ||
(sed.sidechain_currency == object_id_to_string(gpo.parameters.hive_asset()))); (sed.sidechain_currency == object_id_to_string(gpo.parameters.hive_asset())));
@ -243,10 +240,6 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
withdraw_currency = "BTC"; withdraw_currency = "BTC";
withdraw_currency_price = database.get<asset_object>(database.get_global_properties().parameters.btc_asset()).options.core_exchange_rate; withdraw_currency_price = database.get<asset_object>(database.get_global_properties().parameters.btc_asset()).options.core_exchange_rate;
} }
if (sed.sidechain_currency == object_id_to_string(gpo.parameters.eth_asset())) {
withdraw_currency = "ETH";
withdraw_currency_price = database.get<asset_object>(database.get_global_properties().parameters.eth_asset()).options.core_exchange_rate;
}
if (sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset())) { if (sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset())) {
withdraw_currency = "HBD"; withdraw_currency = "HBD";
withdraw_currency_price = database.get<asset_object>(database.get_global_properties().parameters.hbd_asset()).options.core_exchange_rate; withdraw_currency_price = database.get<asset_object>(database.get_global_properties().parameters.hbd_asset()).options.core_exchange_rate;
@ -655,7 +648,6 @@ void sidechain_net_handler::on_applied_block(const signed_block &b) {
bool is_tracked_asset = bool is_tracked_asset =
((sidechain == sidechain_type::bitcoin) && (transfer_op.amount.asset_id == gpo.parameters.btc_asset())) || ((sidechain == sidechain_type::bitcoin) && (transfer_op.amount.asset_id == gpo.parameters.btc_asset())) ||
((sidechain == sidechain_type::ethereum) && (transfer_op.amount.asset_id == gpo.parameters.eth_asset())) ||
((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hbd_asset())) || ((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hbd_asset())) ||
((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hive_asset())); ((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hive_asset()));

View file

@ -29,12 +29,6 @@ bitcoin_rpc_client::bitcoin_rpc_client(std::string _url, std::string _user, std:
rpc_client(_url, _user, _password, _debug_rpc_calls) { rpc_client(_url, _user, _password, _debug_rpc_calls) {
} }
std::string bitcoin_rpc_client::createwallet(const std::string &wallet_name) {
std::string params = std::string("[\"") + wallet_name + std::string("\"]");
std::string str = send_post_request("createwallet", params, debug_rpc_calls);
return str;
}
uint64_t bitcoin_rpc_client::estimatesmartfee(uint16_t conf_target) { uint64_t bitcoin_rpc_client::estimatesmartfee(uint16_t conf_target) {
std::string params = std::string("[") + std::to_string(conf_target) + std::string("]"); std::string params = std::string("[") + std::to_string(conf_target) + std::string("]");
std::string str = send_post_request("estimatesmartfee", params, debug_rpc_calls); std::string str = send_post_request("estimatesmartfee", params, debug_rpc_calls);
@ -59,39 +53,130 @@ uint64_t bitcoin_rpc_client::estimatesmartfee(uint16_t conf_target) {
return 20000; return 20000;
} }
std::string bitcoin_rpc_client::getblock(const std::string &block_hash, int32_t verbosity) { std::vector<info_for_vin> bitcoin_rpc_client::getblock(const block_data &block, int32_t verbosity) {
std::string params = std::string("[\"") + block_hash + std::string("\",") + std::to_string(verbosity) + std::string("]"); std::string params = std::string("[\"") + block.block_hash + std::string("\",") + std::to_string(verbosity) + std::string("]");
std::string str = send_post_request("getblock", params, debug_rpc_calls); std::string str = send_post_request("getblock", params, debug_rpc_calls);
return str; std::vector<info_for_vin> result;
if (str.empty()) {
return result;
}
std::stringstream ss(str);
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
auto json_result = json.get_child_optional("result");
for (const auto &tx_child : json_result.get().get_child("tx")) {
const auto &tx = tx_child.second;
for (const auto &o : tx.get_child("vout")) {
const auto script = o.second.get_child("scriptPubKey");
std::vector<std::string> address_list;
if (script.count("address")) {
address_list.emplace_back(script.get<std::string>("address"));
} else if (script.count("addresses")) {
for (const auto &addr : script.get_child("addresses")) {
address_list.emplace_back(addr.second.get_value<std::string>());
}
} else {
continue;
}
for (auto &address : address_list) {
const auto address_base58 = address;
info_for_vin vin;
vin.out.hash_tx = tx.get_child("txid").get_value<std::string>();
string amount = o.second.get_child("value").get_value<std::string>();
amount.erase(std::remove(amount.begin(), amount.end(), '.'), amount.end());
vin.out.amount = std::stoll(amount);
vin.out.n_vout = o.second.get_child("n").get_value<uint32_t>();
vin.address = address_base58;
result.push_back(vin);
}
}
}
return result;
} }
std::string bitcoin_rpc_client::getnetworkinfo() { void bitcoin_rpc_client::getnetworkinfo() {
std::string params = std::string("[]"); std::string params = std::string("[]");
std::string str = send_post_request("getnetworkinfo", params, debug_rpc_calls); std::string str = send_post_request("getnetworkinfo", params, debug_rpc_calls);
return str;
std::stringstream network_info_ss(str);
boost::property_tree::ptree network_info_json;
boost::property_tree::read_json(network_info_ss, network_info_json);
bitcoin_major_version = network_info_json.get<uint32_t>("result.version") / 10000;
ilog("Bitcoin major version is: '${version}'", ("version", bitcoin_major_version));
} }
std::string bitcoin_rpc_client::getrawtransaction(const std::string &txid, const bool verbose) { btc_tx bitcoin_rpc_client::getrawtransaction(const std::string &txid, const bool verbose) {
std::string params = std::string("[\"") + txid + std::string("\",") + (verbose ? "true" : "false") + std::string("]"); std::string params = std::string("[\"") + txid + std::string("\",") + (verbose ? "true" : "false") + std::string("]");
std::string str = send_post_request("getrawtransaction", params, debug_rpc_calls); std::string str = send_post_request("getrawtransaction", params, debug_rpc_calls);
return str;
btc_tx tx;
std::stringstream tx_ss(str);
boost::property_tree::ptree tx_json;
boost::property_tree::read_json(tx_ss, tx_json);
if (tx_json.count("error") && tx_json.get_child("error").empty()) {
std::string tx_txid = tx_json.get<std::string>("result.txid");
uint32_t tx_confirmations = tx_json.get<uint32_t>("result.confirmations");
tx.tx_txid = tx_txid;
tx.tx_confirmations = tx_confirmations;
for (auto &input : tx_json.get_child("result.vout")) {
btc_txin tx_in;
std::string tx_vout_s = input.second.get<std::string>("n");
tx_in.tx_vout = std::stoll(tx_vout_s);
if (bitcoin_major_version > 21) {
std::string address = input.second.get<std::string>("scriptPubKey.address");
tx_in.tx_address.emplace_back(address);
} else {
for (auto &address : input.second.get_child("scriptPubKey.addresses")) {
tx_in.tx_address.emplace_back(address.second.data());
}
}
std::string tx_amount_s = input.second.get<std::string>("value");
tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end());
tx_in.tx_amount = std::stoll(tx_amount_s);
tx.tx_in_list.emplace_back(tx_in);
}
}
return tx;
} }
std::string bitcoin_rpc_client::getblockchaininfo() { std::string bitcoin_rpc_client::getblockchaininfo() {
std::string params = std::string("[]"); std::string params = std::string("[]");
std::string str = send_post_request("getblockchaininfo", params, debug_rpc_calls); std::string str = send_post_request("getblockchaininfo", params, debug_rpc_calls);
std::string result;
if (str.length() > 0) { if (str.length() > 0) {
std::stringstream ss(str); std::stringstream ss(str);
boost::property_tree::ptree json; boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json); boost::property_tree::read_json(ss, json);
boost::property_tree::json_parser::write_json(ss, json.get_child("result")); if (json.find("result") != json.not_found()) {
return ss.str(); auto json_result = json.get_child("result");
if (json_result.count("chain")) {
result = json_result.get<std::string>("chain");
}
}
} }
return str; return result;
} }
void bitcoin_rpc_client::importmulti(const std::vector<multi_params> &address_or_script_array, const bool rescan) { void bitcoin_rpc_client::importmulti(const std::vector<multi_params> &address_or_script_array, const bool rescan) {
@ -110,11 +195,11 @@ void bitcoin_rpc_client::importmulti(const std::vector<multi_params> &address_or
//! Note //! Note
/* Creation time of the key expressed in UNIX epoch time, /* Creation time of the key expressed in UNIX epoch time,
or the string "now" to substitute the current synced blockchain time. The timestamp of the oldest or the string "now" to substitute the current synced blockchain time. The timestamp of the oldest
key will determine how far back blockchain rescans need to begin for missing wallet transactions. key will determine how far back blockchain rescans need to begin for missing wallet transactions.
"now" can be specified to bypass scanning, for keys which are known to never have been used, and "now" can be specified to bypass scanning, for keys which are known to never have been used, and
0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key
creation time of all keys being imported by the importmulti call will be scanned.*/ creation time of all keys being imported by the importmulti call will be scanned.*/
if (&param != &address_or_script_array.back()) { if (&param != &address_or_script_array.back()) {
argument_1 += ", "; argument_1 += ", ";
@ -250,15 +335,139 @@ bool bitcoin_rpc_client::walletpassphrase(const std::string &passphrase, uint32_
else else
return true; return true;
} }
bitcoin_libbitcoin_client::bitcoin_libbitcoin_client(std::string url) :
libbitcoin_client(url) {
estimate_fee_ext = std::unique_ptr<estimate_fee_external>();
}
uint64_t bitcoin_libbitcoin_client::estimatesmartfee(uint16_t conf_target) {
uint64_t fee = estimate_fee_ext->get_fee_external(conf_target);
if (fee != 0) {
return fee;
}
return 20000;
}
std::vector<info_for_vin> bitcoin_libbitcoin_client::getblock(const block_data &block, int32_t verbosity) {
std::vector<info_for_vin> result;
const libbitcoin::chain::transaction::list trx_list = block.block.transactions();
for (const auto &tx : trx_list) {
uint32_t vout_seq = 0;
for (const auto &o : tx.outputs()) {
std::vector<std::string> address_list;
libbitcoin::wallet::payment_address::list addresses;
if (is_test_net) {
addresses = o.addresses(libbitcoin::wallet::payment_address::testnet_p2kh,
libbitcoin::wallet::payment_address::testnet_p2sh);
} else {
addresses = o.addresses();
}
for (auto &payment_address : addresses) {
std::stringstream ss;
ss << payment_address;
address_list.emplace_back(ss.str());
}
// addres list consists usual of one element
for (auto &address : address_list) {
const auto address_base58 = address;
info_for_vin vin;
vin.out.hash_tx = libbitcoin::config::hash256(tx.hash()).to_string();
vin.out.amount = std::floor(o.value());
vin.out.n_vout = vout_seq;
vin.address = address_base58;
result.push_back(vin);
}
vout_seq++;
}
}
return result;
}
btc_tx bitcoin_libbitcoin_client::getrawtransaction(const std::string &txid, const bool verbose) {
btc_tx tx;
std::string tx_hash;
uint32_t confirmitions;
libbitcoin::chain::output::list outs = get_transaction(txid, tx_hash, confirmitions);
if (tx_hash.empty()) {
return tx;
}
tx.tx_txid = tx_hash;
tx.tx_confirmations = confirmitions;
uint64_t tx_vout_sequence = 0;
for (auto &out : outs) {
btc_txin tx_in;
tx_in.tx_vout = tx_vout_sequence++;
libbitcoin::wallet::payment_address::list addresses;
if (is_test_net) {
addresses = out.addresses(libbitcoin::wallet::payment_address::testnet_p2kh,
libbitcoin::wallet::payment_address::testnet_p2sh);
} else {
addresses = out.addresses();
}
for (auto &address : addresses) {
std::stringstream ss;
ss << address;
tx_in.tx_address.emplace_back(ss.str());
}
tx_in.tx_amount = std::floor(out.value());
tx.tx_in_list.emplace_back(tx_in);
}
return tx;
}
std::string bitcoin_libbitcoin_client::getblockchaininfo() {
if (get_is_test_net()) {
is_test_net = true;
return "regtest";
}
return "";
}
std::vector<btc_txout> bitcoin_libbitcoin_client::listunspent_by_address_and_amount(const std::string &address, double transfer_amount, const uint32_t minconf, const uint32_t maxconf) {
std::vector<btc_txout> result;
std::vector<list_unspent_replay> outputs = listunspent(address, transfer_amount);
for (auto &output : outputs) {
btc_txout txo;
txo.txid_ = output.hash;
txo.out_num_ = output.index;
txo.amount_ = output.value;
result.push_back(txo);
}
return result;
}
std::string bitcoin_libbitcoin_client::sendrawtransaction(const std::string &tx_hex) {
std::string res = send_transaction(tx_hex);
return res;
}
// ============================================================================= // =============================================================================
zmq_listener::zmq_listener(std::string _ip, uint32_t _zmq) : zmq_listener::zmq_listener(std::string _ip, uint32_t _zmq) :
ip(_ip), zmq_listener_base(_ip, _zmq),
zmq_port(_zmq),
ctx(1), ctx(1),
socket(ctx, ZMQ_SUB), socket(ctx, ZMQ_SUB) {
stopped(false) {
} }
void zmq_listener::start() { void zmq_listener::start() {
@ -309,7 +518,9 @@ void zmq_listener::handle_zmq() {
} }
const auto header = std::string(static_cast<char *>(msg[0].data()), msg[0].size()); const auto header = std::string(static_cast<char *>(msg[0].data()), msg[0].size());
const auto block_hash = boost::algorithm::hex(std::string(static_cast<char *>(msg[1].data()), msg[1].size())); const auto block_hash = boost::algorithm::hex(std::string(static_cast<char *>(msg[1].data()), msg[1].size()));
event_received(block_hash); block_data event_data;
event_data.block_hash = block_hash;
event_received(event_data);
} }
} catch (zmq::error_t &e) { } catch (zmq::error_t &e) {
elog("handle_zmq recv_multipart exception ${str}", ("str", e.what())); elog("handle_zmq recv_multipart exception ${str}", ("str", e.what()));
@ -321,6 +532,58 @@ void zmq_listener::handle_zmq() {
// ============================================================================= // =============================================================================
// =============================================================================
zmq_listener_libbitcoin::zmq_listener_libbitcoin(std::string _ip, uint32_t _zmq_port) :
zmq_listener_base(_ip, _zmq_port),
socket(context, libbitcoin::protocol::zmq::socket::role::subscriber) {
}
zmq_listener_libbitcoin::~zmq_listener_libbitcoin() {
stopped.store(true);
thr.join();
}
void zmq_listener_libbitcoin::start() {
std::string endpoint_address = "tcp://" + ip;
libbitcoin::config::endpoint address(endpoint_address, zmq_port);
socket.connect(address);
thr = std::thread(&zmq_listener_libbitcoin::handle_block, this);
}
void zmq_listener_libbitcoin::handle_block() {
poller.add(socket);
while (!stopped.load()) {
// FIXME change the hard-coded value
const auto identifiers = poller.wait(500);
if (identifiers.contains(socket.id())) {
libbitcoin::protocol::zmq::message message;
socket.receive(message);
std::vector<uint8_t> data;
for (int i = 0; i < 3; i++) {
data.clear();
message.dequeue(data);
}
libbitcoin::chain::block block;
block.from_data(data, true);
block_data event_data;
event_data.block_hash = libbitcoin::config::hash256(block.hash()).to_string();
event_data.block = std::move(block);
event_received(event_data);
}
}
ilog("zmq_listener_libbitcoin thread finished");
}
// =============================================================================
sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
sidechain_net_handler(_plugin, options) { sidechain_net_handler(_plugin, options) {
sidechain = sidechain_type::bitcoin; sidechain = sidechain_type::bitcoin;
@ -329,11 +592,18 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain
debug_rpc_calls = options.at("debug-rpc-calls").as<bool>(); debug_rpc_calls = options.at("debug-rpc-calls").as<bool>();
} }
ip = options.at("bitcoin-node-ip").as<std::string>(); if (options.count("use-bitcoind-client")) {
zmq_port = options.at("bitcoin-node-zmq-port").as<uint32_t>(); use_bitcoind_client = options.at("use-bitcoind-client").as<bool>();
}
bitcoin_node_ip = options.at("bitcoin-node-ip").as<std::string>();
bitcoin_node_zmq_port = options.at("bitcoin-node-zmq-port").as<uint32_t>();
libbitcoin_server_ip = options.at("libbitcoin-server-ip").as<std::string>();
libbitcoin_zmq_port = options.at("libbitcoin-server-zmq-port").as<uint32_t>();
rpc_port = options.at("bitcoin-node-rpc-port").as<uint32_t>(); rpc_port = options.at("bitcoin-node-rpc-port").as<uint32_t>();
rpc_user = options.at("bitcoin-node-rpc-user").as<std::string>(); rpc_user = options.at("bitcoin-node-rpc-user").as<std::string>();
rpc_password = options.at("bitcoin-node-rpc-password").as<std::string>(); rpc_password = options.at("bitcoin-node-rpc-password").as<std::string>();
wallet_name = ""; wallet_name = "";
if (options.count("bitcoin-wallet-name")) { if (options.count("bitcoin-wallet-name")) {
wallet_name = options.at("bitcoin-wallet-name").as<std::string>(); wallet_name = options.at("bitcoin-wallet-name").as<std::string>();
@ -355,46 +625,39 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain
} }
} }
std::string url = ip + ":" + std::to_string(rpc_port); if (use_bitcoind_client) {
if (!wallet_name.empty()) { std::string url = bitcoin_node_ip + ":" + std::to_string(rpc_port);
url = url + "/wallet/" + wallet_name; if (wallet_name.length() > 0) {
url = url + "/wallet/" + wallet_name;
}
bitcoin_client = std::unique_ptr<bitcoin_rpc_client>(new bitcoin_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls));
if (!wallet_name.empty()) {
bitcoin_client->loadwallet(wallet_name);
}
listener = std::unique_ptr<zmq_listener>(new zmq_listener(bitcoin_node_ip, bitcoin_node_zmq_port));
} else {
bitcoin_client = std::unique_ptr<bitcoin_libbitcoin_client>(new bitcoin_libbitcoin_client(libbitcoin_server_ip));
listener = std::unique_ptr<zmq_listener_libbitcoin>(new zmq_listener_libbitcoin(libbitcoin_server_ip, libbitcoin_zmq_port));
} }
bitcoin_client = std::unique_ptr<bitcoin_rpc_client>(new bitcoin_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls)); std::string chain_info = bitcoin_client->getblockchaininfo();
if (!wallet_name.empty()) {
bitcoin_client->loadwallet(wallet_name);
}
std::string blockchain_info = bitcoin_client->getblockchaininfo();
std::stringstream bci_ss(std::string(blockchain_info.begin(), blockchain_info.end()));
boost::property_tree::ptree bci_json;
boost::property_tree::read_json(bci_ss, bci_json);
using namespace bitcoin; using namespace bitcoin;
network_type = bitcoin_address::network::mainnet; network_type = bitcoin_address::network::mainnet;
if (bci_json.count("chain")) { if (chain_info == "test") {
std::string chain = bci_json.get<std::string>("chain"); network_type = bitcoin_address::network::testnet;
if (chain.length() > 0) { } else if (chain_info == "regtest") {
if (chain == "test") { network_type = bitcoin_address::network::regtest;
network_type = bitcoin_address::network::testnet;
} else if (chain == "regtest") {
network_type = bitcoin_address::network::regtest;
}
}
} }
std::string network_info_str = bitcoin_client->getnetworkinfo(); bitcoin_client->getnetworkinfo();
std::stringstream network_info_ss(network_info_str);
boost::property_tree::ptree network_info_json;
boost::property_tree::read_json(network_info_ss, network_info_json);
bitcoin_major_version = network_info_json.get<uint32_t>("result.version") / 10000;
ilog("Bitcoin major version is: '${version}'", ("version", bitcoin_major_version));
listener = std::unique_ptr<zmq_listener>(new zmq_listener(ip, zmq_port));
listener->start(); listener->start();
listener->event_received.connect([this](const std::string &event_data) { listener->event_received.connect([this](const block_data &event_data) {
std::thread(&sidechain_net_handler_bitcoin::handle_event, this, event_data).detach(); std::thread(&sidechain_net_handler_bitcoin::handle_event, this, event_data).detach();
}); });
@ -417,7 +680,7 @@ sidechain_net_handler_bitcoin::~sidechain_net_handler_bitcoin() {
bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) { 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(sidechain))); // ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id(sidechain)));
bool should_approve = false; bool should_approve = false;
@ -526,39 +789,27 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
uint64_t swdo_amount = swdo->sidechain_amount.value; uint64_t swdo_amount = swdo->sidechain_amount.value;
uint64_t swdo_vout = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-") + 1)); uint64_t swdo_vout = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-") + 1));
std::string tx_str = bitcoin_client->getrawtransaction(swdo_txid, true); btc_tx tx = bitcoin_client->getrawtransaction(swdo_txid, true);
std::stringstream tx_ss(tx_str);
boost::property_tree::ptree tx_json;
boost::property_tree::read_json(tx_ss, tx_json);
if (tx_json.count("error") && tx_json.get_child("error").empty()) { if (!tx.tx_in_list.empty()) {
std::string tx_txid = tx_json.get<std::string>("result.txid"); std::string tx_txid = tx.tx_txid;
uint32_t tx_confirmations = tx_json.get<uint32_t>("result.confirmations"); uint32_t tx_confirmations = tx.tx_confirmations;
std::string tx_address = ""; std::string tx_address = "";
uint64_t tx_amount = -1; uint64_t tx_amount = -1;
uint64_t tx_vout = -1; uint64_t tx_vout = -1;
for (auto &input : tx_json.get_child("result.vout")) { for (auto &input : tx.tx_in_list) {
std::string tx_vout_s = input.second.get<std::string>("n"); tx_vout = input.tx_vout;
tx_vout = std::stoll(tx_vout_s);
if (tx_vout == swdo_vout) { if (tx_vout == swdo_vout) {
if (bitcoin_major_version > 21) { for (auto &address : input.tx_address) {
std::string address = input.second.get<std::string>("scriptPubKey.address");
if (address == swdo_address) { if (address == swdo_address) {
tx_address = address; tx_address = address;
} break;
} else {
for (auto &address : input.second.get_child("scriptPubKey.addresses")) {
if (address.second.data() == swdo_address) {
tx_address = address.second.data();
break;
}
} }
} }
std::string tx_amount_s = input.second.get<std::string>("value");
tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end()); tx_amount = input.tx_amount;
tx_amount = std::stoll(tx_amount_s);
break; break;
} }
} }
@ -793,7 +1044,12 @@ void sidechain_net_handler_bitcoin::process_sidechain_addresses() {
if (sao.expires == time_point_sec::maximum()) { if (sao.expires == time_point_sec::maximum()) {
auto usr_pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(sao.deposit_public_key))); auto usr_pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(sao.deposit_public_key)));
btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys, network_type); payment_type payment_type_address = payment_type::P2SH_WSH;
if (use_bitcoind_client) {
payment_type_address = payment_type::P2WSH;
}
btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys, network_type, payment_type_address);
std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) + std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) +
"\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }"; "\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }";
@ -936,12 +1192,11 @@ bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain
return false; return false;
} }
std::string tx_str = bitcoin_client->getrawtransaction(sto.sidechain_transaction, true); btc_tx tx = bitcoin_client->getrawtransaction(sto.sidechain_transaction, true);
std::stringstream tx_ss(tx_str);
boost::property_tree::ptree tx_json;
boost::property_tree::read_json(tx_ss, tx_json);
if ((tx_json.count("error")) && (!tx_json.get_child("error").empty())) { if (tx.tx_in_list.empty()) {
// This case will result with segmentation fault.
// FIXME check if that happened before introducing libbitcoin
return false; return false;
} }
@ -953,31 +1208,26 @@ bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain
auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(si.public_key))); 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)); pubkey_weights.push_back(std::make_pair(pub_key, si.weight));
} }
btc_weighted_multisig_address addr(pubkey_weights, network_type);
std::string tx_txid = tx_json.get<std::string>("result.txid"); payment_type payment_type_address = payment_type::P2SH_WSH;
uint32_t tx_confirmations = tx_json.get<uint32_t>("result.confirmations"); if (use_bitcoind_client) {
payment_type_address = payment_type::P2WSH;
}
btc_weighted_multisig_address addr(pubkey_weights, network_type, payment_type_address);
std::string tx_txid = tx.tx_txid;
uint32_t tx_confirmations = tx.tx_confirmations;
std::string tx_address = addr.get_address(); std::string tx_address = addr.get_address();
int64_t tx_amount = -1; int64_t tx_amount = -1;
if (tx_confirmations >= gpo.parameters.son_bitcoin_min_tx_confirmations()) { if (tx_confirmations >= gpo.parameters.son_bitcoin_min_tx_confirmations()) {
if (sto.object_id.is<son_wallet_deposit_id_type>()) { if (sto.object_id.is<son_wallet_deposit_id_type>()) {
for (auto &input : tx_json.get_child("result.vout")) { for (auto &input : tx.tx_in_list) {
if (bitcoin_major_version > 21) { for (auto &address : input.tx_address) {
std::string address = input.second.get<std::string>("scriptPubKey.address");
if (address == tx_address) { if (address == tx_address) {
std::string tx_amount_s = input.second.get<std::string>("value"); tx_amount = input.tx_amount;
tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end()); break;
tx_amount = std::stoll(tx_amount_s);
}
} else {
for (auto &address : input.second.get_child("scriptPubKey.addresses")) {
if (address.second.data() == tx_address) {
std::string tx_amount_s = input.second.get<std::string>("value");
tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end());
tx_amount = std::stoll(tx_amount_s);
break;
}
} }
} }
} }
@ -1003,7 +1253,11 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const s
pubkey_weights.push_back(std::make_pair(pub_key, son.weight)); pubkey_weights.push_back(std::make_pair(pub_key, son.weight));
} }
btc_weighted_multisig_address addr(pubkey_weights, network_type); payment_type payment_type_address = payment_type::P2SH_WSH;
if (use_bitcoind_client) {
payment_type_address = payment_type::P2WSH;
}
btc_weighted_multisig_address addr(pubkey_weights, network_type, payment_type_address);
std::stringstream ss; std::stringstream ss;
@ -1239,21 +1493,34 @@ std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_tran
} }
// Add redeemscripts to vins and make tx ready for sending // Add redeemscripts to vins and make tx ready for sending
sign_witness_transaction_finalize(tx, redeem_scripts, false); sign_witness_transaction_finalize(tx, redeem_scripts, false);
if (!use_bitcoind_client) {
// get witness script from redeem script
bitcoin::bytes redeem_bytes = parse_hex(redeem_script);
fc::sha256 sha = fc::sha256::hash(&redeem_bytes[0], redeem_bytes.size());
std::string witness_script(sha.str());
witness_script.insert(0, std::string("220020"));
for (size_t i = 0; i < tx.vin.size(); i++) {
tx.vin[i].scriptSig = parse_hex(witness_script);
}
}
std::string final_tx_hex = fc::to_hex(pack(tx)); std::string final_tx_hex = fc::to_hex(pack(tx));
std::string res = bitcoin_client->sendrawtransaction(final_tx_hex); std::string res = bitcoin_client->sendrawtransaction(final_tx_hex);
return res; if (res.empty()) {
return res;
}
return tx.get_txid().str();
} }
void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data) { void sidechain_net_handler_bitcoin::handle_event(const block_data &event_data) {
std::string block = bitcoin_client->getblock(event_data); auto vins = bitcoin_client->getblock(event_data);
if (block.empty())
return;
add_to_son_listener_log("BLOCK : " + event_data); add_to_son_listener_log("BLOCK : " + event_data.block_hash);
auto vins = extract_info_from_block(block);
scoped_lock interlock(event_handler_mutex); scoped_lock interlock(event_handler_mutex);
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>(); const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>();
@ -1309,56 +1576,14 @@ std::string sidechain_net_handler_bitcoin::get_redeemscript_for_userdeposit(cons
pubkey_weights.push_back(std::make_pair(pub_key, son.weight)); 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))); auto user_pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(addr_itr->deposit_public_key)));
btc_one_or_weighted_multisig_address deposit_addr(user_pub_key, pubkey_weights, network_type);
return fc::to_hex(deposit_addr.get_redeem_script());
}
std::vector<info_for_vin> sidechain_net_handler_bitcoin::extract_info_from_block(const std::string &_block) { payment_type payment_type_address = payment_type::P2SH_WSH;
std::stringstream ss(_block); if (use_bitcoind_client) {
boost::property_tree::ptree json; payment_type_address = payment_type::P2WSH;
boost::property_tree::read_json(ss, json);
auto json_result = json.get_child_optional("result");
std::vector<info_for_vin> result;
for (const auto &tx_child : json_result.get().get_child("tx")) {
const auto &tx = tx_child.second;
for (const auto &o : tx.get_child("vout")) {
const auto script = o.second.get_child("scriptPubKey");
if (bitcoin_major_version > 21) {
if (!script.count("address"))
continue;
} else {
if (!script.count("addresses"))
continue;
}
auto sort_out_vin = [&](std::string address) {
const auto address_base58 = address;
info_for_vin vin;
vin.out.hash_tx = tx.get_child("txid").get_value<std::string>();
string amount = o.second.get_child("value").get_value<std::string>();
amount.erase(std::remove(amount.begin(), amount.end(), '.'), amount.end());
vin.out.amount = std::stoll(amount);
vin.out.n_vout = o.second.get_child("n").get_value<uint32_t>();
vin.address = address_base58;
result.push_back(vin);
};
if (bitcoin_major_version > 21) {
std::string address = script.get<std::string>("address");
sort_out_vin(address);
} else {
for (const auto &addr : script.get_child("addresses")) // in which cases there can be more addresses?
sort_out_vin(addr.second.get_value<std::string>());
}
}
} }
btc_one_or_weighted_multisig_address deposit_addr(user_pub_key, pubkey_weights, network_type, payment_type_address);
return result; return fc::to_hex(deposit_addr.get_redeem_script());
} }
void sidechain_net_handler_bitcoin::on_changed_objects(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts) { void sidechain_net_handler_bitcoin::on_changed_objects(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts) {

View file

@ -1,761 +0,0 @@
#include <graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp>
#include <algorithm>
#include <thread>
#include <boost/algorithm/string.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <fc/crypto/base64.hpp>
#include <fc/log/logger.hpp>
#include <fc/network/ip.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/protocol/son_wallet.hpp>
#include <graphene/chain/sidechain_transaction_object.hpp>
#include <graphene/chain/son_info.hpp>
#include <graphene/chain/son_wallet_object.hpp>
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
#define SEND_RAW_TRANSACTION 1
namespace graphene { namespace peerplays_sidechain {
ethereum_rpc_client::ethereum_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) :
rpc_client(url, user_name, password, debug_rpc_calls) {
}
std::string ethereum_rpc_client::admin_node_info() {
return send_post_request("admin_nodeInfo", "", debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_get_block_by_number(std::string block_number, bool full_block) {
std::string params = "[ \"" + block_number + "\", " + (full_block ? "true" : "false") + "]";
return send_post_request("eth_getBlockByNumber", params, debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_get_logs(std::string wallet_contract_address) {
std::string params = "[{\"address\": \"" + wallet_contract_address + "\"}]";
std::string reply_str = send_post_request("eth_getLogs", params, debug_rpc_calls);
return retrieve_value_from_reply(reply_str, "");
}
std::string ethereum_rpc_client::net_version() {
return send_post_request("net_version", "", debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_get_transaction_count(const std::string &params) {
return send_post_request("eth_getTransactionCount", params, debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_gas_price() {
return send_post_request("eth_gasPrice", "", debug_rpc_calls);
}
std::string ethereum_rpc_client::get_chain_id() {
std::string reply_str = net_version();
return retrieve_value_from_reply(reply_str, "");
}
std::string ethereum_rpc_client::get_network_id() {
std::string reply_str = admin_node_info();
return retrieve_value_from_reply(reply_str, "protocols.eth.network");
}
std::string ethereum_rpc_client::get_nonce(const std::string &address) {
std::string reply_str = eth_get_transaction_count("[\"" + address + "\", \"latest\"]");
const auto nonce_val = ethereum::from_hex<boost::multiprecision::uint256_t>(retrieve_value_from_reply(reply_str, ""));
return nonce_val == 0 ? ethereum::add_0x("0") : ethereum::add_0x(ethereum::to_hex(nonce_val));
}
std::string ethereum_rpc_client::get_gas_price() {
std::string reply_str = eth_gas_price();
return retrieve_value_from_reply(reply_str, "");
}
std::string ethereum_rpc_client::get_gas_limit() {
std::string reply_str = eth_get_block_by_number("latest", false);
if (!reply_str.empty()) {
std::stringstream ss(reply_str);
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
if (json.count("result")) {
std::string gas_limit_s = json.get<std::string>("result.gasLimit");
return gas_limit_s;
}
}
return std::string{};
}
std::string ethereum_rpc_client::eth_send_transaction(const std::string &params) {
return send_post_request("eth_sendTransaction", "[" + params + "]", debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_send_raw_transaction(const std::string &params) {
return send_post_request("eth_sendRawTransaction", "[ \"" + params + "\" ]", debug_rpc_calls);
}
std::string ethereum_rpc_client::eth_get_transaction_receipt(const std::string &params) {
return send_post_request("eth_getTransactionReceipt", "[\"" + params + "\"]", debug_rpc_calls);
}
sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
sidechain_net_handler(_plugin, options) {
sidechain = sidechain_type::ethereum;
if (options.count("debug-rpc-calls")) {
debug_rpc_calls = options.at("debug-rpc-calls").as<bool>();
}
rpc_url = options.at("ethereum-node-rpc-url").as<std::string>();
if (options.count("ethereum-node-rpc-user")) {
rpc_user = options.at("ethereum-node-rpc-user").as<std::string>();
} else {
rpc_user = "";
}
if (options.count("ethereum-node-rpc-password")) {
rpc_password = options.at("ethereum-node-rpc-password").as<std::string>();
} else {
rpc_password = "";
}
wallet_contract_address = options.at("ethereum-wallet-contract-address").as<std::string>();
if (options.count("ethereum-private-key")) {
const std::vector<std::string> pub_priv_keys = options["ethereum-private-key"].as<std::vector<std::string>>();
for (const std::string &itr_key_pair : pub_priv_keys) {
auto key_pair = graphene::app::dejsonify<std::pair<std::string, std::string>>(itr_key_pair, 5);
ilog("Ethereum Public Key: ${public}", ("public", key_pair.first));
if (!key_pair.first.length() || !key_pair.second.length()) {
FC_THROW("Invalid public private key pair.");
}
private_keys[key_pair.first] = key_pair.second;
}
}
rpc_client = new ethereum_rpc_client(rpc_url, rpc_user, rpc_password, debug_rpc_calls);
std::string chain_id_str = rpc_client->get_chain_id();
if (chain_id_str.empty()) {
elog("No Ethereum node running at ${url}", ("url", rpc_url));
FC_ASSERT(false);
}
chain_id = std::stoll(chain_id_str);
std::string network_id_str = rpc_client->get_network_id();
network_id = std::stoll(network_id_str);
ilog("Running on Ethereum network, chain id ${chain_id_str}, network id ${network_id_str}", ("chain_id_str", chain_id_str)("network_id_str", network_id_str));
last_block_received = 0;
schedule_ethereum_listener();
event_received.connect([this](const std::string &event_data) {
std::thread(&sidechain_net_handler_ethereum::handle_event, this, event_data).detach();
});
}
sidechain_net_handler_ethereum::~sidechain_net_handler_ethereum() {
}
bool sidechain_net_handler_ethereum::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(sidechain)));
bool should_approve = false;
const chain::global_property_object &gpo = database.get_global_properties();
int32_t op_idx_0 = -1;
chain::operation op_obj_idx_0;
if (po.proposed_transaction.operations.size() >= 1) {
op_idx_0 = po.proposed_transaction.operations[0].which();
op_obj_idx_0 = po.proposed_transaction.operations[0];
}
int32_t op_idx_1 = -1;
chain::operation op_obj_idx_1;
(void)op_idx_1;
if (po.proposed_transaction.operations.size() >= 2) {
op_idx_1 = po.proposed_transaction.operations[1].which();
op_obj_idx_1 = po.proposed_transaction.operations[1];
}
switch (op_idx_0) {
case chain::operation::tag<chain::son_wallet_update_operation>::value: {
bool address_ok = false;
bool transaction_ok = false;
son_wallet_id_type swo_id = op_obj_idx_0.get<son_wallet_update_operation>().son_wallet_id;
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
const auto swo = idx.find(swo_id);
if (swo != idx.end()) {
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());
if (son_sets_equal) {
for (size_t i = 0; i < active_sons.size(); i++) {
son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i);
}
}
if (son_sets_equal) {
address_ok = (op_obj_idx_0.get<son_wallet_update_operation>().address == wallet_contract_address);
}
if (po.proposed_transaction.operations.size() >= 2) {
object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
const auto st = st_idx.find(object_id);
if (st == st_idx.end()) {
std::string tx_str = "";
if (object_id.is<son_wallet_id_type>()) {
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
const auto swo = idx.find(object_id);
if (swo != idx.end()) {
tx_str = create_primary_wallet_transaction(gpo.active_sons.at(sidechain), object_id.operator std::string());
}
}
transaction_ok = (op_tx_str == tx_str);
}
} else {
transaction_ok = true;
}
}
should_approve = address_ok &&
transaction_ok;
break;
}
case chain::operation::tag<chain::son_wallet_deposit_process_operation>::value: {
bool process_ok = false;
son_wallet_deposit_id_type swdo_id = op_obj_idx_0.get<son_wallet_deposit_process_operation>().son_wallet_deposit_id;
const auto &idx = database.get_index_type<son_wallet_deposit_index>().indices().get<by_id>();
const auto swdo = idx.find(swdo_id);
if (swdo != idx.end()) {
//std::string swdo_txid = swdo->sidechain_transaction_id;
//std::string swdo_sidechain_from = swdo->sidechain_from;
//std::string swdo_sidechain_currency = swdo->sidechain_currency;
//uint64_t swdo_sidechain_amount = swdo->sidechain_amount.value;
//uint64_t swdo_op_idx = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-")));
//
//std::string tx_str = rpc_client->account_history_api_get_transaction(swdo_txid);
//if (tx_str != "") {
//
// std::stringstream ss_tx(tx_str);
// boost::property_tree::ptree tx;
// boost::property_tree::read_json(ss_tx, tx);
//
// uint64_t op_idx = -1;
// for (const auto &ops : tx.get_child("result.operations")) {
// const auto &op = ops.second;
// op_idx = op_idx + 1;
// if (op_idx == swdo_op_idx) {
// std::string operation_type = op.get<std::string>("type");
//
// if (operation_type == "transfer_operation") {
// const auto &op_value = op.get_child("value");
//
// std::string sidechain_from = op_value.get<std::string>("from");
//
// const auto &amount_child = op_value.get_child("amount");
//
// uint64_t amount = amount_child.get<uint64_t>("amount");
// std::string nai = amount_child.get<std::string>("nai");
// std::string sidechain_currency = "";
// if ((nai == "@@000000013" /*?? HBD*/) || (nai == "@@000000013" /*TBD*/)) {
// sidechain_currency = "HBD";
// }
// if ((nai == "@@000000021") /*?? HIVE*/ || (nai == "@@000000021" /*TESTS*/)) {
// sidechain_currency = "HIVE";
// }
//
// std::string memo = op_value.get<std::string>("memo");
// boost::trim(memo);
// if (!memo.empty()) {
// sidechain_from = memo;
// }
//
// process_ok = (swdo_sidechain_from == sidechain_from) &&
// (swdo_sidechain_currency == sidechain_currency) &&
// (swdo_sidechain_amount == amount);
// }
// }
// }
//}
}
process_ok = true;
should_approve = process_ok;
break;
}
case chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value: {
bool process_ok = false;
bool transaction_ok = false;
son_wallet_withdraw_id_type swwo_id = op_obj_idx_0.get<son_wallet_withdraw_process_operation>().son_wallet_withdraw_id;
const auto &idx = database.get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
const auto swwo = idx.find(swwo_id);
if (swwo != idx.end()) {
uint32_t swwo_block_num = swwo->block_num;
std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id;
uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1));
const auto &block = database.fetch_block_by_number(swwo_block_num);
for (const auto &tx : block->transactions) {
if (tx.id().str() == swwo_peerplays_transaction_id) {
operation op = tx.operations[swwo_op_idx];
transfer_operation t_op = op.get<transfer_operation>();
price asset_price = database.get<asset_object>(t_op.amount.asset_id).options.core_exchange_rate;
asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount);
process_ok = (t_op.to == gpo.parameters.son_account()) &&
(swwo->peerplays_from == t_op.from) &&
(swwo->peerplays_asset == peerplays_asset);
break;
}
}
object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
const auto st = st_idx.find(object_id);
if (st == st_idx.end()) {
std::string tx_str = "";
if (object_id.is<son_wallet_withdraw_id_type>()) {
const auto &idx = database.get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
const auto swwo = idx.find(object_id);
if (swwo != idx.end()) {
tx_str = create_withdrawal_transaction(*swwo);
}
}
transaction_ok = (op_tx_str == tx_str);
}
}
should_approve = process_ok &&
transaction_ok;
break;
}
case chain::operation::tag<chain::sidechain_transaction_sign_operation>::value: {
should_approve = true;
son_id_type signer = op_obj_idx_0.get<sidechain_transaction_sign_operation>().signer;
std::string signature = op_obj_idx_0.get<sidechain_transaction_sign_operation>().signature;
sidechain_transaction_id_type sidechain_transaction_id = op_obj_idx_0.get<sidechain_transaction_sign_operation>().sidechain_transaction_id;
const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_id>();
const auto sto = st_idx.find(sidechain_transaction_id);
if (sto == st_idx.end()) {
should_approve = false;
break;
}
const auto &s_idx = database.get_index_type<son_index>().indices().get<by_id>();
const auto son = s_idx.find(signer);
if (son == s_idx.end()) {
should_approve = false;
break;
}
break;
}
case chain::operation::tag<chain::sidechain_transaction_settle_operation>::value: {
should_approve = true;
break;
}
default:
should_approve = false;
elog("==================================================");
elog("Proposal not considered for approval ${po}", ("po", po));
elog("==================================================");
}
return should_approve;
}
void sidechain_net_handler_ethereum::process_primary_wallet() {
const auto &swi = database.get_index_type<son_wallet_index>().indices().get<by_id>();
const auto &active_sw = swi.rbegin();
if (active_sw != swi.rend()) {
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;
}
if (!plugin.can_son_participate(sidechain, chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) {
return;
}
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(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);
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;
swu_op.address = wallet_contract_address;
proposal_op.proposed_ops.emplace_back(swu_op);
std::string tx_str = create_primary_wallet_transaction(gpo.active_sons.at(sidechain), active_sw->id.operator std::string());
if (!tx_str.empty()) {
sidechain_transaction_create_operation stc_op;
stc_op.payer = gpo.parameters.son_account();
stc_op.object_id = active_sw->id;
stc_op.sidechain = sidechain;
stc_op.transaction = tx_str;
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(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(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;
}
}
}
}
void sidechain_net_handler_ethereum::process_sidechain_addresses() {
}
bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_object &swdo) {
const chain::global_property_object &gpo = database.get_global_properties();
price asset_price = database.get<asset_object>(database.get_global_properties().parameters.eth_asset()).options.core_exchange_rate;
asset asset_to_issue = asset(swdo.peerplays_asset.amount * asset_price.quote.amount / asset_price.base.amount, database.get_global_properties().parameters.eth_asset());
proposal_create_operation proposal_op;
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);
son_wallet_deposit_process_operation swdp_op;
swdp_op.payer = gpo.parameters.son_account();
swdp_op.son_wallet_deposit_id = swdo.id;
proposal_op.proposed_ops.emplace_back(swdp_op);
asset_issue_operation ai_op;
ai_op.fee = database.current_fee_schedule().calculate_fee(ai_op);
ai_op.issuer = gpo.parameters.son_account();
ai_op.asset_to_issue = asset_to_issue;
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(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));
return true;
} catch (fc::exception &e) {
elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what()));
return false;
}
return false;
}
bool sidechain_net_handler_ethereum::process_withdrawal(const son_wallet_withdraw_object &swwo) {
if (proposal_exists(chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value, swwo.id)) {
return false;
}
std::string tx_str = create_withdrawal_transaction(swwo);
if (!tx_str.empty()) {
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(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);
son_wallet_withdraw_process_operation swwp_op;
swwp_op.payer = gpo.parameters.son_account();
swwp_op.son_wallet_withdraw_id = swwo.id;
proposal_op.proposed_ops.emplace_back(swwp_op);
sidechain_transaction_create_operation stc_op;
stc_op.payer = gpo.parameters.son_account();
stc_op.object_id = swwo.id;
stc_op.sidechain = sidechain;
stc_op.transaction = tx_str;
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(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));
return true;
} catch (fc::exception &e) {
elog("Sending proposal for withdraw sidechain transaction create operation failed with exception ${e}", ("e", e.what()));
return false;
}
}
return false;
}
std::string sidechain_net_handler_ethereum::process_sidechain_transaction(const sidechain_transaction_object &sto) {
return sign_transaction(sto);
}
std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sidechain_transaction_object &sto) {
boost::property_tree::ptree pt;
boost::property_tree::ptree pt_array;
for (const auto &signature : sto.signatures) {
const auto &transaction = signature.second;
//! Check if we have this signed transaction, if not, don't send it
if (transaction.empty())
continue;
#ifdef SEND_RAW_TRANSACTION
const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(transaction);
#else
const std::string sidechain_transaction = rpc_client->eth_send_transaction(transaction);
#endif
std::stringstream ss_tx(sidechain_transaction);
boost::property_tree::ptree tx_json;
boost::property_tree::read_json(ss_tx, tx_json);
if (tx_json.count("result") && !tx_json.count("error")) {
boost::property_tree::ptree node;
node.put("transaction", transaction);
node.put("transaction_receipt", tx_json.get<std::string>("result"));
pt_array.push_back(std::make_pair("", node));
} else {
//! Fixme
//! How should we proceed with error in eth_send_transaction
elog("Error in eth_send_transaction for transaction ${id}, transaction ${transaction}", ("id", sto.id)("transaction", transaction));
return std::string{}; //! Return empty string, as we have error in sending
}
}
pt.add_child("result_array", pt_array);
std::stringstream ss;
boost::property_tree::json_parser::write_json(ss, pt);
return ss.str();
}
bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) {
std::stringstream ss(sto.sidechain_transaction);
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
if (!json.count("result_array")) {
return false;
}
size_t count = 0;
for (const auto &entry : json.get_child("result_array")) {
const std::string receipt = rpc_client->eth_get_transaction_receipt(entry.second.get<std::string>("transaction_receipt"));
std::stringstream ss_receipt(receipt);
boost::property_tree::ptree json_receipt;
boost::property_tree::read_json(ss_receipt, json_receipt);
if (json_receipt.get<std::string>("result") == "null") {
wlog("Block is not minted yet for transaction ${id}", ("id", sto.id));
return false;
}
if ("0x1" == json_receipt.get<std::string>("result.status")) {
count += 1;
//! Fixme - compare data somehow?
//if( sto.transaction == entry_receipt.second.get<std::string>("data") ) {
//}
}
}
//! Check that we have all transactions
if (count != json.get_child("result_array").size()) {
wlog("Not all receipts received for transaction ${id}", ("id", sto.id));
return false;
} else
return true;
return false;
}
std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const std::vector<son_info> &son_pubkeys, const std::string &object_id) {
std::vector<std::pair<std::string, uint16_t>> owners_weights;
for (auto &son : son_pubkeys) {
const std::string pub_key_str = son.public_key;
owners_weights.emplace_back(std::make_pair(pub_key_str, son.weight));
}
const ethereum::update_owners_encoder encoder;
return encoder.encode(owners_weights, object_id);
}
std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) {
return "Deposit-Transaction";
}
std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) {
const ethereum::withdrawal_encoder encoder;
return encoder.encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string());
}
std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) {
const auto &current_son = plugin.get_current_son_object(sidechain);
FC_ASSERT(current_son.sidechain_public_keys.contains(sidechain), "No public keys for current son: ${account_id}", ("account_id", current_son.son_account));
const auto &public_key = current_son.sidechain_public_keys.at(sidechain);
#ifdef SEND_RAW_TRANSACTION
ethereum::raw_transaction raw_tr;
raw_tr.nonce = rpc_client->get_nonce(ethereum::add_0x(public_key));
raw_tr.gas_price = rpc_client->get_gas_price();
raw_tr.gas_limit = rpc_client->get_gas_limit();
raw_tr.to = wallet_contract_address;
raw_tr.value = "";
raw_tr.data = sto.transaction;
raw_tr.chain_id = ethereum::add_0x(ethereum::to_hex(chain_id));
const auto sign_tr = raw_tr.sign(get_private_key(public_key));
return sign_tr.serialize();
#else
ethereum::transaction sign_transaction;
sign_transaction.data = sto.transaction;
sign_transaction.to = wallet_contract_address;
sign_transaction.from = "0x" + public_key;
return sign_transaction.sign(get_private_key(public_key)).serialize();
#endif
}
void sidechain_net_handler_ethereum::schedule_ethereum_listener() {
fc::time_point now = fc::time_point::now();
int64_t time_to_next = 5000;
fc::time_point next_wakeup(now + fc::milliseconds(time_to_next));
_listener_task = fc::schedule([this] {
ethereum_listener_loop();
},
next_wakeup, "SON Ethereum listener task");
}
void sidechain_net_handler_ethereum::ethereum_listener_loop() {
schedule_ethereum_listener();
std::string reply = rpc_client->eth_get_block_by_number("latest", false);
//std::string reply = rpc_client->eth_get_logs(wallet_contract_address);
if (!reply.empty()) {
std::stringstream ss(reply);
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
if (json.count("result")) {
std::string head_block_number_s = json.get<std::string>("result.number");
uint64_t head_block_number = std::strtoul(head_block_number_s.c_str(), nullptr, 16);
if (head_block_number != last_block_received) {
std::string event_data = std::to_string(head_block_number);
handle_event(event_data);
last_block_received = head_block_number;
}
}
}
}
void sidechain_net_handler_ethereum::handle_event(const std::string &event_data) {
std::string block = rpc_client->eth_get_block_by_number("latest", true);
if (block != "") {
add_to_son_listener_log("BLOCK : " + event_data);
std::stringstream ss(block);
boost::property_tree::ptree block_json;
boost::property_tree::read_json(ss, block_json);
size_t tx_idx = -1;
for (const auto &tx_child : block_json.get_child("result.transactions")) {
boost::property_tree::ptree tx = tx_child.second;
tx_idx = tx_idx + 1;
std::string from = tx.get<std::string>("from");
std::string to = tx.get<std::string>("to");
std::string cmp_to = to;
std::transform(cmp_to.begin(), cmp_to.end(), cmp_to.begin(), ::toupper);
std::string cmp_wallet_contract_address = wallet_contract_address;
std::transform(cmp_wallet_contract_address.begin(), cmp_wallet_contract_address.end(), cmp_wallet_contract_address.begin(), ::toupper);
if (cmp_to == cmp_wallet_contract_address) {
std::string value_s = tx.get<std::string>("value");
boost::multiprecision::uint256_t amount(value_s);
amount = amount / 100000;
amount = amount / 100000;
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>();
const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, from, time_point_sec::maximum()));
if (addr_itr == sidechain_addresses_idx.end()) {
continue;
}
std::stringstream ss;
ss << "ethereum"
<< "-" << tx.get<std::string>("hash") << "-" << tx_idx;
std::string sidechain_uid = ss.str();
sidechain_event_data sed;
sed.timestamp = database.head_block_time();
sed.block_num = database.head_block_num();
sed.sidechain = sidechain;
sed.sidechain_uid = sidechain_uid;
sed.sidechain_transaction_id = tx.get<std::string>("hash");
sed.sidechain_from = from;
sed.sidechain_to = to;
sed.sidechain_currency = "ETH";
sed.sidechain_amount = amount;
sed.peerplays_from = addr_itr->sidechain_address_account;
sed.peerplays_to = database.get_global_properties().parameters.son_account();
price eth_price = database.get<asset_object>(database.get_global_properties().parameters.eth_asset()).options.core_exchange_rate;
sed.peerplays_asset = asset(sed.sidechain_amount * eth_price.base.amount / eth_price.quote.amount);
add_to_son_listener_log("TRX : " + sed.sidechain_transaction_id);
sidechain_event_data_received(sed);
}
}
}
}
}} // namespace graphene::peerplays_sidechain

View file

@ -1,7 +1,6 @@
#include <graphene/peerplays_sidechain/sidechain_net_handler_factory.hpp> #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_bitcoin.hpp>
#include <graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp>
#include <graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp> #include <graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp>
#include <graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp> #include <graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp>
@ -19,9 +18,6 @@ std::unique_ptr<sidechain_net_handler> sidechain_net_handler_factory::create_han
case sidechain_type::hive: { case sidechain_type::hive: {
return std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_hive(plugin, options)); return std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_hive(plugin, options));
} }
case sidechain_type::ethereum: {
return std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_ethereum(plugin, options));
}
case sidechain_type::peerplays: { case sidechain_type::peerplays: {
return std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_peerplays(plugin, options)); return std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_peerplays(plugin, options));
} }

View file

@ -28,23 +28,25 @@
#include <graphene/peerplays_sidechain/hive/transaction.hpp> #include <graphene/peerplays_sidechain/hive/transaction.hpp>
#include <graphene/utilities/key_conversion.hpp> #include <graphene/utilities/key_conversion.hpp>
#include <boost/asio.hpp>
namespace graphene { namespace peerplays_sidechain { namespace graphene { namespace peerplays_sidechain {
hive_rpc_client::hive_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : hive_node_rpc_client::hive_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) :
rpc_client(url, user_name, password, debug_rpc_calls) { rpc_client(url, user_name, password, debug_rpc_calls) {
} }
std::string hive_rpc_client::account_history_api_get_transaction(std::string transaction_id) { std::string hive_node_rpc_client::account_history_api_get_transaction(std::string transaction_id) {
std::string params = "{ \"id\": \"" + transaction_id + "\" }"; std::string params = "{ \"id\": \"" + transaction_id + "\" }";
return send_post_request("account_history_api.get_transaction", params, debug_rpc_calls); return send_post_request("account_history_api.get_transaction", params, debug_rpc_calls);
} }
std::string hive_rpc_client::block_api_get_block(uint32_t block_number) { std::string hive_node_rpc_client::block_api_get_block(uint32_t block_number) {
std::string params = "{ \"block_num\": " + std::to_string(block_number) + " }"; std::string params = "{ \"block_num\": " + std::to_string(block_number) + " }";
return send_post_request("block_api.get_block", params, debug_rpc_calls); return send_post_request("block_api.get_block", params, debug_rpc_calls);
} }
std::string hive_rpc_client::condenser_api_get_accounts(std::vector<std::string> accounts) { std::string hive_node_rpc_client::condenser_api_get_accounts(std::vector<std::string> accounts) {
std::string params = ""; std::string params = "";
for (auto account : accounts) { for (auto account : accounts) {
if (!params.empty()) { if (!params.empty()) {
@ -56,58 +58,58 @@ std::string hive_rpc_client::condenser_api_get_accounts(std::vector<std::string>
return send_post_request("condenser_api.get_accounts", params, debug_rpc_calls); return send_post_request("condenser_api.get_accounts", params, debug_rpc_calls);
} }
std::string hive_rpc_client::condenser_api_get_config() { std::string hive_node_rpc_client::condenser_api_get_config() {
std::string params = "[]"; std::string params = "[]";
return send_post_request("condenser_api.get_config", params, debug_rpc_calls); return send_post_request("condenser_api.get_config", params, debug_rpc_calls);
} }
std::string hive_rpc_client::database_api_get_dynamic_global_properties() { std::string hive_node_rpc_client::database_api_get_dynamic_global_properties() {
return send_post_request("database_api.get_dynamic_global_properties", "", debug_rpc_calls); return send_post_request("database_api.get_dynamic_global_properties", "", debug_rpc_calls);
} }
std::string hive_rpc_client::database_api_get_version() { std::string hive_node_rpc_client::database_api_get_version() {
return send_post_request("database_api.get_version", "", debug_rpc_calls); return send_post_request("database_api.get_version", "", debug_rpc_calls);
} }
std::string hive_rpc_client::network_broadcast_api_broadcast_transaction(std::string htrx) { std::string hive_node_rpc_client::network_broadcast_api_broadcast_transaction(std::string htrx) {
std::string params = "{ \"trx\": " + htrx + ", \"max_block_age\": -1 }"; std::string params = "{ \"trx\": " + htrx + ", \"max_block_age\": -1 }";
return send_post_request("network_broadcast_api.broadcast_transaction", params, debug_rpc_calls); return send_post_request("network_broadcast_api.broadcast_transaction", params, debug_rpc_calls);
} }
std::string hive_rpc_client::get_account(std::string account) { std::string hive_node_rpc_client::get_account(std::string account) {
std::vector<std::string> accounts; std::vector<std::string> accounts;
accounts.push_back(account); accounts.push_back(account);
std::string reply_str = condenser_api_get_accounts(accounts); std::string reply_str = condenser_api_get_accounts(accounts);
return retrieve_array_value_from_reply(reply_str, "", 0); return retrieve_array_value_from_reply(reply_str, "", 0);
} }
std::string hive_rpc_client::get_account_memo_key(std::string account) { std::string hive_node_rpc_client::get_account_memo_key(std::string account) {
std::string reply_str = get_account(account); std::string reply_str = get_account(account);
reply_str = "{\"result\":" + reply_str + "}"; reply_str = "{\"result\":" + reply_str + "}";
return retrieve_value_from_reply(reply_str, "memo_key"); return retrieve_value_from_reply(reply_str, "memo_key");
} }
std::string hive_rpc_client::get_chain_id() { std::string hive_node_rpc_client::get_chain_id() {
std::string reply_str = database_api_get_version(); std::string reply_str = database_api_get_version();
return retrieve_value_from_reply(reply_str, "chain_id"); return retrieve_value_from_reply(reply_str, "chain_id");
} }
std::string hive_rpc_client::get_head_block_id() { std::string hive_node_rpc_client::get_head_block_id() {
std::string reply_str = database_api_get_dynamic_global_properties(); std::string reply_str = database_api_get_dynamic_global_properties();
return retrieve_value_from_reply(reply_str, "head_block_id"); return retrieve_value_from_reply(reply_str, "head_block_id");
} }
std::string hive_rpc_client::get_head_block_time() { std::string hive_node_rpc_client::get_head_block_time() {
std::string reply_str = database_api_get_dynamic_global_properties(); std::string reply_str = database_api_get_dynamic_global_properties();
return retrieve_value_from_reply(reply_str, "time"); return retrieve_value_from_reply(reply_str, "time");
} }
std::string hive_rpc_client::get_is_test_net() { std::string hive_node_rpc_client::get_is_test_net() {
std::string reply_str = condenser_api_get_config(); std::string reply_str = condenser_api_get_config();
return retrieve_value_from_reply(reply_str, "IS_TEST_NET"); return retrieve_value_from_reply(reply_str, "IS_TEST_NET");
} }
std::string hive_rpc_client::get_last_irreversible_block_num() { std::string hive_node_rpc_client::get_last_irreversible_block_num() {
std::string reply_str = database_api_get_dynamic_global_properties(); std::string reply_str = database_api_get_dynamic_global_properties();
return retrieve_value_from_reply(reply_str, "last_irreversible_block_num"); return retrieve_value_from_reply(reply_str, "last_irreversible_block_num");
} }
@ -120,20 +122,18 @@ sidechain_net_handler_hive::sidechain_net_handler_hive(peerplays_sidechain_plugi
debug_rpc_calls = options.at("debug-rpc-calls").as<bool>(); debug_rpc_calls = options.at("debug-rpc-calls").as<bool>();
} }
rpc_url = options.at("hive-node-rpc-url").as<std::string>(); node_rpc_url = options.at("hive-node-rpc-url").as<std::string>();
if (options.count("hive-rpc-user")) { if (options.count("hive-node-rpc-user")) {
rpc_user = options.at("hive-rpc-user").as<std::string>(); node_rpc_user = options.at("hive-node-rpc-user").as<std::string>();
} else { } else {
rpc_user = ""; node_rpc_user = "";
} }
if (options.count("hive-rpc-password")) { if (options.count("hive-node-rpc-password")) {
rpc_password = options.at("hive-rpc-password").as<std::string>(); node_rpc_password = options.at("hive-node-rpc-password").as<std::string>();
} else { } else {
rpc_password = ""; node_rpc_password = "";
} }
wallet_account_name = options.at("hive-wallet-account-name").as<std::string>();
if (options.count("hive-private-key")) { if (options.count("hive-private-key")) {
const std::vector<std::string> pub_priv_keys = options["hive-private-key"].as<std::vector<std::string>>(); const std::vector<std::string> pub_priv_keys = options["hive-private-key"].as<std::vector<std::string>>();
for (const std::string &itr_key_pair : pub_priv_keys) { for (const std::string &itr_key_pair : pub_priv_keys) {
@ -146,16 +146,16 @@ sidechain_net_handler_hive::sidechain_net_handler_hive(peerplays_sidechain_plugi
} }
} }
rpc_client = new hive_rpc_client(rpc_url, rpc_user, rpc_password, debug_rpc_calls); node_rpc_client = new hive_node_rpc_client(node_rpc_url, node_rpc_user, node_rpc_password, debug_rpc_calls);
std::string chain_id_str = rpc_client->get_chain_id(); std::string chain_id_str = node_rpc_client->get_chain_id();
if (chain_id_str.empty()) { if (chain_id_str.empty()) {
elog("No Hive node running at ${url}", ("url", rpc_url)); elog("No Hive node running at ${url}", ("url", node_rpc_url));
FC_ASSERT(false); FC_ASSERT(false);
} }
chain_id = chain_id_type(chain_id_str); chain_id = chain_id_type(chain_id_str);
std::string is_test_net = rpc_client->get_is_test_net(); std::string is_test_net = node_rpc_client->get_is_test_net();
network_type = is_test_net.compare("true") == 0 ? hive::network::testnet : hive::network::mainnet; network_type = is_test_net.compare("true") == 0 ? hive::network::testnet : hive::network::mainnet;
if (network_type == hive::network::mainnet) { if (network_type == hive::network::mainnet) {
ilog("Running on Hive mainnet, chain id ${chain_id_str}", ("chain_id_str", chain_id_str)); ilog("Running on Hive mainnet, chain id ${chain_id_str}", ("chain_id_str", chain_id_str));
@ -225,7 +225,7 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) {
} }
if (son_sets_equal) { if (son_sets_equal) {
address_ok = (op_obj_idx_0.get<son_wallet_update_operation>().address == wallet_account_name); address_ok = (op_obj_idx_0.get<son_wallet_update_operation>().address == "son-account");
} }
if (po.proposed_transaction.operations.size() >= 2) { if (po.proposed_transaction.operations.size() >= 2) {
@ -254,14 +254,14 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) {
account_auths[wallet_son.public_key] = wallet_son.weight; account_auths[wallet_son.public_key] = wallet_son.weight;
} }
std::string memo_key = rpc_client->get_account_memo_key(wallet_account_name); std::string memo_key = node_rpc_client->get_account_memo_key("son-account");
hive::authority active; hive::authority active;
active.weight_threshold = total_weight * 2 / 3 + 1; active.weight_threshold = total_weight * 2 / 3 + 1;
active.account_auths = account_auths; active.account_auths = account_auths;
hive::account_update_operation auo; hive::account_update_operation auo;
auo.account = wallet_account_name; auo.account = "son-account";
auo.active = active; auo.active = active;
auo.memo_key = op_trx.operations[0].get<hive::account_update_operation>().memo_key; auo.memo_key = op_trx.operations[0].get<hive::account_update_operation>().memo_key;
@ -303,7 +303,7 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) {
uint64_t swdo_sidechain_amount = swdo->sidechain_amount.value; uint64_t swdo_sidechain_amount = swdo->sidechain_amount.value;
uint64_t swdo_op_idx = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-"))); uint64_t swdo_op_idx = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-")));
std::string tx_str = rpc_client->account_history_api_get_transaction(swdo_txid); std::string tx_str = node_rpc_client->account_history_api_get_transaction(swdo_txid);
if (tx_str != "") { if (tx_str != "") {
std::stringstream ss_tx(tx_str); std::stringstream ss_tx(tx_str);
@ -408,7 +408,7 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) {
} }
hive::transfer_operation t_op; hive::transfer_operation t_op;
t_op.from = wallet_account_name; t_op.from = "son-account";
t_op.to = swwo->withdraw_address; t_op.to = swwo->withdraw_address;
t_op.amount.amount = swwo->withdraw_amount; t_op.amount.amount = swwo->withdraw_amount;
t_op.amount.symbol = symbol; t_op.amount.symbol = symbol;
@ -495,7 +495,7 @@ void sidechain_net_handler_hive::process_primary_wallet() {
account_auths[active_son.public_key] = active_son.weight; account_auths[active_son.public_key] = active_son.weight;
} }
std::string memo_key = rpc_client->get_account_memo_key(wallet_account_name); std::string memo_key = node_rpc_client->get_account_memo_key("son-account");
if (memo_key.empty()) { if (memo_key.empty()) {
return; return;
@ -506,14 +506,14 @@ void sidechain_net_handler_hive::process_primary_wallet() {
active.account_auths = account_auths; active.account_auths = account_auths;
hive::account_update_operation auo; hive::account_update_operation auo;
auo.account = wallet_account_name; auo.account = "son-account";
auo.active = active; auo.active = active;
auo.memo_key = hive::public_key_type(memo_key); auo.memo_key = hive::public_key_type(memo_key);
std::string block_id_str = rpc_client->get_head_block_id(); std::string block_id_str = node_rpc_client->get_head_block_id();
hive::block_id_type head_block_id(block_id_str); hive::block_id_type head_block_id(block_id_str);
std::string head_block_time_str = rpc_client->get_head_block_time(); std::string head_block_time_str = node_rpc_client->get_head_block_time();
time_point head_block_time = fc::time_point_sec::from_iso_string(head_block_time_str); time_point head_block_time = fc::time_point_sec::from_iso_string(head_block_time_str);
hive::signed_transaction htrx; hive::signed_transaction htrx;
@ -538,7 +538,7 @@ void sidechain_net_handler_hive::process_primary_wallet() {
swu_op.payer = gpo.parameters.son_account(); swu_op.payer = gpo.parameters.son_account();
swu_op.son_wallet_id = active_sw->id; swu_op.son_wallet_id = active_sw->id;
swu_op.sidechain = sidechain; swu_op.sidechain = sidechain;
swu_op.address = wallet_account_name; swu_op.address = "son-account";
proposal_op.proposed_ops.emplace_back(swu_op); proposal_op.proposed_ops.emplace_back(swu_op);
@ -662,16 +662,16 @@ bool sidechain_net_handler_hive::process_withdrawal(const son_wallet_withdraw_ob
} }
hive::transfer_operation t_op; hive::transfer_operation t_op;
t_op.from = wallet_account_name; t_op.from = "son-account";
t_op.to = swwo.withdraw_address; t_op.to = swwo.withdraw_address;
t_op.amount.amount = swwo.withdraw_amount; t_op.amount.amount = swwo.withdraw_amount;
t_op.amount.symbol = symbol; t_op.amount.symbol = symbol;
t_op.memo = ""; t_op.memo = "";
std::string block_id_str = rpc_client->get_head_block_id(); std::string block_id_str = node_rpc_client->get_head_block_id();
hive::block_id_type head_block_id(block_id_str); hive::block_id_type head_block_id(block_id_str);
std::string head_block_time_str = rpc_client->get_head_block_time(); std::string head_block_time_str = node_rpc_client->get_head_block_time();
time_point head_block_time = fc::time_point_sec::from_iso_string(head_block_time_str); time_point head_block_time = fc::time_point_sec::from_iso_string(head_block_time_str);
hive::signed_transaction htrx; hive::signed_transaction htrx;
@ -727,7 +727,7 @@ std::string sidechain_net_handler_hive::process_sidechain_transaction(const side
hive::signed_transaction htrx; hive::signed_transaction htrx;
fc::raw::unpack(ss_trx, htrx, 1000); fc::raw::unpack(ss_trx, htrx, 1000);
std::string chain_id_str = rpc_client->get_chain_id(); std::string chain_id_str = node_rpc_client->get_chain_id();
const hive::chain_id_type chain_id(chain_id_str); 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).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)));
@ -755,7 +755,7 @@ std::string sidechain_net_handler_hive::send_sidechain_transaction(const sidecha
} }
std::string params = fc::json::to_string(htrx); std::string params = fc::json::to_string(htrx);
rpc_client->network_broadcast_api_broadcast_transaction(params); node_rpc_client->network_broadcast_api_broadcast_transaction(params);
return htrx.id().str(); return htrx.id().str();
} }
@ -770,7 +770,7 @@ bool sidechain_net_handler_hive::settle_sidechain_transaction(const sidechain_tr
return false; return false;
} }
std::string tx_str = rpc_client->account_history_api_get_transaction(sto.sidechain_transaction); std::string tx_str = node_rpc_client->account_history_api_get_transaction(sto.sidechain_transaction);
if (tx_str != "") { if (tx_str != "") {
std::stringstream ss_tx(tx_str); std::stringstream ss_tx(tx_str);
@ -781,7 +781,7 @@ bool sidechain_net_handler_hive::settle_sidechain_transaction(const sidechain_tr
std::string tx_txid = tx_json.get<std::string>("result.transaction_id"); std::string tx_txid = tx_json.get<std::string>("result.transaction_id");
uint32_t tx_block_num = tx_json.get<uint32_t>("result.block_num"); uint32_t tx_block_num = tx_json.get<uint32_t>("result.block_num");
uint32_t last_irreversible_block = std::stoul(rpc_client->get_last_irreversible_block_num()); uint32_t last_irreversible_block = std::stoul(node_rpc_client->get_last_irreversible_block_num());
//std::string tx_address = addr.get_address(); //std::string tx_address = addr.get_address();
//int64_t tx_amount = -1; //int64_t tx_amount = -1;
@ -817,7 +817,7 @@ void sidechain_net_handler_hive::schedule_hive_listener() {
void sidechain_net_handler_hive::hive_listener_loop() { void sidechain_net_handler_hive::hive_listener_loop() {
schedule_hive_listener(); schedule_hive_listener();
std::string reply = rpc_client->database_api_get_dynamic_global_properties(); std::string reply = node_rpc_client->database_api_get_dynamic_global_properties();
if (!reply.empty()) { if (!reply.empty()) {
std::stringstream ss(reply); std::stringstream ss(reply);
boost::property_tree::ptree json; boost::property_tree::ptree json;
@ -832,7 +832,7 @@ void sidechain_net_handler_hive::hive_listener_loop() {
} }
} }
//std::string reply = rpc_client->get_last_irreversible_block_num(); //std::string reply = node_rpc_client->get_last_irreversible_block_num();
//if (!reply.empty()) { //if (!reply.empty()) {
// uint64_t last_irreversible_block = std::stoul(reply); // uint64_t last_irreversible_block = std::stoul(reply);
// if (last_irreversible_block != last_block_received) { // if (last_irreversible_block != last_block_received) {
@ -844,7 +844,7 @@ void sidechain_net_handler_hive::hive_listener_loop() {
} }
void sidechain_net_handler_hive::handle_event(const std::string &event_data) { void sidechain_net_handler_hive::handle_event(const std::string &event_data) {
std::string block = rpc_client->block_api_get_block(std::atoll(event_data.c_str())); std::string block = node_rpc_client->block_api_get_block(std::atoll(event_data.c_str()));
if (block != "") { if (block != "") {
add_to_son_listener_log("BLOCK : " + event_data); add_to_son_listener_log("BLOCK : " + event_data);
std::stringstream ss(block); std::stringstream ss(block);
@ -869,7 +869,7 @@ void sidechain_net_handler_hive::handle_event(const std::string &event_data) {
std::string from = op_value.get<std::string>("from"); std::string from = op_value.get<std::string>("from");
std::string to = op_value.get<std::string>("to"); std::string to = op_value.get<std::string>("to");
if (to == wallet_account_name) { if (to == "son-account") {
const auto &amount_child = op_value.get_child("amount"); const auto &amount_child = op_value.get_child("amount");

View file

@ -1,16 +0,0 @@
file(GLOB HEADERS "include/sha3/*.h")
add_library( sha3
memzero.c
sha3.c
)
target_include_directories( sha3 PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include )
target_compile_definitions( sha3 PUBLIC USE_KECCAK=1 )
install( TARGETS
sha3
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)

View file

@ -1,16 +0,0 @@
#ifndef __MEMZERO_H__
#define __MEMZERO_H__
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void memzero(void* const pnt, const size_t len);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View file

@ -1,88 +0,0 @@
/* sha3.h - an implementation of Secure Hash Algorithm 3 (Keccak).
* based on the
* The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011
* by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche
*
* Copyright: 2013 Aleksey Kravchenko <rhash.admin@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
*/
#ifndef __SHA3_H__
#define __SHA3_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define sha3_224_hash_size 28
#define sha3_256_hash_size 32
#define sha3_384_hash_size 48
#define sha3_512_hash_size 64
#define sha3_max_permutation_size 25
#define sha3_max_rate_in_qwords 24
#define SHA3_224_BLOCK_LENGTH 144
#define SHA3_256_BLOCK_LENGTH 136
#define SHA3_384_BLOCK_LENGTH 104
#define SHA3_512_BLOCK_LENGTH 72
#define SHA3_224_DIGEST_LENGTH sha3_224_hash_size
#define SHA3_256_DIGEST_LENGTH sha3_256_hash_size
#define SHA3_384_DIGEST_LENGTH sha3_384_hash_size
#define SHA3_512_DIGEST_LENGTH sha3_512_hash_size
/**
* SHA3 Algorithm context.
*/
typedef struct SHA3_CTX
{
/* 1600 bits algorithm hashing state */
uint64_t hash[sha3_max_permutation_size];
/* 1536-bit buffer for leftovers */
uint64_t message[sha3_max_rate_in_qwords];
/* count of bytes in the message[] buffer */
unsigned rest;
/* size of a message block processed at once */
unsigned block_size;
} SHA3_CTX;
/* methods for calculating the hash function */
void sha3_224_Init(SHA3_CTX *ctx);
void sha3_256_Init(SHA3_CTX *ctx);
void sha3_384_Init(SHA3_CTX *ctx);
void sha3_512_Init(SHA3_CTX *ctx);
void sha3_Update(SHA3_CTX *ctx, const unsigned char* msg, size_t size);
void sha3_Final(SHA3_CTX *ctx, unsigned char* result);
#if USE_KECCAK
#define keccak_224_Init sha3_224_Init
#define keccak_256_Init sha3_256_Init
#define keccak_384_Init sha3_384_Init
#define keccak_512_Init sha3_512_Init
#define keccak_Update sha3_Update
void keccak_Final(SHA3_CTX *ctx, unsigned char* result);
void keccak_256(const unsigned char* data, size_t len, unsigned char* digest);
void keccak_512(const unsigned char* data, size_t len, unsigned char* digest);
#endif
void sha3_256(const unsigned char* data, size_t len, unsigned char* digest);
void sha3_512(const unsigned char* data, size_t len, unsigned char* digest);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* __SHA3_H__ */

View file

@ -1,75 +0,0 @@
#ifndef __STDC_WANT_LIB_EXT1__
#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface.
#endif
#include <string.h>
#ifdef _WIN32
#include <Windows.h>
#endif
#ifdef __unix__
#include <strings.h>
#include <sys/param.h>
#endif
// C11's bounds-checking interface.
#if defined(__STDC_LIB_EXT1__)
#define HAVE_MEMSET_S 1
#endif
// GNU C Library version 2.25 or later.
#if defined(__GLIBC__) && \
(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))
#define HAVE_EXPLICIT_BZERO 1
#endif
// Newlib
#if defined(__NEWLIB__)
#define HAVE_EXPLICIT_BZERO 1
#endif
// FreeBSD version 11.0 or later.
#if defined(__FreeBSD__) && __FreeBSD_version >= 1100037
#define HAVE_EXPLICIT_BZERO 1
#endif
// OpenBSD version 5.5 or later.
#if defined(__OpenBSD__) && OpenBSD >= 201405
#define HAVE_EXPLICIT_BZERO 1
#endif
// NetBSD version 7.2 or later.
#if defined(__NetBSD__) && __NetBSD_Version__ >= 702000000
#define HAVE_EXPLICIT_MEMSET 1
#endif
// Adapted from
// https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130
void memzero(void *const pnt, const size_t len) {
#ifdef _WIN32
SecureZeroMemory(pnt, len);
#elif defined(HAVE_MEMSET_S)
memset_s(pnt, (rsize_t)len, 0, (rsize_t)len);
#elif defined(HAVE_EXPLICIT_BZERO)
explicit_bzero(pnt, len);
#elif defined(HAVE_EXPLICIT_MEMSET)
explicit_memset(pnt, 0, len);
#else
volatile unsigned char *volatile pnt_ = (volatile unsigned char *volatile)pnt;
size_t i = (size_t)0U;
while (i < len) {
pnt_[i++] = 0U;
}
#endif
// explicitly mark the memory as overwritten for the Clang MemorySanitizer
// this is only included at compile time if MemorySanitizer is enabled and
// should not come with any downsides during regular builds
#if defined(__has_feature)
#if __has_feature(memory_sanitizer)
memset(pnt, 0, len);
#endif
#endif
}

View file

@ -1,397 +0,0 @@
/* sha3.c - an implementation of Secure Hash Algorithm 3 (Keccak).
* based on the
* The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011
* by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche
*
* Copyright: 2013 Aleksey Kravchenko <rhash.admin@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
*/
#include <assert.h>
#include <string.h>
#include <sha3/sha3.h>
#include <sha3/memzero.h>
#define I64(x) x##LL
#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n))))
#define le2me_64(x) (x)
#define IS_ALIGNED_64(p) (0 == (7 & ((long)(p)))) // [wallet-core] pointer/numerical type, for MacOS SDK 12.3
# define me64_to_le_str(to, from, length) memcpy((to), (from), (length))
/* constants */
#define NumberOfRounds 24
/* SHA3 (Keccak) constants for 24 rounds */
uint64_t keccak_round_constants[NumberOfRounds] = {
I64(0x0000000000000001), I64(0x0000000000008082), I64(0x800000000000808A), I64(0x8000000080008000),
I64(0x000000000000808B), I64(0x0000000080000001), I64(0x8000000080008081), I64(0x8000000000008009),
I64(0x000000000000008A), I64(0x0000000000000088), I64(0x0000000080008009), I64(0x000000008000000A),
I64(0x000000008000808B), I64(0x800000000000008B), I64(0x8000000000008089), I64(0x8000000000008003),
I64(0x8000000000008002), I64(0x8000000000000080), I64(0x000000000000800A), I64(0x800000008000000A),
I64(0x8000000080008081), I64(0x8000000000008080), I64(0x0000000080000001), I64(0x8000000080008008)
};
/* Initializing a sha3 context for given number of output bits */
static void keccak_Init(SHA3_CTX *ctx, unsigned bits)
{
/* NB: The Keccak capacity parameter = bits * 2 */
unsigned rate = 1600 - bits * 2;
memzero(ctx, sizeof(SHA3_CTX));
ctx->block_size = rate / 8;
assert(rate <= 1600 && (rate % 64) == 0);
}
/**
* Initialize context before calculating hash.
*
* @param ctx context to initialize
*/
void sha3_224_Init(SHA3_CTX *ctx)
{
keccak_Init(ctx, 224);
}
/**
* Initialize context before calculating hash.
*
* @param ctx context to initialize
*/
void sha3_256_Init(SHA3_CTX *ctx)
{
keccak_Init(ctx, 256);
}
/**
* Initialize context before calculating hash.
*
* @param ctx context to initialize
*/
void sha3_384_Init(SHA3_CTX *ctx)
{
keccak_Init(ctx, 384);
}
/**
* Initialize context before calculating hash.
*
* @param ctx context to initialize
*/
void sha3_512_Init(SHA3_CTX *ctx)
{
keccak_Init(ctx, 512);
}
/* Keccak theta() transformation */
static void keccak_theta(uint64_t *A)
{
unsigned int x = 0;
uint64_t C[5] = {0}, D[5] = {0};
for (x = 0; x < 5; x++) {
C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20];
}
D[0] = ROTL64(C[1], 1) ^ C[4];
D[1] = ROTL64(C[2], 1) ^ C[0];
D[2] = ROTL64(C[3], 1) ^ C[1];
D[3] = ROTL64(C[4], 1) ^ C[2];
D[4] = ROTL64(C[0], 1) ^ C[3];
for (x = 0; x < 5; x++) {
A[x] ^= D[x];
A[x + 5] ^= D[x];
A[x + 10] ^= D[x];
A[x + 15] ^= D[x];
A[x + 20] ^= D[x];
}
}
/* Keccak pi() transformation */
static void keccak_pi(uint64_t *A)
{
uint64_t A1 = 0;
A1 = A[1];
A[ 1] = A[ 6];
A[ 6] = A[ 9];
A[ 9] = A[22];
A[22] = A[14];
A[14] = A[20];
A[20] = A[ 2];
A[ 2] = A[12];
A[12] = A[13];
A[13] = A[19];
A[19] = A[23];
A[23] = A[15];
A[15] = A[ 4];
A[ 4] = A[24];
A[24] = A[21];
A[21] = A[ 8];
A[ 8] = A[16];
A[16] = A[ 5];
A[ 5] = A[ 3];
A[ 3] = A[18];
A[18] = A[17];
A[17] = A[11];
A[11] = A[ 7];
A[ 7] = A[10];
A[10] = A1;
/* note: A[ 0] is left as is */
}
/* Keccak chi() transformation */
static void keccak_chi(uint64_t *A)
{
int i = 0;
for (i = 0; i < 25; i += 5) {
uint64_t A0 = A[0 + i], A1 = A[1 + i];
A[0 + i] ^= ~A1 & A[2 + i];
A[1 + i] ^= ~A[2 + i] & A[3 + i];
A[2 + i] ^= ~A[3 + i] & A[4 + i];
A[3 + i] ^= ~A[4 + i] & A0;
A[4 + i] ^= ~A0 & A1;
}
}
static void sha3_permutation(uint64_t *state)
{
int round = 0;
for (round = 0; round < NumberOfRounds; round++)
{
keccak_theta(state);
/* apply Keccak rho() transformation */
state[ 1] = ROTL64(state[ 1], 1);
state[ 2] = ROTL64(state[ 2], 62);
state[ 3] = ROTL64(state[ 3], 28);
state[ 4] = ROTL64(state[ 4], 27);
state[ 5] = ROTL64(state[ 5], 36);
state[ 6] = ROTL64(state[ 6], 44);
state[ 7] = ROTL64(state[ 7], 6);
state[ 8] = ROTL64(state[ 8], 55);
state[ 9] = ROTL64(state[ 9], 20);
state[10] = ROTL64(state[10], 3);
state[11] = ROTL64(state[11], 10);
state[12] = ROTL64(state[12], 43);
state[13] = ROTL64(state[13], 25);
state[14] = ROTL64(state[14], 39);
state[15] = ROTL64(state[15], 41);
state[16] = ROTL64(state[16], 45);
state[17] = ROTL64(state[17], 15);
state[18] = ROTL64(state[18], 21);
state[19] = ROTL64(state[19], 8);
state[20] = ROTL64(state[20], 18);
state[21] = ROTL64(state[21], 2);
state[22] = ROTL64(state[22], 61);
state[23] = ROTL64(state[23], 56);
state[24] = ROTL64(state[24], 14);
keccak_pi(state);
keccak_chi(state);
/* apply iota(state, round) */
*state ^= keccak_round_constants[round];
}
}
/**
* The core transformation. Process the specified block of data.
*
* @param hash the algorithm state
* @param block the message block to process
* @param block_size the size of the processed block in bytes
*/
static void sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t block_size)
{
/* expanded loop */
hash[ 0] ^= le2me_64(block[ 0]);
hash[ 1] ^= le2me_64(block[ 1]);
hash[ 2] ^= le2me_64(block[ 2]);
hash[ 3] ^= le2me_64(block[ 3]);
hash[ 4] ^= le2me_64(block[ 4]);
hash[ 5] ^= le2me_64(block[ 5]);
hash[ 6] ^= le2me_64(block[ 6]);
hash[ 7] ^= le2me_64(block[ 7]);
hash[ 8] ^= le2me_64(block[ 8]);
/* if not sha3-512 */
if (block_size > 72) {
hash[ 9] ^= le2me_64(block[ 9]);
hash[10] ^= le2me_64(block[10]);
hash[11] ^= le2me_64(block[11]);
hash[12] ^= le2me_64(block[12]);
/* if not sha3-384 */
if (block_size > 104) {
hash[13] ^= le2me_64(block[13]);
hash[14] ^= le2me_64(block[14]);
hash[15] ^= le2me_64(block[15]);
hash[16] ^= le2me_64(block[16]);
/* if not sha3-256 */
if (block_size > 136) {
hash[17] ^= le2me_64(block[17]);
#ifdef FULL_SHA3_FAMILY_SUPPORT
/* if not sha3-224 */
if (block_size > 144) {
hash[18] ^= le2me_64(block[18]);
hash[19] ^= le2me_64(block[19]);
hash[20] ^= le2me_64(block[20]);
hash[21] ^= le2me_64(block[21]);
hash[22] ^= le2me_64(block[22]);
hash[23] ^= le2me_64(block[23]);
hash[24] ^= le2me_64(block[24]);
}
#endif
}
}
}
/* make a permutation of the hash */
sha3_permutation(hash);
}
#define SHA3_FINALIZED 0x80000000
/**
* Calculate message hash.
* Can be called repeatedly with chunks of the message to be hashed.
*
* @param ctx the algorithm context containing current hashing state
* @param msg message chunk
* @param size length of the message chunk
*/
void sha3_Update(SHA3_CTX *ctx, const unsigned char *msg, size_t size)
{
size_t idx = (size_t)ctx->rest;
size_t block_size = (size_t)ctx->block_size;
if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */
ctx->rest = (unsigned)((ctx->rest + size) % block_size);
/* fill partial block */
if (idx) {
size_t left = block_size - idx;
memcpy((char*)ctx->message + idx, msg, (size < left ? size : left));
if (size < left) return;
/* process partial block */
sha3_process_block(ctx->hash, ctx->message, block_size);
msg += left;
size -= left;
}
while (size >= block_size) {
uint64_t *aligned_message_block = NULL;
if (IS_ALIGNED_64(msg)) {
/* the most common case is processing of an already aligned message
without copying it */
aligned_message_block = (uint64_t*)(void*)msg;
} else {
memcpy(ctx->message, msg, block_size);
aligned_message_block = ctx->message;
}
sha3_process_block(ctx->hash, aligned_message_block, block_size);
msg += block_size;
size -= block_size;
}
if (size) {
memcpy(ctx->message, msg, size); /* save leftovers */
}
}
/**
* Store calculated hash into the given array.
*
* @param ctx the algorithm context containing current hashing state
* @param result calculated hash in binary form
*/
void sha3_Final(SHA3_CTX *ctx, unsigned char* result)
{
size_t digest_length = 100 - ctx->block_size / 2;
const size_t block_size = ctx->block_size;
if (!(ctx->rest & SHA3_FINALIZED))
{
/* clear the rest of the data queue */
memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest);
((char*)ctx->message)[ctx->rest] |= 0x06;
((char*)ctx->message)[block_size - 1] |= 0x80;
/* process final block */
sha3_process_block(ctx->hash, ctx->message, block_size);
ctx->rest = SHA3_FINALIZED; /* mark context as finalized */
}
assert(block_size > digest_length);
if (result) me64_to_le_str(result, ctx->hash, digest_length);
memzero(ctx, sizeof(SHA3_CTX));
}
#if USE_KECCAK
/**
* Store calculated hash into the given array.
*
* @param ctx the algorithm context containing current hashing state
* @param result calculated hash in binary form
*/
void keccak_Final(SHA3_CTX *ctx, unsigned char* result)
{
size_t digest_length = 100 - ctx->block_size / 2;
const size_t block_size = ctx->block_size;
if (!(ctx->rest & SHA3_FINALIZED))
{
/* clear the rest of the data queue */
memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest);
((char*)ctx->message)[ctx->rest] |= 0x01;
((char*)ctx->message)[block_size - 1] |= 0x80;
/* process final block */
sha3_process_block(ctx->hash, ctx->message, block_size);
ctx->rest = SHA3_FINALIZED; /* mark context as finalized */
}
assert(block_size > digest_length);
if (result) me64_to_le_str(result, ctx->hash, digest_length);
memzero(ctx, sizeof(SHA3_CTX));
}
void keccak_256(const unsigned char* data, size_t len, unsigned char* digest)
{
SHA3_CTX ctx = {0};
keccak_256_Init(&ctx);
keccak_Update(&ctx, data, len);
keccak_Final(&ctx, digest);
}
void keccak_512(const unsigned char* data, size_t len, unsigned char* digest)
{
SHA3_CTX ctx = {0};
keccak_512_Init(&ctx);
keccak_Update(&ctx, data, len);
keccak_Final(&ctx, digest);
}
#endif /* USE_KECCAK */
void sha3_256(const unsigned char* data, size_t len, unsigned char* digest)
{
SHA3_CTX ctx = {0};
sha3_256_Init(&ctx);
sha3_Update(&ctx, data, len);
sha3_Final(&ctx, digest);
}
void sha3_512(const unsigned char* data, size_t len, unsigned char* digest)
{
SHA3_CTX ctx = {0};
sha3_512_Init(&ctx);
sha3_Update(&ctx, data, len);
sha3_Final(&ctx, digest);
}

View file

@ -44,37 +44,13 @@ for my $class (@{$doxydocs->{classes}})
if ($member->{kind} eq 'function') if ($member->{kind} eq 'function')
{ {
my @params = map { join(' ', cleanupDoxygenType($_->{type}), $_->{declaration_name}) } @{$member->{parameters}}; my @params = map { join(' ', cleanupDoxygenType($_->{type}), $_->{declaration_name}) } @{$member->{parameters}};
my $callDescription = sprintf("%40s %s(%s)\n", cleanupDoxygenType($member->{type}), $member->{name}, join(', ', @params)); my $briefDescription = sprintf("%40s %s(%s)\n", cleanupDoxygenType($member->{type}), $member->{name}, join(', ', @params));
my $escapedBriefDescription = "\"" . escapeStringForC($callDescription) . "\""; my $escapedBriefDescription = "\"" . escapeStringForC($briefDescription) . "\"";
my %paramInfo = map { $_->{declaration_name} => { type => explainCType(cleanupDoxygenType($_->{type})) } } @{$member->{parameters}}; my %paramInfo = map { $_->{declaration_name} => { type => $_->{type}} } @{$member->{parameters}};
my $escapedDetailedDescription = "\"\"\n"; my $escapedDetailedDescription = "\"\"\n";
my $doc = $member->{detailed}->{doc}; if ($member->{detailed}->{doc})
if ($doc)
{ {
my $briefDescr = formatDocComment($member->{brief}->{doc}); # get from the proper place my $docString = formatDocComment($member->{detailed}->{doc}, \%paramInfo);
unless ($briefDescr =~ /\w/) # if not provided (API author forgot to add '@brief' comment),
{
for (my $i = 0; $i < @{$doc}; ++$i) # then look inside 'detailed' section
{
my $docElement = $doc->[$i];
if ($docElement->{type} eq 'text' and $docElement->{content} =~ /\w+/) # use first meaningful line as brief description
{
$briefDescr = $docElement->{content};
$briefDescr =~ s/^\s+|\s+$//g;
splice @{$doc}, $i, 1; # this section shouldn't be used twice
last;
}
}
}
my $cmdSyntax = $member->{name};
my $cmdArgs = join(' ', map { $_->{declaration_name} } @{$member->{parameters}});
$cmdSyntax .= " $cmdArgs" if $cmdArgs;
my $docString;
$docString .= $briefDescr;
$docString .= "\n\n" . formatDocComment($doc, \%paramInfo, $cmdSyntax);
for my $line (split(/\n/, $docString)) for my $line (split(/\n/, $docString))
{ {
$escapedDetailedDescription .= " \"" . escapeStringForC($line . "\n") . "\"\n"; $escapedDetailedDescription .= " \"" . escapeStringForC($line . "\n") . "\"\n";
@ -120,85 +96,62 @@ sub cleanupDoxygenType
return $type; return $type;
} }
sub explainCType
{
my($type) = @_;
$type =~ s/\b\w+:://g; # remove namespaces
$type =~ s/^(?:optional|api)<(.+)>$/$1/; # disregard optional<> and some other templates
$type =~ s/^const\s+(.+)/$1/; # strip const modifier
$type =~ s/^(.+)&/$1/; # strip references
$type =~ s/\s+$/$1/;
$type =~ s/\b(u?int(8|16|32|64)_t|int|unsigned)\b/integer/; # spare the user from width and signedness
$type =~ s/\bbool\b/boolean/; # they're not C++ people
$type =~ s/^(?:vector|set|flat_set)<(.+)>$/[$1, ...]/; # represent as JSon-like array notation
$type =~ s/^(?:map|flat_map)<(.+)\s*,\s*(.+)>$/{$1 => $2, ...}/; # same for map
$type =~ s/^time_point_sec$/time, e.g. 2021-12-25T14:30:05/;
return $type;
}
sub formatDocComment sub formatDocComment
{ {
my($doc, $paramInfo, $cmdSyntax) = @_; my($doc, $paramInfo) = @_;
my $bodyDocs = ''; my $bodyDocs = '';
my $notes = '';
my $see = '';
my $paramDocs = ''; my $paramDocs = '';
my $returnDocs = ''; my $returnDocs = '';
for (my $i = 0; $i < @{$doc}; ++$i) for (my $i = 0; $i < @{$doc}; ++$i)
{ {
my $docElement = $doc->[$i]; if ($doc->[$i] eq 'params')
if ($docElement->{params})
{ {
$paramDocs .= "Parameters:\n"; $paramDocs .= "Parameters:\n";
for my $parameter (@{$docElement->{params}}) @parametersList = @{$doc->[$i + 1]};
for my $parameter (@parametersList)
{ {
my $declname = $parameter->{parameters}->[0]->{name}; my $declname = $parameter->{parameters}->[0]->{name};
my $decltype = cleanupDoxygenType($paramInfo->{$declname}->{type}); my $decltype = cleanupDoxygenType($paramInfo->{$declname}->{type});
$paramDocs .= Text::Wrap::fill(' ', ' ', "$declname ($decltype): " . formatDocComment($parameter->{doc})) . "\n"; $paramDocs .= Text::Wrap::fill(' ', ' ', "$declname: " . formatDocComment($parameter->{doc}) . " (type: $decltype)") . "\n";
} }
++$i;
} }
elsif ($docElement->{return}) elsif ($doc->[$i]->{return})
{ {
$returnDocs .= "Returns:\n"; $returnDocs .= "Returns\n";
$returnDocs .= Text::Wrap::fill(' ',' ', formatDocComment($docElement->{return})) . "\n"; $returnDocs .= Text::Wrap::fill(' ',' ', formatDocComment($doc->[$i]->{return})) . "\n";
} }
elsif ($docElement->{note}) else
{ {
$notes .= Text::Wrap::fill(' ',' ', "Note: ".formatDocComment($docElement->{note})) . "\n"; my $docElement = $doc->[$i];
} if ($docElement->{type} eq 'text' or $docElement->{type} eq 'url')
elsif ($docElement->{see}) {
{ $bodyDocs .= $docElement->{content};
$see .= Text::Wrap::fill(' ',' ', "See: ".formatDocComment($docElement->{see})) . "\n"; }
} elsif ($docElement->{type} eq 'parbreak')
elsif ($docElement->{type} eq 'text' or $docElement->{type} eq 'url') {
{ $bodyDocs .= "\n\n";
$bodyDocs .= $docElement->{content}; }
} elsif ($docElement->{type} eq 'style' and $docElement->{style} eq 'code')
elsif ($docElement->{type} eq 'parbreak') {
{ $bodyDocs .= "'";
$bodyDocs .= "\n\n"; }
}
elsif ($docElement->{type} eq 'style' and $docElement->{style} eq 'code')
{
$bodyDocs .= "'";
} }
} }
$bodyDocs =~ s/^\s+|\s+$//g; $bodyDocs =~ s/^\s+|\s+$//g;
$bodyDocs = Text::Wrap::fill('', '', $bodyDocs); $bodyDocs = Text::Wrap::fill('', '', $bodyDocs);
$notes =~ s/^\s+|\s+$//g; $paramDocs =~ s/^\s+|\s+$//g;
$see =~ s/^\s+|\s+$//g;
$paramDocs =~ s/^\s+|\s+$//g;
$returnDocs =~ s/^\s+|\s+$//g; $returnDocs =~ s/^\s+|\s+$//g;
my $cmdDocs; my $result = Text::Wrap::fill('', '', $bodyDocs);
$cmdDocs = "Command:\n" . Text::Wrap::fill(' ',' ', $cmdSyntax) if $cmdSyntax; $result .= "\n\n" . $paramDocs if $paramDocs;
$result .= "\n\n" . $returnDocs if $returnDocs;
return join "\n\n", grep {$_} ($bodyDocs, $notes, $see, $cmdDocs, $paramDocs, $returnDocs); return $result;
} }
sub escapeCharForCString sub escapeCharForCString

View file

@ -84,32 +84,6 @@ typedef multi_index_container<
> >
> key_label_index_type; > key_label_index_type;
/* How to write doxygen docs
*
* Good
* / ** Returns the block chain's rapidly-changing properties.
* *
* * The returned object contains information that changes every block interval
* * such as the head block number, the next witness, etc.
* * /
*
* Bad, no empty line
* / ** Returns the block chain's rapidly-changing properties.
* * The returned object contains information that changes every block interval
* * such as the head block number, the next witness, etc.
* * /
*
* Better, using @brief tag
* / **
* * @brief Returns the block chain's rapidly-changing properties.
* * Long description text 1
* * Long description text 2
* * @param param1 param1 description
* * @param param2 param2 description
* * @returns return value description
* * /
* string get_rapidly_changing_properties(int32_t interval, string chain_id)
*/
struct wallet_data struct wallet_data
{ {
@ -275,7 +249,6 @@ class wallet_api
*/ */
uint64_t get_account_count()const; uint64_t get_account_count()const;
/** Lists all accounts controlled by this wallet. /** Lists all accounts controlled by this wallet.
*
* This returns a list of the full account objects for all accounts whose private keys * This returns a list of the full account objects for all accounts whose private keys
* we possess. * we possess.
* @returns a list of account objects * @returns a list of account objects
@ -357,7 +330,6 @@ class wallet_api
vector<force_settlement_object> get_settle_orders(string a, uint32_t limit)const; vector<force_settlement_object> get_settle_orders(string a, uint32_t limit)const;
/** Returns the block chain's slowly-changing settings. /** Returns the block chain's slowly-changing settings.
*
* This object contains all of the properties of the blockchain that are fixed * This object contains all of the properties of the blockchain that are fixed
* or that change only once per maintenance interval (daily) such as the * or that change only once per maintenance interval (daily) such as the
* current list of witnesses, committee_members, block interval, etc. * current list of witnesses, committee_members, block interval, etc.
@ -367,7 +339,6 @@ class wallet_api
global_property_object get_global_properties() const; global_property_object get_global_properties() const;
/** Returns the block chain's rapidly-changing properties. /** Returns the block chain's rapidly-changing properties.
*
* The returned object contains information that changes every block interval * The returned object contains information that changes every block interval
* such as the head block number, the next witness, etc. * such as the head block number, the next witness, etc.
* @see \c get_global_properties() for less-frequently changing properties * @see \c get_global_properties() for less-frequently changing properties
@ -383,7 +354,6 @@ class wallet_api
account_object get_account(string account_name_or_id) const; account_object get_account(string account_name_or_id) const;
/** Returns information about the given asset. /** Returns information about the given asset.
*
* @param asset_name_or_id the symbol or id of the asset in question * @param asset_name_or_id the symbol or id of the asset in question
* @returns the information about the asset stored in the block chain * @returns the information about the asset stored in the block chain
*/ */
@ -398,7 +368,6 @@ class wallet_api
asset_bitasset_data_object get_bitasset_data(string asset_name_or_id)const; asset_bitasset_data_object get_bitasset_data(string asset_name_or_id)const;
/** Lookup the id of a named account. /** Lookup the id of a named account.
*
* @param account_name_or_id the name of the account to look up * @param account_name_or_id the name of the account to look up
* @returns the id of the named account * @returns the id of the named account
*/ */
@ -406,7 +375,6 @@ class wallet_api
/** /**
* Lookup the id of a named asset. * Lookup the id of a named asset.
*
* @param asset_name_or_id the symbol of an asset to look up * @param asset_name_or_id the symbol of an asset to look up
* @returns the id of the given asset * @returns the id of the given asset
*/ */
@ -609,7 +577,7 @@ class wallet_api
/** /**
* Derive any number of *possible* owner keys from a given brain key. * Derive any number of *possible* owner keys from a given brain key.
* *
* @note These keys may or may not match with the owner keys of any account. * NOTE: These keys may or may not match with the owner keys of any account.
* This function is merely intended to assist with account or key recovery. * This function is merely intended to assist with account or key recovery.
* *
* @see suggest_brain_key() * @see suggest_brain_key()
@ -623,8 +591,7 @@ class wallet_api
/** /**
* Determine whether a textual representation of a public key * Determine whether a textual representation of a public key
* (in Base-58 format) is *currently* linked * (in Base-58 format) is *currently* linked
* to any *registered* (i.e. non-stealth) account on the blockchain. * to any *registered* (i.e. non-stealth) account on the blockchain
*
* @param public_key Public key * @param public_key Public key
* @return Whether a public key is known * @return Whether a public key is known
*/ */
@ -715,7 +682,7 @@ class wallet_api
uint32_t referrer_percent, uint32_t referrer_percent,
bool broadcast = false); bool broadcast = false);
/** Updates account public keys. /** Updates account public keys
* *
* @param name the name of the existing account * @param name the name of the existing account
* @param old_owner the owner key for the named account to be replaced * @param old_owner the owner key for the named account to be replaced
@ -733,8 +700,7 @@ class wallet_api
bool broadcast = false); bool broadcast = false);
/** /**
* Updates the key of an authority for an exisiting account. * This method updates the key of an authority for an exisiting account.
* Warning: You can create impossible authorities using this method. The method * Warning: You can create impossible authorities using this method. The method
* will fail if you create an impossible owner authority, but will allow impossible * will fail if you create an impossible owner authority, but will allow impossible
* active and posting authorities. * active and posting authorities.
@ -753,7 +719,6 @@ class wallet_api
/** /**
* Upgrades an account to prime status. * Upgrades an account to prime status.
*
* This makes the account holder a 'lifetime member'. * This makes the account holder a 'lifetime member'.
* *
* @todo there is no option for annual membership * @todo there is no option for annual membership
@ -821,7 +786,7 @@ class wallet_api
/** /**
* Convert a JSON transaction to its transactin ID. * This method is used to convert a JSON transaction to its transactin ID.
*/ */
transaction_id_type get_transaction_id( const signed_transaction& trx )const { return trx.id(); } transaction_id_type get_transaction_id( const signed_transaction& trx )const { return trx.id(); }
@ -829,7 +794,7 @@ class wallet_api
/** These methods are used for stealth transfers */ /** These methods are used for stealth transfers */
///@{ ///@{
/** /**
* Set the label for a public key * This method can be used to set the label for a public key
* *
* @note No two keys can have the same label. * @note No two keys can have the same label.
* *
@ -953,7 +918,7 @@ class wallet_api
signed_transaction borrow_asset(string borrower_name, string amount_to_borrow, string asset_symbol, signed_transaction borrow_asset(string borrower_name, string amount_to_borrow, string asset_symbol,
string amount_of_collateral, bool broadcast = false); string amount_of_collateral, bool broadcast = false);
/** Cancel an existing order. /** Cancel an existing order
* *
* @param order_id the id of order to be cancelled * @param order_id the id of order to be cancelled
* @param broadcast true to broadcast the transaction on the network * @param broadcast true to broadcast the transaction on the network
@ -1013,7 +978,6 @@ class wallet_api
bool broadcast = false); bool broadcast = false);
/** Update the core options on an asset. /** Update the core options on an asset.
*
* There are a number of options which all assets in the network use. These options are * There are a number of options which all assets in the network use. These options are
* enumerated in the asset_object::asset_options struct. This command is used to update * enumerated in the asset_object::asset_options struct. This command is used to update
* these options for an existing asset. * these options for an existing asset.
@ -1220,7 +1184,6 @@ class wallet_api
bool broadcast = false); bool broadcast = false);
/** Lists all witnesses registered in the blockchain. /** Lists all witnesses registered in the blockchain.
*
* This returns a list of all account names that own witnesses, and the associated witness id, * This returns a list of all account names that own witnesses, and the associated witness id,
* sorted by name. This lists witnesses whether they are currently voted in or not. * sorted by name. This lists witnesses whether they are currently voted in or not.
* *
@ -1251,7 +1214,6 @@ class wallet_api
map<string, committee_member_id_type> list_committee_members(const string& lowerbound, uint32_t limit); map<string, committee_member_id_type> list_committee_members(const string& lowerbound, uint32_t limit);
/** Lists all workers in the blockchain. /** Lists all workers in the blockchain.
*
* This returns a list of all account names that own worker, and the associated worker id, * This returns a list of all account names that own worker, and the associated worker id,
* sorted by name. This lists workers whether they are currently voted in or not. * sorted by name. This lists workers whether they are currently voted in or not.
* *
@ -1393,7 +1355,6 @@ class wallet_api
bool broadcast = false); bool broadcast = false);
/** Lists all SONs in the blockchain. /** Lists all SONs in the blockchain.
*
* This returns a list of all account names that own SON, and the associated SON id, * This returns a list of all account names that own SON, and the associated SON id,
* sorted by name. This lists SONs whether they are currently voted in or not. * sorted by name. This lists SONs whether they are currently voted in or not.
* *
@ -1415,31 +1376,11 @@ class wallet_api
*/ */
map<string, son_id_type> list_active_sons(); map<string, son_id_type> list_active_sons();
/**
* @brief Get list of active sons
* @return List of active SONs
*/
flat_map<sidechain_type, vector<son_info>> get_active_sons();
/**
* @brief Get list of active sons
* @param sidechain Sidechain type [bitcoin|ethereum|hive]
* @return List of active SONs
*/
vector<son_info> get_active_sons_by_sidechain(sidechain_type sidechain);
/** /**
* @brief Get SON network status * @brief Get SON network status
* @return SON network status description for a given sidechain type * @return SON network status description
*/ */
map<sidechain_type, map<son_id_type, string>> get_son_network_status(); map<son_id_type, string> get_son_network_status();
/**
* @brief Get SON network status
* @param sidechain Sidechain type [bitcoin|ethereum|hive]
* @return SON network status description for a given sidechain type
*/
map<son_id_type, string> get_son_network_status_by_sidechain(sidechain_type sidechain);
/** /**
* @brief Get active SON wallet * @brief Get active SON wallet
@ -1621,7 +1562,8 @@ class wallet_api
string asset_symbol, string asset_symbol,
bool broadcast = false); bool broadcast = false);
/** Withdraw a GPOS vesting balance. /**
* Withdraw a GPOS vesting balance.
* *
* @param account_name The account name of the witness/user, also accepts account ID or vesting balance ID type. * @param account_name The account name of the witness/user, also accepts account ID or vesting balance ID type.
* @param amount The amount to withdraw. * @param amount The amount to withdraw.
@ -2657,10 +2599,7 @@ FC_API( graphene::wallet::wallet_api,
(activate_deregistered_son) (activate_deregistered_son)
(list_sons) (list_sons)
(list_active_sons) (list_active_sons)
(get_active_sons)
(get_active_sons_by_sidechain)
(get_son_network_status) (get_son_network_status)
(get_son_network_status_by_sidechain)
(request_son_maintenance) (request_son_maintenance)
(cancel_request_son_maintenance) (cancel_request_son_maintenance)
(get_active_son_wallet) (get_active_son_wallet)

View file

@ -2274,25 +2274,55 @@ public:
FC_CAPTURE_AND_RETHROW() FC_CAPTURE_AND_RETHROW()
} }
flat_map<sidechain_type, vector<son_info>> get_active_sons() //! Fixme - do we need to specify sidechain_type as params here?
{ try { map<son_id_type, string> get_son_network_status()
return _remote_db->get_active_sons(); {
} FC_CAPTURE_AND_RETHROW() } try
{
const global_property_object& gpo = get_global_properties();
vector<son_info> get_active_sons_by_sidechain(sidechain_type sidechain) set<son_id_type> son_ids_set;
{ try { for(const auto& active_sidechain_type : active_sidechain_types) {
return _remote_db->get_active_sons_by_sidechain(sidechain); std::transform(gpo.active_sons.at(active_sidechain_type).cbegin(), gpo.active_sons.at(active_sidechain_type).cend(),
} FC_CAPTURE_AND_RETHROW() } 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<sidechain_type, map<son_id_type, string>> get_son_network_status() map<son_id_type, string> result;
{ try { std::vector<fc::optional<son_object>> son_objects = _remote_db->get_sons(son_ids);
return _remote_db->get_son_network_status(); for(auto son_obj: son_objects) {
} FC_CAPTURE_AND_RETHROW() } string status;
if (son_obj) {
map<son_id_type, string> get_son_network_status_by_sidechain(sidechain_type sidechain) son_statistics_object sso = get_object(son_obj->statistics);
{ try { for(const auto& active_sidechain_type : active_sidechain_types) {
return _remote_db->get_son_network_status_by_sidechain(sidechain); if (sso.last_active_timestamp.at(active_sidechain_type) + fc::seconds(gpo.parameters.son_heartbeat_frequency()) > time_point::now()) {
} FC_CAPTURE_AND_RETHROW() } 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() optional<son_wallet_object> get_active_son_wallet()
{ try { { try {
@ -2815,7 +2845,7 @@ public:
account_id_type son_account_id = get_account_id(son); 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); fc::optional<son_object> son_obj = _remote_db->get_son_by_account_id(son_account_id);
FC_ASSERT(son_obj, "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 || sidechain == sidechain_type::ethereum, "Unexpected sidechain type"); FC_ASSERT(sidechain == sidechain_type::bitcoin || sidechain == sidechain_type::hive, "Unexpected sidechain type");
if (approve) if (approve)
{ {
@ -2861,7 +2891,7 @@ public:
account_id_type son_owner_account_id = get_account_id(son); 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); fc::optional<son_object> son_obj = _remote_db->get_son_by_account_id(son_owner_account_id);
FC_ASSERT(son_obj, "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 || sidechain == sidechain_type::ethereum, "Unexpected sidechain type"); 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)); auto insert_result = voting_account_object.options.votes.insert(son_obj->get_sidechain_vote_id(sidechain));
if (!insert_result.second) if (!insert_result.second)
@ -2872,7 +2902,7 @@ public:
account_id_type son_owner_account_id = get_account_id(son); 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); fc::optional<son_object> son_obj = _remote_db->get_son_by_account_id(son_owner_account_id);
FC_ASSERT(son_obj, "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 || sidechain == sidechain_type::ethereum, "Unexpected sidechain type"); 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)); unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->get_sidechain_vote_id(sidechain));
if (!votes_removed) if (!votes_removed)
@ -2913,7 +2943,6 @@ public:
case sidechain_type::peerplays : return "peerplays"; case sidechain_type::peerplays : return "peerplays";
case sidechain_type::bitcoin : return "bitcoin"; case sidechain_type::bitcoin : return "bitcoin";
case sidechain_type::hive : return "hive"; case sidechain_type::hive : return "hive";
case sidechain_type::ethereum : return "ethereum";
default: default:
FC_THROW("Wrong sidechain type: ${sidechain}", ("sidechain", sidechain)); FC_THROW("Wrong sidechain type: ${sidechain}", ("sidechain", sidechain));
} }
@ -5281,26 +5310,11 @@ map<string, son_id_type> wallet_api::list_active_sons()
return my->list_active_sons(); return my->list_active_sons();
} }
flat_map<sidechain_type, vector<son_info>> wallet_api::get_active_sons() map<son_id_type, string> wallet_api::get_son_network_status()
{
return my->get_active_sons();
}
vector<son_info> wallet_api::get_active_sons_by_sidechain(sidechain_type sidechain)
{
return my->get_active_sons_by_sidechain(sidechain);
}
map<sidechain_type, map<son_id_type, string>> wallet_api::get_son_network_status()
{ {
return my->get_son_network_status(); return my->get_son_network_status();
} }
map<son_id_type, string> wallet_api::get_son_network_status_by_sidechain(sidechain_type sidechain)
{
return my->get_son_network_status_by_sidechain(sidechain);
}
optional<son_wallet_object> wallet_api::get_active_son_wallet() optional<son_wallet_object> wallet_api::get_active_son_wallet()
{ {
return my->get_active_son_wallet(); return my->get_active_son_wallet();

View file

@ -4,6 +4,7 @@ if( BUILD_PEERPLAYS_PROGRAMS )
add_subdirectory( genesis_util ) add_subdirectory( genesis_util )
add_subdirectory( witness_node ) add_subdirectory( witness_node )
add_subdirectory( debug_node ) add_subdirectory( debug_node )
add_subdirectory( delayed_node )
add_subdirectory( js_operation_serializer ) add_subdirectory( js_operation_serializer )
add_subdirectory( size_checker ) add_subdirectory( size_checker )
endif( BUILD_PEERPLAYS_PROGRAMS ) endif( BUILD_PEERPLAYS_PROGRAMS )

View file

@ -0,0 +1,21 @@
add_executable( delayed_node main.cpp )
if( UNIX AND NOT APPLE )
set(rt_library rt )
endif()
find_package( Gperftools QUIET )
if( GPERFTOOLS_FOUND )
message( STATUS "Found gperftools; compiling delayed_node with TCMalloc")
list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc )
endif()
target_link_libraries( delayed_node
PRIVATE graphene_app graphene_egenesis_full graphene_delayed_node ${PLATFORM_SPECIFIC_LIBS} )
install( TARGETS
delayed_node
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)

View file

@ -0,0 +1,305 @@
/*
* Copyright (c) 2015 Cryptonomex, Inc., and contributors.
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <graphene/app/application.hpp>
#include <graphene/delayed_node/delayed_node_plugin.hpp>
#include <graphene/account_history/account_history_plugin.hpp>
#include <graphene/market_history/market_history_plugin.hpp>
#include <fc/exception/exception.hpp>
#include <fc/thread/thread.hpp>
#include <fc/interprocess/signals.hpp>
#include <fc/log/console_appender.hpp>
#include <fc/log/file_appender.hpp>
#include <fc/log/logger.hpp>
#include <fc/log/logger_config.hpp>
#include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <iostream>
#include <fstream>
#ifdef WIN32
# include <signal.h>
#else
# include <csignal>
#endif
using namespace graphene;
namespace bpo = boost::program_options;
void write_default_logging_config_to_stream(std::ostream& out);
fc::optional<fc::logging_config> load_logging_config_from_ini_file(const fc::path& config_ini_filename);
int main(int argc, char** argv) {
try {
app::application node;
bpo::options_description app_options("Graphene Delayed Node");
bpo::options_description cfg_options("Graphene Delayed Node");
app_options.add_options()
("help,h", "Print this help message and exit.")
("data-dir,d", bpo::value<boost::filesystem::path>()->default_value("delayed_node_data_dir"), "Directory containing databases, configuration file, etc.")
;
bpo::variables_map options;
bpo::options_description cli, cfg;
node.set_program_options(cli, cfg);
cfg_options.add(cfg);
cfg_options.add_options()
("plugins", bpo::value<std::string>()->default_value("delayed_node account_history market_history"),
"Space-separated list of plugins to activate");
auto delayed_plug = node.register_plugin<delayed_node::delayed_node_plugin>();
auto history_plug = node.register_plugin<account_history::account_history_plugin>();
auto market_history_plug = node.register_plugin<market_history::market_history_plugin>();
// add plugin options to config
try
{
bpo::options_description cli, cfg;
node.set_program_options(cli, cfg);
app_options.add(cli);
cfg_options.add(cfg);
bpo::store(bpo::parse_command_line(argc, argv, app_options), options);
}
catch (const boost::program_options::error& e)
{
std::cerr << "Error parsing command line: " << e.what() << "\n";
return 1;
}
if( options.count("help") )
{
std::cout << app_options << "\n";
return 0;
}
fc::path data_dir;
if( options.count("data-dir") )
{
data_dir = options["data-dir"].as<boost::filesystem::path>();
if( data_dir.is_relative() )
data_dir = fc::current_path() / data_dir;
}
fc::path config_ini_path = data_dir / "config.ini";
// Create config file if not already present
if( !fc::exists(config_ini_path) )
{
ilog("Writing new config file at ${path}", ("path", config_ini_path));
if( !fc::exists(data_dir) )
fc::create_directories(data_dir);
std::ofstream out_cfg(config_ini_path.preferred_string());
for( const boost::shared_ptr<bpo::option_description> od : cfg_options.options() )
{
if( !od->description().empty() )
out_cfg << "# " << od->description() << "\n";
boost::any store;
if( !od->semantic()->apply_default(store) )
out_cfg << "# " << od->long_name() << " = \n";
else {
auto example = od->format_parameter();
if( example.empty() )
// This is a boolean switch
out_cfg << od->long_name() << " = " << "false\n";
else {
// The string is formatted "arg (=<interesting part>)"
example.erase(0, 6);
example.erase(example.length()-1);
out_cfg << od->long_name() << " = " << example << "\n";
}
}
out_cfg << "\n";
}
write_default_logging_config_to_stream(out_cfg);
out_cfg.close();
// read the default logging config we just wrote out to the file and start using it
fc::optional<fc::logging_config> logging_config = load_logging_config_from_ini_file(config_ini_path);
if (logging_config)
fc::configure_logging(*logging_config);
}
// Parse configuration file
try {
bpo::store(bpo::parse_config_file<char>(config_ini_path.preferred_string().c_str(), cfg_options, true), options);
// try to get logging options from the config file.
try
{
fc::optional<fc::logging_config> logging_config = load_logging_config_from_ini_file(config_ini_path);
if (logging_config)
fc::configure_logging(*logging_config);
}
catch (const fc::exception&)
{
wlog("Error parsing logging config from config file ${config}, using default config", ("config", config_ini_path.preferred_string()));
}
bpo::notify(options);
} catch( const boost::program_options::error& e ) {
elog("Error parsing configuration file: ${e}", ("e", e.what()));
return 1;
}
if( !options.count("plugins") )
options.insert( std::make_pair( "plugins", bpo::variable_value(std::string("delayed_node account_history market_history"), true) ) );
node.initialize(data_dir, options);
node.initialize_plugins( options );
node.startup();
node.startup_plugins();
fc::promise<int>::ptr exit_promise = new fc::promise<int>("UNIX Signal Handler");
fc::set_signal_handler([&exit_promise](int signal) {
exit_promise->set_value(signal);
}, SIGINT);
ilog("Started delayed node on a chain with ${h} blocks.", ("h", node.chain_database()->head_block_num()));
ilog("Chain ID is ${id}", ("id", node.chain_database()->get_chain_id()) );
int signal = exit_promise->wait();
ilog("Exiting from signal ${n}", ("n", signal));
node.shutdown_plugins();
return 0;
} catch( const fc::exception& e ) {
elog("Exiting with error:\n${e}", ("e", e.to_detail_string()));
return 1;
}
}
// logging config is too complicated to be parsed by boost::program_options,
// so we do it by hand
//
// Currently, you can only specify the filenames and logging levels, which
// are all most users would want to change. At a later time, options can
// be added to control rotation intervals, compression, and other seldom-
// used features
void write_default_logging_config_to_stream(std::ostream& out)
{
out << "# declare an appender named \"stderr\" that writes messages to the console\n"
"[log.console_appender.stderr]\n"
"stream=std_error\n\n"
"# declare an appender named \"p2p\" that writes messages to p2p.log\n"
"[log.file_appender.p2p]\n"
"filename=logs/p2p/p2p.log\n"
"# filename can be absolute or relative to this config file\n\n"
"# route any messages logged to the default logger to the \"stderr\" logger we\n"
"# declared above, if they are info level are higher\n"
"[logger.default]\n"
"level=info\n"
"appenders=stderr\n\n"
"# route messages sent to the \"p2p\" logger to the p2p appender declared above\n"
"[logger.p2p]\n"
"level=info\n"
"appenders=p2p\n\n";
}
fc::optional<fc::logging_config> load_logging_config_from_ini_file(const fc::path& config_ini_filename)
{
try
{
fc::logging_config logging_config;
bool found_logging_config = false;
boost::property_tree::ptree config_ini_tree;
boost::property_tree::ini_parser::read_ini(config_ini_filename.preferred_string().c_str(), config_ini_tree);
for (const auto& section : config_ini_tree)
{
const std::string& section_name = section.first;
const boost::property_tree::ptree& section_tree = section.second;
const std::string console_appender_section_prefix = "log.console_appender.";
const std::string file_appender_section_prefix = "log.file_appender.";
const std::string logger_section_prefix = "logger.";
if (boost::starts_with(section_name, console_appender_section_prefix))
{
std::string console_appender_name = section_name.substr(console_appender_section_prefix.length());
std::string stream_name = section_tree.get<std::string>("stream");
// construct a default console appender config here
// stdout/stderr will be taken from ini file, everything else hard-coded here
fc::console_appender::config console_appender_config;
console_appender_config.level_colors.emplace_back(
fc::console_appender::level_color(fc::log_level::debug,
fc::console_appender::color::green));
console_appender_config.level_colors.emplace_back(
fc::console_appender::level_color(fc::log_level::warn,
fc::console_appender::color::brown));
console_appender_config.level_colors.emplace_back(
fc::console_appender::level_color(fc::log_level::error,
fc::console_appender::color::cyan));
console_appender_config.stream = fc::variant(stream_name, 1).as<fc::console_appender::stream::type>(1);
logging_config.appenders.push_back(fc::appender_config(console_appender_name, "console", fc::variant(console_appender_config, GRAPHENE_MAX_NESTED_OBJECTS)));
found_logging_config = true;
}
else if (boost::starts_with(section_name, file_appender_section_prefix))
{
std::string file_appender_name = section_name.substr(file_appender_section_prefix.length());
fc::path file_name = section_tree.get<std::string>("filename");
if (file_name.is_relative())
file_name = fc::absolute(config_ini_filename).parent_path() / file_name;
// construct a default file appender config here
// filename will be taken from ini file, everything else hard-coded here
fc::file_appender::config file_appender_config;
file_appender_config.filename = file_name;
file_appender_config.flush = true;
file_appender_config.rotate = true;
file_appender_config.rotation_interval = fc::hours(1);
file_appender_config.rotation_limit = fc::days(1);
logging_config.appenders.push_back(fc::appender_config(file_appender_name, "file", fc::variant(file_appender_config, GRAPHENE_MAX_NESTED_OBJECTS)));
found_logging_config = true;
}
else if (boost::starts_with(section_name, logger_section_prefix))
{
std::string logger_name = section_name.substr(logger_section_prefix.length());
std::string level_string = section_tree.get<std::string>("level");
std::string appenders_string = section_tree.get<std::string>("appenders");
fc::logger_config logger_config(logger_name);
logger_config.level = fc::variant(level_string, 1).as<fc::log_level>(1);
boost::split(logger_config.appenders, appenders_string,
boost::is_any_of(" ,"),
boost::token_compress_on);
logging_config.loggers.push_back(logger_config);
found_logging_config = true;
}
}
if (found_logging_config)
return logging_config;
else
return fc::optional<fc::logging_config>();
}
FC_RETHROW_EXCEPTIONS(warn, "")
}

View file

@ -11,7 +11,7 @@ endif()
# We have to link against graphene_debug_witness because deficiency in our API infrastructure doesn't allow plugins to be fully abstracted #246 # We have to link against graphene_debug_witness because deficiency in our API infrastructure doesn't allow plugins to be fully abstracted #246
target_link_libraries( witness_node target_link_libraries( witness_node
PRIVATE graphene_app graphene_egenesis_full graphene_snapshot graphene_delayed_node graphene_witness peerplays_sidechain ${PLATFORM_SPECIFIC_LIBS} ) PRIVATE graphene_app graphene_egenesis_full graphene_snapshot graphene_witness peerplays_sidechain ${PLATFORM_SPECIFIC_LIBS} )
# also add dependencies to graphene_generate_genesis graphene_generate_uia_sharedrop_genesis if you want those plugins # also add dependencies to graphene_generate_genesis graphene_generate_uia_sharedrop_genesis if you want those plugins
install( TARGETS install( TARGETS

View file

@ -36,7 +36,6 @@
#include <graphene/affiliate_stats/affiliate_stats_plugin.hpp> #include <graphene/affiliate_stats/affiliate_stats_plugin.hpp>
#include <graphene/bookie/bookie_plugin.hpp> #include <graphene/bookie/bookie_plugin.hpp>
#include <graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp> #include <graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp>
#include <graphene/delayed_node/delayed_node_plugin.hpp>
#include <graphene/utilities/git_revision.hpp> #include <graphene/utilities/git_revision.hpp>
#include <graphene/snapshot/snapshot.hpp> #include <graphene/snapshot/snapshot.hpp>
@ -91,7 +90,6 @@ int main(int argc, char** argv) {
auto bookie_plug = node->register_plugin<bookie::bookie_plugin>(); auto bookie_plug = node->register_plugin<bookie::bookie_plugin>();
auto peerplays_sidechain = node->register_plugin<peerplays_sidechain::peerplays_sidechain_plugin>(); auto peerplays_sidechain = node->register_plugin<peerplays_sidechain::peerplays_sidechain_plugin>();
auto snapshot_plug = node->register_plugin<snapshot_plugin::snapshot_plugin>(); auto snapshot_plug = node->register_plugin<snapshot_plugin::snapshot_plugin>();
auto delayed_plug = node->register_plugin<delayed_node::delayed_node_plugin>();
// add plugin options to config // add plugin options to config
try try

View file

@ -128,13 +128,11 @@ BOOST_AUTO_TEST_CASE( create_sons )
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1";
sidechain_public_keys[sidechain_type::hive] = "hive account 1"; sidechain_public_keys[sidechain_type::hive] = "hive account 1";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 1";
sth.create_son("son1account", "http://son1", sidechain_public_keys); sth.create_son("son1account", "http://son1", sidechain_public_keys);
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2";
sidechain_public_keys[sidechain_type::hive] = "hive account 2"; sidechain_public_keys[sidechain_type::hive] = "hive account 2";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 2";
sth.create_son("son2account", "http://son2", sidechain_public_keys); sth.create_son("son2account", "http://son2", sidechain_public_keys);
auto son1_obj = con.wallet_api_ptr->get_son("son1account"); auto son1_obj = con.wallet_api_ptr->get_son("son1account");
@ -142,20 +140,16 @@ BOOST_AUTO_TEST_CASE( create_sons )
BOOST_CHECK_EQUAL(son1_obj.url, "http://son1"); 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::bitcoin], "bitcoin_address 1");
BOOST_CHECK_EQUAL(son1_obj.sidechain_public_keys[sidechain_type::hive], "hive account 1"); BOOST_CHECK_EQUAL(son1_obj.sidechain_public_keys[sidechain_type::hive], "hive account 1");
BOOST_CHECK_EQUAL(son1_obj.sidechain_public_keys[sidechain_type::ethereum], "ethereum address 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::bitcoin).instance(), 22);
BOOST_CHECK_EQUAL(son1_obj.get_sidechain_vote_id(sidechain_type::hive).instance(), 23); BOOST_CHECK_EQUAL(son1_obj.get_sidechain_vote_id(sidechain_type::hive).instance(), 23);
BOOST_CHECK_EQUAL(son1_obj.get_sidechain_vote_id(sidechain_type::ethereum).instance(), 24);
auto son2_obj = con.wallet_api_ptr->get_son("son2account"); 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(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.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::bitcoin], "bitcoin_address 2");
BOOST_CHECK_EQUAL(son2_obj.sidechain_public_keys[sidechain_type::hive], "hive account 2"); BOOST_CHECK_EQUAL(son2_obj.sidechain_public_keys[sidechain_type::hive], "hive account 2");
BOOST_CHECK_EQUAL(son2_obj.sidechain_public_keys[sidechain_type::ethereum], "ethereum address 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::bitcoin).instance(), 25); BOOST_CHECK_EQUAL(son2_obj.get_sidechain_vote_id(sidechain_type::hive).instance(), 25);
BOOST_CHECK_EQUAL(son2_obj.get_sidechain_vote_id(sidechain_type::hive).instance(), 26);
BOOST_CHECK_EQUAL(son2_obj.get_sidechain_vote_id(sidechain_type::ethereum).instance(), 27);
} catch( fc::exception& e ) { } catch( fc::exception& e ) {
BOOST_TEST_MESSAGE("SON cli wallet tests exception"); BOOST_TEST_MESSAGE("SON cli wallet tests exception");
@ -176,7 +170,6 @@ BOOST_AUTO_TEST_CASE( cli_update_son )
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1";
sidechain_public_keys[sidechain_type::hive] = "hive account 1"; sidechain_public_keys[sidechain_type::hive] = "hive account 1";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 1";
son_test_helper sth(*this); son_test_helper sth(*this);
sth.create_son("sonmember", "http://sonmember", sidechain_public_keys); sth.create_son("sonmember", "http://sonmember", sidechain_public_keys);
@ -189,23 +182,19 @@ BOOST_AUTO_TEST_CASE( cli_update_son )
BOOST_CHECK(son_data.son_account == sonmember_acct.get_id()); 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::bitcoin], "bitcoin_address 1");
BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::hive], "hive account 1"); BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::hive], "hive account 1");
BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::ethereum], "ethereum address 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::bitcoin).instance(), 22);
BOOST_CHECK_EQUAL(son_data.get_sidechain_vote_id(sidechain_type::hive).instance(), 23); BOOST_CHECK_EQUAL(son_data.get_sidechain_vote_id(sidechain_type::hive).instance(), 23);
BOOST_CHECK_EQUAL(son_data.get_sidechain_vote_id(sidechain_type::ethereum).instance(), 24);
// update SON // update SON
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2";
sidechain_public_keys[sidechain_type::hive] = "hive account 2"; sidechain_public_keys[sidechain_type::hive] = "hive account 2";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 2";
con.wallet_api_ptr->update_son("sonmember", "http://sonmember_updated", "", sidechain_public_keys, true); con.wallet_api_ptr->update_son("sonmember", "http://sonmember_updated", "", sidechain_public_keys, true);
son_data = con.wallet_api_ptr->get_son("sonmember"); son_data = con.wallet_api_ptr->get_son("sonmember");
BOOST_CHECK(son_data.url == "http://sonmember_updated"); 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::bitcoin], "bitcoin_address 2");
BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::hive], "hive account 2"); BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::hive], "hive account 2");
BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::ethereum], "ethereum address 2");
// update SON signing key // update SON signing key
sidechain_public_keys.clear(); sidechain_public_keys.clear();
@ -233,13 +222,11 @@ BOOST_AUTO_TEST_CASE( son_voting )
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1";
sidechain_public_keys[sidechain_type::hive] = "hive account 1"; sidechain_public_keys[sidechain_type::hive] = "hive account 1";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 1";
sth.create_son("son1account", "http://son1", sidechain_public_keys); sth.create_son("son1account", "http://son1", sidechain_public_keys);
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2";
sidechain_public_keys[sidechain_type::hive] = "hive account 2"; sidechain_public_keys[sidechain_type::hive] = "hive account 2";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 2";
sth.create_son("son2account", "http://son2", sidechain_public_keys); sth.create_son("son2account", "http://son2", sidechain_public_keys);
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
@ -266,7 +253,6 @@ BOOST_AUTO_TEST_CASE( son_voting )
BOOST_TEST_MESSAGE("Voting for son1account"); BOOST_TEST_MESSAGE("Voting for son1account");
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::bitcoin, true, true);
vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::hive, true, true); vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::hive, true, true);
vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::ethereum, true, true);
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
// Verify that the vote is there // Verify that the vote is there
@ -274,13 +260,11 @@ BOOST_AUTO_TEST_CASE( son_voting )
son1_end_votes = son1_obj.total_votes; son1_end_votes = son1_obj.total_votes;
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] > son1_start_votes[sidechain_type::bitcoin]); 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]); BOOST_CHECK(son1_end_votes[sidechain_type::hive] > son1_start_votes[sidechain_type::hive]);
BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] > son1_start_votes[sidechain_type::ethereum]);
// Vote for a son2account // Vote for a son2account
BOOST_TEST_MESSAGE("Voting for son2account"); BOOST_TEST_MESSAGE("Voting for son2account");
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::bitcoin, true, true);
vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::hive, true, true); vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::hive, true, true);
vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::ethereum, true, true);
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
// Verify that the vote is there // Verify that the vote is there
@ -288,7 +272,6 @@ BOOST_AUTO_TEST_CASE( son_voting )
son2_end_votes = son2_obj.total_votes; son2_end_votes = son2_obj.total_votes;
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] > son2_start_votes[sidechain_type::bitcoin]); 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]); BOOST_CHECK(son2_end_votes[sidechain_type::hive] > son2_start_votes[sidechain_type::hive]);
BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] > son2_start_votes[sidechain_type::ethereum]);
//! Check son1account voters //! Check son1account voters
auto voters_for_son1account = con.wallet_api_ptr->get_voters("son1account").voters_for_son; auto voters_for_son1account = con.wallet_api_ptr->get_voters("son1account").voters_for_son;
@ -297,8 +280,6 @@ BOOST_AUTO_TEST_CASE( son_voting )
BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::bitcoin).voters[0].instance, nathan_account_object.id.instance()); 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_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()); BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::hive).voters[0].instance, nathan_account_object.id.instance());
BOOST_REQUIRE_EQUAL(voters_for_son1account->at(sidechain_type::ethereum).voters.size(), 1);
BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::ethereum).voters[0].instance, nathan_account_object.id.instance());
//! Check son2account voters //! Check son2account voters
auto voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son; auto voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son;
@ -307,8 +288,6 @@ BOOST_AUTO_TEST_CASE( son_voting )
BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::bitcoin).voters[0].instance, nathan_account_object.id.instance()); 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_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()); BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::hive).voters[0].instance, nathan_account_object.id.instance());
BOOST_REQUIRE_EQUAL(voters_for_son2account->at(sidechain_type::ethereum).voters.size(), 1);
BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::ethereum).voters[0].instance, nathan_account_object.id.instance());
//! Check votes of nathan //! Check votes of nathan
auto nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; auto nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
@ -319,15 +298,11 @@ BOOST_AUTO_TEST_CASE( son_voting )
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 2); 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(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()); BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(1).id.instance(), son2_obj.id.instance());
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).size(), 2);
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(0).id.instance(), son1_obj.id.instance());
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(1).id.instance(), son2_obj.id.instance());
// Withdraw vote for a son1account // Withdraw vote for a son1account
BOOST_TEST_MESSAGE("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", sidechain_type::bitcoin, 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); vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::hive, false, true);
vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::ethereum, false, true);
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
// Verify that the vote is removed // Verify that the vote is removed
@ -335,14 +310,12 @@ BOOST_AUTO_TEST_CASE( son_voting )
son1_end_votes = son1_obj.total_votes; son1_end_votes = son1_obj.total_votes;
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]); 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]); BOOST_CHECK(son1_end_votes[sidechain_type::hive] == son1_start_votes[sidechain_type::hive]);
BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] == son1_start_votes[sidechain_type::ethereum]);
//! Check son1account voters //! Check son1account voters
voters_for_son1account = con.wallet_api_ptr->get_voters("son1account").voters_for_son; voters_for_son1account = con.wallet_api_ptr->get_voters("son1account").voters_for_son;
BOOST_REQUIRE(voters_for_son1account); 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::bitcoin).voters.size(), 0);
BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::hive).voters.size(), 0); BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::hive).voters.size(), 0);
BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::ethereum).voters.size(), 0);
//! Check votes of nathan //! Check votes of nathan
nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
@ -351,14 +324,11 @@ BOOST_AUTO_TEST_CASE( son_voting )
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::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).size(), 1);
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son2_obj.id.instance()); BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son2_obj.id.instance());
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).size(), 1);
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(0).id.instance(), son2_obj.id.instance());
// Withdraw vote for a son2account // Withdraw vote for a son2account
BOOST_TEST_MESSAGE("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", sidechain_type::bitcoin, 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); vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::hive, false, true);
vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::ethereum, false, true);
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
// Verify that the vote is removed // Verify that the vote is removed
@ -366,14 +336,12 @@ BOOST_AUTO_TEST_CASE( son_voting )
son2_end_votes = son2_obj.total_votes; son2_end_votes = son2_obj.total_votes;
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] == son2_start_votes[sidechain_type::bitcoin]); 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]); BOOST_CHECK(son2_end_votes[sidechain_type::hive] == son2_start_votes[sidechain_type::hive]);
BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] == son2_start_votes[sidechain_type::ethereum]);
//! Check son2account voters //! Check son2account voters
voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son; voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son;
BOOST_REQUIRE(voters_for_son2account); 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::bitcoin).voters.size(), 0);
BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::hive).voters.size(), 0); BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::hive).voters.size(), 0);
BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::ethereum).voters.size(), 0);
//! Check votes of nathan //! Check votes of nathan
nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
@ -415,7 +383,6 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture )
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i);
sidechain_public_keys[sidechain_type::hive] = "hive account " + fc::to_pretty_string(i); sidechain_public_keys[sidechain_type::hive] = "hive account " + fc::to_pretty_string(i);
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address " + fc::to_pretty_string(i);
sth.create_son("sonaccount" + fc::to_pretty_string(i), sth.create_son("sonaccount" + fc::to_pretty_string(i),
"http://son" + fc::to_pretty_string(i), "http://son" + fc::to_pretty_string(i),
sidechain_public_keys, sidechain_public_keys,
@ -433,7 +400,6 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture )
std::string name = "sonaccount" + fc::to_pretty_string(i); std::string name = "sonaccount" + fc::to_pretty_string(i);
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::bitcoin, true, true);
vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::hive, true, true); vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::hive, true, true);
vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::ethereum, true, true);
} }
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
@ -443,17 +409,14 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture )
std::string name2 = "sonaccount" + fc::to_pretty_string(i + 1); std::string name2 = "sonaccount" + fc::to_pretty_string(i + 1);
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::bitcoin, true, true);
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true); vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true);
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::ethereum, true, true);
} }
gpo = con.wallet_api_ptr->get_global_properties(); gpo = con.wallet_api_ptr->get_global_properties();
BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).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_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size());
BOOST_TEST_MESSAGE("gpo active_sons[ethereum]: " << gpo.active_sons.at(sidechain_type::ethereum).size());
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
gpo = con.wallet_api_ptr->get_global_properties(); gpo = con.wallet_api_ptr->get_global_properties();
BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).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_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size());
BOOST_TEST_MESSAGE("gpo active_sons[ethereum]: " << gpo.active_sons.at(sidechain_type::ethereum).size());
for(unsigned int i = 0; i < son_number - 1; i++) for(unsigned int i = 0; i < son_number - 1; i++)
{ {
@ -461,17 +424,14 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture )
std::string name2 = "sonaccount" + fc::to_pretty_string(i); std::string name2 = "sonaccount" + fc::to_pretty_string(i);
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::bitcoin, true, true);
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true); vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true);
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::ethereum, true, true);
} }
gpo = con.wallet_api_ptr->get_global_properties(); gpo = con.wallet_api_ptr->get_global_properties();
BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).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_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size());
BOOST_TEST_MESSAGE("gpo active_sons[ethereum]: " << gpo.active_sons.at(sidechain_type::ethereum).size());
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
gpo = con.wallet_api_ptr->get_global_properties(); gpo = con.wallet_api_ptr->get_global_properties();
BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).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_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size());
BOOST_TEST_MESSAGE("gpo active_sons[ethereum]: " << gpo.active_sons.at(sidechain_type::ethereum).size());
for(unsigned int i = 0; i < son_number - 2; i++) for(unsigned int i = 0; i < son_number - 2; i++)
{ {
@ -479,17 +439,14 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture )
std::string name2 = "sonaccount" + fc::to_pretty_string(i); std::string name2 = "sonaccount" + fc::to_pretty_string(i);
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::bitcoin, true, true);
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true); vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true);
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::ethereum, true, true);
} }
gpo = con.wallet_api_ptr->get_global_properties(); gpo = con.wallet_api_ptr->get_global_properties();
BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).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_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size());
BOOST_TEST_MESSAGE("gpo active_sons[ethereum]: " << gpo.active_sons.at(sidechain_type::ethereum).size());
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).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); BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == son_number);
BOOST_CHECK(gpo.active_sons.at(sidechain_type::ethereum).size() == son_number);
} catch( fc::exception& e ) { } catch( fc::exception& e ) {
BOOST_TEST_MESSAGE("SON cli wallet tests exception"); BOOST_TEST_MESSAGE("SON cli wallet tests exception");
@ -511,13 +468,11 @@ BOOST_AUTO_TEST_CASE( list_son )
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1";
sidechain_public_keys[sidechain_type::hive] = "hive account 1"; sidechain_public_keys[sidechain_type::hive] = "hive account 1";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 1";
sth.create_son("son1account", "http://son1", sidechain_public_keys); sth.create_son("son1account", "http://son1", sidechain_public_keys);
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2";
sidechain_public_keys[sidechain_type::hive] = "hive account 2"; sidechain_public_keys[sidechain_type::hive] = "hive account 2";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 2";
sth.create_son("son2account", "http://son2", sidechain_public_keys); sth.create_son("son2account", "http://son2", sidechain_public_keys);
auto res = con.wallet_api_ptr->list_sons("", 100); auto res = con.wallet_api_ptr->list_sons("", 100);
@ -545,13 +500,11 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1";
sidechain_public_keys[sidechain_type::hive] = "hive account 1"; sidechain_public_keys[sidechain_type::hive] = "hive account 1";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 1";
sth.create_son("son1account", "http://son1", sidechain_public_keys); sth.create_son("son1account", "http://son1", sidechain_public_keys);
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2";
sidechain_public_keys[sidechain_type::hive] = "hive account 2"; sidechain_public_keys[sidechain_type::hive] = "hive account 2";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 2";
sth.create_son("son2account", "http://son2", sidechain_public_keys); sth.create_son("son2account", "http://son2", sidechain_public_keys);
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
@ -586,8 +539,6 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
sidechain_type::bitcoin, 2, true); sidechain_type::bitcoin, 2, true);
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
sidechain_type::hive, 2, true); sidechain_type::hive, 2, true);
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
sidechain_type::ethereum, 2, true);
generate_block(); generate_block();
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
@ -595,14 +546,10 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
son1_obj = con.wallet_api_ptr->get_son("son1account"); son1_obj = con.wallet_api_ptr->get_son("son1account");
son1_end_votes = son1_obj.total_votes; son1_end_votes = son1_obj.total_votes;
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] > son1_start_votes[sidechain_type::bitcoin]); 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]);
BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] > son1_start_votes[sidechain_type::ethereum]);
son1_start_votes = son1_end_votes; son1_start_votes = son1_end_votes;
son2_obj = con.wallet_api_ptr->get_son("son2account"); son2_obj = con.wallet_api_ptr->get_son("son2account");
son2_end_votes = son2_obj.total_votes; son2_end_votes = son2_obj.total_votes;
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] > son2_start_votes[sidechain_type::bitcoin]); 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]);
BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] > son2_start_votes[sidechain_type::ethereum]);
son2_start_votes = son2_end_votes; son2_start_votes = son2_end_votes;
//! Check son1account voters //! Check son1account voters
@ -612,8 +559,6 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::bitcoin).voters[0].instance, nathan_account_object.id.instance()); 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_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()); BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::hive).voters[0].instance, nathan_account_object.id.instance());
BOOST_REQUIRE_EQUAL(voters_for_son1account->at(sidechain_type::ethereum).voters.size(), 1);
BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::ethereum).voters[0].instance, nathan_account_object.id.instance());
//! Check son2account voters //! Check son2account voters
auto voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son; auto voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son;
@ -622,8 +567,6 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::bitcoin).voters[0].instance, nathan_account_object.id.instance()); 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_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()); BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::hive).voters[0].instance, nathan_account_object.id.instance());
BOOST_REQUIRE_EQUAL(voters_for_son2account->at(sidechain_type::ethereum).voters.size(), 1);
BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::ethereum).voters[0].instance, nathan_account_object.id.instance());
//! Check votes of nathan //! Check votes of nathan
auto nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; auto nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
@ -634,9 +577,6 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 2); 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(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()); BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(1).id.instance(), son2_obj.id.instance());
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).size(), 2);
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(0).id.instance(), son1_obj.id.instance());
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(1).id.instance(), son2_obj.id.instance());
// Withdraw vote for SON 1 // Withdraw vote for SON 1
accepted.clear(); accepted.clear();
@ -647,23 +587,17 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
sidechain_type::bitcoin, 1, true); sidechain_type::bitcoin, 1, true);
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
sidechain_type::hive, 1, true); sidechain_type::hive, 1, true);
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
sidechain_type::ethereum, 1, true);
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
// Verify the votes // Verify the votes
son1_obj = con.wallet_api_ptr->get_son("son1account"); son1_obj = con.wallet_api_ptr->get_son("son1account");
son1_end_votes = son1_obj.total_votes; son1_end_votes = son1_obj.total_votes;
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] < son1_start_votes[sidechain_type::bitcoin]); 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]);
BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] < son1_start_votes[sidechain_type::ethereum]);
son1_start_votes = son1_end_votes; son1_start_votes = son1_end_votes;
son2_obj = con.wallet_api_ptr->get_son("son2account"); son2_obj = con.wallet_api_ptr->get_son("son2account");
// voice distribution changed, SON2 now has all voices // voice distribution changed, SON2 now has all voices
son2_end_votes = son2_obj.total_votes; son2_end_votes = son2_obj.total_votes;
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] > son2_start_votes[sidechain_type::bitcoin]); // 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
BOOST_CHECK(son2_end_votes[sidechain_type::hive] > son2_start_votes[sidechain_type::hive]);
BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] > son2_start_votes[sidechain_type::ethereum]);
son2_start_votes = son2_end_votes; son2_start_votes = son2_end_votes;
//! Check son1account voters //! Check son1account voters
@ -671,7 +605,6 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
BOOST_REQUIRE(voters_for_son1account); 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::bitcoin).voters.size(), 0);
BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::hive).voters.size(), 0); BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::hive).voters.size(), 0);
BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::ethereum).voters.size(), 0);
//! Check votes of nathan //! Check votes of nathan
nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
@ -680,8 +613,6 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
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::bitcoin).at(0).id.instance(), son2_obj.id.instance());
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 1); 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()); BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son2_obj.id.instance());
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).size(), 1);
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(0).id.instance(), son2_obj.id.instance());
// Try to reject incorrect SON // Try to reject incorrect SON
accepted.clear(); accepted.clear();
@ -691,22 +622,16 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
sidechain_type::bitcoin, 1, true), fc::exception); sidechain_type::bitcoin, 1, true), fc::exception);
BOOST_CHECK_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, BOOST_CHECK_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
sidechain_type::hive, 1, true), fc::exception); sidechain_type::hive, 1, true), fc::exception);
BOOST_CHECK_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
sidechain_type::ethereum, 1, true), fc::exception);
generate_block(); generate_block();
// Verify the votes // Verify the votes
son1_obj = con.wallet_api_ptr->get_son("son1account"); son1_obj = con.wallet_api_ptr->get_son("son1account");
son1_end_votes = son1_obj.total_votes; son1_end_votes = son1_obj.total_votes;
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]); 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]);
BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] == son1_start_votes[sidechain_type::ethereum]);
son1_start_votes = son1_end_votes; son1_start_votes = son1_end_votes;
son2_obj = con.wallet_api_ptr->get_son("son2account"); son2_obj = con.wallet_api_ptr->get_son("son2account");
son2_end_votes = son2_obj.total_votes; son2_end_votes = son2_obj.total_votes;
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] == son2_start_votes[sidechain_type::bitcoin]); 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]);
BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] == son2_start_votes[sidechain_type::ethereum]);
son2_start_votes = son2_end_votes; son2_start_votes = son2_end_votes;
//! Check votes of nathan //! Check votes of nathan
@ -716,8 +641,6 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
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::bitcoin).at(0).id.instance(), son2_obj.id.instance());
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 1); 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()); BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son2_obj.id.instance());
BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).size(), 1);
BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(0).id.instance(), son2_obj.id.instance());
// Reject SON2 // Reject SON2
accepted.clear(); accepted.clear();
@ -727,22 +650,16 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
sidechain_type::bitcoin, 0, true); sidechain_type::bitcoin, 0, true);
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
sidechain_type::hive, 0, true); sidechain_type::hive, 0, true);
update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
sidechain_type::ethereum, 0, true);
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
// Verify the votes // Verify the votes
son1_obj = con.wallet_api_ptr->get_son("son1account"); son1_obj = con.wallet_api_ptr->get_son("son1account");
son1_end_votes = son1_obj.total_votes; son1_end_votes = son1_obj.total_votes;
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]); 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]);
BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] == son1_start_votes[sidechain_type::ethereum]);
son1_start_votes = son1_end_votes; son1_start_votes = son1_end_votes;
son2_obj = con.wallet_api_ptr->get_son("son2account"); son2_obj = con.wallet_api_ptr->get_son("son2account");
son2_end_votes = son2_obj.total_votes; son2_end_votes = son2_obj.total_votes;
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] < son2_start_votes[sidechain_type::bitcoin]); 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]);
BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] < son2_start_votes[sidechain_type::ethereum]);
son2_start_votes = son2_end_votes; son2_start_votes = son2_end_votes;
//! Check son2account voters //! Check son2account voters
@ -750,7 +667,6 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
BOOST_REQUIRE(voters_for_son2account); 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::bitcoin).voters.size(), 0);
BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::hive).voters.size(), 0); BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::hive).voters.size(), 0);
BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::ethereum).voters.size(), 0);
//! Check votes of nathan //! Check votes of nathan
nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons;
@ -765,22 +681,16 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
sidechain_type::bitcoin, 1, true), fc::exception); sidechain_type::bitcoin, 1, true), fc::exception);
BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
sidechain_type::hive, 1, true), fc::exception); sidechain_type::hive, 1, true), fc::exception);
BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
sidechain_type::ethereum, 1, true), fc::exception);
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
// Verify the votes // Verify the votes
son1_obj = con.wallet_api_ptr->get_son("son1account"); son1_obj = con.wallet_api_ptr->get_son("son1account");
son1_end_votes = son1_obj.total_votes; son1_end_votes = son1_obj.total_votes;
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]); 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]);
BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] == son1_start_votes[sidechain_type::ethereum]);
son1_start_votes = son1_end_votes; son1_start_votes = son1_end_votes;
son2_obj = con.wallet_api_ptr->get_son("son2account"); son2_obj = con.wallet_api_ptr->get_son("son2account");
son2_end_votes = son2_obj.total_votes; son2_end_votes = son2_obj.total_votes;
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] == son2_start_votes[sidechain_type::bitcoin]); 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]);
BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] == son2_start_votes[sidechain_type::ethereum]);
son2_start_votes = son2_end_votes; son2_start_votes = son2_end_votes;
//! Check votes of nathan //! Check votes of nathan
@ -792,24 +702,16 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
rejected.clear(); rejected.clear();
BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
sidechain_type::bitcoin, 1, true), fc::exception); 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_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected,
sidechain_type::ethereum, 1, true), fc::exception);
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
// Verify the votes // Verify the votes
son1_obj = con.wallet_api_ptr->get_son("son1account"); son1_obj = con.wallet_api_ptr->get_son("son1account");
son1_end_votes = son1_obj.total_votes; son1_end_votes = son1_obj.total_votes;
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]); 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]);
BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]);
son1_start_votes = son1_end_votes; son1_start_votes = son1_end_votes;
son2_obj = con.wallet_api_ptr->get_son("son2account"); son2_obj = con.wallet_api_ptr->get_son("son2account");
son2_end_votes = son2_obj.total_votes; son2_end_votes = son2_obj.total_votes;
BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] == son2_start_votes[sidechain_type::bitcoin]); 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]);
BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] == son2_start_votes[sidechain_type::ethereum]);
son2_start_votes = son2_end_votes; son2_start_votes = son2_end_votes;
//! Check votes of nathan //! Check votes of nathan
@ -832,7 +734,6 @@ BOOST_AUTO_TEST_CASE( related_functions )
global_property_object gpo = con.wallet_api_ptr->get_global_properties(); global_property_object gpo = con.wallet_api_ptr->get_global_properties();
BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).size() == 0); BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).size() == 0);
BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == 0); BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == 0);
BOOST_CHECK(gpo.active_sons.at(sidechain_type::ethereum).size() == 0);
flat_map<sidechain_type, string> sidechain_public_keys; flat_map<sidechain_type, string> sidechain_public_keys;
@ -841,19 +742,16 @@ BOOST_AUTO_TEST_CASE( related_functions )
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1";
sidechain_public_keys[sidechain_type::hive] = "hive account 1"; sidechain_public_keys[sidechain_type::hive] = "hive account 1";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 1";
sth.create_son("son1account", "http://son1", sidechain_public_keys); sth.create_son("son1account", "http://son1", sidechain_public_keys);
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2";
sidechain_public_keys[sidechain_type::hive] = "hive account 2"; sidechain_public_keys[sidechain_type::hive] = "hive account 2";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 2";
sth.create_son("son2account", "http://son2", sidechain_public_keys); sth.create_son("son2account", "http://son2", sidechain_public_keys);
gpo = con.wallet_api_ptr->get_global_properties(); gpo = con.wallet_api_ptr->get_global_properties();
BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).size() == 2); BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).size() == 2);
BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == 2); BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == 2);
BOOST_CHECK(gpo.active_sons.at(sidechain_type::ethereum).size() == 2);
} catch( fc::exception& e ) { } catch( fc::exception& e ) {
BOOST_TEST_MESSAGE("SON cli wallet tests exception"); BOOST_TEST_MESSAGE("SON cli wallet tests exception");
@ -885,7 +783,6 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture )
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i);
sidechain_public_keys[sidechain_type::hive] = "hive account " + fc::to_pretty_string(i); sidechain_public_keys[sidechain_type::hive] = "hive account " + fc::to_pretty_string(i);
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address " + fc::to_pretty_string(i);
sth.create_son("sonaccount" + fc::to_pretty_string(i), sth.create_son("sonaccount" + fc::to_pretty_string(i),
"http://son" + fc::to_pretty_string(i), "http://son" + fc::to_pretty_string(i),
sidechain_public_keys, sidechain_public_keys,
@ -902,7 +799,6 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture )
std::string name = "sonaccount" + fc::to_pretty_string(i); std::string name = "sonaccount" + fc::to_pretty_string(i);
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::bitcoin, true, true);
vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::hive, true, true); vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::hive, true, true);
vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::ethereum, true, true);
} }
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
@ -912,17 +808,14 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture )
std::string name2 = "sonaccount" + fc::to_pretty_string(i + 1); std::string name2 = "sonaccount" + fc::to_pretty_string(i + 1);
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::bitcoin, true, true);
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true); vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true);
vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::ethereum, true, true);
} }
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
gpo = con.wallet_api_ptr->get_global_properties(); gpo = con.wallet_api_ptr->get_global_properties();
BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).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_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size());
BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::ethereum).size());
BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).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); BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == son_number);
BOOST_CHECK(gpo.active_sons.at(sidechain_type::ethereum).size() == son_number);
map<string, son_id_type> active_sons = con.wallet_api_ptr->list_active_sons(); map<string, son_id_type> active_sons = con.wallet_api_ptr->list_active_sons();
BOOST_CHECK(active_sons.size() == son_number); BOOST_CHECK(active_sons.size() == son_number);
@ -962,7 +855,6 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
sidechain_public_keys.clear(); sidechain_public_keys.clear();
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i);
sidechain_public_keys[sidechain_type::hive] = "hive account " + fc::to_pretty_string(i); sidechain_public_keys[sidechain_type::hive] = "hive account " + fc::to_pretty_string(i);
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address " + fc::to_pretty_string(i);
sth.create_son("sonaccount" + fc::to_pretty_string(i), sth.create_son("sonaccount" + fc::to_pretty_string(i),
"http://son" + fc::to_pretty_string(i), "http://son" + fc::to_pretty_string(i),
sidechain_public_keys, sidechain_public_keys,
@ -978,14 +870,12 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
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->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, sidechain_type::bitcoin, 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); con.wallet_api_ptr->vote_for_son("sonaccount" + fc::to_pretty_string(i), name, sidechain_type::hive, true, true);
con.wallet_api_ptr->vote_for_son("sonaccount" + fc::to_pretty_string(i), name, sidechain_type::ethereum, true, true);
} }
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
son_object son_obj = con.wallet_api_ptr->get_son(name); son_object son_obj = con.wallet_api_ptr->get_son(name);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == 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); BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::active);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::ethereum) == son_status::active);
// put SON in maintenance mode // put SON in maintenance mode
con.wallet_api_ptr->request_son_maintenance(name, true); con.wallet_api_ptr->request_son_maintenance(name, true);
@ -995,7 +885,6 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
son_obj = con.wallet_api_ptr->get_son(name); son_obj = con.wallet_api_ptr->get_son(name);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == 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); BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::request_maintenance);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::ethereum) == son_status::request_maintenance);
// restore SON activity // restore SON activity
con.wallet_api_ptr->cancel_request_son_maintenance(name, true); con.wallet_api_ptr->cancel_request_son_maintenance(name, true);
@ -1005,7 +894,6 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
son_obj = con.wallet_api_ptr->get_son(name); son_obj = con.wallet_api_ptr->get_son(name);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == 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); BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::active);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::ethereum) == son_status::active);
// put SON in maintenance mode // put SON in maintenance mode
con.wallet_api_ptr->request_son_maintenance(name, true); con.wallet_api_ptr->request_son_maintenance(name, true);
@ -1015,7 +903,6 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
son_obj = con.wallet_api_ptr->get_son(name); son_obj = con.wallet_api_ptr->get_son(name);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == 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); BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::request_maintenance);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::ethereum) == son_status::request_maintenance);
// process maintenance // process maintenance
BOOST_CHECK(generate_maintenance_block()); BOOST_CHECK(generate_maintenance_block());
@ -1024,7 +911,7 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
son_obj = con.wallet_api_ptr->get_son(name); son_obj = con.wallet_api_ptr->get_son(name);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == 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); BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::in_maintenance);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::ethereum) == son_status::in_maintenance);
} catch( fc::exception& e ) { } catch( fc::exception& e ) {
BOOST_TEST_MESSAGE("SON cli wallet tests exception"); BOOST_TEST_MESSAGE("SON cli wallet tests exception");

View file

@ -1,147 +0,0 @@
#include <boost/test/unit_test.hpp>
#include <fc/crypto/hex.hpp>
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
using namespace graphene::peerplays_sidechain::ethereum;
BOOST_AUTO_TEST_SUITE(ethereum_transaction_tests)
BOOST_AUTO_TEST_CASE(withdrawal_encoder_test) {
const withdrawal_encoder encoder;
const auto tx = encoder.encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.0");
BOOST_CHECK_EQUAL(tx, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000");
const auto tx1 = encoder.encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1");
BOOST_CHECK_EQUAL(tx1, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(update_owners_encoder_test) {
std::vector<std::pair<std::string, uint16_t>> owners_weights;
owners_weights.emplace_back("5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12", 1);
owners_weights.emplace_back("76ce31bd03f601c3fc13732def921c5bac282676", 1);
const update_owners_encoder encoder;
const auto tx = encoder.encode(owners_weights, "1.35.0");
BOOST_CHECK_EQUAL(tx, "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000");
owners_weights.emplace_back("09ee460834498a4ee361beb819470061b7381b49", 1);
const auto tx1 = encoder.encode(owners_weights, "1.36.1");
BOOST_CHECK_EQUAL(tx1, "0x23ab6adf0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(raw_transaction_serialization_test) {
raw_transaction raw_tr;
raw_tr.nonce = "0x0";
raw_tr.gas_price = "0x3b9aca07";
raw_tr.gas_limit = "0x7a1200";
raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348";
raw_tr.value = "";
raw_tr.data = "";
raw_tr.chain_id = "0x21";
const auto tx = raw_tr.serialize();
BOOST_CHECK_EQUAL(tx, "0xE480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C02903488080218080");
//! Change value
raw_tr.value = "0x1BC16D674EC80000";
const auto tx1 = raw_tr.serialize();
BOOST_CHECK_EQUAL(tx1, "0xEC80843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C0290348881BC16D674EC8000080218080");
//! Change data
raw_tr.data = "0x893d20e8";
const auto tx2 = raw_tr.serialize();
BOOST_CHECK_EQUAL(tx2, "0xF080843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C0290348881BC16D674EC8000084893D20E8218080");
}
BOOST_AUTO_TEST_CASE(raw_transaction_deserialization_test) {
const raw_transaction raw_tr{"E480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C02903488080218080"};
BOOST_CHECK_EQUAL(raw_tr.nonce, "0x0");
BOOST_CHECK_EQUAL(raw_tr.gas_price, "0x3b9aca07");
BOOST_CHECK_EQUAL(raw_tr.gas_limit, "0x7a1200");
BOOST_CHECK_EQUAL(raw_tr.to, "0x875a7e0efe5140c80c5c822f99c02281c0290348");
BOOST_CHECK_EQUAL(raw_tr.value, "0x0");
BOOST_CHECK_EQUAL(raw_tr.data, "");
BOOST_CHECK_EQUAL(raw_tr.chain_id, "0x21");
}
BOOST_AUTO_TEST_CASE(raw_transaction_hash_test) {
raw_transaction raw_tr;
raw_tr.nonce = "0x0";
raw_tr.gas_price = "0x3b9aca07";
raw_tr.gas_limit = "0x7a1200";
raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348";
raw_tr.value = "";
raw_tr.data = "";
raw_tr.chain_id = "0x21";
const auto tx = raw_tr.serialize();
BOOST_CHECK_EQUAL(tx, "0xE480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C02903488080218080");
const auto hash = raw_tr.hash();
const auto hash_str = fc::to_hex((char *)&hash[0], hash.size());
BOOST_CHECK_EQUAL(hash_str, "34934410cd305f4fa4e75a2c9294d625d6fbba729b5642ed2ca757ead50bb1fb");
}
BOOST_AUTO_TEST_CASE(sign_transaction_test) {
raw_transaction raw_tr;
raw_tr.nonce = "0x0";
raw_tr.gas_price = "0x3b9aca07";
raw_tr.gas_limit = "0x7a1200";
raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348";
raw_tr.value = "";
raw_tr.data = "";
raw_tr.chain_id = "0x21";
const auto sign_tr = raw_tr.sign("eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060");
BOOST_CHECK_EQUAL(sign_tr.r, "5f09de6ac850b2a9e94acd709c12d4e9adbabc6b72281ec0bbe13bca7e57c7ce");
BOOST_CHECK_EQUAL(sign_tr.v, "65");
BOOST_CHECK_EQUAL(sign_tr.s, "7ca5f26c5b3e25f14a32b18ac9a2a41b7c68efd3b04b118e1b1f4bf1c4e299b0");
}
BOOST_AUTO_TEST_CASE(sign_transaction_serialization_test) {
raw_transaction raw_tr;
raw_tr.nonce = "0x0";
raw_tr.gas_price = "0x3b9aca07";
raw_tr.gas_limit = "0x7a1200";
raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348";
raw_tr.value = "";
raw_tr.data = "";
raw_tr.chain_id = "0x21";
const auto sign_tr = raw_tr.sign("eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060");
const auto tx = sign_tr.serialize();
BOOST_CHECK_EQUAL(tx, "0xF86480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C0290348808065A05F09DE6AC850B2A9E94ACD709C12D4E9ADBABC6B72281EC0BBE13BCA7E57C7CEA07CA5F26C5B3E25F14A32B18AC9A2A41B7C68EFD3B04B118E1B1F4BF1C4E299B0");
}
BOOST_AUTO_TEST_CASE(sign_transaction_deserialization_test) {
const signed_transaction sign_tr{"0xF86480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C0290348808065A05F09DE6AC850B2A9E94ACD709C12D4E9ADBABC6B72281EC0BBE13BCA7E57C7CEA07CA5F26C5B3E25F14A32B18AC9A2A41B7C68EFD3B04B118E1B1F4BF1C4E299B0"};
BOOST_CHECK_EQUAL(sign_tr.nonce, "0x0");
BOOST_CHECK_EQUAL(sign_tr.gas_price, "0x3b9aca07");
BOOST_CHECK_EQUAL(sign_tr.gas_limit, "0x7a1200");
BOOST_CHECK_EQUAL(sign_tr.to, "0x875a7e0efe5140c80c5c822f99c02281c0290348");
BOOST_CHECK_EQUAL(sign_tr.value, "0x0");
BOOST_CHECK_EQUAL(sign_tr.data, "");
}
BOOST_AUTO_TEST_CASE(sign_transaction_recover_test) {
const std::string chain_id = "0x21";
raw_transaction raw_tr;
raw_tr.nonce = "0x0";
raw_tr.gas_price = "0x3b9aca07";
raw_tr.gas_limit = "0x7a1200";
raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348";
raw_tr.value = "";
raw_tr.data = "";
raw_tr.chain_id = chain_id;
const auto sign_tr = raw_tr.sign("eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060");
const auto from = sign_tr.recover(chain_id);
BOOST_CHECK_EQUAL(from, "0x5fbbb31be52608d2f52247e8400b7fcaa9e0bc12");
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -135,7 +135,6 @@ BOOST_AUTO_TEST_CASE( sidechain_address_update_test ) {
flat_map<sidechain_type, string> sidechain_public_keys; flat_map<sidechain_type, string> sidechain_public_keys;
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin address"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin address";
sidechain_public_keys[sidechain_type::hive] = "hive address"; sidechain_public_keys[sidechain_type::hive] = "hive address";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address";
son_create_operation op; son_create_operation op;
op.owner_account = bob_id; op.owner_account = bob_id;

View file

@ -87,8 +87,6 @@ BOOST_AUTO_TEST_CASE( create_son_test ) {
{ {
flat_map<sidechain_type, string> sidechain_public_keys; flat_map<sidechain_type, string> sidechain_public_keys;
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin address"; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin address";
sidechain_public_keys[sidechain_type::hive] = "hive account";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address";
son_create_operation op; son_create_operation op;
op.owner_account = alice_id; op.owner_account = alice_id;
@ -113,8 +111,6 @@ BOOST_AUTO_TEST_CASE( create_son_test ) {
BOOST_CHECK( obj->url == test_url ); BOOST_CHECK( obj->url == test_url );
BOOST_CHECK( obj->signing_key == alice_public_key ); BOOST_CHECK( obj->signing_key == alice_public_key );
BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::bitcoin) == "bitcoin address" ); BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::bitcoin) == "bitcoin address" );
BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::hive) == "hive account" );
BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::ethereum) == "ethereum address" );
BOOST_CHECK( obj->deposit.instance == deposit.instance.value ); BOOST_CHECK( obj->deposit.instance == deposit.instance.value );
BOOST_CHECK( obj->pay_vb.instance == payment.instance.value ); BOOST_CHECK( obj->pay_vb.instance == payment.instance.value );
} }
@ -128,9 +124,7 @@ BOOST_AUTO_TEST_CASE( update_son_test ) {
{ {
flat_map<sidechain_type, string> sidechain_public_keys; flat_map<sidechain_type, string> sidechain_public_keys;
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin address"; sidechain_public_keys[sidechain_type::bitcoin] = "new bitcoin address";
sidechain_public_keys[sidechain_type::hive] = "hive account";
sidechain_public_keys[sidechain_type::ethereum] = "ethereum address";
son_update_operation op; son_update_operation op;
op.son_id = son_id_type(0); op.son_id = son_id_type(0);
@ -149,9 +143,7 @@ BOOST_AUTO_TEST_CASE( update_son_test ) {
auto obj = idx.find( alice_id ); auto obj = idx.find( alice_id );
BOOST_REQUIRE( obj != idx.end() ); BOOST_REQUIRE( obj != idx.end() );
BOOST_CHECK( obj->url == new_url ); BOOST_CHECK( obj->url == new_url );
BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::bitcoin) == "bitcoin address" ); BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::bitcoin) == "new bitcoin address" );
BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::hive) == "hive account" );
BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::ethereum) == "ethereum address" );
} }
BOOST_AUTO_TEST_CASE( deregister_son_test ) { BOOST_AUTO_TEST_CASE( deregister_son_test ) {
@ -203,14 +195,12 @@ try {
{ {
_s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance; _s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance;
_s.statuses[sidechain_type::hive] = son_status::in_maintenance; _s.statuses[sidechain_type::hive] = son_status::in_maintenance;
_s.statuses[sidechain_type::ethereum] = son_status::in_maintenance;
}); });
db.modify( *son_stats_obj, [&]( son_statistics_object& _s) db.modify( *son_stats_obj, [&]( son_statistics_object& _s)
{ {
_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::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()); _s.last_down_timestamp[sidechain_type::hive] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time());
_s.last_down_timestamp[sidechain_type::ethereum] = 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)); auto deposit_vesting = db.get<vesting_balance_object>(vesting_balance_id_type(0));
@ -232,7 +222,6 @@ try {
BOOST_REQUIRE( idx.size() == 1 ); BOOST_REQUIRE( idx.size() == 1 );
BOOST_REQUIRE( obj->statuses.at(sidechain_type::bitcoin) == 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( obj->statuses.at(sidechain_type::hive) == son_status::deregistered );
BOOST_REQUIRE( obj->statuses.at(sidechain_type::ethereum) == son_status::deregistered );
BOOST_REQUIRE( son_stats_obj->deregistered_timestamp == now ); BOOST_REQUIRE( son_stats_obj->deregistered_timestamp == now );
deposit_vesting = db.get<vesting_balance_object>(vesting_balance_id_type(0)); deposit_vesting = db.get<vesting_balance_object>(vesting_balance_id_type(0));
@ -507,38 +496,30 @@ BOOST_AUTO_TEST_CASE( son_pay_test )
{ {
_s.txs_signed[sidechain_type::bitcoin] = 2; _s.txs_signed[sidechain_type::bitcoin] = 2;
_s.txs_signed[sidechain_type::hive] = 4; _s.txs_signed[sidechain_type::hive] = 4;
_s.txs_signed[sidechain_type::ethereum] = 6;
_s.total_txs_signed[sidechain_type::bitcoin] = 2; _s.total_txs_signed[sidechain_type::bitcoin] = 2;
_s.total_txs_signed[sidechain_type::hive] = 4; _s.total_txs_signed[sidechain_type::hive] = 4;
_s.total_txs_signed[sidechain_type::ethereum] = 6;
_s.sidechain_txs_reported[sidechain_type::bitcoin] = 4; _s.sidechain_txs_reported[sidechain_type::bitcoin] = 4;
_s.sidechain_txs_reported[sidechain_type::hive] = 8; _s.sidechain_txs_reported[sidechain_type::hive] = 8;
_s.sidechain_txs_reported[sidechain_type::ethereum] = 12;
_s.total_sidechain_txs_reported[sidechain_type::bitcoin] = 4; _s.total_sidechain_txs_reported[sidechain_type::bitcoin] = 4;
_s.total_sidechain_txs_reported[sidechain_type::hive] = 8; _s.total_sidechain_txs_reported[sidechain_type::hive] = 8;
_s.total_sidechain_txs_reported[sidechain_type::ethereum] = 12;
}); });
// Modify the transaction signed statistics of Bob's SON // Modify the transaction signed statistics of Bob's SON
db.modify( *son_stats_obj2, [&]( son_statistics_object& _s) db.modify( *son_stats_obj2, [&]( son_statistics_object& _s)
{ {
_s.txs_signed[sidechain_type::bitcoin] = 3; _s.txs_signed[sidechain_type::bitcoin] = 3;
_s.txs_signed[sidechain_type::hive] = 6; _s.txs_signed[sidechain_type::hive] = 6;
_s.txs_signed[sidechain_type::ethereum] = 9;
_s.total_txs_signed[sidechain_type::bitcoin] = 3; _s.total_txs_signed[sidechain_type::bitcoin] = 3;
_s.total_txs_signed[sidechain_type::hive] = 6; _s.total_txs_signed[sidechain_type::hive] = 6;
_s.total_txs_signed[sidechain_type::ethereum] = 9;
_s.sidechain_txs_reported[sidechain_type::bitcoin] = 6; _s.sidechain_txs_reported[sidechain_type::bitcoin] = 6;
_s.sidechain_txs_reported[sidechain_type::hive] = 12; _s.sidechain_txs_reported[sidechain_type::hive] = 12;
_s.sidechain_txs_reported[sidechain_type::ethereum] = 18;
_s.total_sidechain_txs_reported[sidechain_type::bitcoin] = 6; _s.total_sidechain_txs_reported[sidechain_type::bitcoin] = 6;
_s.total_sidechain_txs_reported[sidechain_type::hive] = 12; _s.total_sidechain_txs_reported[sidechain_type::hive] = 12;
_s.total_sidechain_txs_reported[sidechain_type::ethereum] = 18;
}); });
// Note the balances before the maintenance // Note the balances before the maintenance
@ -550,29 +531,21 @@ BOOST_AUTO_TEST_CASE( son_pay_test )
// Check if the signed transaction statistics are reset for both SONs // Check if the signed transaction statistics are reset for both SONs
BOOST_REQUIRE_EQUAL(son_stats_obj1->txs_signed.at(sidechain_type::bitcoin), 0); BOOST_REQUIRE_EQUAL(son_stats_obj1->txs_signed.at(sidechain_type::bitcoin), 0);
BOOST_REQUIRE_EQUAL(son_stats_obj1->txs_signed.at(sidechain_type::hive), 0); BOOST_REQUIRE_EQUAL(son_stats_obj1->txs_signed.at(sidechain_type::hive), 0);
BOOST_REQUIRE_EQUAL(son_stats_obj1->txs_signed.at(sidechain_type::ethereum), 0);
BOOST_REQUIRE_EQUAL(son_stats_obj2->txs_signed.at(sidechain_type::bitcoin), 0); BOOST_REQUIRE_EQUAL(son_stats_obj2->txs_signed.at(sidechain_type::bitcoin), 0);
BOOST_REQUIRE_EQUAL(son_stats_obj2->txs_signed.at(sidechain_type::hive), 0); BOOST_REQUIRE_EQUAL(son_stats_obj2->txs_signed.at(sidechain_type::hive), 0);
BOOST_REQUIRE_EQUAL(son_stats_obj2->txs_signed.at(sidechain_type::ethereum), 0);
BOOST_REQUIRE_EQUAL(son_stats_obj1->sidechain_txs_reported.at(sidechain_type::bitcoin), 0); BOOST_REQUIRE_EQUAL(son_stats_obj1->sidechain_txs_reported.at(sidechain_type::bitcoin), 0);
BOOST_REQUIRE_EQUAL(son_stats_obj1->sidechain_txs_reported.at(sidechain_type::hive), 0); BOOST_REQUIRE_EQUAL(son_stats_obj1->sidechain_txs_reported.at(sidechain_type::hive), 0);
BOOST_REQUIRE_EQUAL(son_stats_obj1->sidechain_txs_reported.at(sidechain_type::ethereum), 0);
BOOST_REQUIRE_EQUAL(son_stats_obj2->sidechain_txs_reported.at(sidechain_type::bitcoin), 0); BOOST_REQUIRE_EQUAL(son_stats_obj2->sidechain_txs_reported.at(sidechain_type::bitcoin), 0);
BOOST_REQUIRE_EQUAL(son_stats_obj2->sidechain_txs_reported.at(sidechain_type::hive), 0); BOOST_REQUIRE_EQUAL(son_stats_obj2->sidechain_txs_reported.at(sidechain_type::hive), 0);
BOOST_REQUIRE_EQUAL(son_stats_obj2->sidechain_txs_reported.at(sidechain_type::ethereum), 0);
BOOST_REQUIRE_EQUAL(son_stats_obj1->total_txs_signed.at(sidechain_type::bitcoin), 2); BOOST_REQUIRE_EQUAL(son_stats_obj1->total_txs_signed.at(sidechain_type::bitcoin), 2);
BOOST_REQUIRE_EQUAL(son_stats_obj1->total_txs_signed.at(sidechain_type::hive), 4); BOOST_REQUIRE_EQUAL(son_stats_obj1->total_txs_signed.at(sidechain_type::hive), 4);
BOOST_REQUIRE_EQUAL(son_stats_obj1->total_txs_signed.at(sidechain_type::ethereum), 6);
BOOST_REQUIRE_EQUAL(son_stats_obj2->total_txs_signed.at(sidechain_type::bitcoin), 3); BOOST_REQUIRE_EQUAL(son_stats_obj2->total_txs_signed.at(sidechain_type::bitcoin), 3);
BOOST_REQUIRE_EQUAL(son_stats_obj2->total_txs_signed.at(sidechain_type::hive), 6); BOOST_REQUIRE_EQUAL(son_stats_obj2->total_txs_signed.at(sidechain_type::hive), 6);
BOOST_REQUIRE_EQUAL(son_stats_obj2->total_txs_signed.at(sidechain_type::ethereum), 9);
BOOST_REQUIRE_EQUAL(son_stats_obj1->total_sidechain_txs_reported.at(sidechain_type::bitcoin), 4); BOOST_REQUIRE_EQUAL(son_stats_obj1->total_sidechain_txs_reported.at(sidechain_type::bitcoin), 4);
BOOST_REQUIRE_EQUAL(son_stats_obj1->total_sidechain_txs_reported.at(sidechain_type::hive), 8); BOOST_REQUIRE_EQUAL(son_stats_obj1->total_sidechain_txs_reported.at(sidechain_type::hive), 8);
BOOST_REQUIRE_EQUAL(son_stats_obj1->total_sidechain_txs_reported.at(sidechain_type::ethereum), 12);
BOOST_REQUIRE_EQUAL(son_stats_obj2->total_sidechain_txs_reported.at(sidechain_type::bitcoin), 6); BOOST_REQUIRE_EQUAL(son_stats_obj2->total_sidechain_txs_reported.at(sidechain_type::bitcoin), 6);
BOOST_REQUIRE_EQUAL(son_stats_obj2->total_sidechain_txs_reported.at(sidechain_type::hive), 12); BOOST_REQUIRE_EQUAL(son_stats_obj2->total_sidechain_txs_reported.at(sidechain_type::hive), 12);
BOOST_REQUIRE_EQUAL(son_stats_obj2->total_sidechain_txs_reported.at(sidechain_type::ethereum), 18);
// Check that Alice and Bob are paid for signing the transactions in the previous day/cycle // Check that Alice and Bob are paid for signing the transactions in the previous day/cycle
BOOST_REQUIRE_EQUAL(db.get_balance(obj1->son_account, asset_id_type()).amount.value, 80+obj1_balance); BOOST_REQUIRE_EQUAL(db.get_balance(obj1->son_account, asset_id_type()).amount.value, 80+obj1_balance);
BOOST_REQUIRE_EQUAL(db.get_balance(obj2->son_account, asset_id_type()).amount.value, 120+obj2_balance); BOOST_REQUIRE_EQUAL(db.get_balance(obj2->son_account, asset_id_type()).amount.value, 120+obj2_balance);
@ -636,14 +609,12 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
{ {
_s.statuses[sidechain_type::bitcoin] = son_status::active; _s.statuses[sidechain_type::bitcoin] = son_status::active;
_s.statuses[sidechain_type::hive] = son_status::active; _s.statuses[sidechain_type::hive] = son_status::active;
_s.statuses[sidechain_type::ethereum] = son_status::active;
}); });
db.modify( *son_stats_obj, [&]( son_statistics_object& _s) db.modify( *son_stats_obj, [&]( son_statistics_object& _s)
{ {
_s.last_down_timestamp[sidechain_type::bitcoin] = 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()); _s.last_down_timestamp[sidechain_type::hive] = fc::time_point_sec(db.head_block_time());
_s.last_down_timestamp[sidechain_type::ethereum] = fc::time_point_sec(db.head_block_time());
}); });
{ {
@ -662,7 +633,6 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
trx.clear(); trx.clear();
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == 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); BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::request_maintenance);
BOOST_CHECK( obj->statuses.at(sidechain_type::ethereum) == son_status::request_maintenance);
} }
{ {
@ -681,7 +651,6 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
trx.clear(); trx.clear();
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == 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); BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active);
BOOST_CHECK( obj->statuses.at(sidechain_type::ethereum) == son_status::active);
} }
// Modify SON's status to in_maintenance // Modify SON's status to in_maintenance
@ -689,13 +658,11 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
{ {
_s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance; _s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance;
_s.statuses[sidechain_type::hive] = son_status::in_maintenance; _s.statuses[sidechain_type::hive] = son_status::in_maintenance;
_s.statuses[sidechain_type::ethereum] = son_status::in_maintenance;
}); });
flat_map<sidechain_type, uint64_t> downtime; flat_map<sidechain_type, uint64_t> downtime;
downtime[sidechain_type::bitcoin] = 0; downtime[sidechain_type::bitcoin] = 0;
downtime[sidechain_type::hive] = 0; downtime[sidechain_type::hive] = 0;
downtime[sidechain_type::ethereum] = 0;
{ {
generate_block(); generate_block();
@ -713,16 +680,12 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
trx.clear(); trx.clear();
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::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()); 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());
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::ethereum), op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::ethereum).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::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(); downtime[sidechain_type::hive] += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::hive).sec_since_epoch();
downtime[sidechain_type::ethereum] += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::ethereum).sec_since_epoch();
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::inactive); BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::inactive);
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::inactive); BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::inactive);
BOOST_CHECK( obj->statuses.at(sidechain_type::ethereum) == 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::bitcoin) == op.ts);
BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::hive) == op.ts); BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::hive) == op.ts);
BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::ethereum) == op.ts);
} }
// Modify SON's status to in_maintenance // Modify SON's status to in_maintenance
@ -730,7 +693,6 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
{ {
_s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance; _s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance;
_s.statuses[sidechain_type::hive] = son_status::in_maintenance; _s.statuses[sidechain_type::hive] = son_status::in_maintenance;
_s.statuses[sidechain_type::ethereum] = son_status::in_maintenance;
}); });
// SON is selected as one of the active SONs // SON is selected as one of the active SONs
@ -740,7 +702,6 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
son_inf.son_id = son_id_type(0); son_inf.son_id = son_id_type(0);
_gpo.active_sons[sidechain_type::bitcoin].push_back(son_inf); _gpo.active_sons[sidechain_type::bitcoin].push_back(son_inf);
_gpo.active_sons[sidechain_type::hive].push_back(son_inf); _gpo.active_sons[sidechain_type::hive].push_back(son_inf);
_gpo.active_sons[sidechain_type::ethereum].push_back(son_inf);
}); });
{ {
@ -760,16 +721,12 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
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::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()); 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());
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::ethereum), downtime.at(sidechain_type::ethereum) + op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::ethereum).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::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(); downtime[sidechain_type::hive] += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::hive).sec_since_epoch();
downtime[sidechain_type::ethereum] += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::ethereum).sec_since_epoch();
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == 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); BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active);
BOOST_CHECK( obj->statuses.at(sidechain_type::ethereum) == 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::bitcoin) == op.ts);
BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::hive) == op.ts); BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::hive) == op.ts);
BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::ethereum) == op.ts);
} }
{ {
@ -788,13 +745,10 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
trx.clear(); trx.clear();
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::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_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::hive), downtime.at(sidechain_type::hive));
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::ethereum), downtime.at(sidechain_type::ethereum));
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == 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); BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active);
BOOST_CHECK( obj->statuses.at(sidechain_type::ethereum) == 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::bitcoin) == op.ts);
BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::hive) == op.ts); BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::hive) == op.ts);
BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::ethereum) == op.ts);
} }
} FC_LOG_AND_RETHROW() } FC_LOG_AND_RETHROW()
} }
@ -821,7 +775,6 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) {
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == 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); BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active);
BOOST_CHECK( obj->statuses.at(sidechain_type::ethereum) == son_status::active);
{ {
// Check that transaction fails if down_ts < last_active_timestamp // Check that transaction fails if down_ts < last_active_timestamp
@ -875,10 +828,8 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) {
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::in_maintenance); 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( obj->statuses.at(sidechain_type::hive) == son_status::in_maintenance);
BOOST_CHECK( obj->statuses.at(sidechain_type::ethereum) == 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::bitcoin) == op.down_ts);
BOOST_CHECK( son_stats_obj->last_down_timestamp.at(sidechain_type::hive) == op.down_ts); BOOST_CHECK( son_stats_obj->last_down_timestamp.at(sidechain_type::hive) == op.down_ts);
BOOST_CHECK( son_stats_obj->last_down_timestamp.at(sidechain_type::ethereum) == op.down_ts);
} }
{ {