From d89e5e1f2341888a24a03de0833a819904368db5 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Mon, 30 Jan 2023 19:27:27 +0200 Subject: [PATCH 1/8] #500 - fix son_wallet_update_operation --- libraries/chain/son_wallet_evaluator.cpp | 8 +++-- .../sidechain_net_handler_bitcoin.cpp | 30 ++++++++++++------- .../sidechain_net_handler_ethereum.cpp | 27 ++++++++++------- .../sidechain_net_handler_hive.cpp | 23 +++++++++----- 4 files changed, 58 insertions(+), 30 deletions(-) diff --git a/libraries/chain/son_wallet_evaluator.cpp b/libraries/chain/son_wallet_evaluator.cpp index 9b1ff1b7..1a6b6f94 100644 --- a/libraries/chain/son_wallet_evaluator.cpp +++ b/libraries/chain/son_wallet_evaluator.cpp @@ -64,7 +64,9 @@ void_result update_son_wallet_evaluator::do_evaluate(const son_wallet_update_ope FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." ); const auto& idx = db().get_index_type().indices().get(); - FC_ASSERT( idx.find(op.son_wallet_id) != idx.end() ); + const auto id = (op.son_wallet_id.instance.value - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(op.sidechain))) / active_sidechain_types.size(); + const son_wallet_id_type son_wallet_id{ id }; + FC_ASSERT( idx.find(son_wallet_id) != idx.end() ); //auto itr = idx.find(op.son_wallet_id); //FC_ASSERT( itr->addresses.find(op.sidechain) == itr->addresses.end() || // itr->addresses.at(op.sidechain).empty(), "Sidechain wallet address already set"); @@ -74,7 +76,9 @@ void_result update_son_wallet_evaluator::do_evaluate(const son_wallet_update_ope object_id_type update_son_wallet_evaluator::do_apply(const son_wallet_update_operation& op) { try { const auto& idx = db().get_index_type().indices().get(); - auto itr = idx.find(op.son_wallet_id); + const auto id = (op.son_wallet_id.instance.value - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(op.sidechain))) / active_sidechain_types.size(); + const son_wallet_id_type son_wallet_id{ id }; + auto itr = idx.find(son_wallet_id); if (itr != idx.end()) { if (itr->addresses.find(op.sidechain) == itr->addresses.end()) { diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 862f991a..eabcac8e 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -448,8 +448,10 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) bool transaction_ok = false; std::string new_pw_address = ""; son_wallet_id_type swo_id = op_obj_idx_0.get().son_wallet_id; + const auto id = (swo_id.instance.value - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain))) / active_sidechain_types.size(); + const son_wallet_id_type op_id{ id }; const auto &idx = database.get_index_type().indices().get(); - const auto swo = idx.find(swo_id); + const auto swo = idx.find(op_id); if (swo != idx.end()) { const auto &active_sons = gpo.active_sons.at(sidechain); @@ -485,18 +487,20 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) } if (po.proposed_transaction.operations.size() >= 2) { - object_id_type object_id = op_obj_idx_1.get().object_id; + const object_id_type object_id = op_obj_idx_1.get().object_id; + const auto id = (object_id.instance() - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain))) / active_sidechain_types.size(); + const object_id_type obj_id{ object_id.space(), object_id.type(), id }; std::string op_tx_str = op_obj_idx_1.get().transaction; const auto &st_idx = database.get_index_type().indices().get(); - const auto st = st_idx.find(object_id); + const auto st = st_idx.find(obj_id); if (st == st_idx.end()) { std::string tx_str = ""; - if (object_id.is()) { + if (obj_id.is()) { const auto &idx = database.get_index_type().indices().get(); - const auto swo = idx.find(object_id); + const auto swo = idx.find(obj_id); if (swo != idx.end()) { tx_str = create_primary_wallet_transaction(*swo, new_pw_address); } @@ -716,7 +720,10 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { if ((active_sw->addresses.find(sidechain) == active_sw->addresses.end()) || (active_sw->addresses.at(sidechain).empty())) { - if (proposal_exists(chain::operation::tag::value, active_sw->id)) { + const auto id = active_sw->id.instance() * active_sidechain_types.size() + std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain)); + const object_id_type op_id{ active_sw->id.space(), active_sw->id.type(), id }; + + if (proposal_exists(chain::operation::tag::value, op_id)) { return; } @@ -729,7 +736,7 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { boost::property_tree::ptree active_pw_pt; boost::property_tree::read_json(active_pw_ss, active_pw_pt); if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { - if (!plugin.can_son_participate(sidechain, chain::operation::tag::value, active_sw->id)) { + if (!plugin.can_son_participate(sidechain, chain::operation::tag::value, op_id)) { return; } @@ -743,7 +750,7 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { son_wallet_update_operation swu_op; swu_op.payer = gpo.parameters.son_account(); - swu_op.son_wallet_id = active_sw->id; + swu_op.son_wallet_id = op_id; swu_op.sidechain = sidechain; swu_op.address = res.str(); @@ -753,9 +760,12 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { std::string new_pw_address = active_pw_pt.get("result.address"); std::string tx_str = create_primary_wallet_transaction(*prev_sw, new_pw_address); if (!tx_str.empty()) { + const auto prev_id = prev_sw->id.instance() * active_sidechain_types.size() + std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain)); + const object_id_type prev_op_id{ prev_sw->id.space(), prev_sw->id.type(), prev_id }; + sidechain_transaction_create_operation stc_op; stc_op.payer = gpo.parameters.son_account(); - stc_op.object_id = prev_sw->id; + stc_op.object_id = prev_op_id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; stc_op.signers = prev_sw->sons.at(sidechain); @@ -769,7 +779,7 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { 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::value, active_sw->id); + plugin.log_son_proposal_retry(sidechain, chain::operation::tag::value, op_id); } catch (fc::exception &e) { elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); return; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 6fe4a91d..09bd8b49 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -218,8 +218,10 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) bool address_ok = false; bool transaction_ok = false; const son_wallet_id_type swo_id = op_obj_idx_0.get().son_wallet_id; + const auto id = (swo_id.instance.value - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain))) / active_sidechain_types.size(); + const son_wallet_id_type op_id{ id }; const auto &idx = database.get_index_type().indices().get(); - const auto swo = idx.find(swo_id); + const auto swo = idx.find(op_id); if (swo != idx.end()) { const auto active_sons = gpo.active_sons.at(sidechain); @@ -239,17 +241,19 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) if (po.proposed_transaction.operations.size() >= 2) { const object_id_type object_id = op_obj_idx_1.get().object_id; + const auto id = (object_id.instance() - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain))) / active_sidechain_types.size(); + const object_id_type obj_id{ object_id.space(), object_id.type(), id }; const std::string op_tx_str = op_obj_idx_1.get().transaction; const auto &st_idx = database.get_index_type().indices().get(); - const auto st = st_idx.find(object_id); + const auto st = st_idx.find(obj_id); if (st == st_idx.end()) { std::string tx_str = ""; - if (object_id.is()) { + if (obj_id.is()) { const auto &idx = database.get_index_type().indices().get(); - const auto swo = idx.find(object_id); + const auto swo = idx.find(obj_id); if (swo != idx.end()) { tx_str = create_primary_wallet_transaction(gpo.active_sons.at(sidechain), object_id.operator std::string()); } @@ -416,11 +420,14 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { if ((active_sw->addresses.find(sidechain) == active_sw->addresses.end()) || (active_sw->addresses.at(sidechain).empty())) { - if (proposal_exists(chain::operation::tag::value, active_sw->id)) { + const auto id = active_sw->id.instance() * active_sidechain_types.size() + std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain)); + const object_id_type op_id{ active_sw->id.space(), active_sw->id.type(), id }; + + if (proposal_exists(chain::operation::tag::value, op_id)) { return; } - if (!plugin.can_son_participate(sidechain, chain::operation::tag::value, active_sw->id)) { + if (!plugin.can_son_participate(sidechain, chain::operation::tag::value, op_id)) { return; } @@ -432,7 +439,7 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { son_wallet_update_operation swu_op; swu_op.payer = gpo.parameters.son_account(); - swu_op.son_wallet_id = active_sw->id; + swu_op.son_wallet_id = op_id; swu_op.sidechain = sidechain; swu_op.address = wallet_contract_address; proposal_op.proposed_ops.emplace_back(swu_op); @@ -452,11 +459,11 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { return signers; }(); - std::string tx_str = create_primary_wallet_transaction(gpo.active_sons.at(sidechain), active_sw->id.operator std::string()); + std::string tx_str = create_primary_wallet_transaction(gpo.active_sons.at(sidechain), op_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.object_id = op_id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; stc_op.signers = signers; @@ -469,7 +476,7 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { 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::value, active_sw->id); + plugin.log_son_proposal_retry(sidechain, chain::operation::tag::value, op_id); } catch (fc::exception &e) { elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); return; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp index 873fa08e..50d59121 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp @@ -209,8 +209,10 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { bool address_ok = false; bool transaction_ok = false; son_wallet_id_type swo_id = op_obj_idx_0.get().son_wallet_id; + const auto id = (swo_id.instance.value - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain))) / active_sidechain_types.size(); + const son_wallet_id_type op_id{ id }; const auto &idx = database.get_index_type().indices().get(); - const auto swo = idx.find(swo_id); + const auto swo = idx.find(op_id); if (swo != idx.end()) { auto active_sons = gpo.active_sons.at(sidechain); @@ -229,18 +231,20 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { } if (po.proposed_transaction.operations.size() >= 2) { - object_id_type object_id = op_obj_idx_1.get().object_id; + const object_id_type object_id = op_obj_idx_1.get().object_id; + const auto id = (object_id.instance() - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain))) / active_sidechain_types.size(); + const object_id_type obj_id{ object_id.space(), object_id.type(), id }; std::string op_tx_str = op_obj_idx_1.get().transaction; const auto &st_idx = database.get_index_type().indices().get(); - const auto st = st_idx.find(object_id); + const auto st = st_idx.find(obj_id); if (st == st_idx.end()) { std::string tx_str = ""; - if (object_id.is()) { + if (obj_id.is()) { const auto &idx = database.get_index_type().indices().get(); - const auto swo = idx.find(object_id); + const auto swo = idx.find(obj_id); if (swo != idx.end()) { std::stringstream ss_trx(boost::algorithm::unhex(op_tx_str)); @@ -486,7 +490,10 @@ void sidechain_net_handler_hive::process_primary_wallet() { if ((active_sw->addresses.find(sidechain) == active_sw->addresses.end()) || (active_sw->addresses.at(sidechain).empty())) { - if (proposal_exists(chain::operation::tag::value, active_sw->id)) { + const auto id = active_sw->id.instance() * active_sidechain_types.size() + std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain)); + const object_id_type op_id{ active_sw->id.space(), active_sw->id.type(), id }; + + if (proposal_exists(chain::operation::tag::value, op_id)) { return; } @@ -542,7 +549,7 @@ void sidechain_net_handler_hive::process_primary_wallet() { son_wallet_update_operation swu_op; swu_op.payer = gpo.parameters.son_account(); - swu_op.son_wallet_id = active_sw->id; + swu_op.son_wallet_id = op_id; swu_op.sidechain = sidechain; swu_op.address = wallet_account_name; @@ -565,7 +572,7 @@ void sidechain_net_handler_hive::process_primary_wallet() { sidechain_transaction_create_operation stc_op; stc_op.payer = gpo.parameters.son_account(); - stc_op.object_id = active_sw->id; + stc_op.object_id = op_id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; stc_op.signers = signers; From 0b64f0cfccb6f606799c802e9283aeed2561a9c8 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Tue, 31 Jan 2023 10:48:45 +0000 Subject: [PATCH 2/8] #473 erc20-support --- .../peerplays_sidechain/common/utils.cpp | 14 ++ .../peerplays_sidechain/ethereum/decoders.cpp | 45 ++++- .../peerplays_sidechain/ethereum/encoders.cpp | 25 ++- .../peerplays_sidechain/common/utils.hpp | 1 + .../graphene/peerplays_sidechain/defs.hpp | 6 + .../peerplays_sidechain/ethereum/decoders.hpp | 21 +++ .../peerplays_sidechain/ethereum/encoders.hpp | 10 +- .../sidechain_net_handler_ethereum.hpp | 6 +- .../peerplays_sidechain_plugin.cpp | 7 + .../sidechain_net_handler.cpp | 45 +++-- .../sidechain_net_handler_bitcoin.cpp | 1 + .../sidechain_net_handler_ethereum.cpp | 163 +++++++++++++----- .../sidechain_net_handler_hive.cpp | 1 + .../ethereum_transaction_tests.cpp | 67 +++++-- 14 files changed, 329 insertions(+), 83 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/common/utils.cpp b/libraries/plugins/peerplays_sidechain/common/utils.cpp index 5bd1dfd7..e135afa2 100644 --- a/libraries/plugins/peerplays_sidechain/common/utils.cpp +++ b/libraries/plugins/peerplays_sidechain/common/utils.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -47,4 +48,17 @@ std::string object_id_to_string(graphene::chain::object_id_type id) { return object_id; } +graphene::chain::object_id_type string_to_object_id(const std::string &id) { + std::vector strs; + boost::split(strs, id, boost::is_any_of(".")); + if (strs.size() != 3) { + elog("Wrong object_id format: ${id}", ("id", id)); + return graphene::chain::object_id_type{}; + } + + auto s = boost::lexical_cast(strs.at(0)); + auto t = boost::lexical_cast(strs.at(1)); + return graphene::chain::object_id_type{(uint8_t)s, (uint8_t)t, boost::lexical_cast(strs.at(2))}; +} + }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp index 02f334f5..009eec69 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp @@ -5,8 +5,51 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { -//! rlp_decoder +//! base_decoder +boost::multiprecision::uint256_t base_decoder::decode_uint256(const std::string &value) { + boost::multiprecision::uint256_t result = 0; + boost::multiprecision::uint256_t power(1); + uint8_t digit; + int pos = value.size() - 1; + while (pos >= 0) { + digit = 0; + if ('0' <= value[pos] && value[pos] <= '9') { + digit = value[pos] - '0'; + } else if ('a' <= value[pos] && value[pos] <= 'z') { + digit = value[pos] - 'a' + 10; + } + result += digit * power; + pos--; + power *= 16; + } + + return result; +} + +std::string base_decoder::decode_address(const std::string &value) { + return value.substr(24, 40); +} + +//! deposit_erc20_decoder +const std::string deposit_erc20_decoder::function_signature = "97feb926"; //! depositERC20(address,uint256) +fc::optional deposit_erc20_decoder::decode(const std::string &input) { + const auto input_without_0x = remove_0x(input); + if (function_signature != input_without_0x.substr(0, 8)) { + return fc::optional{}; + } + if (input_without_0x.size() != 136) { + return fc::optional{}; + } + + deposit_erc20_transaction erc_20; + erc_20.token = add_0x(base_decoder::decode_address(input_without_0x.substr(8, 64))); + erc_20.amount = base_decoder::decode_uint256(input_without_0x.substr(72, 64)); + + return erc_20; +} + +//! 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, diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index ce1e0083..872a5720 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -28,7 +28,7 @@ std::string base_encoder::encode_string(const std::string &value) { //! update_owners_encoder const std::string update_owners_encoder::function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string) std::string update_owners_encoder::encode(const std::vector> &owners_weights, const std::string &object_id) { - std::string data = "0x" + function_signature; + std::string data = add_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()); @@ -44,7 +44,7 @@ std::string update_owners_encoder::encode(const std::vector &transactions) const { - std::string data = "0x" + function_signature; + std::string data = add_0x(function_signature); data += base_encoder::encode_uint256(32); data += base_encoder::encode_uint256(transactions.size()); size_t offset = (transactions.size()) * 32; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/utils.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/utils.hpp index 066a36fe..5b0f3f7d 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/utils.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/utils.hpp @@ -8,5 +8,6 @@ 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); +graphene::chain::object_id_type string_to_object_id(const std::string &id); }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp index 70618236..b3063a99 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp @@ -57,10 +57,16 @@ struct info_for_vin { bool resend = false; }; +enum class sidechain_event_type { + deposit, + withdrawal +}; + struct sidechain_event_data { fc::time_point_sec timestamp; uint32_t block_num; sidechain_type sidechain; + sidechain_event_type type; std::string sidechain_uid; std::string sidechain_transaction_id; std::string sidechain_from; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/decoders.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/decoders.hpp index 9edb6ae3..68bd325b 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/decoders.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/decoders.hpp @@ -1,10 +1,31 @@ #pragma once +#include #include #include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { +class base_decoder { +public: + static boost::multiprecision::uint256_t decode_uint256(const std::string &value); + static std::string decode_address(const std::string &value); +}; + +struct deposit_erc20_transaction { + std::string token; + boost::multiprecision::uint256_t amount; +}; + +class deposit_erc20_decoder { +public: + static const std::string function_signature; + + static fc::optional decode(const std::string &input); +}; + class rlp_decoder { private: enum RLP_constants { diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp index ce02f7ed..43a2a862 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp @@ -8,9 +8,6 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { -const std::string update_owners_function_signature = "9d608673"; //! updateOwners((bytes,(uint8,bytes32,bytes32))[]) -const std::string withdrawal_function_signature = "daac6c81"; //! withdraw((bytes,(uint8,bytes32,bytes32))[]) - struct encoded_sign_transaction { std::string data; signature sign; @@ -37,6 +34,13 @@ public: static std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id); }; +class withdrawal_erc20_encoder { +public: + static const std::string function_signature; + + static std::string encode(const std::string &token, const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id); +}; + class signature_encoder { public: const std::string function_signature; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp index 8bc463ab..5e4b6a61 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp @@ -4,6 +4,7 @@ #include +#include #include #include @@ -52,11 +53,15 @@ public: bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); virtual optional estimate_withdrawal_transaction_fee() const override; +private: + using bimap_type = boost::bimap; + private: std::string rpc_url; std::string rpc_user; std::string rpc_password; std::string wallet_contract_address; + bimap_type erc20_addresses; ethereum_rpc_client *rpc_client; @@ -64,7 +69,6 @@ private: ethereum::network_id_type network_id; std::string create_primary_wallet_transaction(const std::vector &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); diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 541b8537..ae9967f7 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -192,6 +192,8 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("ethereum-node-rpc-user", bpo::value(), "Ethereum RPC user"); cli.add_options()("ethereum-node-rpc-password", bpo::value(), "Ethereum RPC password"); cli.add_options()("ethereum-wallet-contract-address", bpo::value(), "Ethereum wallet contract address"); + cli.add_options()("erc-20-address", bpo::value>()->composing()->multitoken(), + "Tuple of [ERC-20 symbol, ERC-20 address] (may specify multiple times)"); cli.add_options()("ethereum-private-key", bpo::value>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", "9bedac2bd8fe2a6f6528e066c67fc8ac0622e96828d40c0e820d83c5bd2b0589")), "Tuple of [Ethereum public key, Ethereum private key] (may specify multiple times)"); @@ -630,6 +632,11 @@ std::map> peerplays_sidechain_plugin_im } optional peerplays_sidechain_plugin_impl::estimate_withdrawal_transaction_fee(sidechain_type sidechain) { + if (net_handlers.count(sidechain) == 0) { + wlog("No net handler for sidechain: ${sidechain}", ("sidechain", sidechain)); + return optional(); + } + if (!net_handlers.at(sidechain)) { wlog("Net handler is null for sidechain: ${sidechain}", ("sidechain", sidechain)); return optional(); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp index 38345935..490cfe0b 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp @@ -190,22 +190,25 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ // (sed.sidechain_currency.compare("HIVE") != 0); #endif - 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::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("HIVE") == 0)) || - enable_peerplays_asset_deposits); + const bool deposit_condition = (sed.peerplays_to == gpo.parameters.son_account()) && + (sed.sidechain == sidechain) && + (sed.type == sidechain_event_type::deposit) && + (((sed.sidechain == sidechain_type::bitcoin) && (sed.sidechain_currency.compare("BTC") == 0)) || + ((sed.sidechain == sidechain_type::ethereum) && (!sed.sidechain_currency.empty())) || + ((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HBD") == 0)) || + ((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HIVE") == 0)) || + enable_peerplays_asset_deposits); - bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain == sidechain) && //! Fixme -> sidechain_type::peerplays - ((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.hive_asset()))); + const bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) && + (sed.sidechain == sidechain) && + (sed.type == sidechain_event_type::withdrawal) && + (((sed.sidechain == sidechain_type::bitcoin) && (sed.sidechain_currency == object_id_to_string(gpo.parameters.btc_asset()))) || + ((sed.sidechain == sidechain_type::ethereum) && (!sed.sidechain_currency.empty())) || + ((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset()))) || + ((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency == object_id_to_string(gpo.parameters.hive_asset())))); // Deposit request if (deposit_condition) { - for (son_id_type son_id : plugin.get_sons()) { if (plugin.is_active_son(sidechain, son_id)) { @@ -269,7 +272,17 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ withdraw_currency_price = database.get(database.get_global_properties().parameters.hive_asset()).options.core_exchange_rate; } if (withdraw_currency.empty()) { - return; + //! This is ERC-20 withdrawal + const auto asset_object_id = string_to_object_id(sed.sidechain_currency); + const auto &assets_by_id = database.get_index_type().indices().get(); + const auto asset_itr = assets_by_id.find(asset_object_id); + if (asset_itr == assets_by_id.end()) { + wlog("Could not find asset: ${asset_object_id}", ("asset_object_id", asset_object_id)); + return; + } + + withdraw_currency = asset_itr->symbol; + withdraw_currency_price = asset_itr->options.core_exchange_rate; } for (son_id_type son_id : plugin.get_sons()) { @@ -663,9 +676,10 @@ void sidechain_net_handler::on_applied_block(const signed_block &b) { continue; } - bool is_tracked_asset = + const bool is_tracked_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::ethereum) || ((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())); @@ -691,7 +705,8 @@ void sidechain_net_handler::on_applied_block(const signed_block &b) { sidechain_event_data sed; sed.timestamp = database.head_block_time(); sed.block_num = database.head_block_num(); - sed.sidechain = sidechain; //! Fixme -> sidechain_type::peerplays + sed.sidechain = sidechain; + sed.type = sidechain_event_type::withdrawal; sed.sidechain_uid = sidechain_uid; sed.sidechain_transaction_id = trx.id().str(); sed.sidechain_from = sidechain_from; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 862f991a..f1594c0f 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -1282,6 +1282,7 @@ void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data) sed.timestamp = database.head_block_time(); sed.block_num = database.head_block_num(); sed.sidechain = addr_itr->sidechain; + sed.type = sidechain_event_type::deposit; sed.sidechain_uid = sidechain_uid; sed.sidechain_transaction_id = v.out.hash_tx; sed.sidechain_from = v.address; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 6fe4a91d..80a11b16 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -147,6 +148,21 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha wallet_contract_address = options.at("ethereum-wallet-contract-address").as(); + if (options.count("erc-20-address")) { + const std::vector symbol_addresses = options["erc-20-address"].as>(); + for (const std::string &itr : symbol_addresses) { + auto itr_pair = graphene::app::dejsonify>(itr, 5); + ilog("ERC-20 symbol: ${symbol}, address: ${address}", ("symbol", itr_pair.first)("address", itr_pair.second)); + if (!itr_pair.first.length() || !itr_pair.second.length()) { + FC_THROW("Invalid symbol address pair."); + } + + auto address = itr_pair.second; + std::transform(address.begin(), address.end(), address.begin(), ::tolower); + erc20_addresses.insert(bimap_type::value_type{itr_pair.first, address}); + } + } + if (options.count("ethereum-private-key")) { const std::vector pub_priv_keys = options["ethereum-private-key"].as>(); for (const std::string &itr_key_pair : pub_priv_keys) { @@ -290,21 +306,41 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) const std::string sidechain_from = tx.get("result.from"); const std::string sidechain_to = tx.get("result.to"); - const std::string value_s = tx.get("result.value"); - boost::multiprecision::uint256_t amount(value_s); - amount = amount / 100000; - amount = amount / 100000; - const fc::safe sidechain_amount = amount; std::string cmp_sidechain_to = sidechain_to; std::transform(cmp_sidechain_to.begin(), cmp_sidechain_to.end(), cmp_sidechain_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); - process_ok = (swdo_sidechain_from == sidechain_from) && + //! Check whether it is ERC-20 token deposit + std::string symbol; + boost::multiprecision::uint256_t amount; + bool error_in_deposit = false; + const auto deposit_erc_20 = ethereum::deposit_erc20_decoder::decode(tx.get("result.input")); + if (deposit_erc_20.valid()) { + std::string cmp_token = deposit_erc_20->token; + std::transform(cmp_token.begin(), cmp_token.end(), cmp_token.begin(), ::tolower); + + const auto it = erc20_addresses.right.find(cmp_token); + if (it == erc20_addresses.right.end()) { + wlog("No erc-20 token with address: ${address}", ("address", cmp_token)); + error_in_deposit = true; + } + symbol = it->second; + amount = deposit_erc_20->amount; + } else { + symbol = "ETH"; + const std::string value_s = tx.get("result.value"); + amount = boost::multiprecision::uint256_t{value_s}; + amount = amount / 100000; + amount = amount / 100000; + } + + process_ok = (!error_in_deposit) && + (swdo_sidechain_from == sidechain_from) && (cmp_sidechain_to == cmp_wallet_contract_address) && - (swdo_sidechain_currency == "ETH") && - (swdo_sidechain_amount == sidechain_amount.value); + (swdo_sidechain_currency == symbol) && + (swdo_sidechain_amount == fc::safe{amount}.value); } } } @@ -427,7 +463,7 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { 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; + const 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; @@ -489,12 +525,19 @@ bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_ob const chain::global_property_object &gpo = database.get_global_properties(); - price asset_price = database.get(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()); + const auto &assets_by_symbol = database.get_index_type().indices().get(); + const auto asset_itr = assets_by_symbol.find(swdo.sidechain_currency); + if (asset_itr == assets_by_symbol.end()) { + wlog("Could not find asset: ${symbol}", ("symbol", swdo.sidechain_currency)); + return false; + } + + const price asset_price = asset_itr->options.core_exchange_rate; + const asset asset_to_issue = asset(swdo.peerplays_asset.amount * asset_price.quote.amount / asset_price.base.amount, asset_itr->get_id()); 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; + const 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; @@ -537,7 +580,7 @@ bool sidechain_net_handler_ethereum::process_withdrawal(const son_wallet_withdra 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; + const 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; @@ -683,7 +726,13 @@ bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechai if (sto.object_id.is()) { auto swwo = database.get(sto.object_id); - settle_amount = asset(swwo.withdraw_amount, database.get_global_properties().parameters.eth_asset()); + const auto &assets_by_symbol = database.get_index_type().indices().get(); + const auto asset_itr = assets_by_symbol.find(swwo.withdraw_currency); + if (asset_itr == assets_by_symbol.end()) { + wlog("Could not find asset: ${symbol}", ("symbol", swwo.withdraw_currency)); + return false; + } + settle_amount = asset(swwo.withdraw_amount, asset_itr->get_id()); } return true; @@ -712,13 +761,6 @@ optional sidechain_net_handler_ethereum::estimate_withdrawal_transaction_ return optional{}; } - const auto &assets_by_symbol = database.get_index_type().indices().get(); - auto asset_itr = assets_by_symbol.find("ETH"); - if (asset_itr == assets_by_symbol.end()) { - wlog("Could not find asset matching ETH"); - return optional{}; - } - const auto &public_key = son->sidechain_public_keys.at(sidechain); const auto data = ethereum::withdrawal_encoder::encode(public_key, 1 * 10000000000, son_wallet_withdraw_id_type{0}.operator object_id_type().operator std::string()); const std::string params = "[{\"from\":\"" + ethereum::add_0x(public_key) + "\", \"to\":\"" + wallet_contract_address + "\", \"data\":\"" + data + "\"}]"; @@ -726,7 +768,9 @@ optional sidechain_net_handler_ethereum::estimate_withdrawal_transaction_ const auto estimate_gas = ethereum::from_hex(rpc_client->get_estimate_gas(params)); const auto gas_price = ethereum::from_hex(rpc_client->get_gas_price()); const auto eth_gas_fee = double(estimate_gas * gas_price) / double{1000000000000000000}; - return asset_itr->amount_from_string(std::to_string(eth_gas_fee)); + + const auto asset = database.get(database.get_global_properties().parameters.eth_asset()); + return asset.amount_from_string(std::to_string(eth_gas_fee)); } std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const std::vector &son_pubkeys, const std::string &object_id) { @@ -739,12 +783,19 @@ std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(co return ethereum::update_owners_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) { - return ethereum::withdrawal_encoder::encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string()); + if (swwo.withdraw_currency == "ETH") { + return ethereum::withdrawal_encoder::encode(ethereum::remove_0x(swwo.withdraw_address), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string()); + } else { + const auto it = erc20_addresses.left.find(swwo.withdraw_currency); + if (it == erc20_addresses.left.end()) { + elog("No erc-20 token: ${symbol}", ("symbol", swwo.withdraw_currency)); + return ""; + } + return ethereum::withdrawal_erc20_encoder::encode(ethereum::remove_0x(it->second), ethereum::remove_0x(swwo.withdraw_address), swwo.withdraw_amount.value, swwo.id.operator std::string()); + } + + return ""; } std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) { @@ -761,10 +812,10 @@ std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_tra } void sidechain_net_handler_ethereum::schedule_ethereum_listener() { - fc::time_point now = fc::time_point::now(); - int64_t time_to_next = 5000; + const fc::time_point now = fc::time_point::now(); + const int64_t time_to_next = 5000; - fc::time_point next_wakeup(now + fc::milliseconds(time_to_next)); + const fc::time_point next_wakeup(now + fc::milliseconds(time_to_next)); _listener_task = fc::schedule([this] { ethereum_listener_loop(); @@ -776,10 +827,9 @@ void sidechain_net_handler_ethereum::ethereum_listener_loop() { schedule_ethereum_listener(); const auto reply = rpc_client->eth_blockNumber(); - //std::string reply = rpc_client->eth_get_logs(wallet_contract_address); if (!reply.empty()) { - uint64_t head_block_number = ethereum::from_hex(reply); + const uint64_t head_block_number = ethereum::from_hex(reply); if (head_block_number != last_block_received) { //! Check that current block number is greater than last one @@ -814,11 +864,11 @@ void sidechain_net_handler_ethereum::handle_event(const std::string &block_numbe size_t tx_idx = -1; for (const auto &tx_child : block_json.get_child("result.transactions")) { - boost::property_tree::ptree tx = tx_child.second; + const boost::property_tree::ptree tx = tx_child.second; tx_idx = tx_idx + 1; - std::string from = tx.get("from"); - std::string to = tx.get("to"); + const std::string from = tx.get("from"); + const std::string to = tx.get("to"); std::string cmp_to = to; std::transform(cmp_to.begin(), cmp_to.end(), cmp_to.begin(), ::toupper); @@ -827,10 +877,35 @@ void sidechain_net_handler_ethereum::handle_event(const std::string &block_numbe if (cmp_to == cmp_wallet_contract_address) { - std::string value_s = tx.get("value"); - boost::multiprecision::uint256_t amount(value_s); - amount = amount / 100000; - amount = amount / 100000; + //! Check whether it is ERC-20 token deposit + std::string symbol; + boost::multiprecision::uint256_t amount; + const auto deposit_erc_20 = ethereum::deposit_erc20_decoder::decode(tx.get("input")); + if (deposit_erc_20.valid()) { + std::string cmp_token = deposit_erc_20->token; + std::transform(cmp_token.begin(), cmp_token.end(), cmp_token.begin(), ::tolower); + + const auto it = erc20_addresses.right.find(cmp_token); + if (it == erc20_addresses.right.end()) { + wlog("No erc-20 token with address: ${address}", ("address", cmp_token)); + continue; + } + symbol = it->second; + amount = deposit_erc_20->amount; + } else { + symbol = "ETH"; + const std::string value_s = tx.get("value"); + amount = boost::multiprecision::uint256_t{value_s}; + amount = amount / 100000; + amount = amount / 100000; + } + + const auto &assets_by_symbol = database.get_index_type().indices().get(); + const auto asset_itr = assets_by_symbol.find(symbol); + if (asset_itr == assets_by_symbol.end()) { + wlog("Could not find asset: ${symbol}", ("symbol", symbol)); + continue; + } const auto &sidechain_addresses_idx = database.get_index_type().indices().get(); const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, from, time_point_sec::maximum())); @@ -841,22 +916,22 @@ void sidechain_net_handler_ethereum::handle_event(const std::string &block_numbe std::stringstream ss; ss << "ethereum" << "-" << tx.get("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.type = sidechain_event_type::deposit; + sed.sidechain_uid = ss.str(); sed.sidechain_transaction_id = tx.get("hash"); sed.sidechain_from = from; sed.sidechain_to = to; - sed.sidechain_currency = "ETH"; + sed.sidechain_currency = symbol; 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(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); + const price price = asset_itr->options.core_exchange_rate; + sed.peerplays_asset = asset(sed.sidechain_amount * price.base.amount / price.quote.amount); add_to_son_listener_log("TRX : " + sed.sidechain_transaction_id); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp index 873fa08e..c3897f74 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp @@ -950,6 +950,7 @@ void sidechain_net_handler_hive::handle_event(const std::string &event_data) { sed.timestamp = database.head_block_time(); sed.block_num = database.head_block_num(); sed.sidechain = sidechain; + sed.type = sidechain_event_type::deposit; sed.sidechain_uid = sidechain_uid; sed.sidechain_transaction_id = transaction_id; sed.sidechain_from = from; diff --git a/tests/peerplays_sidechain/ethereum_transaction_tests.cpp b/tests/peerplays_sidechain/ethereum_transaction_tests.cpp index 47cc090c..b3f094c8 100644 --- a/tests/peerplays_sidechain/ethereum_transaction_tests.cpp +++ b/tests/peerplays_sidechain/ethereum_transaction_tests.cpp @@ -2,6 +2,7 @@ #include #include +#include #include using namespace graphene::peerplays_sidechain::ethereum; @@ -9,22 +10,43 @@ using namespace graphene::peerplays_sidechain::ethereum; BOOST_AUTO_TEST_SUITE(ethereum_transaction_tests) BOOST_AUTO_TEST_CASE(withdrawal_encoder_test) { - const auto tx = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.0"); - BOOST_CHECK_EQUAL(tx, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000"); + const auto tx = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.39.0"); + BOOST_CHECK_EQUAL(tx, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33392E300000000000000000000000000000000000000000000000000000"); - const auto tx1 = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1"); - BOOST_CHECK_EQUAL(tx1, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); + const auto tx1 = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.39.1"); + BOOST_CHECK_EQUAL(tx1, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33392E310000000000000000000000000000000000000000000000000000"); } BOOST_AUTO_TEST_CASE(withdrawal_signature_encoder_test) { - const signature_encoder encoder{withdrawal_function_signature}; - encoded_sign_transaction transaction; - transaction.data = "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000"; + transaction.data = "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33392E300000000000000000000000000000000000000000000000000000"; transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" ); + const auto function_signature = signature_encoder::get_function_signature_from_transaction(transaction.data); + BOOST_REQUIRE_EQUAL(function_signature.empty(), false); + const signature_encoder encoder{function_signature}; const auto tx = encoder.encode({transaction}); - BOOST_CHECK_EQUAL(tx, "0xdaac6c8100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000065c4622d2ff2b2d89c5c6f8225ab0f979bc69d4fcd4fd47db757b66fb8a39e2bc5522be5d101aa11e66da78db973f136b323be10bd107ff0b648f06b4c71ef2a4f00000000000000000000000000000000000000000000000000000000000000a4e088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(tx, "0xdaac6c810000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006689c3a93d7059430d19ff952900dfada310c0dcced9ed046c335f886091c7e50c1a01016a488777b41a1815ca01a7d809ed47c36dcb0d5f86a43b079ce0d04afe00000000000000000000000000000000000000000000000000000000000000a4e088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33392E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); +} + +BOOST_AUTO_TEST_CASE(withdrawal_erc20_encoder_test) { + const auto tx = withdrawal_erc20_encoder::encode("cc806da9df9d634b5dac0aa36dca1e7780e42C60", "5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10, "1.39.0"); + BOOST_CHECK_EQUAL(tx, "0x483c0467000000000000000000000000cc806da9df9d634b5dac0aa36dca1e7780e42C600000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc12000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000006312E33392E300000000000000000000000000000000000000000000000000000"); + + const auto tx1 = withdrawal_erc20_encoder::encode("cc806da9df9d634b5dac0aa36dca1e7780e42C60", "5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10, "1.39.1"); + BOOST_CHECK_EQUAL(tx1, "0x483c0467000000000000000000000000cc806da9df9d634b5dac0aa36dca1e7780e42C600000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc12000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000006312E33392E310000000000000000000000000000000000000000000000000000"); +} + +BOOST_AUTO_TEST_CASE(withdrawal_erc20_signature_encoder_test) { + encoded_sign_transaction transaction; + transaction.data = "0x483c0467000000000000000000000000cc806da9df9d634b5dac0aa36dca1e7780e42C600000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc12000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000006312E33392E300000000000000000000000000000000000000000000000000000"; + transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" ); + + const auto function_signature = signature_encoder::get_function_signature_from_transaction(transaction.data); + BOOST_REQUIRE_EQUAL(function_signature.empty(), false); + const signature_encoder encoder{function_signature}; + const auto tx = encoder.encode({transaction}); + BOOST_CHECK_EQUAL(tx, "0xd2bf286600000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000066f51f7732435016936f0e21aa3c290023ea96ddbc369a957aca28a865cb5004a46675855fccd4bd5a283e1ff61aa60ca9b8b63664e770689e5cfc1a0c6bbdc79a00000000000000000000000000000000000000000000000000000000000000c4483c0467000000000000000000000000cc806da9df9d634b5dac0aa36dca1e7780e42C600000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc12000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000006312E33392E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); } BOOST_AUTO_TEST_CASE(update_owners_encoder_test) { @@ -32,23 +54,36 @@ BOOST_AUTO_TEST_CASE(update_owners_encoder_test) { owners_weights.emplace_back("5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12", 1); owners_weights.emplace_back("76ce31bd03f601c3fc13732def921c5bac282676", 1); - const auto tx = update_owners_encoder::encode(owners_weights, "1.35.0"); - BOOST_CHECK_EQUAL(tx, "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"); + const auto tx = update_owners_encoder::encode(owners_weights, "1.39.0"); + BOOST_CHECK_EQUAL(tx, "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33392E300000000000000000000000000000000000000000000000000000"); owners_weights.emplace_back("09ee460834498a4ee361beb819470061b7381b49", 1); - const auto tx1 = update_owners_encoder::encode(owners_weights, "1.36.1"); - BOOST_CHECK_EQUAL(tx1, "0x23ab6adf0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); + const auto tx1 = update_owners_encoder::encode(owners_weights, "1.39.1"); + BOOST_CHECK_EQUAL(tx1, "0x23ab6adf0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33392E310000000000000000000000000000000000000000000000000000"); } BOOST_AUTO_TEST_CASE(update_owners_signature_encoder_test) { - const signature_encoder encoder{update_owners_function_signature}; - encoded_sign_transaction transaction; - transaction.data = "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"; + transaction.data = "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33392E300000000000000000000000000000000000000000000000000000"; transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" ); + const auto function_signature = signature_encoder::get_function_signature_from_transaction(transaction.data); + BOOST_REQUIRE_EQUAL(function_signature.empty(), false); + const signature_encoder encoder{function_signature}; const auto tx = encoder.encode({transaction}); - BOOST_CHECK_EQUAL(tx, "0x9d6086730000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006698877eafa525c1a55f6b5e0a7187dfae484c97d9f77c4421a00276a9408a3e713d24402b44c05a883142fcffa84e1a802be37c17bb360f6f4810eb0415c8bbfd000000000000000000000000000000000000000000000000000000000000012423ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(tx, "0x9d608673000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000667121da3c6ab5054b1a77cac477f24e7ce7bfcb5e3a857cfcaf48e67fc8f003ac38dfa8821525383608a68c9f215f9a2a232e192ae80079cd2f31b0e01caa6e1d000000000000000000000000000000000000000000000000000000000000012423ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33392E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); +} + +BOOST_AUTO_TEST_CASE(deposit_erc20_decoder_test) { + const auto erc_20_1 = deposit_erc20_decoder::decode("0x97feb926000000000000000000000000cc806da9df9d634b5dac0aa36dca1e7780e42c600000000000000000000000000000000000000000000000000000000000000064"); + BOOST_REQUIRE_EQUAL(erc_20_1.valid(), true); + BOOST_CHECK_EQUAL(erc_20_1->token, "0xcc806da9df9d634b5dac0aa36dca1e7780e42c60"); + BOOST_CHECK_EQUAL(erc_20_1->amount, 100); + + const auto erc_20_2 = deposit_erc20_decoder::decode("0x97feb926000000000000000000000000cc806da9df9d634b5dac0aa36dca1e7780e42c600000000000000000000000000000000000000000000000006400000000000000"); + BOOST_REQUIRE_EQUAL(erc_20_2.valid(), true); + BOOST_CHECK_EQUAL(erc_20_2->token, "0xcc806da9df9d634b5dac0aa36dca1e7780e42c60"); + BOOST_CHECK_EQUAL(erc_20_2->amount, 7205759403792793600); } BOOST_AUTO_TEST_CASE(raw_transaction_serialization_test) { From da3a858aa660b7bd95d308fcf104c6cbd5d77cd7 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Wed, 1 Feb 2023 17:13:02 +0000 Subject: [PATCH 3/8] Fix replay blockchain --- libraries/app/database_api.cpp | 20 +- .../app/include/graphene/app/database_api.hpp | 4 +- libraries/chain/account_evaluator.cpp | 16 +- libraries/chain/db_block.cpp | 2 +- libraries/chain/db_getter.cpp | 2 +- libraries/chain/db_init.cpp | 2 +- libraries/chain/db_maint.cpp | 197 +++++++++++------- libraries/chain/db_management.cpp | 1 - libraries/chain/db_witness_schedule.cpp | 9 +- libraries/chain/hardfork.d/SON3.hf | 7 - .../chain/hardfork.d/SON_FOR_ETHEREUM.hf | 4 +- .../chain/include/graphene/chain/database.hpp | 10 +- .../graphene/chain/global_property_object.hpp | 16 +- .../graphene/chain/protocol/account.hpp | 2 +- .../chain/protocol/sidechain_transaction.hpp | 2 +- .../graphene/chain/protocol/son_wallet.hpp | 49 +++-- .../include/graphene/chain/sidechain_defs.hpp | 22 +- .../chain/sidechain_transaction_object.hpp | 4 +- .../chain/include/graphene/chain/son_info.hpp | 30 +-- .../include/graphene/chain/son_object.hpp | 38 ++-- .../graphene/chain/son_sidechain_info.hpp | 31 +++ .../graphene/chain/son_wallet_object.hpp | 4 +- libraries/chain/protocol/account.cpp | 34 +-- .../chain/sidechain_transaction_evaluator.cpp | 20 +- libraries/chain/son_evaluator.cpp | 39 ++-- libraries/chain/son_object.cpp | 28 ++- libraries/chain/son_wallet_evaluator.cpp | 44 +++- .../chain/son_wallet_withdraw_evaluator.cpp | 33 ++- .../sidechain_net_handler_bitcoin.hpp | 2 +- .../sidechain_net_handler_ethereum.hpp | 3 +- .../peerplays_sidechain_plugin.cpp | 18 +- .../sidechain_net_handler_bitcoin.cpp | 35 +++- .../sidechain_net_handler_ethereum.cpp | 26 ++- .../sidechain_net_handler_hive.cpp | 27 ++- .../sidechain_net_handler_peerplays.cpp | 9 +- .../wallet/include/graphene/wallet/wallet.hpp | 4 +- libraries/wallet/wallet.cpp | 20 +- tests/cli/son.cpp | 39 ++-- tests/tests/block_tests.cpp | 2 +- tests/tests/son_operations_tests.cpp | 135 ++++++------ tests/tests/son_wallet_tests.cpp | 8 +- 41 files changed, 629 insertions(+), 369 deletions(-) delete mode 100644 libraries/chain/hardfork.d/SON3.hf create mode 100644 libraries/chain/include/graphene/chain/son_sidechain_info.hpp diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index ef48a88d..c4e69607 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -196,8 +196,8 @@ public: fc::optional get_son_by_account(const std::string account_id_or_name) const; map lookup_son_accounts(const string &lower_bound_name, uint32_t limit) const; uint64_t get_son_count() const; - flat_map> get_active_sons(); - vector get_active_sons_by_sidechain(sidechain_type sidechain); + flat_map> get_active_sons(); + vector get_active_sons_by_sidechain(sidechain_type sidechain); map> get_son_network_status(); map get_son_network_status_by_sidechain(sidechain_type sidechain); @@ -1877,22 +1877,22 @@ uint64_t database_api_impl::get_son_count() const { return _db.get_index_type().indices().size(); } -flat_map> database_api::get_active_sons() { +flat_map> database_api::get_active_sons() { return my->get_active_sons(); } -flat_map> database_api_impl::get_active_sons() { +flat_map> database_api_impl::get_active_sons() { return get_global_properties().active_sons; } -vector database_api::get_active_sons_by_sidechain(sidechain_type sidechain) { +vector database_api::get_active_sons_by_sidechain(sidechain_type sidechain) { return my->get_active_sons_by_sidechain(sidechain); } -vector database_api_impl::get_active_sons_by_sidechain(sidechain_type sidechain) { +vector database_api_impl::get_active_sons_by_sidechain(sidechain_type sidechain) { const global_property_object &gpo = get_global_properties(); - vector result; + vector result; if (gpo.active_sons.find(sidechain) != gpo.active_sons.end()) { result = gpo.active_sons.at(sidechain); @@ -1908,7 +1908,7 @@ map> database_api::get_son_network_stat map> database_api_impl::get_son_network_status() { map> result; - for (auto active_sidechain_type : active_sidechain_types) { + for (auto active_sidechain_type : active_sidechain_types(_db.head_block_time())) { result[active_sidechain_type] = get_son_network_status_by_sidechain(active_sidechain_type); } @@ -2340,7 +2340,9 @@ votes_info database_api_impl::get_votes(const string &account_name_or_id) const votes_for_sons[sidechain].reserve(sidechain_ids.size()); for (const auto &son : sidechain_ids) { const auto &son_obj = son.as(6); - votes_for_sons[sidechain].emplace_back(votes_info_object{son_obj.get_sidechain_vote_id(sidechain), son_obj.id}); + if(son_obj.get_sidechain_vote_id(sidechain).valid()) { + votes_for_sons[sidechain].emplace_back(votes_info_object{*son_obj.get_sidechain_vote_id(sidechain), son_obj.id}); + } } } result.votes_for_sons = std::move(votes_for_sons); diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 948b6d55..ddd909f1 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -695,14 +695,14 @@ public: * @brief Get list of active sons * @return List of active SONs */ - flat_map> get_active_sons(); + flat_map> get_active_sons(); /** * @brief Get list of active sons * @param sidechain Sidechain type [bitcoin|ethereum|hive] * @return List of active SONs */ - vector get_active_sons_by_sidechain(sidechain_type sidechain); + vector get_active_sons_by_sidechain(sidechain_type sidechain); /** * @brief Get SON network status diff --git a/libraries/chain/account_evaluator.cpp b/libraries/chain/account_evaluator.cpp index 5f1a4416..4ecb3307 100644 --- a/libraries/chain/account_evaluator.cpp +++ b/libraries/chain/account_evaluator.cpp @@ -69,11 +69,13 @@ void verify_account_votes( const database& db, const account_options& options ) FC_ASSERT( options.num_committee <= chain_params.maximum_committee_count, "Voted for more committee members than currently allowed (${c})", ("c", chain_params.maximum_committee_count) ); FC_ASSERT( chain_params.extensions.value.maximum_son_count.valid() , "Invalid maximum son count" ); - FC_ASSERT( options.extensions.value.num_son.valid() , "Invalid son number" ); - for(const auto& num_sons : *options.extensions.value.num_son) + if ( options.extensions.value.num_son.valid() ) { - FC_ASSERT( num_sons.second <= *chain_params.extensions.value.maximum_son_count, - "Voted for more sons than currently allowed (${c})", ("c", *chain_params.extensions.value.maximum_son_count) ); + for(const auto& num_sons : *options.extensions.value.num_son) + { + FC_ASSERT( num_sons.second <= *chain_params.extensions.value.maximum_son_count, + "Voted for more sons than currently allowed (${c})", ("c", *chain_params.extensions.value.maximum_son_count) ); + } } FC_ASSERT( db.find_object(options.voting_account), "Invalid proxy account specified." ); @@ -188,6 +190,12 @@ object_id_type account_create_evaluator::do_apply( const account_create_operatio obj.owner = o.owner; obj.active = o.active; obj.options = o.options; + + if (!obj.options.extensions.value.num_son.valid()) + { + obj.options.extensions.value = account_options::ext(); + } + obj.statistics = d.create([&obj](account_statistics_object& s){ s.owner = obj.id; s.name = obj.name; diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index d49f1dc5..adabcffe 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -784,7 +784,7 @@ void database::_apply_block( const signed_block& next_block ) update_witness_schedule(); bool need_update_son_schedule = false; - for(const auto& active_sidechain_type : active_sidechain_types) { + for(const auto& active_sidechain_type : active_sidechain_types(dynamic_global_props.time)) { if(global_props.active_sons.at(active_sidechain_type).size() > 0) { need_update_son_schedule = true; } diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index 4dc72649..9510692c 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -342,7 +342,7 @@ bool database::is_son_active( sidechain_type type, son_id_type son_id ) active_son_ids.reserve(gpo_as.size()); std::transform(gpo_as.cbegin(), gpo_as.cend(), std::inserter(active_son_ids, active_son_ids.end()), - [](const son_info& swi) { + [](const son_sidechain_info& swi) { return swi.son_id; }); diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 82d7fde1..2e296e39 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -365,7 +365,7 @@ void database::initialize_hardforks() _hardfork_times.emplace_back(HARDFORK_SON_FOR_HIVE_TIME); _hardfork_times.emplace_back(HARDFORK_SON_TIME); _hardfork_times.emplace_back(HARDFORK_SON2_TIME); - _hardfork_times.emplace_back(HARDFORK_SON3_TIME); + _hardfork_times.emplace_back(HARDFORK_SON_FOR_ETHEREUM_TIME); _hardfork_times.emplace_back(HARDFORK_SWEEPS_TIME); std::sort(_hardfork_times.begin(), _hardfork_times.end()); diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index f7b30caf..e4ccc45d 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -84,7 +84,7 @@ vector> database::sort_votable_objects< std::vector> refs; for( auto& son : all_sons ) { - if(son.has_valid_config(head_block_time()) && son.statuses.at(sidechain) != son_status::deregistered) + if(son.has_valid_config(head_block_time(), sidechain) && son.statuses.at(sidechain) != son_status::deregistered) { refs.push_back(std::cref(son)); } @@ -97,8 +97,10 @@ vector> database::sort_votable_objects< sidechain == sidechain_type::hive, "Unexpected sidechain type"); - const share_type oa_vote = _vote_tally_buffer[a.get_sidechain_vote_id(sidechain)]; - const share_type ob_vote = _vote_tally_buffer[b.get_sidechain_vote_id(sidechain)]; + FC_ASSERT(a.get_sidechain_vote_id(sidechain).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", sidechain)("son", a)); + FC_ASSERT(b.get_sidechain_vote_id(sidechain).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", sidechain)("son", b)); + const share_type oa_vote = _vote_tally_buffer.size() > *a.get_sidechain_vote_id(sidechain) ? _vote_tally_buffer[*a.get_sidechain_vote_id(sidechain)] : 0; + const share_type ob_vote = _vote_tally_buffer.size() > *b.get_sidechain_vote_id(sidechain) ? _vote_tally_buffer[*b.get_sidechain_vote_id(sidechain)] : 0; if( oa_vote != ob_vote ) return oa_vote > ob_vote; @@ -190,7 +192,7 @@ void database::pay_sons() // Current requirement is that we have to pay every 24 hours, so the following check if( dpo.son_budget.value > 0 && ((now - dpo.last_son_payout_time) >= fc::seconds(get_global_properties().parameters.son_pay_time()))) { - for(const auto& active_sidechain_type : active_sidechain_types) + for(const auto& active_sidechain_type : active_sidechain_types(now)) { assert( _son_count_histogram_buffer.at(active_sidechain_type).size() > 0 ); const share_type stake_target = (_total_voting_stake-_son_count_histogram_buffer.at(active_sidechain_type)[0]) / 2; @@ -207,7 +209,14 @@ void database::pay_sons() } } - const auto sons = sort_votable_objects(active_sidechain_type, + const sidechain_type st = [&now, &active_sidechain_type]{ + if( now < HARDFORK_SON_FOR_ETHEREUM_TIME ) + return sidechain_type::bitcoin; + else + return active_sidechain_type; + }(); + + const auto sons = sort_votable_objects(st, (std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count)) ); @@ -215,7 +224,8 @@ void database::pay_sons() uint64_t total_votes = 0; for( const son_object& son : sons ) { - total_votes += _vote_tally_buffer[son.sidechain_vote_ids.at(active_sidechain_type)]; + FC_ASSERT(son.get_sidechain_vote_id(st).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", st)("son", son)); + total_votes += _vote_tally_buffer[*son.get_sidechain_vote_id(st)]; } const int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(total_votes)) - 15, 0); auto get_weight = [&bits_to_drop]( uint64_t son_votes ) { @@ -230,35 +240,37 @@ void database::pay_sons() }; uint64_t weighted_total_txs_signed = 0; const share_type son_budget = dpo.son_budget; - get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &get_weight, &now, &get_weight_before_son2_hf, &active_sidechain_type](const object& o) { + get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &get_weight, &now, &get_weight_before_son2_hf, &active_sidechain_type, &st](const object& o) { const son_statistics_object& s = static_cast(o); const auto& idx = get_index_type().indices().get(); const auto son_obj = idx.find( s.owner ); uint16_t son_weight = 0; + FC_ASSERT(son_obj->get_sidechain_vote_id(st).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", st)("son", *son_obj)); if( now >= HARDFORK_SON2_TIME ) { - son_weight += get_weight(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]); + son_weight += get_weight(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]); } else { - son_weight += get_weight_before_son2_hf(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]); + son_weight += get_weight_before_son2_hf(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]); } const uint64_t txs_signed = s.txs_signed.contains(active_sidechain_type) ? s.txs_signed.at(active_sidechain_type) : 0; weighted_total_txs_signed += (txs_signed * son_weight); }); // Now pay off each SON proportional to the number of transactions signed. - get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &dpo, &son_budget, &get_weight, &get_weight_before_son2_hf, &now, &active_sidechain_type](const object& o) { + get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &dpo, &son_budget, &get_weight, &get_weight_before_son2_hf, &now, &active_sidechain_type, &st](const object& o) { const son_statistics_object& s = static_cast(o); const uint64_t txs_signed = s.txs_signed.contains(active_sidechain_type) ? s.txs_signed.at(active_sidechain_type) : 0; - if(txs_signed > 0){ + if(txs_signed > 0) { const auto& idx = get_index_type().indices().get(); auto son_obj = idx.find( s.owner ); uint16_t son_weight = 0; + FC_ASSERT(son_obj->get_sidechain_vote_id(st).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", st)("son", *son_obj)); if( now >= HARDFORK_SON2_TIME ) { - son_weight += get_weight(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]); + son_weight += get_weight(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]); } else { - son_weight += get_weight_before_son2_hf(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]); + son_weight += get_weight_before_son2_hf(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]); } const share_type pay = (txs_signed * son_weight * son_budget.value)/weighted_total_txs_signed; modify( *son_obj, [&]( son_object& _son_obj) @@ -287,7 +299,7 @@ void database::pay_sons() } } -void database::update_son_metrics(const flat_map >& curr_active_sons) +void database::update_son_metrics(const flat_map >& curr_active_sons) { for(const auto& curr_active_sidechain_sons : curr_active_sons) { const auto& sidechain = curr_active_sidechain_sons.first; @@ -298,7 +310,7 @@ void database::update_son_metrics(const flat_map >& curr_active_sons, - const flat_map >& new_active_sons ) +void database::update_son_statuses( const flat_map >& curr_active_sons, + const flat_map >& new_active_sons ) { for(const auto& new_active_sidechain_sons : new_active_sons) { const auto& sidechain = new_active_sidechain_sons.first; @@ -335,7 +347,7 @@ void database::update_son_statuses( const flat_mapstatuses.at(sidechain) == son_status::inactive) { modify(*son, [&](son_object &obj) { @@ -414,7 +426,7 @@ void database::update_son_statuses( const flat_map >& new_active_sons) +void database::update_son_wallet(const flat_map >& new_active_sons) { bool should_recreate_pw = true; @@ -729,39 +741,22 @@ void database::update_active_sons() } #endif - const flat_map stake_target = [this]{ - flat_map stake_target; - for( const auto& son_count_histogram_buffer : _son_count_histogram_buffer ){ - const auto sidechain = son_count_histogram_buffer.first; - stake_target[sidechain] = (_total_voting_stake-son_count_histogram_buffer.second[0]) / 2; - } - return stake_target; - }(); + const auto supported_active_sidechain_types = active_sidechain_types(head_block_time()); + flat_map son_count; + for(const auto& active_sidechain_type : supported_active_sidechain_types) + { + const share_type stake_target = (_total_voting_stake-_son_count_histogram_buffer.at(active_sidechain_type)[0]) / 2; - /// accounts that vote for 0 or 1 son do not get to express an opinion on - /// the number of sons to have (they abstain and are non-voting accounts) - flat_map stake_tally = []{ - flat_map stake_tally; - for(const auto& active_sidechain_type : active_sidechain_types){ - stake_tally[active_sidechain_type] = 0; - } - return stake_tally; - }(); - flat_map son_count = []{ - flat_map son_count; - for(const auto& active_sidechain_type : active_sidechain_types){ - son_count[active_sidechain_type] = 0; - } - return son_count; - }(); - for( const auto& stake_target_sidechain : stake_target ){ - const auto sidechain = stake_target_sidechain.first; - if( stake_target_sidechain.second > 0 ) + /// accounts that vote for 0 or 1 son do not get to express an opinion on + /// the number of sons to have (they abstain and are non-voting accounts) + share_type stake_tally = 0; + son_count[active_sidechain_type] = 0; + if( stake_target > 0 ) { - while( (son_count[sidechain] < _son_count_histogram_buffer.at(sidechain).size() - 1) - && (stake_tally[sidechain] <= stake_target_sidechain.second) ) + while( (son_count.at(active_sidechain_type) < _son_count_histogram_buffer.at(active_sidechain_type).size() - 1) + && (stake_tally <= stake_target) ) { - stake_tally[sidechain] += _son_count_histogram_buffer.at(sidechain)[ ++son_count[sidechain] ]; + stake_tally += _son_count_histogram_buffer.at(active_sidechain_type)[ ++son_count[active_sidechain_type] ]; } } } @@ -770,18 +765,17 @@ void database::update_active_sons() const chain_property_object& cpo = get_chain_properties(); const auto& all_sons = get_index_type().indices(); flat_map > > sons; - for(const auto& active_sidechain_type : active_sidechain_types) + for(const auto& active_sidechain_type : supported_active_sidechain_types) { - if(head_block_time() >= HARDFORK_SON3_TIME) { + if(head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME) { sons[active_sidechain_type] = sort_votable_objects(active_sidechain_type, (std::max(son_count.at(active_sidechain_type) * 2 + 1, (size_t)cpo.immutable_parameters.min_son_count))); } else { - sons[active_sidechain_type] = sort_votable_objects(active_sidechain_type, get_global_properties().parameters.maximum_son_count()); + sons[active_sidechain_type] = sort_votable_objects(sidechain_type::bitcoin, get_global_properties().parameters.maximum_son_count()); } } - auto& local_vote_buffer_ref = _vote_tally_buffer; for( const son_object& son : all_sons ) { for(const auto& status: son.statuses) @@ -796,9 +790,9 @@ void database::update_active_sons() } } - modify( son, [local_vote_buffer_ref]( son_object& obj ){ + modify( son, [this]( son_object& obj ){ for(const auto& sidechain_vote_id : obj.sidechain_vote_ids ){ - obj.total_votes[sidechain_vote_id.first] = local_vote_buffer_ref[sidechain_vote_id.second]; + obj.total_votes[sidechain_vote_id.first] = _vote_tally_buffer.size() > sidechain_vote_id.second ? _vote_tally_buffer[sidechain_vote_id.second] : 0; } for(auto& status: obj.statuses) { @@ -853,7 +847,7 @@ void database::update_active_sons() // Compare current and to-be lists of active sons const auto cur_active_sons = gpo.active_sons; - flat_map > new_active_sons; + flat_map > new_active_sons; const auto &acc = get(gpo.parameters.son_account()); for( const auto& sidechain_sons : sons ){ const auto& sidechain = sidechain_sons.first; @@ -861,11 +855,12 @@ void database::update_active_sons() new_active_sons[sidechain].reserve(sons_array.size()); for( const son_object& son : sons_array ) { - son_info swi; + son_sidechain_info swi; swi.son_id = son.id; swi.weight = acc.active.account_auths.at(son.son_account); swi.signing_key = son.signing_key; - swi.public_key = son.sidechain_public_keys.at(sidechain); + if (son.sidechain_public_keys.find(sidechain) != son.sidechain_public_keys.end()) + swi.public_key = son.sidechain_public_keys.at(sidechain); new_active_sons[sidechain].push_back(swi); } } @@ -905,7 +900,7 @@ void database::update_active_sons() } }); - for(const auto& active_sidechain_type : active_sidechain_types) + for(const auto& active_sidechain_type : supported_active_sidechain_types) { const son_schedule_object& sidechain_sso = son_schedule_id_type(get_son_schedule_id(active_sidechain_type))(*this); modify(sidechain_sso, [&](son_schedule_object& _sso) @@ -914,12 +909,13 @@ void database::update_active_sons() active_sons.reserve(gpo.active_sons.at(active_sidechain_type).size()); std::transform(gpo.active_sons.at(active_sidechain_type).cbegin(), gpo.active_sons.at(active_sidechain_type).cend(), std::inserter(active_sons, active_sons.end()), - [](const son_info& swi) { + [](const son_sidechain_info& swi) { return swi.son_id; }); _sso.scheduler.update(active_sons); // similar to witness, produce schedule for sons - if(cur_active_sons.at(active_sidechain_type).size() == 0 && new_active_sons.at(active_sidechain_type).size() > 0) + if( ((cur_active_sons.contains(active_sidechain_type) && cur_active_sons.at(active_sidechain_type).size() == 0) || + !cur_active_sons.contains(active_sidechain_type)) && new_active_sons.at(active_sidechain_type).size() > 0 ) { witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); for( size_t i=0; iextensions.value.hive_asset = hive_asset.get_id(); }); } + // Pay the SONs if (head_block_time() >= HARDFORK_SON_TIME) { @@ -2197,18 +2194,57 @@ void database::perform_son_tasks() // and modify the global son funds accordingly, whatever is left is passed on to next budget pay_sons(); } + + // Split vote_ids + if (head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME) { + // Get SON 1.33.0 and check if it has HIVE vote_id + const son_id_type sid = son_id_type(0); + const auto p_son = find(sid); + if(p_son != nullptr) { + if (p_son->sidechain_vote_ids.find(sidechain_type::hive) == p_son->sidechain_vote_ids.end()) { + // Add vote_ids for HIVE and ETHEREUM to all existing SONs + const auto &all_sons = get_index_type().indices().get(); + for (const son_object &son : all_sons) { + vote_id_type existing_vote_id_bitcoin; + vote_id_type new_vote_id_hive; + vote_id_type new_vote_id_eth; + + modify(gpo, [&new_vote_id_hive, &new_vote_id_eth](global_property_object &p) { + new_vote_id_hive = get_next_vote_id(p, vote_id_type::son_hive); + new_vote_id_eth = get_next_vote_id(p, vote_id_type::son_ethereum); + }); + + modify(son, [new_vote_id_hive, new_vote_id_eth](son_object &obj) { + obj.sidechain_vote_ids[sidechain_type::hive] = new_vote_id_hive; + obj.sidechain_vote_ids[sidechain_type::ethereum] = new_vote_id_eth; + }); + + // Duplicate all votes from bitcoin to hive + const auto &all_accounts = get_index_type().indices().get(); + for (const auto &account : all_accounts) { + if (account.options.votes.count(existing_vote_id_bitcoin) != 0) { + modify(account, [new_vote_id_hive](account_object &a) { + a.options.votes.insert(new_vote_id_hive); + }); + } + } + } + } + } + } } void update_son_params(database& db) { - if( (db.head_block_time() >= HARDFORK_SON2_TIME) && (db.head_block_time() < HARDFORK_SON3_TIME) ) + if( (db.head_block_time() >= HARDFORK_SON2_TIME) && (db.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME) ) { const auto& gpo = db.get_global_properties(); db.modify( gpo, []( global_property_object& gpo ) { gpo.parameters.extensions.value.maximum_son_count = 7; }); } - else + + if( (db.head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME) ) { const auto& gpo = db.get_global_properties(); db.modify( gpo, []( global_property_object& gpo ) { @@ -2343,20 +2379,23 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g // same rationale as for witnesses d._committee_count_histogram_buffer[offset] += voting_stake; } - FC_ASSERT( opinion_account.options.extensions.value.num_son.valid() , "Invalid son number" ); - for(const auto& num_sidechain_son : *opinion_account.options.extensions.value.num_son) { - const auto sidechain = num_sidechain_son.first; - const auto& num_son = num_sidechain_son.second; - if (num_son <= props.parameters.maximum_son_count()) { - uint16_t offset = std::min(size_t(num_son / 2), - d._son_count_histogram_buffer.at(sidechain).size() - 1); - // votes for a number greater than maximum_son_count - // are turned into votes for maximum_son_count. - // - // in particular, this takes care of the case where a - // member was voting for a high number, then the - // parameter was lowered. - d._son_count_histogram_buffer.at(sidechain)[offset] += voting_stake; + + if ( opinion_account.options.extensions.value.num_son.valid() ) + { + for(const auto& num_sidechain_son : *opinion_account.options.extensions.value.num_son) { + const auto sidechain = num_sidechain_son.first; + const auto& num_son = num_sidechain_son.second; + if (num_son <= props.parameters.maximum_son_count()) { + uint16_t offset = std::min(size_t(num_son / 2), + d._son_count_histogram_buffer.at(sidechain).size() - 1); + // votes for a number greater than maximum_son_count + // are turned into votes for maximum_son_count. + // + // in particular, this takes care of the case where a + // member was voting for a high number, then the + // parameter was lowered. + d._son_count_histogram_buffer.at(sidechain)[offset] += voting_stake; + } } } diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index dea75bc6..4a3b519f 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -112,7 +112,6 @@ void database::reindex( fc::path data_dir ) uint32_t undo_point = last_block_num < 50 ? 0 : last_block_num - 50; ilog( "Replaying blocks, starting at ${next}...", ("next",head_block_num() + 1) ); - const std::lock_guard undo_db_lock{_undo_db_mutex}; auto_undo_enabler undo(_slow_replays, _undo_db); if( head_block_num() >= undo_point ) { diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index b4c4bb6a..12d4a6dd 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -204,17 +204,18 @@ void database::update_son_schedule() { const global_property_object& gpo = get_global_properties(); - for(const auto& active_sidechain_type : active_sidechain_types) + for(const auto& active_sidechain_type : active_sidechain_types(head_block_time())) { const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(active_sidechain_type))); - if( head_block_num() % gpo.active_sons.at(active_sidechain_type).size() == 0) + if( gpo.active_sons.at(active_sidechain_type).size() != 0 && + head_block_num() % gpo.active_sons.at(active_sidechain_type).size() == 0) { modify( sidechain_sso, [&]( son_schedule_object& _sso ) { _sso.current_shuffled_sons.clear(); _sso.current_shuffled_sons.reserve( gpo.active_sons.at(active_sidechain_type).size() ); - for ( const son_info &w : gpo.active_sons.at(active_sidechain_type) ) { + for ( const auto &w : gpo.active_sons.at(active_sidechain_type) ) { _sso.current_shuffled_sons.push_back(w.son_id); } @@ -350,7 +351,7 @@ void database::update_son_schedule(const signed_block& next_block) assert( dpo.random.data_size() == witness_scheduler_rng::seed_length ); assert( witness_scheduler_rng::seed_length == sso.rng_seed.size() ); - for(const auto& active_sidechain_type : active_sidechain_types) + for(const auto& active_sidechain_type : active_sidechain_types(head_block_time())) { const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(active_sidechain_type))); son_id_type first_son; diff --git a/libraries/chain/hardfork.d/SON3.hf b/libraries/chain/hardfork.d/SON3.hf deleted file mode 100644 index d9556e30..00000000 --- a/libraries/chain/hardfork.d/SON3.hf +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef HARDFORK_SON3_TIME -#ifdef BUILD_PEERPLAYS_TESTNET -#define HARDFORK_SON3_TIME (fc::time_point_sec::from_iso_string("2022-07-16T00:00:00")) -#else -#define HARDFORK_SON3_TIME (fc::time_point_sec::from_iso_string("2022-07-16T00:00:00")) -#endif -#endif diff --git a/libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf b/libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf index 72e929fe..0eb8cc04 100644 --- a/libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf +++ b/libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf @@ -1,7 +1,7 @@ #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")) +#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2023-01-24T00:00:00")) #else -#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2022-07-01T00:00:00")) +#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2023-03-24T00:00:00")) #endif #endif diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 2a432732..c8e1f214 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -584,14 +584,14 @@ namespace graphene { namespace chain { void perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props); void update_active_witnesses(); void update_active_committee_members(); - void update_son_metrics( const flat_map >& curr_active_sons ); + void update_son_metrics( const flat_map >& curr_active_sons ); void update_active_sons(); void remove_son_proposal( const proposal_object& proposal ); void remove_inactive_son_down_proposals( const vector& son_ids_to_remove ); void remove_inactive_son_proposals( const vector& son_ids_to_remove ); - void update_son_statuses( const flat_map >& curr_active_sons, - const flat_map >& new_active_sons ); - void update_son_wallet( const flat_map >& new_active_sons ); + void update_son_statuses( const flat_map >& curr_active_sons, + const flat_map >& new_active_sons ); + void update_son_wallet( const flat_map >& new_active_sons ); void update_worker_votes(); public: @@ -636,7 +636,7 @@ namespace graphene { namespace chain { vector _committee_count_histogram_buffer; flat_map > _son_count_histogram_buffer = []{ flat_map > son_count_histogram_buffer; - for(const auto& active_sidechain_type : active_sidechain_types){ + for(const auto& active_sidechain_type : all_sidechain_types){ son_count_histogram_buffer[active_sidechain_type] = vector{}; } return son_count_histogram_buffer; diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index 71aba1dd..78798202 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include namespace graphene { namespace chain { @@ -49,15 +49,15 @@ namespace graphene { namespace chain { chain_parameters parameters; optional pending_parameters; - uint32_t next_available_vote_id = 0; - vector active_committee_members; // updated once per maintenance interval - flat_set active_witnesses; // updated once per maintenance interval - flat_map > active_sons = []() // updated once per maintenance interval + uint32_t next_available_vote_id = 0; + vector active_committee_members; // updated once per maintenance interval + flat_set active_witnesses; // updated once per maintenance interval + flat_map > active_sons = []() // updated once per maintenance interval { - flat_map > active_sons; - for(const auto& active_sidechain_type : active_sidechain_types) + flat_map > active_sons; + for(const auto& active_sidechain_type : all_sidechain_types) { - active_sons[active_sidechain_type] = vector(); + active_sons[active_sidechain_type] = vector(); } return active_sons; }(); diff --git a/libraries/chain/include/graphene/chain/protocol/account.hpp b/libraries/chain/include/graphene/chain/protocol/account.hpp index 9c4c16d5..c8074885 100644 --- a/libraries/chain/include/graphene/chain/protocol/account.hpp +++ b/libraries/chain/include/graphene/chain/protocol/account.hpp @@ -44,7 +44,7 @@ namespace graphene { namespace chain { /// Must not exceed the actual number of son members voted for in @ref votes optional< flat_map > num_son = []{ flat_map num_son; - for(const auto& active_sidechain_type : active_sidechain_types){ + for(const auto& active_sidechain_type : all_sidechain_types){ num_son[active_sidechain_type] = 0; } return num_son; diff --git a/libraries/chain/include/graphene/chain/protocol/sidechain_transaction.hpp b/libraries/chain/include/graphene/chain/protocol/sidechain_transaction.hpp index 01a4ce74..593432bf 100644 --- a/libraries/chain/include/graphene/chain/protocol/sidechain_transaction.hpp +++ b/libraries/chain/include/graphene/chain/protocol/sidechain_transaction.hpp @@ -71,7 +71,7 @@ FC_REFLECT( graphene::chain::sidechain_transaction_create_operation, (fee)(payer (sidechain) (object_id) (transaction) - (signers) ) + (signers)) FC_REFLECT( graphene::chain::sidechain_transaction_sign_operation::fee_parameters_type, (fee) ) FC_REFLECT( graphene::chain::sidechain_transaction_sign_operation, (fee)(signer)(payer) diff --git a/libraries/chain/include/graphene/chain/protocol/son_wallet.hpp b/libraries/chain/include/graphene/chain/protocol/son_wallet.hpp index 75c3db85..3165554f 100644 --- a/libraries/chain/include/graphene/chain/protocol/son_wallet.hpp +++ b/libraries/chain/include/graphene/chain/protocol/son_wallet.hpp @@ -1,40 +1,47 @@ #pragma once #include #include +#include namespace graphene { namespace chain { - struct son_wallet_recreate_operation : public base_operation - { - struct fee_parameters_type { uint64_t fee = 0; }; + struct son_wallet_recreate_operation : public base_operation + { + struct fee_parameters_type { uint64_t fee = 0; }; + struct ext + { + optional > > sidechain_sons; + }; - asset fee; - account_id_type payer; + asset fee; + account_id_type payer; - flat_map > sons; + vector sons; + extension< ext > extensions; - account_id_type fee_payer()const { return payer; } - share_type calculate_fee(const fee_parameters_type& k)const { return 0; } - }; + account_id_type fee_payer()const { return payer; } + share_type calculate_fee(const fee_parameters_type& k)const { return 0; } + }; - struct son_wallet_update_operation : public base_operation - { - struct fee_parameters_type { uint64_t fee = 0; }; + struct son_wallet_update_operation : public base_operation + { + struct fee_parameters_type { uint64_t fee = 0; }; - asset fee; - account_id_type payer; + asset fee; + account_id_type payer; - son_wallet_id_type son_wallet_id; - sidechain_type sidechain; - string address; + son_wallet_id_type son_wallet_id; + sidechain_type sidechain; + string address; - account_id_type fee_payer()const { return payer; } - share_type calculate_fee(const fee_parameters_type& k)const { return 0; } - }; + account_id_type fee_payer()const { return payer; } + share_type calculate_fee(const fee_parameters_type& k)const { return 0; } + }; } } // namespace graphene::chain FC_REFLECT(graphene::chain::son_wallet_recreate_operation::fee_parameters_type, (fee) ) -FC_REFLECT(graphene::chain::son_wallet_recreate_operation, (fee)(payer)(sons) ) +FC_REFLECT(graphene::chain::son_wallet_recreate_operation::ext, (sidechain_sons)) +FC_REFLECT(graphene::chain::son_wallet_recreate_operation, (fee)(payer)(sons)(extensions) ) FC_REFLECT(graphene::chain::son_wallet_update_operation::fee_parameters_type, (fee) ) FC_REFLECT(graphene::chain::son_wallet_update_operation, (fee)(payer)(son_wallet_id)(sidechain)(address) ) diff --git a/libraries/chain/include/graphene/chain/sidechain_defs.hpp b/libraries/chain/include/graphene/chain/sidechain_defs.hpp index a717f778..421ef597 100644 --- a/libraries/chain/include/graphene/chain/sidechain_defs.hpp +++ b/libraries/chain/include/graphene/chain/sidechain_defs.hpp @@ -1,7 +1,11 @@ #pragma once #include + +#include + #include +#include namespace graphene { namespace chain { @@ -14,9 +18,23 @@ enum class sidechain_type { hive }; -static const std::set active_sidechain_types = {sidechain_type::bitcoin, sidechain_type::ethereum, sidechain_type::hive}; +static const std::set all_sidechain_types = {sidechain_type::bitcoin, sidechain_type::ethereum, sidechain_type::hive}; -} } +inline std::set active_sidechain_types(const fc::time_point_sec block_time) { + std::set active_sidechain_types{}; + + if (block_time >= HARDFORK_SON_TIME) + active_sidechain_types.insert(sidechain_type::bitcoin); + if (block_time >= HARDFORK_SON_FOR_HIVE_TIME) + active_sidechain_types.insert(sidechain_type::hive); + if (block_time >= HARDFORK_SON_FOR_ETHEREUM_TIME) + active_sidechain_types.insert(sidechain_type::ethereum); + + return active_sidechain_types; +} + +} // namespace chain +} // namespace graphene FC_REFLECT_ENUM(graphene::chain::sidechain_type, (unknown) diff --git a/libraries/chain/include/graphene/chain/sidechain_transaction_object.hpp b/libraries/chain/include/graphene/chain/sidechain_transaction_object.hpp index 30a0dd5e..171c564a 100644 --- a/libraries/chain/include/graphene/chain/sidechain_transaction_object.hpp +++ b/libraries/chain/include/graphene/chain/sidechain_transaction_object.hpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include namespace graphene { namespace chain { using namespace graphene::db; @@ -30,7 +30,7 @@ namespace graphene { namespace chain { sidechain_type sidechain = sidechain_type::unknown; object_id_type object_id; std::string transaction; - std::vector signers; + std::vector signers; std::vector> signatures; std::string sidechain_transaction; diff --git a/libraries/chain/include/graphene/chain/son_info.hpp b/libraries/chain/include/graphene/chain/son_info.hpp index 75e58319..afaf9506 100644 --- a/libraries/chain/include/graphene/chain/son_info.hpp +++ b/libraries/chain/include/graphene/chain/son_info.hpp @@ -3,34 +3,40 @@ #include namespace graphene { namespace chain { - using namespace graphene::db; /** - * @class son_info - * @brief tracks information about a SON info required to re/create primary wallet - * @ingroup object + * @class son_info + * @brief tracks information about a SON info required to re/create primary wallet + * @ingroup object */ struct son_info { son_id_type son_id; weight_type weight = 0; public_key_type signing_key; - string public_key; + flat_map sidechain_public_keys; - bool operator==(const son_info& rhs) const { + bool operator==(const son_info& rhs) { bool son_sets_equal = (son_id == rhs.son_id) && (weight == rhs.weight) && (signing_key == rhs.signing_key) && - (public_key == rhs.public_key); + (sidechain_public_keys.size() == rhs.sidechain_public_keys.size()); + if (son_sets_equal) { + bool sidechain_public_keys_equal = true; + for (size_t i = 0; i < sidechain_public_keys.size(); i++) { + const auto lhs_scpk = sidechain_public_keys.nth(i); + const auto rhs_scpk = rhs.sidechain_public_keys.nth(i); + sidechain_public_keys_equal = sidechain_public_keys_equal && + (lhs_scpk->first == rhs_scpk->first) && + (lhs_scpk->second == rhs_scpk->second); + } + son_sets_equal = son_sets_equal && sidechain_public_keys_equal; + } return son_sets_equal; } }; } } -FC_REFLECT( graphene::chain::son_info, - (son_id) - (weight) - (signing_key) - (public_key) ) +FC_REFLECT( graphene::chain::son_info, (son_id) (weight) (signing_key) (sidechain_public_keys) ) diff --git a/libraries/chain/include/graphene/chain/son_object.hpp b/libraries/chain/include/graphene/chain/son_object.hpp index afe7230f..61ada2e5 100644 --- a/libraries/chain/include/graphene/chain/son_object.hpp +++ b/libraries/chain/include/graphene/chain/son_object.hpp @@ -65,7 +65,15 @@ namespace graphene { namespace chain { account_id_type son_account; flat_map sidechain_vote_ids; - flat_map total_votes; + flat_map total_votes = []() + { + flat_map total_votes; + for(const auto& active_sidechain_type : all_sidechain_types) + { + total_votes[active_sidechain_type] = 0; + } + return total_votes; + }(); string url; vesting_balance_id_type deposit; public_key_type signing_key; @@ -74,7 +82,7 @@ namespace graphene { namespace chain { flat_map statuses = []() { flat_map statuses; - for(const auto& active_sidechain_type : active_sidechain_types) + for(const auto& active_sidechain_type : all_sidechain_types) { statuses[active_sidechain_type] = son_status::inactive; } @@ -83,13 +91,15 @@ namespace graphene { namespace chain { flat_map sidechain_public_keys; void pay_son_fee(share_type pay, database& db); - bool has_valid_config()const; - bool has_valid_config(time_point_sec head_block_time)const; + bool has_valid_config(time_point_sec head_block_time, sidechain_type sidechain) const; - inline vote_id_type get_sidechain_vote_id(sidechain_type sidechain) const { return sidechain_vote_ids.at(sidechain); } - inline vote_id_type get_bitcoin_vote_id() const { return get_sidechain_vote_id(sidechain_type::bitcoin); } - inline vote_id_type get_hive_vote_id() const { return get_sidechain_vote_id(sidechain_type::hive); } - inline vote_id_type get_ethereum_vote_id() const { return get_sidechain_vote_id(sidechain_type::ethereum); } + inline optional get_sidechain_vote_id(sidechain_type sidechain) const { return sidechain_vote_ids.contains(sidechain) ? sidechain_vote_ids.at(sidechain) : optional{}; } + inline optional get_bitcoin_vote_id() const { return get_sidechain_vote_id(sidechain_type::bitcoin); } + inline optional get_hive_vote_id() const { return get_sidechain_vote_id(sidechain_type::hive); } + inline optional get_ethereum_vote_id() const { return get_sidechain_vote_id(sidechain_type::ethereum); } + + private: + bool has_valid_config(sidechain_type sidechain) const; }; struct by_account; @@ -105,14 +115,14 @@ namespace graphene { namespace chain { ordered_unique< tag, member >, - ordered_unique< tag, - const_mem_fun + ordered_non_unique< tag, + const_mem_fun, &son_object::get_bitcoin_vote_id> >, - ordered_unique< tag, - const_mem_fun + ordered_non_unique< tag, + const_mem_fun, &son_object::get_hive_vote_id> >, - ordered_unique< tag, - const_mem_fun + ordered_non_unique< tag, + const_mem_fun, &son_object::get_ethereum_vote_id> > > >; diff --git a/libraries/chain/include/graphene/chain/son_sidechain_info.hpp b/libraries/chain/include/graphene/chain/son_sidechain_info.hpp new file mode 100644 index 00000000..8d81f2a4 --- /dev/null +++ b/libraries/chain/include/graphene/chain/son_sidechain_info.hpp @@ -0,0 +1,31 @@ +#pragma once +#include +#include + +namespace graphene { namespace chain { + + /** + * @class son_sidechain_info + * @brief tracks information about a SON info required to re/create primary wallet + * @ingroup object + */ + struct son_sidechain_info { + son_id_type son_id; + weight_type weight = 0; + public_key_type signing_key; + string public_key; + + bool operator==(const son_sidechain_info& rhs) const { + bool son_sets_equal = + (son_id == rhs.son_id) && + (weight == rhs.weight) && + (signing_key == rhs.signing_key) && + (public_key == rhs.public_key); + + return son_sets_equal; + } + }; + +} } + +FC_REFLECT( graphene::chain::son_sidechain_info, (son_id) (weight) (signing_key) (public_key) ) diff --git a/libraries/chain/include/graphene/chain/son_wallet_object.hpp b/libraries/chain/include/graphene/chain/son_wallet_object.hpp index 63b546ea..79ffb2e0 100644 --- a/libraries/chain/include/graphene/chain/son_wallet_object.hpp +++ b/libraries/chain/include/graphene/chain/son_wallet_object.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include namespace graphene { namespace chain { @@ -21,7 +21,7 @@ namespace graphene { namespace chain { time_point_sec expires; flat_map addresses; - flat_map > sons; + flat_map > sons; }; struct by_valid_from; diff --git a/libraries/chain/protocol/account.cpp b/libraries/chain/protocol/account.cpp index a1b7994e..2a5c1045 100644 --- a/libraries/chain/protocol/account.cpp +++ b/libraries/chain/protocol/account.cpp @@ -174,31 +174,37 @@ void account_options::validate() const { auto needed_witnesses = num_witness; auto needed_committee = num_committee; - FC_ASSERT( extensions.value.num_son.valid() , "Invalid son number" ); - flat_map needed_sons = *extensions.value.num_son; for( vote_id_type id : votes ) if( id.type() == vote_id_type::witness && needed_witnesses ) --needed_witnesses; else if ( id.type() == vote_id_type::committee && needed_committee ) --needed_committee; - else if ( id.type() == vote_id_type::son_bitcoin && needed_sons[sidechain_type::bitcoin] ) - --needed_sons[sidechain_type::bitcoin]; - else if ( id.type() == vote_id_type::son_hive && needed_sons[sidechain_type::hive] ) - --needed_sons[sidechain_type::hive]; - else if ( id.type() == vote_id_type::son_ethereum && needed_sons[sidechain_type::ethereum] ) - --needed_sons[sidechain_type::ethereum]; FC_ASSERT( needed_witnesses == 0, "May not specify fewer witnesses than the number voted for."); FC_ASSERT( needed_committee == 0, "May not specify fewer committee members than the number voted for."); - FC_ASSERT( needed_sons[sidechain_type::bitcoin] == 0, - "May not specify fewer Bitcoin SONs than the number voted for."); - FC_ASSERT( needed_sons[sidechain_type::hive] == 0, - "May not specify fewer Hive SONs than the number voted for."); - FC_ASSERT( needed_sons[sidechain_type::ethereum] == 0, - "May not specify fewer Ethereum SONs than the number voted for."); + + if ( extensions.value.num_son.valid() ) + { + flat_map needed_sons = *extensions.value.num_son; + + for( vote_id_type id : votes ) + if ( id.type() == vote_id_type::son_bitcoin && needed_sons[sidechain_type::bitcoin] ) + --needed_sons[sidechain_type::bitcoin]; + else if ( id.type() == vote_id_type::son_hive && needed_sons[sidechain_type::hive] ) + --needed_sons[sidechain_type::hive]; + else if ( id.type() == vote_id_type::son_ethereum && needed_sons[sidechain_type::ethereum] ) + --needed_sons[sidechain_type::ethereum]; + + FC_ASSERT( needed_sons[sidechain_type::bitcoin] == 0, + "May not specify fewer Bitcoin SONs than the number voted for."); + FC_ASSERT( needed_sons[sidechain_type::hive] == 0, + "May not specify fewer Hive SONs than the number voted for."); + 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 diff --git a/libraries/chain/sidechain_transaction_evaluator.cpp b/libraries/chain/sidechain_transaction_evaluator.cpp index ba256199..14b5ecea 100644 --- a/libraries/chain/sidechain_transaction_evaluator.cpp +++ b/libraries/chain/sidechain_transaction_evaluator.cpp @@ -11,7 +11,7 @@ namespace graphene { namespace chain { void_result sidechain_transaction_create_evaluator::do_evaluate(const sidechain_transaction_create_operation &op) { try { FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); - FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." ); + FC_ASSERT(op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer."); FC_ASSERT((op.object_id.is() || op.object_id.is() || op.object_id.is()), "Invalid object id"); @@ -28,15 +28,27 @@ void_result sidechain_transaction_create_evaluator::do_evaluate(const sidechain_ object_id_type sidechain_transaction_create_evaluator::do_apply(const sidechain_transaction_create_operation &op) { try { const auto &new_sidechain_transaction_object = db().create([&](sidechain_transaction_object &sto) { + sto.timestamp = db().head_block_time(); sto.sidechain = op.sidechain; sto.object_id = op.object_id; sto.transaction = op.transaction; - sto.signers = op.signers; - std::transform(op.signers.begin(), op.signers.end(), std::inserter(sto.signatures, sto.signatures.end()), [](const son_info &si) { + std::vector signers; + signers.resize(op.signers.size()); + for(const auto& signer : op.signers){ + son_sidechain_info ssi; + ssi.son_id = signer.son_id; + ssi.weight = signer.weight; + ssi.signing_key = signer.signing_key; + ssi.public_key = signer.sidechain_public_keys.at(op.sidechain); + signers.emplace_back(std::move(ssi)); + } + sto.signers = std::move(signers); + + std::transform(sto.signers.begin(), sto.signers.end(), std::inserter(sto.signatures, sto.signatures.end()), [](const son_sidechain_info &si) { return std::make_pair(si.son_id, std::string()); }); - for (const auto &si : op.signers) { + for (const auto &si : sto.signers) { sto.total_weight = sto.total_weight + si.weight; } sto.sidechain_transaction = ""; diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index e17f3a5f..18be9a5b 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -38,20 +38,29 @@ void_result create_son_evaluator::do_evaluate(const son_create_operation& op) object_id_type create_son_evaluator::do_apply(const son_create_operation& op) { try { - vote_id_type vote_id_bitcoin; - vote_id_type vote_id_hive; - vote_id_type vote_id_ethereum; - 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_hive = get_next_vote_id(p, vote_id_type::son_hive); - vote_id_ethereum = get_next_vote_id(p, vote_id_type::son_ethereum); - }); + vote_id_type vote_id; + flat_map vote_ids; - const auto& new_son_object = db().create( [&]( son_object& obj ){ + const auto now = db().head_block_time(); + if( now < HARDFORK_SON_FOR_ETHEREUM_TIME ) { + db().modify(db().get_global_properties(), [&vote_id](global_property_object &p) { + vote_id = get_next_vote_id(p, vote_id_type::son_bitcoin); + }); + } + else { + db().modify(db().get_global_properties(), [&vote_ids](global_property_object &p) { + vote_ids[sidechain_type::bitcoin] = get_next_vote_id(p, vote_id_type::son_bitcoin); + vote_ids[sidechain_type::hive] = get_next_vote_id(p, vote_id_type::son_hive); + vote_ids[sidechain_type::ethereum] = get_next_vote_id(p, vote_id_type::son_ethereum); + }); + } + + const auto& new_son_object = db().create( [&]( son_object& obj ) { obj.son_account = op.owner_account; - 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::ethereum] = vote_id_ethereum; + if( now < HARDFORK_SON_FOR_ETHEREUM_TIME ) + obj.sidechain_vote_ids[sidechain_type::bitcoin] = vote_id; + else + obj.sidechain_vote_ids = vote_ids; obj.url = op.url; obj.deposit = op.deposit; obj.signing_key = op.signing_key; @@ -168,7 +177,7 @@ void_result son_heartbeat_evaluator::do_evaluate(const son_heartbeat_operation& fc::time_point_sec min_ts = db().head_block_time() - fc::seconds(5 * db().block_interval()); // Account for server ntp sync difference fc::time_point_sec max_ts = db().head_block_time() + fc::seconds(5 * db().block_interval()); - for(const auto& active_sidechain_type : active_sidechain_types) { + for(const auto& active_sidechain_type : active_sidechain_types(db().head_block_time())) { if(stats.last_active_timestamp.contains(active_sidechain_type)) FC_ASSERT(op.ts > stats.last_active_timestamp.at(active_sidechain_type), "Heartbeat sent for sidechain = ${sidechain} without waiting minimum time", ("sidechain", active_sidechain_type)); if(stats.last_down_timestamp.contains(active_sidechain_type)) @@ -195,7 +204,7 @@ object_id_type son_heartbeat_evaluator::do_apply(const son_heartbeat_operation& active_son_ids.reserve(active_sons.size()); std::transform(active_sons.cbegin(), active_sons.cend(), std::inserter(active_son_ids, active_son_ids.end()), - [](const son_info &swi) { + [](const son_sidechain_info &swi) { return swi.son_id; }); @@ -244,7 +253,7 @@ void_result son_report_down_evaluator::do_evaluate(const son_report_down_operati status_need_to_report_down = true; } FC_ASSERT(status_need_to_report_down, "Inactive/Deregistered/in_maintenance SONs cannot be reported on as down"); - for(const auto& active_sidechain_type : active_sidechain_types) { + for(const auto& active_sidechain_type : active_sidechain_types(db().head_block_time())) { if(stats.last_active_timestamp.contains(active_sidechain_type)) FC_ASSERT(op.down_ts >= stats.last_active_timestamp.at(active_sidechain_type), "sidechain = ${sidechain} down_ts should be greater than last_active_timestamp", ("sidechain", active_sidechain_type)); } diff --git a/libraries/chain/son_object.cpp b/libraries/chain/son_object.cpp index e607c103..717285ae 100644 --- a/libraries/chain/son_object.cpp +++ b/libraries/chain/son_object.cpp @@ -6,24 +6,22 @@ namespace graphene { namespace chain { db.adjust_balance(son_account, pay); } - bool son_object::has_valid_config()const { - return ((std::string(signing_key).length() > 0) && - (sidechain_public_keys.size() > 0) && - (sidechain_public_keys.find( sidechain_type::bitcoin ) != sidechain_public_keys.end()) && - (sidechain_public_keys.at(sidechain_type::bitcoin).length() > 0)); + bool son_object::has_valid_config(sidechain_type sidechain) const { + return (sidechain_public_keys.find( sidechain ) != sidechain_public_keys.end()) && + (sidechain_public_keys.at(sidechain).length() > 0); } - bool son_object::has_valid_config(time_point_sec head_block_time)const { - bool retval = has_valid_config(); + bool son_object::has_valid_config(time_point_sec head_block_time, sidechain_type sidechain) const { + bool retval = (std::string(signing_key).length() > 0) && (sidechain_public_keys.size() > 0); - if (head_block_time >= HARDFORK_SON_FOR_HIVE_TIME) { - retval = retval && - (sidechain_public_keys.find( sidechain_type::hive ) != sidechain_public_keys.end()) && - (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); + if (head_block_time < HARDFORK_SON_FOR_HIVE_TIME) { + retval = retval && has_valid_config(sidechain_type::bitcoin); + } + if (head_block_time >= HARDFORK_SON_FOR_HIVE_TIME && head_block_time < HARDFORK_SON_FOR_ETHEREUM_TIME) { + retval = retval && has_valid_config(sidechain_type::bitcoin) && has_valid_config(sidechain_type::hive); + } + else if (head_block_time >= HARDFORK_SON_FOR_ETHEREUM_TIME) { + retval = retval && has_valid_config(sidechain); } return retval; diff --git a/libraries/chain/son_wallet_evaluator.cpp b/libraries/chain/son_wallet_evaluator.cpp index 9b1ff1b7..7f7d830c 100644 --- a/libraries/chain/son_wallet_evaluator.cpp +++ b/libraries/chain/son_wallet_evaluator.cpp @@ -7,8 +7,9 @@ namespace graphene { namespace chain { void_result recreate_son_wallet_evaluator::do_evaluate(const son_wallet_recreate_operation& op) { try{ - FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); - FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." ); + const auto now = db().head_block_time(); + FC_ASSERT(now >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); + FC_ASSERT(op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer."); const auto& idx = db().get_index_type().indices().get(); auto itr = idx.rbegin(); @@ -16,7 +17,23 @@ void_result recreate_son_wallet_evaluator::do_evaluate(const son_wallet_recreate { // Compare current wallet SONs and to-be lists of active sons auto cur_wallet_sons = (*itr).sons; - auto new_wallet_sons = op.sons; + flat_map > new_wallet_sons; + if( now < HARDFORK_SON_FOR_ETHEREUM_TIME ) { + for(const auto& son : op.sons){ + for(const auto& active_sidechain_type : active_sidechain_types(db().head_block_time())){ + son_sidechain_info ssi; + ssi.son_id = son.son_id; + ssi.weight = son.weight; + ssi.signing_key = son.signing_key; + ssi.public_key = son.sidechain_public_keys.at(active_sidechain_type); + new_wallet_sons[active_sidechain_type].emplace_back(std::move(ssi)); + } + } + } + else{ + FC_ASSERT(op.extensions.value.sidechain_sons.valid(), "Sons is not valid"); + new_wallet_sons = *op.extensions.value.sidechain_sons; + } bool son_sets_equal = (cur_wallet_sons.size() == new_wallet_sons.size()); if (son_sets_equal) { @@ -51,9 +68,26 @@ object_id_type recreate_son_wallet_evaluator::do_apply(const son_wallet_recreate } const auto& new_son_wallet_object = db().create( [&]( son_wallet_object& obj ){ - obj.valid_from = db().head_block_time(); + const auto now = db().head_block_time(); + obj.valid_from = now; obj.expires = time_point_sec::maximum(); - obj.sons = op.sons; + if( now < HARDFORK_SON_FOR_ETHEREUM_TIME ) { + flat_map > sons; + for(const auto& son : op.sons){ + for(const auto& active_sidechain_type : active_sidechain_types(db().head_block_time())){ + son_sidechain_info ssi; + ssi.son_id = son.son_id; + ssi.weight = son.weight; + ssi.signing_key = son.signing_key; + ssi.public_key = son.sidechain_public_keys.at(active_sidechain_type); + sons[active_sidechain_type].emplace_back(std::move(ssi)); + } + } + obj.sons = std::move(sons); + } + else{ + obj.sons = *op.extensions.value.sidechain_sons; + } }); return new_son_wallet_object.id; } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/chain/son_wallet_withdraw_evaluator.cpp b/libraries/chain/son_wallet_withdraw_evaluator.cpp index ae0a867b..7101c5fa 100644 --- a/libraries/chain/son_wallet_withdraw_evaluator.cpp +++ b/libraries/chain/son_wallet_withdraw_evaluator.cpp @@ -10,12 +10,13 @@ namespace graphene { namespace chain { void_result create_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_withdraw_create_operation& op) { try { - FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); - + const auto now = db().head_block_time(); + FC_ASSERT(now >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); const auto &son_idx = db().get_index_type().indices().get(); const auto so = son_idx.find(op.son_id); FC_ASSERT(so != son_idx.end(), "SON not found"); FC_ASSERT(so->son_account == op.payer, "Payer is not SON account owner"); + FC_ASSERT(!(op.sidechain == sidechain_type::peerplays && now >= HARDFORK_SON_FOR_ETHEREUM_TIME), "Peerplays sidechain type is not allowed"); const auto &ss_idx = db().get_index_type().indices().get(); FC_ASSERT(ss_idx.find(op.son_id) != ss_idx.end(), "Statistic object for a given SON ID does not exists"); @@ -23,9 +24,17 @@ void_result create_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_w const auto &swwo_idx = db().get_index_type().indices().get(); const auto swwo = swwo_idx.find(op.peerplays_uid); if (swwo == swwo_idx.end()) { + const sidechain_type sidechain = [&op]{ + if(op.sidechain == sidechain_type::peerplays){ + return op.withdraw_sidechain; + } + else + return op.sidechain; + }(); + const auto &gpo = db().get_global_properties(); bool expected = false; - for (auto &si : gpo.active_sons.at(op.sidechain)) { + for (auto &si : gpo.active_sons.at(sidechain)) { if (op.son_id == si.son_id) { expected = true; break; @@ -76,8 +85,16 @@ object_id_type create_son_wallet_withdraw_evaluator::do_apply(const son_wallet_w swwo.withdraw_currency = op.withdraw_currency; swwo.withdraw_amount = op.withdraw_amount; + const sidechain_type sidechain = [&op]{ + if(op.sidechain == sidechain_type::peerplays){ + return op.withdraw_sidechain; + } + else + return op.sidechain; + }(); + const auto &gpo = db().get_global_properties(); - for (auto &si : gpo.active_sons.at(op.sidechain)) { + for (auto &si : gpo.active_sons.at(sidechain)) { swwo.expected_reports.insert(std::make_pair(si.son_id, si.weight)); auto stats_itr = db().get_index_type().indices().get().find(si.son_id); @@ -138,13 +155,17 @@ object_id_type create_son_wallet_withdraw_evaluator::do_apply(const son_wallet_w void_result process_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_withdraw_process_operation& op) { try{ - FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); + const auto now = db().head_block_time(); + FC_ASSERT(now >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." ); const auto& idx = db().get_index_type().indices().get(); const auto& itr = idx.find(op.son_wallet_withdraw_id); FC_ASSERT(itr != idx.end(), "Son wallet withdraw not found"); - FC_ASSERT(db().get_global_properties().active_sons.at(itr->sidechain).size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present"); + FC_ASSERT(!(itr->sidechain == sidechain_type::peerplays && now >= HARDFORK_SON_FOR_ETHEREUM_TIME), "Peerplays sidechain type is not allowed"); + if(itr->sidechain != sidechain_type::peerplays) { + FC_ASSERT(db().get_global_properties().active_sons.at(itr->sidechain).size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present"); + } FC_ASSERT(!itr->processed, "Son wallet withdraw is already processed"); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp index eaa48526..e880a7ae 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp @@ -128,7 +128,7 @@ private: std::mutex event_handler_mutex; typedef std::lock_guard scoped_lock; - std::string create_primary_wallet_address(const std::vector &son_pubkeys); + std::string create_primary_wallet_address(const std::vector &son_pubkeys); std::string create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address); std::string create_deposit_transaction(const son_wallet_deposit_object &swdo); diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp index 5e4b6a61..0cd22f96 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp @@ -68,7 +68,8 @@ private: ethereum::chain_id_type chain_id; ethereum::network_id_type network_id; - std::string create_primary_wallet_transaction(const std::vector &son_pubkeys, const std::string &object_id); + std::string create_primary_wallet_transaction(const std::vector &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); diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index ae9967f7..bd5bb504 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -116,21 +116,21 @@ peerplays_sidechain_plugin_impl::peerplays_sidechain_plugin_impl(peerplays_sidec sidechain_enabled_peerplays(false), current_son_id([] { std::map current_son_id; - for (const auto &active_sidechain_type : active_sidechain_types) { + for (const auto &active_sidechain_type : all_sidechain_types) { current_son_id.emplace(active_sidechain_type, son_id_type(std::numeric_limits().max())); } return current_son_id; }()), sidechain_enabled([] { std::map sidechain_enabled; - for (const auto &active_sidechain_type : active_sidechain_types) { + for (const auto &active_sidechain_type : all_sidechain_types) { sidechain_enabled.emplace(active_sidechain_type, false); } return sidechain_enabled; }()), net_handlers([] { std::map> net_handlers; - for (const auto &active_sidechain_type : active_sidechain_types) { + for (const auto &active_sidechain_type : all_sidechain_types) { net_handlers.emplace(active_sidechain_type, nullptr); } return net_handlers; @@ -149,7 +149,7 @@ peerplays_sidechain_plugin_impl::~peerplays_sidechain_plugin_impl() { } try { - for (const auto &active_sidechain_type : active_sidechain_types) { + for (const auto &active_sidechain_type : all_sidechain_types) { if (_son_processing_task.count(active_sidechain_type) != 0 && _son_processing_task.at(active_sidechain_type).valid()) _son_processing_task.at(active_sidechain_type).wait(); } @@ -362,7 +362,7 @@ bool peerplays_sidechain_plugin_impl::is_active_son(sidechain_type sidechain, so set active_son_ids; std::transform(gpo.active_sons.at(sidechain).cbegin(), gpo.active_sons.at(sidechain).cend(), std::inserter(active_son_ids, active_son_ids.end()), - [](const son_info &swi) { + [](const son_sidechain_info &swi) { return swi.son_id; }); @@ -415,7 +415,7 @@ bool peerplays_sidechain_plugin_impl::is_son_down_op_valid(const chain::operatio status_son_down_op_valid = false; } if (status_son_down_op_valid) { - for (const auto &active_sidechain_type : active_sidechain_types) { + for (const auto &active_sidechain_type : active_sidechain_types(d.head_block_time())) { if (stats.last_active_timestamp.contains(active_sidechain_type)) { const fc::time_point_sec last_active_ts = ((stats.last_active_timestamp.at(active_sidechain_type) > last_maintenance_time) ? stats.last_active_timestamp.at(active_sidechain_type) : last_maintenance_time); if (((fc::time_point::now() - last_active_ts) <= fc::seconds(down_threshold))) { @@ -468,7 +468,7 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop() { //! Check that son is active (at least for one sidechain_type) bool is_son_active = false; - for (const auto &active_sidechain_type : active_sidechain_types) { + for (const auto &active_sidechain_type : active_sidechain_types(d.head_block_time())) { if (sidechain_enabled.at(active_sidechain_type)) { if (is_active_son(active_sidechain_type, son_id)) is_son_active = true; @@ -506,7 +506,7 @@ void peerplays_sidechain_plugin_impl::schedule_son_processing() { const auto next_wakeup = now + std::chrono::microseconds(time_to_next_son_processing); - for (const auto &active_sidechain_type : active_sidechain_types) { + for (const auto &active_sidechain_type : active_sidechain_types(plugin.database().head_block_time())) { if (_son_processing_task.count(active_sidechain_type) != 0 && _son_processing_task.at(active_sidechain_type).wait_for(std::chrono::seconds{0}) != std::future_status::ready) { wlog("Son doesn't process in time for sidechain: ${active_sidechain_type}", ("active_sidechain_type", active_sidechain_type)); _son_processing_task.at(active_sidechain_type).wait(); @@ -623,7 +623,7 @@ bool peerplays_sidechain_plugin_impl::can_son_participate(sidechain_type sidecha std::map> peerplays_sidechain_plugin_impl::get_son_listener_log() { std::map> result; - for (const auto &active_sidechain_type : active_sidechain_types) { + for (const auto &active_sidechain_type : active_sidechain_types(plugin.database().head_block_time())) { if (net_handlers.at(active_sidechain_type)) { result.emplace(active_sidechain_type, net_handlers.at(active_sidechain_type)->get_son_listener_log()); } diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index f1594c0f..ee60bd28 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -453,7 +453,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) if (swo != idx.end()) { const auto &active_sons = gpo.active_sons.at(sidechain); - vector wallet_sons = swo->sons.at(sidechain); + const auto &wallet_sons = swo->sons.at(sidechain); bool son_sets_equal = (active_sons.size() == wallet_sons.size()); @@ -466,7 +466,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) if (son_sets_equal) { const auto &active_sons = gpo.active_sons.at(sidechain); vector son_pubkeys_bitcoin; - for (const son_info &si : active_sons) { + for (const auto &si : active_sons) { son_pubkeys_bitcoin.push_back(si.public_key); } @@ -758,7 +758,14 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { stc_op.object_id = prev_sw->id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = prev_sw->sons.at(sidechain); + for (const auto &signer : prev_sw->sons.at(sidechain)) { + son_info si; + si.son_id = signer.son_id; + si.weight = signer.weight; + si.signing_key = signer.signing_key; + si.sidechain_public_keys[sidechain] = signer.public_key; + stc_op.signers.emplace_back(std::move(si)); + } proposal_op.proposed_ops.emplace_back(stc_op); } } @@ -861,7 +868,14 @@ bool sidechain_net_handler_bitcoin::process_deposit(const son_wallet_deposit_obj stc_op.object_id = swdo.id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons.at(sidechain); + for (const auto &signer : gpo.active_sons.at(sidechain)) { + son_info si; + si.son_id = signer.son_id; + si.weight = signer.weight; + si.signing_key = signer.signing_key; + si.sidechain_public_keys[sidechain] = signer.public_key; + stc_op.signers.emplace_back(std::move(si)); + } 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); @@ -905,7 +919,14 @@ bool sidechain_net_handler_bitcoin::process_withdrawal(const son_wallet_withdraw stc_op.object_id = swwo.id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons.at(sidechain); + for (const auto &signer : gpo.active_sons.at(sidechain)) { + son_info si; + si.son_id = signer.son_id; + si.weight = signer.weight; + si.signing_key = signer.signing_key; + si.sidechain_public_keys[sidechain] = signer.public_key; + stc_op.signers.emplace_back(std::move(si)); + } 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); @@ -1007,7 +1028,7 @@ optional sidechain_net_handler_bitcoin::estimate_withdrawal_transaction_f return optional{}; } -std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const std::vector &son_pubkeys) { +std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const std::vector &son_pubkeys) { using namespace bitcoin; std::vector> pubkey_weights; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 80a11b16..bce2ce50 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -239,7 +239,7 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) if (swo != idx.end()) { const auto active_sons = gpo.active_sons.at(sidechain); - const vector wallet_sons = swo->sons.at(sidechain); + const vector wallet_sons = swo->sons.at(sidechain); bool son_sets_equal = (active_sons.size() == wallet_sons.size()); @@ -474,7 +474,7 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { proposal_op.proposed_ops.emplace_back(swu_op); const auto signers = [this, &prev_sw, &active_sw, &swi] { - std::vector signers; + std::vector signers; //! Check if we don't have any previous set of active SONs use the current one if (prev_sw != swi.rend()) { if (!prev_sw->sons.at(sidechain).empty()) @@ -495,7 +495,14 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { stc_op.object_id = active_sw->id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = signers; + for (const auto &signer : signers) { + son_info si; + si.son_id = signer.son_id; + si.weight = signer.weight; + si.signing_key = signer.signing_key; + si.sidechain_public_keys[sidechain] = signer.public_key; + stc_op.signers.emplace_back(std::move(si)); + } proposal_op.proposed_ops.emplace_back(stc_op); } @@ -593,7 +600,14 @@ bool sidechain_net_handler_ethereum::process_withdrawal(const son_wallet_withdra stc_op.object_id = swwo.id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons.at(sidechain); + for (const auto &signer : gpo.active_sons.at(sidechain)) { + son_info si; + si.son_id = signer.son_id; + si.weight = signer.weight; + si.signing_key = signer.signing_key; + si.sidechain_public_keys[sidechain] = signer.public_key; + stc_op.signers.emplace_back(std::move(si)); + } 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); @@ -773,7 +787,7 @@ optional sidechain_net_handler_ethereum::estimate_withdrawal_transaction_ return asset.amount_from_string(std::to_string(eth_gas_fee)); } -std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const std::vector &son_pubkeys, const std::string &object_id) { +std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const std::vector &son_pubkeys, const std::string &object_id) { std::vector> owners_weights; for (auto &son : son_pubkeys) { const std::string pub_key_str = son.public_key; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp index c3897f74..2a11db85 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -213,8 +213,8 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { const auto swo = idx.find(swo_id); if (swo != idx.end()) { - auto active_sons = gpo.active_sons.at(sidechain); - vector wallet_sons = swo->sons.at(sidechain); + const auto &active_sons = gpo.active_sons.at(sidechain); + const auto &wallet_sons = swo->sons.at(sidechain); bool son_sets_equal = (active_sons.size() == wallet_sons.size()); @@ -549,7 +549,7 @@ void sidechain_net_handler_hive::process_primary_wallet() { proposal_op.proposed_ops.emplace_back(swu_op); const auto signers = [this, &prev_sw, &active_sw, &swi] { - std::vector signers; + std::vector signers; //! Check if we don't have any previous set of active SONs use the current one if (prev_sw != swi.rend()) { if (!prev_sw->sons.at(sidechain).empty()) @@ -568,8 +568,14 @@ void sidechain_net_handler_hive::process_primary_wallet() { stc_op.object_id = active_sw->id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = signers; - + for (const auto &signer : gpo.active_sons.at(sidechain)) { + son_info si; + si.son_id = signer.son_id; + si.weight = signer.weight; + si.signing_key = signer.signing_key; + si.sidechain_public_keys[sidechain] = signer.public_key; + stc_op.signers.emplace_back(std::move(si)); + } 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); @@ -725,7 +731,14 @@ bool sidechain_net_handler_hive::process_withdrawal(const son_wallet_withdraw_ob stc_op.object_id = swwo.id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons.at(sidechain); + for (const auto &signer : gpo.active_sons.at(sidechain)) { + son_info si; + si.son_id = signer.son_id; + si.weight = signer.weight; + si.signing_key = signer.signing_key; + si.sidechain_public_keys[sidechain] = signer.public_key; + stc_op.signers.emplace_back(std::move(si)); + } 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); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp index 76fbbb3e..0f6d06eb 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp @@ -197,7 +197,14 @@ bool sidechain_net_handler_peerplays::process_deposit(const son_wallet_deposit_o stc_op.object_id = swdo.id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons.at(sidechain); + for (const auto &signer : gpo.active_sons.at(sidechain)) { + son_info si; + si.son_id = signer.son_id; + si.weight = signer.weight; + si.signing_key = signer.signing_key; + si.sidechain_public_keys[sidechain] = signer.public_key; + stc_op.signers.emplace_back(std::move(si)); + } proposal_create_operation proposal_op; proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 6d97f647..1de38ffa 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -1559,14 +1559,14 @@ class wallet_api * @brief Get list of active sons * @return List of active SONs */ - flat_map> get_active_sons(); + flat_map> get_active_sons(); /** * @brief Get list of active sons * @param sidechain Sidechain type [bitcoin|ethereum|hive] * @return List of active SONs */ - vector get_active_sons_by_sidechain(sidechain_type sidechain); + vector get_active_sons_by_sidechain(sidechain_type sidechain); /** * @brief Get SON network status diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 794e8692..e1363b0b 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2230,12 +2230,12 @@ public: return sign_transaction( tx, broadcast ); } FC_CAPTURE_AND_RETHROW( (owner_account) ) } - flat_map> get_active_sons() + flat_map> get_active_sons() { try { return _remote_db->get_active_sons(); } FC_CAPTURE_AND_RETHROW() } - vector get_active_sons_by_sidechain(sidechain_type sidechain) + vector get_active_sons_by_sidechain(sidechain_type sidechain) { try { return _remote_db->get_active_sons_by_sidechain(sidechain); } FC_CAPTURE_AND_RETHROW() } @@ -2775,13 +2775,15 @@ public: if (approve) { - auto insert_result = voting_account_object.options.votes.insert(son_obj->get_sidechain_vote_id(sidechain)); + FC_ASSERT(son_obj->get_sidechain_vote_id(sidechain).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", sidechain)("son", *son_obj)); + auto insert_result = voting_account_object.options.votes.insert(*son_obj->get_sidechain_vote_id(sidechain)); if (!insert_result.second) FC_THROW("Account ${account} has already voted for son ${son} for sidechain ${sidechain}", ("account", voting_account)("son", son)("sidechain", sidechain)); } else { - unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->get_sidechain_vote_id(sidechain)); + FC_ASSERT(son_obj->get_sidechain_vote_id(sidechain).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", sidechain)("son", *son_obj)); + unsigned votes_removed = voting_account_object.options.votes.erase(*son_obj->get_sidechain_vote_id(sidechain)); if (!votes_removed) FC_THROW("Account ${account} has already unvoted for son ${son} for sidechain ${sidechain}", ("account", voting_account)("son", son)("sidechain", sidechain)); } @@ -2819,7 +2821,8 @@ public: 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"); - auto insert_result = voting_account_object.options.votes.insert(son_obj->get_sidechain_vote_id(sidechain)); + FC_ASSERT(son_obj->get_sidechain_vote_id(sidechain).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", sidechain)("son", *son_obj)); + auto insert_result = voting_account_object.options.votes.insert(*son_obj->get_sidechain_vote_id(sidechain)); if (!insert_result.second) FC_THROW("Account ${account} was already voting for SON ${son}", ("account", voting_account)("son", son)); } @@ -2830,7 +2833,8 @@ public: 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"); - unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->get_sidechain_vote_id(sidechain)); + FC_ASSERT(son_obj->get_sidechain_vote_id(sidechain).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", sidechain)("son", *son_obj)); + unsigned votes_removed = voting_account_object.options.votes.erase(*son_obj->get_sidechain_vote_id(sidechain)); if (!votes_removed) FC_THROW("Account ${account} is already not voting for SON ${son}", ("account", voting_account)("son", son)); } @@ -5294,12 +5298,12 @@ map wallet_api::list_sons(const string& lowerbound, uint32_ return my->_remote_db->lookup_son_accounts(lowerbound, limit); } -flat_map> wallet_api::get_active_sons() +flat_map> wallet_api::get_active_sons() { return my->get_active_sons(); } -vector wallet_api::get_active_sons_by_sidechain(sidechain_type sidechain) +vector wallet_api::get_active_sons_by_sidechain(sidechain_type sidechain) { return my->get_active_sons_by_sidechain(sidechain); } diff --git a/tests/cli/son.cpp b/tests/cli/son.cpp index 83db8d48..4662c57c 100644 --- a/tests/cli/son.cpp +++ b/tests/cli/son.cpp @@ -39,7 +39,7 @@ public: fixture_(fixture) { fixture_.init_nathan(); - fixture_.generate_blocks(HARDFORK_SON3_TIME); + fixture_.generate_blocks(HARDFORK_SON_FOR_ETHEREUM_TIME); fixture_.generate_block(); } @@ -143,9 +143,12 @@ BOOST_AUTO_TEST_CASE( create_sons ) 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::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::hive).instance(), 23); - BOOST_CHECK_EQUAL(son1_obj.get_sidechain_vote_id(sidechain_type::ethereum).instance(), 24); + BOOST_REQUIRE(son1_obj.get_sidechain_vote_id(sidechain_type::bitcoin)); + BOOST_CHECK_EQUAL(son1_obj.get_sidechain_vote_id(sidechain_type::bitcoin)->instance(), 22); + BOOST_REQUIRE(son1_obj.get_sidechain_vote_id(sidechain_type::hive)); + BOOST_CHECK_EQUAL(son1_obj.get_sidechain_vote_id(sidechain_type::hive)->instance(), 23); + BOOST_REQUIRE(son1_obj.get_sidechain_vote_id(sidechain_type::ethereum)); + BOOST_CHECK_EQUAL(son1_obj.get_sidechain_vote_id(sidechain_type::ethereum)->instance(), 24); auto son2_obj = con.wallet_api_ptr->get_son("son2account"); BOOST_CHECK(son2_obj.son_account == con.wallet_api_ptr->get_account_id("son2account")); @@ -153,9 +156,12 @@ BOOST_AUTO_TEST_CASE( create_sons ) 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::ethereum], "ethereum address 2"); - 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(), 26); - BOOST_CHECK_EQUAL(son2_obj.get_sidechain_vote_id(sidechain_type::ethereum).instance(), 27); + BOOST_REQUIRE(son2_obj.get_sidechain_vote_id(sidechain_type::bitcoin)); + BOOST_CHECK_EQUAL(son2_obj.get_sidechain_vote_id(sidechain_type::bitcoin)->instance(), 25); + BOOST_REQUIRE(son2_obj.get_sidechain_vote_id(sidechain_type::hive)); + BOOST_CHECK_EQUAL(son2_obj.get_sidechain_vote_id(sidechain_type::hive)->instance(), 26); + BOOST_REQUIRE(son2_obj.get_sidechain_vote_id(sidechain_type::ethereum)); + BOOST_CHECK_EQUAL(son2_obj.get_sidechain_vote_id(sidechain_type::ethereum)->instance(), 27); } catch( fc::exception& e ) { BOOST_TEST_MESSAGE("SON cli wallet tests exception"); @@ -190,9 +196,12 @@ BOOST_AUTO_TEST_CASE( cli_update_son ) 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::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::hive).instance(), 23); - BOOST_CHECK_EQUAL(son_data.get_sidechain_vote_id(sidechain_type::ethereum).instance(), 24); + BOOST_REQUIRE(son_data.get_sidechain_vote_id(sidechain_type::bitcoin)); + BOOST_CHECK_EQUAL(son_data.get_sidechain_vote_id(sidechain_type::bitcoin)->instance(), 22); + BOOST_REQUIRE(son_data.get_sidechain_vote_id(sidechain_type::hive)); + BOOST_CHECK_EQUAL(son_data.get_sidechain_vote_id(sidechain_type::hive)->instance(), 23); + BOOST_REQUIRE(son_data.get_sidechain_vote_id(sidechain_type::ethereum)); + BOOST_CHECK_EQUAL(son_data.get_sidechain_vote_id(sidechain_type::ethereum)->instance(), 24); // update SON sidechain_public_keys.clear(); @@ -1400,7 +1409,7 @@ BOOST_FIXTURE_TEST_CASE( get_son_network_status_by_sidechain, cli_fixture ) // Check Network Status Before sending Heartbeats BOOST_CHECK(generate_maintenance_block()); - for(sidechain_type sidechain:active_sidechain_types) + for(sidechain_type sidechain : all_sidechain_types) { auto network_status_obj = con.wallet_api_ptr->get_son_network_status_by_sidechain(sidechain); for(map::iterator iter=network_status_obj.begin(); iter!=network_status_obj.end(); ++iter) @@ -1448,7 +1457,7 @@ BOOST_FIXTURE_TEST_CASE( get_son_network_status_by_sidechain, cli_fixture ) generate_blocks(50); BOOST_TEST_MESSAGE("Checking Network Status"); - for(sidechain_type sidechain:active_sidechain_types) + for(sidechain_type sidechain : all_sidechain_types) { auto network_status_obj = con.wallet_api_ptr->get_son_network_status_by_sidechain(sidechain); for(map::iterator iter=network_status_obj.begin(); iter!=network_status_obj.end(); ++iter) @@ -1479,7 +1488,7 @@ BOOST_FIXTURE_TEST_CASE( get_son_network_status_by_sidechain, cli_fixture ) con.wallet_api_ptr->sign_transaction(trx2, true); generate_blocks(50); - for(sidechain_type sidechain:active_sidechain_types) + for(sidechain_type sidechain : all_sidechain_types) { auto network_status_obj = con.wallet_api_ptr->get_son_network_status_by_sidechain(sidechain); for(map::iterator iter=network_status_obj.begin(); iter!=network_status_obj.end(); ++iter) @@ -1507,7 +1516,7 @@ BOOST_FIXTURE_TEST_CASE( get_son_network_status_by_sidechain, cli_fixture ) generate_blocks(db->head_block_time() + gpo.parameters.son_heartbeat_frequency(), false); BOOST_TEST_MESSAGE("Checking Network Status"); - for(sidechain_type sidechain:active_sidechain_types) + for(sidechain_type sidechain : all_sidechain_types) { auto network_status_obj = con.wallet_api_ptr->get_son_network_status_by_sidechain(sidechain); for(map::iterator iter=network_status_obj.begin(); iter!=network_status_obj.end(); ++iter) @@ -1535,7 +1544,7 @@ BOOST_FIXTURE_TEST_CASE( get_son_network_status_by_sidechain, cli_fixture ) generate_blocks(db->head_block_time() + gpo.parameters.son_heartbeat_frequency() + gpo.parameters.son_down_time(), false);; BOOST_TEST_MESSAGE("Checking Network Status"); - for(sidechain_type sidechain:active_sidechain_types) + for(sidechain_type sidechain : all_sidechain_types) { auto network_status_obj = con.wallet_api_ptr->get_son_network_status_by_sidechain(sidechain); for(map::iterator iter=network_status_obj.begin(); iter!=network_status_obj.end(); ++iter) diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 807c495a..c69768a3 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -1038,7 +1038,7 @@ BOOST_FIXTURE_TEST_CASE( hardfork_son2_time, database_fixture ) generate_block(); // get the maintenance skip slots out of the way*/ BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maximum_son_count(), 7); - generate_blocks(HARDFORK_SON3_TIME); + generate_blocks(HARDFORK_SON_FOR_ETHEREUM_TIME); // after this hardfork maximum son account should not reset the value // on 7 after maintenance interval anymore. It must be HARDFORK_SON2_TIME BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maximum_son_count(), GRAPHENE_DEFAULT_MAX_SONS); diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index 23ddfd1c..0da34705 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -15,7 +15,7 @@ using namespace graphene::chain::test; BOOST_FIXTURE_TEST_SUITE( son_operation_tests, database_fixture ) BOOST_AUTO_TEST_CASE( create_son_test ) { - generate_blocks(HARDFORK_SON_TIME); + generate_blocks(HARDFORK_SON_FOR_ETHEREUM_TIME); generate_block(); set_expiration(db, trx); @@ -314,7 +314,7 @@ BOOST_AUTO_TEST_CASE( son_pay_test ) const dynamic_global_property_object& dpo = db.get_dynamic_global_properties(); const auto block_interval = db.get_global_properties().parameters.block_interval; BOOST_CHECK( dpo.son_budget.value == 0); - generate_blocks(HARDFORK_SON_TIME); + generate_blocks(HARDFORK_SON_FOR_ETHEREUM_TIME); while (db.head_block_time() <= HARDFORK_SON_TIME) { generate_block(); } @@ -634,16 +634,18 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { // Modify SON's status to active db.modify( *obj, [&]( son_object& _s) { - _s.statuses[sidechain_type::bitcoin] = son_status::active; - _s.statuses[sidechain_type::hive] = son_status::active; - _s.statuses[sidechain_type::ethereum] = son_status::active; + for (const auto& active_sidechain_type : active_sidechain_types(db.head_block_time())) + { + _s.statuses[active_sidechain_type] = son_status::active; + } }); 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::hive] = fc::time_point_sec(db.head_block_time()); - _s.last_down_timestamp[sidechain_type::ethereum] = fc::time_point_sec(db.head_block_time()); + for (const auto& active_sidechain_type : active_sidechain_types(db.head_block_time())) + { + _s.last_down_timestamp[active_sidechain_type] = fc::time_point_sec(db.head_block_time()); + } }); { @@ -660,9 +662,10 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { PUSH_TX( db, trx, ~0); generate_block(); trx.clear(); - 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::ethereum) == son_status::request_maintenance); + for (const auto& active_sidechain_type : active_sidechain_types(db.head_block_time())) + { + BOOST_CHECK( obj->statuses.at(active_sidechain_type) == son_status::request_maintenance); + } } { @@ -679,23 +682,26 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { PUSH_TX( db, trx, ~0); generate_block(); trx.clear(); - 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::ethereum) == son_status::active); + for (const auto& active_sidechain_type : active_sidechain_types(db.head_block_time())) + { + BOOST_CHECK( obj->statuses.at(active_sidechain_type) == son_status::active); + } } // Modify SON's status to in_maintenance db.modify( *obj, [&]( son_object& _s) { - _s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance; - _s.statuses[sidechain_type::hive] = son_status::in_maintenance; - _s.statuses[sidechain_type::ethereum] = son_status::in_maintenance; + for (const auto& active_sidechain_type : active_sidechain_types(db.head_block_time())) + { + _s.statuses[active_sidechain_type] = son_status::in_maintenance; + } }); flat_map downtime; - downtime[sidechain_type::bitcoin] = 0; - downtime[sidechain_type::hive] = 0; - downtime[sidechain_type::ethereum] = 0; + for (const auto& active_sidechain_type : active_sidechain_types(db.head_block_time())) + { + downtime[active_sidechain_type] = 0; + } { generate_block(); @@ -711,36 +717,34 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { PUSH_TX( db, trx, ~0); generate_block(); trx.clear(); - BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.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::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::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::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::hive) == op.ts); - BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::ethereum) == op.ts); + + for (const auto& active_sidechain_type : active_sidechain_types(db.head_block_time())) + { + BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(active_sidechain_type), op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(active_sidechain_type).sec_since_epoch()); + downtime[active_sidechain_type] += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(active_sidechain_type).sec_since_epoch(); + BOOST_CHECK( obj->statuses.at(active_sidechain_type) == son_status::inactive); + BOOST_CHECK( son_stats_obj->last_active_timestamp.at(active_sidechain_type) == op.ts); + } } // Modify SON's status to in_maintenance db.modify( *obj, [&]( son_object& _s) { - _s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance; - _s.statuses[sidechain_type::hive] = son_status::in_maintenance; - _s.statuses[sidechain_type::ethereum] = son_status::in_maintenance; + for (const auto& active_sidechain_type : active_sidechain_types(db.head_block_time())) + { + _s.statuses[active_sidechain_type] = son_status::in_maintenance; + } }); // SON is selected as one of the active SONs db.modify( db.get_global_properties(), [&]( global_property_object& _gpo ) { - son_info son_inf; + son_sidechain_info son_inf; son_inf.son_id = son_id_type(0); - _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::ethereum].push_back(son_inf); + for (const auto& active_sidechain_type : active_sidechain_types(db.head_block_time())) + { + _gpo.active_sons[active_sidechain_type].push_back(son_inf); + } }); { @@ -758,18 +762,13 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { generate_block(); trx.clear(); - 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::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::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::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::hive) == op.ts); - BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::ethereum) == op.ts); + for (const auto& active_sidechain_type : active_sidechain_types(db.head_block_time())) + { + BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(active_sidechain_type), downtime.at(active_sidechain_type) + op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(active_sidechain_type).sec_since_epoch()); + downtime[active_sidechain_type] += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(active_sidechain_type).sec_since_epoch(); + BOOST_CHECK( obj->statuses.at(active_sidechain_type) == son_status::active); + BOOST_CHECK( son_stats_obj->last_active_timestamp.at(active_sidechain_type) == op.ts); + } } { @@ -786,15 +785,13 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { PUSH_TX( db, trx, ~0); generate_block(); trx.clear(); - BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.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::ethereum), downtime.at(sidechain_type::ethereum)); - 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::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::hive) == op.ts); - BOOST_CHECK( son_stats_obj->last_active_timestamp.at(sidechain_type::ethereum) == op.ts); + + for (const auto& active_sidechain_type : active_sidechain_types(db.head_block_time())) + { + BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(active_sidechain_type), downtime.at(active_sidechain_type)); + BOOST_CHECK( obj->statuses.at(active_sidechain_type) == son_status::active); + BOOST_CHECK( son_stats_obj->last_active_timestamp.at(active_sidechain_type) == op.ts); + } } } FC_LOG_AND_RETHROW() } @@ -819,9 +816,10 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) { auto son_stats_obj = sidx.find( obj->statistics ); BOOST_REQUIRE( son_stats_obj != sidx.end() ); - BOOST_CHECK( obj->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::ethereum) == son_status::active); + for (const auto& active_sidechain_type : active_sidechain_types(db.head_block_time())) + { + BOOST_CHECK( obj->statuses.at(active_sidechain_type) == son_status::active); + } { // Check that transaction fails if down_ts < last_active_timestamp @@ -873,12 +871,11 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) { generate_block(); trx.clear(); - 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::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::hive) == op.down_ts); - BOOST_CHECK( son_stats_obj->last_down_timestamp.at(sidechain_type::ethereum) == op.down_ts); + for (const auto& active_sidechain_type : active_sidechain_types(db.head_block_time())) + { + BOOST_CHECK( obj->statuses.at(active_sidechain_type) == son_status::in_maintenance); + BOOST_CHECK( son_stats_obj->last_down_timestamp.at(active_sidechain_type) == op.down_ts); + } } { diff --git a/tests/tests/son_wallet_tests.cpp b/tests/tests/son_wallet_tests.cpp index 4b1e4fe2..fd0d65e8 100644 --- a/tests/tests/son_wallet_tests.cpp +++ b/tests/tests/son_wallet_tests.cpp @@ -160,8 +160,8 @@ BOOST_AUTO_TEST_CASE( son_wallet_recreate_test ) { si.son_id = son_id_type(0); si.weight = 1000; si.signing_key = alice_public_key; - si.public_key = ""; - op.sons[sidechain_type::bitcoin].push_back(si); + si.sidechain_public_keys[sidechain_type::bitcoin] = ""; + op.sons.push_back(si); } { @@ -169,8 +169,8 @@ BOOST_AUTO_TEST_CASE( son_wallet_recreate_test ) { si.son_id = son_id_type(1); si.weight = 1000; si.signing_key = bob_public_key; - si.public_key = ""; - op.sons[sidechain_type::bitcoin].push_back(si); + si.sidechain_public_keys[sidechain_type::bitcoin] = ""; + op.sons.push_back(si); } trx.operations.push_back(op); From fc1cdf262971d1ff811b7893fcdb9762a846b2a8 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Wed, 1 Feb 2023 20:54:44 +0200 Subject: [PATCH 4/8] Fix build errors active_sidechain_types --- libraries/chain/son_wallet_evaluator.cpp | 6 ++++-- .../sidechain_net_handler_bitcoin.cpp | 12 ++++++++---- .../sidechain_net_handler_ethereum.cpp | 8 +++++--- .../sidechain_net_handler_hive.cpp | 8 +++++--- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/libraries/chain/son_wallet_evaluator.cpp b/libraries/chain/son_wallet_evaluator.cpp index 4eaba48f..138f8e57 100644 --- a/libraries/chain/son_wallet_evaluator.cpp +++ b/libraries/chain/son_wallet_evaluator.cpp @@ -98,7 +98,8 @@ void_result update_son_wallet_evaluator::do_evaluate(const son_wallet_update_ope FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." ); const auto& idx = db().get_index_type().indices().get(); - const auto id = (op.son_wallet_id.instance.value - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(op.sidechain))) / active_sidechain_types.size(); + const auto ast = active_sidechain_types(db().head_block_time()); + const auto id = (op.son_wallet_id.instance.value - std::distance(ast.begin(), ast.find(op.sidechain))) / ast.size(); const son_wallet_id_type son_wallet_id{ id }; FC_ASSERT( idx.find(son_wallet_id) != idx.end() ); //auto itr = idx.find(op.son_wallet_id); @@ -110,7 +111,8 @@ void_result update_son_wallet_evaluator::do_evaluate(const son_wallet_update_ope object_id_type update_son_wallet_evaluator::do_apply(const son_wallet_update_operation& op) { try { const auto& idx = db().get_index_type().indices().get(); - const auto id = (op.son_wallet_id.instance.value - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(op.sidechain))) / active_sidechain_types.size(); + const auto ast = active_sidechain_types(db().head_block_time()); + const auto id = (op.son_wallet_id.instance.value - std::distance(ast.begin(), ast.find(op.sidechain))) / ast.size(); const son_wallet_id_type son_wallet_id{ id }; auto itr = idx.find(son_wallet_id); if (itr != idx.end()) diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 4acd91e0..3f469cc8 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -448,7 +448,8 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) bool transaction_ok = false; std::string new_pw_address = ""; son_wallet_id_type swo_id = op_obj_idx_0.get().son_wallet_id; - const auto id = (swo_id.instance.value - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain))) / active_sidechain_types.size(); + const auto ast = active_sidechain_types(database.head_block_time()); + const auto id = (swo_id.instance.value - std::distance(ast.begin(), ast.find(sidechain))) / ast.size(); const son_wallet_id_type op_id{ id }; const auto &idx = database.get_index_type().indices().get(); const auto swo = idx.find(op_id); @@ -488,7 +489,8 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) if (po.proposed_transaction.operations.size() >= 2) { const object_id_type object_id = op_obj_idx_1.get().object_id; - const auto id = (object_id.instance() - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain))) / active_sidechain_types.size(); + const auto ast = active_sidechain_types(database.head_block_time()); + const auto id = (object_id.instance() - std::distance(ast.begin(), ast.find(sidechain))) / ast.size(); const object_id_type obj_id{ object_id.space(), object_id.type(), id }; std::string op_tx_str = op_obj_idx_1.get().transaction; @@ -720,7 +722,8 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { if ((active_sw->addresses.find(sidechain) == active_sw->addresses.end()) || (active_sw->addresses.at(sidechain).empty())) { - const auto id = active_sw->id.instance() * active_sidechain_types.size() + std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain)); + const auto ast = active_sidechain_types(database.head_block_time()); + const auto id = active_sw->id.instance() * ast.size() + std::distance(ast.begin(), ast.find(sidechain)); const object_id_type op_id{ active_sw->id.space(), active_sw->id.type(), id }; if (proposal_exists(chain::operation::tag::value, op_id)) { @@ -760,7 +763,8 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { std::string new_pw_address = active_pw_pt.get("result.address"); std::string tx_str = create_primary_wallet_transaction(*prev_sw, new_pw_address); if (!tx_str.empty()) { - const auto prev_id = prev_sw->id.instance() * active_sidechain_types.size() + std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain)); + const auto ast = active_sidechain_types(database.head_block_time()); + const auto prev_id = prev_sw->id.instance() * ast.size() + std::distance(ast.begin(), ast.find(sidechain)); const object_id_type prev_op_id{ prev_sw->id.space(), prev_sw->id.type(), prev_id }; sidechain_transaction_create_operation stc_op; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 3f912309..d0051714 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -234,7 +234,8 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) bool address_ok = false; bool transaction_ok = false; const son_wallet_id_type swo_id = op_obj_idx_0.get().son_wallet_id; - const auto id = (swo_id.instance.value - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain))) / active_sidechain_types.size(); + const auto ast = active_sidechain_types(database.head_block_time()); + const auto id = (swo_id.instance.value - std::distance(ast.begin(), ast.find(sidechain))) / ast.size(); const son_wallet_id_type op_id{ id }; const auto &idx = database.get_index_type().indices().get(); const auto swo = idx.find(op_id); @@ -257,7 +258,7 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) if (po.proposed_transaction.operations.size() >= 2) { const object_id_type object_id = op_obj_idx_1.get().object_id; - const auto id = (object_id.instance() - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain))) / active_sidechain_types.size(); + const auto id = (object_id.instance() - std::distance(ast.begin(), ast.find(sidechain))) / ast.size(); const object_id_type obj_id{ object_id.space(), object_id.type(), id }; const std::string op_tx_str = op_obj_idx_1.get().transaction; @@ -456,7 +457,8 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { if ((active_sw->addresses.find(sidechain) == active_sw->addresses.end()) || (active_sw->addresses.at(sidechain).empty())) { - const auto id = active_sw->id.instance() * active_sidechain_types.size() + std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain)); + const auto ast = active_sidechain_types(database.head_block_time()); + const auto id = active_sw->id.instance() * ast.size() + std::distance(ast.begin(), ast.find(sidechain)); const object_id_type op_id{ active_sw->id.space(), active_sw->id.type(), id }; if (proposal_exists(chain::operation::tag::value, op_id)) { diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp index 2932e5f3..3f1378e7 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp @@ -209,7 +209,8 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { bool address_ok = false; bool transaction_ok = false; son_wallet_id_type swo_id = op_obj_idx_0.get().son_wallet_id; - const auto id = (swo_id.instance.value - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain))) / active_sidechain_types.size(); + const auto ast = active_sidechain_types(database.head_block_time()); + const auto id = (swo_id.instance.value - std::distance(ast.begin(), ast.find(sidechain))) / ast.size(); const son_wallet_id_type op_id{ id }; const auto &idx = database.get_index_type().indices().get(); const auto swo = idx.find(op_id); @@ -232,7 +233,7 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { if (po.proposed_transaction.operations.size() >= 2) { const object_id_type object_id = op_obj_idx_1.get().object_id; - const auto id = (object_id.instance() - std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain))) / active_sidechain_types.size(); + const auto id = (object_id.instance() - std::distance(ast.begin(), ast.find(sidechain))) / ast.size(); const object_id_type obj_id{ object_id.space(), object_id.type(), id }; std::string op_tx_str = op_obj_idx_1.get().transaction; @@ -490,7 +491,8 @@ void sidechain_net_handler_hive::process_primary_wallet() { if ((active_sw->addresses.find(sidechain) == active_sw->addresses.end()) || (active_sw->addresses.at(sidechain).empty())) { - const auto id = active_sw->id.instance() * active_sidechain_types.size() + std::distance(active_sidechain_types.begin(), active_sidechain_types.find(sidechain)); + const auto ast = active_sidechain_types(database.head_block_time()); + const auto id = active_sw->id.instance() * ast.size() + std::distance(ast.begin(), ast.find(sidechain)); const object_id_type op_id{ active_sw->id.space(), active_sw->id.type(), id }; if (proposal_exists(chain::operation::tag::value, op_id)) { From 936f13d2a1e6fbda61270c496e230a167cd13dde Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Mon, 6 Feb 2023 08:14:05 +0200 Subject: [PATCH 5/8] #506 - fix load fees from genesis file --- libraries/chain/db_init.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 2e296e39..05326d16 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -1168,6 +1168,11 @@ void database::init_genesis(const genesis_state_type& genesis_state) }); assert( ssohive.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::hive)) ); + // Enable fees + modify(get_global_properties(), [&genesis_state](global_property_object& p) { + p.parameters.current_fees = genesis_state.initial_parameters.current_fees; + }); + // Create FBA counters create([&]( fba_accumulator_object& acc ) { From 73b2ba635b5b98e3e64e96b63b78484f3881ebbd Mon Sep 17 00:00:00 2001 From: hirunda Date: Mon, 6 Feb 2023 21:09:28 +0100 Subject: [PATCH 6/8] Fix the issue for wrong number of signers --- libraries/chain/sidechain_transaction_evaluator.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/chain/sidechain_transaction_evaluator.cpp b/libraries/chain/sidechain_transaction_evaluator.cpp index 14b5ecea..b0d1a494 100644 --- a/libraries/chain/sidechain_transaction_evaluator.cpp +++ b/libraries/chain/sidechain_transaction_evaluator.cpp @@ -34,7 +34,6 @@ object_id_type sidechain_transaction_create_evaluator::do_apply(const sidechain_ sto.object_id = op.object_id; sto.transaction = op.transaction; std::vector signers; - signers.resize(op.signers.size()); for(const auto& signer : op.signers){ son_sidechain_info ssi; ssi.son_id = signer.son_id; From e9c7021e161cb63e206dbc957fd64cb3f55afb6d Mon Sep 17 00:00:00 2001 From: Davor Hirunda Date: Mon, 6 Feb 2023 22:48:40 +0000 Subject: [PATCH 7/8] Bitcoin SON based on libbitcoin --- Dockerfile | 96 ++- Dockerfile.18.04 | 94 ++- README.md | 152 ++-- libraries/app/database_api.cpp | 2 +- .../peerplays_sidechain/CMakeLists.txt | 4 +- .../bitcoin/bitcoin_address.cpp | 58 +- .../bitcoin/estimate_fee_external.cpp | 157 ++++ .../bitcoin/libbitcoin_client.cpp | 227 ++++++ .../bitcoin/bitcoin_address.hpp | 15 +- .../bitcoin/estimate_fee_external.hpp | 37 + .../bitcoin/libbitcoin_client.hpp | 53 ++ .../peerplays_sidechain/bitcoin/utils.hpp | 1 + .../sidechain_net_handler.hpp | 1 + .../sidechain_net_handler_bitcoin.hpp | 157 +++- .../peerplays_sidechain_plugin.cpp | 20 +- .../sidechain_net_handler_bitcoin.cpp | 729 +++++++++++++----- .../sidechain_net_handler_ethereum.cpp | 10 +- .../sidechain_net_handler_hive.cpp | 6 +- 18 files changed, 1396 insertions(+), 423 deletions(-) mode change 100755 => 100644 libraries/plugins/peerplays_sidechain/CMakeLists.txt create mode 100644 libraries/plugins/peerplays_sidechain/bitcoin/estimate_fee_external.cpp create mode 100644 libraries/plugins/peerplays_sidechain/bitcoin/libbitcoin_client.cpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/estimate_fee_external.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/libbitcoin_client.hpp diff --git a/Dockerfile b/Dockerfile index 3f4c62b5..d49bbe08 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,4 @@ FROM ubuntu:20.04 -MAINTAINER Peerplays Blockchain Standards Association #=============================================================================== # Ubuntu setup @@ -51,69 +50,102 @@ RUN echo 'peerplays:peerplays' | chpasswd # SSH EXPOSE 22 +WORKDIR /home/peerplays/src + #=============================================================================== # Boost setup #=============================================================================== -WORKDIR /home/peerplays/ - RUN \ - wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \ - tar -xzvf boost_1_72_0.tar.gz boost_1_72_0 && \ - cd boost_1_72_0/ && \ + wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \ + tar -xzf boost_1_72_0.tar.gz && \ + cd boost_1_72_0 && \ ./bootstrap.sh && \ - ./b2 install + ./b2 install && \ + ldconfig && \ + rm -rf /home/peerplays/src/* #=============================================================================== # cmake setup #=============================================================================== -WORKDIR /home/peerplays/ - RUN \ - wget -c 'https://cmake.org/files/v3.23/cmake-3.23.1-linux-x86_64.sh' -O cmake-3.23.1-linux-x86_64.sh && \ - chmod 755 ./cmake-3.23.1-linux-x86_64.sh && \ - ./cmake-3.23.1-linux-x86_64.sh --prefix=/usr/ --skip-license && \ - cmake --version + wget https://github.com/Kitware/CMake/releases/download/v3.24.2/cmake-3.24.2-linux-x86_64.sh && \ + chmod 755 ./cmake-3.24.2-linux-x86_64.sh && \ + ./cmake-3.24.2-linux-x86_64.sh --prefix=/usr --skip-license && \ + cmake --version && \ + rm -rf /home/peerplays/src/* #=============================================================================== # libzmq setup #=============================================================================== -WORKDIR /home/peerplays/ - RUN \ - wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip && \ - unzip v4.3.4.zip && \ + wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.tar.gz && \ + tar -xzvf v4.3.4.tar.gz && \ cd libzmq-4.3.4 && \ mkdir build && \ cd build && \ cmake .. && \ - make -j$(nproc) install && \ - ldconfig + make -j$(nproc) && \ + make install && \ + ldconfig && \ + rm -rf /home/peerplays/src/* #=============================================================================== # cppzmq setup #=============================================================================== -WORKDIR /home/peerplays/ - RUN \ - wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.8.1.zip && \ - unzip v4.8.1.zip && \ - cd cppzmq-4.8.1 && \ + wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.9.0.tar.gz && \ + tar -xzvf v4.9.0.tar.gz && \ + cd cppzmq-4.9.0 && \ mkdir build && \ cd build && \ cmake .. && \ - make -j$(nproc) install && \ - ldconfig + make -j$(nproc) && \ + make install && \ + ldconfig && \ + rm -rf /home/peerplays/src/* + +#=============================================================================== +# gsl setup +#=============================================================================== + +RUN \ + DEBIAN_FRONTEND=noninteractive apt-get install -y \ + libpcre3-dev + +RUN \ + wget https://github.com/imatix/gsl/archive/refs/tags/v4.1.4.tar.gz && \ + tar -xzvf v4.1.4.tar.gz && \ + cd gsl-4.1.4 && \ + make -j$(nproc) && \ + make install && \ + rm -rf /home/peerplays/src/* + +#=============================================================================== +# libbitcoin-build setup +# libbitcoin-explorer setup +#=============================================================================== + +RUN \ + DEBIAN_FRONTEND=noninteractive apt-get install -y \ + libsodium-dev + +RUN \ + git clone https://github.com/libbitcoin/libbitcoin-build.git && \ + cd libbitcoin-build && \ + ./generate3.sh && \ + cd ../libbitcoin-explorer && \ + ./install.sh && \ + ldconfig && \ + rm -rf /home/peerplays/src/* #=============================================================================== # Doxygen setup #=============================================================================== -WORKDIR /home/peerplays/ - RUN \ sudo apt install -y bison flex && \ wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \ @@ -129,8 +161,6 @@ RUN \ # Perl setup #=============================================================================== -WORKDIR /home/peerplays/ - RUN \ wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \ tar -xvf v5.30.0.tar.gz && \ @@ -143,8 +173,6 @@ RUN \ # Peerplays setup #=============================================================================== -WORKDIR /home/peerplays/ - ## Clone Peerplays #RUN \ # git clone https://gitlab.com/PBSA/peerplays.git && \ @@ -176,8 +204,8 @@ WORKDIR /home/peerplays/peerplays-network # Setup Peerplays runimage RUN \ - ln -s /home/peerplays/peerplays/build/programs/cli_wallet/cli_wallet ./ && \ - ln -s /home/peerplays/peerplays/build/programs/witness_node/witness_node ./ + ln -s /home/peerplays/src/peerplays/build/programs/cli_wallet/cli_wallet ./ && \ + ln -s /home/peerplays/src/peerplays/build/programs/witness_node/witness_node ./ RUN ./witness_node --create-genesis-json genesis.json && \ rm genesis.json diff --git a/Dockerfile.18.04 b/Dockerfile.18.04 index 2e153962..d09e01b2 100644 --- a/Dockerfile.18.04 +++ b/Dockerfile.18.04 @@ -1,5 +1,4 @@ FROM ubuntu:18.04 -MAINTAINER Peerplays Blockchain Standards Association #=============================================================================== # Ubuntu setup @@ -51,69 +50,102 @@ RUN echo 'peerplays:peerplays' | chpasswd # SSH EXPOSE 22 +WORKDIR /home/peerplays/src + #=============================================================================== # Boost setup #=============================================================================== -WORKDIR /home/peerplays/ - RUN \ wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \ - tar -xzvf boost_1_72_0.tar.gz boost_1_72_0 && \ - cd boost_1_72_0/ && \ + tar -xzf boost_1_72_0.tar.gz && \ + cd boost_1_72_0 && \ ./bootstrap.sh && \ - ./b2 install + ./b2 install && \ + ldconfig && \ + rm -rf /home/peerplays/src/* #=============================================================================== # cmake setup #=============================================================================== -WORKDIR /home/peerplays/ - RUN \ - wget -c 'https://cmake.org/files/v3.23/cmake-3.23.1-linux-x86_64.sh' -O cmake-3.23.1-linux-x86_64.sh && \ - chmod 755 ./cmake-3.23.1-linux-x86_64.sh && \ - ./cmake-3.23.1-linux-x86_64.sh --prefix=/usr/ --skip-license && \ - cmake --version + wget https://github.com/Kitware/CMake/releases/download/v3.24.2/cmake-3.24.2-linux-x86_64.sh && \ + chmod 755 ./cmake-3.24.2-linux-x86_64.sh && \ + ./cmake-3.24.2-linux-x86_64.sh --prefix=/usr --skip-license && \ + cmake --version && \ + rm -rf /home/peerplays/src/* #=============================================================================== # libzmq setup #=============================================================================== -WORKDIR /home/peerplays/ - RUN \ - wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip && \ - unzip v4.3.4.zip && \ + wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.tar.gz && \ + tar -xzvf v4.3.4.tar.gz && \ cd libzmq-4.3.4 && \ mkdir build && \ cd build && \ cmake .. && \ - make -j$(nproc) install && \ - ldconfig + make -j$(nproc) && \ + make install && \ + ldconfig && \ + rm -rf /home/peerplays/src/* #=============================================================================== # cppzmq setup #=============================================================================== -WORKDIR /home/peerplays/ - RUN \ - wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.8.1.zip && \ - unzip v4.8.1.zip && \ - cd cppzmq-4.8.1 && \ + wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.9.0.tar.gz && \ + tar -xzvf v4.9.0.tar.gz && \ + cd cppzmq-4.9.0 && \ mkdir build && \ cd build && \ cmake .. && \ - make -j$(nproc) install && \ - ldconfig + make -j$(nproc) && \ + make install && \ + ldconfig && \ + rm -rf /home/peerplays/src/* + +#=============================================================================== +# gsl setup +#=============================================================================== + +RUN \ + DEBIAN_FRONTEND=noninteractive apt-get install -y \ + libpcre3-dev + +RUN \ + wget https://github.com/imatix/gsl/archive/refs/tags/v4.1.4.tar.gz && \ + tar -xzvf v4.1.4.tar.gz && \ + cd gsl-4.1.4 && \ + make -j$(nproc) && \ + make install && \ + rm -rf /home/peerplays/src/* + +#=============================================================================== +# libbitcoin-build setup +# libbitcoin-explorer setup +#=============================================================================== + +RUN \ + DEBIAN_FRONTEND=noninteractive apt-get install -y \ + libsodium-dev + +RUN \ + git clone https://github.com/libbitcoin/libbitcoin-build.git && \ + cd libbitcoin-build && \ + ./generate3.sh && \ + cd ../libbitcoin-explorer && \ + ./install.sh && \ + ldconfig && \ + rm -rf /home/peerplays/src/* #=============================================================================== # Doxygen setup #=============================================================================== -WORKDIR /home/peerplays/ - RUN \ sudo apt install -y bison flex && \ wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \ @@ -129,8 +161,6 @@ RUN \ # Perl setup #=============================================================================== -WORKDIR /home/peerplays/ - RUN \ wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \ tar -xvf v5.30.0.tar.gz && \ @@ -143,8 +173,6 @@ RUN \ # Peerplays setup #=============================================================================== -WORKDIR /home/peerplays/ - ## Clone Peerplays #RUN \ # git clone https://gitlab.com/PBSA/peerplays.git && \ @@ -176,8 +204,8 @@ WORKDIR /home/peerplays/peerplays-network # Setup Peerplays runimage RUN \ - ln -s /home/peerplays/peerplays/build/programs/cli_wallet/cli_wallet ./ && \ - ln -s /home/peerplays/peerplays/build/programs/witness_node/witness_node ./ + ln -s /home/peerplays/src/peerplays/build/programs/cli_wallet/cli_wallet ./ && \ + ln -s /home/peerplays/src/peerplays/build/programs/witness_node/witness_node ./ RUN ./witness_node --create-genesis-json genesis.json && \ rm genesis.json diff --git a/README.md b/README.md index f3d8c5b9..c3533d29 100644 --- a/README.md +++ b/README.md @@ -8,100 +8,41 @@ This is a quick introduction to get new developers and witnesses up to speed on Officially supported OS are Ubuntu 20.04 and Ubuntu 18.04. -## Ubuntu 20.04 +## Ubuntu 20.04 and 18.04 -Following dependencies are needed for a clean install of Ubuntu 20.04: +Following dependencies are needed for a clean install of Ubuntu 20.04 and Ubuntu 18.04: ``` sudo apt-get install \ - apt-utils autoconf bash build-essential ca-certificates clang-format cmake \ - dnsutils doxygen expect git graphviz libboost-all-dev libbz2-dev \ - libcurl4-openssl-dev libncurses-dev libsnappy-dev \ - libssl-dev libtool libzip-dev locales lsb-release mc nano net-tools ntp \ - openssh-server pkg-config perl python3 python3-jinja2 sudo \ + autoconf bash bison build-essential ca-certificates dnsutils expect flex git \ + graphviz libbz2-dev libcurl4-openssl-dev libncurses-dev libpcre3-dev \ + libsnappy-dev libsodium-dev libssl-dev libtool libzip-dev locales lsb-release \ + mc nano net-tools ntp openssh-server pkg-config python3 python3-jinja2 sudo \ systemd-coredump wget ``` -Install libzmq from source: +Boost libraries setup: ``` -wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip -unzip v4.3.4.zip -cd libzmq-4.3.4 -mkdir build -cd build -cmake .. -make -j$(nproc) -sudo make install -sudo ldconfig -``` - -Install cppzmq from source: -``` -wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.8.1.zip -unzip v4.8.1.zip -cd cppzmq-4.8.1 -mkdir build -cd build -cmake .. -make -j$(nproc) -sudo make install -sudo ldconfig -``` - -Building Peerplays -``` -git clone https://gitlab.com/PBSA/peerplays.git -cd peerplays -git submodule update --init --recursive - -# If you want to build Mainnet node -cmake -DCMAKE_BUILD_TYPE=Release - -# If you want to build Testnet node -cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_PEERPLAYS_TESTNET=1 - -# Update -j flag depending on your current system specs; -# Recommended 4GB of RAM per 1 CPU core -# make -j2 for 8GB RAM -# make -j4 for 16GB RAM -# make -j8 for 32GB RAM -make -j$(nproc) - -sudo make install # this can install the executable files under /usr/local -``` - -## Ubuntu 18.04 - -Following dependencies are needed for a clean install of Ubuntu 18.04: -``` -sudo apt-get install \ - apt-utils autoconf bash build-essential ca-certificates clang-format \ - dnsutils doxygen expect git graphviz libbz2-dev \ - libcurl4-openssl-dev libncurses-dev libsnappy-dev \ - libssl-dev libtool libzip-dev locales lsb-release mc nano net-tools ntp \ - openssh-server pkg-config perl python3 python3-jinja2 sudo \ - systemd-coredump wget -``` - -Install Boost libraries from source -``` -wget -c 'https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/boost_1_71_0.tar.bz2' -O boost_1_71_0.tar.bz2 -tar xjf boost_1_71_0.tar.bz2 -cd boost_1_71_0/ +wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz +tar -xzf boost_1_72_0.tar.gz boost_1_72_0 +cd boost_1_72_0 ./bootstrap.sh +./b2 sudo ./b2 install +sudo ldconfig ``` -Install cmake +cmake setup: ``` -wget -c 'https://cmake.org/files/v3.23/cmake-3.23.1-linux-x86_64.sh' -O cmake-3.23.1-linux-x86_64.sh -chmod 755 ./cmake-3.23.1-linux-x86_64.sh -sudo ./cmake-3.23.1-linux-x86_64.sh --prefix=/usr/ --skip-license +wget https://github.com/Kitware/CMake/releases/download/v3.24.2/cmake-3.24.2-linux-x86_64.sh +chmod 755 ./cmake-3.24.2-linux-x86_64.sh +sudo ./cmake-3.24.2-linux-x86_64.sh --prefix=/usr --skip-license +cmake --version ``` -Install libzmq from source: +libzmq setup: ``` -wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.zip -unzip v4.3.4.zip +wget https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.4.tar.gz +tar -xzvf v4.3.4.tar.gz cd libzmq-4.3.4 mkdir build cd build @@ -111,11 +52,11 @@ sudo make install sudo ldconfig ``` -Install cppzmq from source: +cppzmq setup: ``` -wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.8.1.zip -unzip v4.8.1.zip -cd cppzmq-4.8.1 +wget https://github.com/zeromq/cppzmq/archive/refs/tags/v4.9.0.tar.gz +tar -xzvf v4.9.0.tar.gz +cd cppzmq-4.9.0 mkdir build cd build cmake .. @@ -124,6 +65,50 @@ sudo make install sudo ldconfig ``` +gsl setup: +``` +wget https://github.com/imatix/gsl/archive/refs/tags/v4.1.4.tar.gz +tar -xzvf v4.1.4.tar.gz +cd gsl-4.1.4 +make -j$(nproc) +sudo make install +sudo ldconfig +``` + +libbitcoin-explorer setup: +``` +git clone https://github.com/libbitcoin/libbitcoin-build.git +cd libbitcoin-build +./generate3.sh +cd ../libbitcoin-explorer +sudo ./install.sh +sudo ldconfig +``` + +Doxygen setup: +``` +wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz +tar -xvf Release_1_8_17.tar.gz +cd doxygen-Release_1_8_17 +mkdir build +cd build +cmake .. +make -j$(nproc) +sudo make install +sudo ldconfig +``` + +Perl setup: +``` +wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz +tar -xvf v5.30.0.tar.gz +cd perl5-5.30.0 +./Configure -des +make -j$(nproc) +sudo make install +sudo ldconfig +``` + Building Peerplays ``` git clone https://gitlab.com/PBSA/peerplays.git @@ -146,7 +131,6 @@ make -j$(nproc) sudo make install # this can install the executable files under /usr/local ``` - ## Docker images Install docker, and add current user to docker group. diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index c4e69607..be60de78 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -2340,7 +2340,7 @@ votes_info database_api_impl::get_votes(const string &account_name_or_id) const votes_for_sons[sidechain].reserve(sidechain_ids.size()); for (const auto &son : sidechain_ids) { const auto &son_obj = son.as(6); - if(son_obj.get_sidechain_vote_id(sidechain).valid()) { + if (son_obj.get_sidechain_vote_id(sidechain).valid()) { votes_for_sons[sidechain].emplace_back(votes_info_object{*son_obj.get_sidechain_vote_id(sidechain), son_obj.id}); } } diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt old mode 100755 new mode 100644 index 4f724602..21fac167 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -16,6 +16,8 @@ add_library( peerplays_sidechain bitcoin/segwit_addr.cpp bitcoin/utils.cpp bitcoin/sign_bitcoin_transaction.cpp + bitcoin/libbitcoin_client.cpp + bitcoin/estimate_fee_external.cpp common/rpc_client.cpp common/utils.cpp ethereum/encoders.cpp @@ -42,7 +44,7 @@ endif() unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS) 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 sha3 zmq bitcoin-system bitcoin-protocol bitcoin-client bitcoin-explorer ) target_include_directories( peerplays_sidechain PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_address.cpp b/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_address.cpp index 69b28ee1..4eb9803d 100644 --- a/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_address.cpp +++ b/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_address.cpp @@ -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> &keys_data, - network ntype) { + network ntype, payment_type type) { network_type = ntype; + this->type = type; create_redeem_script(keys_data); create_witness_script(); create_segwit_address(); - type = payment_type::P2WSH; } void btc_weighted_multisig_address::create_redeem_script(const std::vector> &keys_data) { @@ -278,26 +278,43 @@ void btc_weighted_multisig_address::create_witness_script() { script_builder builder; builder << op::_0; builder << fc::sha256::hash(redeem_script_.data(), redeem_script_.size()); - witness_script_ = builder; } void btc_weighted_multisig_address::create_segwit_address() { std::string hrp; + address_types byte_version; switch (network_type) { case (network::mainnet): hrp = "bc"; + byte_version = address_types::MAINNET_SCRIPT; break; case (network::testnet): hrp = "tb"; + byte_version = address_types::TESTNET_SCRIPT; break; case (network::regtest): hrp = "bcrt"; + byte_version = address_types::TESTNET_SCRIPT; break; } - fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size()); - std::vector hash_data(sh.data(), sh.data() + sh.data_size()); - address = segwit_addr::encode(hrp, 0, hash_data); + + if (type == payment_type::P2WSH) { + fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size()); + std::vector 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, @@ -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, const std::vector> &keys_data, - bitcoin_address::network ntype) { + bitcoin_address::network ntype, payment_type type) { network_type = ntype; + this->type = type; create_redeem_script(user_key_data, keys_data); create_witness_script(); 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> &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() { std::string hrp; + address_types byte_version; switch (network_type) { case (network::mainnet): + byte_version = address_types::MAINNET_SCRIPT; hrp = "bc"; break; case (network::testnet): + byte_version = address_types::TESTNET_SCRIPT; hrp = "tb"; break; case (network::regtest): + byte_version = address_types::TESTNET_SCRIPT; hrp = "bcrt"; break; } - fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size()); - std::vector hash_data(sh.data(), sh.data() + sh.data_size()); - address = segwit_addr::encode(hrp, 0, hash_data); + + if (type == payment_type::P2WSH) { + fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size()); + std::vector 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> &keys_data, bitcoin_address::network ntype) : diff --git a/libraries/plugins/peerplays_sidechain/bitcoin/estimate_fee_external.cpp b/libraries/plugins/peerplays_sidechain/bitcoin/estimate_fee_external.cpp new file mode 100644 index 00000000..7ae350e7 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/bitcoin/estimate_fee_external.cpp @@ -0,0 +1,157 @@ + +#include + +#include +#include + +#include + +#include + +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); +} + +std::vector> estimate_fee_external::get_fee_external(uint16_t target_block) { + + std::vector> estimate_fee_external_collection; + 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(); + std::string url_str = url_fee_parser.first; + if (fee != 0) { + estimate_fee_external_collection.emplace_back(std::make_pair(url_fee_parser.first, fee)); + } + } + + return estimate_fee_external_collection; +} + +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 / 30; + + 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 \ No newline at end of file diff --git a/libraries/plugins/peerplays_sidechain/bitcoin/libbitcoin_client.cpp b/libraries/plugins/peerplays_sidechain/bitcoin/libbitcoin_client.cpp new file mode 100644 index 00000000..fdcaa98e --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/bitcoin/libbitcoin_client.cpp @@ -0,0 +1,227 @@ + +#include + +#include + +#include +#include + +#include + +#include +#include + +namespace graphene { namespace peerplays_sidechain { + +libbitcoin_client::libbitcoin_client(std::string url) : + obelisk_client(LIBBITCOIN_SERVER_TIMEOUT, LIBBITCOIN_SERVER_RETRIES) { + + std::string reg_expr = "^((?Phttps|http|tcp):\\/\\/)?(?P[a-zA-Z0-9\\-\\.]+)(:(?P\\d{1,5}))?(?P\\/.+)?"; + 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 libbitcoin_client::listunspent(std::string address, double amount) { + std::vector 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; +} + +uint64_t libbitcoin_client::get_fee_from_trx(libbitcoin::chain::transaction trx) { + bool general_fee_est_error = false; + + if (trx.is_coinbase()) { + return 0; + } + + const auto total_output_value = trx.total_output_value(); + // get the inputs and from inputs previous outputs + std::map> prev_out_trxs; + for (auto &ins : trx.inputs()) { + const auto &prev_out = ins.previous_output(); + prev_out_trxs[prev_out.hash()].emplace_back(prev_out.index()); + } + + // fetch the trx to get total input value + uint64_t total_input_value = 0; + auto transaction_handler = [&](const libbitcoin::chain::transaction &tx_handler) { + std::vector indexes = prev_out_trxs[tx_handler.hash()]; + + for (auto &index : indexes) { + total_input_value += tx_handler.outputs()[index].value(); + } + }; + + auto error_handler = [&](const std::error_code &ec) { + elog("error on fetching trx ${error_code}", ("error_code", ec.message())); + general_fee_est_error = true; + }; + + for (const auto &iter : prev_out_trxs) { + if (general_fee_est_error) { + break; + } + + obelisk_client.blockchain_fetch_transaction2(error_handler, transaction_handler, iter.first); + obelisk_client.wait(); + } + + if (total_input_value >= total_output_value) { + return total_input_value - total_output_value; + } else { + // something is really wrong if this happens,so we are going to mark as an error + elog("On fee estimation something is wrong in total inputs and total outputs for trx hash: ${hash}", + ("hash", libbitcoin::config::hash256(trx.hash()).to_string())); + return 0; + } +} + +uint64_t libbitcoin_client::get_average_fee_from_trxs(std::vector trx_list) { + std::vector fee_per_trxs; + + for (auto &trx : trx_list) { + + uint64_t fee = get_fee_from_trx(trx); + if (fee > 0) { + fee_per_trxs.emplace_back(fee); + } + } + + uint64_t average_estimated_fee = 0; + + if (fee_per_trxs.size()) { + for (const auto &fee : fee_per_trxs) { + average_estimated_fee += fee; + } + + average_estimated_fee /= fee_per_trxs.size(); + } + + return average_estimated_fee; +} +}} // namespace graphene::peerplays_sidechain \ No newline at end of file diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/bitcoin_address.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/bitcoin_address.hpp index b9467e2f..04762352 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/bitcoin_address.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/bitcoin_address.hpp @@ -8,6 +8,14 @@ using namespace graphene::chain; 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 +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 { @@ -96,9 +104,6 @@ private: void create_address(); public: - enum address_types { MAINNET_SCRIPT = 5, - TESTNET_SCRIPT = 196 }; - enum { OP_0 = 0x00, OP_EQUAL = 0x87, OP_HASH160 = 0xa9, @@ -145,7 +150,7 @@ public: btc_weighted_multisig_address() = default; btc_weighted_multisig_address(const std::vector> &keys_data, - network network_type = network::regtest); + network network_type = network::regtest, payment_type type = payment_type::P2SH_WSH); bytes get_redeem_script() const { return redeem_script_; @@ -190,7 +195,7 @@ class btc_one_or_weighted_multisig_address : public bitcoin_address { public: btc_one_or_weighted_multisig_address() = default; btc_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, const std::vector> &keys_data, - network network_type = network::regtest); + network network_type = network::regtest, payment_type type = payment_type::P2SH_WSH); bytes get_redeem_script() const { return redeem_script_; } diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/estimate_fee_external.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/estimate_fee_external.hpp new file mode 100644 index 00000000..10be2868 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/estimate_fee_external.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include +#include +#include + +typedef std::function get_fee_func_type; + +namespace graphene { namespace peerplays_sidechain { + +class estimate_fee_external { +public: + estimate_fee_external(); + ~estimate_fee_external(); + std::vector> 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 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 \ No newline at end of file diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/libbitcoin_client.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/libbitcoin_client.hpp new file mode 100644 index 00000000..4426983a --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/libbitcoin_client.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#define LIBBITCOIN_SERVER_TIMEOUT (10) +#define LIBBITCOIN_SERVER_RETRIES (100) +#define DEAFULT_LIBBITCOIN_TRX_FEE (20000) +#define MAX_TRXS_IN_MEMORY_POOL (30000) +#define MIN_TRXS_IN_BUCKET (100) + +#define GENESIS_MAINNET_HASH "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" +#define GENESIS_TESTNET_HASH "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943" +#define GENESIS_REGTEST_HASH "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206" + +namespace graphene { namespace peerplays_sidechain { + +typedef std::function + 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 listunspent(std::string address, double amount); + uint64_t get_average_fee_from_trxs(std::vector trx_list); + uint64_t get_fee_from_trx(libbitcoin::chain::transaction trx); + 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 \ No newline at end of file diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/utils.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/utils.hpp index 4e1c4b58..5f582eb1 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/utils.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/utils.hpp @@ -1,4 +1,5 @@ #pragma once + #include #include #include diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp index 0e7e2fc1..836a1f05 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp @@ -59,6 +59,7 @@ protected: sidechain_type sidechain; bool debug_rpc_calls; + bool use_bitcoind_client; std::map private_keys; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp index e880a7ae..bfb93805 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp @@ -1,18 +1,20 @@ #pragma once -#include #include +#include #include #include #include #include -#include - #include + #include +#include +#include +#include namespace graphene { namespace peerplays_sidechain { @@ -23,7 +25,27 @@ public: uint64_t amount_; }; -class bitcoin_rpc_client : public rpc_client { +class btc_txin { +public: + std::vector tx_address; + uint64_t tx_amount; + uint64_t tx_vout; +}; + +class btc_tx { +public: + std::string tx_txid; + uint32_t tx_confirmations; + std::vector tx_in_list; +}; + +class block_data { +public: + std::string block_hash; + libbitcoin::chain::block block; +}; + +class bitcoin_client_base { public: enum class multi_type { script, @@ -41,14 +63,47 @@ public: std::string label; }; + virtual uint64_t estimatesmartfee(uint16_t conf_target = 1) = 0; + virtual std::vector 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() = 0; + virtual std::string getblockchaininfo() = 0; + virtual std::vector 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 &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; + }; + + void import_trx_to_memory_pool(const libbitcoin::chain::transaction &trx) { + std::unique_lock lck(libbitcoin_event_mutex); + if (trx_memory_pool.size() < MAX_TRXS_IN_MEMORY_POOL) { + trx_memory_pool.emplace_back(trx); + } + } + +protected: + std::vector trx_memory_pool; + std::mutex libbitcoin_event_mutex; +}; + +class bitcoin_rpc_client : public bitcoin_client_base, public rpc_client { +public: public: 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); - std::string getblock(const std::string &block_hash, int32_t verbosity = 2); - std::string getrawtransaction(const std::string &txid, const bool verbose = false); - std::string getnetworkinfo(); + uint64_t estimatesmartfee(uint16_t conf_target = 1); + std::vector getblock(const block_data &block, int32_t verbosity = 2); + btc_tx getrawtransaction(const std::string &txid, const bool verbose = false); + void getnetworkinfo(); std::string getblockchaininfo(); void importmulti(const std::vector &address_or_script_array, const bool rescan = true); std::vector listunspent(const uint32_t minconf = 1, const uint32_t maxconf = 9999999); @@ -60,35 +115,84 @@ public: private: std::string ip; - uint32_t rpc_port; std::string user; std::string password; std::string wallet_name; 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 = 1); + std::vector getblock(const block_data &block, int32_t verbosity = 2); + btc_tx getrawtransaction(const std::string &txid, const bool verbose = false); + void getnetworkinfo(); + std::string getblockchaininfo(); + std::vector 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_ext; + uint64_t current_internal_fee = DEAFULT_LIBBITCOIN_TRX_FEE; }; // ============================================================================= -class zmq_listener { +class zmq_listener_base { public: - zmq_listener(std::string _ip, uint32_t _zmq); - virtual ~zmq_listener(); + virtual ~zmq_listener_base(){}; + zmq_listener_base(std::string _ip, uint32_t _block_zmq_port, uint32_t _trx_zmq_port = 0) { + ip = _ip; + block_zmq_port = _block_zmq_port; + trx_zmq_port = _trx_zmq_port; + stopped = false; + }; + virtual void start() = 0; + boost::signals2::signal block_event_received; + boost::signals2::signal trx_event_received; +protected: + std::string ip; + uint32_t block_zmq_port; + uint32_t trx_zmq_port; + std::atomic_bool stopped; + std::thread block_thr; + std::thread trx_thr; +}; + +class zmq_listener : public zmq_listener_base { +public: + zmq_listener(std::string _ip, uint32_t _block_zmq_port, uint32_t _trx_zmq_port = 0); + virtual ~zmq_listener(); void start(); - boost::signals2::signal event_received; private: void handle_zmq(); std::vector receive_multipart(); - std::string ip; - uint32_t zmq_port; - zmq::context_t ctx; zmq::socket_t socket; +}; - std::atomic_bool stopped; - std::thread thr; +class zmq_listener_libbitcoin : public zmq_listener_base { +public: + zmq_listener_libbitcoin(std::string _ip, uint32_t _block_zmq_port = 9093, uint32_t _trx_zmq_port = 9094); + virtual ~zmq_listener_libbitcoin(); + void start(); + +private: + void handle_block(); + void handle_trx(); + + libbitcoin::protocol::zmq::context block_context; + libbitcoin::protocol::zmq::socket block_socket; + libbitcoin::protocol::zmq::poller block_poller; + libbitcoin::protocol::zmq::context trx_context; + libbitcoin::protocol::zmq::socket trx_socket; + libbitcoin::protocol::zmq::poller trx_poller; }; // ============================================================================= @@ -109,16 +213,19 @@ public: virtual optional estimate_withdrawal_transaction_fee() const override; private: - std::string ip; - uint32_t zmq_port; + std::string bitcoin_node_ip; + std::string libbitcoin_server_ip; + uint32_t libbitcoin_block_zmq_port; + uint32_t libbitcoin_trx_zmq_port; + uint32_t bitcoin_node_zmq_port; uint32_t rpc_port; std::string rpc_user; std::string rpc_password; std::string wallet_name; std::string wallet_password; - std::unique_ptr bitcoin_client; - std::unique_ptr listener; + std::unique_ptr bitcoin_client; + std::unique_ptr listener; fc::future on_changed_objects_task; @@ -138,9 +245,9 @@ private: std::string sign_transaction(const sidechain_transaction_object &sto); std::string send_transaction(const sidechain_transaction_object &sto); - void handle_event(const std::string &event_data); + void block_handle_event(const block_data &event_data); + void trx_handle_event(const libbitcoin::chain::transaction &event_data); std::string get_redeemscript_for_userdeposit(const std::string &user_address); - std::vector extract_info_from_block(const std::string &_block); void on_changed_objects(const vector &ids, const flat_set &accounts); void on_changed_objects_cb(const vector &ids, const flat_set &accounts); }; diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index bd5bb504..e4a2b8ea 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -177,6 +177,10 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("debug-rpc-calls", bpo::value()->default_value(false), "Outputs RPC calls to console"); cli.add_options()("bitcoin-sidechain-enabled", bpo::value()->default_value(false), "Bitcoin sidechain handler enabled"); + cli.add_options()("use-bitcoind-client", bpo::value()->default_value(false), "Use bitcoind client instead of libbitcoin client"); + cli.add_options()("libbitcoin-server-ip", bpo::value()->default_value("127.0.0.1"), "Libbitcoin server IP address"); + cli.add_options()("libbitcoin-server-block-zmq-port", bpo::value()->default_value(9093), "Block ZMQ port of libbitcoin server"); + cli.add_options()("libbitcoin-server-trx-zmq-port", bpo::value()->default_value(9094), "Trx ZMQ port of libbitcoin server"); cli.add_options()("bitcoin-node-ip", bpo::value()->default_value("127.0.0.1"), "IP address of Bitcoin node"); cli.add_options()("bitcoin-node-zmq-port", bpo::value()->default_value(11111), "ZMQ port of Bitcoin node"); cli.add_options()("bitcoin-node-rpc-port", bpo::value()->default_value(8332), "RPC port of Bitcoin node"); @@ -192,7 +196,7 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("ethereum-node-rpc-user", bpo::value(), "Ethereum RPC user"); cli.add_options()("ethereum-node-rpc-password", bpo::value(), "Ethereum RPC password"); cli.add_options()("ethereum-wallet-contract-address", bpo::value(), "Ethereum wallet contract address"); - cli.add_options()("erc-20-address", bpo::value>()->composing()->multitoken(), + cli.add_options()("ethereum-erc-20-address", bpo::value>()->composing()->multitoken(), "Tuple of [ERC-20 symbol, ERC-20 address] (may specify multiple times)"); cli.add_options()("ethereum-private-key", bpo::value>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", "9bedac2bd8fe2a6f6528e066c67fc8ac0622e96828d40c0e820d83c5bd2b0589")), "Tuple of [Ethereum public key, Ethereum private key] (may specify multiple times)"); @@ -249,12 +253,14 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt } sidechain_enabled_bitcoin = options.at("bitcoin-sidechain-enabled").as(); - config_ready_bitcoin = options.count("bitcoin-node-ip") && - options.count("bitcoin-node-zmq-port") && options.count("bitcoin-node-rpc-port") && - options.count("bitcoin-node-rpc-user") && options.count("bitcoin-node-rpc-password") && - options.count("bitcoin-wallet-name") && options.count("bitcoin-wallet-password") && - options.count("bitcoin-private-key"); - if (sidechain_enabled_bitcoin && !config_ready_bitcoin) { + + config_ready_bitcoin = (((options.count("libbitcoin-server-ip") && options.count("libbitcoin-server-zmq-port")) || + (options.count("bitcoin-node-ip") && options.count("bitcoin-node-zmq-port") && + options.count("bitcoin-node-rpc-port") && options.count("bitcoin-node-rpc-user") && + options.count("bitcoin-node-rpc-password") && options.count("bitcoin-wallet-name") && + options.count("bitcoin-wallet-password"))) && + options.count("bitcoin-private-key")); + if (!config_ready_bitcoin) { wlog("Haven't set up Bitcoin sidechain parameters"); } diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 3f469cc8..f37352bb 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -29,11 +29,6 @@ bitcoin_rpc_client::bitcoin_rpc_client(std::string _url, std::string _user, std: rpc_client(_url, _user, _password, _debug_rpc_calls) { } -std::string bitcoin_rpc_client::createwallet(const std::string &wallet_name) { - const std::string params = std::string("[\"") + wallet_name + std::string("\"]"); - return send_post_request("createwallet", params, debug_rpc_calls); -} - uint64_t bitcoin_rpc_client::estimatesmartfee(uint16_t conf_target) { const std::string params = std::string("[") + std::to_string(conf_target) + std::string("]"); const std::string str = send_post_request("estimatesmartfee", params, debug_rpc_calls); @@ -58,36 +53,130 @@ uint64_t bitcoin_rpc_client::estimatesmartfee(uint16_t conf_target) { return 20000; } -std::string bitcoin_rpc_client::getblock(const std::string &block_hash, int32_t verbosity) { - const std::string params = std::string("[\"") + block_hash + std::string("\",") + std::to_string(verbosity) + std::string("]"); - return send_post_request("getblock", params, debug_rpc_calls); +std::vector bitcoin_rpc_client::getblock(const block_data &block, int32_t verbosity) { + 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::vector 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 address_list; + + if (script.count("address")) { + address_list.emplace_back(script.get("address")); + } else if (script.count("addresses")) { + for (const auto &addr : script.get_child("addresses")) { + address_list.emplace_back(addr.second.get_value()); + } + } 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(); + string amount = o.second.get_child("value").get_value(); + 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(); + vin.address = address_base58; + result.push_back(vin); + } + } + } + + return result; } -std::string bitcoin_rpc_client::getnetworkinfo() { - static const std::string params = std::string("[]"); - return send_post_request("getnetworkinfo", params, debug_rpc_calls); +void bitcoin_rpc_client::getnetworkinfo() { + std::string params = std::string("[]"); + std::string str = send_post_request("getnetworkinfo", params, debug_rpc_calls); + + 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("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) { - const std::string params = std::string("[\"") + txid + std::string("\",") + (verbose ? "true" : "false") + std::string("]"); - return send_post_request("getrawtransaction", params, debug_rpc_calls); +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 str = send_post_request("getrawtransaction", params, debug_rpc_calls); + + 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("result.txid"); + uint32_t tx_confirmations = tx_json.get("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("n"); + tx_in.tx_vout = std::stoll(tx_vout_s); + if (bitcoin_major_version > 21) { + std::string address = input.second.get("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("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() { static const std::string params = std::string("[]"); const std::string str = send_post_request("getblockchaininfo", params, debug_rpc_calls); + std::string result; + if (str.length() > 0) { std::stringstream ss(str); boost::property_tree::ptree json; boost::property_tree::read_json(ss, json); - boost::property_tree::json_parser::write_json(ss, json.get_child("result")); - return ss.str(); + if (json.find("result") != json.not_found()) { + auto json_result = json.get_child("result"); + if (json_result.count("chain")) { + result = json_result.get("chain"); + } + } } - return str; + return result; } void bitcoin_rpc_client::importmulti(const std::vector &address_or_script_array, const bool rescan) { @@ -106,11 +195,11 @@ void bitcoin_rpc_client::importmulti(const std::vector &address_or //! Note /* 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 - 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 - 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.*/ + 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. + "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 + creation time of all keys being imported by the importmulti call will be scanned.*/ if (¶m != &address_or_script_array.back()) { argument_1 += ", "; @@ -243,15 +332,178 @@ bool bitcoin_rpc_client::walletpassphrase(const std::string &passphrase, uint32_ else return true; } +bitcoin_libbitcoin_client::bitcoin_libbitcoin_client(std::string url) : + libbitcoin_client(url) { + + estimate_fee_ext = std::unique_ptr(new estimate_fee_external()); +} + +uint64_t bitcoin_libbitcoin_client::estimatesmartfee(uint16_t conf_target) { + std::vector> fees = estimate_fee_ext->get_fee_external(conf_target); + std::vector accumulated_fees; + for (auto &external_fees : fees) { + if (external_fees.second != 0) { + accumulated_fees.emplace_back(external_fees.second); + } + } + + // we will rather pick minimal fee from external sources than internal fee calculation + if (accumulated_fees.empty()) { + accumulated_fees.emplace_back(current_internal_fee); + } + + return *std::min_element(accumulated_fees.begin(), accumulated_fees.end()); +} + +std::vector bitcoin_libbitcoin_client::getblock(const block_data &block, int32_t verbosity) { + + std::unique_lock lck(libbitcoin_event_mutex); + + // estimate fee + const auto &block_trxs = block.block.transactions(); + std::vector bucket_trxs; + for (auto &mem_pool_trx : trx_memory_pool) { + for (auto &trx : block_trxs) { + if (mem_pool_trx.hash() == trx.hash()) { + bucket_trxs.emplace_back(mem_pool_trx); + break; + } + } + } + + uint64_t average_fee = get_average_fee_from_trxs(bucket_trxs); + if (average_fee > 0 && bucket_trxs.size() >= MIN_TRXS_IN_BUCKET) { + current_internal_fee = average_fee; + } + + // We could consider accumulation which could spread to multiple blocks for better metric + // for now we only keep tracking for not confirmed transaction until we get next block + trx_memory_pool.clear(); + + std::vector 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 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; +} + +void bitcoin_libbitcoin_client::getnetworkinfo() { + // This function is only used for bitcoind client in order of getting + // version of bitcoin client. Version is used for extracting addresses or address + // which is not important for libbitcoin client +} + +std::string bitcoin_libbitcoin_client::getblockchaininfo() { + if (get_is_test_net()) { + is_test_net = true; + return "regtest"; + } + + return ""; +} + +std::vector 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 result; + std::vector 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) : - ip(_ip), - zmq_port(_zmq), +zmq_listener::zmq_listener(std::string _ip, uint32_t _zmq_block_port, uint32_t _zmq_trx_port) : + zmq_listener_base(_ip, _zmq_block_port, _zmq_trx_port), ctx(1), - socket(ctx, ZMQ_SUB), - stopped(false) { + socket(ctx, ZMQ_SUB) { } void zmq_listener::start() { @@ -265,16 +517,16 @@ void zmq_listener::start() { // socket.setsockopt( ZMQ_SUBSCRIBE, "hashtx", 6 ); // socket.setsockopt( ZMQ_SUBSCRIBE, "rawblock", 8 ); // socket.setsockopt( ZMQ_SUBSCRIBE, "rawtx", 5 ); - socket.connect("tcp://" + ip + ":" + std::to_string(zmq_port)); + socket.connect("tcp://" + ip + ":" + std::to_string(block_zmq_port)); - thr = std::thread(&zmq_listener::handle_zmq, this); + block_thr = std::thread(&zmq_listener::handle_zmq, this); ilog("zmq_listener thread started"); } zmq_listener::~zmq_listener() { stopped = true; - thr.join(); + block_thr.join(); } std::vector zmq_listener::receive_multipart() { @@ -302,7 +554,9 @@ void zmq_listener::handle_zmq() { } const auto header = std::string(static_cast(msg[0].data()), msg[0].size()); const auto block_hash = boost::algorithm::hex(std::string(static_cast(msg[1].data()), msg[1].size())); - event_received(block_hash); + block_data event_data; + event_data.block_hash = block_hash; + block_event_received(event_data); } } catch (zmq::error_t &e) { elog("handle_zmq recv_multipart exception ${str}", ("str", e.what())); @@ -314,6 +568,92 @@ void zmq_listener::handle_zmq() { // ============================================================================= +// ============================================================================= + +zmq_listener_libbitcoin::zmq_listener_libbitcoin(std::string _ip, uint32_t _block_zmq_port, uint32_t _trx_zmq_port) : + zmq_listener_base(_ip, _block_zmq_port, _trx_zmq_port), + block_socket(block_context, libbitcoin::protocol::zmq::socket::role::subscriber), + trx_socket(trx_context, libbitcoin::protocol::zmq::socket::role::subscriber) { +} + +zmq_listener_libbitcoin::~zmq_listener_libbitcoin() { + stopped.store(true); + block_thr.join(); + trx_thr.join(); +} + +void zmq_listener_libbitcoin::start() { + std::string endpoint_address = "tcp://" + ip; + + libbitcoin::config::endpoint block_address(endpoint_address, block_zmq_port); + libbitcoin::config::endpoint trx_address(endpoint_address, trx_zmq_port); + + block_socket.connect(block_address); + trx_socket.connect(trx_address); + + block_thr = std::thread(&zmq_listener_libbitcoin::handle_block, this); + trx_thr = std::thread(&zmq_listener_libbitcoin::handle_trx, this); +} + +void zmq_listener_libbitcoin::handle_trx() { + trx_poller.add(trx_socket); + + while (!stopped.load()) { + const auto identifiers = trx_poller.wait(500); + + if (identifiers.contains(trx_socket.id())) { + libbitcoin::protocol::zmq::message message; + + trx_socket.receive(message); + + std::vector data; + for (int i = 0; i < 2; i++) { + data.clear(); + message.dequeue(data); + } + + libbitcoin::chain::transaction trx; + trx.from_data(data, true); + + trx_event_received(trx); + } + } + + ilog("zmq_listener_libbitcoin trx thread finished"); +} + +void zmq_listener_libbitcoin::handle_block() { + block_poller.add(block_socket); + + while (!stopped.load()) { + const auto identifiers = block_poller.wait(500); + + if (identifiers.contains(block_socket.id())) { + libbitcoin::protocol::zmq::message message; + + block_socket.receive(message); + + std::vector 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); + block_event_received(event_data); + } + } + + ilog("zmq_listener_libbitcoin block thread finished"); +} + +// ============================================================================= + 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 = sidechain_type::bitcoin; @@ -322,8 +662,16 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain debug_rpc_calls = options.at("debug-rpc-calls").as(); } - ip = options.at("bitcoin-node-ip").as(); - zmq_port = options.at("bitcoin-node-zmq-port").as(); + if (options.count("use-bitcoind-client")) { + use_bitcoind_client = options.at("use-bitcoind-client").as(); + } + + libbitcoin_server_ip = options.at("libbitcoin-server-ip").as(); + libbitcoin_block_zmq_port = options.at("libbitcoin-server-block-zmq-port").as(); + libbitcoin_trx_zmq_port = options.at("libbitcoin-server-trx-zmq-port").as(); + + bitcoin_node_ip = options.at("bitcoin-node-ip").as(); + bitcoin_node_zmq_port = options.at("bitcoin-node-zmq-port").as(); rpc_port = options.at("bitcoin-node-rpc-port").as(); rpc_user = options.at("bitcoin-node-rpc-user").as(); rpc_password = options.at("bitcoin-node-rpc-password").as(); @@ -348,55 +696,44 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain } } - std::string url = ip + ":" + std::to_string(rpc_port); - if (!wallet_name.empty()) { - url = url + "/wallet/" + wallet_name; + if (use_bitcoind_client) { + std::string url = bitcoin_node_ip + ":" + std::to_string(rpc_port); + if (!wallet_name.empty()) { + url = url + "/wallet/" + wallet_name; + } + bitcoin_client = std::unique_ptr(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(new zmq_listener(bitcoin_node_ip, bitcoin_node_zmq_port)); + + } else { + bitcoin_client = std::unique_ptr(new bitcoin_libbitcoin_client(libbitcoin_server_ip)); + + listener = std::unique_ptr(new zmq_listener_libbitcoin(libbitcoin_server_ip, libbitcoin_block_zmq_port, libbitcoin_trx_zmq_port)); } - bitcoin_client = std::unique_ptr(new bitcoin_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls)); - if (!wallet_name.empty()) { - bitcoin_client->loadwallet(wallet_name); - } - - std::string blockchain_info = bitcoin_client->getblockchaininfo(); - if (blockchain_info.empty()) { - elog("No Bitcoin node running at ${url}", ("url", url)); - FC_ASSERT(false); - } - 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); + std::string chain_info = bitcoin_client->getblockchaininfo(); using namespace bitcoin; network_type = bitcoin_address::network::mainnet; - if (bci_json.count("chain")) { - std::string chain = bci_json.get("chain"); - if (chain.length() > 0) { - if (chain == "test") { - network_type = bitcoin_address::network::testnet; - } else if (chain == "regtest") { - network_type = bitcoin_address::network::regtest; - } - } + if (chain_info == "test") { + network_type = bitcoin_address::network::testnet; + } else if (chain_info == "regtest") { + network_type = bitcoin_address::network::regtest; } - std::string network_info_str = bitcoin_client->getnetworkinfo(); - if (network_info_str.empty()) { - elog("No Bitcoin node running at ${url}", ("url", url)); - FC_ASSERT(false); - } - 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_client->getnetworkinfo(); - bitcoin_major_version = network_info_json.get("result.version") / 10000; - ilog("Bitcoin major version is: '${version}'", ("version", bitcoin_major_version)); - - listener = std::unique_ptr(new zmq_listener(ip, zmq_port)); listener->start(); - listener->event_received.connect([this](const std::string &event_data) { - std::thread(&sidechain_net_handler_bitcoin::handle_event, this, event_data).detach(); + listener->block_event_received.connect([this](const block_data &block_event_data) { + std::thread(&sidechain_net_handler_bitcoin::block_handle_event, this, block_event_data).detach(); + }); + + listener->trx_event_received.connect([this](const libbitcoin::chain::transaction &trx_event_data) { + std::thread(&sidechain_net_handler_bitcoin::trx_handle_event, this, trx_event_data).detach(); }); database.changed_objects.connect([this](const vector &ids, const flat_set &accounts) { @@ -418,7 +755,7 @@ sidechain_net_handler_bitcoin::~sidechain_net_handler_bitcoin() { bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) { - //ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id(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; @@ -450,7 +787,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) son_wallet_id_type swo_id = op_obj_idx_0.get().son_wallet_id; const auto ast = active_sidechain_types(database.head_block_time()); const auto id = (swo_id.instance.value - std::distance(ast.begin(), ast.find(sidechain))) / ast.size(); - const son_wallet_id_type op_id{ id }; + const son_wallet_id_type op_id{id}; const auto &idx = database.get_index_type().indices().get(); const auto swo = idx.find(op_id); if (swo != idx.end()) { @@ -491,7 +828,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) const object_id_type object_id = op_obj_idx_1.get().object_id; const auto ast = active_sidechain_types(database.head_block_time()); const auto id = (object_id.instance() - std::distance(ast.begin(), ast.find(sidechain))) / ast.size(); - const object_id_type obj_id{ object_id.space(), object_id.type(), id }; + const object_id_type obj_id{object_id.space(), object_id.type(), id}; std::string op_tx_str = op_obj_idx_1.get().transaction; const auto &st_idx = database.get_index_type().indices().get(); @@ -533,50 +870,35 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) 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)); - const std::string tx_str = bitcoin_client->getrawtransaction(swdo_txid, true); - if (tx_str != "") { - std::stringstream tx_ss(tx_str); - boost::property_tree::ptree tx_json; - boost::property_tree::read_json(tx_ss, tx_json); + btc_tx tx = bitcoin_client->getrawtransaction(swdo_txid, true); - if (tx_json.count("error") && tx_json.get_child("error").empty()) { + if (!tx.tx_in_list.empty()) { - std::string tx_txid = tx_json.get("result.txid"); - uint32_t tx_confirmations = tx_json.get("result.confirmations"); - std::string tx_address = ""; - uint64_t tx_amount = -1; - uint64_t tx_vout = -1; + std::string tx_txid = tx.tx_txid; + uint32_t tx_confirmations = tx.tx_confirmations; + std::string tx_address = ""; + uint64_t tx_amount = -1; + uint64_t tx_vout = -1; - for (auto &input : tx_json.get_child("result.vout")) { - std::string tx_vout_s = input.second.get("n"); - tx_vout = std::stoll(tx_vout_s); - if (tx_vout == swdo_vout) { - if (bitcoin_major_version > 21) { - std::string address = input.second.get("scriptPubKey.address"); - if (address == swdo_address) { - tx_address = address; - } - } else { - for (auto &address : input.second.get_child("scriptPubKey.addresses")) { - if (address.second.data() == swdo_address) { - tx_address = address.second.data(); - break; - } - } + for (auto &input : tx.tx_in_list) { + tx_vout = input.tx_vout; + if (tx_vout == swdo_vout) { + for (auto &address : input.tx_address) { + if (address == swdo_address) { + tx_address = address; + break; } - std::string tx_amount_s = input.second.get("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; } + tx_amount = input.tx_amount; + break; } - - process_ok = (swdo_txid == tx_txid) && - (swdo_address == tx_address) && - (swdo_amount == tx_amount) && - (swdo_vout == tx_vout) && - (gpo.parameters.son_bitcoin_min_tx_confirmations() <= tx_confirmations); } + + process_ok = (swdo_txid == tx_txid) && + (swdo_address == tx_address) && + (swdo_amount == tx_amount) && + (swdo_vout == tx_vout) && + (gpo.parameters.son_bitcoin_min_tx_confirmations() <= tx_confirmations); } object_id_type object_id = op_obj_idx_1.get().object_id; @@ -724,7 +1046,7 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { const auto ast = active_sidechain_types(database.head_block_time()); const auto id = active_sw->id.instance() * ast.size() + std::distance(ast.begin(), ast.find(sidechain)); - const object_id_type op_id{ active_sw->id.space(), active_sw->id.type(), id }; + const object_id_type op_id{active_sw->id.space(), active_sw->id.type(), id}; if (proposal_exists(chain::operation::tag::value, op_id)) { return; @@ -765,7 +1087,7 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { if (!tx_str.empty()) { const auto ast = active_sidechain_types(database.head_block_time()); const auto prev_id = prev_sw->id.instance() * ast.size() + std::distance(ast.begin(), ast.find(sidechain)); - const object_id_type prev_op_id{ prev_sw->id.space(), prev_sw->id.type(), prev_id }; + const object_id_type prev_op_id{prev_sw->id.space(), prev_sw->id.type(), prev_id}; sidechain_transaction_create_operation stc_op; stc_op.payer = gpo.parameters.son_account(); @@ -820,7 +1142,12 @@ void sidechain_net_handler_bitcoin::process_sidechain_addresses() { if (sao.expires == time_point_sec::maximum()) { 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()) + "\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }"; @@ -977,61 +1304,53 @@ bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain return false; } - const std::string tx_str = bitcoin_client->getrawtransaction(sto.sidechain_transaction, true); - if (tx_str != "") { - std::stringstream tx_ss(tx_str); - boost::property_tree::ptree tx_json; - boost::property_tree::read_json(tx_ss, tx_json); + btc_tx tx = bitcoin_client->getrawtransaction(sto.sidechain_transaction, true); - if ((tx_json.count("error")) && (!tx_json.get_child("error").empty())) { - return false; - } + if (tx.tx_in_list.empty()) { + // This case will result with segmentation fault. + // FIXME check if that happened before introducing libbitcoin + return false; + } - const chain::global_property_object &gpo = database.get_global_properties(); + const chain::global_property_object &gpo = database.get_global_properties(); - using namespace bitcoin; - std::vector> pubkey_weights; - for (auto si : sto.signers) { - auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(si.public_key))); - pubkey_weights.push_back(std::make_pair(pub_key, si.weight)); - } - btc_weighted_multisig_address addr(pubkey_weights, network_type); + using namespace bitcoin; + std::vector> pubkey_weights; + for (auto si : sto.signers) { + 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)); + } - std::string tx_txid = tx_json.get("result.txid"); - uint32_t tx_confirmations = tx_json.get("result.confirmations"); - std::string tx_address = addr.get_address(); - int64_t tx_amount = -1; + payment_type payment_type_address = payment_type::P2SH_WSH; + if (use_bitcoind_client) { + payment_type_address = payment_type::P2WSH; + } - if (tx_confirmations >= gpo.parameters.son_bitcoin_min_tx_confirmations()) { - if (sto.object_id.is()) { - for (auto &input : tx_json.get_child("result.vout")) { - if (bitcoin_major_version > 21) { - std::string address = input.second.get("scriptPubKey.address"); - if (address == tx_address) { - std::string tx_amount_s = input.second.get("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); - } - } else { - for (auto &address : input.second.get_child("scriptPubKey.addresses")) { - if (address.second.data() == tx_address) { - std::string tx_amount_s = input.second.get("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; - } - } + 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(); + int64_t tx_amount = -1; + + if (tx_confirmations >= gpo.parameters.son_bitcoin_min_tx_confirmations()) { + if (sto.object_id.is()) { + for (auto &input : tx.tx_in_list) { + for (auto &address : input.tx_address) { + if (address == tx_address) { + tx_amount = input.tx_amount; + break; } } settle_amount = asset(tx_amount, database.get_global_properties().parameters.btc_asset()); return true; } + } - if (sto.object_id.is()) { - auto swwo = database.get(sto.object_id); - settle_amount = asset(swwo.withdraw_amount, database.get_global_properties().parameters.btc_asset()); - return true; - } + if (sto.object_id.is()) { + auto swwo = database.get(sto.object_id); + settle_amount = asset(swwo.withdraw_amount, database.get_global_properties().parameters.btc_asset()); + return true; } } return false; @@ -1051,7 +1370,11 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const s 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; @@ -1287,18 +1610,34 @@ std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_tran } // Add redeemscripts to vins and make tx ready for sending 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)); - return bitcoin_client->sendrawtransaction(final_tx_hex); + std::string res = bitcoin_client->sendrawtransaction(final_tx_hex); + + if (res.empty()) { + return res; + } + + return tx.get_txid().str(); } -void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data) { - const std::string block = bitcoin_client->getblock(event_data); - if (block.empty()) - return; +void sidechain_net_handler_bitcoin::block_handle_event(const block_data &event_data) { - add_to_son_listener_log("BLOCK : " + event_data); + auto vins = bitcoin_client->getblock(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); const auto &sidechain_addresses_idx = database.get_index_type().indices().get(); @@ -1335,6 +1674,10 @@ void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data) } } +void sidechain_net_handler_bitcoin::trx_handle_event(const libbitcoin::chain::transaction &trx_data) { + bitcoin_client->import_trx_to_memory_pool(trx_data); +} + std::string sidechain_net_handler_bitcoin::get_redeemscript_for_userdeposit(const std::string &user_address) { using namespace bitcoin; const auto &sidechain_addresses_idx = database.get_index_type().indices().get(); @@ -1355,56 +1698,14 @@ std::string sidechain_net_handler_bitcoin::get_redeemscript_for_userdeposit(cons 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))); - 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 sidechain_net_handler_bitcoin::extract_info_from_block(const std::string &_block) { - std::stringstream ss(_block); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - - auto json_result = json.get_child_optional("result"); - - std::vector 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(); - string amount = o.second.get_child("value").get_value(); - 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(); - vin.address = address_base58; - result.push_back(vin); - }; - - if (bitcoin_major_version > 21) { - std::string address = script.get("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()); - } - } + 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 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 &ids, const flat_set &accounts) { diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index d0051714..40bf8481 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -148,8 +148,8 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha wallet_contract_address = options.at("ethereum-wallet-contract-address").as(); - if (options.count("erc-20-address")) { - const std::vector symbol_addresses = options["erc-20-address"].as>(); + if (options.count("ethereum-erc-20-address")) { + const std::vector symbol_addresses = options["ethereum-erc-20-address"].as>(); for (const std::string &itr : symbol_addresses) { auto itr_pair = graphene::app::dejsonify>(itr, 5); ilog("ERC-20 symbol: ${symbol}, address: ${address}", ("symbol", itr_pair.first)("address", itr_pair.second)); @@ -236,7 +236,7 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) const son_wallet_id_type swo_id = op_obj_idx_0.get().son_wallet_id; const auto ast = active_sidechain_types(database.head_block_time()); const auto id = (swo_id.instance.value - std::distance(ast.begin(), ast.find(sidechain))) / ast.size(); - const son_wallet_id_type op_id{ id }; + const son_wallet_id_type op_id{id}; const auto &idx = database.get_index_type().indices().get(); const auto swo = idx.find(op_id); if (swo != idx.end()) { @@ -259,7 +259,7 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) if (po.proposed_transaction.operations.size() >= 2) { const object_id_type object_id = op_obj_idx_1.get().object_id; const auto id = (object_id.instance() - std::distance(ast.begin(), ast.find(sidechain))) / ast.size(); - const object_id_type obj_id{ object_id.space(), object_id.type(), id }; + const object_id_type obj_id{object_id.space(), object_id.type(), id}; const std::string op_tx_str = op_obj_idx_1.get().transaction; const auto &st_idx = database.get_index_type().indices().get(); @@ -459,7 +459,7 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { const auto ast = active_sidechain_types(database.head_block_time()); const auto id = active_sw->id.instance() * ast.size() + std::distance(ast.begin(), ast.find(sidechain)); - const object_id_type op_id{ active_sw->id.space(), active_sw->id.type(), id }; + const object_id_type op_id{active_sw->id.space(), active_sw->id.type(), id}; if (proposal_exists(chain::operation::tag::value, op_id)) { return; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp index 3f1378e7..6ad95850 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp @@ -211,7 +211,7 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { son_wallet_id_type swo_id = op_obj_idx_0.get().son_wallet_id; const auto ast = active_sidechain_types(database.head_block_time()); const auto id = (swo_id.instance.value - std::distance(ast.begin(), ast.find(sidechain))) / ast.size(); - const son_wallet_id_type op_id{ id }; + const son_wallet_id_type op_id{id}; const auto &idx = database.get_index_type().indices().get(); const auto swo = idx.find(op_id); if (swo != idx.end()) { @@ -234,7 +234,7 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { if (po.proposed_transaction.operations.size() >= 2) { const object_id_type object_id = op_obj_idx_1.get().object_id; const auto id = (object_id.instance() - std::distance(ast.begin(), ast.find(sidechain))) / ast.size(); - const object_id_type obj_id{ object_id.space(), object_id.type(), id }; + const object_id_type obj_id{object_id.space(), object_id.type(), id}; std::string op_tx_str = op_obj_idx_1.get().transaction; const auto &st_idx = database.get_index_type().indices().get(); @@ -493,7 +493,7 @@ void sidechain_net_handler_hive::process_primary_wallet() { const auto ast = active_sidechain_types(database.head_block_time()); const auto id = active_sw->id.instance() * ast.size() + std::distance(ast.begin(), ast.find(sidechain)); - const object_id_type op_id{ active_sw->id.space(), active_sw->id.type(), id }; + const object_id_type op_id{active_sw->id.space(), active_sw->id.type(), id}; if (proposal_exists(chain::operation::tag::value, op_id)) { return; From 19e0911d64ca2fa4fdbff3fa71598e8788a5f019 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Fri, 10 Feb 2023 13:34:53 +0200 Subject: [PATCH 8/8] #492 - fix withdrawal encoders for big numbers --- .../peerplays_sidechain/bitcoin/estimate_fee_external.hpp | 2 ++ .../peerplays_sidechain/sidechain_net_handler_ethereum.cpp | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/estimate_fee_external.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/estimate_fee_external.hpp index 10be2868..fdfcc73f 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/estimate_fee_external.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/estimate_fee_external.hpp @@ -2,8 +2,10 @@ #include +#include #include #include +#include #include typedef std::function get_fee_func_type; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 40bf8481..a3be8649 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -785,7 +785,7 @@ optional sidechain_net_handler_ethereum::estimate_withdrawal_transaction_ } const auto &public_key = son->sidechain_public_keys.at(sidechain); - const auto data = ethereum::withdrawal_encoder::encode(public_key, 1 * 10000000000, son_wallet_withdraw_id_type{0}.operator object_id_type().operator std::string()); + const auto data = ethereum::withdrawal_encoder::encode(public_key, boost::multiprecision::uint256_t{1} * boost::multiprecision::uint256_t{10000000000}, son_wallet_withdraw_id_type{0}.operator object_id_type().operator std::string()); const std::string params = "[{\"from\":\"" + ethereum::add_0x(public_key) + "\", \"to\":\"" + wallet_contract_address + "\", \"data\":\"" + data + "\"}]"; const auto estimate_gas = ethereum::from_hex(rpc_client->get_estimate_gas(params)); @@ -808,14 +808,14 @@ std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(co std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { if (swwo.withdraw_currency == "ETH") { - return ethereum::withdrawal_encoder::encode(ethereum::remove_0x(swwo.withdraw_address), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string()); + return ethereum::withdrawal_encoder::encode(ethereum::remove_0x(swwo.withdraw_address), boost::multiprecision::uint256_t{swwo.withdraw_amount.value} * boost::multiprecision::uint256_t{10000000000}, swwo.id.operator std::string()); } else { const auto it = erc20_addresses.left.find(swwo.withdraw_currency); if (it == erc20_addresses.left.end()) { elog("No erc-20 token: ${symbol}", ("symbol", swwo.withdraw_currency)); return ""; } - return ethereum::withdrawal_erc20_encoder::encode(ethereum::remove_0x(it->second), ethereum::remove_0x(swwo.withdraw_address), swwo.withdraw_amount.value, swwo.id.operator std::string()); + return ethereum::withdrawal_erc20_encoder::encode(ethereum::remove_0x(it->second), ethereum::remove_0x(swwo.withdraw_address), boost::multiprecision::uint256_t{swwo.withdraw_amount.value}, swwo.id.operator std::string()); } return "";