From bb976816af460c7cecdbce27ab7ad7d09c7dec7e Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Wed, 18 May 2022 19:38:49 -0300 Subject: [PATCH 01/60] sidechain_net_handler_eth, eth_rpc_client --- .../peerplays_sidechain/CMakeLists.txt | 1 + .../sidechain_net_handler_eth.hpp | 139 +++ .../peerplays_sidechain_plugin.cpp | 25 +- .../sidechain_net_handler_eth.cpp | 807 ++++++++++++++++++ .../sidechain_net_manager.cpp | 7 + 5 files changed, 968 insertions(+), 11 deletions(-) create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp create mode 100644 libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index 9ea2ce34..b61e908d 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -6,6 +6,7 @@ add_library( peerplays_sidechain sidechain_net_manager.cpp sidechain_net_handler.cpp sidechain_net_handler_bitcoin.cpp + sidechain_net_handler_eth.cpp sidechain_net_handler_hive.cpp sidechain_net_handler_peerplays.cpp bitcoin/bech32.cpp diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp new file mode 100644 index 00000000..7816e99e --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -0,0 +1,139 @@ +#pragma once + +#include + +#include +#include + +#include + +#include + +#include +#include + +#include +#include +#include +#include + +namespace graphene { namespace peerplays_sidechain { + +class eth_rpc_client { +public: + enum class multi_type { + script, + address + }; + struct multi_params { + multi_params(multi_type _type, const std::string &_address_or_script, const std::string &_label = "") : + type{_type}, + address_or_script{_address_or_script}, + label{_label} { + } + + multi_type type; + std::string address_or_script; + std::string label; + }; + +public: + eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); + + void connect(); + std::string get_chain_id(); + + std::string addmultisigaddress(const uint32_t nrequired, const std::vector public_keys); + std::string combinepsbt(const vector &psbts); + std::string createmultisig(const uint32_t nrequired, const std::vector public_keys); + std::string createpsbt(); + std::string createrawtransaction(); + std::string createwallet(const std::string &wallet_name); + std::string decodepsbt(std::string const &tx_psbt); + std::string decoderawtransaction(std::string const &tx_hex); + std::string encryptwallet(const std::string &passphrase); + uint64_t estimatesmartfee(uint16_t conf_target = 128); + std::string finalizepsbt(std::string const &tx_psbt); + std::string getaddressinfo(const std::string &address); + 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(); + std::string gettransaction(const std::string &txid, const bool include_watch_only = false); + std::string getblockchaininfo(); + void importaddress(const std::string &address_or_script, const std::string &label = "", const bool rescan = true, const bool p2sh = false); + void importmulti(const std::vector &address_or_script_array, const bool rescan = true); + std::string loadwallet(const std::string &filename); + std::string sendrawtransaction(const std::string &tx_hex); + std::string signrawtransactionwithwallet(const std::string &tx_hash); + std::string unloadwallet(const std::string &filename); + std::string walletlock(); + std::string walletprocesspsbt(std::string const &tx_psbt); + bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); + +private: + std::string geth_url; + std::string ip; + uint32_t rpc_port; + std::string user; + std::string password; + std::string wallet; + std::string wallet_password; + bool debug_rpc_calls; + + fc::http::header authorization; + + fc::http::websocket_client client; + std::shared_ptr client_connection; +}; + +// ============================================================================= + +class sidechain_net_handler_eth : public sidechain_net_handler { +public: + sidechain_net_handler_eth(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options); + virtual ~sidechain_net_handler_eth(); + + bool process_proposal(const proposal_object &po); + void process_primary_wallet(); + void process_sidechain_addresses(); + bool process_deposit(const son_wallet_deposit_object &swdo); + bool process_withdrawal(const son_wallet_withdraw_object &swwo); + std::string process_sidechain_transaction(const sidechain_transaction_object &sto); + std::string send_sidechain_transaction(const sidechain_transaction_object &sto); + bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); + +private: + std::string url; + uint32_t rpc_port; + + std::string rpc_user; + std::string rpc_password; + std::string wallet; + std::string wallet_password; + + std::unique_ptr eth_client; + + fc::future on_changed_objects_task; + bitcoin::bitcoin_address::network network_type; + + 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_transaction(const son_wallet_object &prev_swo, std::string new_sw_address); + std::string create_deposit_transaction(const son_wallet_deposit_object &swdo); + std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo); + + std::string create_transaction(); + 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); + 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); +}; + +}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index ed80fbfc..570358c7 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -157,6 +157,9 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("bitcoin-private-key", bpo::value>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")), "Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)"); + cli.add_options()("ethereum-sidechain-enabled", bpo::value()->default_value(true), "Hive sidechain handler enabled"); + cli.add_options()("ethereum-node-rpc-url", bpo::value()->default_value("ws://127.0.0.1:8546/"), "Ethereum node RPC WS URL [ws[s]://]host[:port]"); + cli.add_options()("hive-sidechain-enabled", bpo::value()->default_value(false), "Hive sidechain handler enabled"); cli.add_options()("hive-node-rpc-url", bpo::value()->default_value("127.0.0.1:28090"), "Hive node RPC URL [http[s]://]host[:port]"); cli.add_options()("hive-node-rpc-user", bpo::value(), "Hive node RPC user"); @@ -217,13 +220,13 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt wlog("Haven't set up Bitcoin sidechain parameters"); } - //sidechain_enabled_ethereum = options.at("ethereum-sidechain-enabled").as(); - //config_ready_ethereum = options.count("ethereum-node-ip") && - // options.count("ethereum-address") && - // options.count("ethereum-public-key") && options.count("ethereum-private-key"); - //if (!config_ready_ethereum) { - // wlog("Haven't set up Ethereum sidechain parameters"); - //} + sidechain_enabled_ethereum = options.at("ethereum-sidechain-enabled").as(); + config_ready_ethereum = options.count("ethereum-node-rpc-url"); + //options.count("ethereum-address") && + //options.count("ethereum-public-key") && options.count("ethereum-private-key"); + if (!config_ready_ethereum) { + wlog("Haven't set up Ethereum sidechain parameters"); + } sidechain_enabled_hive = options.at("hive-sidechain-enabled").as(); config_ready_hive = options.count("hive-node-rpc-url") && @@ -269,10 +272,10 @@ void peerplays_sidechain_plugin_impl::plugin_startup() { ilog("Bitcoin sidechain handler running"); } - //if (sidechain_enabled_ethereum && config_ready_ethereum) { - // net_manager->create_handler(sidechain_type::ethereum, options); - // ilog("Ethereum sidechain handler running"); - //} + if (sidechain_enabled_ethereum && config_ready_ethereum) { + net_manager->create_handler(sidechain_type::ethereum, options); + ilog("Ethereum sidechain handler running"); + } if (sidechain_enabled_hive && config_ready_hive) { net_manager->create_handler(sidechain_type::hive, options); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp new file mode 100644 index 00000000..0f8b5328 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -0,0 +1,807 @@ +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace graphene { namespace peerplays_sidechain { + +// ============================================================================= + +eth_rpc_client::eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) { + geth_url = url; + user = user_name; + this->password = password; + this->debug_rpc_calls = debug_rpc_calls; + + ilog("eth_rpc_client"); + ilog("### Geth URL: ${url}", ("url", url)); +} + +void eth_rpc_client::connect() { + client_connection = std::make_shared(client.connect(geth_url), GRAPHENE_MAX_NESTED_OBJECTS); +} + +std::string eth_rpc_client::get_chain_id() { + //std::string reply_str = database_api_get_version(); + return "";//retrieve_value_from_reply(reply_str, "chain_id"); +} + +std::string eth_rpc_client::addmultisigaddress(const uint32_t nrequired, const std::vector public_keys) { + return ""; +} + +std::string eth_rpc_client::combinepsbt(const vector &psbts) { + return ""; +} + +std::string eth_rpc_client::createmultisig(const uint32_t nrequired, const std::vector public_keys) { + return ""; +} + +std::string eth_rpc_client::createpsbt() { +} + +std::string eth_rpc_client::createrawtransaction() { + return ""; +} + +std::string eth_rpc_client::createwallet(const std::string &wallet_name) { + return ""; +} + +std::string eth_rpc_client::decodepsbt(std::string const &tx_psbt) { + return ""; +} + +std::string eth_rpc_client::decoderawtransaction(std::string const &tx_hex) { + return ""; +} + +std::string eth_rpc_client::encryptwallet(const std::string &passphrase) { + return ""; +} + +uint64_t eth_rpc_client::estimatesmartfee(uint16_t conf_target) { + return 20000; +} + +std::string eth_rpc_client::finalizepsbt(std::string const &tx_psbt) { + return ""; +} + +std::string eth_rpc_client::getaddressinfo(const std::string &address) { + return ""; +} + +std::string eth_rpc_client::getblock(const std::string &block_hash, int32_t verbosity) { + return ""; +} + +std::string eth_rpc_client::getnetworkinfo() { + return ""; +} + +std::string eth_rpc_client::getrawtransaction(const std::string &txid, const bool verbose) { + return ""; +} + +std::string eth_rpc_client::gettransaction(const std::string &txid, const bool include_watch_only) { + return ""; +} + +std::string eth_rpc_client::getblockchaininfo() { + return ""; +} + +void eth_rpc_client::importaddress(const std::string &address_or_script, const std::string &label, const bool rescan, const bool p2sh) { + return; +} + +void eth_rpc_client::importmulti(const std::vector &address_or_script_array, const bool rescan) { +} + +std::string eth_rpc_client::loadwallet(const std::string &filename) { + return ""; +} + +std::string eth_rpc_client::sendrawtransaction(const std::string &tx_hex) { + return ""; +} + +std::string eth_rpc_client::signrawtransactionwithwallet(const std::string &tx_hash) { + return ""; +} + +std::string eth_rpc_client::unloadwallet(const std::string &filename) { + return ""; +} + +std::string eth_rpc_client::walletlock() { + return ""; +} + +std::string eth_rpc_client::walletprocesspsbt(std::string const &tx_psbt) { + return ""; +} + +bool eth_rpc_client::walletpassphrase(const std::string &passphrase, uint32_t timeout) { + return false; +} + +// ============================================================================= + +sidechain_net_handler_eth::sidechain_net_handler_eth(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : + sidechain_net_handler(_plugin, options) { + sidechain = sidechain_type::ethereum; + + if (options.count("debug-rpc-calls")) { + debug_rpc_calls = options.at("debug-rpc-calls").as(); + } + + url = options.at("ethereum-node-rpc-url").as(); + eth_client = std::unique_ptr(new eth_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls)); + eth_client->connect(); +/* + if (!wallet.empty()) { + eth_client->loadwallet(wallet); + } + + + std::thread(&sidechain_net_handler_eth::handle_event, this, event_data).detach(); + }); + + database.changed_objects.connect([this](const vector &ids, const flat_set &accounts) { + on_changed_objects(ids, accounts); + }); +*/ +} + +sidechain_net_handler_eth::~sidechain_net_handler_eth() { + try { + if (on_changed_objects_task.valid()) { + on_changed_objects_task.cancel_and_wait(__FUNCTION__); + } + } catch (fc::canceled_exception &) { + //Expected exception. Move along. + } catch (fc::exception &e) { + edump((e.to_detail_string())); + } +} + +bool sidechain_net_handler_eth::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())); +/* + bool should_approve = false; + + const chain::global_property_object &gpo = database.get_global_properties(); + + int32_t op_idx_0 = -1; + chain::operation op_obj_idx_0; + + if (po.proposed_transaction.operations.size() >= 1) { + op_idx_0 = po.proposed_transaction.operations[0].which(); + op_obj_idx_0 = po.proposed_transaction.operations[0]; + } + + int32_t op_idx_1 = -1; + chain::operation op_obj_idx_1; + (void)op_idx_1; + + if (po.proposed_transaction.operations.size() >= 2) { + op_idx_1 = po.proposed_transaction.operations[1].which(); + op_obj_idx_1 = po.proposed_transaction.operations[1]; + } + + switch (op_idx_0) { + + case chain::operation::tag::value: { + bool address_ok = false; + 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 &idx = database.get_index_type().indices().get(); + const auto swo = idx.find(swo_id); + if (swo != idx.end()) { + + auto active_sons = gpo.active_sons; + vector wallet_sons = swo->sons; + + bool son_sets_equal = (active_sons.size() == wallet_sons.size()); + + if (son_sets_equal) { + for (size_t i = 0; i < active_sons.size(); i++) { + son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i); + } + } + + if (son_sets_equal) { + auto active_sons = gpo.active_sons; + vector son_pubkeys_bitcoin; + for (const son_info &si : active_sons) { + son_pubkeys_bitcoin.push_back(si.sidechain_public_keys.at(sidechain_type::bitcoin)); + } + + string reply_str = create_primary_wallet_address(active_sons); + + std::stringstream active_pw_ss(reply_str); + boost::property_tree::ptree active_pw_pt; + boost::property_tree::read_json(active_pw_ss, active_pw_pt); + if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { + std::stringstream res; + boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); + new_pw_address = active_pw_pt.get("result.address"); + + address_ok = (op_obj_idx_0.get().address == res.str()); + } + } + + if (po.proposed_transaction.operations.size() >= 2) { + object_id_type object_id = op_obj_idx_1.get().object_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); + if (st == st_idx.end()) { + + std::string tx_str = ""; + + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swo = idx.find(object_id); + if (swo != idx.end()) { + tx_str = create_primary_wallet_transaction(*swo, new_pw_address); + } + } + + transaction_ok = (op_tx_str == tx_str); + } + } else { + transaction_ok = true; + } + } + + should_approve = address_ok && + transaction_ok; + break; + } + + case chain::operation::tag::value: { + bool process_ok = false; + bool transaction_ok = false; + son_wallet_deposit_id_type swdo_id = op_obj_idx_0.get().son_wallet_deposit_id; + const auto &idx = database.get_index_type().indices().get(); + const auto swdo = idx.find(swdo_id); + if (swdo != idx.end()) { + + std::string swdo_txid = swdo->sidechain_transaction_id; + std::string swdo_address = swdo->sidechain_from; + 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)); + + std::string tx_str = eth_client->getrawtransaction(swdo_txid, true); + std::stringstream tx_ss(tx_str); + boost::property_tree::ptree tx_json; + boost::property_tree::read_json(tx_ss, tx_json); + + if (tx_json.count("error") && tx_json.get_child("error").empty()) { + + 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; + + 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; + } + } + } + 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; + } + } + + 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; + 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); + if (st == st_idx.end()) { + + std::string tx_str = ""; + + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swdo = idx.find(object_id); + if (swdo != idx.end()) { + tx_str = create_deposit_transaction(*swdo); + } + } + + transaction_ok = (op_tx_str == tx_str); + } + } + + should_approve = process_ok && + transaction_ok; + break; + } + + case chain::operation::tag::value: { + bool process_ok = false; + bool transaction_ok = false; + son_wallet_withdraw_id_type swwo_id = op_obj_idx_0.get().son_wallet_withdraw_id; + const auto &idx = database.get_index_type().indices().get(); + const auto swwo = idx.find(swwo_id); + if (swwo != idx.end()) { + + uint32_t swwo_block_num = swwo->block_num; + std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id; + uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1)); + + const auto &block = database.fetch_block_by_number(swwo_block_num); + + for (const auto &tx : block->transactions) { + if (tx.id().str() == swwo_peerplays_transaction_id) { + operation op = tx.operations[swwo_op_idx]; + transfer_operation t_op = op.get(); + + price asset_price = database.get(t_op.amount.asset_id).options.core_exchange_rate; + asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); + + process_ok = (t_op.to == gpo.parameters.son_account()) && + (swwo->peerplays_from == t_op.from) && + (swwo->peerplays_asset == peerplays_asset); + break; + } + } + + object_id_type object_id = op_obj_idx_1.get().object_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); + if (st == st_idx.end()) { + + std::string tx_str = ""; + + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swwo = idx.find(object_id); + if (swwo != idx.end()) { + tx_str = create_withdrawal_transaction(*swwo); + } + } + + transaction_ok = (op_tx_str == tx_str); + } + } + + should_approve = process_ok && + transaction_ok; + break; + } + + case chain::operation::tag::value: { + using namespace bitcoin; + should_approve = true; + son_id_type signer = op_obj_idx_0.get().signer; + std::string signature = op_obj_idx_0.get().signature; + sidechain_transaction_id_type sidechain_transaction_id = op_obj_idx_0.get().sidechain_transaction_id; + std::vector in_amounts; + std::string tx_hex; + std::string redeem_script; + const auto &st_idx = database.get_index_type().indices().get(); + const auto sto = st_idx.find(sidechain_transaction_id); + if (sto == st_idx.end()) { + should_approve = false; + break; + } + + const auto &s_idx = database.get_index_type().indices().get(); + const auto son = s_idx.find(signer); + if (son == s_idx.end()) { + should_approve = false; + break; + } + + read_transaction_data(sto->transaction, tx_hex, in_amounts, redeem_script); + bitcoin_transaction tx = unpack(parse_hex(tx_hex)); + bitcoin::bytes pubkey = parse_hex(son->sidechain_public_keys.at(sidechain_type::bitcoin)); + vector sigs = read_byte_arrays_from_string(signature); + for (size_t i = 0; i < tx.vin.size(); i++) { + const auto &sighash_str = get_signature_hash(tx, parse_hex(redeem_script), static_cast(in_amounts[i]), i, 1, true).str(); + const bitcoin::bytes &sighash_hex = parse_hex(sighash_str); + should_approve = should_approve && verify_sig(sigs[i], pubkey, sighash_hex, btc_context()); + } + break; + } + + case chain::operation::tag::value: { + should_approve = true; + break; + } + + default: + should_approve = false; + elog("=================================================="); + elog("Proposal not considered for approval ${po}", ("po", po)); + elog("=================================================="); + } + + return should_approve; + */ + return false; +} + +void sidechain_net_handler_eth::process_primary_wallet() { + const auto &swi = database.get_index_type().indices().get(); + const auto &active_sw = swi.rbegin(); + if (active_sw != swi.rend()) { + + if ((active_sw->addresses.find(sidechain_type::bitcoin) == active_sw->addresses.end()) || + (active_sw->addresses.at(sidechain_type::bitcoin).empty())) { + + if (proposal_exists(chain::operation::tag::value, active_sw->id)) { + return; + } + + const chain::global_property_object &gpo = database.get_global_properties(); + + auto active_sons = gpo.active_sons; + string reply_str = create_primary_wallet_address(active_sons); + + std::stringstream active_pw_ss(reply_str); + boost::property_tree::ptree active_pw_pt; + boost::property_tree::read_json(active_pw_ss, active_pw_pt); + if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { + if (!plugin.can_son_participate(chain::operation::tag::value, active_sw->id)) { + return; + } + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + + std::stringstream res; + boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); + + son_wallet_update_operation swu_op; + swu_op.payer = gpo.parameters.son_account(); + swu_op.son_wallet_id = active_sw->id; + swu_op.sidechain = sidechain_type::bitcoin; + swu_op.address = res.str(); + + proposal_op.proposed_ops.emplace_back(swu_op); + + const auto &prev_sw = std::next(active_sw); + if (prev_sw != swi.rend()) { + 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()) { + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = prev_sw->id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = prev_sw->sons; + proposal_op.proposed_ops.emplace_back(stc_op); + } + } + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + plugin.log_son_proposal_retry(chain::operation::tag::value, active_sw->id); + } catch (fc::exception &e) { + elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); + return; + } + } + } + } +} + +void sidechain_net_handler_eth::process_sidechain_addresses() { + using namespace bitcoin; + + const chain::global_property_object &gpo = database.get_global_properties(); + std::vector> pubkeys; + for (auto &son : gpo.active_sons) { + std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin); + auto pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); + pubkeys.push_back(std::make_pair(pubkey, son.weight)); + } + + const auto &sidechain_addresses_idx = database.get_index_type(); + const auto &sidechain_addresses_by_sidechain_idx = sidechain_addresses_idx.indices().get(); + const auto &sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain); + std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second, + [&](const sidechain_address_object &sao) { + bool retval = true; + try { + 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); + std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) + + "\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }"; + + if (addr.get_address() != sao.deposit_address) { + sidechain_address_update_operation op; + op.payer = plugin.get_current_son_object().son_account; + op.sidechain_address_id = sao.id; + op.sidechain_address_account = sao.sidechain_address_account; + op.sidechain = sao.sidechain; + op.deposit_public_key = sao.deposit_public_key; + op.deposit_address = addr.get_address(); + op.deposit_address_data = address_data; + op.withdraw_public_key = sao.withdraw_public_key; + op.withdraw_address = sao.withdraw_address; + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + retval = true; + } catch (fc::exception &e) { + elog("Sending transaction for sidechain address update operation failed with exception ${e}", ("e", e.what())); + retval = false; + } + } + } + } catch (fc::exception &e) { + retval = false; + } + return retval; + }); +} + +bool sidechain_net_handler_eth::process_deposit(const son_wallet_deposit_object &swdo) { + + if (proposal_exists(chain::operation::tag::value, swdo.id)) { + return false; + } + + std::string tx_str = create_deposit_transaction(swdo); + + if (!tx_str.empty()) { + const chain::global_property_object &gpo = database.get_global_properties(); + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + + son_wallet_deposit_process_operation swdp_op; + swdp_op.payer = gpo.parameters.son_account(); + swdp_op.son_wallet_deposit_id = swdo.id; + proposal_op.proposed_ops.emplace_back(swdp_op); + + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = swdo.id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = gpo.active_sons; + proposal_op.proposed_ops.emplace_back(stc_op); + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + return true; + } catch (fc::exception &e) { + elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + return false; + } + } + return false; +} + +bool sidechain_net_handler_eth::process_withdrawal(const son_wallet_withdraw_object &swwo) { + + if (proposal_exists(chain::operation::tag::value, swwo.id)) { + return false; + } + + std::string tx_str = create_withdrawal_transaction(swwo); + + if (!tx_str.empty()) { + const chain::global_property_object &gpo = database.get_global_properties(); + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + + son_wallet_withdraw_process_operation swwp_op; + swwp_op.payer = gpo.parameters.son_account(); + swwp_op.son_wallet_withdraw_id = swwo.id; + proposal_op.proposed_ops.emplace_back(swwp_op); + + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = swwo.id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = gpo.active_sons; + proposal_op.proposed_ops.emplace_back(stc_op); + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + return true; + } catch (fc::exception &e) { + elog("Sending proposal for withdraw sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + return false; + } + } + return false; +} + +std::string sidechain_net_handler_eth::process_sidechain_transaction(const sidechain_transaction_object &sto) { + return sign_transaction(sto); +} + +std::string sidechain_net_handler_eth::send_sidechain_transaction(const sidechain_transaction_object &sto) { + return send_transaction(sto); +} + +bool sidechain_net_handler_eth::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) { + return false; +} + +std::string sidechain_net_handler_eth::create_primary_wallet_address(const std::vector &son_pubkeys) { + using namespace bitcoin; + + std::vector> pubkey_weights; + for (auto &son : son_pubkeys) { + std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin); + auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); + pubkey_weights.push_back(std::make_pair(pub_key, son.weight)); + } + + btc_weighted_multisig_address addr(pubkey_weights, network_type); + + std::stringstream ss; + + ss << "{\"result\": {\"address\": \"" << addr.get_address() << "\", \"redeemScript\": \"" << fc::to_hex(addr.get_redeem_script()) << "\"" + << "}, \"error\":null}"; + + std::string res = ss.str(); + return res; +} + +std::string sidechain_net_handler_eth::create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address) { + return "";//create_transaction(inputs, outputs, prev_redeem_script); +} + +std::string sidechain_net_handler_eth::create_deposit_transaction(const son_wallet_deposit_object &swdo) { + return "";//create_transaction(inputs, outputs, redeem_script); +} + +std::string sidechain_net_handler_eth::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { + return "";//create_transaction(inputs, outputs, redeem_script); +} + +std::string sidechain_net_handler_eth::create_transaction() { + std::string tx_raw;// = write_transaction_data(hex_tx, in_amounts, redeem_script); + return tx_raw; +} + +std::string sidechain_net_handler_eth::sign_transaction(const sidechain_transaction_object &sto) { + std::string tx_signature;// = write_transaction_signatures(sigs); + + return tx_signature; +} + +std::string sidechain_net_handler_eth::send_transaction(const sidechain_transaction_object &sto) { + std::string res;// = eth_client->sendrawtransaction(final_tx_hex); + + return res; +} + +void sidechain_net_handler_eth::handle_event(const std::string &event_data) { +} + +std::string sidechain_net_handler_eth::get_redeemscript_for_userdeposit(const std::string &user_address) { + using namespace bitcoin; + const auto &sidechain_addresses_idx = database.get_index_type().indices().get(); + const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, user_address, time_point_sec::maximum())); + if (addr_itr == sidechain_addresses_idx.end()) { + return ""; + } + + const auto &idx = database.get_index_type().indices().get(); + auto obj = idx.rbegin(); + if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) { + return ""; + } + + std::vector> pubkey_weights; + for (auto &son : obj->sons) { + std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin); + auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); + 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_eth::extract_info_from_block(const std::string &_block) { + std::stringstream ss(_block); + boost::property_tree::ptree block; + boost::property_tree::read_json(ss, block); + + std::vector result; + + return result; +} + +void sidechain_net_handler_eth::on_changed_objects(const vector &ids, const flat_set &accounts) { + fc::time_point now = fc::time_point::now(); + int64_t time_to_next_changed_objects_processing = 5000; + + fc::time_point next_wakeup(now + fc::microseconds(time_to_next_changed_objects_processing)); + + on_changed_objects_task = fc::schedule([this, ids, accounts] { + on_changed_objects_cb(ids, accounts); + }, + next_wakeup, "SON Processing"); +} + +void sidechain_net_handler_eth::on_changed_objects_cb(const vector &ids, const flat_set &accounts) { +} + +// ============================================================================= +}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp index e2cb1608..a5c52920 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,12 @@ bool sidechain_net_manager::create_handler(sidechain_type sidechain, const boost ret_val = true; break; } + case sidechain_type::ethereum: { + std::unique_ptr h = std::unique_ptr(new sidechain_net_handler_eth(plugin, options)); + net_handlers.push_back(std::move(h)); + ret_val = true; + break; + } case sidechain_type::hive: { std::unique_ptr h = std::unique_ptr(new sidechain_net_handler_hive(plugin, options)); net_handlers.push_back(std::move(h)); -- 2.45.2 From eac7f1ead6e88982f8c6e737d9efdbd383b3ebf4 Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Fri, 20 May 2022 12:11:59 -0300 Subject: [PATCH 02/60] websocket connection to geth --- .../sidechain_net_handler_eth.hpp | 36 ++++++-- .../sidechain_net_handler_eth.cpp | 82 +++++++++++++++++-- 2 files changed, 106 insertions(+), 12 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index 7816e99e..44aa29f6 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -3,7 +3,6 @@ #include #include -#include #include @@ -14,13 +13,27 @@ #include #include -#include -#include + +#include +#include namespace graphene { namespace peerplays_sidechain { +typedef websocketpp::client client; + +using websocketpp::lib::placeholders::_1; +using websocketpp::lib::placeholders::_2; +using websocketpp::lib::bind; + +// pull out the type of messages sent by our config +typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr; +typedef websocketpp::lib::shared_ptr context_ptr; +typedef client::connection_ptr connection_ptr; + class eth_rpc_client { public: + typedef eth_rpc_client type; + enum class multi_type { script, address @@ -40,8 +53,17 @@ public: public: eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); - void connect(); + void start(std::string uri); + void on_socket_init(websocketpp::connection_hdl); + void on_fail(websocketpp::connection_hdl hdl); + void on_open(websocketpp::connection_hdl hdl); + void on_message(websocketpp::connection_hdl hdl, message_ptr msg); + void on_close(websocketpp::connection_hdl); + std::string get_chain_id(); + std::string eth_getTransactionReceipt(const std::string& tx_id); + std::string eth_call(const std::string& to, const std::string& data); + std::string eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data); std::string addmultisigaddress(const uint32_t nrequired, const std::vector public_keys); std::string combinepsbt(const vector &psbts); @@ -72,6 +94,8 @@ public: private: std::string geth_url; + uint64_t t_id; + std::string ip; uint32_t rpc_port; std::string user; @@ -82,8 +106,8 @@ private: fc::http::header authorization; - fc::http::websocket_client client; - std::shared_ptr client_connection; + client m_endpoint; + websocketpp::connection_hdl m_hdl; }; // ============================================================================= diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index 0f8b5328..2320ef74 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -19,7 +20,6 @@ #include namespace graphene { namespace peerplays_sidechain { - // ============================================================================= eth_rpc_client::eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) { @@ -27,18 +27,88 @@ eth_rpc_client::eth_rpc_client(const std::string &url, const std::string &user_n user = user_name; this->password = password; this->debug_rpc_calls = debug_rpc_calls; + t_id = 1; ilog("eth_rpc_client"); ilog("### Geth URL: ${url}", ("url", url)); + + m_endpoint.set_access_channels(websocketpp::log::alevel::none); + m_endpoint.set_error_channels(websocketpp::log::elevel::none); + + // Initialize ASIO + m_endpoint.init_asio(); + + // Register our handlers + m_endpoint.set_socket_init_handler(bind(&type::on_socket_init,this,::_1)); + m_endpoint.set_message_handler(bind(&type::on_message,this,::_1,::_2)); + m_endpoint.set_open_handler(bind(&type::on_open,this,::_1)); + m_endpoint.set_close_handler(bind(&type::on_close,this,::_1)); + m_endpoint.set_fail_handler(bind(&type::on_fail,this,::_1)); } -void eth_rpc_client::connect() { - client_connection = std::make_shared(client.connect(geth_url), GRAPHENE_MAX_NESTED_OBJECTS); +void eth_rpc_client::start(std::string uri) { + websocketpp::lib::error_code ec; + client::connection_ptr con = m_endpoint.get_connection(uri, ec); + m_hdl = con->get_handle(); + + if (ec) { + m_endpoint.get_alog().write(websocketpp::log::alevel::app,ec.message()); + return; + } + + m_endpoint.connect(con); + + // Start the ASIO io_service run loop + m_endpoint.run(); +} + +void eth_rpc_client::on_socket_init(websocketpp::connection_hdl) { +} + +void eth_rpc_client::on_fail(websocketpp::connection_hdl hdl) { + client::connection_ptr con = m_endpoint.get_con_from_hdl(hdl); + + elog("Ethereum websocket fail"); + //elog("get_state: ${state}", ("state", con->get_state() ) ); + elog("get_local_close_code: ${code}", ("code", con->get_local_close_code())); + elog("get_local_close_reason: ${close}", ("close",con->get_local_close_reason())); + elog("get_remote_close_code: ${close}", ("close", con->get_remote_close_code())); + elog("get_remote_close_reason: ${close}", ("close", con->get_remote_close_reason())); + elog("get_ec().message(): ${ec}", ("ec", con->get_ec().message())); +} + +void eth_rpc_client::on_open(websocketpp::connection_hdl hdl) { + m_endpoint.send(hdl, "{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":84}", websocketpp::frame::opcode::text); +} + +void eth_rpc_client::on_message(websocketpp::connection_hdl hdl, message_ptr msg) { + + ilog("on_message: ${msg}", ("msg", msg->get_payload())); + + //m_endpoint.close(hdl,websocketpp::close::status::going_away,""); +} + +void eth_rpc_client::on_close(websocketpp::connection_hdl) { + ilog("Ethereum websocket close"); } std::string eth_rpc_client::get_chain_id() { - //std::string reply_str = database_api_get_version(); - return "";//retrieve_value_from_reply(reply_str, "chain_id"); + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":%1%}") % t_id++); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); +} + +std::string eth_rpc_client::eth_getTransactionReceipt(const std::string& tx_id) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"0xbc262e1222ff48cd026a62fd925912ab5006650e311b7711a7216054461a64e0\"],\"id\":%1%}") % t_id++); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + return ""; +} + +std::string eth_rpc_client::eth_call(const std::string& to, const std::string& data) { + return ""; +} + +std::string eth_rpc_client::eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data) { + return ""; } std::string eth_rpc_client::addmultisigaddress(const uint32_t nrequired, const std::vector public_keys) { @@ -155,7 +225,7 @@ sidechain_net_handler_eth::sidechain_net_handler_eth(peerplays_sidechain_plugin url = options.at("ethereum-node-rpc-url").as(); eth_client = std::unique_ptr(new eth_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls)); - eth_client->connect(); + eth_client->start(url); /* if (!wallet.empty()) { eth_client->loadwallet(wallet); -- 2.45.2 From c09044bc70f2380e8f19bf61d59d746a6a5b1e47 Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Tue, 24 May 2022 09:24:46 -0300 Subject: [PATCH 03/60] implement helpers rpc functions, parse json reply, eth_rpc_client stop --- .../sidechain_net_handler_eth.hpp | 22 +++- .../sidechain_net_handler_eth.cpp | 100 +++++++++++++++--- 2 files changed, 105 insertions(+), 17 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index 44aa29f6..3d80cb15 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -54,20 +54,31 @@ public: eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); void start(std::string uri); + void stop(); void on_socket_init(websocketpp::connection_hdl); void on_fail(websocketpp::connection_hdl hdl); void on_open(websocketpp::connection_hdl hdl); void on_message(websocketpp::connection_hdl hdl, message_ptr msg); void on_close(websocketpp::connection_hdl); - std::string get_chain_id(); - std::string eth_getTransactionReceipt(const std::string& tx_id); - std::string eth_call(const std::string& to, const std::string& data); - std::string eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data); + uint64_t get_chain_id(); + uint64_t eth_getTransactionReceipt(const std::string& tx_id); + uint64_t eth_call(const std::string& to, const std::string& data); + uint64_t eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data); + uint64_t eth_sendRawTransaction(const std::string& params); + uint64_t eth_getCode(const std::string& addr); + uint64_t eth_getBalance(const std::string& addr); + uint64_t eth_sign(const string& addr, const string& message); + + std::vector get_list_owners(const std::string& safe_account); + uint64_t add_owner(const std::string& addr ); + uint64_t remove_owner(const std::string& addr); std::string addmultisigaddress(const uint32_t nrequired, const std::vector public_keys); std::string combinepsbt(const vector &psbts); - std::string createmultisig(const uint32_t nrequired, const std::vector public_keys); + + uint64_t createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key); + std::string createpsbt(); std::string createrawtransaction(); std::string createwallet(const std::string &wallet_name); @@ -95,6 +106,7 @@ public: private: std::string geth_url; uint64_t t_id; + std::string safe_account_addr; std::string ip; uint32_t rpc_port; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index 2320ef74..af3b0209 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -19,6 +19,8 @@ #include #include +#include + namespace graphene { namespace peerplays_sidechain { // ============================================================================= @@ -62,6 +64,10 @@ void eth_rpc_client::start(std::string uri) { m_endpoint.run(); } +void eth_rpc_client::stop() { + m_endpoint.close(m_hdl,websocketpp::close::status::normal,""); +} + void eth_rpc_client::on_socket_init(websocketpp::connection_hdl) { } @@ -85,30 +91,86 @@ void eth_rpc_client::on_message(websocketpp::connection_hdl hdl, message_ptr msg ilog("on_message: ${msg}", ("msg", msg->get_payload())); - //m_endpoint.close(hdl,websocketpp::close::status::going_away,""); + fc::variants list = fc::json::variants_from_string( msg->get_payload() ); + + ilog("json reposnse: ${list}", ("list", list)); } void eth_rpc_client::on_close(websocketpp::connection_hdl) { ilog("Ethereum websocket close"); } -std::string eth_rpc_client::get_chain_id() { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":%1%}") % t_id++); +uint64_t eth_rpc_client::get_chain_id() { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":%1%}") % t_id); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + + return t_id++; } -std::string eth_rpc_client::eth_getTransactionReceipt(const std::string& tx_id) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"0xbc262e1222ff48cd026a62fd925912ab5006650e311b7711a7216054461a64e0\"],\"id\":%1%}") % t_id++); +uint64_t eth_rpc_client::eth_getTransactionReceipt(const std::string& tx_id) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"%1%\"],\"id\":%2%}") % tx_id.c_str() % t_id); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - return ""; + return t_id++; } -std::string eth_rpc_client::eth_call(const std::string& to, const std::string& data) { - return ""; +uint64_t eth_rpc_client::eth_call(const std::string& to, const std::string& data) { + std::string req = str(boost::format("{\"jsonrpc\": \"2.0\", \"method\": \"eth_call\", \"params\": [{\"to\": \"%1%\", \"data\": \"%2%\"}, \"latest\"], \"id\": %3%}") % to.c_str() % data.c_str() % t_id); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + + return t_id++; } -std::string eth_rpc_client::eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data) { - return ""; +uint64_t eth_rpc_client::eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sendTransaction\", \"params\": [{\"from\": \"%1%\", \"to\": \"%2%\", \"data\": \"%3%\"}], \"id\": %4%}") % from.c_str() % to.c_str() % data.c_str() % t_id); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + + return t_id++; +} + +uint64_t eth_rpc_client::eth_sendRawTransaction(const std::string& params) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"%1%\"],\"id\":%2%}") % params.c_str() % t_id); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + return t_id++; +} + +uint64_t eth_rpc_client::eth_getCode(const std::string& addr) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getCode\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + + return t_id++; +} + +uint64_t eth_rpc_client::eth_getBalance(const std::string& addr) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getBalance\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + + return t_id++; +} + +uint64_t eth_rpc_client::eth_sign(const string& addr, const string& message) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sign\", \"params\": [\"%1%\",\"%2%\"], \"id\": %2%}") % addr.c_str() % message.c_str() % t_id); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + + return t_id++; +} + +std::vector eth_rpc_client::get_list_owners(const std::string& safe_account) { + std::vector output; + + return output; +} + +uint64_t eth_rpc_client::add_owner(const std::string& addr ) { +} + +uint64_t eth_rpc_client::remove_owner(const std::string& addr) { + //It's require to execute + //execTransaction method of smart contract , using safe-account address + //execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 dataGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) + //std::string address = safe_account_addr; + //std::string value = str(boost::format("%020u") % 0); + //std::string data = "f8dc5dd9000000000000000000000000" + prev_addr; + } std::string eth_rpc_client::addmultisigaddress(const uint32_t nrequired, const std::vector public_keys) { @@ -119,8 +181,22 @@ std::string eth_rpc_client::combinepsbt(const vector &psbts) { return ""; } -std::string eth_rpc_client::createmultisig(const uint32_t nrequired, const std::vector public_keys) { - return ""; +uint64_t eth_rpc_client::createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key) { +//That's will create +//0x5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12 +//0x76ce31BD03f601c3fC13732deF921c5Bac282676 +//0x09EE460834498a4ee361beB819470061B7381B49 +//0x6AEFbd09209e1eE2e0a589d31e732F69B77713D2 +//0x631e128b16f9aDCF1bB6385112B1519C917D77a7 +//0xcD5C788e84220E8b8934Ea4F1dC6a12009bCc91D +//0x3627C1B31525887CB9441130C831e35887650305 +//0x03A13a989AF30C92AD7ABD1E6210308A6c96f373 + + + std::string from = "0xeE52b70e8D7AB5Fe661311D47e81228EAD6B06B9"; + std::string to = "0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2"; + std::string data = "0x1688f0b9000000000000000000000000d9db270c1b5e3bd161e8c8503c55ceabee70955200000000000000000000000000000000000000000000000000000000000000604fa262bd05cdef2e3d5261787ee66d9447a4036324990e04380339bec83b4c7a0000000000000000000000000000000000000000000000000000000000000264b63e800d0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000f48f2b2d2a534e402487b3ee7c18c33aec0fe5e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC1200000000000000000000000076ce31BD03f601c3fC13732deF921c5Bac28267600000000000000000000000009EE460834498a4ee361beB819470061B7381B490000000000000000000000006AEFbd09209e1eE2e0a589d31e732F69B77713D2000000000000000000000000631e128b16f9aDCF1bB6385112B1519C917D77a7000000000000000000000000cD5C788e84220E8b8934Ea4F1dC6a12009bCc91D0000000000000000000000003627C1B31525887CB9441130C831e3588765030500000000000000000000000003A13a989AF30C92AD7ABD1E6210308A6c96f3730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + return eth_sendTransaction(from, to, data); } std::string eth_rpc_client::createpsbt() { -- 2.45.2 From 367a20300795e0aafee280deb0224f2f69c2689e Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Wed, 25 May 2022 09:10:00 -0300 Subject: [PATCH 04/60] add_owner, remove_owner, get_list_owners --- .../sidechain_net_handler_eth.hpp | 8 +++- .../sidechain_net_handler_eth.cpp | 48 +++++++++++++++---- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index 3d80cb15..3faf4a4a 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -70,9 +71,9 @@ public: uint64_t eth_getBalance(const std::string& addr); uint64_t eth_sign(const string& addr, const string& message); - std::vector get_list_owners(const std::string& safe_account); + uint64_t get_list_owners(const std::string& safe_account); uint64_t add_owner(const std::string& addr ); - uint64_t remove_owner(const std::string& addr); + uint64_t remove_owner(const std::string& addr, uint32_t threshold); std::string addmultisigaddress(const uint32_t nrequired, const std::vector public_keys); std::string combinepsbt(const vector &psbts); @@ -107,6 +108,9 @@ private: std::string geth_url; uint64_t t_id; std::string safe_account_addr; + std::vector owners; + uint32_t threshold; + std::unordered_map m_messages; std::string ip; uint32_t rpc_port; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index af3b0209..00c88db9 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -154,22 +154,52 @@ uint64_t eth_rpc_client::eth_sign(const string& addr, const string& message) { return t_id++; } -std::vector eth_rpc_client::get_list_owners(const std::string& safe_account) { - std::vector output; - - return output; +uint64_t eth_rpc_client::get_list_owners(const std::string& safe_account) { + return eth_call(safe_account.c_str(), "0xa0e67e2b"); } uint64_t eth_rpc_client::add_owner(const std::string& addr ) { -} + if (std::count(owners.begin(), owners.end(), addr)){ + FC_THROW_EXCEPTION(fc::exception, "Owners allready have addr: ${addr}", ("addr", addr)); + } -uint64_t eth_rpc_client::remove_owner(const std::string& addr) { //It's require to execute //execTransaction method of smart contract , using safe-account address //execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 dataGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) - //std::string address = safe_account_addr; - //std::string value = str(boost::format("%020u") % 0); - //std::string data = "f8dc5dd9000000000000000000000000" + prev_addr; + std::string method_id = "6a761202"; + std::string address = safe_account_addr; + std::string value = str(boost::format("%020u") % 0); + std::string data = "f8dc5dd9000000000000000000000000" + owners[0] + "000000000000000000000000" + addr + str(boost::format("%032u") % threshold); + std::string operatio = "0"; + std::string safeTxGas = str(boost::format("%032u") % 0); + std::string dataGas = str(boost::format("%032u") % 0); + std::string gasPrice = str(boost::format("%032u") % 0); + std::string gasToken = "0000000000000000000000000000000000000000"; + std::string refundReceiver = "0000000000000000000000000000000000000000"; +} + +uint64_t eth_rpc_client::remove_owner(const std::string& addr, uint32_t threshold) { + if (!std::count(owners.begin(), owners.end(), addr)){ + FC_THROW_EXCEPTION(fc::exception, "Owners does not have addr: ${addr}", ("addr", addr)); + } + + if (threshold == owners.size()){ + FC_THROW_EXCEPTION(fc::exception, "Owners size does not meet threshold: ${th}", ("th", threshold)); + } + + //It's require to execute + //execTransaction method of smart contract , using safe-account address + //execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 dataGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) + std::string method_id = "6a761202"; + std::string address = safe_account_addr; + std::string value = str(boost::format("%032u") % 0); + std::string data = "f8dc5dd90000000000000000000000000000000000000000000000000000000000000001000000000000000000000000" + addr + str(boost::format("%032u") % threshold); + std::string operatio = "0"; + std::string safeTxGas = str(boost::format("%032u") % 0); + std::string dataGas = str(boost::format("%032u") % 0); + std::string gasPrice = str(boost::format("%032u") % 0); + std::string gasToken = "0000000000000000000000000000000000000000"; + std::string refundReceiver = "0000000000000000000000000000000000000000"; } -- 2.45.2 From cff3bec50765965b92d8c604a7aaaa6b28cc7097 Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Thu, 26 May 2022 09:17:26 -0300 Subject: [PATCH 05/60] parse output of rpc commands --- .../sidechain_net_handler_eth.hpp | 18 +++++- .../sidechain_net_handler_eth.cpp | 57 +++++++++++++++++-- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index 3faf4a4a..24478105 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -35,6 +35,20 @@ class eth_rpc_client { public: typedef eth_rpc_client type; + enum req_t { + ETH_CHAIN_ID, + ETH_GET_TRANSACTION_RECEIPT, + ETH_CALL, + ETH_SEND_TRANSACTION, + ETH_SEND_RAW_TRANSACTION, + ETH_GET_CODE, + ETH_GET_BALANCE, + ETH_SIGN, + GET_LIST_OWNERS, + ADD_OWNER, + REMOVE_OWNER + }; + enum class multi_type { script, address @@ -107,10 +121,12 @@ public: private: std::string geth_url; uint64_t t_id; + std::string transaction_id; std::string safe_account_addr; std::vector owners; uint32_t threshold; - std::unordered_map m_messages; + std::unordered_map m_requests; + std::string chain_id;//256 bit value std::string ip; uint32_t rpc_port; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index 00c88db9..06f58b71 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -94,6 +94,46 @@ void eth_rpc_client::on_message(websocketpp::connection_hdl hdl, message_ptr msg fc::variants list = fc::json::variants_from_string( msg->get_payload() ); ilog("json reposnse: ${list}", ("list", list)); + + const auto& b_obj = list[0].get_object().find( "id" ); + std::string result_str = list[0].get_object().find( "result" )->value().as(1); + uint32_t num_owners = 0; + uint32_t i = 0; + fc::variant v; + switch(b_obj->value().as(1)){ + case ETH_CHAIN_ID: + chain_id = result_str; + break; + case ETH_GET_TRANSACTION_RECEIPT: + list = fc::json::variants_from_string( result_str ); + v = list[0].get_object().find( "logs" )->value(); + safe_account_addr = v.get_object().find( "address" )->value().as(1); + break; + case ETH_CALL: + break; + case ETH_SEND_TRANSACTION: + transaction_id = result_str; + break; + case ETH_SEND_RAW_TRANSACTION: + break; + case ETH_GET_CODE: + break; + case ETH_GET_BALANCE: + break; + case ETH_SIGN: + break; + case GET_LIST_OWNERS: + num_owners = (uint32_t)strtol(result_str.substr(2 + 32 + 32 - 4, 4).c_str(), NULL, 16); + owners.clear(); + for (i = 0; i < num_owners; ++i){ + owners.push_back("0x" + result_str.substr(2 + 32 + 32 + 12 + 32 * i,20)); + } + break; + case ADD_OWNER: + break; + case REMOVE_OWNER: + break; + } } void eth_rpc_client::on_close(websocketpp::connection_hdl) { @@ -103,26 +143,29 @@ void eth_rpc_client::on_close(websocketpp::connection_hdl) { uint64_t eth_rpc_client::get_chain_id() { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":%1%}") % t_id); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - + m_requests[t_id] = req_t::ETH_CHAIN_ID; return t_id++; } uint64_t eth_rpc_client::eth_getTransactionReceipt(const std::string& tx_id) { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"%1%\"],\"id\":%2%}") % tx_id.c_str() % t_id); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_GET_TRANSACTION_RECEIPT; return t_id++; } uint64_t eth_rpc_client::eth_call(const std::string& to, const std::string& data) { std::string req = str(boost::format("{\"jsonrpc\": \"2.0\", \"method\": \"eth_call\", \"params\": [{\"to\": \"%1%\", \"data\": \"%2%\"}, \"latest\"], \"id\": %3%}") % to.c_str() % data.c_str() % t_id); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - + m_requests[t_id] = req_t::ETH_CALL; + return t_id++; } uint64_t eth_rpc_client::eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data) { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sendTransaction\", \"params\": [{\"from\": \"%1%\", \"to\": \"%2%\", \"data\": \"%3%\"}], \"id\": %4%}") % from.c_str() % to.c_str() % data.c_str() % t_id); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_SEND_TRANSACTION; return t_id++; } @@ -130,26 +173,29 @@ uint64_t eth_rpc_client::eth_sendTransaction(const std::string& from, const std: uint64_t eth_rpc_client::eth_sendRawTransaction(const std::string& params) { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"%1%\"],\"id\":%2%}") % params.c_str() % t_id); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_SEND_RAW_TRANSACTION; + return t_id++; } uint64_t eth_rpc_client::eth_getCode(const std::string& addr) { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getCode\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - + m_requests[t_id] = req_t::ETH_GET_CODE; return t_id++; } uint64_t eth_rpc_client::eth_getBalance(const std::string& addr) { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getBalance\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - + m_requests[t_id] = req_t::ETH_GET_BALANCE; return t_id++; } uint64_t eth_rpc_client::eth_sign(const string& addr, const string& message) { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sign\", \"params\": [\"%1%\",\"%2%\"], \"id\": %2%}") % addr.c_str() % message.c_str() % t_id); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_SIGN; return t_id++; } @@ -176,6 +222,8 @@ uint64_t eth_rpc_client::add_owner(const std::string& addr ) { std::string gasPrice = str(boost::format("%032u") % 0); std::string gasToken = "0000000000000000000000000000000000000000"; std::string refundReceiver = "0000000000000000000000000000000000000000"; + + m_requests[t_id] = req_t::ADD_OWNER; } uint64_t eth_rpc_client::remove_owner(const std::string& addr, uint32_t threshold) { @@ -201,6 +249,7 @@ uint64_t eth_rpc_client::remove_owner(const std::string& addr, uint32_t threshol std::string gasToken = "0000000000000000000000000000000000000000"; std::string refundReceiver = "0000000000000000000000000000000000000000"; + m_requests[t_id] = req_t::REMOVE_OWNER; } std::string eth_rpc_client::addmultisigaddress(const uint32_t nrequired, const std::vector public_keys) { -- 2.45.2 From 61923c797fe01467def9653aa03b77d85ec557d6 Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Tue, 31 May 2022 08:38:13 -0300 Subject: [PATCH 06/60] eth_coinbase --- .../sidechain_net_handler_eth.hpp | 7 ++++++- .../sidechain_net_handler_eth.cpp | 21 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index 24478105..95d333cd 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -43,7 +43,8 @@ public: ETH_SEND_RAW_TRANSACTION, ETH_GET_CODE, ETH_GET_BALANCE, - ETH_SIGN, + ETH_SIGN, + ETH_COINBASE, GET_LIST_OWNERS, ADD_OWNER, REMOVE_OWNER @@ -84,6 +85,7 @@ public: uint64_t eth_getCode(const std::string& addr); uint64_t eth_getBalance(const std::string& addr); uint64_t eth_sign(const string& addr, const string& message); + uint64_t eth_coinbase(); uint64_t get_list_owners(const std::string& safe_account); uint64_t add_owner(const std::string& addr ); @@ -121,12 +123,15 @@ public: private: std::string geth_url; uint64_t t_id; + std::string account_address; std::string transaction_id; std::string safe_account_addr; std::vector owners; uint32_t threshold; std::unordered_map m_requests; std::string chain_id;//256 bit value + std::string balance; + std::string code; std::string ip; uint32_t rpc_port; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index 06f58b71..97540024 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -85,6 +85,10 @@ void eth_rpc_client::on_fail(websocketpp::connection_hdl hdl) { void eth_rpc_client::on_open(websocketpp::connection_hdl hdl) { m_endpoint.send(hdl, "{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":84}", websocketpp::frame::opcode::text); + + vector owner_addresses; + std::string private_key = ""; + createmultisig(5, owner_addresses, private_key); } void eth_rpc_client::on_message(websocketpp::connection_hdl hdl, message_ptr msg) { @@ -117,11 +121,16 @@ void eth_rpc_client::on_message(websocketpp::connection_hdl hdl, message_ptr msg case ETH_SEND_RAW_TRANSACTION: break; case ETH_GET_CODE: + code = result_str; break; case ETH_GET_BALANCE: + balance = result_str; break; case ETH_SIGN: break; + case ETH_COINBASE: + account_address = result_str; + break; case GET_LIST_OWNERS: num_owners = (uint32_t)strtol(result_str.substr(2 + 32 + 32 - 4, 4).c_str(), NULL, 16); owners.clear(); @@ -200,6 +209,13 @@ uint64_t eth_rpc_client::eth_sign(const string& addr, const string& message) { return t_id++; } +uint64_t eth_rpc_client::eth_coinbase() { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_coinbase\",\"params\":[],\"id\":%1%}") % t_id); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_COINBASE; + return t_id++; +} + uint64_t eth_rpc_client::get_list_owners(const std::string& safe_account) { return eth_call(safe_account.c_str(), "0xa0e67e2b"); } @@ -216,13 +232,16 @@ uint64_t eth_rpc_client::add_owner(const std::string& addr ) { std::string address = safe_account_addr; std::string value = str(boost::format("%020u") % 0); std::string data = "f8dc5dd9000000000000000000000000" + owners[0] + "000000000000000000000000" + addr + str(boost::format("%032u") % threshold); - std::string operatio = "0"; + std::string operation = "0"; std::string safeTxGas = str(boost::format("%032u") % 0); std::string dataGas = str(boost::format("%032u") % 0); std::string gasPrice = str(boost::format("%032u") % 0); std::string gasToken = "0000000000000000000000000000000000000000"; std::string refundReceiver = "0000000000000000000000000000000000000000"; + std::string message = method_id + address + value + data + operation + safeTxGas + dataGas + gasPrice + gasToken + refundReceiver; + uint64_t id = eth_sign(account_address, message); + m_requests[t_id] = req_t::ADD_OWNER; } -- 2.45.2 From 854e5ccb44c5eb533de27c6e3d35543280bde1ad Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Fri, 3 Jun 2022 09:17:10 -0300 Subject: [PATCH 07/60] ethereum_function_call_encoder --- CMakeLists.txt | 1 + libraries/fc | 2 +- .../sidechain_net_handler_eth.hpp | 9 ++- .../sidechain_net_handler_eth.cpp | 58 ++++++++++++++++++- 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 695881be..1d4c2f1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") list(GET arg_list 0 output) message("Ubuntu version is: ${output}") add_definitions(-DPEERPLAYS_UBUNTU_VERSION=${output}) + endif() # function to help with cUrl diff --git a/libraries/fc b/libraries/fc index e7369949..c24b2df9 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit e7369949bea26f3201d8442ba78286a88df74762 +Subproject commit c24b2df96d949f25ff85ca0aae5e17da111bde79 diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index 95d333cd..505bc3a4 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -66,7 +66,6 @@ public: std::string label; }; -public: eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); void start(std::string uri); @@ -121,6 +120,14 @@ public: bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); private: + class ethereum_function_call_encoder { + std::string encode_function_signature(const std::string& function_signature); + std::string encode_address(const std::string& addr); + std::string encode_uint256(const std::string& value); + std::string encode_uint8(uint8_t value); + std::string encode_bytes(const std::string& values); + }; + std::string geth_url; uint64_t t_id; std::string account_address; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index 97540024..25464be8 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -20,9 +20,49 @@ #include #include +extern "C" { +#include +} namespace graphene { namespace peerplays_sidechain { // ============================================================================= +std::string eth_rpc_client::ethereum_function_call_encoder::encode_function_signature(const std::string& function_signature) { + sha3_context c; + uint8_t *hash; + + sha3_Init256(static_cast(&c)); + sha3_Update(&c, "abc", 3); + hash = (uint8_t*)sha3_Finalize(&c); + +// 'hash' points to a buffer inside 'c' +// with the value of SHA3-256 +// + return ""; +}; + +std::string eth_rpc_client::ethereum_function_call_encoder::encode_address(const std::string& addr) { + FC_ASSERT(20 == addr.length()); + std::string output = str(boost::format("%012u") % 0) + addr; + return output; +} + +std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint256(const std::string& value) { + FC_ASSERT(value.length() <= 64); + std::string output = std::string(64 - value.length(), '0') + value; + return output; +} + +std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint8(uint8_t value) { + std::string output = str(boost::format("%02X") % value) + std::string(62, '0'); + return output; +} + +std::string eth_rpc_client::ethereum_function_call_encoder::encode_bytes(const std::string& values) { + size_t len = values.length(); + std::string output = encode_uint256((boost::format("%x") % len).str()) + values + std::string(64 - len, '0'); + return output; +} + eth_rpc_client::eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) { geth_url = url; @@ -983,9 +1023,23 @@ std::string sidechain_net_handler_eth::create_transaction() { } std::string sidechain_net_handler_eth::sign_transaction(const sidechain_transaction_object &sto) { - std::string tx_signature;// = write_transaction_signatures(sigs); +/* + std::stringstream ss_trx(boost::algorithm::unhex(sto.transaction)); + hive::signed_transaction htrx; + fc::raw::unpack(ss_trx, htrx, 1000); + + std::string chain_id_str = node_rpc_client->get_chain_id(); + const hive::chain_id_type chain_id(chain_id_str); + + fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))); + signature_type st = htrx.sign(*privkey, chain_id); + + std::stringstream ss_st; + fc::raw::pack(ss_st, st, 1000); + std::string st_str = boost::algorithm::hex(ss_st.str()); +*/ + return "";//st_str; - return tx_signature; } std::string sidechain_net_handler_eth::send_transaction(const sidechain_transaction_object &sto) { -- 2.45.2 From 1bfa8dba1412491acb25e14122e3facfdb9cc925 Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Fri, 3 Jun 2022 12:49:30 -0300 Subject: [PATCH 08/60] use ethereum_function_call_encoder for signature calculation --- .../sidechain_net_handler_eth.hpp | 13 ++++++++----- .../sidechain_net_handler_eth.cpp | 18 ++++++++++-------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index 505bc3a4..40f2a7ae 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -121,13 +121,16 @@ public: private: class ethereum_function_call_encoder { - std::string encode_function_signature(const std::string& function_signature); - std::string encode_address(const std::string& addr); - std::string encode_uint256(const std::string& value); - std::string encode_uint8(uint8_t value); - std::string encode_bytes(const std::string& values); + public: + std::string encode_function_signature(const std::string& function_signature); + std::string encode_address(const std::string& addr); + std::string encode_uint256(const std::string& value); + std::string encode_uint8(uint8_t value); + std::string encode_bytes(const std::string& values); }; + ethereum_function_call_encoder m_ethereum_function_call_encoder; + std::string geth_url; uint64_t t_id; std::string account_address; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index 25464be8..7fe06e86 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -28,16 +28,16 @@ namespace graphene { namespace peerplays_sidechain { // ============================================================================= std::string eth_rpc_client::ethereum_function_call_encoder::encode_function_signature(const std::string& function_signature) { sha3_context c; - uint8_t *hash; + char *hash; sha3_Init256(static_cast(&c)); + sha3_SetFlags(&c, SHA3_FLAGS_KECCAK); sha3_Update(&c, "abc", 3); - hash = (uint8_t*)sha3_Finalize(&c); + hash = (char*)sha3_Finalize(&c); + std::string output(hash); + output = output.substr(0,8); -// 'hash' points to a buffer inside 'c' -// with the value of SHA3-256 -// - return ""; + return output; }; std::string eth_rpc_client::ethereum_function_call_encoder::encode_address(const std::string& addr) { @@ -268,7 +268,8 @@ uint64_t eth_rpc_client::add_owner(const std::string& addr ) { //It's require to execute //execTransaction method of smart contract , using safe-account address //execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 dataGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) - std::string method_id = "6a761202"; + std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); + FC_ASSERT("6a761202" == method_id); std::string address = safe_account_addr; std::string value = str(boost::format("%020u") % 0); std::string data = "f8dc5dd9000000000000000000000000" + owners[0] + "000000000000000000000000" + addr + str(boost::format("%032u") % threshold); @@ -297,7 +298,8 @@ uint64_t eth_rpc_client::remove_owner(const std::string& addr, uint32_t threshol //It's require to execute //execTransaction method of smart contract , using safe-account address //execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 dataGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) - std::string method_id = "6a761202"; + std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); + FC_ASSERT("6a761202" == method_id); std::string address = safe_account_addr; std::string value = str(boost::format("%032u") % 0); std::string data = "f8dc5dd90000000000000000000000000000000000000000000000000000000000000001000000000000000000000000" + addr + str(boost::format("%032u") % threshold); -- 2.45.2 From 4e9d5805f925ef4b2a30aa683d3ba23651c2f2b2 Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Tue, 7 Jun 2022 07:23:53 -0300 Subject: [PATCH 09/60] handle errors in geth webscoket replies, save signatures --- .../peerplays_sidechain/sidechain_net_handler_eth.hpp | 1 + .../peerplays_sidechain/sidechain_net_handler_eth.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index 40f2a7ae..d322da3a 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -131,6 +131,7 @@ private: ethereum_function_call_encoder m_ethereum_function_call_encoder; + std::string signature; std::string geth_url; uint64_t t_id; std::string account_address; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index 7fe06e86..2b939085 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -140,6 +140,12 @@ void eth_rpc_client::on_message(websocketpp::connection_hdl hdl, message_ptr msg ilog("json reposnse: ${list}", ("list", list)); const auto& b_obj = list[0].get_object().find( "id" ); + + if (true == list[0].get_object().contains( "error" )){ + elog("error in json reposnse: ${list}", ("list", list)); + return; + } + std::string result_str = list[0].get_object().find( "result" )->value().as(1); uint32_t num_owners = 0; uint32_t i = 0; @@ -167,6 +173,7 @@ void eth_rpc_client::on_message(websocketpp::connection_hdl hdl, message_ptr msg balance = result_str; break; case ETH_SIGN: + signature = result_str; break; case ETH_COINBASE: account_address = result_str; -- 2.45.2 From 02f40093d08394f1bf3c8dfeced77a6ad593f935 Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Tue, 7 Jun 2022 09:02:56 -0300 Subject: [PATCH 10/60] ethereum transaction class and RLP --- .../peerplays_sidechain/ethereum/RLP.h | 472 ++++++++++++++++++ .../ethereum/transaction.hpp | 78 +++ 2 files changed, 550 insertions(+) create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/RLP.h create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/RLP.h b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/RLP.h new file mode 100644 index 00000000..99a77023 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/RLP.h @@ -0,0 +1,472 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2013-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +/// @file +/// Recursive Linear-Prefix serialization / deserialization. +#pragma once + +#include "Exceptions.h" +#include "FixedHash.h" +#include "vector_ref.h" + +#include +#include +#include +#include +#include + +namespace dev +{ + +class RLP; + +template struct intTraits { static const unsigned maxSize = sizeof(_T); }; +template <> struct intTraits { static const unsigned maxSize = 20; }; +template <> struct intTraits { static const unsigned maxSize = 32; }; +template <> struct intTraits { static const unsigned maxSize = ~(unsigned)0; }; + +static const byte c_rlpMaxLengthBytes = 8; +static const byte c_rlpDataImmLenStart = 0x80; +static const byte c_rlpListStart = 0xc0; + +static const byte c_rlpDataImmLenCount = c_rlpListStart - c_rlpDataImmLenStart - c_rlpMaxLengthBytes; +static const byte c_rlpDataIndLenZero = c_rlpDataImmLenStart + c_rlpDataImmLenCount - 1; +static const byte c_rlpListImmLenCount = 256 - c_rlpListStart - c_rlpMaxLengthBytes; +static const byte c_rlpListIndLenZero = c_rlpListStart + c_rlpListImmLenCount - 1; + +template struct Converter { static T convert(RLP const&, int) { BOOST_THROW_EXCEPTION(BadCast()); } }; + +/** + * Class for interpreting Recursive Linear-Prefix Data. + */ +class RLP +{ +public: + /// Conversion flags + enum + { + AllowNonCanon = 1, + ThrowOnFail = 4, + FailIfTooBig = 8, + FailIfTooSmall = 16, + Strict = ThrowOnFail | FailIfTooBig, + VeryStrict = ThrowOnFail | FailIfTooBig | FailIfTooSmall, + LaissezFaire = AllowNonCanon + }; + + using Strictness = int; + + /// Construct a null node. + RLP() {} + + /// Construct a node of value given in the bytes. + explicit RLP(bytesConstRef _d, Strictness _s = VeryStrict); + + /// Construct a node of value given in the bytes. + explicit RLP(bytes const& _d, Strictness _s = VeryStrict): RLP(&_d, _s) {} + + /// Construct a node to read RLP data in the bytes given. + RLP(byte const* _b, unsigned _s, Strictness _st = VeryStrict): RLP(bytesConstRef(_b, _s), _st) {} + + /// Construct a node to read RLP data in the string. + explicit RLP(std::string const& _s, Strictness _st = VeryStrict): RLP(bytesConstRef((byte const*)_s.data(), _s.size()), _st) {} + + /// The bare data of the RLP. + bytesConstRef data() const { return m_data; } + + /// @returns true if the RLP is non-null. + explicit operator bool() const { return !isNull(); } + + /// No value. + bool isNull() const { return m_data.size() == 0; } + + /// Contains a zero-length string or zero-length list. + bool isEmpty() const { return !isNull() && (m_data[0] == c_rlpDataImmLenStart || m_data[0] == c_rlpListStart); } + + /// String value. + bool isData() const { return !isNull() && m_data[0] < c_rlpListStart; } + + /// List value. + bool isList() const { return !isNull() && m_data[0] >= c_rlpListStart; } + + /// Integer value. Must not have a leading zero. + bool isInt() const; + + /// @returns the number of items in the list, or zero if it isn't a list. + size_t itemCount() const { return isList() ? items() : 0; } + size_t itemCountStrict() const { if (!isList()) BOOST_THROW_EXCEPTION(BadCast()); return items(); } + + /// @returns the number of bytes in the data, or zero if it isn't data. + size_t size() const { return isData() ? length() : 0; } + size_t sizeStrict() const { if (!isData()) BOOST_THROW_EXCEPTION(BadCast()); return length(); } + + /// Equality operators; does best-effort conversion and checks for equality. + bool operator==(char const* _s) const { return isData() && toString() == _s; } + bool operator!=(char const* _s) const { return isData() && toString() != _s; } + bool operator==(std::string const& _s) const { return isData() && toString() == _s; } + bool operator!=(std::string const& _s) const { return isData() && toString() != _s; } + template bool operator==(FixedHash<_N> const& _h) const { return isData() && toHash<_N>() == _h; } + template bool operator!=(FixedHash<_N> const& _s) const { return isData() && toHash<_N>() != _s; } + bool operator==(unsigned const& _i) const { return isInt() && toInt() == _i; } + bool operator!=(unsigned const& _i) const { return isInt() && toInt() != _i; } + bool operator==(u256 const& _i) const { return isInt() && toInt() == _i; } + bool operator!=(u256 const& _i) const { return isInt() && toInt() != _i; } + bool operator==(bigint const& _i) const { return isInt() && toInt() == _i; } + bool operator!=(bigint const& _i) const { return isInt() && toInt() != _i; } + + /// Subscript operator. + /// @returns the list item @a _i if isList() and @a _i < listItems(), or RLP() otherwise. + /// @note if used to access items in ascending order, this is efficient. + RLP operator[](size_t _i) const; + + using element_type = RLP; + + /// @brief Iterator class for iterating through items of RLP list. + class iterator + { + friend class RLP; + + public: + using value_type = RLP; + using element_type = RLP; + + iterator& operator++(); + iterator operator++(int) { auto ret = *this; operator++(); return ret; } + RLP operator*() const { return RLP(m_currentItem); } + bool operator==(iterator const& _cmp) const { return m_currentItem == _cmp.m_currentItem; } + bool operator!=(iterator const& _cmp) const { return !operator==(_cmp); } + + private: + iterator() {} + iterator(RLP const& _parent, bool _begin); + + size_t m_remaining = 0; + bytesConstRef m_currentItem; + }; + + /// @brief Iterator into beginning of sub-item list (valid only if we are a list). + iterator begin() const { return iterator(*this, true); } + + /// @brief Iterator into end of sub-item list (valid only if we are a list). + iterator end() const { return iterator(*this, false); } + + template inline T convert(int _flags) const; + + /// Best-effort conversion operators. + explicit operator std::string() const { return toString(); } + explicit operator bytes() const { return toBytes(); } + explicit operator uint8_t() const { return toInt(); } + explicit operator uint16_t() const { return toInt(); } + explicit operator uint32_t() const { return toInt(); } + explicit operator uint64_t() const { return toInt(); } + explicit operator u160() const { return toInt(); } + explicit operator u256() const { return toInt(); } + explicit operator bigint() const { return toInt(); } + template explicit operator FixedHash() const { return toHash>(); } + template explicit operator std::pair() const { return toPair(); } + template explicit operator std::vector() const { return toVector(); } + template explicit operator std::set() const { return toSet(); } + template explicit operator std::array() const { return toArray(); } + + /// Converts to bytearray. @returns the empty byte array if not a string. + bytes toBytes(int _flags = LaissezFaire) const { if (!isData()) { if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else return bytes(); } return bytes(payload().data(), payload().data() + length()); } + /// Converts to bytearray. @returns the empty byte array if not a string. + bytesConstRef toBytesConstRef(int _flags = LaissezFaire) const { if (!isData()) { if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else return bytesConstRef(); } return payload().cropped(0, length()); } + /// Converts to string. @returns the empty string if not a string. + std::string toString(int _flags = LaissezFaire) const { if (!isData()) { if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else return std::string(); } return payload().cropped(0, length()).toString(); } + /// Converts to string. @throws BadCast if not a string. + std::string toStringStrict() const { return toString(Strict); } + + template + std::vector toVector(int _flags = LaissezFaire) const + { + std::vector ret; + if (isList()) + { + ret.reserve(itemCount()); + for (auto const& i: *this) + ret.push_back(i.convert(_flags)); + } + else if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + return ret; + } + + template + std::set toSet(int _flags = LaissezFaire) const + { + std::set ret; + if (isList()) + for (auto const& i: *this) + ret.insert(i.convert(_flags)); + else if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + return ret; + } + + template + std::unordered_set toUnorderedSet(int _flags = LaissezFaire) const + { + std::unordered_set ret; + if (isList()) + for (auto const& i: *this) + ret.insert(i.convert(_flags)); + else if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + return ret; + } + + template + std::pair toPair(int _flags = Strict) const + { + std::pair ret; + if (itemCountStrict() != 2) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return ret; + } + ret.first = (*this)[0].convert(_flags); + ret.second = (*this)[1].convert(_flags); + return ret; + } + + template + std::array toArray(int _flags = LaissezFaire) const + { + if (itemCount() != N) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return std::array(); + } + std::array ret; + for (size_t i = 0; i < N; ++i) + ret[i] = operator[](i).convert(_flags); + return ret; + } + + /// Converts to int of type given; if isData(), decodes as big-endian bytestream. @returns 0 if not an int or data. + template _T toInt(int _flags = Strict) const + { + requireGood(); + if ((!isInt() && !(_flags & AllowNonCanon)) || isList() || isNull()) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return 0; + } + + auto p = payload(); + if (p.size() > intTraits<_T>::maxSize && (_flags & FailIfTooBig)) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return 0; + } + + return fromBigEndian<_T>(p); + } + + int64_t toPositiveInt64(int _flags = Strict) const + { + int64_t i = toInt(_flags); + if ((_flags & ThrowOnFail) && i < 0) + BOOST_THROW_EXCEPTION(BadCast()); + return i; + } + + template _N toHash(int _flags = Strict) const + { + requireGood(); + auto p = payload(); + auto l = p.size(); + if (!isData() || (l > _N::size && (_flags & FailIfTooBig)) || (l < _N::size && (_flags & FailIfTooSmall))) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return _N(); + } + + _N ret; + size_t s = std::min(_N::size, l); + memcpy(ret.data() + _N::size - s, p.data(), s); + return ret; + } + + /// @returns the data payload. Valid for all types. + bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) BOOST_THROW_EXCEPTION(BadRLP()); return m_data.cropped(payloadOffset(), l); } + + /// @returns the theoretical size of this item as encoded in the data. + /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work. + size_t actualSize() const; + +private: + /// Disable construction from rvalue + explicit RLP(bytes const&&) {} + + /// Throws if is non-canonical data (i.e. single byte done in two bytes that could be done in one). + void requireGood() const; + + /// Single-byte data payload. + bool isSingleByte() const { return !isNull() && m_data[0] < c_rlpDataImmLenStart; } + + /// @returns the amount of bytes used to encode the length of the data. Valid for all types. + unsigned lengthSize() const { if (isData() && m_data[0] > c_rlpDataIndLenZero) return m_data[0] - c_rlpDataIndLenZero; if (isList() && m_data[0] > c_rlpListIndLenZero) return m_data[0] - c_rlpListIndLenZero; return 0; } + + /// @returns the size in bytes of the payload, as given by the RLP as opposed to as inferred from m_data. + size_t length() const; + + /// @returns the number of bytes into the data that the payload starts. + size_t payloadOffset() const { return isSingleByte() ? 0 : (1 + lengthSize()); } + + /// @returns the number of data items. + size_t items() const; + + /// @returns the size encoded into the RLP in @a _data and throws if _data is too short. + static size_t sizeAsEncoded(bytesConstRef _data) { return RLP(_data, ThrowOnFail | FailIfTooSmall).actualSize(); } + + /// Our byte data. + bytesConstRef m_data; + + /// The list-indexing cache. + // Index of the last item accessed with operator[] + mutable size_t m_lastIndex = (size_t)-1; + // Offset of the next byte after last byte of m_lastItem + mutable size_t m_lastEnd = 0; + // Data of the last item accessed with operator[] + mutable bytesConstRef m_lastItem; +}; + +template <> struct Converter { static std::string convert(RLP const& _r, int _flags) { return _r.toString(_flags); } }; +template <> struct Converter { static bytes convert(RLP const& _r, int _flags) { return _r.toBytes(_flags); } }; +template <> struct Converter { static uint8_t convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template <> struct Converter { static uint16_t convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template <> struct Converter { static uint32_t convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template <> struct Converter { static uint64_t convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template <> struct Converter { static u160 convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template <> struct Converter { static u256 convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template <> struct Converter { static bigint convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template struct Converter> { static FixedHash convert(RLP const& _r, int _flags) { return _r.toHash>(_flags); } }; +template struct Converter> { static std::pair convert(RLP const& _r, int _flags) { return _r.toPair(_flags); } }; +template struct Converter> { static std::vector convert(RLP const& _r, int _flags) { return _r.toVector(_flags); } }; +template struct Converter> { static std::set convert(RLP const& _r, int _flags) { return _r.toSet(_flags); } }; +template struct Converter> { static std::unordered_set convert(RLP const& _r, int _flags) { return _r.toUnorderedSet(_flags); } }; +template struct Converter> { static std::array convert(RLP const& _r, int _flags) { return _r.toArray(_flags); } }; + +template inline T RLP::convert(int _flags) const { return Converter::convert(*this, _flags); } + +/** + * @brief Class for writing to an RLP bytestream. + */ +class RLPStream +{ +public: + /// Initializes empty RLPStream. + RLPStream() {} + + /// Initializes the RLPStream as a list of @a _listItems items. + explicit RLPStream(size_t _listItems) { appendList(_listItems); } + + ~RLPStream() {} + + /// Append given datum to the byte stream. + RLPStream& append(unsigned _s) { return append(bigint(_s)); } + RLPStream& append(u160 _s) { return append(bigint(_s)); } + RLPStream& append(u256 _s) { return append(bigint(_s)); } + RLPStream& append(bigint _s); + RLPStream& append(bytesConstRef _s, bool _compact = false); + RLPStream& append(bytes const& _s) { return append(bytesConstRef(&_s)); } + RLPStream& append(std::string const& _s) { return append(bytesConstRef(_s)); } + RLPStream& append(char const* _s) { return append(std::string(_s)); } + template RLPStream& append(FixedHash _s, bool _compact = false, bool _allOrNothing = false) { return _allOrNothing && !_s ? append(bytesConstRef()) : append(_s.ref(), _compact); } + + /// Appends an arbitrary RLP fragment - this *must* be a single item unless @a _itemCount is given. + RLPStream& append(RLP const& _rlp, size_t _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); } + + /// Appends a sequence of data to the stream as a list. + template RLPStream& append(std::vector<_T> const& _s) { return appendVector(_s); } + template RLPStream& appendVector(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } + template RLPStream& append(std::array<_T, S> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } + template RLPStream& append(std::set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } + template RLPStream& append(std::unordered_set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } + template RLPStream& append(std::pair const& _s) { appendList(2); append(_s.first); append(_s.second); return *this; } + + /// Appends a list. + RLPStream& appendList(size_t _items); + RLPStream& appendList(bytesConstRef _rlp); + RLPStream& appendList(bytes const& _rlp) { return appendList(&_rlp); } + RLPStream& appendList(RLPStream const& _s) { return appendList(&_s.out()); } + + /// Appends raw (pre-serialised) RLP data. Use with caution. + RLPStream& appendRaw(bytesConstRef _rlp, size_t _itemCount = 1); + RLPStream& appendRaw(bytes const& _rlp, size_t _itemCount = 1) { return appendRaw(&_rlp, _itemCount); } + + /// Shift operators for appending data items. + template RLPStream& operator<<(T _data) { return append(_data); } + + /// Clear the output stream so far. + void clear() { m_out.clear(); m_listStack.clear(); } + + /// Read the byte stream. + bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; } + + /// Invalidate the object and steal the output byte stream. + bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); } + + /// Swap the contents of the output stream out for some other byte array. + void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); } + +private: + void noteAppended(size_t _itemCount = 1); + + /// Push the node-type byte (using @a _base) along with the item count @a _count. + /// @arg _count is number of characters for strings, data-bytes for ints, or items for lists. + void pushCount(size_t _count, byte _offset); + + /// Push an integer as a raw big-endian byte-stream. + template void pushInt(_T _i, size_t _br) + { + m_out.resize(m_out.size() + _br); + byte* b = &m_out.back(); + for (; _i; _i >>= 8) + *(b--) = (byte)(_i & 0xff); + } + + /// Our output byte stream. + bytes m_out; + + std::vector> m_listStack; +}; + +template void rlpListAux(RLPStream& _out, _T _t) { _out << _t; } +template void rlpListAux(RLPStream& _out, _T _t, _Ts ... _ts) { rlpListAux(_out << _t, _ts...); } + +/// Export a single item in RLP format, returning a byte array. +template bytes rlp(_T _t) { return (RLPStream() << _t).out(); } + +/// Export a list of items in RLP format, returning a byte array. +inline bytes rlpList() { return RLPStream(0).out(); } +template bytes rlpList(_Ts ... _ts) +{ + RLPStream out(sizeof ...(_Ts)); + rlpListAux(out, _ts...); + return out.out(); +} + +/// The empty string in RLP format. +extern bytes RLPNull; + +/// The empty list in RLP format. +extern bytes RLPEmptyList; + +/// Human readable version of RLP. +std::ostream& operator<<(std::ostream& _out, dev::RLP const& _d); + +} diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp new file mode 100644 index 00000000..116a6df3 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include +#include + +#include +#include + + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +class transaction { + uint16_t ref_block_num = 0; + uint32_t ref_block_prefix = 0; + fc::time_point_sec expiration; + std::vector operations; + extensions_type extensions; + + digest_type digest() const; + transaction_id_type id() const; + digest_type sig_digest(const chain_id_type &chain_id) const; + + void set_expiration(fc::time_point_sec expiration_time); + void set_reference_block(const block_id_type &reference_block); + + /// Serialises this transaction to an RLPStream. + /// @throws TransactionIsUnsigned if including signature was requested but it was not initialized + void streamRLP(RLPStream& _s, IncludeSignature _sig = WithSignature, bool _forEip155hash = false) const; + + /// @returns the RLP serialisation of this transaction. + bytes rlp(IncludeSignature _sig = WithSignature) const { RLPStream s; streamRLP(s, _sig); return s.out(); } +protected: + /// Type of transaction. + enum Type + { + NullTransaction, ///< Null transaction. + ContractCreation, ///< Transaction to create contracts - receiveAddress() is ignored. + MessageCall ///< Transaction to invoke a message call - receiveAddress() is used. + }; + + static bool isZeroSignature(u256 const& _r, u256 const& _s) { return !_r && !_s; } + + /// Clears the signature. + void clearSignature() { m_vrs = SignatureStruct(); } + + Type m_type = NullTransaction; ///< Is this a contract-creation transaction or a message-call transaction? + u256 m_nonce; ///< The transaction-count of the sender. + u256 m_value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. + Address m_receiveAddress; ///< The receiving address of the transaction. + u256 m_gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. + u256 m_gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. + bytes m_data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. + boost::optional m_vrs; ///< The signature of the transaction. Encodes the sender. + /// EIP155 value for calculating transaction hash + /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md + boost::optional m_chainId; + + mutable h256 m_hashWith; ///< Cached hash of transaction with signature. + mutable boost::optional
m_sender; ///< Cached sender, determined from signature. +}; + +class signed_transaction : public transaction { +public: + std::vector signatures; + + const signature_type &sign(const ethereum::private_key_type &key, const ethereum::chain_id_type &chain_id); + signature_type sign(const ethereum::private_key_type &key, const ethereum::chain_id_type &chain_id) const; + void clear(); +}; + +}}} // namespace graphene::peerplays_sidechain::ethereum + +FC_REFLECT(graphene::peerplays_sidechain::ethereum::transaction, + (ref_block_num)(ref_block_prefix)(expiration)(operations)(extensions)) + +FC_REFLECT_DERIVED(graphene::peerplays_sidechain::ethereum::signed_transaction, + (graphene::peerplays_sidechain::ethereum::transaction), + (signatures)) -- 2.45.2 From 9334080df544c411bd8280966b36f1b25b6d6d09 Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Thu, 9 Jun 2022 05:19:14 -0300 Subject: [PATCH 11/60] sign transaction in peeerplays --- .../peerplays_sidechain/CMakeLists.txt | 2 + .../ethereum/transaction.cpp | 57 ++++++++ .../peerplays_sidechain/ethereum/types.cpp | 73 +++++++++++ .../peerplays_sidechain/ethereum/asset.hpp | 41 ++++++ .../ethereum/authority.hpp | 33 +++++ .../ethereum/ethereum_operations.hpp | 123 ++++++++++++++++++ .../ethereum/operations.hpp | 69 ++++++++++ .../ethereum/transaction.hpp | 12 +- .../peerplays_sidechain/ethereum/types.hpp | 72 ++++++++++ .../sidechain_net_handler_eth.hpp | 2 +- .../sidechain_net_handler_eth.cpp | 15 ++- 11 files changed, 490 insertions(+), 9 deletions(-) create mode 100644 libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp create mode 100644 libraries/plugins/peerplays_sidechain/ethereum/types.cpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/asset.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/authority.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/ethereum_operations.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index b61e908d..57a91935 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -22,6 +22,8 @@ add_library( peerplays_sidechain hive/operations.cpp hive/transaction.cpp hive/types.cpp + ethereum/transaction.cpp + ethereum/types.cpp ) if (ENABLE_DEV_FEATURES) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp new file mode 100644 index 00000000..f952dadd --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -0,0 +1,57 @@ +#include + +#include + +#include +#include + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +digest_type transaction::digest() const { + digest_type::encoder enc; + fc::raw::pack(enc, *this); + return enc.result(); +} + +transaction_id_type transaction::id() const { + auto h = digest(); + transaction_id_type result; + memcpy(result._hash, h._hash, std::min(sizeof(result), sizeof(h))); + return result; +} + +digest_type transaction::sig_digest(const chain_id_type &chain_id) const { + digest_type::encoder enc; + fc::raw::pack(enc, chain_id); + fc::raw::pack(enc, *this); + return enc.result(); +} + +void transaction::set_expiration(fc::time_point_sec expiration_time) { + expiration = expiration_time; +} + +void transaction::set_reference_block(const block_id_type &reference_block) { + ref_block_num = fc::endian_reverse_u32(reference_block._hash[0]); + ref_block_prefix = reference_block._hash[1]; +} + +void signed_transaction::clear() { + operations.clear(); + signatures.clear(); +} + +const signature_type &signed_transaction::sign(const ethereum::private_key_type &key, const ethereum::chain_id_type &chain_id) { + digest_type h = sig_digest(chain_id); + signatures.push_back(key.sign_compact(h, true)); + return signatures.back(); +} + +signature_type signed_transaction::sign(const ethereum::private_key_type &key, const ethereum::chain_id_type &chain_id) const { + digest_type::encoder enc; + fc::raw::pack(enc, chain_id); + fc::raw::pack(enc, *this); + return key.sign_compact(enc.result(), true); +} + +}}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/types.cpp b/libraries/plugins/peerplays_sidechain/ethereum/types.cpp new file mode 100644 index 00000000..7a62cc58 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/ethereum/types.cpp @@ -0,0 +1,73 @@ +#include + +#include +#include +#include +#include + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +std::string public_key_type::prefix = KEY_PREFIX_STM; + +public_key_type::public_key_type() : + key_data(){}; + +public_key_type::public_key_type(const fc::ecc::public_key_data &data) : + key_data(data){}; + +public_key_type::public_key_type(const fc::ecc::public_key &pubkey) : + key_data(pubkey){}; + +public_key_type::public_key_type(const std::string &base58str) { + const size_t prefix_len = prefix.size(); + FC_ASSERT(base58str.size() > prefix_len); + FC_ASSERT(base58str.substr(0, prefix_len) == prefix, "", ("base58str", base58str)); + auto bin = fc::from_base58(base58str.substr(prefix_len)); + auto bin_key = fc::raw::unpack(bin); + key_data = bin_key.data; + FC_ASSERT(fc::ripemd160::hash(key_data.data, key_data.size())._hash[0] == bin_key.check); +}; + +public_key_type::operator fc::ecc::public_key_data() const { + return key_data; +}; + +public_key_type::operator fc::ecc::public_key() const { + return fc::ecc::public_key(key_data); +}; + +public_key_type::operator std::string() const { + binary_key k; + k.data = key_data; + k.check = fc::ripemd160::hash(k.data.data, k.data.size())._hash[0]; + auto data = fc::raw::pack(k); + return prefix + fc::to_base58(data.data(), data.size()); +} + +bool operator==(const public_key_type &p1, const fc::ecc::public_key &p2) { + return p1.key_data == p2.serialize(); +} + +bool operator==(const public_key_type &p1, const public_key_type &p2) { + return p1.key_data == p2.key_data; +} + +bool operator!=(const public_key_type &p1, const public_key_type &p2) { + return p1.key_data != p2.key_data; +} + +}}} // namespace graphene::peerplays_sidechain::ethereum + +namespace fc { + +using namespace std; + +void to_variant(const graphene::peerplays_sidechain::ethereum::public_key_type &var, fc::variant &vo, uint32_t max_depth) { + vo = std::string(var); +} + +void from_variant(const fc::variant &var, graphene::peerplays_sidechain::ethereum::public_key_type &vo, uint32_t max_depth) { + vo = graphene::peerplays_sidechain::ethereum::public_key_type(var.as_string()); +} + +} // namespace fc diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/asset.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/asset.hpp new file mode 100644 index 00000000..05aed34f --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/asset.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +#define HBD_NAI "@@000000013" +#define HBD_PRECISION 3 +#define HBD_SYMBOL_U64 (uint64_t('S') | (uint64_t('B') << 8) | (uint64_t('D') << 16)) +#define HBD_SYMBOL_SER (uint64_t(3) | (HBD_SYMBOL_U64 << 8)) + +#define HIVE_NAI "@@000000021" +#define HIVE_PRECISION 3 +#define HIVE_SYMBOL_U64 (uint64_t('S') | (uint64_t('T') << 8) | (uint64_t('E') << 16) | (uint64_t('E') << 24) | (uint64_t('M') << 32)) +#define HIVE_SYMBOL_SER (uint64_t(3) | (HIVE_SYMBOL_U64 << 8)) + +#define TBD_NAI "@@000000013" +#define TBD_PRECISION 3 +#define TBD_SYMBOL_U64 (uint64_t('T') | (uint64_t('B') << 8) | (uint64_t('D') << 16)) +#define TBD_SYMBOL_SER (uint64_t(3) | (TBD_SYMBOL_U64 << 8)) + +#define TESTS_NAI "@@000000021" +#define TESTS_PRECISION 3 +#define TESTS_SYMBOL_U64 (uint64_t('T') | (uint64_t('E') << 8) | (uint64_t('S') << 16) | (uint64_t('T') << 24) | (uint64_t('S') << 32)) +#define TESTS_SYMBOL_SER (uint64_t(3) | (TESTS_SYMBOL_U64 << 8)) + +struct asset { + static uint64_t hbd_symbol_ser; + static uint64_t ethereum_symbol_ser; + share_type amount; + uint64_t symbol; +}; + +}}} // namespace graphene::peerplays_sidechain::ethereum + +namespace fc { +void to_variant(const graphene::peerplays_sidechain::ethereum::asset &var, fc::variant &vo, uint32_t max_depth); +void from_variant(const fc::variant &var, graphene::peerplays_sidechain::ethereum::asset &vo, uint32_t max_depth); +} // namespace fc + +FC_REFLECT(graphene::peerplays_sidechain::ethereum::asset, (amount)(symbol)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/authority.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/authority.hpp new file mode 100644 index 00000000..d4d5455f --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/authority.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include + +#include + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +struct authority { + authority() { + } + + enum classification { + owner = 0, + active = 1, + key = 2, + posting = 3 + }; + + uint32_t weight_threshold = 0; + fc::flat_map account_auths; + fc::flat_map key_auths; +}; + +}}} // namespace graphene::peerplays_sidechain::ethereum + +FC_REFLECT_ENUM(graphene::peerplays_sidechain::ethereum::authority::classification, + (owner)(active)(key)(posting)) + +FC_REFLECT(graphene::peerplays_sidechain::ethereum::authority, + (weight_threshold)(account_auths)(key_auths)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/ethereum_operations.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/ethereum_operations.hpp new file mode 100644 index 00000000..4b8a7399 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/ethereum_operations.hpp @@ -0,0 +1,123 @@ +#pragma once + +#include +#include + +#include + +#include +#include +#include +#include + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +struct vote_operation {}; +struct comment_operation {}; + +struct transfer_operation { + ethereum::account_name_type from; + ethereum::account_name_type to; + ethereum::asset amount; + std::string memo; +}; + +struct transfer_to_vesting_operation {}; +struct withdraw_vesting_operation {}; +struct limit_order_create_operation {}; +struct limit_order_cancel_operation {}; +struct feed_publish_operation {}; +struct convert_operation {}; +struct account_create_operation {}; + +struct account_update_operation { + ethereum::account_name_type account; + fc::optional owner; + fc::optional active; + fc::optional posting; + ethereum::public_key_type memo_key; + std::string json_metadata; +}; + +struct witness_update_operation {}; +struct account_witness_vote_operation {}; +struct account_witness_proxy_operation {}; +struct pow_operation {}; +struct custom_operation {}; +struct report_over_production_operation {}; +struct delete_comment_operation {}; +struct custom_json_operation {}; +struct comment_options_operation {}; +struct set_withdraw_vesting_route_operation {}; +struct limit_order_create2_operation {}; +struct claim_account_operation {}; +struct create_claimed_account_operation {}; +struct request_account_recovery_operation {}; +struct recover_account_operation {}; +struct change_recovery_account_operation {}; +struct escrow_transfer_operation {}; +struct escrow_dispute_operation {}; +struct escrow_release_operation {}; +struct pow2_operation {}; +struct escrow_approve_operation {}; +struct transfer_to_savings_operation {}; +struct transfer_from_savings_operation {}; +struct cancel_transfer_from_savings_operation {}; +struct custom_binary_operation {}; +struct decline_voting_rights_operation {}; +struct reset_account_operation {}; +struct set_reset_account_operation {}; +struct claim_reward_balance_operation {}; + +struct delegate_vesting_shares_operation { + ethereum::account_name_type delegator; + ethereum::account_name_type delegatee; + ethereum::asset vesting_shares; +}; + +}}} // namespace graphene::peerplays_sidechain::ethereum + +FC_REFLECT(graphene::peerplays_sidechain::ethereum::vote_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::comment_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::transfer_operation, + (from)(to)(amount)(memo)) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::transfer_to_vesting_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::withdraw_vesting_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::limit_order_create_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::limit_order_cancel_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::feed_publish_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::convert_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::account_create_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::account_update_operation, + (account)(owner)(active)(posting)(memo_key)(json_metadata)) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::witness_update_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::account_witness_vote_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::account_witness_proxy_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::pow_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::custom_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::report_over_production_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::delete_comment_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::custom_json_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::comment_options_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::set_withdraw_vesting_route_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::limit_order_create2_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::claim_account_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::create_claimed_account_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::request_account_recovery_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::recover_account_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::change_recovery_account_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::escrow_transfer_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::escrow_dispute_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::escrow_release_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::pow2_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::escrow_approve_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::transfer_to_savings_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::transfer_from_savings_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::cancel_transfer_from_savings_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::custom_binary_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::decline_voting_rights_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::reset_account_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::set_reset_account_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::claim_reward_balance_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::delegate_vesting_shares_operation, + (delegator)(delegatee)(vesting_shares)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp new file mode 100644 index 00000000..586d31dd --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +typedef fc::static_variant< + vote_operation, + comment_operation, + + transfer_operation, + transfer_to_vesting_operation, + withdraw_vesting_operation, + + limit_order_create_operation, + limit_order_cancel_operation, + + feed_publish_operation, + convert_operation, + + account_create_operation, + account_update_operation, + + witness_update_operation, + account_witness_vote_operation, + account_witness_proxy_operation, + + pow_operation, + + custom_operation, + + report_over_production_operation, + + delete_comment_operation, + custom_json_operation, + comment_options_operation, + set_withdraw_vesting_route_operation, + limit_order_create2_operation, + claim_account_operation, + create_claimed_account_operation, + request_account_recovery_operation, + recover_account_operation, + change_recovery_account_operation, + escrow_transfer_operation, + escrow_dispute_operation, + escrow_release_operation, + pow2_operation, + escrow_approve_operation, + transfer_to_savings_operation, + transfer_from_savings_operation, + cancel_transfer_from_savings_operation, + custom_binary_operation, + decline_voting_rights_operation, + reset_account_operation, + set_reset_account_operation, + claim_reward_balance_operation, + delegate_vesting_shares_operation> + ethereum_operation; + +}}} // namespace graphene::peerplays_sidechain::hive + +namespace fc { + +void to_variant(const graphene::peerplays_sidechain::ethereum::ethereum_operation &var, fc::variant &vo, uint32_t max_depth = 5); +void from_variant(const fc::variant &var, graphene::peerplays_sidechain::ethereum::ethereum_operation &vo, uint32_t max_depth = 5); + +} // namespace fc + +FC_REFLECT_TYPENAME(graphene::peerplays_sidechain::ethereum::ethereum_operation) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp index 116a6df3..61fc39c6 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp @@ -3,17 +3,23 @@ #include #include +#include +#include + #include #include - +#include namespace graphene { namespace peerplays_sidechain { namespace ethereum { +typedef fc::ecc::private_key private_key_type; +typedef fc::sha256 chain_id_type; class transaction { +public: uint16_t ref_block_num = 0; uint32_t ref_block_prefix = 0; fc::time_point_sec expiration; - std::vector operations; + std::vector operations; extensions_type extensions; digest_type digest() const; @@ -23,6 +29,7 @@ class transaction { void set_expiration(fc::time_point_sec expiration_time); void set_reference_block(const block_id_type &reference_block); +/* /// Serialises this transaction to an RLPStream. /// @throws TransactionIsUnsigned if including signature was requested but it was not initialized void streamRLP(RLPStream& _s, IncludeSignature _sig = WithSignature, bool _forEip155hash = false) const; @@ -57,6 +64,7 @@ protected: mutable h256 m_hashWith; ///< Cached hash of transaction with signature. mutable boost::optional
m_sender; ///< Cached sender, determined from signature. +*/ }; class signed_transaction : public transaction { diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp new file mode 100644 index 00000000..f8a06c6c --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +#define KEY_PREFIX_STM "STM" +#define KEY_PREFIX_TST "TST" + +enum network { + mainnet, + testnet +}; + +struct void_t {}; + +typedef fc::static_variant future_extensions; +typedef fc::flat_set extensions_type; + +typedef fc::ecc::private_key private_key_type; +typedef fc::sha256 chain_id_type; +typedef std::string account_name_type; +typedef fc::ripemd160 block_id_type; +//typedef fc::ripemd160 checksum_type; +typedef fc::ripemd160 transaction_id_type; +typedef fc::sha256 digest_type; +typedef fc::ecc::compact_signature signature_type; +typedef fc::safe share_type; +//typedef safe ushare_type; +//typedef uint16_t weight_type; +//typedef uint32_t contribution_id_type; +//typedef fixed_string<32> custom_id_type; + +struct public_key_type { + + static std::string prefix; + + struct binary_key { + binary_key() { + } + uint32_t check = 0; + fc::ecc::public_key_data data; + }; + fc::ecc::public_key_data key_data; + public_key_type(); + public_key_type(const fc::ecc::public_key_data &data); + public_key_type(const fc::ecc::public_key &pubkey); + explicit public_key_type(const std::string &base58str); + operator fc::ecc::public_key_data() const; + operator fc::ecc::public_key() const; + explicit operator std::string() const; + friend bool operator==(const public_key_type &p1, const fc::ecc::public_key &p2); + friend bool operator==(const public_key_type &p1, const public_key_type &p2); + friend bool operator<(const public_key_type &p1, const public_key_type &p2) { + return p1.key_data < p2.key_data; + } + friend bool operator!=(const public_key_type &p1, const public_key_type &p2); +}; + +}}} // namespace graphene::peerplays_sidechain::ethereum + +namespace fc { +void to_variant(const graphene::peerplays_sidechain::ethereum::public_key_type &var, fc::variant &vo, uint32_t max_depth = 2); +void from_variant(const fc::variant &var, graphene::peerplays_sidechain::ethereum::public_key_type &vo, uint32_t max_depth = 2); +} // namespace fc + +FC_REFLECT(graphene::peerplays_sidechain::ethereum::public_key_type, (key_data)) +FC_REFLECT(graphene::peerplays_sidechain::ethereum::public_key_type::binary_key, (data)(check)) + +FC_REFLECT(graphene::peerplays_sidechain::ethereum::void_t, ) +FC_REFLECT_TYPENAME(graphene::peerplays_sidechain::ethereum::future_extensions) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index d322da3a..a690bc40 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -119,6 +119,7 @@ public: std::string walletprocesspsbt(std::string const &tx_psbt); bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); + std::string chain_id;//256 bit value private: class ethereum_function_call_encoder { public: @@ -140,7 +141,6 @@ private: std::vector owners; uint32_t threshold; std::unordered_map m_requests; - std::string chain_id;//256 bit value std::string balance; std::string code; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index 2b939085..0abd9ba7 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include extern "C" { @@ -291,6 +292,8 @@ uint64_t eth_rpc_client::add_owner(const std::string& addr ) { uint64_t id = eth_sign(account_address, message); m_requests[t_id] = req_t::ADD_OWNER; + + return 0; } uint64_t eth_rpc_client::remove_owner(const std::string& addr, uint32_t threshold) { @@ -318,6 +321,8 @@ uint64_t eth_rpc_client::remove_owner(const std::string& addr, uint32_t threshol std::string refundReceiver = "0000000000000000000000000000000000000000"; m_requests[t_id] = req_t::REMOVE_OWNER; + + return 0; } std::string eth_rpc_client::addmultisigaddress(const uint32_t nrequired, const std::vector public_keys) { @@ -1032,13 +1037,12 @@ std::string sidechain_net_handler_eth::create_transaction() { } std::string sidechain_net_handler_eth::sign_transaction(const sidechain_transaction_object &sto) { -/* std::stringstream ss_trx(boost::algorithm::unhex(sto.transaction)); - hive::signed_transaction htrx; + ethereum::signed_transaction htrx; fc::raw::unpack(ss_trx, htrx, 1000); - std::string chain_id_str = node_rpc_client->get_chain_id(); - const hive::chain_id_type chain_id(chain_id_str); + std::string chain_id_str = eth_client->chain_id;//eth_rpc_client->get_chain_id(); + const ethereum::chain_id_type chain_id(chain_id_str); fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))); signature_type st = htrx.sign(*privkey, chain_id); @@ -1046,8 +1050,7 @@ std::string sidechain_net_handler_eth::sign_transaction(const sidechain_transact std::stringstream ss_st; fc::raw::pack(ss_st, st, 1000); std::string st_str = boost::algorithm::hex(ss_st.str()); -*/ - return "";//st_str; + return st_str; } -- 2.45.2 From 61fe72fb15ef98b62deb976c030c4a2b82747707 Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Thu, 9 Jun 2022 05:21:00 -0300 Subject: [PATCH 12/60] remove RLP --- .../peerplays_sidechain/ethereum/RLP.h | 472 ------------------ 1 file changed, 472 deletions(-) delete mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/RLP.h diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/RLP.h b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/RLP.h deleted file mode 100644 index 99a77023..00000000 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/RLP.h +++ /dev/null @@ -1,472 +0,0 @@ -// Aleth: Ethereum C++ client, tools and libraries. -// Copyright 2013-2019 Aleth Authors. -// Licensed under the GNU General Public License, Version 3. - -/// @file -/// Recursive Linear-Prefix serialization / deserialization. -#pragma once - -#include "Exceptions.h" -#include "FixedHash.h" -#include "vector_ref.h" - -#include -#include -#include -#include -#include - -namespace dev -{ - -class RLP; - -template struct intTraits { static const unsigned maxSize = sizeof(_T); }; -template <> struct intTraits { static const unsigned maxSize = 20; }; -template <> struct intTraits { static const unsigned maxSize = 32; }; -template <> struct intTraits { static const unsigned maxSize = ~(unsigned)0; }; - -static const byte c_rlpMaxLengthBytes = 8; -static const byte c_rlpDataImmLenStart = 0x80; -static const byte c_rlpListStart = 0xc0; - -static const byte c_rlpDataImmLenCount = c_rlpListStart - c_rlpDataImmLenStart - c_rlpMaxLengthBytes; -static const byte c_rlpDataIndLenZero = c_rlpDataImmLenStart + c_rlpDataImmLenCount - 1; -static const byte c_rlpListImmLenCount = 256 - c_rlpListStart - c_rlpMaxLengthBytes; -static const byte c_rlpListIndLenZero = c_rlpListStart + c_rlpListImmLenCount - 1; - -template struct Converter { static T convert(RLP const&, int) { BOOST_THROW_EXCEPTION(BadCast()); } }; - -/** - * Class for interpreting Recursive Linear-Prefix Data. - */ -class RLP -{ -public: - /// Conversion flags - enum - { - AllowNonCanon = 1, - ThrowOnFail = 4, - FailIfTooBig = 8, - FailIfTooSmall = 16, - Strict = ThrowOnFail | FailIfTooBig, - VeryStrict = ThrowOnFail | FailIfTooBig | FailIfTooSmall, - LaissezFaire = AllowNonCanon - }; - - using Strictness = int; - - /// Construct a null node. - RLP() {} - - /// Construct a node of value given in the bytes. - explicit RLP(bytesConstRef _d, Strictness _s = VeryStrict); - - /// Construct a node of value given in the bytes. - explicit RLP(bytes const& _d, Strictness _s = VeryStrict): RLP(&_d, _s) {} - - /// Construct a node to read RLP data in the bytes given. - RLP(byte const* _b, unsigned _s, Strictness _st = VeryStrict): RLP(bytesConstRef(_b, _s), _st) {} - - /// Construct a node to read RLP data in the string. - explicit RLP(std::string const& _s, Strictness _st = VeryStrict): RLP(bytesConstRef((byte const*)_s.data(), _s.size()), _st) {} - - /// The bare data of the RLP. - bytesConstRef data() const { return m_data; } - - /// @returns true if the RLP is non-null. - explicit operator bool() const { return !isNull(); } - - /// No value. - bool isNull() const { return m_data.size() == 0; } - - /// Contains a zero-length string or zero-length list. - bool isEmpty() const { return !isNull() && (m_data[0] == c_rlpDataImmLenStart || m_data[0] == c_rlpListStart); } - - /// String value. - bool isData() const { return !isNull() && m_data[0] < c_rlpListStart; } - - /// List value. - bool isList() const { return !isNull() && m_data[0] >= c_rlpListStart; } - - /// Integer value. Must not have a leading zero. - bool isInt() const; - - /// @returns the number of items in the list, or zero if it isn't a list. - size_t itemCount() const { return isList() ? items() : 0; } - size_t itemCountStrict() const { if (!isList()) BOOST_THROW_EXCEPTION(BadCast()); return items(); } - - /// @returns the number of bytes in the data, or zero if it isn't data. - size_t size() const { return isData() ? length() : 0; } - size_t sizeStrict() const { if (!isData()) BOOST_THROW_EXCEPTION(BadCast()); return length(); } - - /// Equality operators; does best-effort conversion and checks for equality. - bool operator==(char const* _s) const { return isData() && toString() == _s; } - bool operator!=(char const* _s) const { return isData() && toString() != _s; } - bool operator==(std::string const& _s) const { return isData() && toString() == _s; } - bool operator!=(std::string const& _s) const { return isData() && toString() != _s; } - template bool operator==(FixedHash<_N> const& _h) const { return isData() && toHash<_N>() == _h; } - template bool operator!=(FixedHash<_N> const& _s) const { return isData() && toHash<_N>() != _s; } - bool operator==(unsigned const& _i) const { return isInt() && toInt() == _i; } - bool operator!=(unsigned const& _i) const { return isInt() && toInt() != _i; } - bool operator==(u256 const& _i) const { return isInt() && toInt() == _i; } - bool operator!=(u256 const& _i) const { return isInt() && toInt() != _i; } - bool operator==(bigint const& _i) const { return isInt() && toInt() == _i; } - bool operator!=(bigint const& _i) const { return isInt() && toInt() != _i; } - - /// Subscript operator. - /// @returns the list item @a _i if isList() and @a _i < listItems(), or RLP() otherwise. - /// @note if used to access items in ascending order, this is efficient. - RLP operator[](size_t _i) const; - - using element_type = RLP; - - /// @brief Iterator class for iterating through items of RLP list. - class iterator - { - friend class RLP; - - public: - using value_type = RLP; - using element_type = RLP; - - iterator& operator++(); - iterator operator++(int) { auto ret = *this; operator++(); return ret; } - RLP operator*() const { return RLP(m_currentItem); } - bool operator==(iterator const& _cmp) const { return m_currentItem == _cmp.m_currentItem; } - bool operator!=(iterator const& _cmp) const { return !operator==(_cmp); } - - private: - iterator() {} - iterator(RLP const& _parent, bool _begin); - - size_t m_remaining = 0; - bytesConstRef m_currentItem; - }; - - /// @brief Iterator into beginning of sub-item list (valid only if we are a list). - iterator begin() const { return iterator(*this, true); } - - /// @brief Iterator into end of sub-item list (valid only if we are a list). - iterator end() const { return iterator(*this, false); } - - template inline T convert(int _flags) const; - - /// Best-effort conversion operators. - explicit operator std::string() const { return toString(); } - explicit operator bytes() const { return toBytes(); } - explicit operator uint8_t() const { return toInt(); } - explicit operator uint16_t() const { return toInt(); } - explicit operator uint32_t() const { return toInt(); } - explicit operator uint64_t() const { return toInt(); } - explicit operator u160() const { return toInt(); } - explicit operator u256() const { return toInt(); } - explicit operator bigint() const { return toInt(); } - template explicit operator FixedHash() const { return toHash>(); } - template explicit operator std::pair() const { return toPair(); } - template explicit operator std::vector() const { return toVector(); } - template explicit operator std::set() const { return toSet(); } - template explicit operator std::array() const { return toArray(); } - - /// Converts to bytearray. @returns the empty byte array if not a string. - bytes toBytes(int _flags = LaissezFaire) const { if (!isData()) { if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else return bytes(); } return bytes(payload().data(), payload().data() + length()); } - /// Converts to bytearray. @returns the empty byte array if not a string. - bytesConstRef toBytesConstRef(int _flags = LaissezFaire) const { if (!isData()) { if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else return bytesConstRef(); } return payload().cropped(0, length()); } - /// Converts to string. @returns the empty string if not a string. - std::string toString(int _flags = LaissezFaire) const { if (!isData()) { if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else return std::string(); } return payload().cropped(0, length()).toString(); } - /// Converts to string. @throws BadCast if not a string. - std::string toStringStrict() const { return toString(Strict); } - - template - std::vector toVector(int _flags = LaissezFaire) const - { - std::vector ret; - if (isList()) - { - ret.reserve(itemCount()); - for (auto const& i: *this) - ret.push_back(i.convert(_flags)); - } - else if (_flags & ThrowOnFail) - BOOST_THROW_EXCEPTION(BadCast()); - return ret; - } - - template - std::set toSet(int _flags = LaissezFaire) const - { - std::set ret; - if (isList()) - for (auto const& i: *this) - ret.insert(i.convert(_flags)); - else if (_flags & ThrowOnFail) - BOOST_THROW_EXCEPTION(BadCast()); - return ret; - } - - template - std::unordered_set toUnorderedSet(int _flags = LaissezFaire) const - { - std::unordered_set ret; - if (isList()) - for (auto const& i: *this) - ret.insert(i.convert(_flags)); - else if (_flags & ThrowOnFail) - BOOST_THROW_EXCEPTION(BadCast()); - return ret; - } - - template - std::pair toPair(int _flags = Strict) const - { - std::pair ret; - if (itemCountStrict() != 2) - { - if (_flags & ThrowOnFail) - BOOST_THROW_EXCEPTION(BadCast()); - else - return ret; - } - ret.first = (*this)[0].convert(_flags); - ret.second = (*this)[1].convert(_flags); - return ret; - } - - template - std::array toArray(int _flags = LaissezFaire) const - { - if (itemCount() != N) - { - if (_flags & ThrowOnFail) - BOOST_THROW_EXCEPTION(BadCast()); - else - return std::array(); - } - std::array ret; - for (size_t i = 0; i < N; ++i) - ret[i] = operator[](i).convert(_flags); - return ret; - } - - /// Converts to int of type given; if isData(), decodes as big-endian bytestream. @returns 0 if not an int or data. - template _T toInt(int _flags = Strict) const - { - requireGood(); - if ((!isInt() && !(_flags & AllowNonCanon)) || isList() || isNull()) - { - if (_flags & ThrowOnFail) - BOOST_THROW_EXCEPTION(BadCast()); - else - return 0; - } - - auto p = payload(); - if (p.size() > intTraits<_T>::maxSize && (_flags & FailIfTooBig)) - { - if (_flags & ThrowOnFail) - BOOST_THROW_EXCEPTION(BadCast()); - else - return 0; - } - - return fromBigEndian<_T>(p); - } - - int64_t toPositiveInt64(int _flags = Strict) const - { - int64_t i = toInt(_flags); - if ((_flags & ThrowOnFail) && i < 0) - BOOST_THROW_EXCEPTION(BadCast()); - return i; - } - - template _N toHash(int _flags = Strict) const - { - requireGood(); - auto p = payload(); - auto l = p.size(); - if (!isData() || (l > _N::size && (_flags & FailIfTooBig)) || (l < _N::size && (_flags & FailIfTooSmall))) - { - if (_flags & ThrowOnFail) - BOOST_THROW_EXCEPTION(BadCast()); - else - return _N(); - } - - _N ret; - size_t s = std::min(_N::size, l); - memcpy(ret.data() + _N::size - s, p.data(), s); - return ret; - } - - /// @returns the data payload. Valid for all types. - bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) BOOST_THROW_EXCEPTION(BadRLP()); return m_data.cropped(payloadOffset(), l); } - - /// @returns the theoretical size of this item as encoded in the data. - /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work. - size_t actualSize() const; - -private: - /// Disable construction from rvalue - explicit RLP(bytes const&&) {} - - /// Throws if is non-canonical data (i.e. single byte done in two bytes that could be done in one). - void requireGood() const; - - /// Single-byte data payload. - bool isSingleByte() const { return !isNull() && m_data[0] < c_rlpDataImmLenStart; } - - /// @returns the amount of bytes used to encode the length of the data. Valid for all types. - unsigned lengthSize() const { if (isData() && m_data[0] > c_rlpDataIndLenZero) return m_data[0] - c_rlpDataIndLenZero; if (isList() && m_data[0] > c_rlpListIndLenZero) return m_data[0] - c_rlpListIndLenZero; return 0; } - - /// @returns the size in bytes of the payload, as given by the RLP as opposed to as inferred from m_data. - size_t length() const; - - /// @returns the number of bytes into the data that the payload starts. - size_t payloadOffset() const { return isSingleByte() ? 0 : (1 + lengthSize()); } - - /// @returns the number of data items. - size_t items() const; - - /// @returns the size encoded into the RLP in @a _data and throws if _data is too short. - static size_t sizeAsEncoded(bytesConstRef _data) { return RLP(_data, ThrowOnFail | FailIfTooSmall).actualSize(); } - - /// Our byte data. - bytesConstRef m_data; - - /// The list-indexing cache. - // Index of the last item accessed with operator[] - mutable size_t m_lastIndex = (size_t)-1; - // Offset of the next byte after last byte of m_lastItem - mutable size_t m_lastEnd = 0; - // Data of the last item accessed with operator[] - mutable bytesConstRef m_lastItem; -}; - -template <> struct Converter { static std::string convert(RLP const& _r, int _flags) { return _r.toString(_flags); } }; -template <> struct Converter { static bytes convert(RLP const& _r, int _flags) { return _r.toBytes(_flags); } }; -template <> struct Converter { static uint8_t convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; -template <> struct Converter { static uint16_t convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; -template <> struct Converter { static uint32_t convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; -template <> struct Converter { static uint64_t convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; -template <> struct Converter { static u160 convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; -template <> struct Converter { static u256 convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; -template <> struct Converter { static bigint convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; -template struct Converter> { static FixedHash convert(RLP const& _r, int _flags) { return _r.toHash>(_flags); } }; -template struct Converter> { static std::pair convert(RLP const& _r, int _flags) { return _r.toPair(_flags); } }; -template struct Converter> { static std::vector convert(RLP const& _r, int _flags) { return _r.toVector(_flags); } }; -template struct Converter> { static std::set convert(RLP const& _r, int _flags) { return _r.toSet(_flags); } }; -template struct Converter> { static std::unordered_set convert(RLP const& _r, int _flags) { return _r.toUnorderedSet(_flags); } }; -template struct Converter> { static std::array convert(RLP const& _r, int _flags) { return _r.toArray(_flags); } }; - -template inline T RLP::convert(int _flags) const { return Converter::convert(*this, _flags); } - -/** - * @brief Class for writing to an RLP bytestream. - */ -class RLPStream -{ -public: - /// Initializes empty RLPStream. - RLPStream() {} - - /// Initializes the RLPStream as a list of @a _listItems items. - explicit RLPStream(size_t _listItems) { appendList(_listItems); } - - ~RLPStream() {} - - /// Append given datum to the byte stream. - RLPStream& append(unsigned _s) { return append(bigint(_s)); } - RLPStream& append(u160 _s) { return append(bigint(_s)); } - RLPStream& append(u256 _s) { return append(bigint(_s)); } - RLPStream& append(bigint _s); - RLPStream& append(bytesConstRef _s, bool _compact = false); - RLPStream& append(bytes const& _s) { return append(bytesConstRef(&_s)); } - RLPStream& append(std::string const& _s) { return append(bytesConstRef(_s)); } - RLPStream& append(char const* _s) { return append(std::string(_s)); } - template RLPStream& append(FixedHash _s, bool _compact = false, bool _allOrNothing = false) { return _allOrNothing && !_s ? append(bytesConstRef()) : append(_s.ref(), _compact); } - - /// Appends an arbitrary RLP fragment - this *must* be a single item unless @a _itemCount is given. - RLPStream& append(RLP const& _rlp, size_t _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); } - - /// Appends a sequence of data to the stream as a list. - template RLPStream& append(std::vector<_T> const& _s) { return appendVector(_s); } - template RLPStream& appendVector(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } - template RLPStream& append(std::array<_T, S> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } - template RLPStream& append(std::set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } - template RLPStream& append(std::unordered_set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } - template RLPStream& append(std::pair const& _s) { appendList(2); append(_s.first); append(_s.second); return *this; } - - /// Appends a list. - RLPStream& appendList(size_t _items); - RLPStream& appendList(bytesConstRef _rlp); - RLPStream& appendList(bytes const& _rlp) { return appendList(&_rlp); } - RLPStream& appendList(RLPStream const& _s) { return appendList(&_s.out()); } - - /// Appends raw (pre-serialised) RLP data. Use with caution. - RLPStream& appendRaw(bytesConstRef _rlp, size_t _itemCount = 1); - RLPStream& appendRaw(bytes const& _rlp, size_t _itemCount = 1) { return appendRaw(&_rlp, _itemCount); } - - /// Shift operators for appending data items. - template RLPStream& operator<<(T _data) { return append(_data); } - - /// Clear the output stream so far. - void clear() { m_out.clear(); m_listStack.clear(); } - - /// Read the byte stream. - bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; } - - /// Invalidate the object and steal the output byte stream. - bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); } - - /// Swap the contents of the output stream out for some other byte array. - void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); } - -private: - void noteAppended(size_t _itemCount = 1); - - /// Push the node-type byte (using @a _base) along with the item count @a _count. - /// @arg _count is number of characters for strings, data-bytes for ints, or items for lists. - void pushCount(size_t _count, byte _offset); - - /// Push an integer as a raw big-endian byte-stream. - template void pushInt(_T _i, size_t _br) - { - m_out.resize(m_out.size() + _br); - byte* b = &m_out.back(); - for (; _i; _i >>= 8) - *(b--) = (byte)(_i & 0xff); - } - - /// Our output byte stream. - bytes m_out; - - std::vector> m_listStack; -}; - -template void rlpListAux(RLPStream& _out, _T _t) { _out << _t; } -template void rlpListAux(RLPStream& _out, _T _t, _Ts ... _ts) { rlpListAux(_out << _t, _ts...); } - -/// Export a single item in RLP format, returning a byte array. -template bytes rlp(_T _t) { return (RLPStream() << _t).out(); } - -/// Export a list of items in RLP format, returning a byte array. -inline bytes rlpList() { return RLPStream(0).out(); } -template bytes rlpList(_Ts ... _ts) -{ - RLPStream out(sizeof ...(_Ts)); - rlpListAux(out, _ts...); - return out.out(); -} - -/// The empty string in RLP format. -extern bytes RLPNull; - -/// The empty list in RLP format. -extern bytes RLPEmptyList; - -/// Human readable version of RLP. -std::ostream& operator<<(std::ostream& _out, dev::RLP const& _d); - -} -- 2.45.2 From 1a684df3f265783f8c60f8dd42403f2310f3687d Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Fri, 10 Jun 2022 09:07:16 -0300 Subject: [PATCH 13/60] create_primary_wallet_address, create_public_key_data --- .../sidechain_net_handler_eth.hpp | 10 +-- .../sidechain_net_handler_eth.cpp | 86 +++++++++---------- 2 files changed, 47 insertions(+), 49 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index a690bc40..2c89aa50 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -120,6 +119,8 @@ public: bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); std::string chain_id;//256 bit value + std::vector owners; + std::string safe_account_addr; private: class ethereum_function_call_encoder { public: @@ -137,8 +138,6 @@ private: uint64_t t_id; std::string account_address; std::string transaction_id; - std::string safe_account_addr; - std::vector owners; uint32_t threshold; std::unordered_map m_requests; std::string balance; @@ -186,7 +185,6 @@ private: std::unique_ptr eth_client; fc::future on_changed_objects_task; - bitcoin::bitcoin_address::network network_type; std::mutex event_handler_mutex; typedef std::lock_guard scoped_lock; @@ -202,10 +200,12 @@ private: std::string send_transaction(const sidechain_transaction_object &sto); void handle_event(const std::string &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); + + std::vector parse_hex(const std::string &str); + fc::ecc::public_key_data create_public_key_data(const std::vector &public_key); }; }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index 0abd9ba7..caa88650 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -20,6 +20,8 @@ #include #include +#include + #include extern "C" { #include @@ -774,8 +776,8 @@ void sidechain_net_handler_eth::process_primary_wallet() { const auto &active_sw = swi.rbegin(); if (active_sw != swi.rend()) { - if ((active_sw->addresses.find(sidechain_type::bitcoin) == active_sw->addresses.end()) || - (active_sw->addresses.at(sidechain_type::bitcoin).empty())) { + if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) || + (active_sw->addresses.at(sidechain_type::ethereum).empty())) { if (proposal_exists(chain::operation::tag::value, active_sw->id)) { return; @@ -787,6 +789,9 @@ void sidechain_net_handler_eth::process_primary_wallet() { string reply_str = create_primary_wallet_address(active_sons); std::stringstream active_pw_ss(reply_str); + + ilog("### process_primary_wallet: ${reply}", ("reply", reply_str)); + boost::property_tree::ptree active_pw_pt; boost::property_tree::read_json(active_pw_ss, active_pw_pt); if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { @@ -805,7 +810,7 @@ void sidechain_net_handler_eth::process_primary_wallet() { son_wallet_update_operation swu_op; swu_op.payer = gpo.parameters.son_account(); swu_op.son_wallet_id = active_sw->id; - swu_op.sidechain = sidechain_type::bitcoin; + swu_op.sidechain = sidechain_type::ethereum; swu_op.address = res.str(); proposal_op.proposed_ops.emplace_back(swu_op); @@ -842,12 +847,11 @@ void sidechain_net_handler_eth::process_primary_wallet() { } void sidechain_net_handler_eth::process_sidechain_addresses() { - using namespace bitcoin; - +/* const chain::global_property_object &gpo = database.get_global_properties(); std::vector> pubkeys; for (auto &son : gpo.active_sons) { - std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin); + std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); auto pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); pubkeys.push_back(std::make_pair(pubkey, son.weight)); } @@ -896,6 +900,7 @@ void sidechain_net_handler_eth::process_sidechain_addresses() { } return retval; }); +*/ } bool sidechain_net_handler_eth::process_deposit(const son_wallet_deposit_object &swdo) { @@ -998,22 +1003,31 @@ bool sidechain_net_handler_eth::settle_sidechain_transaction(const sidechain_tra return false; } +std::vector sidechain_net_handler_eth::parse_hex(const std::string &str) { + std::vector vec(str.size() / 2); + fc::from_hex(str, vec.data(), vec.size()); + return vec; +} + std::string sidechain_net_handler_eth::create_primary_wallet_address(const std::vector &son_pubkeys) { - using namespace bitcoin; - - std::vector> pubkey_weights; - for (auto &son : son_pubkeys) { - std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin); - auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); - pubkey_weights.push_back(std::make_pair(pub_key, son.weight)); - } - - btc_weighted_multisig_address addr(pubkey_weights, network_type); - std::stringstream ss; - ss << "{\"result\": {\"address\": \"" << addr.get_address() << "\", \"redeemScript\": \"" << fc::to_hex(addr.get_redeem_script()) << "\"" - << "}, \"error\":null}"; + ss << "{\"result\": {\"address\": \"" << eth_client->safe_account_addr << "\"" << "}, "; + ss << "\"onwers\": ["; + for (auto &owner : eth_client->owners){ + ss << "\"" << owner << "\","; + } + ss.seekp(-1, std::ios_base::end); + ss << "], keys: ["; + + for (auto &son : son_pubkeys) { + std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); + ss << "\"" << pub_key_str << "\","; + } + ss.seekp(-1, std::ios_base::end); + ss << "], "; + + ss << "\"error\":null}"; std::string res = ss.str(); return res; @@ -1063,31 +1077,6 @@ std::string sidechain_net_handler_eth::send_transaction(const sidechain_transact void sidechain_net_handler_eth::handle_event(const std::string &event_data) { } -std::string sidechain_net_handler_eth::get_redeemscript_for_userdeposit(const std::string &user_address) { - using namespace bitcoin; - const auto &sidechain_addresses_idx = database.get_index_type().indices().get(); - const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, user_address, time_point_sec::maximum())); - if (addr_itr == sidechain_addresses_idx.end()) { - return ""; - } - - const auto &idx = database.get_index_type().indices().get(); - auto obj = idx.rbegin(); - if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) { - return ""; - } - - std::vector> pubkey_weights; - for (auto &son : obj->sons) { - std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin); - auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); - 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_eth::extract_info_from_block(const std::string &_block) { std::stringstream ss(_block); boost::property_tree::ptree block; @@ -1113,5 +1102,14 @@ void sidechain_net_handler_eth::on_changed_objects(const vector void sidechain_net_handler_eth::on_changed_objects_cb(const vector &ids, const flat_set &accounts) { } +fc::ecc::public_key_data sidechain_net_handler_eth::create_public_key_data(const std::vector &public_key) { + FC_ASSERT(public_key.size() == 33); + fc::ecc::public_key_data key; + for (size_t i = 0; i < 33; i++) { + key.at(i) = public_key[i]; + } + return key; +} + // ============================================================================= }} // namespace graphene::peerplays_sidechain -- 2.45.2 From 4a63c202be654228ce82d1d47008d0f1db0f70ee Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Mon, 13 Jun 2022 07:23:40 -0300 Subject: [PATCH 14/60] websocket connection in a separate thread --- .../sidechain_net_handler_eth.hpp | 5 +++- .../sidechain_net_handler_eth.cpp | 30 +++++++++++-------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index 2c89aa50..11df4cb8 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -17,6 +17,8 @@ #include #include +#include + namespace graphene { namespace peerplays_sidechain { typedef websocketpp::client client; @@ -67,7 +69,7 @@ public: eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); - void start(std::string uri); + void start(); void stop(); void on_socket_init(websocketpp::connection_hdl); void on_fail(websocketpp::connection_hdl hdl); @@ -133,6 +135,7 @@ private: ethereum_function_call_encoder m_ethereum_function_call_encoder; + std::shared_ptr _thread; std::string signature; std::string geth_url; uint64_t t_id; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index caa88650..f3fcabb5 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -67,7 +67,7 @@ std::string eth_rpc_client::ethereum_function_call_encoder::encode_bytes(const s } -eth_rpc_client::eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) { +eth_rpc_client::eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : _thread(std::make_shared("eth_rpc_client")){ geth_url = url; user = user_name; this->password = password; @@ -91,20 +91,24 @@ eth_rpc_client::eth_rpc_client(const std::string &url, const std::string &user_n m_endpoint.set_fail_handler(bind(&type::on_fail,this,::_1)); } -void eth_rpc_client::start(std::string uri) { - websocketpp::lib::error_code ec; - client::connection_ptr con = m_endpoint.get_connection(uri, ec); - m_hdl = con->get_handle(); +void eth_rpc_client::start() { + ilog("### eth_rpc_client::start uri: ${uri}", ("uri", geth_url)); + auto future = _thread->async([this] + { + websocketpp::lib::error_code ec; + client::connection_ptr con = m_endpoint.get_connection(this->geth_url, ec); + m_hdl = con->get_handle(); - if (ec) { - m_endpoint.get_alog().write(websocketpp::log::alevel::app,ec.message()); - return; - } + if (ec) { + m_endpoint.get_alog().write(websocketpp::log::alevel::app,ec.message()); + return; + } - m_endpoint.connect(con); + m_endpoint.connect(con); - // Start the ASIO io_service run loop - m_endpoint.run(); + // Start the ASIO io_service run loop + m_endpoint.run(); + }); } void eth_rpc_client::stop() { @@ -455,7 +459,7 @@ sidechain_net_handler_eth::sidechain_net_handler_eth(peerplays_sidechain_plugin url = options.at("ethereum-node-rpc-url").as(); eth_client = std::unique_ptr(new eth_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls)); - eth_client->start(url); + eth_client->start(); /* if (!wallet.empty()) { eth_client->loadwallet(wallet); -- 2.45.2 From 6cdf6c68a7bed94ffa115e43ac3bee8238866d78 Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Mon, 13 Jun 2022 09:12:53 -0300 Subject: [PATCH 15/60] add more traces --- .../sidechain_net_handler_eth.cpp | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index f3fcabb5..f940dc16 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -131,7 +131,9 @@ void eth_rpc_client::on_fail(websocketpp::connection_hdl hdl) { } void eth_rpc_client::on_open(websocketpp::connection_hdl hdl) { - m_endpoint.send(hdl, "{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":84}", websocketpp::frame::opcode::text); + std::string str = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":84}"; + ilog("on_open: ${str}", ("str", str)); + m_endpoint.send(hdl, str.c_str(), websocketpp::frame::opcode::text); vector owner_addresses; std::string private_key = ""; @@ -205,6 +207,7 @@ void eth_rpc_client::on_close(websocketpp::connection_hdl) { uint64_t eth_rpc_client::get_chain_id() { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":%1%}") % t_id); + ilog("get_chain_id: ${req}", ("req", req.c_str())); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); m_requests[t_id] = req_t::ETH_CHAIN_ID; return t_id++; @@ -212,6 +215,7 @@ uint64_t eth_rpc_client::get_chain_id() { uint64_t eth_rpc_client::eth_getTransactionReceipt(const std::string& tx_id) { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"%1%\"],\"id\":%2%}") % tx_id.c_str() % t_id); + ilog("eth_getTransactionReceipt: ${req}", ("req", req.c_str())); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); m_requests[t_id] = req_t::ETH_GET_TRANSACTION_RECEIPT; return t_id++; @@ -219,6 +223,7 @@ uint64_t eth_rpc_client::eth_getTransactionReceipt(const std::string& tx_id) { uint64_t eth_rpc_client::eth_call(const std::string& to, const std::string& data) { std::string req = str(boost::format("{\"jsonrpc\": \"2.0\", \"method\": \"eth_call\", \"params\": [{\"to\": \"%1%\", \"data\": \"%2%\"}, \"latest\"], \"id\": %3%}") % to.c_str() % data.c_str() % t_id); + ilog("eth_call: ${req}", ("req", req.c_str())); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); m_requests[t_id] = req_t::ETH_CALL; @@ -227,6 +232,7 @@ uint64_t eth_rpc_client::eth_call(const std::string& to, const std::string& data uint64_t eth_rpc_client::eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data) { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sendTransaction\", \"params\": [{\"from\": \"%1%\", \"to\": \"%2%\", \"data\": \"%3%\"}], \"id\": %4%}") % from.c_str() % to.c_str() % data.c_str() % t_id); + ilog("eth_sendTransaction: ${req}", ("req", req.c_str())); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); m_requests[t_id] = req_t::ETH_SEND_TRANSACTION; @@ -235,6 +241,7 @@ uint64_t eth_rpc_client::eth_sendTransaction(const std::string& from, const std: uint64_t eth_rpc_client::eth_sendRawTransaction(const std::string& params) { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"%1%\"],\"id\":%2%}") % params.c_str() % t_id); + ilog("eth_sendRawTransaction: ${req}", ("req", req.c_str())); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); m_requests[t_id] = req_t::ETH_SEND_RAW_TRANSACTION; @@ -243,6 +250,7 @@ uint64_t eth_rpc_client::eth_sendRawTransaction(const std::string& params) { uint64_t eth_rpc_client::eth_getCode(const std::string& addr) { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getCode\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); + ilog("eth_getCode: ${req}", ("req", req.c_str())); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); m_requests[t_id] = req_t::ETH_GET_CODE; return t_id++; @@ -250,6 +258,7 @@ uint64_t eth_rpc_client::eth_getCode(const std::string& addr) { uint64_t eth_rpc_client::eth_getBalance(const std::string& addr) { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getBalance\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); + ilog("eth_getBalance: ${req}", ("req", req.c_str())); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); m_requests[t_id] = req_t::ETH_GET_BALANCE; return t_id++; @@ -257,6 +266,7 @@ uint64_t eth_rpc_client::eth_getBalance(const std::string& addr) { uint64_t eth_rpc_client::eth_sign(const string& addr, const string& message) { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sign\", \"params\": [\"%1%\",\"%2%\"], \"id\": %2%}") % addr.c_str() % message.c_str() % t_id); + ilog("eth_sign: ${req}", ("req", req.c_str())); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); m_requests[t_id] = req_t::ETH_SIGN; @@ -265,6 +275,7 @@ uint64_t eth_rpc_client::eth_sign(const string& addr, const string& message) { uint64_t eth_rpc_client::eth_coinbase() { std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_coinbase\",\"params\":[],\"id\":%1%}") % t_id); + ilog("eth_coinbase: ${req}", ("req", req.c_str())); m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); m_requests[t_id] = req_t::ETH_COINBASE; return t_id++; @@ -340,6 +351,8 @@ std::string eth_rpc_client::combinepsbt(const vector &psbts) { } uint64_t eth_rpc_client::createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key) { + ilog("createmultisig: ${key}", ("key", private_key.c_str())); + //That's will create //0x5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12 //0x76ce31BD03f601c3fC13732deF921c5Bac282676 @@ -776,6 +789,8 @@ bool sidechain_net_handler_eth::process_proposal(const proposal_object &po) { } void sidechain_net_handler_eth::process_primary_wallet() { + ilog("### process_primary_wallet:"); + const auto &swi = database.get_index_type().indices().get(); const auto &active_sw = swi.rbegin(); if (active_sw != swi.rend()) { @@ -908,6 +923,7 @@ void sidechain_net_handler_eth::process_sidechain_addresses() { } bool sidechain_net_handler_eth::process_deposit(const son_wallet_deposit_object &swdo) { + ilog("### process_deposit:"); if (proposal_exists(chain::operation::tag::value, swdo.id)) { return false; @@ -952,6 +968,7 @@ bool sidechain_net_handler_eth::process_deposit(const son_wallet_deposit_object } bool sidechain_net_handler_eth::process_withdrawal(const son_wallet_withdraw_object &swwo) { + ilog("### process_withdrawal:"); if (proposal_exists(chain::operation::tag::value, swwo.id)) { return false; @@ -996,10 +1013,12 @@ bool sidechain_net_handler_eth::process_withdrawal(const son_wallet_withdraw_obj } std::string sidechain_net_handler_eth::process_sidechain_transaction(const sidechain_transaction_object &sto) { + ilog("### process_sidechain_transaction: "); return sign_transaction(sto); } std::string sidechain_net_handler_eth::send_sidechain_transaction(const sidechain_transaction_object &sto) { + ilog("### send_sidechain_transaction: "); return send_transaction(sto); } @@ -1055,6 +1074,8 @@ std::string sidechain_net_handler_eth::create_transaction() { } std::string sidechain_net_handler_eth::sign_transaction(const sidechain_transaction_object &sto) { + ilog("### sign_transaction: "); + std::stringstream ss_trx(boost::algorithm::unhex(sto.transaction)); ethereum::signed_transaction htrx; fc::raw::unpack(ss_trx, htrx, 1000); @@ -1092,6 +1113,8 @@ std::vector sidechain_net_handler_eth::extract_info_from_block(con } void sidechain_net_handler_eth::on_changed_objects(const vector &ids, const flat_set &accounts) { + ilog("### on_changed_objects: "); + fc::time_point now = fc::time_point::now(); int64_t time_to_next_changed_objects_processing = 5000; -- 2.45.2 From 647a5369fc7c950f7f9b78fb19f10cf53310b0db Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Tue, 14 Jun 2022 13:13:52 -0300 Subject: [PATCH 16/60] process_proposal stub true --- .../peerplays_sidechain/sidechain_net_handler_eth.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index f940dc16..3cc7ec43 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -502,7 +502,7 @@ sidechain_net_handler_eth::~sidechain_net_handler_eth() { bool sidechain_net_handler_eth::process_proposal(const proposal_object &po) { - //ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); + ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); /* bool should_approve = false; @@ -785,7 +785,8 @@ bool sidechain_net_handler_eth::process_proposal(const proposal_object &po) { return should_approve; */ - return false; + + return true; } void sidechain_net_handler_eth::process_primary_wallet() { -- 2.45.2 From 6e213fcfad8789ad6e364ed6c29e0185e95f5247 Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Wed, 15 Jun 2022 09:16:55 -0300 Subject: [PATCH 17/60] remove hardcodes, implementation build_transaction safe_transaction_encoder --- .../sidechain_net_handler_eth.hpp | 337 +-- .../sidechain_net_handler_eth.cpp | 1899 +++++++++-------- 2 files changed, 1139 insertions(+), 1097 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index 11df4cb8..705b40b0 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -21,194 +21,217 @@ namespace graphene { namespace peerplays_sidechain { -typedef websocketpp::client client; + typedef websocketpp::client client; -using websocketpp::lib::placeholders::_1; -using websocketpp::lib::placeholders::_2; -using websocketpp::lib::bind; + using websocketpp::lib::placeholders::_1; + using websocketpp::lib::placeholders::_2; + using websocketpp::lib::bind; -// pull out the type of messages sent by our config -typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr; -typedef websocketpp::lib::shared_ptr context_ptr; -typedef client::connection_ptr connection_ptr; + // pull out the type of messages sent by our config + typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr; + typedef websocketpp::lib::shared_ptr context_ptr; + typedef client::connection_ptr connection_ptr; -class eth_rpc_client { -public: - typedef eth_rpc_client type; + class eth_rpc_client { + public: + typedef eth_rpc_client type; - enum req_t { - ETH_CHAIN_ID, - ETH_GET_TRANSACTION_RECEIPT, - ETH_CALL, - ETH_SEND_TRANSACTION, - ETH_SEND_RAW_TRANSACTION, - ETH_GET_CODE, - ETH_GET_BALANCE, - ETH_SIGN, - ETH_COINBASE, - GET_LIST_OWNERS, - ADD_OWNER, - REMOVE_OWNER - }; + enum req_t { + ETH_CHAIN_ID, + ETH_GET_TRANSACTION_RECEIPT, + ETH_CALL, + ETH_SEND_TRANSACTION, + ETH_SEND_RAW_TRANSACTION, + ETH_GET_CODE, + ETH_GET_BALANCE, + ETH_SIGN, + ETH_COINBASE, + GET_LIST_OWNERS, + ADD_OWNER, + REMOVE_OWNER + }; - enum class multi_type { - script, - address - }; - struct multi_params { - multi_params(multi_type _type, const std::string &_address_or_script, const std::string &_label = "") : - type{_type}, - address_or_script{_address_or_script}, - label{_label} { - } + enum class multi_type { + script, + address + }; + struct multi_params { + multi_params(multi_type _type, const std::string &_address_or_script, const std::string &_label = "") : + type{_type}, + address_or_script{_address_or_script}, + label{_label} { + } - multi_type type; - std::string address_or_script; - std::string label; - }; + multi_type type; + std::string address_or_script; + std::string label; + }; - eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); + eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); - void start(); - void stop(); - void on_socket_init(websocketpp::connection_hdl); - void on_fail(websocketpp::connection_hdl hdl); - void on_open(websocketpp::connection_hdl hdl); - void on_message(websocketpp::connection_hdl hdl, message_ptr msg); - void on_close(websocketpp::connection_hdl); + void start(); + void stop(); + void on_socket_init(websocketpp::connection_hdl); + void on_fail(websocketpp::connection_hdl hdl); + void on_open(websocketpp::connection_hdl hdl); + void on_message(websocketpp::connection_hdl hdl, message_ptr msg); + void on_close(websocketpp::connection_hdl); - uint64_t get_chain_id(); - uint64_t eth_getTransactionReceipt(const std::string& tx_id); - uint64_t eth_call(const std::string& to, const std::string& data); - uint64_t eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data); - uint64_t eth_sendRawTransaction(const std::string& params); - uint64_t eth_getCode(const std::string& addr); - uint64_t eth_getBalance(const std::string& addr); - uint64_t eth_sign(const string& addr, const string& message); - uint64_t eth_coinbase(); + uint64_t get_chain_id(); + uint64_t eth_getTransactionReceipt(const std::string& tx_id); + uint64_t eth_call(const std::string& to, const std::string& data); + uint64_t eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data); + uint64_t eth_sendRawTransaction(const std::string& params); + uint64_t eth_getCode(const std::string& addr); + uint64_t eth_getBalance(const std::string& addr); + uint64_t eth_sign(const string& addr, const string& message); + uint64_t eth_coinbase(); - uint64_t get_list_owners(const std::string& safe_account); - uint64_t add_owner(const std::string& addr ); - uint64_t remove_owner(const std::string& addr, uint32_t threshold); + uint64_t get_list_owners(const std::string& safe_account); + uint64_t add_owner(const std::string& addr ); + uint64_t remove_owner(const std::string& addr, uint32_t threshold); - std::string addmultisigaddress(const uint32_t nrequired, const std::vector public_keys); - std::string combinepsbt(const vector &psbts); + std::string addmultisigaddress(const uint32_t nrequired, const std::vector public_keys); + std::string combinepsbt(const vector &psbts); - uint64_t createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key); + uint64_t createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key); - std::string createpsbt(); - std::string createrawtransaction(); - std::string createwallet(const std::string &wallet_name); - std::string decodepsbt(std::string const &tx_psbt); - std::string decoderawtransaction(std::string const &tx_hex); - std::string encryptwallet(const std::string &passphrase); - uint64_t estimatesmartfee(uint16_t conf_target = 128); - std::string finalizepsbt(std::string const &tx_psbt); - std::string getaddressinfo(const std::string &address); - 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(); - std::string gettransaction(const std::string &txid, const bool include_watch_only = false); - std::string getblockchaininfo(); - void importaddress(const std::string &address_or_script, const std::string &label = "", const bool rescan = true, const bool p2sh = false); - void importmulti(const std::vector &address_or_script_array, const bool rescan = true); - std::string loadwallet(const std::string &filename); - std::string sendrawtransaction(const std::string &tx_hex); - std::string signrawtransactionwithwallet(const std::string &tx_hash); - std::string unloadwallet(const std::string &filename); - std::string walletlock(); - std::string walletprocesspsbt(std::string const &tx_psbt); - bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); + std::string createpsbt(); + std::string createrawtransaction(); + std::string createwallet(const std::string &wallet_name); + std::string decodepsbt(std::string const &tx_psbt); + std::string decoderawtransaction(std::string const &tx_hex); + std::string encryptwallet(const std::string &passphrase); + uint64_t estimatesmartfee(uint16_t conf_target = 128); + std::string finalizepsbt(std::string const &tx_psbt); + std::string getaddressinfo(const std::string &address); + 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(); + std::string gettransaction(const std::string &txid, const bool include_watch_only = false); + std::string getblockchaininfo(); + void importaddress(const std::string &address_or_script, const std::string &label = "", const bool rescan = true, const bool p2sh = false); + void importmulti(const std::vector &address_or_script_array, const bool rescan = true); + std::string loadwallet(const std::string &filename); + std::string sendrawtransaction(const std::string &tx_hex); + std::string signrawtransactionwithwallet(const std::string &tx_hash); + std::string unloadwallet(const std::string &filename); + std::string walletlock(); + std::string walletprocesspsbt(std::string const &tx_psbt); + bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); - std::string chain_id;//256 bit value - std::vector owners; - std::string safe_account_addr; -private: - class ethereum_function_call_encoder { - public: - std::string encode_function_signature(const std::string& function_signature); - std::string encode_address(const std::string& addr); - std::string encode_uint256(const std::string& value); - std::string encode_uint8(uint8_t value); - std::string encode_bytes(const std::string& values); - }; + std::string chain_id;//256 bit value + std::vector owners; + std::string safe_account_addr; + private: + class ethereum_function_call_encoder { + public: + enum operation_t { + OPERATION_CALL, + OPERATION_DELEGATE_CALL + }; - ethereum_function_call_encoder m_ethereum_function_call_encoder; + static constexpr const char*const default_prev_addr = "0000000000000000000000000000000000000001"; - std::shared_ptr _thread; - std::string signature; - std::string geth_url; - uint64_t t_id; - std::string account_address; - std::string transaction_id; - uint32_t threshold; - std::unordered_map m_requests; - std::string balance; - std::string code; + std::string encode_function_signature(const std::string& function_signature); + std::string encode_address(const std::string& addr); + std::string encode_uint256(const std::string& value); + std::string encode_uint8(uint8_t value); + std::string encode_bytes(const std::string& values); + }; - std::string ip; - uint32_t rpc_port; - std::string user; - std::string password; - std::string wallet; - std::string wallet_password; - bool debug_rpc_calls; + class safe_transaction_encoder { + public: + static constexpr const char*const default_safe_tx_gas = "0"; + static constexpr const char*const default_data_gas = "0"; + static constexpr const char*const default_gas_price = "0"; + static constexpr const char*const default_gas_token = "0000000000000000000000000000000000000000"; + static constexpr const char*const default_refund_receiver = "0000000000000000000000000000000000000000"; - fc::http::header authorization; + std::string create_safe_address(const std::vector owner_addresses, uint32_t threshold); + std::string build_transaction(const std::string& safe_account_addr, const std::string& value, const std::string& data, uint8_t operation, const std::string& safeTxGas, const std::string& dataGas, const std::string& gasPrice, const std::string& gasToken, const std::string& refundReceiver); - client m_endpoint; - websocketpp::connection_hdl m_hdl; -}; + private: + ethereum_function_call_encoder m_ethereum_function_call_encoder; + }; -// ============================================================================= + ethereum_function_call_encoder m_ethereum_function_call_encoder; + safe_transaction_encoder m_safe_transaction_encoder; -class sidechain_net_handler_eth : public sidechain_net_handler { -public: - sidechain_net_handler_eth(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options); - virtual ~sidechain_net_handler_eth(); + std::shared_ptr _thread; + std::string signature; + std::string geth_url; + uint64_t t_id; + std::string account_address; + std::string transaction_id; + uint32_t threshold; + std::unordered_map m_requests; + std::string balance; + std::string code; - bool process_proposal(const proposal_object &po); - void process_primary_wallet(); - void process_sidechain_addresses(); - bool process_deposit(const son_wallet_deposit_object &swdo); - bool process_withdrawal(const son_wallet_withdraw_object &swwo); - std::string process_sidechain_transaction(const sidechain_transaction_object &sto); - std::string send_sidechain_transaction(const sidechain_transaction_object &sto); - bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); + std::string ip; + uint32_t rpc_port; + std::string user; + std::string password; + std::string wallet; + std::string wallet_password; + bool debug_rpc_calls; -private: - std::string url; - uint32_t rpc_port; + fc::http::header authorization; - std::string rpc_user; - std::string rpc_password; - std::string wallet; - std::string wallet_password; + client m_endpoint; + websocketpp::connection_hdl m_hdl; + }; - std::unique_ptr eth_client; + // ============================================================================= - fc::future on_changed_objects_task; + class sidechain_net_handler_eth : public sidechain_net_handler { + public: + sidechain_net_handler_eth(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options); + virtual ~sidechain_net_handler_eth(); - std::mutex event_handler_mutex; - typedef std::lock_guard scoped_lock; + bool process_proposal(const proposal_object &po); + void process_primary_wallet(); + void process_sidechain_addresses(); + bool process_deposit(const son_wallet_deposit_object &swdo); + bool process_withdrawal(const son_wallet_withdraw_object &swwo); + std::string process_sidechain_transaction(const sidechain_transaction_object &sto); + std::string send_sidechain_transaction(const sidechain_transaction_object &sto); + bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); - std::string create_primary_wallet_address(const std::vector &son_pubkeys); + private: + std::string url; + uint32_t rpc_port; - 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); - std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo); + std::string rpc_user; + std::string rpc_password; + std::string wallet; + std::string wallet_password; - std::string create_transaction(); - std::string sign_transaction(const sidechain_transaction_object &sto); - std::string send_transaction(const sidechain_transaction_object &sto); + std::unique_ptr eth_client; - void handle_event(const std::string &event_data); - 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); + fc::future on_changed_objects_task; - std::vector parse_hex(const std::string &str); - fc::ecc::public_key_data create_public_key_data(const std::vector &public_key); -}; + 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_transaction(const son_wallet_object &prev_swo, std::string new_sw_address); + std::string create_deposit_transaction(const son_wallet_deposit_object &swdo); + std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo); + + std::string create_transaction(); + 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); + 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); + + std::vector parse_hex(const std::string &str); + fc::ecc::public_key_data create_public_key_data(const std::vector &public_key); + }; }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index 3cc7ec43..1c333811 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -28,1115 +28,1134 @@ extern "C" { } namespace graphene { namespace peerplays_sidechain { -// ============================================================================= -std::string eth_rpc_client::ethereum_function_call_encoder::encode_function_signature(const std::string& function_signature) { - sha3_context c; - char *hash; - - sha3_Init256(static_cast(&c)); - sha3_SetFlags(&c, SHA3_FLAGS_KECCAK); - sha3_Update(&c, "abc", 3); - hash = (char*)sha3_Finalize(&c); - std::string output(hash); - output = output.substr(0,8); - - return output; -}; - -std::string eth_rpc_client::ethereum_function_call_encoder::encode_address(const std::string& addr) { - FC_ASSERT(20 == addr.length()); - std::string output = str(boost::format("%012u") % 0) + addr; - return output; -} - -std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint256(const std::string& value) { - FC_ASSERT(value.length() <= 64); - std::string output = std::string(64 - value.length(), '0') + value; - return output; -} - -std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint8(uint8_t value) { - std::string output = str(boost::format("%02X") % value) + std::string(62, '0'); - return output; -} - -std::string eth_rpc_client::ethereum_function_call_encoder::encode_bytes(const std::string& values) { - size_t len = values.length(); - std::string output = encode_uint256((boost::format("%x") % len).str()) + values + std::string(64 - len, '0'); - return output; -} - - -eth_rpc_client::eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : _thread(std::make_shared("eth_rpc_client")){ - geth_url = url; - user = user_name; - this->password = password; - this->debug_rpc_calls = debug_rpc_calls; - t_id = 1; - - ilog("eth_rpc_client"); - ilog("### Geth URL: ${url}", ("url", url)); - - m_endpoint.set_access_channels(websocketpp::log::alevel::none); - m_endpoint.set_error_channels(websocketpp::log::elevel::none); - - // Initialize ASIO - m_endpoint.init_asio(); - - // Register our handlers - m_endpoint.set_socket_init_handler(bind(&type::on_socket_init,this,::_1)); - m_endpoint.set_message_handler(bind(&type::on_message,this,::_1,::_2)); - m_endpoint.set_open_handler(bind(&type::on_open,this,::_1)); - m_endpoint.set_close_handler(bind(&type::on_close,this,::_1)); - m_endpoint.set_fail_handler(bind(&type::on_fail,this,::_1)); -} - -void eth_rpc_client::start() { - ilog("### eth_rpc_client::start uri: ${uri}", ("uri", geth_url)); - auto future = _thread->async([this] - { - websocketpp::lib::error_code ec; - client::connection_ptr con = m_endpoint.get_connection(this->geth_url, ec); - m_hdl = con->get_handle(); - - if (ec) { - m_endpoint.get_alog().write(websocketpp::log::alevel::app,ec.message()); - return; - } - - m_endpoint.connect(con); - - // Start the ASIO io_service run loop - m_endpoint.run(); - }); -} - -void eth_rpc_client::stop() { - m_endpoint.close(m_hdl,websocketpp::close::status::normal,""); -} - -void eth_rpc_client::on_socket_init(websocketpp::connection_hdl) { -} - -void eth_rpc_client::on_fail(websocketpp::connection_hdl hdl) { - client::connection_ptr con = m_endpoint.get_con_from_hdl(hdl); - - elog("Ethereum websocket fail"); - //elog("get_state: ${state}", ("state", con->get_state() ) ); - elog("get_local_close_code: ${code}", ("code", con->get_local_close_code())); - elog("get_local_close_reason: ${close}", ("close",con->get_local_close_reason())); - elog("get_remote_close_code: ${close}", ("close", con->get_remote_close_code())); - elog("get_remote_close_reason: ${close}", ("close", con->get_remote_close_reason())); - elog("get_ec().message(): ${ec}", ("ec", con->get_ec().message())); -} - -void eth_rpc_client::on_open(websocketpp::connection_hdl hdl) { - std::string str = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":84}"; - ilog("on_open: ${str}", ("str", str)); - m_endpoint.send(hdl, str.c_str(), websocketpp::frame::opcode::text); - - vector owner_addresses; - std::string private_key = ""; - createmultisig(5, owner_addresses, private_key); -} - -void eth_rpc_client::on_message(websocketpp::connection_hdl hdl, message_ptr msg) { - - ilog("on_message: ${msg}", ("msg", msg->get_payload())); - - fc::variants list = fc::json::variants_from_string( msg->get_payload() ); - - ilog("json reposnse: ${list}", ("list", list)); - - const auto& b_obj = list[0].get_object().find( "id" ); - - if (true == list[0].get_object().contains( "error" )){ - elog("error in json reposnse: ${list}", ("list", list)); - return; - } - - std::string result_str = list[0].get_object().find( "result" )->value().as(1); - uint32_t num_owners = 0; - uint32_t i = 0; - fc::variant v; - switch(b_obj->value().as(1)){ - case ETH_CHAIN_ID: - chain_id = result_str; - break; - case ETH_GET_TRANSACTION_RECEIPT: - list = fc::json::variants_from_string( result_str ); - v = list[0].get_object().find( "logs" )->value(); - safe_account_addr = v.get_object().find( "address" )->value().as(1); - break; - case ETH_CALL: - break; - case ETH_SEND_TRANSACTION: - transaction_id = result_str; - break; - case ETH_SEND_RAW_TRANSACTION: - break; - case ETH_GET_CODE: - code = result_str; - break; - case ETH_GET_BALANCE: - balance = result_str; - break; - case ETH_SIGN: - signature = result_str; - break; - case ETH_COINBASE: - account_address = result_str; - break; - case GET_LIST_OWNERS: - num_owners = (uint32_t)strtol(result_str.substr(2 + 32 + 32 - 4, 4).c_str(), NULL, 16); - owners.clear(); - for (i = 0; i < num_owners; ++i){ - owners.push_back("0x" + result_str.substr(2 + 32 + 32 + 12 + 32 * i,20)); - } - break; - case ADD_OWNER: - break; - case REMOVE_OWNER: - break; - } -} - -void eth_rpc_client::on_close(websocketpp::connection_hdl) { - ilog("Ethereum websocket close"); -} - -uint64_t eth_rpc_client::get_chain_id() { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":%1%}") % t_id); - ilog("get_chain_id: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_CHAIN_ID; - return t_id++; -} - -uint64_t eth_rpc_client::eth_getTransactionReceipt(const std::string& tx_id) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"%1%\"],\"id\":%2%}") % tx_id.c_str() % t_id); - ilog("eth_getTransactionReceipt: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_GET_TRANSACTION_RECEIPT; - return t_id++; -} - -uint64_t eth_rpc_client::eth_call(const std::string& to, const std::string& data) { - std::string req = str(boost::format("{\"jsonrpc\": \"2.0\", \"method\": \"eth_call\", \"params\": [{\"to\": \"%1%\", \"data\": \"%2%\"}, \"latest\"], \"id\": %3%}") % to.c_str() % data.c_str() % t_id); - ilog("eth_call: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_CALL; - - return t_id++; -} - -uint64_t eth_rpc_client::eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sendTransaction\", \"params\": [{\"from\": \"%1%\", \"to\": \"%2%\", \"data\": \"%3%\"}], \"id\": %4%}") % from.c_str() % to.c_str() % data.c_str() % t_id); - ilog("eth_sendTransaction: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_SEND_TRANSACTION; - - return t_id++; -} - -uint64_t eth_rpc_client::eth_sendRawTransaction(const std::string& params) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"%1%\"],\"id\":%2%}") % params.c_str() % t_id); - ilog("eth_sendRawTransaction: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_SEND_RAW_TRANSACTION; - - return t_id++; -} - -uint64_t eth_rpc_client::eth_getCode(const std::string& addr) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getCode\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); - ilog("eth_getCode: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_GET_CODE; - return t_id++; -} - -uint64_t eth_rpc_client::eth_getBalance(const std::string& addr) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getBalance\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); - ilog("eth_getBalance: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_GET_BALANCE; - return t_id++; -} - -uint64_t eth_rpc_client::eth_sign(const string& addr, const string& message) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sign\", \"params\": [\"%1%\",\"%2%\"], \"id\": %2%}") % addr.c_str() % message.c_str() % t_id); - ilog("eth_sign: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_SIGN; - - return t_id++; -} - -uint64_t eth_rpc_client::eth_coinbase() { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_coinbase\",\"params\":[],\"id\":%1%}") % t_id); - ilog("eth_coinbase: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_COINBASE; - return t_id++; -} - -uint64_t eth_rpc_client::get_list_owners(const std::string& safe_account) { - return eth_call(safe_account.c_str(), "0xa0e67e2b"); -} - -uint64_t eth_rpc_client::add_owner(const std::string& addr ) { - if (std::count(owners.begin(), owners.end(), addr)){ - FC_THROW_EXCEPTION(fc::exception, "Owners allready have addr: ${addr}", ("addr", addr)); - } - - //It's require to execute - //execTransaction method of smart contract , using safe-account address - //execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 dataGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); - FC_ASSERT("6a761202" == method_id); - std::string address = safe_account_addr; - std::string value = str(boost::format("%020u") % 0); - std::string data = "f8dc5dd9000000000000000000000000" + owners[0] + "000000000000000000000000" + addr + str(boost::format("%032u") % threshold); - std::string operation = "0"; - std::string safeTxGas = str(boost::format("%032u") % 0); - std::string dataGas = str(boost::format("%032u") % 0); - std::string gasPrice = str(boost::format("%032u") % 0); - std::string gasToken = "0000000000000000000000000000000000000000"; - std::string refundReceiver = "0000000000000000000000000000000000000000"; - - std::string message = method_id + address + value + data + operation + safeTxGas + dataGas + gasPrice + gasToken + refundReceiver; - uint64_t id = eth_sign(account_address, message); - - m_requests[t_id] = req_t::ADD_OWNER; - - return 0; -} - -uint64_t eth_rpc_client::remove_owner(const std::string& addr, uint32_t threshold) { - if (!std::count(owners.begin(), owners.end(), addr)){ - FC_THROW_EXCEPTION(fc::exception, "Owners does not have addr: ${addr}", ("addr", addr)); - } - - if (threshold == owners.size()){ - FC_THROW_EXCEPTION(fc::exception, "Owners size does not meet threshold: ${th}", ("th", threshold)); - } - - //It's require to execute - //execTransaction method of smart contract , using safe-account address - //execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 dataGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); - FC_ASSERT("6a761202" == method_id); - std::string address = safe_account_addr; - std::string value = str(boost::format("%032u") % 0); - std::string data = "f8dc5dd90000000000000000000000000000000000000000000000000000000000000001000000000000000000000000" + addr + str(boost::format("%032u") % threshold); - std::string operatio = "0"; - std::string safeTxGas = str(boost::format("%032u") % 0); - std::string dataGas = str(boost::format("%032u") % 0); - std::string gasPrice = str(boost::format("%032u") % 0); - std::string gasToken = "0000000000000000000000000000000000000000"; - std::string refundReceiver = "0000000000000000000000000000000000000000"; - - m_requests[t_id] = req_t::REMOVE_OWNER; - - return 0; -} - -std::string eth_rpc_client::addmultisigaddress(const uint32_t nrequired, const std::vector public_keys) { - return ""; -} - -std::string eth_rpc_client::combinepsbt(const vector &psbts) { - return ""; -} - -uint64_t eth_rpc_client::createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key) { - ilog("createmultisig: ${key}", ("key", private_key.c_str())); - -//That's will create -//0x5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12 -//0x76ce31BD03f601c3fC13732deF921c5Bac282676 -//0x09EE460834498a4ee361beB819470061B7381B49 -//0x6AEFbd09209e1eE2e0a589d31e732F69B77713D2 -//0x631e128b16f9aDCF1bB6385112B1519C917D77a7 -//0xcD5C788e84220E8b8934Ea4F1dC6a12009bCc91D -//0x3627C1B31525887CB9441130C831e35887650305 -//0x03A13a989AF30C92AD7ABD1E6210308A6c96f373 - - - std::string from = "0xeE52b70e8D7AB5Fe661311D47e81228EAD6B06B9"; - std::string to = "0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2"; - std::string data = "0x1688f0b9000000000000000000000000d9db270c1b5e3bd161e8c8503c55ceabee70955200000000000000000000000000000000000000000000000000000000000000604fa262bd05cdef2e3d5261787ee66d9447a4036324990e04380339bec83b4c7a0000000000000000000000000000000000000000000000000000000000000264b63e800d0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000f48f2b2d2a534e402487b3ee7c18c33aec0fe5e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC1200000000000000000000000076ce31BD03f601c3fC13732deF921c5Bac28267600000000000000000000000009EE460834498a4ee361beB819470061B7381B490000000000000000000000006AEFbd09209e1eE2e0a589d31e732F69B77713D2000000000000000000000000631e128b16f9aDCF1bB6385112B1519C917D77a7000000000000000000000000cD5C788e84220E8b8934Ea4F1dC6a12009bCc91D0000000000000000000000003627C1B31525887CB9441130C831e3588765030500000000000000000000000003A13a989AF30C92AD7ABD1E6210308A6c96f3730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; - return eth_sendTransaction(from, to, data); -} - -std::string eth_rpc_client::createpsbt() { -} - -std::string eth_rpc_client::createrawtransaction() { - return ""; -} - -std::string eth_rpc_client::createwallet(const std::string &wallet_name) { - return ""; -} - -std::string eth_rpc_client::decodepsbt(std::string const &tx_psbt) { - return ""; -} - -std::string eth_rpc_client::decoderawtransaction(std::string const &tx_hex) { - return ""; -} - -std::string eth_rpc_client::encryptwallet(const std::string &passphrase) { - return ""; -} - -uint64_t eth_rpc_client::estimatesmartfee(uint16_t conf_target) { - return 20000; -} - -std::string eth_rpc_client::finalizepsbt(std::string const &tx_psbt) { - return ""; -} - -std::string eth_rpc_client::getaddressinfo(const std::string &address) { - return ""; -} - -std::string eth_rpc_client::getblock(const std::string &block_hash, int32_t verbosity) { - return ""; -} - -std::string eth_rpc_client::getnetworkinfo() { - return ""; -} - -std::string eth_rpc_client::getrawtransaction(const std::string &txid, const bool verbose) { - return ""; -} - -std::string eth_rpc_client::gettransaction(const std::string &txid, const bool include_watch_only) { - return ""; -} - -std::string eth_rpc_client::getblockchaininfo() { - return ""; -} - -void eth_rpc_client::importaddress(const std::string &address_or_script, const std::string &label, const bool rescan, const bool p2sh) { - return; -} - -void eth_rpc_client::importmulti(const std::vector &address_or_script_array, const bool rescan) { -} - -std::string eth_rpc_client::loadwallet(const std::string &filename) { - return ""; -} + // ============================================================================= + std::string eth_rpc_client::ethereum_function_call_encoder::encode_function_signature(const std::string& function_signature) { + sha3_context c; + char *hash; + + sha3_Init256(static_cast(&c)); + sha3_SetFlags(&c, SHA3_FLAGS_KECCAK); + sha3_Update(&c, "abc", 3); + hash = (char*)sha3_Finalize(&c); + std::string output(hash); + output = output.substr(0,8); + + return output; + }; + + std::string eth_rpc_client::ethereum_function_call_encoder::encode_address(const std::string& addr) { + FC_ASSERT(40 == addr.length()); + std::string output = str(boost::format("%024u") % 0) + addr; + return output; + } + + std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint256(const std::string& value) { + FC_ASSERT(value.length() <= 64); + std::string output = std::string(64 - value.length(), '0') + value; + return output; + } + + std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint8(uint8_t value) { + std::string output = str(boost::format("%02X") % value) + std::string(62, '0'); + return output; + } + + std::string eth_rpc_client::ethereum_function_call_encoder::encode_bytes(const std::string& values) { + size_t len = values.length(); + std::string output = encode_uint256((boost::format("%x") % len).str()) + values + std::string(64 - len, '0'); + return output; + } + + std::string eth_rpc_client::safe_transaction_encoder::create_safe_address(const std::vector owner_addresses, uint32_t threshold) { + } + + std::string eth_rpc_client::safe_transaction_encoder::build_transaction(const std::string& safe_account_addr, const std::string& value, const std::string& data, uint8_t operation, const std::string& safeTxGas, const std::string& dataGas, const std::string& gasPrice, const std::string& gasToken, const std::string& refundReceiver){ + //execTransaction method of smart contract , using safe-account address + //execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 dataGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) + std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); + FC_ASSERT("6a761202" == method_id); + //"" + std::string to = m_ethereum_function_call_encoder.encode_address(safe_account_addr); + // Value in wei + std::string value_encoded = m_ethereum_function_call_encoder.encode_uint256(value); + // 0 CALL, 1 DELEGATE_CALL + std::string operation_encoded = m_ethereum_function_call_encoder.encode_uint8(operation); + // Max gas to use in the transaction + std::string safeTxGas_encoded = m_ethereum_function_call_encoder.encode_uint256(safeTxGas); + // Gas costs not related to the transaction execution (signature check, refund payment...) + std::string dataGas_encoded = m_ethereum_function_call_encoder.encode_uint256(dataGas); + // Gas price used for the refund calculation + std::string gasPrice_encoded = m_ethereum_function_call_encoder.encode_uint256(gasPrice); + //"", Token address (hold by the Safe) to be used as a refund to the sender, if `null` is Ether + std::string gasToken_encoded = m_ethereum_function_call_encoder.encode_address(gasToken); + //"", Address of receiver of gas payment (or `null` if tx.origin) + std::string refundReceiver_encoded = m_ethereum_function_call_encoder.encode_address(refundReceiver); + + std::string message = method_id + to + value_encoded + data + operation_encoded + safeTxGas_encoded + dataGas_encoded + gasPrice_encoded + gasToken_encoded + refundReceiver_encoded; + + return message; + } + + + eth_rpc_client::eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : _thread(std::make_shared("eth_rpc_client")){ + geth_url = url; + user = user_name; + this->password = password; + this->debug_rpc_calls = debug_rpc_calls; + t_id = 1; + + ilog("eth_rpc_client"); + ilog("### Geth URL: ${url}", ("url", url)); + + m_endpoint.set_access_channels(websocketpp::log::alevel::none); + m_endpoint.set_error_channels(websocketpp::log::elevel::none); + + // Initialize ASIO + m_endpoint.init_asio(); + + // Register our handlers + m_endpoint.set_socket_init_handler(bind(&type::on_socket_init,this,::_1)); + m_endpoint.set_message_handler(bind(&type::on_message,this,::_1,::_2)); + m_endpoint.set_open_handler(bind(&type::on_open,this,::_1)); + m_endpoint.set_close_handler(bind(&type::on_close,this,::_1)); + m_endpoint.set_fail_handler(bind(&type::on_fail,this,::_1)); + } + + void eth_rpc_client::start() { + ilog("### eth_rpc_client::start uri: ${uri}", ("uri", geth_url)); + auto future = _thread->async([this] + { + websocketpp::lib::error_code ec; + client::connection_ptr con = m_endpoint.get_connection(this->geth_url, ec); + m_hdl = con->get_handle(); + + if (ec) { + m_endpoint.get_alog().write(websocketpp::log::alevel::app,ec.message()); + return; + } + + m_endpoint.connect(con); + + // Start the ASIO io_service run loop + m_endpoint.run(); + }); + } + + void eth_rpc_client::stop() { + m_endpoint.close(m_hdl,websocketpp::close::status::normal,""); + } + + void eth_rpc_client::on_socket_init(websocketpp::connection_hdl) { + } + + void eth_rpc_client::on_fail(websocketpp::connection_hdl hdl) { + client::connection_ptr con = m_endpoint.get_con_from_hdl(hdl); + + elog("Ethereum websocket fail"); + //elog("get_state: ${state}", ("state", con->get_state() ) ); + elog("get_local_close_code: ${code}", ("code", con->get_local_close_code())); + elog("get_local_close_reason: ${close}", ("close",con->get_local_close_reason())); + elog("get_remote_close_code: ${close}", ("close", con->get_remote_close_code())); + elog("get_remote_close_reason: ${close}", ("close", con->get_remote_close_reason())); + elog("get_ec().message(): ${ec}", ("ec", con->get_ec().message())); + } + + void eth_rpc_client::on_open(websocketpp::connection_hdl hdl) { + std::string str = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":84}"; + ilog("on_open: ${str}", ("str", str)); + m_endpoint.send(hdl, str.c_str(), websocketpp::frame::opcode::text); + + vector owner_addresses; + std::string private_key = ""; + createmultisig(5, owner_addresses, private_key); + } + + void eth_rpc_client::on_message(websocketpp::connection_hdl hdl, message_ptr msg) { + + ilog("on_message: ${msg}", ("msg", msg->get_payload())); + + fc::variants list = fc::json::variants_from_string( msg->get_payload() ); + + ilog("json reposnse: ${list}", ("list", list)); + + const auto& b_obj = list[0].get_object().find( "id" ); + + if (true == list[0].get_object().contains( "error" )){ + elog("error in json reposnse: ${list}", ("list", list)); + return; + } + + std::string result_str = list[0].get_object().find( "result" )->value().as(1); + uint32_t num_owners = 0; + uint32_t i = 0; + fc::variant v; + switch(b_obj->value().as(1)){ + case ETH_CHAIN_ID: + chain_id = result_str; + break; + case ETH_GET_TRANSACTION_RECEIPT: + list = fc::json::variants_from_string( result_str ); + v = list[0].get_object().find( "logs" )->value(); + safe_account_addr = v.get_object().find( "address" )->value().as(1); + break; + case ETH_CALL: + break; + case ETH_SEND_TRANSACTION: + transaction_id = result_str; + break; + case ETH_SEND_RAW_TRANSACTION: + break; + case ETH_GET_CODE: + code = result_str; + break; + case ETH_GET_BALANCE: + balance = result_str; + break; + case ETH_SIGN: + signature = result_str; + break; + case ETH_COINBASE: + account_address = result_str; + break; + case GET_LIST_OWNERS: + num_owners = (uint32_t)strtol(result_str.substr(2 + 32 + 32 - 4, 4).c_str(), NULL, 16); + owners.clear(); + for (i = 0; i < num_owners; ++i){ + owners.push_back("0x" + result_str.substr(2 + 32 + 32 + 12 + 32 * i,20)); + } + break; + case ADD_OWNER: + break; + case REMOVE_OWNER: + break; + } + } + + void eth_rpc_client::on_close(websocketpp::connection_hdl) { + ilog("Ethereum websocket close"); + } + + uint64_t eth_rpc_client::get_chain_id() { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":%1%}") % t_id); + ilog("get_chain_id: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_CHAIN_ID; + return t_id++; + } + + uint64_t eth_rpc_client::eth_getTransactionReceipt(const std::string& tx_id) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"%1%\"],\"id\":%2%}") % tx_id.c_str() % t_id); + ilog("eth_getTransactionReceipt: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_GET_TRANSACTION_RECEIPT; + return t_id++; + } + + uint64_t eth_rpc_client::eth_call(const std::string& to, const std::string& data) { + std::string req = str(boost::format("{\"jsonrpc\": \"2.0\", \"method\": \"eth_call\", \"params\": [{\"to\": \"%1%\", \"data\": \"%2%\"}, \"latest\"], \"id\": %3%}") % to.c_str() % data.c_str() % t_id); + ilog("eth_call: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_CALL; + + return t_id++; + } + + uint64_t eth_rpc_client::eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sendTransaction\", \"params\": [{\"from\": \"%1%\", \"to\": \"%2%\", \"data\": \"%3%\"}], \"id\": %4%}") % from.c_str() % to.c_str() % data.c_str() % t_id); + ilog("eth_sendTransaction: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_SEND_TRANSACTION; + + return t_id++; + } + + uint64_t eth_rpc_client::eth_sendRawTransaction(const std::string& params) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"%1%\"],\"id\":%2%}") % params.c_str() % t_id); + ilog("eth_sendRawTransaction: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_SEND_RAW_TRANSACTION; + + return t_id++; + } + + uint64_t eth_rpc_client::eth_getCode(const std::string& addr) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getCode\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); + ilog("eth_getCode: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_GET_CODE; + return t_id++; + } + + uint64_t eth_rpc_client::eth_getBalance(const std::string& addr) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getBalance\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); + ilog("eth_getBalance: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_GET_BALANCE; + return t_id++; + } + + uint64_t eth_rpc_client::eth_sign(const string& addr, const string& message) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sign\", \"params\": [\"%1%\",\"%2%\"], \"id\": %2%}") % addr.c_str() % message.c_str() % t_id); + ilog("eth_sign: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_SIGN; + + return t_id++; + } + + uint64_t eth_rpc_client::eth_coinbase() { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_coinbase\",\"params\":[],\"id\":%1%}") % t_id); + ilog("eth_coinbase: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_COINBASE; + return t_id++; + } + + uint64_t eth_rpc_client::get_list_owners(const std::string& safe_account) { + //getOwners() + std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("getOwners()"); + FC_ASSERT("a0e67e2b" == method_id); + return eth_call(safe_account.c_str(), method_id); + } + + uint64_t eth_rpc_client::add_owner(const std::string& addr ) { + if (std::count(owners.begin(), owners.end(), addr)){ + FC_THROW_EXCEPTION(fc::exception, "Owners allready have addr: ${addr}", ("addr", addr)); + } + + std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); + //addOwnerWithThreshold(address,uint256) + std::string data_method_id = m_ethereum_function_call_encoder.encode_function_signature("addOwnerWithThreshold(address,uint256)"); + FC_ASSERT("0d582f13" == data_method_id); + std::string data = data_method_id + m_ethereum_function_call_encoder.encode_address(addr) + m_ethereum_function_call_encoder.encode_uint256((boost::format("%x") % threshold).str()); + + std::string message = m_safe_transaction_encoder.build_transaction(safe_account_addr, "0", data, ethereum_function_call_encoder::operation_t::OPERATION_CALL, m_safe_transaction_encoder.default_safe_tx_gas, m_safe_transaction_encoder.default_data_gas, m_safe_transaction_encoder.default_gas_price, m_safe_transaction_encoder.default_gas_token, m_safe_transaction_encoder.default_refund_receiver); + + uint64_t id = eth_sign(account_address, message); + + m_requests[t_id] = req_t::ADD_OWNER; + + return 0; + } + + uint64_t eth_rpc_client::remove_owner(const std::string& addr, uint32_t threshold) { + if (!std::count(owners.begin(), owners.end(), addr)){ + FC_THROW_EXCEPTION(fc::exception, "Owners does not have addr: ${addr}", ("addr", addr)); + } + + if (threshold == owners.size()){ + FC_THROW_EXCEPTION(fc::exception, "Owners size does not meet threshold: ${th}", ("th", threshold)); + } + + //removeOwner(address,address,uint256) + std::string data_method_id = m_ethereum_function_call_encoder.encode_function_signature("removeOwner(address,address,uint256)"); + FC_ASSERT("f8dc5dd9" == data_method_id); + std::string data = data_method_id + m_ethereum_function_call_encoder.encode_address(m_ethereum_function_call_encoder.default_prev_addr) + m_ethereum_function_call_encoder.encode_address(addr) + m_ethereum_function_call_encoder.encode_uint256((boost::format("%x") % threshold).str()); + + std::string message = m_safe_transaction_encoder.build_transaction(safe_account_addr, "0", data, ethereum_function_call_encoder::operation_t::OPERATION_CALL, m_safe_transaction_encoder.default_safe_tx_gas, m_safe_transaction_encoder.default_data_gas, m_safe_transaction_encoder.default_gas_price, m_safe_transaction_encoder.default_gas_token, m_safe_transaction_encoder.default_refund_receiver); + + uint64_t id = eth_sign(account_address, message); + + m_requests[t_id] = req_t::REMOVE_OWNER; + + return 0; + } + + std::string eth_rpc_client::addmultisigaddress(const uint32_t nrequired, const std::vector public_keys) { + return ""; + } + + std::string eth_rpc_client::combinepsbt(const vector &psbts) { + return ""; + } + + uint64_t eth_rpc_client::createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key) { + ilog("createmultisig: ${key}", ("key", private_key.c_str())); + + //That's will create + //0x5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12 + //0x76ce31BD03f601c3fC13732deF921c5Bac282676 + //0x09EE460834498a4ee361beB819470061B7381B49 + //0x6AEFbd09209e1eE2e0a589d31e732F69B77713D2 + //0x631e128b16f9aDCF1bB6385112B1519C917D77a7 + //0xcD5C788e84220E8b8934Ea4F1dC6a12009bCc91D + //0x3627C1B31525887CB9441130C831e35887650305 + //0x03A13a989AF30C92AD7ABD1E6210308A6c96f373 + + + std::string from = "0xeE52b70e8D7AB5Fe661311D47e81228EAD6B06B9"; + std::string to = "0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2"; + std::string data = "0x1688f0b9000000000000000000000000d9db270c1b5e3bd161e8c8503c55ceabee70955200000000000000000000000000000000000000000000000000000000000000604fa262bd05cdef2e3d5261787ee66d9447a4036324990e04380339bec83b4c7a0000000000000000000000000000000000000000000000000000000000000264b63e800d0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000f48f2b2d2a534e402487b3ee7c18c33aec0fe5e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC1200000000000000000000000076ce31BD03f601c3fC13732deF921c5Bac28267600000000000000000000000009EE460834498a4ee361beB819470061B7381B490000000000000000000000006AEFbd09209e1eE2e0a589d31e732F69B77713D2000000000000000000000000631e128b16f9aDCF1bB6385112B1519C917D77a7000000000000000000000000cD5C788e84220E8b8934Ea4F1dC6a12009bCc91D0000000000000000000000003627C1B31525887CB9441130C831e3588765030500000000000000000000000003A13a989AF30C92AD7ABD1E6210308A6c96f3730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + return eth_sendTransaction(from, to, data); + } + + std::string eth_rpc_client::createpsbt() { + } + + std::string eth_rpc_client::createrawtransaction() { + return ""; + } + + std::string eth_rpc_client::createwallet(const std::string &wallet_name) { + return ""; + } -std::string eth_rpc_client::sendrawtransaction(const std::string &tx_hex) { - return ""; -} - -std::string eth_rpc_client::signrawtransactionwithwallet(const std::string &tx_hash) { - return ""; -} - -std::string eth_rpc_client::unloadwallet(const std::string &filename) { - return ""; -} - -std::string eth_rpc_client::walletlock() { - return ""; -} - -std::string eth_rpc_client::walletprocesspsbt(std::string const &tx_psbt) { - return ""; -} - -bool eth_rpc_client::walletpassphrase(const std::string &passphrase, uint32_t timeout) { - return false; -} + std::string eth_rpc_client::decodepsbt(std::string const &tx_psbt) { + return ""; + } + + std::string eth_rpc_client::decoderawtransaction(std::string const &tx_hex) { + return ""; + } -// ============================================================================= + std::string eth_rpc_client::encryptwallet(const std::string &passphrase) { + return ""; + } -sidechain_net_handler_eth::sidechain_net_handler_eth(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : - sidechain_net_handler(_plugin, options) { - sidechain = sidechain_type::ethereum; - - if (options.count("debug-rpc-calls")) { - debug_rpc_calls = options.at("debug-rpc-calls").as(); - } + uint64_t eth_rpc_client::estimatesmartfee(uint16_t conf_target) { + return 20000; + } - url = options.at("ethereum-node-rpc-url").as(); - eth_client = std::unique_ptr(new eth_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls)); - eth_client->start(); -/* - if (!wallet.empty()) { - eth_client->loadwallet(wallet); - } - - - std::thread(&sidechain_net_handler_eth::handle_event, this, event_data).detach(); - }); - - database.changed_objects.connect([this](const vector &ids, const flat_set &accounts) { - on_changed_objects(ids, accounts); - }); -*/ + std::string eth_rpc_client::finalizepsbt(std::string const &tx_psbt) { + return ""; + } + + std::string eth_rpc_client::getaddressinfo(const std::string &address) { + return ""; + } + + std::string eth_rpc_client::getblock(const std::string &block_hash, int32_t verbosity) { + return ""; + } + + std::string eth_rpc_client::getnetworkinfo() { + return ""; + } + + std::string eth_rpc_client::getrawtransaction(const std::string &txid, const bool verbose) { + return ""; + } + + std::string eth_rpc_client::gettransaction(const std::string &txid, const bool include_watch_only) { + return ""; + } + + std::string eth_rpc_client::getblockchaininfo() { + return ""; + } + + void eth_rpc_client::importaddress(const std::string &address_or_script, const std::string &label, const bool rescan, const bool p2sh) { + return; + } + + void eth_rpc_client::importmulti(const std::vector &address_or_script_array, const bool rescan) { + } + + std::string eth_rpc_client::loadwallet(const std::string &filename) { + return ""; + } + + std::string eth_rpc_client::sendrawtransaction(const std::string &tx_hex) { + return ""; + } + + std::string eth_rpc_client::signrawtransactionwithwallet(const std::string &tx_hash) { + return ""; + } + + std::string eth_rpc_client::unloadwallet(const std::string &filename) { + return ""; + } + + std::string eth_rpc_client::walletlock() { + return ""; + } + + std::string eth_rpc_client::walletprocesspsbt(std::string const &tx_psbt) { + return ""; + } + + bool eth_rpc_client::walletpassphrase(const std::string &passphrase, uint32_t timeout) { + return false; + } + + // ============================================================================= + + sidechain_net_handler_eth::sidechain_net_handler_eth(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : + sidechain_net_handler(_plugin, options) { + sidechain = sidechain_type::ethereum; + + if (options.count("debug-rpc-calls")) { + debug_rpc_calls = options.at("debug-rpc-calls").as(); + } + + url = options.at("ethereum-node-rpc-url").as(); + eth_client = std::unique_ptr(new eth_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls)); + eth_client->start(); + /* + if (!wallet.empty()) { + eth_client->loadwallet(wallet); + } + + + std::thread(&sidechain_net_handler_eth::handle_event, this, event_data).detach(); + }); + + database.changed_objects.connect([this](const vector &ids, const flat_set &accounts) { + on_changed_objects(ids, accounts); + }); + */ } sidechain_net_handler_eth::~sidechain_net_handler_eth() { - try { - if (on_changed_objects_task.valid()) { - on_changed_objects_task.cancel_and_wait(__FUNCTION__); - } - } catch (fc::canceled_exception &) { - //Expected exception. Move along. - } catch (fc::exception &e) { - edump((e.to_detail_string())); - } + try { + if (on_changed_objects_task.valid()) { + on_changed_objects_task.cancel_and_wait(__FUNCTION__); + } + } catch (fc::canceled_exception &) { + //Expected exception. Move along. + } catch (fc::exception &e) { + edump((e.to_detail_string())); + } } bool sidechain_net_handler_eth::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())); -/* - bool should_approve = false; + ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); + /* + bool should_approve = false; - const chain::global_property_object &gpo = database.get_global_properties(); + const chain::global_property_object &gpo = database.get_global_properties(); - int32_t op_idx_0 = -1; - chain::operation op_obj_idx_0; + int32_t op_idx_0 = -1; + chain::operation op_obj_idx_0; - if (po.proposed_transaction.operations.size() >= 1) { - op_idx_0 = po.proposed_transaction.operations[0].which(); - op_obj_idx_0 = po.proposed_transaction.operations[0]; - } + if (po.proposed_transaction.operations.size() >= 1) { + op_idx_0 = po.proposed_transaction.operations[0].which(); + op_obj_idx_0 = po.proposed_transaction.operations[0]; + } - int32_t op_idx_1 = -1; - chain::operation op_obj_idx_1; - (void)op_idx_1; + int32_t op_idx_1 = -1; + chain::operation op_obj_idx_1; + (void)op_idx_1; - if (po.proposed_transaction.operations.size() >= 2) { - op_idx_1 = po.proposed_transaction.operations[1].which(); - op_obj_idx_1 = po.proposed_transaction.operations[1]; - } + if (po.proposed_transaction.operations.size() >= 2) { + op_idx_1 = po.proposed_transaction.operations[1].which(); + op_obj_idx_1 = po.proposed_transaction.operations[1]; + } - switch (op_idx_0) { + switch (op_idx_0) { - case chain::operation::tag::value: { - bool address_ok = false; - 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 &idx = database.get_index_type().indices().get(); - const auto swo = idx.find(swo_id); - if (swo != idx.end()) { + case chain::operation::tag::value: { + bool address_ok = false; + 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 &idx = database.get_index_type().indices().get(); + const auto swo = idx.find(swo_id); + if (swo != idx.end()) { - auto active_sons = gpo.active_sons; - vector wallet_sons = swo->sons; + auto active_sons = gpo.active_sons; + vector wallet_sons = swo->sons; - bool son_sets_equal = (active_sons.size() == wallet_sons.size()); + bool son_sets_equal = (active_sons.size() == wallet_sons.size()); - if (son_sets_equal) { - for (size_t i = 0; i < active_sons.size(); i++) { - son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i); - } - } + if (son_sets_equal) { + for (size_t i = 0; i < active_sons.size(); i++) { + son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i); + } + } - if (son_sets_equal) { - auto active_sons = gpo.active_sons; - vector son_pubkeys_bitcoin; - for (const son_info &si : active_sons) { - son_pubkeys_bitcoin.push_back(si.sidechain_public_keys.at(sidechain_type::bitcoin)); - } + if (son_sets_equal) { + auto active_sons = gpo.active_sons; + vector son_pubkeys_bitcoin; + for (const son_info &si : active_sons) { + son_pubkeys_bitcoin.push_back(si.sidechain_public_keys.at(sidechain_type::bitcoin)); + } - string reply_str = create_primary_wallet_address(active_sons); + string reply_str = create_primary_wallet_address(active_sons); - std::stringstream active_pw_ss(reply_str); - boost::property_tree::ptree active_pw_pt; - boost::property_tree::read_json(active_pw_ss, active_pw_pt); - if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { - std::stringstream res; - boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); - new_pw_address = active_pw_pt.get("result.address"); + std::stringstream active_pw_ss(reply_str); + boost::property_tree::ptree active_pw_pt; + boost::property_tree::read_json(active_pw_ss, active_pw_pt); + if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { + std::stringstream res; + boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); + new_pw_address = active_pw_pt.get("result.address"); - address_ok = (op_obj_idx_0.get().address == res.str()); - } - } + address_ok = (op_obj_idx_0.get().address == res.str()); + } + } - if (po.proposed_transaction.operations.size() >= 2) { - object_id_type object_id = op_obj_idx_1.get().object_id; - std::string op_tx_str = op_obj_idx_1.get().transaction; + if (po.proposed_transaction.operations.size() >= 2) { + object_id_type object_id = op_obj_idx_1.get().object_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); - if (st == st_idx.end()) { + const auto &st_idx = database.get_index_type().indices().get(); + const auto st = st_idx.find(object_id); + if (st == st_idx.end()) { - std::string tx_str = ""; + std::string tx_str = ""; - if (object_id.is()) { - const auto &idx = database.get_index_type().indices().get(); - const auto swo = idx.find(object_id); - if (swo != idx.end()) { - tx_str = create_primary_wallet_transaction(*swo, new_pw_address); - } - } + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swo = idx.find(object_id); + if (swo != idx.end()) { + tx_str = create_primary_wallet_transaction(*swo, new_pw_address); + } + } - transaction_ok = (op_tx_str == tx_str); - } - } else { - transaction_ok = true; - } - } + transaction_ok = (op_tx_str == tx_str); + } +} else { + transaction_ok = true; +} +} - should_approve = address_ok && - transaction_ok; - break; - } +should_approve = address_ok && +transaction_ok; +break; +} - case chain::operation::tag::value: { - bool process_ok = false; - bool transaction_ok = false; - son_wallet_deposit_id_type swdo_id = op_obj_idx_0.get().son_wallet_deposit_id; - const auto &idx = database.get_index_type().indices().get(); - const auto swdo = idx.find(swdo_id); - if (swdo != idx.end()) { +case chain::operation::tag::value: { + bool process_ok = false; + bool transaction_ok = false; + son_wallet_deposit_id_type swdo_id = op_obj_idx_0.get().son_wallet_deposit_id; + const auto &idx = database.get_index_type().indices().get(); + const auto swdo = idx.find(swdo_id); + if (swdo != idx.end()) { - std::string swdo_txid = swdo->sidechain_transaction_id; - std::string swdo_address = swdo->sidechain_from; - 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)); + std::string swdo_txid = swdo->sidechain_transaction_id; + std::string swdo_address = swdo->sidechain_from; + 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)); - std::string tx_str = eth_client->getrawtransaction(swdo_txid, true); - std::stringstream tx_ss(tx_str); - boost::property_tree::ptree tx_json; - boost::property_tree::read_json(tx_ss, tx_json); + std::string tx_str = eth_client->getrawtransaction(swdo_txid, true); + std::stringstream tx_ss(tx_str); + boost::property_tree::ptree tx_json; + boost::property_tree::read_json(tx_ss, tx_json); - if (tx_json.count("error") && tx_json.get_child("error").empty()) { + if (tx_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"); - std::string tx_address = ""; - uint64_t tx_amount = -1; - uint64_t tx_vout = -1; + 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; - 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; - } - } - } - 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; - } - } + 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; + } + } + } + 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; + } + } - 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; - std::string op_tx_str = op_obj_idx_1.get().transaction; + object_id_type object_id = op_obj_idx_1.get().object_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); - if (st == st_idx.end()) { + const auto &st_idx = database.get_index_type().indices().get(); + const auto st = st_idx.find(object_id); + if (st == st_idx.end()) { - std::string tx_str = ""; + std::string tx_str = ""; - if (object_id.is()) { - const auto &idx = database.get_index_type().indices().get(); - const auto swdo = idx.find(object_id); - if (swdo != idx.end()) { - tx_str = create_deposit_transaction(*swdo); - } - } + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swdo = idx.find(object_id); + if (swdo != idx.end()) { + tx_str = create_deposit_transaction(*swdo); + } + } - transaction_ok = (op_tx_str == tx_str); - } - } + transaction_ok = (op_tx_str == tx_str); + } + } - should_approve = process_ok && - transaction_ok; - break; - } + should_approve = process_ok && + transaction_ok; + break; + } - case chain::operation::tag::value: { - bool process_ok = false; - bool transaction_ok = false; - son_wallet_withdraw_id_type swwo_id = op_obj_idx_0.get().son_wallet_withdraw_id; - const auto &idx = database.get_index_type().indices().get(); - const auto swwo = idx.find(swwo_id); - if (swwo != idx.end()) { +case chain::operation::tag::value: { + bool process_ok = false; + bool transaction_ok = false; + son_wallet_withdraw_id_type swwo_id = op_obj_idx_0.get().son_wallet_withdraw_id; + const auto &idx = database.get_index_type().indices().get(); + const auto swwo = idx.find(swwo_id); + if (swwo != idx.end()) { - uint32_t swwo_block_num = swwo->block_num; - std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id; - uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1)); + uint32_t swwo_block_num = swwo->block_num; + std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id; + uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1)); - const auto &block = database.fetch_block_by_number(swwo_block_num); + const auto &block = database.fetch_block_by_number(swwo_block_num); - for (const auto &tx : block->transactions) { - if (tx.id().str() == swwo_peerplays_transaction_id) { - operation op = tx.operations[swwo_op_idx]; - transfer_operation t_op = op.get(); + for (const auto &tx : block->transactions) { + if (tx.id().str() == swwo_peerplays_transaction_id) { + operation op = tx.operations[swwo_op_idx]; + transfer_operation t_op = op.get(); - price asset_price = database.get(t_op.amount.asset_id).options.core_exchange_rate; - asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); + price asset_price = database.get(t_op.amount.asset_id).options.core_exchange_rate; + asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); - process_ok = (t_op.to == gpo.parameters.son_account()) && - (swwo->peerplays_from == t_op.from) && - (swwo->peerplays_asset == peerplays_asset); - break; - } - } + process_ok = (t_op.to == gpo.parameters.son_account()) && + (swwo->peerplays_from == t_op.from) && + (swwo->peerplays_asset == peerplays_asset); + break; + } + } - object_id_type object_id = op_obj_idx_1.get().object_id; - std::string op_tx_str = op_obj_idx_1.get().transaction; + object_id_type object_id = op_obj_idx_1.get().object_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); - if (st == st_idx.end()) { + const auto &st_idx = database.get_index_type().indices().get(); + const auto st = st_idx.find(object_id); + if (st == st_idx.end()) { - std::string tx_str = ""; + std::string tx_str = ""; - if (object_id.is()) { - const auto &idx = database.get_index_type().indices().get(); - const auto swwo = idx.find(object_id); - if (swwo != idx.end()) { - tx_str = create_withdrawal_transaction(*swwo); - } - } + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swwo = idx.find(object_id); + if (swwo != idx.end()) { + tx_str = create_withdrawal_transaction(*swwo); + } + } - transaction_ok = (op_tx_str == tx_str); - } - } + transaction_ok = (op_tx_str == tx_str); + } + } - should_approve = process_ok && - transaction_ok; - break; - } + should_approve = process_ok && + transaction_ok; + break; + } - case chain::operation::tag::value: { - using namespace bitcoin; - should_approve = true; - son_id_type signer = op_obj_idx_0.get().signer; - std::string signature = op_obj_idx_0.get().signature; - sidechain_transaction_id_type sidechain_transaction_id = op_obj_idx_0.get().sidechain_transaction_id; - std::vector in_amounts; - std::string tx_hex; - std::string redeem_script; - const auto &st_idx = database.get_index_type().indices().get(); - const auto sto = st_idx.find(sidechain_transaction_id); - if (sto == st_idx.end()) { - should_approve = false; - break; - } +case chain::operation::tag::value: { + using namespace bitcoin; + should_approve = true; + son_id_type signer = op_obj_idx_0.get().signer; + std::string signature = op_obj_idx_0.get().signature; + sidechain_transaction_id_type sidechain_transaction_id = op_obj_idx_0.get().sidechain_transaction_id; + std::vector in_amounts; + std::string tx_hex; + std::string redeem_script; + const auto &st_idx = database.get_index_type().indices().get(); + const auto sto = st_idx.find(sidechain_transaction_id); + if (sto == st_idx.end()) { + should_approve = false; + break; + } - const auto &s_idx = database.get_index_type().indices().get(); - const auto son = s_idx.find(signer); - if (son == s_idx.end()) { - should_approve = false; - break; - } + const auto &s_idx = database.get_index_type().indices().get(); + const auto son = s_idx.find(signer); + if (son == s_idx.end()) { + should_approve = false; + break; + } - read_transaction_data(sto->transaction, tx_hex, in_amounts, redeem_script); - bitcoin_transaction tx = unpack(parse_hex(tx_hex)); - bitcoin::bytes pubkey = parse_hex(son->sidechain_public_keys.at(sidechain_type::bitcoin)); - vector sigs = read_byte_arrays_from_string(signature); - for (size_t i = 0; i < tx.vin.size(); i++) { - const auto &sighash_str = get_signature_hash(tx, parse_hex(redeem_script), static_cast(in_amounts[i]), i, 1, true).str(); - const bitcoin::bytes &sighash_hex = parse_hex(sighash_str); - should_approve = should_approve && verify_sig(sigs[i], pubkey, sighash_hex, btc_context()); - } - break; - } + read_transaction_data(sto->transaction, tx_hex, in_amounts, redeem_script); + bitcoin_transaction tx = unpack(parse_hex(tx_hex)); + bitcoin::bytes pubkey = parse_hex(son->sidechain_public_keys.at(sidechain_type::bitcoin)); + vector sigs = read_byte_arrays_from_string(signature); + for (size_t i = 0; i < tx.vin.size(); i++) { + const auto &sighash_str = get_signature_hash(tx, parse_hex(redeem_script), static_cast(in_amounts[i]), i, 1, true).str(); + const bitcoin::bytes &sighash_hex = parse_hex(sighash_str); + should_approve = should_approve && verify_sig(sigs[i], pubkey, sighash_hex, btc_context()); + } + break; + } - case chain::operation::tag::value: { - should_approve = true; - break; - } +case chain::operation::tag::value: { + should_approve = true; + break; + } - default: - should_approve = false; - elog("=================================================="); - elog("Proposal not considered for approval ${po}", ("po", po)); - elog("=================================================="); - } +default: +should_approve = false; +elog("=================================================="); +elog("Proposal not considered for approval ${po}", ("po", po)); +elog("=================================================="); +} - return should_approve; - */ +return should_approve; +*/ - return true; +return true; } void sidechain_net_handler_eth::process_primary_wallet() { - ilog("### process_primary_wallet:"); - - const auto &swi = database.get_index_type().indices().get(); - const auto &active_sw = swi.rbegin(); - if (active_sw != swi.rend()) { + ilog("### process_primary_wallet:"); - if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) || - (active_sw->addresses.at(sidechain_type::ethereum).empty())) { + const auto &swi = database.get_index_type().indices().get(); + const auto &active_sw = swi.rbegin(); + if (active_sw != swi.rend()) { - if (proposal_exists(chain::operation::tag::value, active_sw->id)) { - return; - } + if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) || + (active_sw->addresses.at(sidechain_type::ethereum).empty())) { - const chain::global_property_object &gpo = database.get_global_properties(); + if (proposal_exists(chain::operation::tag::value, active_sw->id)) { + return; + } - auto active_sons = gpo.active_sons; - string reply_str = create_primary_wallet_address(active_sons); + const chain::global_property_object &gpo = database.get_global_properties(); - std::stringstream active_pw_ss(reply_str); + auto active_sons = gpo.active_sons; + string reply_str = create_primary_wallet_address(active_sons); - ilog("### process_primary_wallet: ${reply}", ("reply", reply_str)); + std::stringstream active_pw_ss(reply_str); - boost::property_tree::ptree active_pw_pt; - boost::property_tree::read_json(active_pw_ss, active_pw_pt); - if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { - if (!plugin.can_son_participate(chain::operation::tag::value, active_sw->id)) { - return; - } + ilog("### process_primary_wallet: ${reply}", ("reply", reply_str)); - proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; - uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + boost::property_tree::ptree active_pw_pt; + boost::property_tree::read_json(active_pw_ss, active_pw_pt); + if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { + if (!plugin.can_son_participate(chain::operation::tag::value, active_sw->id)) { + return; + } - std::stringstream res; - boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - son_wallet_update_operation swu_op; - swu_op.payer = gpo.parameters.son_account(); - swu_op.son_wallet_id = active_sw->id; - swu_op.sidechain = sidechain_type::ethereum; - swu_op.address = res.str(); + std::stringstream res; + boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); - proposal_op.proposed_ops.emplace_back(swu_op); + son_wallet_update_operation swu_op; + swu_op.payer = gpo.parameters.son_account(); + swu_op.son_wallet_id = active_sw->id; + swu_op.sidechain = sidechain_type::ethereum; + swu_op.address = res.str(); - const auto &prev_sw = std::next(active_sw); - if (prev_sw != swi.rend()) { - 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()) { - sidechain_transaction_create_operation stc_op; - stc_op.payer = gpo.parameters.son_account(); - stc_op.object_id = prev_sw->id; - stc_op.sidechain = sidechain; - stc_op.transaction = tx_str; - stc_op.signers = prev_sw->sons; - proposal_op.proposed_ops.emplace_back(stc_op); - } - } + proposal_op.proposed_ops.emplace_back(swu_op); - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); - try { - trx.validate(); - database.push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - plugin.log_son_proposal_retry(chain::operation::tag::value, active_sw->id); - } catch (fc::exception &e) { - elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); - return; - } - } - } - } + const auto &prev_sw = std::next(active_sw); + if (prev_sw != swi.rend()) { + 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()) { + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = prev_sw->id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = prev_sw->sons; + proposal_op.proposed_ops.emplace_back(stc_op); + } + } + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + plugin.log_son_proposal_retry(chain::operation::tag::value, active_sw->id); + } catch (fc::exception &e) { + elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); + return; + } + } + } + } } void sidechain_net_handler_eth::process_sidechain_addresses() { -/* - const chain::global_property_object &gpo = database.get_global_properties(); - std::vector> pubkeys; - for (auto &son : gpo.active_sons) { - std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); - auto pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); - pubkeys.push_back(std::make_pair(pubkey, son.weight)); - } + /* + const chain::global_property_object &gpo = database.get_global_properties(); + std::vector> pubkeys; + for (auto &son : gpo.active_sons) { + std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); + auto pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); + pubkeys.push_back(std::make_pair(pubkey, son.weight)); + } - const auto &sidechain_addresses_idx = database.get_index_type(); - const auto &sidechain_addresses_by_sidechain_idx = sidechain_addresses_idx.indices().get(); - const auto &sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain); - std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second, - [&](const sidechain_address_object &sao) { - bool retval = true; - try { - if (sao.expires == time_point_sec::maximum()) { - auto usr_pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(sao.deposit_public_key))); + const auto &sidechain_addresses_idx = database.get_index_type(); + const auto &sidechain_addresses_by_sidechain_idx = sidechain_addresses_idx.indices().get(); + const auto &sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain); + std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second, + [&](const sidechain_address_object &sao) { + bool retval = true; + try { + 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); - std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) + - "\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }"; + btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys, network_type); + std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) + + "\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }"; - if (addr.get_address() != sao.deposit_address) { - sidechain_address_update_operation op; - op.payer = plugin.get_current_son_object().son_account; - op.sidechain_address_id = sao.id; - op.sidechain_address_account = sao.sidechain_address_account; - op.sidechain = sao.sidechain; - op.deposit_public_key = sao.deposit_public_key; - op.deposit_address = addr.get_address(); - op.deposit_address_data = address_data; - op.withdraw_public_key = sao.withdraw_public_key; - op.withdraw_address = sao.withdraw_address; + if (addr.get_address() != sao.deposit_address) { + sidechain_address_update_operation op; + op.payer = plugin.get_current_son_object().son_account; + op.sidechain_address_id = sao.id; + op.sidechain_address_account = sao.sidechain_address_account; + op.sidechain = sao.sidechain; + op.deposit_public_key = sao.deposit_public_key; + op.deposit_address = addr.get_address(); + op.deposit_address_data = address_data; + op.withdraw_public_key = sao.withdraw_public_key; + op.withdraw_address = sao.withdraw_address; - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); - try { - trx.validate(); - database.push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - retval = true; - } catch (fc::exception &e) { - elog("Sending transaction for sidechain address update operation failed with exception ${e}", ("e", e.what())); - retval = false; - } - } - } - } catch (fc::exception &e) { - retval = false; - } - return retval; - }); -*/ + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + retval = true; + } catch (fc::exception &e) { + elog("Sending transaction for sidechain address update operation failed with exception ${e}", ("e", e.what())); + retval = false; + } + } + } + } catch (fc::exception &e) { + retval = false; + } + return retval; + }); + */ } bool sidechain_net_handler_eth::process_deposit(const son_wallet_deposit_object &swdo) { - ilog("### process_deposit:"); + ilog("### process_deposit:"); - if (proposal_exists(chain::operation::tag::value, swdo.id)) { - return false; - } + if (proposal_exists(chain::operation::tag::value, swdo.id)) { + return false; + } - std::string tx_str = create_deposit_transaction(swdo); + std::string tx_str = create_deposit_transaction(swdo); - if (!tx_str.empty()) { - const chain::global_property_object &gpo = database.get_global_properties(); + if (!tx_str.empty()) { + const chain::global_property_object &gpo = database.get_global_properties(); - proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; - uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - son_wallet_deposit_process_operation swdp_op; - swdp_op.payer = gpo.parameters.son_account(); - swdp_op.son_wallet_deposit_id = swdo.id; - proposal_op.proposed_ops.emplace_back(swdp_op); + son_wallet_deposit_process_operation swdp_op; + swdp_op.payer = gpo.parameters.son_account(); + swdp_op.son_wallet_deposit_id = swdo.id; + proposal_op.proposed_ops.emplace_back(swdp_op); - sidechain_transaction_create_operation stc_op; - stc_op.payer = gpo.parameters.son_account(); - stc_op.object_id = swdo.id; - stc_op.sidechain = sidechain; - stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons; - proposal_op.proposed_ops.emplace_back(stc_op); + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = swdo.id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = gpo.active_sons; + proposal_op.proposed_ops.emplace_back(stc_op); - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); - try { - trx.validate(); - database.push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - return true; - } catch (fc::exception &e) { - elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what())); - return false; - } - } - return false; + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + return true; + } catch (fc::exception &e) { + elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + return false; + } + } + return false; } bool sidechain_net_handler_eth::process_withdrawal(const son_wallet_withdraw_object &swwo) { - ilog("### process_withdrawal:"); + ilog("### process_withdrawal:"); - if (proposal_exists(chain::operation::tag::value, swwo.id)) { - return false; - } + if (proposal_exists(chain::operation::tag::value, swwo.id)) { + return false; + } - std::string tx_str = create_withdrawal_transaction(swwo); + std::string tx_str = create_withdrawal_transaction(swwo); - if (!tx_str.empty()) { - const chain::global_property_object &gpo = database.get_global_properties(); + if (!tx_str.empty()) { + const chain::global_property_object &gpo = database.get_global_properties(); - proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; - uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - son_wallet_withdraw_process_operation swwp_op; - swwp_op.payer = gpo.parameters.son_account(); - swwp_op.son_wallet_withdraw_id = swwo.id; - proposal_op.proposed_ops.emplace_back(swwp_op); + son_wallet_withdraw_process_operation swwp_op; + swwp_op.payer = gpo.parameters.son_account(); + swwp_op.son_wallet_withdraw_id = swwo.id; + proposal_op.proposed_ops.emplace_back(swwp_op); - sidechain_transaction_create_operation stc_op; - stc_op.payer = gpo.parameters.son_account(); - stc_op.object_id = swwo.id; - stc_op.sidechain = sidechain; - stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons; - proposal_op.proposed_ops.emplace_back(stc_op); + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = swwo.id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = gpo.active_sons; + proposal_op.proposed_ops.emplace_back(stc_op); - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); - try { - trx.validate(); - database.push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - return true; - } catch (fc::exception &e) { - elog("Sending proposal for withdraw sidechain transaction create operation failed with exception ${e}", ("e", e.what())); - return false; - } - } - return false; + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + return true; + } catch (fc::exception &e) { + elog("Sending proposal for withdraw sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + return false; + } + } + return false; } std::string sidechain_net_handler_eth::process_sidechain_transaction(const sidechain_transaction_object &sto) { - ilog("### process_sidechain_transaction: "); - return sign_transaction(sto); + ilog("### process_sidechain_transaction: "); + return sign_transaction(sto); } std::string sidechain_net_handler_eth::send_sidechain_transaction(const sidechain_transaction_object &sto) { - ilog("### send_sidechain_transaction: "); - return send_transaction(sto); + ilog("### send_sidechain_transaction: "); + return send_transaction(sto); } bool sidechain_net_handler_eth::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) { - return false; + return false; } std::vector sidechain_net_handler_eth::parse_hex(const std::string &str) { - std::vector vec(str.size() / 2); - fc::from_hex(str, vec.data(), vec.size()); - return vec; + std::vector vec(str.size() / 2); + fc::from_hex(str, vec.data(), vec.size()); + return vec; } std::string sidechain_net_handler_eth::create_primary_wallet_address(const std::vector &son_pubkeys) { - std::stringstream ss; + std::stringstream ss; - ss << "{\"result\": {\"address\": \"" << eth_client->safe_account_addr << "\"" << "}, "; - ss << "\"onwers\": ["; - for (auto &owner : eth_client->owners){ - ss << "\"" << owner << "\","; - } - ss.seekp(-1, std::ios_base::end); - ss << "], keys: ["; + ss << "{\"result\": {\"address\": \"" << eth_client->safe_account_addr << "\"" << "}, "; + ss << "\"onwers\": ["; + for (auto &owner : eth_client->owners){ + ss << "\"" << owner << "\","; + } + ss.seekp(-1, std::ios_base::end); + ss << "], keys: ["; - for (auto &son : son_pubkeys) { - std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); - ss << "\"" << pub_key_str << "\","; - } - ss.seekp(-1, std::ios_base::end); - ss << "], "; + for (auto &son : son_pubkeys) { + std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); + ss << "\"" << pub_key_str << "\","; + } + ss.seekp(-1, std::ios_base::end); + ss << "], "; - ss << "\"error\":null}"; + ss << "\"error\":null}"; - std::string res = ss.str(); - return res; + std::string res = ss.str(); + return res; } std::string sidechain_net_handler_eth::create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address) { - return "";//create_transaction(inputs, outputs, prev_redeem_script); + return "";//create_transaction(inputs, outputs, prev_redeem_script); } std::string sidechain_net_handler_eth::create_deposit_transaction(const son_wallet_deposit_object &swdo) { - return "";//create_transaction(inputs, outputs, redeem_script); + return "";//create_transaction(inputs, outputs, redeem_script); } std::string sidechain_net_handler_eth::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { - return "";//create_transaction(inputs, outputs, redeem_script); + return "";//create_transaction(inputs, outputs, redeem_script); } std::string sidechain_net_handler_eth::create_transaction() { - std::string tx_raw;// = write_transaction_data(hex_tx, in_amounts, redeem_script); - return tx_raw; + std::string tx_raw;// = write_transaction_data(hex_tx, in_amounts, redeem_script); + return tx_raw; } std::string sidechain_net_handler_eth::sign_transaction(const sidechain_transaction_object &sto) { - ilog("### sign_transaction: "); + ilog("### sign_transaction: "); - std::stringstream ss_trx(boost::algorithm::unhex(sto.transaction)); - ethereum::signed_transaction htrx; - fc::raw::unpack(ss_trx, htrx, 1000); + std::stringstream ss_trx(boost::algorithm::unhex(sto.transaction)); + ethereum::signed_transaction htrx; + fc::raw::unpack(ss_trx, htrx, 1000); - std::string chain_id_str = eth_client->chain_id;//eth_rpc_client->get_chain_id(); - const ethereum::chain_id_type chain_id(chain_id_str); + std::string chain_id_str = eth_client->chain_id;//eth_rpc_client->get_chain_id(); + const ethereum::chain_id_type chain_id(chain_id_str); - fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))); - signature_type st = htrx.sign(*privkey, chain_id); + fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))); + signature_type st = htrx.sign(*privkey, chain_id); - std::stringstream ss_st; - fc::raw::pack(ss_st, st, 1000); - std::string st_str = boost::algorithm::hex(ss_st.str()); - return st_str; + std::stringstream ss_st; + fc::raw::pack(ss_st, st, 1000); + std::string st_str = boost::algorithm::hex(ss_st.str()); + return st_str; } std::string sidechain_net_handler_eth::send_transaction(const sidechain_transaction_object &sto) { - std::string res;// = eth_client->sendrawtransaction(final_tx_hex); + std::string res;// = eth_client->sendrawtransaction(final_tx_hex); - return res; + return res; } void sidechain_net_handler_eth::handle_event(const std::string &event_data) { } std::vector sidechain_net_handler_eth::extract_info_from_block(const std::string &_block) { - std::stringstream ss(_block); - boost::property_tree::ptree block; - boost::property_tree::read_json(ss, block); + std::stringstream ss(_block); + boost::property_tree::ptree block; + boost::property_tree::read_json(ss, block); - std::vector result; + std::vector result; - return result; + return result; } void sidechain_net_handler_eth::on_changed_objects(const vector &ids, const flat_set &accounts) { - ilog("### on_changed_objects: "); + ilog("### on_changed_objects: "); - fc::time_point now = fc::time_point::now(); - int64_t time_to_next_changed_objects_processing = 5000; + fc::time_point now = fc::time_point::now(); + int64_t time_to_next_changed_objects_processing = 5000; - fc::time_point next_wakeup(now + fc::microseconds(time_to_next_changed_objects_processing)); + fc::time_point next_wakeup(now + fc::microseconds(time_to_next_changed_objects_processing)); - on_changed_objects_task = fc::schedule([this, ids, accounts] { - on_changed_objects_cb(ids, accounts); - }, - next_wakeup, "SON Processing"); + on_changed_objects_task = fc::schedule([this, ids, accounts] { + on_changed_objects_cb(ids, accounts); + }, + next_wakeup, "SON Processing"); } void sidechain_net_handler_eth::on_changed_objects_cb(const vector &ids, const flat_set &accounts) { } fc::ecc::public_key_data sidechain_net_handler_eth::create_public_key_data(const std::vector &public_key) { - FC_ASSERT(public_key.size() == 33); - fc::ecc::public_key_data key; - for (size_t i = 0; i < 33; i++) { - key.at(i) = public_key[i]; - } - return key; + FC_ASSERT(public_key.size() == 33); + fc::ecc::public_key_data key; + for (size_t i = 0; i < 33; i++) { + key.at(i) = public_key[i]; + } + return key; } // ============================================================================= -- 2.45.2 From 3a142d9fd2fdfd02182dfa5b76747fecf1c896a1 Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Wed, 15 Jun 2022 10:17:15 -0300 Subject: [PATCH 18/60] missing Makefile in sha3, create_safe_address --- libraries/fc | 2 +- .../sidechain_net_handler_eth.hpp | 2 +- .../sidechain_net_handler_eth.cpp | 12 ++++++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/libraries/fc b/libraries/fc index c24b2df9..10aa7e5c 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit c24b2df96d949f25ff85ca0aae5e17da111bde79 +Subproject commit 10aa7e5cfb48a606201c39d379f99dbc48a72bfe diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index 705b40b0..d95d81a2 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -148,7 +148,7 @@ namespace graphene { namespace peerplays_sidechain { static constexpr const char*const default_gas_token = "0000000000000000000000000000000000000000"; static constexpr const char*const default_refund_receiver = "0000000000000000000000000000000000000000"; - std::string create_safe_address(const std::vector owner_addresses, uint32_t threshold); + std::string create_safe_address(const std::vector& owner_addresses, uint32_t threshold); std::string build_transaction(const std::string& safe_account_addr, const std::string& value, const std::string& data, uint8_t operation, const std::string& safeTxGas, const std::string& dataGas, const std::string& gasPrice, const std::string& gasToken, const std::string& refundReceiver); private: diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index 1c333811..dc0544f9 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -66,7 +66,14 @@ namespace graphene { namespace peerplays_sidechain { return output; } - std::string eth_rpc_client::safe_transaction_encoder::create_safe_address(const std::vector owner_addresses, uint32_t threshold) { + std::string eth_rpc_client::safe_transaction_encoder::create_safe_address(const std::vector& owner_addresses, uint32_t threshold) { + //createProxyWithNonce(address,bytes,uint256) + std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("createProxyWithNonce(address,bytes,uint256)"); + FC_ASSERT("1688f0b9" == method_id); + + std::string data = "0x1688f0b9000000000000000000000000d9db270c1b5e3bd161e8c8503c55ceabee70955200000000000000000000000000000000000000000000000000000000000000604fa262bd05cdef2e3d5261787ee66d9447a4036324990e04380339bec83b4c7a0000000000000000000000000000000000000000000000000000000000000264b63e800d0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000f48f2b2d2a534e402487b3ee7c18c33aec0fe5e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC1200000000000000000000000076ce31BD03f601c3fC13732deF921c5Bac28267600000000000000000000000009EE460834498a4ee361beB819470061B7381B490000000000000000000000006AEFbd09209e1eE2e0a589d31e732F69B77713D2000000000000000000000000631e128b16f9aDCF1bB6385112B1519C917D77a7000000000000000000000000cD5C788e84220E8b8934Ea4F1dC6a12009bCc91D0000000000000000000000003627C1B31525887CB9441130C831e3588765030500000000000000000000000003A13a989AF30C92AD7ABD1E6210308A6c96f3730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + + return data; } std::string eth_rpc_client::safe_transaction_encoder::build_transaction(const std::string& safe_account_addr, const std::string& value, const std::string& data, uint8_t operation, const std::string& safeTxGas, const std::string& dataGas, const std::string& gasPrice, const std::string& gasToken, const std::string& refundReceiver){ @@ -385,7 +392,8 @@ namespace graphene { namespace peerplays_sidechain { std::string from = "0xeE52b70e8D7AB5Fe661311D47e81228EAD6B06B9"; std::string to = "0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2"; - std::string data = "0x1688f0b9000000000000000000000000d9db270c1b5e3bd161e8c8503c55ceabee70955200000000000000000000000000000000000000000000000000000000000000604fa262bd05cdef2e3d5261787ee66d9447a4036324990e04380339bec83b4c7a0000000000000000000000000000000000000000000000000000000000000264b63e800d0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000f48f2b2d2a534e402487b3ee7c18c33aec0fe5e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC1200000000000000000000000076ce31BD03f601c3fC13732deF921c5Bac28267600000000000000000000000009EE460834498a4ee361beB819470061B7381B490000000000000000000000006AEFbd09209e1eE2e0a589d31e732F69B77713D2000000000000000000000000631e128b16f9aDCF1bB6385112B1519C917D77a7000000000000000000000000cD5C788e84220E8b8934Ea4F1dC6a12009bCc91D0000000000000000000000003627C1B31525887CB9441130C831e3588765030500000000000000000000000003A13a989AF30C92AD7ABD1E6210308A6c96f3730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + std::string data = m_safe_transaction_encoder.create_safe_address(owner_addresses, nrequired); + return eth_sendTransaction(from, to, data); } -- 2.45.2 From cd235455ccb82c34239420d2f37a691c53ef09ab Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Thu, 16 Jun 2022 09:56:42 +0300 Subject: [PATCH 19/60] Fix linking sha3 library --- libraries/fc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fc b/libraries/fc index 10aa7e5c..7d9ffc63 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 10aa7e5cfb48a606201c39d379f99dbc48a72bfe +Subproject commit 7d9ffc63d230fca73e93eaaa96969633294f4fe3 -- 2.45.2 From a2c0793c488cfb1c553d5a9cf612960936ab4052 Mon Sep 17 00:00:00 2001 From: Pavel Baykov Date: Mon, 20 Jun 2022 09:45:50 -0300 Subject: [PATCH 20/60] big multiprecision values and serialize an Ethereum transaction for RPC --- .../sidechain_net_handler_eth.hpp | 33 +++++++++++++++++++ .../sidechain_net_handler_eth.cpp | 6 ++++ 2 files changed, 39 insertions(+) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp index d95d81a2..7b9427cb 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp @@ -19,6 +19,16 @@ #include +#include + +using namespace boost::multiprecision::literals; +using u256 = boost::multiprecision::number>; +using s256 = boost::multiprecision::number>; +u256 constexpr Invalid256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_cppui256; +using byte = uint8_t; +using bytes = std::vector; + + namespace graphene { namespace peerplays_sidechain { typedef websocketpp::client client; @@ -124,6 +134,29 @@ namespace graphene { namespace peerplays_sidechain { std::vector owners; std::string safe_account_addr; private: + /// Encodes an Ethereum transaction for exporting in JSON + class Transaction + { + public: + /// JSON serialization + std::string serialize(const std::string& from, const std::string& to, const std::string& tx_id, u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce = Invalid256); + protected: + /// Type of transaction. + enum Type + { + NullTransaction, ///< Null transaction. + ContractCreation, ///< Transaction to create contracts - receiveAddress() is ignored. + MessageCall ///< Transaction to invoke a message call - receiveAddress() is used. + }; + + Type m_type = NullTransaction; ///< Is this a contract-creation transaction or a message-call transaction? + u256 m_nonce; ///< The transaction-count of the sender. + u256 m_value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. + u256 m_gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. + u256 m_gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. + bytes m_data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. + }; + class ethereum_function_call_encoder { public: enum operation_t { diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp index dc0544f9..5afa4eda 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp @@ -28,6 +28,12 @@ extern "C" { } namespace graphene { namespace peerplays_sidechain { + std::string eth_rpc_client::Transaction::serialize(const std::string& from, const std::string& to, const std::string& tx_id,u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce) { + std::string m_data_str(m_data.begin(), m_data.end()); + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"account_signTransaction\",\"params\":[{\"from\": \"%1%\", \"gas\": \"%2%\", \"gasPrice\": \"%3%\", \"input\": \"%4%\", \"nonce\": \"%5%\", \"to\": \"%6%\", \"value\": \"%7%\" }],\"id\":%8%}") % from.c_str() % m_gas.str() % m_gasPrice.str() % m_data_str % m_nonce.str() % to.c_str() % m_value.str() % tx_id.c_str()); + return req; + } + // ============================================================================= std::string eth_rpc_client::ethereum_function_call_encoder::encode_function_signature(const std::string& function_signature) { sha3_context c; -- 2.45.2 From e23ff2e5dcbc6ea95692864edd07beac3754f6fd Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Mon, 27 Jun 2022 08:43:56 +0300 Subject: [PATCH 21/60] Updated submodule --- libraries/fc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fc b/libraries/fc index 7d9ffc63..101a1714 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 7d9ffc63d230fca73e93eaaa96969633294f4fe3 +Subproject commit 101a1714de4e241b80945c4c53c36e07caae4c0b -- 2.45.2 From 03b71bb2fef116c5dabb40fe757d5fa3cfeb7071 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Mon, 27 Jun 2022 12:02:15 +0300 Subject: [PATCH 22/60] Move SHA3IUF from fc repo --- .gitmodules | 3 +++ libraries/CMakeLists.txt | 1 + libraries/fc | 2 +- .../peerplays_sidechain/CMakeLists.txt | 8 +++--- libraries/vendor/CMakeLists.txt | 1 + libraries/vendor/SHA3IUF/CMakeLists.txt | 26 +++++++++++++++++++ libraries/vendor/SHA3IUF/SHA3IUF | 1 + 7 files changed, 38 insertions(+), 4 deletions(-) create mode 100755 libraries/vendor/CMakeLists.txt create mode 100755 libraries/vendor/SHA3IUF/CMakeLists.txt create mode 160000 libraries/vendor/SHA3IUF/SHA3IUF diff --git a/.gitmodules b/.gitmodules index e535465c..c08da2e2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ url = https://gitlab.com/PBSA/tools-libs/peerplays-fc.git branch = latest-fc ignore = dirty +[submodule "libraries/vendor/SHA3IUF/SHA3IUF"] + path = libraries/vendor/SHA3IUF/SHA3IUF + url = https://github.com/brainhub/SHA3IUF.git diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index cf2355f1..dfe3d397 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory( vendor ) add_subdirectory( app ) add_subdirectory( chain ) add_subdirectory( db ) diff --git a/libraries/fc b/libraries/fc index 101a1714..e7369949 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 101a1714de4e241b80945c4c53c36e07caae4c0b +Subproject commit e7369949bea26f3201d8442ba78286a88df74762 diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index 57a91935..44c0a8e3 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -39,9 +39,11 @@ endif() unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS) unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE) -target_link_libraries( peerplays_sidechain PRIVATE curl graphene_plugin zmq ) -target_include_directories( peerplays_sidechain - PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) +target_link_directories( peerplays_sidechain PUBLIC ${SHA3IUF_link_dirs} ) +target_link_libraries( peerplays_sidechain PRIVATE curl graphene_plugin zmq ${SHA3IUF_libraries} ) +target_include_directories( peerplays_sidechain PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${SHA3IUF_include_dirs}" ) install( TARGETS peerplays_sidechain diff --git a/libraries/vendor/CMakeLists.txt b/libraries/vendor/CMakeLists.txt new file mode 100755 index 00000000..c423bd66 --- /dev/null +++ b/libraries/vendor/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory( SHA3IUF ) \ No newline at end of file diff --git a/libraries/vendor/SHA3IUF/CMakeLists.txt b/libraries/vendor/SHA3IUF/CMakeLists.txt new file mode 100755 index 00000000..0666d7ed --- /dev/null +++ b/libraries/vendor/SHA3IUF/CMakeLists.txt @@ -0,0 +1,26 @@ +PROJECT( SHA3IUF ) + +include(ExternalProject) + +ExternalProject_Add(project_SHA3IUF + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF + CONFIGURE_COMMAND cp -R ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF/. ${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build + BUILD_COMMAND make + INSTALL_COMMAND true + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX} + LOG_BUILD ON +) + +ExternalProject_Get_Property(project_SHA3IUF binary_dir) +add_library(SHA3IUF STATIC IMPORTED) +message(STATUS "Setting up SHA3IUF to ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX}") +set_property(TARGET SHA3IUF PROPERTY IMPORTED_LOCATION ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX}) +set_property(TARGET SHA3IUF PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF) + +add_dependencies(SHA3IUF project_SHA3IUF) +install( FILES ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION lib ) + +set(SHA3IUF_libraries sha3 CACHE INTERNAL "") +set(SHA3IUF_include_dirs "${CMAKE_CURRENT_LIST_DIR}/SHA3IUF" CACHE INTERNAL "") +set(SHA3IUF_link_dirs "${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build" CACHE INTERNAL "") \ No newline at end of file diff --git a/libraries/vendor/SHA3IUF/SHA3IUF b/libraries/vendor/SHA3IUF/SHA3IUF new file mode 160000 index 00000000..fc850475 --- /dev/null +++ b/libraries/vendor/SHA3IUF/SHA3IUF @@ -0,0 +1 @@ +Subproject commit fc8504750a5c2174a1874094dd05e6a0d8797753 -- 2.45.2 From 7689d5adc0e389d3e74cef4869542bd4302d6b54 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Tue, 28 Jun 2022 17:52:11 +0200 Subject: [PATCH 23/60] SHA3IUF as git submodule --- .gitmodules | 5 ++-- .../peerplays_sidechain/CMakeLists.txt | 6 ++--- ...hpp => sidechain_net_handler_ethereum.hpp} | 0 ...cpp => sidechain_net_handler_ethereum.cpp} | 2 +- .../sidechain_net_manager.cpp | 4 +-- libraries/vendor/CMakeLists.txt | 27 ++++++++++++++++++- libraries/vendor/{SHA3IUF => }/SHA3IUF | 0 libraries/vendor/SHA3IUF/CMakeLists.txt | 26 ------------------ 8 files changed, 35 insertions(+), 35 deletions(-) rename libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/{sidechain_net_handler_eth.hpp => sidechain_net_handler_ethereum.hpp} (100%) rename libraries/plugins/peerplays_sidechain/{sidechain_net_handler_eth.cpp => sidechain_net_handler_ethereum.cpp} (99%) rename libraries/vendor/{SHA3IUF => }/SHA3IUF (100%) delete mode 100755 libraries/vendor/SHA3IUF/CMakeLists.txt diff --git a/.gitmodules b/.gitmodules index c08da2e2..9e00a2cb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,6 +7,7 @@ url = https://gitlab.com/PBSA/tools-libs/peerplays-fc.git branch = latest-fc ignore = dirty -[submodule "libraries/vendor/SHA3IUF/SHA3IUF"] - path = libraries/vendor/SHA3IUF/SHA3IUF +[submodule "libraries/vendor/SHA3IUF"] + path = libraries/vendor/SHA3IUF url = https://github.com/brainhub/SHA3IUF.git + branch = master diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index 44c0a8e3..6546b031 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -6,7 +6,7 @@ add_library( peerplays_sidechain sidechain_net_manager.cpp sidechain_net_handler.cpp sidechain_net_handler_bitcoin.cpp - sidechain_net_handler_eth.cpp + sidechain_net_handler_ethereum.cpp sidechain_net_handler_hive.cpp sidechain_net_handler_peerplays.cpp bitcoin/bech32.cpp @@ -18,12 +18,12 @@ add_library( peerplays_sidechain bitcoin/sign_bitcoin_transaction.cpp common/rpc_client.cpp common/utils.cpp + ethereum/transaction.cpp + ethereum/types.cpp hive/asset.cpp hive/operations.cpp hive/transaction.cpp hive/types.cpp - ethereum/transaction.cpp - ethereum/types.cpp ) if (ENABLE_DEV_FEATURES) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp similarity index 100% rename from libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_eth.hpp rename to libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp similarity index 99% rename from libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp rename to libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 5afa4eda..cf830a7c 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_eth.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp index a5c52920..adb9196d 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include @@ -33,7 +33,7 @@ bool sidechain_net_manager::create_handler(sidechain_type sidechain, const boost break; } case sidechain_type::ethereum: { - std::unique_ptr h = std::unique_ptr(new sidechain_net_handler_eth(plugin, options)); + std::unique_ptr h = std::unique_ptr(new sidechain_net_handler_ethereum(plugin, options)); net_handlers.push_back(std::move(h)); ret_val = true; break; diff --git a/libraries/vendor/CMakeLists.txt b/libraries/vendor/CMakeLists.txt index c423bd66..6047e95e 100755 --- a/libraries/vendor/CMakeLists.txt +++ b/libraries/vendor/CMakeLists.txt @@ -1 +1,26 @@ -add_subdirectory( SHA3IUF ) \ No newline at end of file +PROJECT( SHA3IUF ) + +include(ExternalProject) + +ExternalProject_Add(project_SHA3IUF + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF + CONFIGURE_COMMAND cp -R ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF/. ${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build + BUILD_COMMAND make + INSTALL_COMMAND true + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX} + LOG_BUILD ON +) + +ExternalProject_Get_Property(project_SHA3IUF binary_dir) +add_library(SHA3IUF STATIC IMPORTED) +message(STATUS "Setting up SHA3IUF to ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX}") +set_property(TARGET SHA3IUF PROPERTY IMPORTED_LOCATION ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX}) +set_property(TARGET SHA3IUF PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF) + +add_dependencies(SHA3IUF project_SHA3IUF) +install( FILES ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION lib ) + +set(SHA3IUF_libraries sha3 CACHE INTERNAL "") +set(SHA3IUF_include_dirs "${CMAKE_CURRENT_LIST_DIR}/SHA3IUF" CACHE INTERNAL "") +set(SHA3IUF_link_dirs "${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build" CACHE INTERNAL "") diff --git a/libraries/vendor/SHA3IUF/SHA3IUF b/libraries/vendor/SHA3IUF similarity index 100% rename from libraries/vendor/SHA3IUF/SHA3IUF rename to libraries/vendor/SHA3IUF diff --git a/libraries/vendor/SHA3IUF/CMakeLists.txt b/libraries/vendor/SHA3IUF/CMakeLists.txt deleted file mode 100755 index 0666d7ed..00000000 --- a/libraries/vendor/SHA3IUF/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -PROJECT( SHA3IUF ) - -include(ExternalProject) - -ExternalProject_Add(project_SHA3IUF - PREFIX ${CMAKE_CURRENT_BINARY_DIR} - SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF - CONFIGURE_COMMAND cp -R ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF/. ${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build - BUILD_COMMAND make - INSTALL_COMMAND true - BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX} - LOG_BUILD ON -) - -ExternalProject_Get_Property(project_SHA3IUF binary_dir) -add_library(SHA3IUF STATIC IMPORTED) -message(STATUS "Setting up SHA3IUF to ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX}") -set_property(TARGET SHA3IUF PROPERTY IMPORTED_LOCATION ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX}) -set_property(TARGET SHA3IUF PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF) - -add_dependencies(SHA3IUF project_SHA3IUF) -install( FILES ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION lib ) - -set(SHA3IUF_libraries sha3 CACHE INTERNAL "") -set(SHA3IUF_include_dirs "${CMAKE_CURRENT_LIST_DIR}/SHA3IUF" CACHE INTERNAL "") -set(SHA3IUF_link_dirs "${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build" CACHE INTERNAL "") \ No newline at end of file -- 2.45.2 From cfaf31e7052c46141ca762bcd2c778eb7d1549c2 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Tue, 28 Jun 2022 20:39:00 +0200 Subject: [PATCH 24/60] Code formatting --- .../ethereum/operations.hpp | 2 +- .../ethereum/transaction.hpp | 6 +- .../sidechain_net_handler_ethereum.hpp | 399 +++-- .../peerplays_sidechain_plugin.cpp | 4 +- .../sidechain_net_handler_ethereum.cpp | 1366 ++++++++--------- 5 files changed, 887 insertions(+), 890 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp index 586d31dd..e178b56d 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp @@ -57,7 +57,7 @@ typedef fc::static_variant< delegate_vesting_shares_operation> ethereum_operation; -}}} // namespace graphene::peerplays_sidechain::hive +}}} // namespace graphene::peerplays_sidechain::ethereum namespace fc { diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp index 61fc39c6..ae154a36 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp @@ -11,7 +11,7 @@ #include namespace graphene { namespace peerplays_sidechain { namespace ethereum { -typedef fc::ecc::private_key private_key_type; +typedef fc::ecc::private_key private_key_type; typedef fc::sha256 chain_id_type; class transaction { @@ -29,7 +29,7 @@ public: void set_expiration(fc::time_point_sec expiration_time); void set_reference_block(const block_id_type &reference_block); -/* + /* /// Serialises this transaction to an RLPStream. /// @throws TransactionIsUnsigned if including signature was requested but it was not initialized void streamRLP(RLPStream& _s, IncludeSignature _sig = WithSignature, bool _forEip155hash = false) const; @@ -76,7 +76,7 @@ public: void clear(); }; -}}} // namespace graphene::peerplays_sidechain::ethereum +}}} // namespace graphene::peerplays_sidechain::ethereum FC_REFLECT(graphene::peerplays_sidechain::ethereum::transaction, (ref_block_num)(ref_block_prefix)(expiration)(operations)(extensions)) 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 7b9427cb..3bef8610 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 @@ -14,257 +14,256 @@ #include #include -#include #include +#include #include #include using namespace boost::multiprecision::literals; -using u256 = boost::multiprecision::number>; -using s256 = boost::multiprecision::number>; +using u256 = boost::multiprecision::number>; +using s256 = boost::multiprecision::number>; u256 constexpr Invalid256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_cppui256; using byte = uint8_t; using bytes = std::vector; - namespace graphene { namespace peerplays_sidechain { - typedef websocketpp::client client; +typedef websocketpp::client client; - using websocketpp::lib::placeholders::_1; - using websocketpp::lib::placeholders::_2; - using websocketpp::lib::bind; +using websocketpp::lib::bind; +using websocketpp::lib::placeholders::_1; +using websocketpp::lib::placeholders::_2; - // pull out the type of messages sent by our config - typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr; - typedef websocketpp::lib::shared_ptr context_ptr; - typedef client::connection_ptr connection_ptr; +// pull out the type of messages sent by our config +typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr; +typedef websocketpp::lib::shared_ptr context_ptr; +typedef client::connection_ptr connection_ptr; - class eth_rpc_client { - public: - typedef eth_rpc_client type; +class eth_rpc_client { +public: + typedef eth_rpc_client type; - enum req_t { - ETH_CHAIN_ID, - ETH_GET_TRANSACTION_RECEIPT, - ETH_CALL, - ETH_SEND_TRANSACTION, - ETH_SEND_RAW_TRANSACTION, - ETH_GET_CODE, - ETH_GET_BALANCE, - ETH_SIGN, - ETH_COINBASE, - GET_LIST_OWNERS, - ADD_OWNER, - REMOVE_OWNER - }; + enum req_t { + ETH_CHAIN_ID, + ETH_GET_TRANSACTION_RECEIPT, + ETH_CALL, + ETH_SEND_TRANSACTION, + ETH_SEND_RAW_TRANSACTION, + ETH_GET_CODE, + ETH_GET_BALANCE, + ETH_SIGN, + ETH_COINBASE, + GET_LIST_OWNERS, + ADD_OWNER, + REMOVE_OWNER + }; - enum class multi_type { - script, - address - }; - struct multi_params { - multi_params(multi_type _type, const std::string &_address_or_script, const std::string &_label = "") : - type{_type}, - address_or_script{_address_or_script}, - label{_label} { - } + enum class multi_type { + script, + address + }; + struct multi_params { + multi_params(multi_type _type, const std::string &_address_or_script, const std::string &_label = "") : + type{_type}, + address_or_script{_address_or_script}, + label{_label} { + } - multi_type type; - std::string address_or_script; - std::string label; - }; + multi_type type; + std::string address_or_script; + std::string label; + }; - eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); + eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); - void start(); - void stop(); - void on_socket_init(websocketpp::connection_hdl); - void on_fail(websocketpp::connection_hdl hdl); - void on_open(websocketpp::connection_hdl hdl); - void on_message(websocketpp::connection_hdl hdl, message_ptr msg); - void on_close(websocketpp::connection_hdl); + void start(); + void stop(); + void on_socket_init(websocketpp::connection_hdl); + void on_fail(websocketpp::connection_hdl hdl); + void on_open(websocketpp::connection_hdl hdl); + void on_message(websocketpp::connection_hdl hdl, message_ptr msg); + void on_close(websocketpp::connection_hdl); - uint64_t get_chain_id(); - uint64_t eth_getTransactionReceipt(const std::string& tx_id); - uint64_t eth_call(const std::string& to, const std::string& data); - uint64_t eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data); - uint64_t eth_sendRawTransaction(const std::string& params); - uint64_t eth_getCode(const std::string& addr); - uint64_t eth_getBalance(const std::string& addr); - uint64_t eth_sign(const string& addr, const string& message); - uint64_t eth_coinbase(); + uint64_t get_chain_id(); + uint64_t eth_getTransactionReceipt(const std::string &tx_id); + uint64_t eth_call(const std::string &to, const std::string &data); + uint64_t eth_sendTransaction(const std::string &from, const std::string &to, const std::string &data); + uint64_t eth_sendRawTransaction(const std::string ¶ms); + uint64_t eth_getCode(const std::string &addr); + uint64_t eth_getBalance(const std::string &addr); + uint64_t eth_sign(const string &addr, const string &message); + uint64_t eth_coinbase(); - uint64_t get_list_owners(const std::string& safe_account); - uint64_t add_owner(const std::string& addr ); - uint64_t remove_owner(const std::string& addr, uint32_t threshold); + uint64_t get_list_owners(const std::string &safe_account); + uint64_t add_owner(const std::string &addr); + uint64_t remove_owner(const std::string &addr, uint32_t threshold); - std::string addmultisigaddress(const uint32_t nrequired, const std::vector public_keys); - std::string combinepsbt(const vector &psbts); + std::string addmultisigaddress(const uint32_t nrequired, const std::vector public_keys); + std::string combinepsbt(const vector &psbts); - uint64_t createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key); + uint64_t createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key); - std::string createpsbt(); - std::string createrawtransaction(); - std::string createwallet(const std::string &wallet_name); - std::string decodepsbt(std::string const &tx_psbt); - std::string decoderawtransaction(std::string const &tx_hex); - std::string encryptwallet(const std::string &passphrase); - uint64_t estimatesmartfee(uint16_t conf_target = 128); - std::string finalizepsbt(std::string const &tx_psbt); - std::string getaddressinfo(const std::string &address); - 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(); - std::string gettransaction(const std::string &txid, const bool include_watch_only = false); - std::string getblockchaininfo(); - void importaddress(const std::string &address_or_script, const std::string &label = "", const bool rescan = true, const bool p2sh = false); - void importmulti(const std::vector &address_or_script_array, const bool rescan = true); - std::string loadwallet(const std::string &filename); - std::string sendrawtransaction(const std::string &tx_hex); - std::string signrawtransactionwithwallet(const std::string &tx_hash); - std::string unloadwallet(const std::string &filename); - std::string walletlock(); - std::string walletprocesspsbt(std::string const &tx_psbt); - bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); + std::string createpsbt(); + std::string createrawtransaction(); + std::string createwallet(const std::string &wallet_name); + std::string decodepsbt(std::string const &tx_psbt); + std::string decoderawtransaction(std::string const &tx_hex); + std::string encryptwallet(const std::string &passphrase); + uint64_t estimatesmartfee(uint16_t conf_target = 128); + std::string finalizepsbt(std::string const &tx_psbt); + std::string getaddressinfo(const std::string &address); + 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(); + std::string gettransaction(const std::string &txid, const bool include_watch_only = false); + std::string getblockchaininfo(); + void importaddress(const std::string &address_or_script, const std::string &label = "", const bool rescan = true, const bool p2sh = false); + void importmulti(const std::vector &address_or_script_array, const bool rescan = true); + std::string loadwallet(const std::string &filename); + std::string sendrawtransaction(const std::string &tx_hex); + std::string signrawtransactionwithwallet(const std::string &tx_hash); + std::string unloadwallet(const std::string &filename); + std::string walletlock(); + std::string walletprocesspsbt(std::string const &tx_psbt); + bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); - std::string chain_id;//256 bit value - std::vector owners; - std::string safe_account_addr; - private: - /// Encodes an Ethereum transaction for exporting in JSON - class Transaction - { - public: - /// JSON serialization - std::string serialize(const std::string& from, const std::string& to, const std::string& tx_id, u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce = Invalid256); - protected: - /// Type of transaction. - enum Type - { - NullTransaction, ///< Null transaction. - ContractCreation, ///< Transaction to create contracts - receiveAddress() is ignored. - MessageCall ///< Transaction to invoke a message call - receiveAddress() is used. - }; + std::string chain_id; //256 bit value + std::vector owners; + std::string safe_account_addr; - Type m_type = NullTransaction; ///< Is this a contract-creation transaction or a message-call transaction? - u256 m_nonce; ///< The transaction-count of the sender. - u256 m_value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. - u256 m_gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. - u256 m_gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. - bytes m_data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. - }; +private: + /// Encodes an Ethereum transaction for exporting in JSON + class Transaction { + public: + /// JSON serialization + std::string serialize(const std::string &from, const std::string &to, const std::string &tx_id, u256 const &_value, u256 const &_gasPrice, u256 const &_gas, bytes const &_data, u256 const &_nonce = Invalid256); - class ethereum_function_call_encoder { - public: - enum operation_t { - OPERATION_CALL, - OPERATION_DELEGATE_CALL - }; + protected: + /// Type of transaction. + enum Type { + NullTransaction, ///< Null transaction. + ContractCreation, ///< Transaction to create contracts - receiveAddress() is ignored. + MessageCall ///< Transaction to invoke a message call - receiveAddress() is used. + }; - static constexpr const char*const default_prev_addr = "0000000000000000000000000000000000000001"; + Type m_type = NullTransaction; ///< Is this a contract-creation transaction or a message-call transaction? + u256 m_nonce; ///< The transaction-count of the sender. + u256 m_value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. + u256 m_gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. + u256 m_gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. + bytes m_data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. + }; - std::string encode_function_signature(const std::string& function_signature); - std::string encode_address(const std::string& addr); - std::string encode_uint256(const std::string& value); - std::string encode_uint8(uint8_t value); - std::string encode_bytes(const std::string& values); - }; + class ethereum_function_call_encoder { + public: + enum operation_t { + OPERATION_CALL, + OPERATION_DELEGATE_CALL + }; - class safe_transaction_encoder { - public: - static constexpr const char*const default_safe_tx_gas = "0"; - static constexpr const char*const default_data_gas = "0"; - static constexpr const char*const default_gas_price = "0"; - static constexpr const char*const default_gas_token = "0000000000000000000000000000000000000000"; - static constexpr const char*const default_refund_receiver = "0000000000000000000000000000000000000000"; + static constexpr const char *const default_prev_addr = "0000000000000000000000000000000000000001"; - std::string create_safe_address(const std::vector& owner_addresses, uint32_t threshold); - std::string build_transaction(const std::string& safe_account_addr, const std::string& value, const std::string& data, uint8_t operation, const std::string& safeTxGas, const std::string& dataGas, const std::string& gasPrice, const std::string& gasToken, const std::string& refundReceiver); + std::string encode_function_signature(const std::string &function_signature); + std::string encode_address(const std::string &addr); + std::string encode_uint256(const std::string &value); + std::string encode_uint8(uint8_t value); + std::string encode_bytes(const std::string &values); + }; - private: - ethereum_function_call_encoder m_ethereum_function_call_encoder; - }; + class safe_transaction_encoder { + public: + static constexpr const char *const default_safe_tx_gas = "0"; + static constexpr const char *const default_data_gas = "0"; + static constexpr const char *const default_gas_price = "0"; + static constexpr const char *const default_gas_token = "0000000000000000000000000000000000000000"; + static constexpr const char *const default_refund_receiver = "0000000000000000000000000000000000000000"; - ethereum_function_call_encoder m_ethereum_function_call_encoder; - safe_transaction_encoder m_safe_transaction_encoder; + std::string create_safe_address(const std::vector &owner_addresses, uint32_t threshold); + std::string build_transaction(const std::string &safe_account_addr, const std::string &value, const std::string &data, uint8_t operation, const std::string &safeTxGas, const std::string &dataGas, const std::string &gasPrice, const std::string &gasToken, const std::string &refundReceiver); - std::shared_ptr _thread; - std::string signature; - std::string geth_url; - uint64_t t_id; - std::string account_address; - std::string transaction_id; - uint32_t threshold; - std::unordered_map m_requests; - std::string balance; - std::string code; + private: + ethereum_function_call_encoder m_ethereum_function_call_encoder; + }; - std::string ip; - uint32_t rpc_port; - std::string user; - std::string password; - std::string wallet; - std::string wallet_password; - bool debug_rpc_calls; + ethereum_function_call_encoder m_ethereum_function_call_encoder; + safe_transaction_encoder m_safe_transaction_encoder; - fc::http::header authorization; + std::shared_ptr _thread; + std::string signature; + std::string geth_url; + uint64_t t_id; + std::string account_address; + std::string transaction_id; + uint32_t threshold; + std::unordered_map m_requests; + std::string balance; + std::string code; - client m_endpoint; - websocketpp::connection_hdl m_hdl; - }; + std::string ip; + uint32_t rpc_port; + std::string user; + std::string password; + std::string wallet; + std::string wallet_password; + bool debug_rpc_calls; - // ============================================================================= + fc::http::header authorization; - class sidechain_net_handler_eth : public sidechain_net_handler { - public: - sidechain_net_handler_eth(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options); - virtual ~sidechain_net_handler_eth(); + client m_endpoint; + websocketpp::connection_hdl m_hdl; +}; - bool process_proposal(const proposal_object &po); - void process_primary_wallet(); - void process_sidechain_addresses(); - bool process_deposit(const son_wallet_deposit_object &swdo); - bool process_withdrawal(const son_wallet_withdraw_object &swwo); - std::string process_sidechain_transaction(const sidechain_transaction_object &sto); - std::string send_sidechain_transaction(const sidechain_transaction_object &sto); - bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); +// ============================================================================= - private: - std::string url; - uint32_t rpc_port; +class sidechain_net_handler_ethereum : public sidechain_net_handler { +public: + sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options); + virtual ~sidechain_net_handler_ethereum(); - std::string rpc_user; - std::string rpc_password; - std::string wallet; - std::string wallet_password; + bool process_proposal(const proposal_object &po); + void process_primary_wallet(); + void process_sidechain_addresses(); + bool process_deposit(const son_wallet_deposit_object &swdo); + bool process_withdrawal(const son_wallet_withdraw_object &swwo); + std::string process_sidechain_transaction(const sidechain_transaction_object &sto); + std::string send_sidechain_transaction(const sidechain_transaction_object &sto); + bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); - std::unique_ptr eth_client; +private: + std::string url; + uint32_t rpc_port; - fc::future on_changed_objects_task; + std::string rpc_user; + std::string rpc_password; + std::string wallet; + std::string wallet_password; - std::mutex event_handler_mutex; - typedef std::lock_guard scoped_lock; + std::unique_ptr eth_client; - std::string create_primary_wallet_address(const std::vector &son_pubkeys); + fc::future on_changed_objects_task; - 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); - std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo); + std::mutex event_handler_mutex; + typedef std::lock_guard scoped_lock; - std::string create_transaction(); - std::string sign_transaction(const sidechain_transaction_object &sto); - std::string send_transaction(const sidechain_transaction_object &sto); + std::string create_primary_wallet_address(const std::vector &son_pubkeys); - void handle_event(const std::string &event_data); - 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); + 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); + std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo); - std::vector parse_hex(const std::string &str); - fc::ecc::public_key_data create_public_key_data(const std::vector &public_key); - }; + std::string create_transaction(); + 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); + 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); + + std::vector parse_hex(const std::string &str); + fc::ecc::public_key_data create_public_key_data(const std::vector &public_key); +}; }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 570358c7..aa63055a 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -222,8 +222,8 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt sidechain_enabled_ethereum = options.at("ethereum-sidechain-enabled").as(); config_ready_ethereum = options.count("ethereum-node-rpc-url"); - //options.count("ethereum-address") && - //options.count("ethereum-public-key") && options.count("ethereum-private-key"); + //options.count("ethereum-address") && + //options.count("ethereum-public-key") && options.count("ethereum-private-key"); if (!config_ready_ethereum) { wlog("Haven't set up Ethereum sidechain parameters"); } diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index cf830a7c..4feba5ec 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -3,8 +3,8 @@ #include #include -#include #include +#include #include #include @@ -17,8 +17,8 @@ #include #include #include -#include #include +#include #include @@ -28,491 +28,489 @@ extern "C" { } namespace graphene { namespace peerplays_sidechain { - std::string eth_rpc_client::Transaction::serialize(const std::string& from, const std::string& to, const std::string& tx_id,u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce) { - std::string m_data_str(m_data.begin(), m_data.end()); - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"account_signTransaction\",\"params\":[{\"from\": \"%1%\", \"gas\": \"%2%\", \"gasPrice\": \"%3%\", \"input\": \"%4%\", \"nonce\": \"%5%\", \"to\": \"%6%\", \"value\": \"%7%\" }],\"id\":%8%}") % from.c_str() % m_gas.str() % m_gasPrice.str() % m_data_str % m_nonce.str() % to.c_str() % m_value.str() % tx_id.c_str()); - return req; - } - - // ============================================================================= - std::string eth_rpc_client::ethereum_function_call_encoder::encode_function_signature(const std::string& function_signature) { - sha3_context c; - char *hash; - - sha3_Init256(static_cast(&c)); - sha3_SetFlags(&c, SHA3_FLAGS_KECCAK); - sha3_Update(&c, "abc", 3); - hash = (char*)sha3_Finalize(&c); - std::string output(hash); - output = output.substr(0,8); - - return output; - }; - - std::string eth_rpc_client::ethereum_function_call_encoder::encode_address(const std::string& addr) { - FC_ASSERT(40 == addr.length()); - std::string output = str(boost::format("%024u") % 0) + addr; - return output; - } - - std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint256(const std::string& value) { - FC_ASSERT(value.length() <= 64); - std::string output = std::string(64 - value.length(), '0') + value; - return output; - } - - std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint8(uint8_t value) { - std::string output = str(boost::format("%02X") % value) + std::string(62, '0'); - return output; - } - - std::string eth_rpc_client::ethereum_function_call_encoder::encode_bytes(const std::string& values) { - size_t len = values.length(); - std::string output = encode_uint256((boost::format("%x") % len).str()) + values + std::string(64 - len, '0'); - return output; - } - - std::string eth_rpc_client::safe_transaction_encoder::create_safe_address(const std::vector& owner_addresses, uint32_t threshold) { - //createProxyWithNonce(address,bytes,uint256) - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("createProxyWithNonce(address,bytes,uint256)"); - FC_ASSERT("1688f0b9" == method_id); - - std::string data = "0x1688f0b9000000000000000000000000d9db270c1b5e3bd161e8c8503c55ceabee70955200000000000000000000000000000000000000000000000000000000000000604fa262bd05cdef2e3d5261787ee66d9447a4036324990e04380339bec83b4c7a0000000000000000000000000000000000000000000000000000000000000264b63e800d0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000f48f2b2d2a534e402487b3ee7c18c33aec0fe5e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC1200000000000000000000000076ce31BD03f601c3fC13732deF921c5Bac28267600000000000000000000000009EE460834498a4ee361beB819470061B7381B490000000000000000000000006AEFbd09209e1eE2e0a589d31e732F69B77713D2000000000000000000000000631e128b16f9aDCF1bB6385112B1519C917D77a7000000000000000000000000cD5C788e84220E8b8934Ea4F1dC6a12009bCc91D0000000000000000000000003627C1B31525887CB9441130C831e3588765030500000000000000000000000003A13a989AF30C92AD7ABD1E6210308A6c96f3730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; - - return data; - } - - std::string eth_rpc_client::safe_transaction_encoder::build_transaction(const std::string& safe_account_addr, const std::string& value, const std::string& data, uint8_t operation, const std::string& safeTxGas, const std::string& dataGas, const std::string& gasPrice, const std::string& gasToken, const std::string& refundReceiver){ - //execTransaction method of smart contract , using safe-account address - //execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 dataGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); - FC_ASSERT("6a761202" == method_id); - //"" - std::string to = m_ethereum_function_call_encoder.encode_address(safe_account_addr); - // Value in wei - std::string value_encoded = m_ethereum_function_call_encoder.encode_uint256(value); - // 0 CALL, 1 DELEGATE_CALL - std::string operation_encoded = m_ethereum_function_call_encoder.encode_uint8(operation); - // Max gas to use in the transaction - std::string safeTxGas_encoded = m_ethereum_function_call_encoder.encode_uint256(safeTxGas); - // Gas costs not related to the transaction execution (signature check, refund payment...) - std::string dataGas_encoded = m_ethereum_function_call_encoder.encode_uint256(dataGas); - // Gas price used for the refund calculation - std::string gasPrice_encoded = m_ethereum_function_call_encoder.encode_uint256(gasPrice); - //"", Token address (hold by the Safe) to be used as a refund to the sender, if `null` is Ether - std::string gasToken_encoded = m_ethereum_function_call_encoder.encode_address(gasToken); - //"", Address of receiver of gas payment (or `null` if tx.origin) - std::string refundReceiver_encoded = m_ethereum_function_call_encoder.encode_address(refundReceiver); - - std::string message = method_id + to + value_encoded + data + operation_encoded + safeTxGas_encoded + dataGas_encoded + gasPrice_encoded + gasToken_encoded + refundReceiver_encoded; - - return message; - } - - - eth_rpc_client::eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : _thread(std::make_shared("eth_rpc_client")){ - geth_url = url; - user = user_name; - this->password = password; - this->debug_rpc_calls = debug_rpc_calls; - t_id = 1; - - ilog("eth_rpc_client"); - ilog("### Geth URL: ${url}", ("url", url)); - - m_endpoint.set_access_channels(websocketpp::log::alevel::none); - m_endpoint.set_error_channels(websocketpp::log::elevel::none); - - // Initialize ASIO - m_endpoint.init_asio(); - - // Register our handlers - m_endpoint.set_socket_init_handler(bind(&type::on_socket_init,this,::_1)); - m_endpoint.set_message_handler(bind(&type::on_message,this,::_1,::_2)); - m_endpoint.set_open_handler(bind(&type::on_open,this,::_1)); - m_endpoint.set_close_handler(bind(&type::on_close,this,::_1)); - m_endpoint.set_fail_handler(bind(&type::on_fail,this,::_1)); - } - - void eth_rpc_client::start() { - ilog("### eth_rpc_client::start uri: ${uri}", ("uri", geth_url)); - auto future = _thread->async([this] - { - websocketpp::lib::error_code ec; - client::connection_ptr con = m_endpoint.get_connection(this->geth_url, ec); - m_hdl = con->get_handle(); - - if (ec) { - m_endpoint.get_alog().write(websocketpp::log::alevel::app,ec.message()); - return; - } - - m_endpoint.connect(con); - - // Start the ASIO io_service run loop - m_endpoint.run(); - }); - } - - void eth_rpc_client::stop() { - m_endpoint.close(m_hdl,websocketpp::close::status::normal,""); - } - - void eth_rpc_client::on_socket_init(websocketpp::connection_hdl) { - } - - void eth_rpc_client::on_fail(websocketpp::connection_hdl hdl) { - client::connection_ptr con = m_endpoint.get_con_from_hdl(hdl); - - elog("Ethereum websocket fail"); - //elog("get_state: ${state}", ("state", con->get_state() ) ); - elog("get_local_close_code: ${code}", ("code", con->get_local_close_code())); - elog("get_local_close_reason: ${close}", ("close",con->get_local_close_reason())); - elog("get_remote_close_code: ${close}", ("close", con->get_remote_close_code())); - elog("get_remote_close_reason: ${close}", ("close", con->get_remote_close_reason())); - elog("get_ec().message(): ${ec}", ("ec", con->get_ec().message())); - } - - void eth_rpc_client::on_open(websocketpp::connection_hdl hdl) { - std::string str = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":84}"; - ilog("on_open: ${str}", ("str", str)); - m_endpoint.send(hdl, str.c_str(), websocketpp::frame::opcode::text); - - vector owner_addresses; - std::string private_key = ""; - createmultisig(5, owner_addresses, private_key); - } - - void eth_rpc_client::on_message(websocketpp::connection_hdl hdl, message_ptr msg) { - - ilog("on_message: ${msg}", ("msg", msg->get_payload())); - - fc::variants list = fc::json::variants_from_string( msg->get_payload() ); - - ilog("json reposnse: ${list}", ("list", list)); - - const auto& b_obj = list[0].get_object().find( "id" ); - - if (true == list[0].get_object().contains( "error" )){ - elog("error in json reposnse: ${list}", ("list", list)); - return; - } - - std::string result_str = list[0].get_object().find( "result" )->value().as(1); - uint32_t num_owners = 0; - uint32_t i = 0; - fc::variant v; - switch(b_obj->value().as(1)){ - case ETH_CHAIN_ID: - chain_id = result_str; - break; - case ETH_GET_TRANSACTION_RECEIPT: - list = fc::json::variants_from_string( result_str ); - v = list[0].get_object().find( "logs" )->value(); - safe_account_addr = v.get_object().find( "address" )->value().as(1); - break; - case ETH_CALL: - break; - case ETH_SEND_TRANSACTION: - transaction_id = result_str; - break; - case ETH_SEND_RAW_TRANSACTION: - break; - case ETH_GET_CODE: - code = result_str; - break; - case ETH_GET_BALANCE: - balance = result_str; - break; - case ETH_SIGN: - signature = result_str; - break; - case ETH_COINBASE: - account_address = result_str; - break; - case GET_LIST_OWNERS: - num_owners = (uint32_t)strtol(result_str.substr(2 + 32 + 32 - 4, 4).c_str(), NULL, 16); - owners.clear(); - for (i = 0; i < num_owners; ++i){ - owners.push_back("0x" + result_str.substr(2 + 32 + 32 + 12 + 32 * i,20)); - } - break; - case ADD_OWNER: - break; - case REMOVE_OWNER: - break; - } - } - - void eth_rpc_client::on_close(websocketpp::connection_hdl) { - ilog("Ethereum websocket close"); - } - - uint64_t eth_rpc_client::get_chain_id() { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":%1%}") % t_id); - ilog("get_chain_id: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_CHAIN_ID; - return t_id++; - } - - uint64_t eth_rpc_client::eth_getTransactionReceipt(const std::string& tx_id) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"%1%\"],\"id\":%2%}") % tx_id.c_str() % t_id); - ilog("eth_getTransactionReceipt: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_GET_TRANSACTION_RECEIPT; - return t_id++; - } - - uint64_t eth_rpc_client::eth_call(const std::string& to, const std::string& data) { - std::string req = str(boost::format("{\"jsonrpc\": \"2.0\", \"method\": \"eth_call\", \"params\": [{\"to\": \"%1%\", \"data\": \"%2%\"}, \"latest\"], \"id\": %3%}") % to.c_str() % data.c_str() % t_id); - ilog("eth_call: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_CALL; - - return t_id++; - } - - uint64_t eth_rpc_client::eth_sendTransaction(const std::string& from, const std::string& to, const std::string& data) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sendTransaction\", \"params\": [{\"from\": \"%1%\", \"to\": \"%2%\", \"data\": \"%3%\"}], \"id\": %4%}") % from.c_str() % to.c_str() % data.c_str() % t_id); - ilog("eth_sendTransaction: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_SEND_TRANSACTION; - - return t_id++; - } - - uint64_t eth_rpc_client::eth_sendRawTransaction(const std::string& params) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"%1%\"],\"id\":%2%}") % params.c_str() % t_id); - ilog("eth_sendRawTransaction: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_SEND_RAW_TRANSACTION; - - return t_id++; - } - - uint64_t eth_rpc_client::eth_getCode(const std::string& addr) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getCode\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); - ilog("eth_getCode: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_GET_CODE; - return t_id++; - } - - uint64_t eth_rpc_client::eth_getBalance(const std::string& addr) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getBalance\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); - ilog("eth_getBalance: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_GET_BALANCE; - return t_id++; - } - - uint64_t eth_rpc_client::eth_sign(const string& addr, const string& message) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sign\", \"params\": [\"%1%\",\"%2%\"], \"id\": %2%}") % addr.c_str() % message.c_str() % t_id); - ilog("eth_sign: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_SIGN; - - return t_id++; - } - - uint64_t eth_rpc_client::eth_coinbase() { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_coinbase\",\"params\":[],\"id\":%1%}") % t_id); - ilog("eth_coinbase: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_COINBASE; - return t_id++; - } - - uint64_t eth_rpc_client::get_list_owners(const std::string& safe_account) { - //getOwners() - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("getOwners()"); - FC_ASSERT("a0e67e2b" == method_id); - return eth_call(safe_account.c_str(), method_id); - } - - uint64_t eth_rpc_client::add_owner(const std::string& addr ) { - if (std::count(owners.begin(), owners.end(), addr)){ - FC_THROW_EXCEPTION(fc::exception, "Owners allready have addr: ${addr}", ("addr", addr)); - } - - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); - //addOwnerWithThreshold(address,uint256) - std::string data_method_id = m_ethereum_function_call_encoder.encode_function_signature("addOwnerWithThreshold(address,uint256)"); - FC_ASSERT("0d582f13" == data_method_id); - std::string data = data_method_id + m_ethereum_function_call_encoder.encode_address(addr) + m_ethereum_function_call_encoder.encode_uint256((boost::format("%x") % threshold).str()); - - std::string message = m_safe_transaction_encoder.build_transaction(safe_account_addr, "0", data, ethereum_function_call_encoder::operation_t::OPERATION_CALL, m_safe_transaction_encoder.default_safe_tx_gas, m_safe_transaction_encoder.default_data_gas, m_safe_transaction_encoder.default_gas_price, m_safe_transaction_encoder.default_gas_token, m_safe_transaction_encoder.default_refund_receiver); - - uint64_t id = eth_sign(account_address, message); - - m_requests[t_id] = req_t::ADD_OWNER; - - return 0; - } - - uint64_t eth_rpc_client::remove_owner(const std::string& addr, uint32_t threshold) { - if (!std::count(owners.begin(), owners.end(), addr)){ - FC_THROW_EXCEPTION(fc::exception, "Owners does not have addr: ${addr}", ("addr", addr)); - } - - if (threshold == owners.size()){ - FC_THROW_EXCEPTION(fc::exception, "Owners size does not meet threshold: ${th}", ("th", threshold)); - } - - //removeOwner(address,address,uint256) - std::string data_method_id = m_ethereum_function_call_encoder.encode_function_signature("removeOwner(address,address,uint256)"); - FC_ASSERT("f8dc5dd9" == data_method_id); - std::string data = data_method_id + m_ethereum_function_call_encoder.encode_address(m_ethereum_function_call_encoder.default_prev_addr) + m_ethereum_function_call_encoder.encode_address(addr) + m_ethereum_function_call_encoder.encode_uint256((boost::format("%x") % threshold).str()); - - std::string message = m_safe_transaction_encoder.build_transaction(safe_account_addr, "0", data, ethereum_function_call_encoder::operation_t::OPERATION_CALL, m_safe_transaction_encoder.default_safe_tx_gas, m_safe_transaction_encoder.default_data_gas, m_safe_transaction_encoder.default_gas_price, m_safe_transaction_encoder.default_gas_token, m_safe_transaction_encoder.default_refund_receiver); - - uint64_t id = eth_sign(account_address, message); - - m_requests[t_id] = req_t::REMOVE_OWNER; - - return 0; - } - - std::string eth_rpc_client::addmultisigaddress(const uint32_t nrequired, const std::vector public_keys) { - return ""; - } - - std::string eth_rpc_client::combinepsbt(const vector &psbts) { - return ""; - } - - uint64_t eth_rpc_client::createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key) { - ilog("createmultisig: ${key}", ("key", private_key.c_str())); - - //That's will create - //0x5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12 - //0x76ce31BD03f601c3fC13732deF921c5Bac282676 - //0x09EE460834498a4ee361beB819470061B7381B49 - //0x6AEFbd09209e1eE2e0a589d31e732F69B77713D2 - //0x631e128b16f9aDCF1bB6385112B1519C917D77a7 - //0xcD5C788e84220E8b8934Ea4F1dC6a12009bCc91D - //0x3627C1B31525887CB9441130C831e35887650305 - //0x03A13a989AF30C92AD7ABD1E6210308A6c96f373 - - - std::string from = "0xeE52b70e8D7AB5Fe661311D47e81228EAD6B06B9"; - std::string to = "0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2"; - std::string data = m_safe_transaction_encoder.create_safe_address(owner_addresses, nrequired); - - return eth_sendTransaction(from, to, data); - } +std::string eth_rpc_client::Transaction::serialize(const std::string &from, const std::string &to, const std::string &tx_id, u256 const &_value, u256 const &_gasPrice, u256 const &_gas, bytes const &_data, u256 const &_nonce) { + std::string m_data_str(m_data.begin(), m_data.end()); + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"account_signTransaction\",\"params\":[{\"from\": \"%1%\", \"gas\": \"%2%\", \"gasPrice\": \"%3%\", \"input\": \"%4%\", \"nonce\": \"%5%\", \"to\": \"%6%\", \"value\": \"%7%\" }],\"id\":%8%}") % from.c_str() % m_gas.str() % m_gasPrice.str() % m_data_str % m_nonce.str() % to.c_str() % m_value.str() % tx_id.c_str()); + return req; +} + +// ============================================================================= +std::string eth_rpc_client::ethereum_function_call_encoder::encode_function_signature(const std::string &function_signature) { + sha3_context c; + char *hash; + + sha3_Init256(static_cast(&c)); + sha3_SetFlags(&c, SHA3_FLAGS_KECCAK); + sha3_Update(&c, "abc", 3); + hash = (char *)sha3_Finalize(&c); + std::string output(hash); + output = output.substr(0, 8); + + return output; +}; + +std::string eth_rpc_client::ethereum_function_call_encoder::encode_address(const std::string &addr) { + FC_ASSERT(40 == addr.length()); + std::string output = str(boost::format("%024u") % 0) + addr; + return output; +} + +std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint256(const std::string &value) { + FC_ASSERT(value.length() <= 64); + std::string output = std::string(64 - value.length(), '0') + value; + return output; +} + +std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint8(uint8_t value) { + std::string output = str(boost::format("%02X") % value) + std::string(62, '0'); + return output; +} + +std::string eth_rpc_client::ethereum_function_call_encoder::encode_bytes(const std::string &values) { + size_t len = values.length(); + std::string output = encode_uint256((boost::format("%x") % len).str()) + values + std::string(64 - len, '0'); + return output; +} + +std::string eth_rpc_client::safe_transaction_encoder::create_safe_address(const std::vector &owner_addresses, uint32_t threshold) { + //createProxyWithNonce(address,bytes,uint256) + std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("createProxyWithNonce(address,bytes,uint256)"); + FC_ASSERT("1688f0b9" == method_id); + + std::string data = "0x1688f0b9000000000000000000000000d9db270c1b5e3bd161e8c8503c55ceabee70955200000000000000000000000000000000000000000000000000000000000000604fa262bd05cdef2e3d5261787ee66d9447a4036324990e04380339bec83b4c7a0000000000000000000000000000000000000000000000000000000000000264b63e800d0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000f48f2b2d2a534e402487b3ee7c18c33aec0fe5e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC1200000000000000000000000076ce31BD03f601c3fC13732deF921c5Bac28267600000000000000000000000009EE460834498a4ee361beB819470061B7381B490000000000000000000000006AEFbd09209e1eE2e0a589d31e732F69B77713D2000000000000000000000000631e128b16f9aDCF1bB6385112B1519C917D77a7000000000000000000000000cD5C788e84220E8b8934Ea4F1dC6a12009bCc91D0000000000000000000000003627C1B31525887CB9441130C831e3588765030500000000000000000000000003A13a989AF30C92AD7ABD1E6210308A6c96f3730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + + return data; +} + +std::string eth_rpc_client::safe_transaction_encoder::build_transaction(const std::string &safe_account_addr, const std::string &value, const std::string &data, uint8_t operation, const std::string &safeTxGas, const std::string &dataGas, const std::string &gasPrice, const std::string &gasToken, const std::string &refundReceiver) { + //execTransaction method of smart contract , using safe-account address + //execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 dataGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) + std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); + FC_ASSERT("6a761202" == method_id); + //"" + std::string to = m_ethereum_function_call_encoder.encode_address(safe_account_addr); + // Value in wei + std::string value_encoded = m_ethereum_function_call_encoder.encode_uint256(value); + // 0 CALL, 1 DELEGATE_CALL + std::string operation_encoded = m_ethereum_function_call_encoder.encode_uint8(operation); + // Max gas to use in the transaction + std::string safeTxGas_encoded = m_ethereum_function_call_encoder.encode_uint256(safeTxGas); + // Gas costs not related to the transaction execution (signature check, refund payment...) + std::string dataGas_encoded = m_ethereum_function_call_encoder.encode_uint256(dataGas); + // Gas price used for the refund calculation + std::string gasPrice_encoded = m_ethereum_function_call_encoder.encode_uint256(gasPrice); + //"", Token address (hold by the Safe) to be used as a refund to the sender, if `null` is Ether + std::string gasToken_encoded = m_ethereum_function_call_encoder.encode_address(gasToken); + //"", Address of receiver of gas payment (or `null` if tx.origin) + std::string refundReceiver_encoded = m_ethereum_function_call_encoder.encode_address(refundReceiver); + + std::string message = method_id + to + value_encoded + data + operation_encoded + safeTxGas_encoded + dataGas_encoded + gasPrice_encoded + gasToken_encoded + refundReceiver_encoded; + + return message; +} + +eth_rpc_client::eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : + _thread(std::make_shared("eth_rpc_client")) { + geth_url = url; + user = user_name; + this->password = password; + this->debug_rpc_calls = debug_rpc_calls; + t_id = 1; + + ilog("eth_rpc_client"); + ilog("### Geth URL: ${url}", ("url", url)); + + m_endpoint.set_access_channels(websocketpp::log::alevel::none); + m_endpoint.set_error_channels(websocketpp::log::elevel::none); + + // Initialize ASIO + m_endpoint.init_asio(); + + // Register our handlers + m_endpoint.set_socket_init_handler(bind(&type::on_socket_init, this, ::_1)); + m_endpoint.set_message_handler(bind(&type::on_message, this, ::_1, ::_2)); + m_endpoint.set_open_handler(bind(&type::on_open, this, ::_1)); + m_endpoint.set_close_handler(bind(&type::on_close, this, ::_1)); + m_endpoint.set_fail_handler(bind(&type::on_fail, this, ::_1)); +} + +void eth_rpc_client::start() { + ilog("### eth_rpc_client::start uri: ${uri}", ("uri", geth_url)); + auto future = _thread->async([this] { + websocketpp::lib::error_code ec; + client::connection_ptr con = m_endpoint.get_connection(this->geth_url, ec); + m_hdl = con->get_handle(); + + if (ec) { + m_endpoint.get_alog().write(websocketpp::log::alevel::app, ec.message()); + return; + } + + m_endpoint.connect(con); + + // Start the ASIO io_service run loop + m_endpoint.run(); + }); +} + +void eth_rpc_client::stop() { + m_endpoint.close(m_hdl, websocketpp::close::status::normal, ""); +} + +void eth_rpc_client::on_socket_init(websocketpp::connection_hdl) { +} + +void eth_rpc_client::on_fail(websocketpp::connection_hdl hdl) { + client::connection_ptr con = m_endpoint.get_con_from_hdl(hdl); + + elog("Ethereum websocket fail"); + //elog("get_state: ${state}", ("state", con->get_state() ) ); + elog("get_local_close_code: ${code}", ("code", con->get_local_close_code())); + elog("get_local_close_reason: ${close}", ("close", con->get_local_close_reason())); + elog("get_remote_close_code: ${close}", ("close", con->get_remote_close_code())); + elog("get_remote_close_reason: ${close}", ("close", con->get_remote_close_reason())); + elog("get_ec().message(): ${ec}", ("ec", con->get_ec().message())); +} + +void eth_rpc_client::on_open(websocketpp::connection_hdl hdl) { + std::string str = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":84}"; + ilog("on_open: ${str}", ("str", str)); + m_endpoint.send(hdl, str.c_str(), websocketpp::frame::opcode::text); + + vector owner_addresses; + std::string private_key = ""; + createmultisig(5, owner_addresses, private_key); +} + +void eth_rpc_client::on_message(websocketpp::connection_hdl hdl, message_ptr msg) { + + ilog("on_message: ${msg}", ("msg", msg->get_payload())); + + fc::variants list = fc::json::variants_from_string(msg->get_payload()); + + ilog("json reposnse: ${list}", ("list", list)); + + const auto &b_obj = list[0].get_object().find("id"); + + if (true == list[0].get_object().contains("error")) { + elog("error in json reposnse: ${list}", ("list", list)); + return; + } + + std::string result_str = list[0].get_object().find("result")->value().as(1); + uint32_t num_owners = 0; + uint32_t i = 0; + fc::variant v; + switch (b_obj->value().as(1)) { + case ETH_CHAIN_ID: + chain_id = result_str; + break; + case ETH_GET_TRANSACTION_RECEIPT: + list = fc::json::variants_from_string(result_str); + v = list[0].get_object().find("logs")->value(); + safe_account_addr = v.get_object().find("address")->value().as(1); + break; + case ETH_CALL: + break; + case ETH_SEND_TRANSACTION: + transaction_id = result_str; + break; + case ETH_SEND_RAW_TRANSACTION: + break; + case ETH_GET_CODE: + code = result_str; + break; + case ETH_GET_BALANCE: + balance = result_str; + break; + case ETH_SIGN: + signature = result_str; + break; + case ETH_COINBASE: + account_address = result_str; + break; + case GET_LIST_OWNERS: + num_owners = (uint32_t)strtol(result_str.substr(2 + 32 + 32 - 4, 4).c_str(), NULL, 16); + owners.clear(); + for (i = 0; i < num_owners; ++i) { + owners.push_back("0x" + result_str.substr(2 + 32 + 32 + 12 + 32 * i, 20)); + } + break; + case ADD_OWNER: + break; + case REMOVE_OWNER: + break; + } +} + +void eth_rpc_client::on_close(websocketpp::connection_hdl) { + ilog("Ethereum websocket close"); +} + +uint64_t eth_rpc_client::get_chain_id() { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":%1%}") % t_id); + ilog("get_chain_id: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_CHAIN_ID; + return t_id++; +} + +uint64_t eth_rpc_client::eth_getTransactionReceipt(const std::string &tx_id) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"%1%\"],\"id\":%2%}") % tx_id.c_str() % t_id); + ilog("eth_getTransactionReceipt: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_GET_TRANSACTION_RECEIPT; + return t_id++; +} + +uint64_t eth_rpc_client::eth_call(const std::string &to, const std::string &data) { + std::string req = str(boost::format("{\"jsonrpc\": \"2.0\", \"method\": \"eth_call\", \"params\": [{\"to\": \"%1%\", \"data\": \"%2%\"}, \"latest\"], \"id\": %3%}") % to.c_str() % data.c_str() % t_id); + ilog("eth_call: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_CALL; + + return t_id++; +} + +uint64_t eth_rpc_client::eth_sendTransaction(const std::string &from, const std::string &to, const std::string &data) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sendTransaction\", \"params\": [{\"from\": \"%1%\", \"to\": \"%2%\", \"data\": \"%3%\"}], \"id\": %4%}") % from.c_str() % to.c_str() % data.c_str() % t_id); + ilog("eth_sendTransaction: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_SEND_TRANSACTION; + + return t_id++; +} + +uint64_t eth_rpc_client::eth_sendRawTransaction(const std::string ¶ms) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"%1%\"],\"id\":%2%}") % params.c_str() % t_id); + ilog("eth_sendRawTransaction: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_SEND_RAW_TRANSACTION; + + return t_id++; +} + +uint64_t eth_rpc_client::eth_getCode(const std::string &addr) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getCode\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); + ilog("eth_getCode: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_GET_CODE; + return t_id++; +} + +uint64_t eth_rpc_client::eth_getBalance(const std::string &addr) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getBalance\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); + ilog("eth_getBalance: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_GET_BALANCE; + return t_id++; +} + +uint64_t eth_rpc_client::eth_sign(const string &addr, const string &message) { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sign\", \"params\": [\"%1%\",\"%2%\"], \"id\": %2%}") % addr.c_str() % message.c_str() % t_id); + ilog("eth_sign: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_SIGN; + + return t_id++; +} + +uint64_t eth_rpc_client::eth_coinbase() { + std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_coinbase\",\"params\":[],\"id\":%1%}") % t_id); + ilog("eth_coinbase: ${req}", ("req", req.c_str())); + m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); + m_requests[t_id] = req_t::ETH_COINBASE; + return t_id++; +} + +uint64_t eth_rpc_client::get_list_owners(const std::string &safe_account) { + //getOwners() + std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("getOwners()"); + FC_ASSERT("a0e67e2b" == method_id); + return eth_call(safe_account.c_str(), method_id); +} + +uint64_t eth_rpc_client::add_owner(const std::string &addr) { + if (std::count(owners.begin(), owners.end(), addr)) { + FC_THROW_EXCEPTION(fc::exception, "Owners allready have addr: ${addr}", ("addr", addr)); + } + + std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); + //addOwnerWithThreshold(address,uint256) + std::string data_method_id = m_ethereum_function_call_encoder.encode_function_signature("addOwnerWithThreshold(address,uint256)"); + FC_ASSERT("0d582f13" == data_method_id); + std::string data = data_method_id + m_ethereum_function_call_encoder.encode_address(addr) + m_ethereum_function_call_encoder.encode_uint256((boost::format("%x") % threshold).str()); + + std::string message = m_safe_transaction_encoder.build_transaction(safe_account_addr, "0", data, ethereum_function_call_encoder::operation_t::OPERATION_CALL, m_safe_transaction_encoder.default_safe_tx_gas, m_safe_transaction_encoder.default_data_gas, m_safe_transaction_encoder.default_gas_price, m_safe_transaction_encoder.default_gas_token, m_safe_transaction_encoder.default_refund_receiver); + + uint64_t id = eth_sign(account_address, message); + + m_requests[t_id] = req_t::ADD_OWNER; + + return 0; +} + +uint64_t eth_rpc_client::remove_owner(const std::string &addr, uint32_t threshold) { + if (!std::count(owners.begin(), owners.end(), addr)) { + FC_THROW_EXCEPTION(fc::exception, "Owners does not have addr: ${addr}", ("addr", addr)); + } + + if (threshold == owners.size()) { + FC_THROW_EXCEPTION(fc::exception, "Owners size does not meet threshold: ${th}", ("th", threshold)); + } + + //removeOwner(address,address,uint256) + std::string data_method_id = m_ethereum_function_call_encoder.encode_function_signature("removeOwner(address,address,uint256)"); + FC_ASSERT("f8dc5dd9" == data_method_id); + std::string data = data_method_id + m_ethereum_function_call_encoder.encode_address(m_ethereum_function_call_encoder.default_prev_addr) + m_ethereum_function_call_encoder.encode_address(addr) + m_ethereum_function_call_encoder.encode_uint256((boost::format("%x") % threshold).str()); + + std::string message = m_safe_transaction_encoder.build_transaction(safe_account_addr, "0", data, ethereum_function_call_encoder::operation_t::OPERATION_CALL, m_safe_transaction_encoder.default_safe_tx_gas, m_safe_transaction_encoder.default_data_gas, m_safe_transaction_encoder.default_gas_price, m_safe_transaction_encoder.default_gas_token, m_safe_transaction_encoder.default_refund_receiver); + + uint64_t id = eth_sign(account_address, message); + + m_requests[t_id] = req_t::REMOVE_OWNER; + + return 0; +} + +std::string eth_rpc_client::addmultisigaddress(const uint32_t nrequired, const std::vector public_keys) { + return ""; +} + +std::string eth_rpc_client::combinepsbt(const vector &psbts) { + return ""; +} + +uint64_t eth_rpc_client::createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key) { + ilog("createmultisig: ${key}", ("key", private_key.c_str())); + + //That's will create + //0x5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12 + //0x76ce31BD03f601c3fC13732deF921c5Bac282676 + //0x09EE460834498a4ee361beB819470061B7381B49 + //0x6AEFbd09209e1eE2e0a589d31e732F69B77713D2 + //0x631e128b16f9aDCF1bB6385112B1519C917D77a7 + //0xcD5C788e84220E8b8934Ea4F1dC6a12009bCc91D + //0x3627C1B31525887CB9441130C831e35887650305 + //0x03A13a989AF30C92AD7ABD1E6210308A6c96f373 + + std::string from = "0xeE52b70e8D7AB5Fe661311D47e81228EAD6B06B9"; + std::string to = "0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2"; + std::string data = m_safe_transaction_encoder.create_safe_address(owner_addresses, nrequired); - std::string eth_rpc_client::createpsbt() { - } + return eth_sendTransaction(from, to, data); +} - std::string eth_rpc_client::createrawtransaction() { - return ""; - } +std::string eth_rpc_client::createpsbt() { +} - std::string eth_rpc_client::createwallet(const std::string &wallet_name) { - return ""; - } +std::string eth_rpc_client::createrawtransaction() { + return ""; +} - std::string eth_rpc_client::decodepsbt(std::string const &tx_psbt) { - return ""; - } +std::string eth_rpc_client::createwallet(const std::string &wallet_name) { + return ""; +} - std::string eth_rpc_client::decoderawtransaction(std::string const &tx_hex) { - return ""; - } +std::string eth_rpc_client::decodepsbt(std::string const &tx_psbt) { + return ""; +} - std::string eth_rpc_client::encryptwallet(const std::string &passphrase) { - return ""; - } +std::string eth_rpc_client::decoderawtransaction(std::string const &tx_hex) { + return ""; +} - uint64_t eth_rpc_client::estimatesmartfee(uint16_t conf_target) { - return 20000; - } +std::string eth_rpc_client::encryptwallet(const std::string &passphrase) { + return ""; +} - std::string eth_rpc_client::finalizepsbt(std::string const &tx_psbt) { - return ""; - } +uint64_t eth_rpc_client::estimatesmartfee(uint16_t conf_target) { + return 20000; +} - std::string eth_rpc_client::getaddressinfo(const std::string &address) { - return ""; - } +std::string eth_rpc_client::finalizepsbt(std::string const &tx_psbt) { + return ""; +} - std::string eth_rpc_client::getblock(const std::string &block_hash, int32_t verbosity) { - return ""; - } +std::string eth_rpc_client::getaddressinfo(const std::string &address) { + return ""; +} - std::string eth_rpc_client::getnetworkinfo() { - return ""; - } +std::string eth_rpc_client::getblock(const std::string &block_hash, int32_t verbosity) { + return ""; +} - std::string eth_rpc_client::getrawtransaction(const std::string &txid, const bool verbose) { - return ""; - } +std::string eth_rpc_client::getnetworkinfo() { + return ""; +} - std::string eth_rpc_client::gettransaction(const std::string &txid, const bool include_watch_only) { - return ""; - } +std::string eth_rpc_client::getrawtransaction(const std::string &txid, const bool verbose) { + return ""; +} - std::string eth_rpc_client::getblockchaininfo() { - return ""; - } +std::string eth_rpc_client::gettransaction(const std::string &txid, const bool include_watch_only) { + return ""; +} - void eth_rpc_client::importaddress(const std::string &address_or_script, const std::string &label, const bool rescan, const bool p2sh) { - return; - } +std::string eth_rpc_client::getblockchaininfo() { + return ""; +} - void eth_rpc_client::importmulti(const std::vector &address_or_script_array, const bool rescan) { - } +void eth_rpc_client::importaddress(const std::string &address_or_script, const std::string &label, const bool rescan, const bool p2sh) { + return; +} - std::string eth_rpc_client::loadwallet(const std::string &filename) { - return ""; - } +void eth_rpc_client::importmulti(const std::vector &address_or_script_array, const bool rescan) { +} - std::string eth_rpc_client::sendrawtransaction(const std::string &tx_hex) { - return ""; - } +std::string eth_rpc_client::loadwallet(const std::string &filename) { + return ""; +} - std::string eth_rpc_client::signrawtransactionwithwallet(const std::string &tx_hash) { - return ""; - } +std::string eth_rpc_client::sendrawtransaction(const std::string &tx_hex) { + return ""; +} - std::string eth_rpc_client::unloadwallet(const std::string &filename) { - return ""; - } +std::string eth_rpc_client::signrawtransactionwithwallet(const std::string &tx_hash) { + return ""; +} - std::string eth_rpc_client::walletlock() { - return ""; - } +std::string eth_rpc_client::unloadwallet(const std::string &filename) { + return ""; +} - std::string eth_rpc_client::walletprocesspsbt(std::string const &tx_psbt) { - return ""; - } +std::string eth_rpc_client::walletlock() { + return ""; +} - bool eth_rpc_client::walletpassphrase(const std::string &passphrase, uint32_t timeout) { - return false; - } +std::string eth_rpc_client::walletprocesspsbt(std::string const &tx_psbt) { + return ""; +} - // ============================================================================= +bool eth_rpc_client::walletpassphrase(const std::string &passphrase, uint32_t timeout) { + return false; +} - sidechain_net_handler_eth::sidechain_net_handler_eth(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : - sidechain_net_handler(_plugin, options) { - sidechain = sidechain_type::ethereum; +// ============================================================================= - if (options.count("debug-rpc-calls")) { - debug_rpc_calls = options.at("debug-rpc-calls").as(); - } +sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : + sidechain_net_handler(_plugin, options) { + sidechain = sidechain_type::ethereum; - url = options.at("ethereum-node-rpc-url").as(); - eth_client = std::unique_ptr(new eth_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls)); - eth_client->start(); - /* + if (options.count("debug-rpc-calls")) { + debug_rpc_calls = options.at("debug-rpc-calls").as(); + } + + url = options.at("ethereum-node-rpc-url").as(); + eth_client = std::unique_ptr(new eth_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls)); + eth_client->start(); + /* if (!wallet.empty()) { eth_client->loadwallet(wallet); } - std::thread(&sidechain_net_handler_eth::handle_event, this, event_data).detach(); + std::thread(&sidechain_net_handler_ethereum::handle_event, this, event_data).detach(); }); database.changed_objects.connect([this](const vector &ids, const flat_set &accounts) { @@ -521,22 +519,22 @@ namespace graphene { namespace peerplays_sidechain { */ } -sidechain_net_handler_eth::~sidechain_net_handler_eth() { - try { - if (on_changed_objects_task.valid()) { - on_changed_objects_task.cancel_and_wait(__FUNCTION__); - } - } catch (fc::canceled_exception &) { - //Expected exception. Move along. - } catch (fc::exception &e) { - edump((e.to_detail_string())); - } +sidechain_net_handler_ethereum::~sidechain_net_handler_ethereum() { + try { + if (on_changed_objects_task.valid()) { + on_changed_objects_task.cancel_and_wait(__FUNCTION__); + } + } catch (fc::canceled_exception &) { + //Expected exception. Move along. + } catch (fc::exception &e) { + edump((e.to_detail_string())); + } } -bool sidechain_net_handler_eth::process_proposal(const proposal_object &po) { +bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) { - ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); - /* + ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); + /* bool should_approve = false; const chain::global_property_object &gpo = database.get_global_properties(); @@ -819,88 +817,88 @@ elog("=================================================="); return should_approve; */ -return true; + return true; } -void sidechain_net_handler_eth::process_primary_wallet() { - ilog("### process_primary_wallet:"); +void sidechain_net_handler_ethereum::process_primary_wallet() { + ilog("### process_primary_wallet:"); - const auto &swi = database.get_index_type().indices().get(); - const auto &active_sw = swi.rbegin(); - if (active_sw != swi.rend()) { + const auto &swi = database.get_index_type().indices().get(); + const auto &active_sw = swi.rbegin(); + if (active_sw != swi.rend()) { - if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) || - (active_sw->addresses.at(sidechain_type::ethereum).empty())) { + if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) || + (active_sw->addresses.at(sidechain_type::ethereum).empty())) { - if (proposal_exists(chain::operation::tag::value, active_sw->id)) { - return; - } + if (proposal_exists(chain::operation::tag::value, active_sw->id)) { + return; + } - const chain::global_property_object &gpo = database.get_global_properties(); + const chain::global_property_object &gpo = database.get_global_properties(); - auto active_sons = gpo.active_sons; - string reply_str = create_primary_wallet_address(active_sons); + auto active_sons = gpo.active_sons; + string reply_str = create_primary_wallet_address(active_sons); - std::stringstream active_pw_ss(reply_str); + std::stringstream active_pw_ss(reply_str); - ilog("### process_primary_wallet: ${reply}", ("reply", reply_str)); + ilog("### process_primary_wallet: ${reply}", ("reply", reply_str)); - boost::property_tree::ptree active_pw_pt; - boost::property_tree::read_json(active_pw_ss, active_pw_pt); - if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { - if (!plugin.can_son_participate(chain::operation::tag::value, active_sw->id)) { - return; - } + boost::property_tree::ptree active_pw_pt; + boost::property_tree::read_json(active_pw_ss, active_pw_pt); + if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { + if (!plugin.can_son_participate(chain::operation::tag::value, active_sw->id)) { + return; + } - proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; - uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - std::stringstream res; - boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); + std::stringstream res; + boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); - son_wallet_update_operation swu_op; - swu_op.payer = gpo.parameters.son_account(); - swu_op.son_wallet_id = active_sw->id; - swu_op.sidechain = sidechain_type::ethereum; - swu_op.address = res.str(); + son_wallet_update_operation swu_op; + swu_op.payer = gpo.parameters.son_account(); + swu_op.son_wallet_id = active_sw->id; + swu_op.sidechain = sidechain_type::ethereum; + swu_op.address = res.str(); - proposal_op.proposed_ops.emplace_back(swu_op); + proposal_op.proposed_ops.emplace_back(swu_op); - const auto &prev_sw = std::next(active_sw); - if (prev_sw != swi.rend()) { - 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()) { - sidechain_transaction_create_operation stc_op; - stc_op.payer = gpo.parameters.son_account(); - stc_op.object_id = prev_sw->id; - stc_op.sidechain = sidechain; - stc_op.transaction = tx_str; - stc_op.signers = prev_sw->sons; - proposal_op.proposed_ops.emplace_back(stc_op); - } - } + const auto &prev_sw = std::next(active_sw); + if (prev_sw != swi.rend()) { + 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()) { + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = prev_sw->id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = prev_sw->sons; + proposal_op.proposed_ops.emplace_back(stc_op); + } + } - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); - try { - trx.validate(); - database.push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - plugin.log_son_proposal_retry(chain::operation::tag::value, active_sw->id); - } catch (fc::exception &e) { - elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); - return; - } - } - } - } + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + plugin.log_son_proposal_retry(chain::operation::tag::value, active_sw->id); + } catch (fc::exception &e) { + elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); + return; + } + } + } + } } -void sidechain_net_handler_eth::process_sidechain_addresses() { - /* +void sidechain_net_handler_ethereum::process_sidechain_addresses() { + /* const chain::global_property_object &gpo = database.get_global_properties(); std::vector> pubkeys; for (auto &son : gpo.active_sons) { @@ -956,220 +954,220 @@ void sidechain_net_handler_eth::process_sidechain_addresses() { */ } -bool sidechain_net_handler_eth::process_deposit(const son_wallet_deposit_object &swdo) { - ilog("### process_deposit:"); +bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_object &swdo) { + ilog("### process_deposit:"); - if (proposal_exists(chain::operation::tag::value, swdo.id)) { - return false; - } + if (proposal_exists(chain::operation::tag::value, swdo.id)) { + return false; + } - std::string tx_str = create_deposit_transaction(swdo); + std::string tx_str = create_deposit_transaction(swdo); - if (!tx_str.empty()) { - const chain::global_property_object &gpo = database.get_global_properties(); + if (!tx_str.empty()) { + const chain::global_property_object &gpo = database.get_global_properties(); - proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; - uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - son_wallet_deposit_process_operation swdp_op; - swdp_op.payer = gpo.parameters.son_account(); - swdp_op.son_wallet_deposit_id = swdo.id; - proposal_op.proposed_ops.emplace_back(swdp_op); + son_wallet_deposit_process_operation swdp_op; + swdp_op.payer = gpo.parameters.son_account(); + swdp_op.son_wallet_deposit_id = swdo.id; + proposal_op.proposed_ops.emplace_back(swdp_op); - sidechain_transaction_create_operation stc_op; - stc_op.payer = gpo.parameters.son_account(); - stc_op.object_id = swdo.id; - stc_op.sidechain = sidechain; - stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons; - proposal_op.proposed_ops.emplace_back(stc_op); + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = swdo.id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = gpo.active_sons; + proposal_op.proposed_ops.emplace_back(stc_op); - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); - try { - trx.validate(); - database.push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - return true; - } catch (fc::exception &e) { - elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what())); - return false; - } - } - return false; + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + return true; + } catch (fc::exception &e) { + elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + return false; + } + } + return false; } -bool sidechain_net_handler_eth::process_withdrawal(const son_wallet_withdraw_object &swwo) { - ilog("### process_withdrawal:"); +bool sidechain_net_handler_ethereum::process_withdrawal(const son_wallet_withdraw_object &swwo) { + ilog("### process_withdrawal:"); - if (proposal_exists(chain::operation::tag::value, swwo.id)) { - return false; - } + if (proposal_exists(chain::operation::tag::value, swwo.id)) { + return false; + } - std::string tx_str = create_withdrawal_transaction(swwo); + std::string tx_str = create_withdrawal_transaction(swwo); - if (!tx_str.empty()) { - const chain::global_property_object &gpo = database.get_global_properties(); + if (!tx_str.empty()) { + const chain::global_property_object &gpo = database.get_global_properties(); - proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; - uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - son_wallet_withdraw_process_operation swwp_op; - swwp_op.payer = gpo.parameters.son_account(); - swwp_op.son_wallet_withdraw_id = swwo.id; - proposal_op.proposed_ops.emplace_back(swwp_op); + son_wallet_withdraw_process_operation swwp_op; + swwp_op.payer = gpo.parameters.son_account(); + swwp_op.son_wallet_withdraw_id = swwo.id; + proposal_op.proposed_ops.emplace_back(swwp_op); - sidechain_transaction_create_operation stc_op; - stc_op.payer = gpo.parameters.son_account(); - stc_op.object_id = swwo.id; - stc_op.sidechain = sidechain; - stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons; - proposal_op.proposed_ops.emplace_back(stc_op); + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = swwo.id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = gpo.active_sons; + proposal_op.proposed_ops.emplace_back(stc_op); - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); - try { - trx.validate(); - database.push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - return true; - } catch (fc::exception &e) { - elog("Sending proposal for withdraw sidechain transaction create operation failed with exception ${e}", ("e", e.what())); - return false; - } - } - return false; + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + return true; + } catch (fc::exception &e) { + elog("Sending proposal for withdraw sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + return false; + } + } + return false; } -std::string sidechain_net_handler_eth::process_sidechain_transaction(const sidechain_transaction_object &sto) { - ilog("### process_sidechain_transaction: "); - return sign_transaction(sto); +std::string sidechain_net_handler_ethereum::process_sidechain_transaction(const sidechain_transaction_object &sto) { + ilog("### process_sidechain_transaction: "); + return sign_transaction(sto); } -std::string sidechain_net_handler_eth::send_sidechain_transaction(const sidechain_transaction_object &sto) { - ilog("### send_sidechain_transaction: "); - return send_transaction(sto); +std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sidechain_transaction_object &sto) { + ilog("### send_sidechain_transaction: "); + return send_transaction(sto); } -bool sidechain_net_handler_eth::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) { - return false; +bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) { + return false; } -std::vector sidechain_net_handler_eth::parse_hex(const std::string &str) { - std::vector vec(str.size() / 2); - fc::from_hex(str, vec.data(), vec.size()); - return vec; +std::vector sidechain_net_handler_ethereum::parse_hex(const std::string &str) { + std::vector vec(str.size() / 2); + fc::from_hex(str, vec.data(), vec.size()); + return vec; } -std::string sidechain_net_handler_eth::create_primary_wallet_address(const std::vector &son_pubkeys) { - std::stringstream ss; +std::string sidechain_net_handler_ethereum::create_primary_wallet_address(const std::vector &son_pubkeys) { + std::stringstream ss; - ss << "{\"result\": {\"address\": \"" << eth_client->safe_account_addr << "\"" << "}, "; - ss << "\"onwers\": ["; - for (auto &owner : eth_client->owners){ - ss << "\"" << owner << "\","; - } - ss.seekp(-1, std::ios_base::end); - ss << "], keys: ["; + ss << "{\"result\": {\"address\": \"" << eth_client->safe_account_addr << "\"" + << "}, "; + ss << "\"onwers\": ["; + for (auto &owner : eth_client->owners) { + ss << "\"" << owner << "\","; + } + ss.seekp(-1, std::ios_base::end); + ss << "], keys: ["; - for (auto &son : son_pubkeys) { - std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); - ss << "\"" << pub_key_str << "\","; - } - ss.seekp(-1, std::ios_base::end); - ss << "], "; + for (auto &son : son_pubkeys) { + std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); + ss << "\"" << pub_key_str << "\","; + } + ss.seekp(-1, std::ios_base::end); + ss << "], "; - ss << "\"error\":null}"; + ss << "\"error\":null}"; - std::string res = ss.str(); - return res; + std::string res = ss.str(); + return res; } -std::string sidechain_net_handler_eth::create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address) { - return "";//create_transaction(inputs, outputs, prev_redeem_script); +std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address) { + return ""; //create_transaction(inputs, outputs, prev_redeem_script); } -std::string sidechain_net_handler_eth::create_deposit_transaction(const son_wallet_deposit_object &swdo) { - return "";//create_transaction(inputs, outputs, redeem_script); +std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) { + return ""; //create_transaction(inputs, outputs, redeem_script); } -std::string sidechain_net_handler_eth::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { - return "";//create_transaction(inputs, outputs, redeem_script); +std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { + return ""; //create_transaction(inputs, outputs, redeem_script); } -std::string sidechain_net_handler_eth::create_transaction() { - std::string tx_raw;// = write_transaction_data(hex_tx, in_amounts, redeem_script); - return tx_raw; +std::string sidechain_net_handler_ethereum::create_transaction() { + std::string tx_raw; // = write_transaction_data(hex_tx, in_amounts, redeem_script); + return tx_raw; } -std::string sidechain_net_handler_eth::sign_transaction(const sidechain_transaction_object &sto) { - ilog("### sign_transaction: "); +std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) { + ilog("### sign_transaction: "); - std::stringstream ss_trx(boost::algorithm::unhex(sto.transaction)); - ethereum::signed_transaction htrx; - fc::raw::unpack(ss_trx, htrx, 1000); + std::stringstream ss_trx(boost::algorithm::unhex(sto.transaction)); + ethereum::signed_transaction htrx; + fc::raw::unpack(ss_trx, htrx, 1000); - std::string chain_id_str = eth_client->chain_id;//eth_rpc_client->get_chain_id(); - const ethereum::chain_id_type chain_id(chain_id_str); + std::string chain_id_str = eth_client->chain_id; //eth_rpc_client->get_chain_id(); + const ethereum::chain_id_type chain_id(chain_id_str); - fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))); - signature_type st = htrx.sign(*privkey, chain_id); - - std::stringstream ss_st; - fc::raw::pack(ss_st, st, 1000); - std::string st_str = boost::algorithm::hex(ss_st.str()); - return st_str; + fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))); + signature_type st = htrx.sign(*privkey, chain_id); + std::stringstream ss_st; + fc::raw::pack(ss_st, st, 1000); + std::string st_str = boost::algorithm::hex(ss_st.str()); + return st_str; } -std::string sidechain_net_handler_eth::send_transaction(const sidechain_transaction_object &sto) { - std::string res;// = eth_client->sendrawtransaction(final_tx_hex); +std::string sidechain_net_handler_ethereum::send_transaction(const sidechain_transaction_object &sto) { + std::string res; // = eth_client->sendrawtransaction(final_tx_hex); - return res; + return res; } -void sidechain_net_handler_eth::handle_event(const std::string &event_data) { +void sidechain_net_handler_ethereum::handle_event(const std::string &event_data) { } -std::vector sidechain_net_handler_eth::extract_info_from_block(const std::string &_block) { - std::stringstream ss(_block); - boost::property_tree::ptree block; - boost::property_tree::read_json(ss, block); +std::vector sidechain_net_handler_ethereum::extract_info_from_block(const std::string &_block) { + std::stringstream ss(_block); + boost::property_tree::ptree block; + boost::property_tree::read_json(ss, block); - std::vector result; + std::vector result; - return result; + return result; } -void sidechain_net_handler_eth::on_changed_objects(const vector &ids, const flat_set &accounts) { - ilog("### on_changed_objects: "); +void sidechain_net_handler_ethereum::on_changed_objects(const vector &ids, const flat_set &accounts) { + ilog("### on_changed_objects: "); - fc::time_point now = fc::time_point::now(); - int64_t time_to_next_changed_objects_processing = 5000; + fc::time_point now = fc::time_point::now(); + int64_t time_to_next_changed_objects_processing = 5000; - fc::time_point next_wakeup(now + fc::microseconds(time_to_next_changed_objects_processing)); + fc::time_point next_wakeup(now + fc::microseconds(time_to_next_changed_objects_processing)); - on_changed_objects_task = fc::schedule([this, ids, accounts] { - on_changed_objects_cb(ids, accounts); - }, - next_wakeup, "SON Processing"); + on_changed_objects_task = fc::schedule([this, ids, accounts] { + on_changed_objects_cb(ids, accounts); + }, + next_wakeup, "SON Processing"); } -void sidechain_net_handler_eth::on_changed_objects_cb(const vector &ids, const flat_set &accounts) { +void sidechain_net_handler_ethereum::on_changed_objects_cb(const vector &ids, const flat_set &accounts) { } -fc::ecc::public_key_data sidechain_net_handler_eth::create_public_key_data(const std::vector &public_key) { - FC_ASSERT(public_key.size() == 33); - fc::ecc::public_key_data key; - for (size_t i = 0; i < 33; i++) { - key.at(i) = public_key[i]; - } - return key; +fc::ecc::public_key_data sidechain_net_handler_ethereum::create_public_key_data(const std::vector &public_key) { + FC_ASSERT(public_key.size() == 33); + fc::ecc::public_key_data key; + for (size_t i = 0; i < 33; i++) { + key.at(i) = public_key[i]; + } + return key; } // ============================================================================= -- 2.45.2 From da46b165601dee2e8d1a6429618c5b59b9617415 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Tue, 28 Jun 2022 23:55:19 +0200 Subject: [PATCH 25/60] WIP: Major refactoring of Ethereum sidechain handler --- .../peerplays_sidechain/ethereum/decoders.cpp | 5 + .../peerplays_sidechain/ethereum/encoders.cpp | 5 + .../ethereum/transaction.cpp | 57 +- .../peerplays_sidechain/ethereum/types.cpp | 68 -- .../peerplays_sidechain/ethereum/asset.hpp | 41 - .../ethereum/authority.hpp | 33 - .../peerplays_sidechain/ethereum/decoders.hpp | 5 + .../peerplays_sidechain/ethereum/encoders.hpp | 36 + .../ethereum/ethereum_operations.hpp | 123 --- .../ethereum/operations.hpp | 69 -- .../ethereum/transaction.hpp | 177 ++-- .../peerplays_sidechain/ethereum/types.hpp | 68 +- .../sidechain_net_handler_ethereum.hpp | 241 +---- .../peerplays_sidechain_plugin.cpp | 16 +- .../sidechain_net_handler_ethereum.cpp | 995 ++---------------- .../sidechain_net_handler_hive.cpp | 2 - 16 files changed, 276 insertions(+), 1665 deletions(-) create mode 100644 libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp create mode 100644 libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp delete mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/asset.hpp delete mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/authority.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/decoders.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp delete mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/ethereum_operations.hpp delete mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp diff --git a/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp new file mode 100644 index 00000000..2ebf3380 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp @@ -0,0 +1,5 @@ +#include #include < graphene / peerplays_sidechain / ethereum / decoders.hpp> + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +}}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp new file mode 100644 index 00000000..e2db7e9f --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -0,0 +1,5 @@ +#include #include < graphene / peerplays_sidechain / ethereum / encoders.hpp> + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +}}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index f952dadd..9bf3bf02 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -1,57 +1,22 @@ #include -#include - -#include -#include - namespace graphene { namespace peerplays_sidechain { namespace ethereum { -digest_type transaction::digest() const { - digest_type::encoder enc; - fc::raw::pack(enc, *this); - return enc.result(); +std::string transaction::sign(std::string private_key) { + v = "signed"; + r = "transaction"; + s = "signed-transaction"; + return v + "|" + r + "|" + s; } -transaction_id_type transaction::id() const { - auto h = digest(); - transaction_id_type result; - memcpy(result._hash, h._hash, std::min(sizeof(result), sizeof(h))); - return result; +std::string transaction::serialize() { + return "serialized-transaction"; } -digest_type transaction::sig_digest(const chain_id_type &chain_id) const { - digest_type::encoder enc; - fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, *this); - return enc.result(); -} - -void transaction::set_expiration(fc::time_point_sec expiration_time) { - expiration = expiration_time; -} - -void transaction::set_reference_block(const block_id_type &reference_block) { - ref_block_num = fc::endian_reverse_u32(reference_block._hash[0]); - ref_block_prefix = reference_block._hash[1]; -} - -void signed_transaction::clear() { - operations.clear(); - signatures.clear(); -} - -const signature_type &signed_transaction::sign(const ethereum::private_key_type &key, const ethereum::chain_id_type &chain_id) { - digest_type h = sig_digest(chain_id); - signatures.push_back(key.sign_compact(h, true)); - return signatures.back(); -} - -signature_type signed_transaction::sign(const ethereum::private_key_type &key, const ethereum::chain_id_type &chain_id) const { - digest_type::encoder enc; - fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, *this); - return key.sign_compact(enc.result(), true); +void transaction::deserialize(std::string raw_tx) { + block_hash = "1"; + block_number = "2"; + hash = "3"; } }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/types.cpp b/libraries/plugins/peerplays_sidechain/ethereum/types.cpp index 7a62cc58..f85d0e61 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/types.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/types.cpp @@ -1,73 +1,5 @@ #include -#include -#include -#include -#include - namespace graphene { namespace peerplays_sidechain { namespace ethereum { -std::string public_key_type::prefix = KEY_PREFIX_STM; - -public_key_type::public_key_type() : - key_data(){}; - -public_key_type::public_key_type(const fc::ecc::public_key_data &data) : - key_data(data){}; - -public_key_type::public_key_type(const fc::ecc::public_key &pubkey) : - key_data(pubkey){}; - -public_key_type::public_key_type(const std::string &base58str) { - const size_t prefix_len = prefix.size(); - FC_ASSERT(base58str.size() > prefix_len); - FC_ASSERT(base58str.substr(0, prefix_len) == prefix, "", ("base58str", base58str)); - auto bin = fc::from_base58(base58str.substr(prefix_len)); - auto bin_key = fc::raw::unpack(bin); - key_data = bin_key.data; - FC_ASSERT(fc::ripemd160::hash(key_data.data, key_data.size())._hash[0] == bin_key.check); -}; - -public_key_type::operator fc::ecc::public_key_data() const { - return key_data; -}; - -public_key_type::operator fc::ecc::public_key() const { - return fc::ecc::public_key(key_data); -}; - -public_key_type::operator std::string() const { - binary_key k; - k.data = key_data; - k.check = fc::ripemd160::hash(k.data.data, k.data.size())._hash[0]; - auto data = fc::raw::pack(k); - return prefix + fc::to_base58(data.data(), data.size()); -} - -bool operator==(const public_key_type &p1, const fc::ecc::public_key &p2) { - return p1.key_data == p2.serialize(); -} - -bool operator==(const public_key_type &p1, const public_key_type &p2) { - return p1.key_data == p2.key_data; -} - -bool operator!=(const public_key_type &p1, const public_key_type &p2) { - return p1.key_data != p2.key_data; -} - }}} // namespace graphene::peerplays_sidechain::ethereum - -namespace fc { - -using namespace std; - -void to_variant(const graphene::peerplays_sidechain::ethereum::public_key_type &var, fc::variant &vo, uint32_t max_depth) { - vo = std::string(var); -} - -void from_variant(const fc::variant &var, graphene::peerplays_sidechain::ethereum::public_key_type &vo, uint32_t max_depth) { - vo = graphene::peerplays_sidechain::ethereum::public_key_type(var.as_string()); -} - -} // namespace fc diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/asset.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/asset.hpp deleted file mode 100644 index 05aed34f..00000000 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/asset.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -namespace graphene { namespace peerplays_sidechain { namespace ethereum { - -#define HBD_NAI "@@000000013" -#define HBD_PRECISION 3 -#define HBD_SYMBOL_U64 (uint64_t('S') | (uint64_t('B') << 8) | (uint64_t('D') << 16)) -#define HBD_SYMBOL_SER (uint64_t(3) | (HBD_SYMBOL_U64 << 8)) - -#define HIVE_NAI "@@000000021" -#define HIVE_PRECISION 3 -#define HIVE_SYMBOL_U64 (uint64_t('S') | (uint64_t('T') << 8) | (uint64_t('E') << 16) | (uint64_t('E') << 24) | (uint64_t('M') << 32)) -#define HIVE_SYMBOL_SER (uint64_t(3) | (HIVE_SYMBOL_U64 << 8)) - -#define TBD_NAI "@@000000013" -#define TBD_PRECISION 3 -#define TBD_SYMBOL_U64 (uint64_t('T') | (uint64_t('B') << 8) | (uint64_t('D') << 16)) -#define TBD_SYMBOL_SER (uint64_t(3) | (TBD_SYMBOL_U64 << 8)) - -#define TESTS_NAI "@@000000021" -#define TESTS_PRECISION 3 -#define TESTS_SYMBOL_U64 (uint64_t('T') | (uint64_t('E') << 8) | (uint64_t('S') << 16) | (uint64_t('T') << 24) | (uint64_t('S') << 32)) -#define TESTS_SYMBOL_SER (uint64_t(3) | (TESTS_SYMBOL_U64 << 8)) - -struct asset { - static uint64_t hbd_symbol_ser; - static uint64_t ethereum_symbol_ser; - share_type amount; - uint64_t symbol; -}; - -}}} // namespace graphene::peerplays_sidechain::ethereum - -namespace fc { -void to_variant(const graphene::peerplays_sidechain::ethereum::asset &var, fc::variant &vo, uint32_t max_depth); -void from_variant(const fc::variant &var, graphene::peerplays_sidechain::ethereum::asset &vo, uint32_t max_depth); -} // namespace fc - -FC_REFLECT(graphene::peerplays_sidechain::ethereum::asset, (amount)(symbol)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/authority.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/authority.hpp deleted file mode 100644 index d4d5455f..00000000 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/authority.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -#include - -#include - -namespace graphene { namespace peerplays_sidechain { namespace ethereum { - -struct authority { - authority() { - } - - enum classification { - owner = 0, - active = 1, - key = 2, - posting = 3 - }; - - uint32_t weight_threshold = 0; - fc::flat_map account_auths; - fc::flat_map key_auths; -}; - -}}} // namespace graphene::peerplays_sidechain::ethereum - -FC_REFLECT_ENUM(graphene::peerplays_sidechain::ethereum::authority::classification, - (owner)(active)(key)(posting)) - -FC_REFLECT(graphene::peerplays_sidechain::ethereum::authority, - (weight_threshold)(account_auths)(key_auths)) 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 new file mode 100644 index 00000000..964ee4a9 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/decoders.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +}}} // namespace graphene::peerplays_sidechain::ethereum 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 new file mode 100644 index 00000000..8db8d59f --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp @@ -0,0 +1,36 @@ +#pragma once + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +class ethereum_function_call_encoder { +public: + enum operation_t { + OPERATION_CALL, + OPERATION_DELEGATE_CALL + }; + + static constexpr const char *const default_prev_addr = "0000000000000000000000000000000000000001"; + + std::string encode_function_signature(const std::string &function_signature); + std::string encode_address(const std::string &addr); + std::string encode_uint256(const std::string &value); + std::string encode_uint8(uint8_t value); + std::string encode_bytes(const std::string &values); +}; + +class safe_transaction_encoder { +public: + static constexpr const char *const default_safe_tx_gas = "0"; + static constexpr const char *const default_data_gas = "0"; + static constexpr const char *const default_gas_price = "0"; + static constexpr const char *const default_gas_token = "0000000000000000000000000000000000000000"; + static constexpr const char *const default_refund_receiver = "0000000000000000000000000000000000000000"; + + std::string create_safe_address(const std::vector &owner_addresses, uint32_t threshold); + std::string build_transaction(const std::string &safe_account_addr, const std::string &value, const std::string &data, uint8_t operation, const std::string &safeTxGas, const std::string &dataGas, const std::string &gasPrice, const std::string &gasToken, const std::string &refundReceiver); + +private: + ethereum_function_call_encoder m_ethereum_function_call_encoder; +}; + +}}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/ethereum_operations.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/ethereum_operations.hpp deleted file mode 100644 index 4b8a7399..00000000 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/ethereum_operations.hpp +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include -#include -#include -#include - -namespace graphene { namespace peerplays_sidechain { namespace ethereum { - -struct vote_operation {}; -struct comment_operation {}; - -struct transfer_operation { - ethereum::account_name_type from; - ethereum::account_name_type to; - ethereum::asset amount; - std::string memo; -}; - -struct transfer_to_vesting_operation {}; -struct withdraw_vesting_operation {}; -struct limit_order_create_operation {}; -struct limit_order_cancel_operation {}; -struct feed_publish_operation {}; -struct convert_operation {}; -struct account_create_operation {}; - -struct account_update_operation { - ethereum::account_name_type account; - fc::optional owner; - fc::optional active; - fc::optional posting; - ethereum::public_key_type memo_key; - std::string json_metadata; -}; - -struct witness_update_operation {}; -struct account_witness_vote_operation {}; -struct account_witness_proxy_operation {}; -struct pow_operation {}; -struct custom_operation {}; -struct report_over_production_operation {}; -struct delete_comment_operation {}; -struct custom_json_operation {}; -struct comment_options_operation {}; -struct set_withdraw_vesting_route_operation {}; -struct limit_order_create2_operation {}; -struct claim_account_operation {}; -struct create_claimed_account_operation {}; -struct request_account_recovery_operation {}; -struct recover_account_operation {}; -struct change_recovery_account_operation {}; -struct escrow_transfer_operation {}; -struct escrow_dispute_operation {}; -struct escrow_release_operation {}; -struct pow2_operation {}; -struct escrow_approve_operation {}; -struct transfer_to_savings_operation {}; -struct transfer_from_savings_operation {}; -struct cancel_transfer_from_savings_operation {}; -struct custom_binary_operation {}; -struct decline_voting_rights_operation {}; -struct reset_account_operation {}; -struct set_reset_account_operation {}; -struct claim_reward_balance_operation {}; - -struct delegate_vesting_shares_operation { - ethereum::account_name_type delegator; - ethereum::account_name_type delegatee; - ethereum::asset vesting_shares; -}; - -}}} // namespace graphene::peerplays_sidechain::ethereum - -FC_REFLECT(graphene::peerplays_sidechain::ethereum::vote_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::comment_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::transfer_operation, - (from)(to)(amount)(memo)) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::transfer_to_vesting_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::withdraw_vesting_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::limit_order_create_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::limit_order_cancel_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::feed_publish_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::convert_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::account_create_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::account_update_operation, - (account)(owner)(active)(posting)(memo_key)(json_metadata)) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::witness_update_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::account_witness_vote_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::account_witness_proxy_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::pow_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::custom_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::report_over_production_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::delete_comment_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::custom_json_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::comment_options_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::set_withdraw_vesting_route_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::limit_order_create2_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::claim_account_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::create_claimed_account_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::request_account_recovery_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::recover_account_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::change_recovery_account_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::escrow_transfer_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::escrow_dispute_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::escrow_release_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::pow2_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::escrow_approve_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::transfer_to_savings_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::transfer_from_savings_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::cancel_transfer_from_savings_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::custom_binary_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::decline_voting_rights_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::reset_account_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::set_reset_account_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::claim_reward_balance_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::delegate_vesting_shares_operation, - (delegator)(delegatee)(vesting_shares)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp deleted file mode 100644 index e178b56d..00000000 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include - -namespace graphene { namespace peerplays_sidechain { namespace ethereum { - -typedef fc::static_variant< - vote_operation, - comment_operation, - - transfer_operation, - transfer_to_vesting_operation, - withdraw_vesting_operation, - - limit_order_create_operation, - limit_order_cancel_operation, - - feed_publish_operation, - convert_operation, - - account_create_operation, - account_update_operation, - - witness_update_operation, - account_witness_vote_operation, - account_witness_proxy_operation, - - pow_operation, - - custom_operation, - - report_over_production_operation, - - delete_comment_operation, - custom_json_operation, - comment_options_operation, - set_withdraw_vesting_route_operation, - limit_order_create2_operation, - claim_account_operation, - create_claimed_account_operation, - request_account_recovery_operation, - recover_account_operation, - change_recovery_account_operation, - escrow_transfer_operation, - escrow_dispute_operation, - escrow_release_operation, - pow2_operation, - escrow_approve_operation, - transfer_to_savings_operation, - transfer_from_savings_operation, - cancel_transfer_from_savings_operation, - custom_binary_operation, - decline_voting_rights_operation, - reset_account_operation, - set_reset_account_operation, - claim_reward_balance_operation, - delegate_vesting_shares_operation> - ethereum_operation; - -}}} // namespace graphene::peerplays_sidechain::ethereum - -namespace fc { - -void to_variant(const graphene::peerplays_sidechain::ethereum::ethereum_operation &var, fc::variant &vo, uint32_t max_depth = 5); -void from_variant(const fc::variant &var, graphene::peerplays_sidechain::ethereum::ethereum_operation &vo, uint32_t max_depth = 5); - -} // namespace fc - -FC_REFLECT_TYPENAME(graphene::peerplays_sidechain::ethereum::ethereum_operation) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp index ae154a36..1ce9497e 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp @@ -1,86 +1,123 @@ #pragma once #include +#include #include -#include -#include - -#include -#include -#include - namespace graphene { namespace peerplays_sidechain { namespace ethereum { -typedef fc::ecc::private_key private_key_type; -typedef fc::sha256 chain_id_type; class transaction { public: - uint16_t ref_block_num = 0; - uint32_t ref_block_prefix = 0; - fc::time_point_sec expiration; - std::vector operations; - extensions_type extensions; + std::string block_hash; + std::string block_number; + std::string from; + std::string gas; + std::string gas_price; + std::string max_fee_per_gas; + std::string max_priority_fee_per_gas; + std::string hash; + std::string input; + std::string nonce; + std::string to; + std::string transaction_index; + std::string value; + std::string type; + std::vector access_list; + std::string chain_id; + std::string v; + std::string r; + std::string s; - digest_type digest() const; - transaction_id_type id() const; - digest_type sig_digest(const chain_id_type &chain_id) const; + std::string sign(std::string private_key); - void set_expiration(fc::time_point_sec expiration_time); - void set_reference_block(const block_id_type &reference_block); - - /* - /// Serialises this transaction to an RLPStream. - /// @throws TransactionIsUnsigned if including signature was requested but it was not initialized - void streamRLP(RLPStream& _s, IncludeSignature _sig = WithSignature, bool _forEip155hash = false) const; - - /// @returns the RLP serialisation of this transaction. - bytes rlp(IncludeSignature _sig = WithSignature) const { RLPStream s; streamRLP(s, _sig); return s.out(); } -protected: - /// Type of transaction. - enum Type - { - NullTransaction, ///< Null transaction. - ContractCreation, ///< Transaction to create contracts - receiveAddress() is ignored. - MessageCall ///< Transaction to invoke a message call - receiveAddress() is used. - }; - - static bool isZeroSignature(u256 const& _r, u256 const& _s) { return !_r && !_s; } - - /// Clears the signature. - void clearSignature() { m_vrs = SignatureStruct(); } - - Type m_type = NullTransaction; ///< Is this a contract-creation transaction or a message-call transaction? - u256 m_nonce; ///< The transaction-count of the sender. - u256 m_value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. - Address m_receiveAddress; ///< The receiving address of the transaction. - u256 m_gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. - u256 m_gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. - bytes m_data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. - boost::optional m_vrs; ///< The signature of the transaction. Encodes the sender. - /// EIP155 value for calculating transaction hash - /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md - boost::optional m_chainId; - - mutable h256 m_hashWith; ///< Cached hash of transaction with signature. - mutable boost::optional
m_sender; ///< Cached sender, determined from signature. -*/ -}; - -class signed_transaction : public transaction { -public: - std::vector signatures; - - const signature_type &sign(const ethereum::private_key_type &key, const ethereum::chain_id_type &chain_id); - signature_type sign(const ethereum::private_key_type &key, const ethereum::chain_id_type &chain_id) const; - void clear(); + std::string serialize(); + void deserialize(std::string raw_tx); }; }}} // namespace graphene::peerplays_sidechain::ethereum -FC_REFLECT(graphene::peerplays_sidechain::ethereum::transaction, - (ref_block_num)(ref_block_prefix)(expiration)(operations)(extensions)) +// Example 1 +//{ +// "blockHash": "0x64a6706ecaf5a97b7f3e047abb20ff223ce82c6994d80e68fdb1fdfb38d0209c", +// "blockNumber": "0xe5827c", +// "from": "0x8614c67e085f2334010f2a28e806c6f1cc176d12", +// "gas": "0x38822", +// "gasPrice": "0xce42cba69", +// "maxFeePerGas": "0xddb4d8d16", +// "maxPriorityFeePerGas": "0x3b9aca00", +// "hash": "0xeac92ea09fa8eb3ca2fb0d156cceb38ae69d4345869d41e8e49d5ecbcbb622dc", +// "input": "0x5ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde03121500000000000000000000000000000000000000000000000000000000", +// "nonce": "0x32", +// "to": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45", +// "transactionIndex": "0xb6", +// "value": "0x2514d9d7d7d8000", +// "type": "0x2", +// "accessList": [], +// "chainId": "0x1", +// "v": "0x1", +// "r": "0x2f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28c", +// "s": "0x782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14" +//} +// +//"0xf9021332850ce42cba69830388229468b3465833fb72a70ecdf485e0e4c7bd8665fc458802514d9d7d7d8000b901a45ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde0312150000000000000000000000000000000000000000000000000000000001a02f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28ca0782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14" +// +//{ +// "nonce": 50, +// "gasPrice": { +// "_hex": "0x0ce42cba69" +// }, +// "gasLimit": { +// "_hex": "0x038822" +// }, +// "to": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45", +// "value": { +// "_hex": "0x02514d9d7d7d8000" +// }, +// "data": "0x5ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde03121500000000000000000000000000000000000000000000000000000000", +// "v": 1, +// "r": "0x2f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28c", +// "s": "0x782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14" +//} -FC_REFLECT_DERIVED(graphene::peerplays_sidechain::ethereum::signed_transaction, - (graphene::peerplays_sidechain::ethereum::transaction), - (signatures)) +// Example 2 +//{ +// "blockHash": "0xe2ae3afd86dc7343c7fb753441447a0a51bb19499325ad6e278256f0cd1b5894", +// "blockNumber": "0xe58271", +// "from": "0xb895ade6d337fbb8cb97f2ea7da43106c7f5cc26", +// "gas": "0x5208", +// "gasPrice": "0xe6f3b322e", +// "maxFeePerGas": "0x1322455fd3", +// "maxPriorityFeePerGas": "0x53724e00", +// "hash": "0xed29b56e52ad2d452e25b8ec70c37f59d935cd6d0f8fe8e83b256f3ffdfd3fce", +// "input": "0x", +// "nonce": "0x37", +// "to": "0x176386b6ffc469ac049f9ec1f6cc0efd1d09b373", +// "transactionIndex": "0x8a", +// "value": "0x4563918244f40000", +// "type": "0x2", +// "accessList": [], +// "chainId": "0x1", +// "v": "0x0", +// "r": "0xdcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4c", +// "s": "0x28c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a" +//} +// +//"0xf86c37850e6f3b322e82520894176386b6ffc469ac049f9ec1f6cc0efd1d09b373884563918244f400008000a0dcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4ca028c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a" +// +//{ +// "nonce": 55, +// "gasPrice": { +// "_hex": "0x0e6f3b322e" +// }, +// "gasLimit": { +// "_hex": "0x5208" +// }, +// "to": "0x176386b6ffc469ac049f9ec1f6cc0efd1d09b373", +// "value": { +// "_hex": "0x4563918244f40000" +// }, +// "data": "0x", +// "v": 0, +// "r": "0xdcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4c", +// "s": "0x28c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a" +//} diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp index f8a06c6c..def91947 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp @@ -1,72 +1,10 @@ #pragma once -#include -#include +#include namespace graphene { namespace peerplays_sidechain { namespace ethereum { -#define KEY_PREFIX_STM "STM" -#define KEY_PREFIX_TST "TST" - -enum network { - mainnet, - testnet -}; - -struct void_t {}; - -typedef fc::static_variant future_extensions; -typedef fc::flat_set extensions_type; - -typedef fc::ecc::private_key private_key_type; -typedef fc::sha256 chain_id_type; -typedef std::string account_name_type; -typedef fc::ripemd160 block_id_type; -//typedef fc::ripemd160 checksum_type; -typedef fc::ripemd160 transaction_id_type; -typedef fc::sha256 digest_type; -typedef fc::ecc::compact_signature signature_type; -typedef fc::safe share_type; -//typedef safe ushare_type; -//typedef uint16_t weight_type; -//typedef uint32_t contribution_id_type; -//typedef fixed_string<32> custom_id_type; - -struct public_key_type { - - static std::string prefix; - - struct binary_key { - binary_key() { - } - uint32_t check = 0; - fc::ecc::public_key_data data; - }; - fc::ecc::public_key_data key_data; - public_key_type(); - public_key_type(const fc::ecc::public_key_data &data); - public_key_type(const fc::ecc::public_key &pubkey); - explicit public_key_type(const std::string &base58str); - operator fc::ecc::public_key_data() const; - operator fc::ecc::public_key() const; - explicit operator std::string() const; - friend bool operator==(const public_key_type &p1, const fc::ecc::public_key &p2); - friend bool operator==(const public_key_type &p1, const public_key_type &p2); - friend bool operator<(const public_key_type &p1, const public_key_type &p2) { - return p1.key_data < p2.key_data; - } - friend bool operator!=(const public_key_type &p1, const public_key_type &p2); -}; +typedef uint64_t chain_id_type; +typedef uint64_t network_id_type; }}} // namespace graphene::peerplays_sidechain::ethereum - -namespace fc { -void to_variant(const graphene::peerplays_sidechain::ethereum::public_key_type &var, fc::variant &vo, uint32_t max_depth = 2); -void from_variant(const fc::variant &var, graphene::peerplays_sidechain::ethereum::public_key_type &vo, uint32_t max_depth = 2); -} // namespace fc - -FC_REFLECT(graphene::peerplays_sidechain::ethereum::public_key_type, (key_data)) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::public_key_type::binary_key, (data)(check)) - -FC_REFLECT(graphene::peerplays_sidechain::ethereum::void_t, ) -FC_REFLECT_TYPENAME(graphene::peerplays_sidechain::ethereum::future_extensions) 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 3bef8610..d8662d2a 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 @@ -3,220 +3,26 @@ #include #include -#include #include -#include - #include - -#include -#include - -#include -#include - -#include - -#include - -using namespace boost::multiprecision::literals; -using u256 = boost::multiprecision::number>; -using s256 = boost::multiprecision::number>; -u256 constexpr Invalid256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_cppui256; -using byte = uint8_t; -using bytes = std::vector; +#include +#include namespace graphene { namespace peerplays_sidechain { -typedef websocketpp::client client; - -using websocketpp::lib::bind; -using websocketpp::lib::placeholders::_1; -using websocketpp::lib::placeholders::_2; - -// pull out the type of messages sent by our config -typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr; -typedef websocketpp::lib::shared_ptr context_ptr; -typedef client::connection_ptr connection_ptr; - -class eth_rpc_client { +class ethereum_node_rpc_client : public rpc_client { public: - typedef eth_rpc_client type; + ethereum_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); - enum req_t { - ETH_CHAIN_ID, - ETH_GET_TRANSACTION_RECEIPT, - ETH_CALL, - ETH_SEND_TRANSACTION, - ETH_SEND_RAW_TRANSACTION, - ETH_GET_CODE, - ETH_GET_BALANCE, - ETH_SIGN, - ETH_COINBASE, - GET_LIST_OWNERS, - ADD_OWNER, - REMOVE_OWNER - }; + std::string admin_node_info(); + std::string net_version(); - enum class multi_type { - script, - address - }; - struct multi_params { - multi_params(multi_type _type, const std::string &_address_or_script, const std::string &_label = "") : - type{_type}, - address_or_script{_address_or_script}, - label{_label} { - } - - multi_type type; - std::string address_or_script; - std::string label; - }; - - eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); - - void start(); - void stop(); - void on_socket_init(websocketpp::connection_hdl); - void on_fail(websocketpp::connection_hdl hdl); - void on_open(websocketpp::connection_hdl hdl); - void on_message(websocketpp::connection_hdl hdl, message_ptr msg); - void on_close(websocketpp::connection_hdl); - - uint64_t get_chain_id(); - uint64_t eth_getTransactionReceipt(const std::string &tx_id); - uint64_t eth_call(const std::string &to, const std::string &data); - uint64_t eth_sendTransaction(const std::string &from, const std::string &to, const std::string &data); - uint64_t eth_sendRawTransaction(const std::string ¶ms); - uint64_t eth_getCode(const std::string &addr); - uint64_t eth_getBalance(const std::string &addr); - uint64_t eth_sign(const string &addr, const string &message); - uint64_t eth_coinbase(); - - uint64_t get_list_owners(const std::string &safe_account); - uint64_t add_owner(const std::string &addr); - uint64_t remove_owner(const std::string &addr, uint32_t threshold); - - std::string addmultisigaddress(const uint32_t nrequired, const std::vector public_keys); - std::string combinepsbt(const vector &psbts); - - uint64_t createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key); - - std::string createpsbt(); - std::string createrawtransaction(); - std::string createwallet(const std::string &wallet_name); - std::string decodepsbt(std::string const &tx_psbt); - std::string decoderawtransaction(std::string const &tx_hex); - std::string encryptwallet(const std::string &passphrase); - uint64_t estimatesmartfee(uint16_t conf_target = 128); - std::string finalizepsbt(std::string const &tx_psbt); - std::string getaddressinfo(const std::string &address); - 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(); - std::string gettransaction(const std::string &txid, const bool include_watch_only = false); - std::string getblockchaininfo(); - void importaddress(const std::string &address_or_script, const std::string &label = "", const bool rescan = true, const bool p2sh = false); - void importmulti(const std::vector &address_or_script_array, const bool rescan = true); - std::string loadwallet(const std::string &filename); - std::string sendrawtransaction(const std::string &tx_hex); - std::string signrawtransactionwithwallet(const std::string &tx_hash); - std::string unloadwallet(const std::string &filename); - std::string walletlock(); - std::string walletprocesspsbt(std::string const &tx_psbt); - bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); - - std::string chain_id; //256 bit value - std::vector owners; - std::string safe_account_addr; - -private: - /// Encodes an Ethereum transaction for exporting in JSON - class Transaction { - public: - /// JSON serialization - std::string serialize(const std::string &from, const std::string &to, const std::string &tx_id, u256 const &_value, u256 const &_gasPrice, u256 const &_gas, bytes const &_data, u256 const &_nonce = Invalid256); - - protected: - /// Type of transaction. - enum Type { - NullTransaction, ///< Null transaction. - ContractCreation, ///< Transaction to create contracts - receiveAddress() is ignored. - MessageCall ///< Transaction to invoke a message call - receiveAddress() is used. - }; - - Type m_type = NullTransaction; ///< Is this a contract-creation transaction or a message-call transaction? - u256 m_nonce; ///< The transaction-count of the sender. - u256 m_value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. - u256 m_gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. - u256 m_gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. - bytes m_data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. - }; - - class ethereum_function_call_encoder { - public: - enum operation_t { - OPERATION_CALL, - OPERATION_DELEGATE_CALL - }; - - static constexpr const char *const default_prev_addr = "0000000000000000000000000000000000000001"; - - std::string encode_function_signature(const std::string &function_signature); - std::string encode_address(const std::string &addr); - std::string encode_uint256(const std::string &value); - std::string encode_uint8(uint8_t value); - std::string encode_bytes(const std::string &values); - }; - - class safe_transaction_encoder { - public: - static constexpr const char *const default_safe_tx_gas = "0"; - static constexpr const char *const default_data_gas = "0"; - static constexpr const char *const default_gas_price = "0"; - static constexpr const char *const default_gas_token = "0000000000000000000000000000000000000000"; - static constexpr const char *const default_refund_receiver = "0000000000000000000000000000000000000000"; - - std::string create_safe_address(const std::vector &owner_addresses, uint32_t threshold); - std::string build_transaction(const std::string &safe_account_addr, const std::string &value, const std::string &data, uint8_t operation, const std::string &safeTxGas, const std::string &dataGas, const std::string &gasPrice, const std::string &gasToken, const std::string &refundReceiver); - - private: - ethereum_function_call_encoder m_ethereum_function_call_encoder; - }; - - ethereum_function_call_encoder m_ethereum_function_call_encoder; - safe_transaction_encoder m_safe_transaction_encoder; - - std::shared_ptr _thread; - std::string signature; - std::string geth_url; - uint64_t t_id; - std::string account_address; - std::string transaction_id; - uint32_t threshold; - std::unordered_map m_requests; - std::string balance; - std::string code; - - std::string ip; - uint32_t rpc_port; - std::string user; - std::string password; - std::string wallet; - std::string wallet_password; - bool debug_rpc_calls; - - fc::http::header authorization; - - client m_endpoint; - websocketpp::connection_hdl m_hdl; + std::string get_chain_id(); + std::string get_network_id(); }; -// ============================================================================= - class sidechain_net_handler_ethereum : public sidechain_net_handler { public: sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options); @@ -232,20 +38,13 @@ public: bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); private: - std::string url; - uint32_t rpc_port; + std::string node_rpc_url; + std::string node_rpc_user; + std::string node_rpc_password; + ethereum_node_rpc_client *node_rpc_client; - std::string rpc_user; - std::string rpc_password; - std::string wallet; - std::string wallet_password; - - std::unique_ptr eth_client; - - fc::future on_changed_objects_task; - - std::mutex event_handler_mutex; - typedef std::lock_guard scoped_lock; + ethereum::chain_id_type chain_id; + ethereum::network_id_type network_id; std::string create_primary_wallet_address(const std::vector &son_pubkeys); @@ -253,17 +52,15 @@ private: std::string create_deposit_transaction(const son_wallet_deposit_object &swdo); std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo); - std::string create_transaction(); std::string sign_transaction(const sidechain_transaction_object &sto); std::string send_transaction(const sidechain_transaction_object &sto); + uint64_t last_block_received; + fc::future _listener_task; + boost::signals2::signal event_received; + void schedule_ethereum_listener(); + void ethereum_listener_loop(); void handle_event(const std::string &event_data); - 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); - - std::vector parse_hex(const std::string &str); - fc::ecc::public_key_data create_public_key_data(const std::vector &public_key); }; }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index aa63055a..0e422961 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -157,8 +157,12 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("bitcoin-private-key", bpo::value>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")), "Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)"); - cli.add_options()("ethereum-sidechain-enabled", bpo::value()->default_value(true), "Hive sidechain handler enabled"); - cli.add_options()("ethereum-node-rpc-url", bpo::value()->default_value("ws://127.0.0.1:8546/"), "Ethereum node RPC WS URL [ws[s]://]host[:port]"); + cli.add_options()("ethereum-sidechain-enabled", bpo::value()->default_value(false), "Ethereum sidechain handler enabled"); + cli.add_options()("ethereum-node-rpc-url", bpo::value()->default_value("127.0.0.1:8545"), "Ethereum node RPC URL [http[s]://]host[:port]"); + cli.add_options()("ethereum-node-rpc-user", bpo::value()->default_value("1"), "Ethereum RPC user"); + cli.add_options()("ethereum-node-rpc-password", bpo::value()->default_value("1"), "Ethereum RPC password"); + 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)"); cli.add_options()("hive-sidechain-enabled", bpo::value()->default_value(false), "Hive sidechain handler enabled"); cli.add_options()("hive-node-rpc-url", bpo::value()->default_value("127.0.0.1:28090"), "Hive node RPC URL [http[s]://]host[:port]"); @@ -221,9 +225,9 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt } sidechain_enabled_ethereum = options.at("ethereum-sidechain-enabled").as(); - config_ready_ethereum = options.count("ethereum-node-rpc-url"); - //options.count("ethereum-address") && - //options.count("ethereum-public-key") && options.count("ethereum-private-key"); + config_ready_ethereum = options.count("ethereum-node-rpc-url") && + /*options.count("ethereum-node-rpc-user") && options.count("ethereum-node-rpc-password") &&*/ + options.count("ethereum-private-key"); if (!config_ready_ethereum) { wlog("Haven't set up Ethereum sidechain parameters"); } @@ -247,7 +251,7 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt } if (!(config_ready_bitcoin && - /*config_ready_ethereum &&*/ + config_ready_ethereum && config_ready_hive && config_ready_peerplays)) { wlog("Haven't set up any sidechain parameters"); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 4feba5ec..6cbd47fc 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -20,479 +20,30 @@ #include #include -#include - -#include -extern "C" { -#include -} - namespace graphene { namespace peerplays_sidechain { -std::string eth_rpc_client::Transaction::serialize(const std::string &from, const std::string &to, const std::string &tx_id, u256 const &_value, u256 const &_gasPrice, u256 const &_gas, bytes const &_data, u256 const &_nonce) { - std::string m_data_str(m_data.begin(), m_data.end()); - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"account_signTransaction\",\"params\":[{\"from\": \"%1%\", \"gas\": \"%2%\", \"gasPrice\": \"%3%\", \"input\": \"%4%\", \"nonce\": \"%5%\", \"to\": \"%6%\", \"value\": \"%7%\" }],\"id\":%8%}") % from.c_str() % m_gas.str() % m_gasPrice.str() % m_data_str % m_nonce.str() % to.c_str() % m_value.str() % tx_id.c_str()); - return req; + +ethereum_node_rpc_client::ethereum_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : + rpc_client(url, user_name, password, debug_rpc_calls) { } -// ============================================================================= -std::string eth_rpc_client::ethereum_function_call_encoder::encode_function_signature(const std::string &function_signature) { - sha3_context c; - char *hash; - - sha3_Init256(static_cast(&c)); - sha3_SetFlags(&c, SHA3_FLAGS_KECCAK); - sha3_Update(&c, "abc", 3); - hash = (char *)sha3_Finalize(&c); - std::string output(hash); - output = output.substr(0, 8); - - return output; -}; - -std::string eth_rpc_client::ethereum_function_call_encoder::encode_address(const std::string &addr) { - FC_ASSERT(40 == addr.length()); - std::string output = str(boost::format("%024u") % 0) + addr; - return output; +std::string ethereum_node_rpc_client::admin_node_info() { + return send_post_request("admin_nodeInfo", "", debug_rpc_calls); } -std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint256(const std::string &value) { - FC_ASSERT(value.length() <= 64); - std::string output = std::string(64 - value.length(), '0') + value; - return output; +std::string ethereum_node_rpc_client::net_version() { + return send_post_request("net_version", "", debug_rpc_calls); } -std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint8(uint8_t value) { - std::string output = str(boost::format("%02X") % value) + std::string(62, '0'); - return output; +std::string ethereum_node_rpc_client::get_chain_id() { + std::string reply_str = net_version(); + return retrieve_value_from_reply(reply_str, "result"); } -std::string eth_rpc_client::ethereum_function_call_encoder::encode_bytes(const std::string &values) { - size_t len = values.length(); - std::string output = encode_uint256((boost::format("%x") % len).str()) + values + std::string(64 - len, '0'); - return output; +std::string ethereum_node_rpc_client::get_network_id() { + std::string reply_str = admin_node_info(); + return retrieve_value_from_reply(reply_str, "result.protocols.eth.network"); } -std::string eth_rpc_client::safe_transaction_encoder::create_safe_address(const std::vector &owner_addresses, uint32_t threshold) { - //createProxyWithNonce(address,bytes,uint256) - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("createProxyWithNonce(address,bytes,uint256)"); - FC_ASSERT("1688f0b9" == method_id); - - std::string data = "0x1688f0b9000000000000000000000000d9db270c1b5e3bd161e8c8503c55ceabee70955200000000000000000000000000000000000000000000000000000000000000604fa262bd05cdef2e3d5261787ee66d9447a4036324990e04380339bec83b4c7a0000000000000000000000000000000000000000000000000000000000000264b63e800d0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000f48f2b2d2a534e402487b3ee7c18c33aec0fe5e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC1200000000000000000000000076ce31BD03f601c3fC13732deF921c5Bac28267600000000000000000000000009EE460834498a4ee361beB819470061B7381B490000000000000000000000006AEFbd09209e1eE2e0a589d31e732F69B77713D2000000000000000000000000631e128b16f9aDCF1bB6385112B1519C917D77a7000000000000000000000000cD5C788e84220E8b8934Ea4F1dC6a12009bCc91D0000000000000000000000003627C1B31525887CB9441130C831e3588765030500000000000000000000000003A13a989AF30C92AD7ABD1E6210308A6c96f3730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; - - return data; -} - -std::string eth_rpc_client::safe_transaction_encoder::build_transaction(const std::string &safe_account_addr, const std::string &value, const std::string &data, uint8_t operation, const std::string &safeTxGas, const std::string &dataGas, const std::string &gasPrice, const std::string &gasToken, const std::string &refundReceiver) { - //execTransaction method of smart contract , using safe-account address - //execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 dataGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); - FC_ASSERT("6a761202" == method_id); - //"" - std::string to = m_ethereum_function_call_encoder.encode_address(safe_account_addr); - // Value in wei - std::string value_encoded = m_ethereum_function_call_encoder.encode_uint256(value); - // 0 CALL, 1 DELEGATE_CALL - std::string operation_encoded = m_ethereum_function_call_encoder.encode_uint8(operation); - // Max gas to use in the transaction - std::string safeTxGas_encoded = m_ethereum_function_call_encoder.encode_uint256(safeTxGas); - // Gas costs not related to the transaction execution (signature check, refund payment...) - std::string dataGas_encoded = m_ethereum_function_call_encoder.encode_uint256(dataGas); - // Gas price used for the refund calculation - std::string gasPrice_encoded = m_ethereum_function_call_encoder.encode_uint256(gasPrice); - //"", Token address (hold by the Safe) to be used as a refund to the sender, if `null` is Ether - std::string gasToken_encoded = m_ethereum_function_call_encoder.encode_address(gasToken); - //"", Address of receiver of gas payment (or `null` if tx.origin) - std::string refundReceiver_encoded = m_ethereum_function_call_encoder.encode_address(refundReceiver); - - std::string message = method_id + to + value_encoded + data + operation_encoded + safeTxGas_encoded + dataGas_encoded + gasPrice_encoded + gasToken_encoded + refundReceiver_encoded; - - return message; -} - -eth_rpc_client::eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : - _thread(std::make_shared("eth_rpc_client")) { - geth_url = url; - user = user_name; - this->password = password; - this->debug_rpc_calls = debug_rpc_calls; - t_id = 1; - - ilog("eth_rpc_client"); - ilog("### Geth URL: ${url}", ("url", url)); - - m_endpoint.set_access_channels(websocketpp::log::alevel::none); - m_endpoint.set_error_channels(websocketpp::log::elevel::none); - - // Initialize ASIO - m_endpoint.init_asio(); - - // Register our handlers - m_endpoint.set_socket_init_handler(bind(&type::on_socket_init, this, ::_1)); - m_endpoint.set_message_handler(bind(&type::on_message, this, ::_1, ::_2)); - m_endpoint.set_open_handler(bind(&type::on_open, this, ::_1)); - m_endpoint.set_close_handler(bind(&type::on_close, this, ::_1)); - m_endpoint.set_fail_handler(bind(&type::on_fail, this, ::_1)); -} - -void eth_rpc_client::start() { - ilog("### eth_rpc_client::start uri: ${uri}", ("uri", geth_url)); - auto future = _thread->async([this] { - websocketpp::lib::error_code ec; - client::connection_ptr con = m_endpoint.get_connection(this->geth_url, ec); - m_hdl = con->get_handle(); - - if (ec) { - m_endpoint.get_alog().write(websocketpp::log::alevel::app, ec.message()); - return; - } - - m_endpoint.connect(con); - - // Start the ASIO io_service run loop - m_endpoint.run(); - }); -} - -void eth_rpc_client::stop() { - m_endpoint.close(m_hdl, websocketpp::close::status::normal, ""); -} - -void eth_rpc_client::on_socket_init(websocketpp::connection_hdl) { -} - -void eth_rpc_client::on_fail(websocketpp::connection_hdl hdl) { - client::connection_ptr con = m_endpoint.get_con_from_hdl(hdl); - - elog("Ethereum websocket fail"); - //elog("get_state: ${state}", ("state", con->get_state() ) ); - elog("get_local_close_code: ${code}", ("code", con->get_local_close_code())); - elog("get_local_close_reason: ${close}", ("close", con->get_local_close_reason())); - elog("get_remote_close_code: ${close}", ("close", con->get_remote_close_code())); - elog("get_remote_close_reason: ${close}", ("close", con->get_remote_close_reason())); - elog("get_ec().message(): ${ec}", ("ec", con->get_ec().message())); -} - -void eth_rpc_client::on_open(websocketpp::connection_hdl hdl) { - std::string str = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":84}"; - ilog("on_open: ${str}", ("str", str)); - m_endpoint.send(hdl, str.c_str(), websocketpp::frame::opcode::text); - - vector owner_addresses; - std::string private_key = ""; - createmultisig(5, owner_addresses, private_key); -} - -void eth_rpc_client::on_message(websocketpp::connection_hdl hdl, message_ptr msg) { - - ilog("on_message: ${msg}", ("msg", msg->get_payload())); - - fc::variants list = fc::json::variants_from_string(msg->get_payload()); - - ilog("json reposnse: ${list}", ("list", list)); - - const auto &b_obj = list[0].get_object().find("id"); - - if (true == list[0].get_object().contains("error")) { - elog("error in json reposnse: ${list}", ("list", list)); - return; - } - - std::string result_str = list[0].get_object().find("result")->value().as(1); - uint32_t num_owners = 0; - uint32_t i = 0; - fc::variant v; - switch (b_obj->value().as(1)) { - case ETH_CHAIN_ID: - chain_id = result_str; - break; - case ETH_GET_TRANSACTION_RECEIPT: - list = fc::json::variants_from_string(result_str); - v = list[0].get_object().find("logs")->value(); - safe_account_addr = v.get_object().find("address")->value().as(1); - break; - case ETH_CALL: - break; - case ETH_SEND_TRANSACTION: - transaction_id = result_str; - break; - case ETH_SEND_RAW_TRANSACTION: - break; - case ETH_GET_CODE: - code = result_str; - break; - case ETH_GET_BALANCE: - balance = result_str; - break; - case ETH_SIGN: - signature = result_str; - break; - case ETH_COINBASE: - account_address = result_str; - break; - case GET_LIST_OWNERS: - num_owners = (uint32_t)strtol(result_str.substr(2 + 32 + 32 - 4, 4).c_str(), NULL, 16); - owners.clear(); - for (i = 0; i < num_owners; ++i) { - owners.push_back("0x" + result_str.substr(2 + 32 + 32 + 12 + 32 * i, 20)); - } - break; - case ADD_OWNER: - break; - case REMOVE_OWNER: - break; - } -} - -void eth_rpc_client::on_close(websocketpp::connection_hdl) { - ilog("Ethereum websocket close"); -} - -uint64_t eth_rpc_client::get_chain_id() { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":%1%}") % t_id); - ilog("get_chain_id: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_CHAIN_ID; - return t_id++; -} - -uint64_t eth_rpc_client::eth_getTransactionReceipt(const std::string &tx_id) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"%1%\"],\"id\":%2%}") % tx_id.c_str() % t_id); - ilog("eth_getTransactionReceipt: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_GET_TRANSACTION_RECEIPT; - return t_id++; -} - -uint64_t eth_rpc_client::eth_call(const std::string &to, const std::string &data) { - std::string req = str(boost::format("{\"jsonrpc\": \"2.0\", \"method\": \"eth_call\", \"params\": [{\"to\": \"%1%\", \"data\": \"%2%\"}, \"latest\"], \"id\": %3%}") % to.c_str() % data.c_str() % t_id); - ilog("eth_call: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_CALL; - - return t_id++; -} - -uint64_t eth_rpc_client::eth_sendTransaction(const std::string &from, const std::string &to, const std::string &data) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sendTransaction\", \"params\": [{\"from\": \"%1%\", \"to\": \"%2%\", \"data\": \"%3%\"}], \"id\": %4%}") % from.c_str() % to.c_str() % data.c_str() % t_id); - ilog("eth_sendTransaction: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_SEND_TRANSACTION; - - return t_id++; -} - -uint64_t eth_rpc_client::eth_sendRawTransaction(const std::string ¶ms) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"%1%\"],\"id\":%2%}") % params.c_str() % t_id); - ilog("eth_sendRawTransaction: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_SEND_RAW_TRANSACTION; - - return t_id++; -} - -uint64_t eth_rpc_client::eth_getCode(const std::string &addr) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getCode\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); - ilog("eth_getCode: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_GET_CODE; - return t_id++; -} - -uint64_t eth_rpc_client::eth_getBalance(const std::string &addr) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getBalance\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); - ilog("eth_getBalance: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_GET_BALANCE; - return t_id++; -} - -uint64_t eth_rpc_client::eth_sign(const string &addr, const string &message) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sign\", \"params\": [\"%1%\",\"%2%\"], \"id\": %2%}") % addr.c_str() % message.c_str() % t_id); - ilog("eth_sign: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_SIGN; - - return t_id++; -} - -uint64_t eth_rpc_client::eth_coinbase() { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_coinbase\",\"params\":[],\"id\":%1%}") % t_id); - ilog("eth_coinbase: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_COINBASE; - return t_id++; -} - -uint64_t eth_rpc_client::get_list_owners(const std::string &safe_account) { - //getOwners() - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("getOwners()"); - FC_ASSERT("a0e67e2b" == method_id); - return eth_call(safe_account.c_str(), method_id); -} - -uint64_t eth_rpc_client::add_owner(const std::string &addr) { - if (std::count(owners.begin(), owners.end(), addr)) { - FC_THROW_EXCEPTION(fc::exception, "Owners allready have addr: ${addr}", ("addr", addr)); - } - - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); - //addOwnerWithThreshold(address,uint256) - std::string data_method_id = m_ethereum_function_call_encoder.encode_function_signature("addOwnerWithThreshold(address,uint256)"); - FC_ASSERT("0d582f13" == data_method_id); - std::string data = data_method_id + m_ethereum_function_call_encoder.encode_address(addr) + m_ethereum_function_call_encoder.encode_uint256((boost::format("%x") % threshold).str()); - - std::string message = m_safe_transaction_encoder.build_transaction(safe_account_addr, "0", data, ethereum_function_call_encoder::operation_t::OPERATION_CALL, m_safe_transaction_encoder.default_safe_tx_gas, m_safe_transaction_encoder.default_data_gas, m_safe_transaction_encoder.default_gas_price, m_safe_transaction_encoder.default_gas_token, m_safe_transaction_encoder.default_refund_receiver); - - uint64_t id = eth_sign(account_address, message); - - m_requests[t_id] = req_t::ADD_OWNER; - - return 0; -} - -uint64_t eth_rpc_client::remove_owner(const std::string &addr, uint32_t threshold) { - if (!std::count(owners.begin(), owners.end(), addr)) { - FC_THROW_EXCEPTION(fc::exception, "Owners does not have addr: ${addr}", ("addr", addr)); - } - - if (threshold == owners.size()) { - FC_THROW_EXCEPTION(fc::exception, "Owners size does not meet threshold: ${th}", ("th", threshold)); - } - - //removeOwner(address,address,uint256) - std::string data_method_id = m_ethereum_function_call_encoder.encode_function_signature("removeOwner(address,address,uint256)"); - FC_ASSERT("f8dc5dd9" == data_method_id); - std::string data = data_method_id + m_ethereum_function_call_encoder.encode_address(m_ethereum_function_call_encoder.default_prev_addr) + m_ethereum_function_call_encoder.encode_address(addr) + m_ethereum_function_call_encoder.encode_uint256((boost::format("%x") % threshold).str()); - - std::string message = m_safe_transaction_encoder.build_transaction(safe_account_addr, "0", data, ethereum_function_call_encoder::operation_t::OPERATION_CALL, m_safe_transaction_encoder.default_safe_tx_gas, m_safe_transaction_encoder.default_data_gas, m_safe_transaction_encoder.default_gas_price, m_safe_transaction_encoder.default_gas_token, m_safe_transaction_encoder.default_refund_receiver); - - uint64_t id = eth_sign(account_address, message); - - m_requests[t_id] = req_t::REMOVE_OWNER; - - return 0; -} - -std::string eth_rpc_client::addmultisigaddress(const uint32_t nrequired, const std::vector public_keys) { - return ""; -} - -std::string eth_rpc_client::combinepsbt(const vector &psbts) { - return ""; -} - -uint64_t eth_rpc_client::createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key) { - ilog("createmultisig: ${key}", ("key", private_key.c_str())); - - //That's will create - //0x5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12 - //0x76ce31BD03f601c3fC13732deF921c5Bac282676 - //0x09EE460834498a4ee361beB819470061B7381B49 - //0x6AEFbd09209e1eE2e0a589d31e732F69B77713D2 - //0x631e128b16f9aDCF1bB6385112B1519C917D77a7 - //0xcD5C788e84220E8b8934Ea4F1dC6a12009bCc91D - //0x3627C1B31525887CB9441130C831e35887650305 - //0x03A13a989AF30C92AD7ABD1E6210308A6c96f373 - - std::string from = "0xeE52b70e8D7AB5Fe661311D47e81228EAD6B06B9"; - std::string to = "0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2"; - std::string data = m_safe_transaction_encoder.create_safe_address(owner_addresses, nrequired); - - return eth_sendTransaction(from, to, data); -} - -std::string eth_rpc_client::createpsbt() { -} - -std::string eth_rpc_client::createrawtransaction() { - return ""; -} - -std::string eth_rpc_client::createwallet(const std::string &wallet_name) { - return ""; -} - -std::string eth_rpc_client::decodepsbt(std::string const &tx_psbt) { - return ""; -} - -std::string eth_rpc_client::decoderawtransaction(std::string const &tx_hex) { - return ""; -} - -std::string eth_rpc_client::encryptwallet(const std::string &passphrase) { - return ""; -} - -uint64_t eth_rpc_client::estimatesmartfee(uint16_t conf_target) { - return 20000; -} - -std::string eth_rpc_client::finalizepsbt(std::string const &tx_psbt) { - return ""; -} - -std::string eth_rpc_client::getaddressinfo(const std::string &address) { - return ""; -} - -std::string eth_rpc_client::getblock(const std::string &block_hash, int32_t verbosity) { - return ""; -} - -std::string eth_rpc_client::getnetworkinfo() { - return ""; -} - -std::string eth_rpc_client::getrawtransaction(const std::string &txid, const bool verbose) { - return ""; -} - -std::string eth_rpc_client::gettransaction(const std::string &txid, const bool include_watch_only) { - return ""; -} - -std::string eth_rpc_client::getblockchaininfo() { - return ""; -} - -void eth_rpc_client::importaddress(const std::string &address_or_script, const std::string &label, const bool rescan, const bool p2sh) { - return; -} - -void eth_rpc_client::importmulti(const std::vector &address_or_script_array, const bool rescan) { -} - -std::string eth_rpc_client::loadwallet(const std::string &filename) { - return ""; -} - -std::string eth_rpc_client::sendrawtransaction(const std::string &tx_hex) { - return ""; -} - -std::string eth_rpc_client::signrawtransactionwithwallet(const std::string &tx_hash) { - return ""; -} - -std::string eth_rpc_client::unloadwallet(const std::string &filename) { - return ""; -} - -std::string eth_rpc_client::walletlock() { - return ""; -} - -std::string eth_rpc_client::walletprocesspsbt(std::string const &tx_psbt) { - return ""; -} - -bool eth_rpc_client::walletpassphrase(const std::string &passphrase, uint32_t timeout) { - return false; -} - -// ============================================================================= - sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : sidechain_net_handler(_plugin, options) { sidechain = sidechain_type::ethereum; @@ -501,328 +52,59 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha debug_rpc_calls = options.at("debug-rpc-calls").as(); } - url = options.at("ethereum-node-rpc-url").as(); - eth_client = std::unique_ptr(new eth_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls)); - eth_client->start(); - /* - if (!wallet.empty()) { - eth_client->loadwallet(wallet); - } + node_rpc_url = options.at("ethereum-node-rpc-url").as(); + if (options.count("ethereum-node-rpc-user")) { + node_rpc_user = options.at("ethereum-node-rpc-user").as(); + } else { + node_rpc_user = ""; + } + if (options.count("ethereum-node-rpc-password")) { + node_rpc_password = options.at("ethereum-node-rpc-password").as(); + } else { + node_rpc_password = ""; + } + 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) { + auto key_pair = graphene::app::dejsonify>(itr_key_pair, 5); + ilog("Ethereum Public Key: ${public}", ("public", key_pair.first)); + if (!key_pair.first.length() || !key_pair.second.length()) { + FC_THROW("Invalid public private key pair."); + } + private_keys[key_pair.first] = key_pair.second; + } + } - std::thread(&sidechain_net_handler_ethereum::handle_event, this, event_data).detach(); - }); + node_rpc_client = new ethereum_node_rpc_client(node_rpc_url, node_rpc_user, node_rpc_password, debug_rpc_calls); - database.changed_objects.connect([this](const vector &ids, const flat_set &accounts) { - on_changed_objects(ids, accounts); - }); - */ + std::string chain_id_str = node_rpc_client->get_chain_id(); + if (chain_id_str.empty()) { + elog("No Ethereum node running at ${url}", ("url", node_rpc_url)); + FC_ASSERT(false); + } + chain_id = std::stoll(chain_id_str); + std::string network_id_str = node_rpc_client->get_network_id(); + network_id = std::stoll(network_id_str); + + ilog("Running on Ethereum network, chain id ${chain_id_str}, network id ${network_id_str}", ("chain_id_str", chain_id_str)("network_id_str", network_id_str)); + + last_block_received = 0; + schedule_ethereum_listener(); + event_received.connect([this](const std::string &event_data) { + std::thread(&sidechain_net_handler_ethereum::handle_event, this, event_data).detach(); + }); } sidechain_net_handler_ethereum::~sidechain_net_handler_ethereum() { - try { - if (on_changed_objects_task.valid()) { - on_changed_objects_task.cancel_and_wait(__FUNCTION__); - } - } catch (fc::canceled_exception &) { - //Expected exception. Move along. - } catch (fc::exception &e) { - edump((e.to_detail_string())); - } } bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) { - ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); - /* - bool should_approve = false; - - const chain::global_property_object &gpo = database.get_global_properties(); - - int32_t op_idx_0 = -1; - chain::operation op_obj_idx_0; - - if (po.proposed_transaction.operations.size() >= 1) { - op_idx_0 = po.proposed_transaction.operations[0].which(); - op_obj_idx_0 = po.proposed_transaction.operations[0]; - } - - int32_t op_idx_1 = -1; - chain::operation op_obj_idx_1; - (void)op_idx_1; - - if (po.proposed_transaction.operations.size() >= 2) { - op_idx_1 = po.proposed_transaction.operations[1].which(); - op_obj_idx_1 = po.proposed_transaction.operations[1]; - } - - switch (op_idx_0) { - - case chain::operation::tag::value: { - bool address_ok = false; - 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 &idx = database.get_index_type().indices().get(); - const auto swo = idx.find(swo_id); - if (swo != idx.end()) { - - auto active_sons = gpo.active_sons; - vector wallet_sons = swo->sons; - - bool son_sets_equal = (active_sons.size() == wallet_sons.size()); - - if (son_sets_equal) { - for (size_t i = 0; i < active_sons.size(); i++) { - son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i); - } - } - - if (son_sets_equal) { - auto active_sons = gpo.active_sons; - vector son_pubkeys_bitcoin; - for (const son_info &si : active_sons) { - son_pubkeys_bitcoin.push_back(si.sidechain_public_keys.at(sidechain_type::bitcoin)); - } - - string reply_str = create_primary_wallet_address(active_sons); - - std::stringstream active_pw_ss(reply_str); - boost::property_tree::ptree active_pw_pt; - boost::property_tree::read_json(active_pw_ss, active_pw_pt); - if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { - std::stringstream res; - boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); - new_pw_address = active_pw_pt.get("result.address"); - - address_ok = (op_obj_idx_0.get().address == res.str()); - } - } - - if (po.proposed_transaction.operations.size() >= 2) { - object_id_type object_id = op_obj_idx_1.get().object_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); - if (st == st_idx.end()) { - - std::string tx_str = ""; - - if (object_id.is()) { - const auto &idx = database.get_index_type().indices().get(); - const auto swo = idx.find(object_id); - if (swo != idx.end()) { - tx_str = create_primary_wallet_transaction(*swo, new_pw_address); - } - } - - transaction_ok = (op_tx_str == tx_str); - } -} else { - transaction_ok = true; -} -} - -should_approve = address_ok && -transaction_ok; -break; -} - -case chain::operation::tag::value: { - bool process_ok = false; - bool transaction_ok = false; - son_wallet_deposit_id_type swdo_id = op_obj_idx_0.get().son_wallet_deposit_id; - const auto &idx = database.get_index_type().indices().get(); - const auto swdo = idx.find(swdo_id); - if (swdo != idx.end()) { - - std::string swdo_txid = swdo->sidechain_transaction_id; - std::string swdo_address = swdo->sidechain_from; - 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)); - - std::string tx_str = eth_client->getrawtransaction(swdo_txid, true); - std::stringstream tx_ss(tx_str); - boost::property_tree::ptree tx_json; - boost::property_tree::read_json(tx_ss, tx_json); - - if (tx_json.count("error") && tx_json.get_child("error").empty()) { - - 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; - - 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; - } - } - } - 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; - } - } - - 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; - 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); - if (st == st_idx.end()) { - - std::string tx_str = ""; - - if (object_id.is()) { - const auto &idx = database.get_index_type().indices().get(); - const auto swdo = idx.find(object_id); - if (swdo != idx.end()) { - tx_str = create_deposit_transaction(*swdo); - } - } - - transaction_ok = (op_tx_str == tx_str); - } - } - - should_approve = process_ok && - transaction_ok; - break; - } - -case chain::operation::tag::value: { - bool process_ok = false; - bool transaction_ok = false; - son_wallet_withdraw_id_type swwo_id = op_obj_idx_0.get().son_wallet_withdraw_id; - const auto &idx = database.get_index_type().indices().get(); - const auto swwo = idx.find(swwo_id); - if (swwo != idx.end()) { - - uint32_t swwo_block_num = swwo->block_num; - std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id; - uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1)); - - const auto &block = database.fetch_block_by_number(swwo_block_num); - - for (const auto &tx : block->transactions) { - if (tx.id().str() == swwo_peerplays_transaction_id) { - operation op = tx.operations[swwo_op_idx]; - transfer_operation t_op = op.get(); - - price asset_price = database.get(t_op.amount.asset_id).options.core_exchange_rate; - asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); - - process_ok = (t_op.to == gpo.parameters.son_account()) && - (swwo->peerplays_from == t_op.from) && - (swwo->peerplays_asset == peerplays_asset); - break; - } - } - - object_id_type object_id = op_obj_idx_1.get().object_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); - if (st == st_idx.end()) { - - std::string tx_str = ""; - - if (object_id.is()) { - const auto &idx = database.get_index_type().indices().get(); - const auto swwo = idx.find(object_id); - if (swwo != idx.end()) { - tx_str = create_withdrawal_transaction(*swwo); - } - } - - transaction_ok = (op_tx_str == tx_str); - } - } - - should_approve = process_ok && - transaction_ok; - break; - } - -case chain::operation::tag::value: { - using namespace bitcoin; - should_approve = true; - son_id_type signer = op_obj_idx_0.get().signer; - std::string signature = op_obj_idx_0.get().signature; - sidechain_transaction_id_type sidechain_transaction_id = op_obj_idx_0.get().sidechain_transaction_id; - std::vector in_amounts; - std::string tx_hex; - std::string redeem_script; - const auto &st_idx = database.get_index_type().indices().get(); - const auto sto = st_idx.find(sidechain_transaction_id); - if (sto == st_idx.end()) { - should_approve = false; - break; - } - - const auto &s_idx = database.get_index_type().indices().get(); - const auto son = s_idx.find(signer); - if (son == s_idx.end()) { - should_approve = false; - break; - } - - read_transaction_data(sto->transaction, tx_hex, in_amounts, redeem_script); - bitcoin_transaction tx = unpack(parse_hex(tx_hex)); - bitcoin::bytes pubkey = parse_hex(son->sidechain_public_keys.at(sidechain_type::bitcoin)); - vector sigs = read_byte_arrays_from_string(signature); - for (size_t i = 0; i < tx.vin.size(); i++) { - const auto &sighash_str = get_signature_hash(tx, parse_hex(redeem_script), static_cast(in_amounts[i]), i, 1, true).str(); - const bitcoin::bytes &sighash_hex = parse_hex(sighash_str); - should_approve = should_approve && verify_sig(sigs[i], pubkey, sighash_hex, btc_context()); - } - break; - } - -case chain::operation::tag::value: { - should_approve = true; - break; - } - -default: -should_approve = false; -elog("=================================================="); -elog("Proposal not considered for approval ${po}", ("po", po)); -elog("=================================================="); -} - -return should_approve; -*/ - return true; } void sidechain_net_handler_ethereum::process_primary_wallet() { - ilog("### process_primary_wallet:"); - const auto &swi = database.get_index_type().indices().get(); const auto &active_sw = swi.rbegin(); if (active_sw != swi.rend()) { @@ -898,64 +180,9 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { } void sidechain_net_handler_ethereum::process_sidechain_addresses() { - /* - const chain::global_property_object &gpo = database.get_global_properties(); - std::vector> pubkeys; - for (auto &son : gpo.active_sons) { - std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); - auto pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); - pubkeys.push_back(std::make_pair(pubkey, son.weight)); - } - - const auto &sidechain_addresses_idx = database.get_index_type(); - const auto &sidechain_addresses_by_sidechain_idx = sidechain_addresses_idx.indices().get(); - const auto &sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain); - std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second, - [&](const sidechain_address_object &sao) { - bool retval = true; - try { - 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); - std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) + - "\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }"; - - if (addr.get_address() != sao.deposit_address) { - sidechain_address_update_operation op; - op.payer = plugin.get_current_son_object().son_account; - op.sidechain_address_id = sao.id; - op.sidechain_address_account = sao.sidechain_address_account; - op.sidechain = sao.sidechain; - op.deposit_public_key = sao.deposit_public_key; - op.deposit_address = addr.get_address(); - op.deposit_address_data = address_data; - op.withdraw_public_key = sao.withdraw_public_key; - op.withdraw_address = sao.withdraw_address; - - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); - try { - trx.validate(); - database.push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - retval = true; - } catch (fc::exception &e) { - elog("Sending transaction for sidechain address update operation failed with exception ${e}", ("e", e.what())); - retval = false; - } - } - } - } catch (fc::exception &e) { - retval = false; - } - return retval; - }); - */ } bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_object &swdo) { - ilog("### process_deposit:"); if (proposal_exists(chain::operation::tag::value, swdo.id)) { return false; @@ -1000,7 +227,6 @@ bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_ob } bool sidechain_net_handler_ethereum::process_withdrawal(const son_wallet_withdraw_object &swwo) { - ilog("### process_withdrawal:"); if (proposal_exists(chain::operation::tag::value, swwo.id)) { return false; @@ -1045,130 +271,59 @@ bool sidechain_net_handler_ethereum::process_withdrawal(const son_wallet_withdra } std::string sidechain_net_handler_ethereum::process_sidechain_transaction(const sidechain_transaction_object &sto) { - ilog("### process_sidechain_transaction: "); return sign_transaction(sto); } std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sidechain_transaction_object &sto) { - ilog("### send_sidechain_transaction: "); return send_transaction(sto); } bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) { - return false; -} - -std::vector sidechain_net_handler_ethereum::parse_hex(const std::string &str) { - std::vector vec(str.size() / 2); - fc::from_hex(str, vec.data(), vec.size()); - return vec; + return true; } std::string sidechain_net_handler_ethereum::create_primary_wallet_address(const std::vector &son_pubkeys) { - std::stringstream ss; - - ss << "{\"result\": {\"address\": \"" << eth_client->safe_account_addr << "\"" - << "}, "; - ss << "\"onwers\": ["; - for (auto &owner : eth_client->owners) { - ss << "\"" << owner << "\","; - } - ss.seekp(-1, std::ios_base::end); - ss << "], keys: ["; - - for (auto &son : son_pubkeys) { - std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); - ss << "\"" << pub_key_str << "\","; - } - ss.seekp(-1, std::ios_base::end); - ss << "], "; - - ss << "\"error\":null}"; - - std::string res = ss.str(); - return res; + return "Primary Wallet Address"; } std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address) { - return ""; //create_transaction(inputs, outputs, prev_redeem_script); + return "Primary-Wallet-Transaction"; } std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) { - return ""; //create_transaction(inputs, outputs, redeem_script); + return "Deposit-Transaction"; } std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { - return ""; //create_transaction(inputs, outputs, redeem_script); -} - -std::string sidechain_net_handler_ethereum::create_transaction() { - std::string tx_raw; // = write_transaction_data(hex_tx, in_amounts, redeem_script); - return tx_raw; + return "Withdrawal-Transaction"; } std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) { - ilog("### sign_transaction: "); - - std::stringstream ss_trx(boost::algorithm::unhex(sto.transaction)); - ethereum::signed_transaction htrx; - fc::raw::unpack(ss_trx, htrx, 1000); - - std::string chain_id_str = eth_client->chain_id; //eth_rpc_client->get_chain_id(); - const ethereum::chain_id_type chain_id(chain_id_str); - - fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))); - signature_type st = htrx.sign(*privkey, chain_id); - - std::stringstream ss_st; - fc::raw::pack(ss_st, st, 1000); - std::string st_str = boost::algorithm::hex(ss_st.str()); - return st_str; + std::string key = get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain)); + return "Transaction-Signature-" + key; } std::string sidechain_net_handler_ethereum::send_transaction(const sidechain_transaction_object &sto) { - std::string res; // = eth_client->sendrawtransaction(final_tx_hex); + return "Transaction-ID"; +} - return res; +void sidechain_net_handler_ethereum::schedule_ethereum_listener() { + fc::time_point now = fc::time_point::now(); + int64_t time_to_next = 1000; + + fc::time_point next_wakeup(now + fc::milliseconds(time_to_next)); + + _listener_task = fc::schedule([this] { + ethereum_listener_loop(); + }, + next_wakeup, "SON Ethereum listener task"); +} + +void sidechain_net_handler_ethereum::ethereum_listener_loop() { + schedule_ethereum_listener(); } void sidechain_net_handler_ethereum::handle_event(const std::string &event_data) { } -std::vector sidechain_net_handler_ethereum::extract_info_from_block(const std::string &_block) { - std::stringstream ss(_block); - boost::property_tree::ptree block; - boost::property_tree::read_json(ss, block); - - std::vector result; - - return result; -} - -void sidechain_net_handler_ethereum::on_changed_objects(const vector &ids, const flat_set &accounts) { - ilog("### on_changed_objects: "); - - fc::time_point now = fc::time_point::now(); - int64_t time_to_next_changed_objects_processing = 5000; - - fc::time_point next_wakeup(now + fc::microseconds(time_to_next_changed_objects_processing)); - - on_changed_objects_task = fc::schedule([this, ids, accounts] { - on_changed_objects_cb(ids, accounts); - }, - next_wakeup, "SON Processing"); -} - -void sidechain_net_handler_ethereum::on_changed_objects_cb(const vector &ids, const flat_set &accounts) { -} - -fc::ecc::public_key_data sidechain_net_handler_ethereum::create_public_key_data(const std::vector &public_key) { - FC_ASSERT(public_key.size() == 33); - fc::ecc::public_key_data key; - for (size_t i = 0; i < 33; i++) { - key.at(i) = public_key[i]; - } - return key; -} - -// ============================================================================= }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp index d63e6743..dacd1e9e 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp @@ -28,8 +28,6 @@ #include #include -#include - namespace graphene { namespace peerplays_sidechain { hive_node_rpc_client::hive_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : -- 2.45.2 From 57ccbdffd4d0998b8505ec10bb588e68aa65f94c Mon Sep 17 00:00:00 2001 From: serkixenos Date: Thu, 30 Jun 2022 00:21:04 +0200 Subject: [PATCH 26/60] Basic RPC communication with Ethereum node established --- .../peerplays_sidechain/CMakeLists.txt | 2 + .../peerplays_sidechain/common/rpc_client.cpp | 1008 ++--------------- .../peerplays_sidechain/ethereum/decoders.cpp | 2 +- .../peerplays_sidechain/ethereum/encoders.cpp | 2 +- .../peerplays_sidechain/common/rpc_client.hpp | 119 +- .../peerplays_sidechain/ethereum/decoders.hpp | 3 + .../peerplays_sidechain/ethereum/encoders.hpp | 3 + .../sidechain_net_handler_ethereum.hpp | 7 +- .../peerplays_sidechain_plugin.cpp | 4 +- .../sidechain_net_handler_ethereum.cpp | 31 +- 10 files changed, 116 insertions(+), 1065 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index 6546b031..d82e874b 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -18,6 +18,8 @@ add_library( peerplays_sidechain bitcoin/sign_bitcoin_transaction.cpp common/rpc_client.cpp common/utils.cpp + ethereum/encoders.cpp + ethereum/decoders.cpp ethereum/transaction.cpp ethereum/types.cpp hive/asset.cpp diff --git a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp index d08d337b..767a2131 100644 --- a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp +++ b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp @@ -3,881 +3,65 @@ #include #include -//#include - -#include -#include -#include #include #include -#include +#include + #include -#include namespace graphene { namespace peerplays_sidechain { -constexpr auto http_port = 80; -constexpr auto https_port = 443; - -template -void make_trimmed(string *str) { - boost::algorithm::trim(*str); -} - -template -void make_lower(string *str) { - boost::algorithm::to_lower(*str); -} - -bool convert_hex_to_num_helper1(const std::string &str, uint32_t *value) { - try { - size_t idx; - auto v = stol(str, &idx, 16); - if (idx != str.size()) - return false; - if (value) - *value = v; - return true; - } catch (...) { - return false; - } -} - -bool convert_dec_to_num_helper1(const std::string &str, uint32_t *value) { - try { - size_t idx; - auto v = stol(str, &idx, 10); - if (idx != str.size()) - return false; - if (value) - *value = v; - return true; - } catch (...) { - return false; - } -} - -bool convert_dec_to_num_helper1(const std::string &str, uint16_t *value) { - try { - size_t idx; - auto v = stol(str, &idx, 10); - if (idx != str.size()) - return false; - if (v > std::numeric_limits::max()) - return false; - if (value) - *value = v; - return true; - } catch (...) { - return false; - } -} - -template -constexpr V ceilDiv(V value, D divider) { - return (value + divider - 1) / divider; -} - -template -constexpr V aligned(V value, A align) { - return ceilDiv(value, align) * align; -} - -template -void reserve( - Container *container, - typename Container::size_type freeSpaceRequired, - typename Container::size_type firstAlloc, - typename Container::size_type nextAlloc) { - //TSL_ASSERT(container); - auto &c = *container; - auto required = c.size() + freeSpaceRequired; - if (c.capacity() >= required) - return; - c.reserve((firstAlloc >= required) ? firstAlloc - : firstAlloc + aligned(required - firstAlloc, nextAlloc)); -} - -template -void reserve( - Container *container, - typename Container::size_type freeSpaceRequired, - typename Container::size_type alloc) { - //TSL_ASSERT(container); - auto &c = *container; - auto required = c.size() + freeSpaceRequired; - if (c.capacity() >= required) - return; - c.reserve(aligned(required, alloc)); -} - -bool is_valid(const boost::asio::ip::tcp::endpoint &ep) { - - if (ep.port() == 0) - return false; - - if (ep.address().is_unspecified()) - return false; - - return true; -} - -// utl - -url_schema_type identify_url_schema_type(const std::string &schema_name) { - // rework - auto temp = schema_name; - make_lower(&temp); - if (temp == "http") - return url_schema_type::http; - if (temp == "https") - return url_schema_type::https; - return url_schema_type::unknown; -} - -// url_data - -url_data::url_data(const std::string &url) { - if (!parse(url)) - FC_THROW("URL parse failed"); -} - -void url_data::clear() { - schema_type = url_schema_type::unknown; - schema = decltype(schema)(); - host = decltype(host)(); - port = 0; - path = decltype(path)(); -} - -bool url_data::parse(const std::string &url) { - - typedef std::string::size_type size_t; - constexpr auto npos = std::string::npos; - - size_t schema_end = url.find("://"); - size_t host_begin; - std::string temp_schema; - - if (schema_end == npos) - host_begin = 0; // no schema - else { - if (schema_end < 3) { // schema too short: less than 3 chars - return false; - } - if (schema_end > 5) { // schema too long: more than 5 chars - return false; - } - host_begin = schema_end + 3; - temp_schema = url.substr(0, schema_end); - } - - // ASSERT(url.size() >= host_begin); - - if (url.size() == host_begin) // host is empty - return false; - - size_t port_sep = url.find(':', host_begin); - - if (port_sep == host_begin) - return false; - - size_t path_sep = url.find('/', host_begin); - - if (path_sep == host_begin) - return false; - - if ((port_sep != npos) && (path_sep != npos) && (port_sep > path_sep)) - port_sep = npos; - - std::string temp_port; - - if (port_sep != npos) { - auto port_index = port_sep + 1; - if (path_sep == npos) - temp_port = url.substr(port_index); - else - temp_port = url.substr(port_index, path_sep - port_index); - } - - if (temp_port.empty()) - port = 0; - else { - if (!convert_dec_to_num_helper1(temp_port, &port)) - return false; - } - - std::string temp_path; - - if (path_sep != npos) - temp_path = url.substr(path_sep); - - std::string temp_host; - - if (port_sep != npos) { - temp_host = url.substr(host_begin, port_sep - host_begin); - } else { - if (path_sep != npos) - temp_host = url.substr(host_begin, path_sep - host_begin); - else - temp_host = url.substr(host_begin); - } - - schema = temp_schema; - host = temp_host; - path = temp_path; - schema_type = identify_url_schema_type(schema); - - return true; -} - -}} // namespace graphene::peerplays_sidechain - -namespace graphene { namespace peerplays_sidechain { - -using namespace boost::asio; -using error_code = boost::system::error_code; -using endpoint = ip::tcp::endpoint; - -namespace detail { - -// http_call_impl - -struct tcp_socket { - - typedef ip::tcp::socket underlying_type; - - underlying_type underlying; - - tcp_socket(http_call &call) : - underlying(call.m_service) { - } - - underlying_type &operator()() { - return underlying; - } - - void connect(const http_call &call, const endpoint &ep, error_code *ec) { - // TCP connect - underlying.connect(ep, *ec); - } - - void shutdown() { - error_code ec; - underlying.close(ec); - } -}; - -struct ssl_socket { - - typedef ssl::stream underlying_type; - - underlying_type underlying; - - ssl_socket(http_call &call) : - underlying(call.m_service, *call.m_context) { - } - - underlying_type &operator()() { - return underlying; - } - - void connect(const http_call &call, const endpoint &ep, error_code *ec) { - - auto &u = underlying; - - // TCP connect - u.lowest_layer().connect(ep, *ec); - - // SSL connect - if (!SSL_set_tlsext_host_name(u.native_handle(), call.m_host.c_str())) - FC_THROW("SSL_set_tlsext_host_name failed"); - - u.set_verify_mode(ssl::verify_peer, *ec); - u.handshake(ssl::stream_base::client, *ec); - } - - void shutdown() { - auto &u = underlying; - error_code ec; - u.shutdown(ec); - u.lowest_layer().close(ec); - } -}; - -template -class http_call_impl { -public: - http_call_impl(http_call &call, const void *body_data, size_t body_size, const std::string &content_type_, http_response &response); - void exec(); - -private: - http_call &call; - const void *body_data; - size_t body_size; - std::string content_type; - http_response &response; - - socket_type socket; - streambuf response_buf; - - int32_t content_length; - bool transfer_encoding_chunked; - -private: - void connect(); - void shutdown(); - void send_request(); - void on_header(std::string &name, std::string &value); - void on_header(); - void process_headers(); - void append_entity_body(std::istream *stream, size_t size); - void append_entity_body_2(std::istream *strm); - bool read_next_chunk(std::istream *strm); - void skip_footer(); - void read_body_chunked(); - void read_body_until_eof(); - void read_body_exact(); - void process_response(); -}; - -static const char cr = 0x0D; -static const char lf = 0x0A; -static const char *crlf = "\x0D\x0A"; -static const char *crlfcrlf = "\x0D\x0A\x0D\x0A"; -static const auto crlf_uint = (((uint16_t)lf) << 8) + cr; - -template -http_call_impl::http_call_impl(http_call &call_, const void *body_data_, size_t body_size_, const std::string &content_type_, http_response &response_) : - call(call_), - body_data(body_data_), - body_size(body_size_), - content_type(content_type_), - response(response_), - socket(call), - response_buf(http_call::response_size_limit_bytes) { -} - -template -void http_call_impl::exec() { - try { - connect(); - send_request(); - process_response(); - shutdown(); - } catch (...) { - shutdown(); - throw; - } -} - -template -void http_call_impl::connect() { - - { - error_code ec; - auto &ep = call.m_endpoint; - if (is_valid(ep)) { - socket.connect(call, ep, &ec); - if (!ec) - return; - } - } - - ip::tcp::resolver resolver(call.m_service); - - auto rng = resolver.resolve(call.m_host, std::string()); - - //ASSERT(rng.begin() != rng.end()); - - error_code ec; - - for (endpoint ep : rng) { - ep.port(call.m_port); - socket.connect(call, ep, &ec); - if (!ec) { - call.m_endpoint = ep; - return; // comment to test1 - } - } - // if (!ec) return; // uncomment to test1 - - //ASSERT(ec); - throw boost::system::system_error(ec); -} - -template -void http_call_impl::shutdown() { - socket.shutdown(); -} - -template -void http_call_impl::send_request() { - - streambuf request; - std::ostream stream(&request); - - // start string: HTTP/1.0 - - //ASSERT(!call.m_path.empty()); - - stream << call.m_method << " " << call.m_path << " HTTP/1.1" << crlf; - - // host - - stream << "Host: " << call.m_host << ":" << call.m_endpoint.port() << crlf; - - // content - - if (body_size) { - stream << "Content-Type: " << content_type << crlf; - stream << "Content-Length: " << body_size << crlf; - } - - // additional headers - - const auto &h = call.m_headers; - - if (!h.empty()) { - if (h.size() < 2) - FC_THROW("invalid headers data"); - stream << h; - // ensure headers finished correctly - if ((h.substr(h.size() - 2) != crlf)) - stream << crlf; - } - - // other - - // stream << "Accept: *\x2F*" << crlf; - stream << "Accept: text/html, application/json" << crlf; - stream << "Connection: close" << crlf; - - // end - - stream << crlf; - - // send headers - - write(socket(), request); - - // send body - - if (body_size) - write(socket(), buffer(body_data, body_size)); -} - -template -void http_call_impl::on_header(std::string &name, std::string &value) { - - if (name == "content-length") { - uint32_t u; - if (!convert_dec_to_num_helper1(value, &u)) - FC_THROW("invalid content-length header data"); - content_length = u; - return; - } - - if (name == "transfer-encoding") { - boost::algorithm::to_lower(value); - if (value == "chunked") - transfer_encoding_chunked = true; - return; - } -} - -template -void http_call_impl::process_headers() { - - std::istream stream(&response_buf); - - std::string http_version; - stream >> http_version; - stream >> response.status_code; - - make_trimmed(&http_version); - make_lower(&http_version); - - if (!stream || http_version.substr(0, 6) != "http/1") - FC_THROW("invalid response data"); - - // read/skip headers - - content_length = -1; - transfer_encoding_chunked = false; - - for (;;) { - std::string header; - if (!std::getline(stream, header, lf) || (header.size() == 1 && header[0] == cr)) - break; - auto pos = header.find(':'); - if (pos == std::string::npos) - continue; - auto name = header.substr(0, pos); - make_trimmed(&name); - boost::algorithm::to_lower(name); - auto value = header.substr(pos + 1); - make_trimmed(&value); - on_header(name, value); - } -} - -template -void http_call_impl::append_entity_body(std::istream *strm, size_t size) { - if (size == 0) - return; - auto &body = response.body; - reserve(&body, size, http_call::response_first_alloc_bytes, http_call::response_next_alloc_bytes); - auto cur = body.size(); - body.resize(cur + size); - auto p = &body[cur]; - if (!strm->read(p, size)) - FC_THROW("stream read failed"); -} - -template -void http_call_impl::append_entity_body_2(std::istream *strm) { - auto avail = response_buf.size(); - if (response.body.size() + avail > http_call::response_size_limit_bytes) - FC_THROW("response body size limit exceeded"); - append_entity_body(strm, avail); -} - -template -bool http_call_impl::read_next_chunk(std::istream *strm) { - - // content length info is used as pre-alloc hint only - // it is not used inside the reading logic - - auto &buf = response_buf; - auto &stream = *strm; - auto &body = response.body; - - read_until(socket(), buf, crlf); - - std::string chunk_header; - - if (!std::getline(stream, chunk_header, lf)) - FC_THROW("failed to read chunk size"); - - auto ext_index = chunk_header.find(':'); - - if (ext_index != std::string::npos) - chunk_header.resize(ext_index); - - make_trimmed(&chunk_header); - - uint32_t chink_size; - - if (!convert_hex_to_num_helper1(chunk_header, &chink_size)) - FC_THROW("invalid chunk size string"); - - if (body.size() + chink_size > http_call::response_size_limit_bytes) - FC_THROW("response body size limit exceeded"); - - auto avail = buf.size(); - if (avail < chink_size + 2) { - auto rest = chink_size + 2 - avail; - read(socket(), buf, transfer_at_least(rest)); - } - - append_entity_body(&stream, chink_size); - - uint16_t temp; - if (!stream.read((char *)(&temp), 2)) - FC_THROW("stream read failed"); - if (temp != crlf_uint) - FC_THROW("invalid chink end"); - - return chink_size != 0; -} - -template -void http_call_impl::skip_footer() { - // to be implemeted -} - -template -void http_call_impl::read_body_chunked() { - - std::istream stream(&response_buf); - - for (;;) { - if (!read_next_chunk(&stream)) - break; - } - - skip_footer(); -} - -template -void http_call_impl::read_body_until_eof() { - - auto &buf = response_buf; - std::istream stream(&buf); - - append_entity_body_2(&stream); - - error_code ec; - - for (;;) { - auto readed = read(socket(), buf, transfer_at_least(1), ec); - append_entity_body_2(&stream); - if (ec) - break; - if (!readed) { - //ASSERT(buf.size() == 0); - FC_THROW("logic error: read failed but no error conditon"); - } - } - if ((ec != error::eof) && - (ec != ssl::error::stream_truncated)) - throw boost::system::system_error(ec); -} - -template -void http_call_impl::read_body_exact() { - - auto &buf = response_buf; - auto &body = response.body; - - auto avail = buf.size(); - - if (avail > ((size_t)content_length)) - FC_THROW("invalid response body (content length mismatch)"); - - body.resize(content_length); - - if (avail) { - if (avail != ((size_t)buf.sgetn(&body[0], avail))) - FC_THROW("stream read failed"); - } - - auto rest = content_length - avail; - - if (rest > 0) { - auto readed = read(socket(), buffer(&body[avail], rest), transfer_exactly(rest)); - //ASSERT(readed <= rest); - if (readed < rest) - FC_THROW("logic error: read failed but no error conditon"); - } -} - -template -void http_call_impl::process_response() { - - auto &buf = response_buf; - auto &body = response.body; - - read_until(socket(), buf, crlfcrlf); - - process_headers(); - - // check content length - - if (content_length >= 0) { - if (content_length < 2) { // minimum content is "{}" - FC_THROW("invalid response body (too short)"); - } - if (content_length > http_call::response_size_limit_bytes) - FC_THROW("response body size limit exceeded"); - body.reserve(content_length); - } - - if (transfer_encoding_chunked) { - read_body_chunked(); - } else { - if (content_length < 0) - read_body_until_eof(); - else { - if (content_length > 0) - read_body_exact(); - } - } -} - -} // namespace detail - -// https_call - -http_call::http_call(const url_data &url, const std::string &method, const std::string &headers) : - m_host(url.host), - m_method(method), - m_headers(headers) { - - if (url.schema_type == url_schema_type::https) { - m_context = new boost::asio::ssl::context(ssl::context::tlsv12_client); - } else { - m_context = 0; - } - - if (url.port) - m_port_default = url.port; - else { - if (url.schema_type == url_schema_type::https) - m_port_default = https_port; - else - m_port_default = http_port; - } - - m_port = m_port_default; - - set_path(url.path); - - try { - ctor_priv(); - } catch (...) { - if (m_context) - delete m_context; - throw; - } -} - -http_call::~http_call() { - if (m_context) - delete m_context; -} - -bool http_call::is_ssl() const { - return m_context != 0; -} - -const std::string &http_call::path() const { - return m_path; -} - -void http_call::set_path(const std::string &path) { - if (path.empty()) - m_path = "/"; - else - m_path = path; -} - -void http_call::set_method(const std::string &method) { - m_method = method; -} - -void http_call::set_headers(const std::string &headers) { - m_headers = headers; -} - -const std::string &http_call::host() const { - return m_host; -} - -void http_call::set_host(const std::string &host) { - m_host = host; -} - -uint16_t http_call::port() const { - return m_port; -} - -void http_call::set_port(uint16_t port) { - if (port) - m_port = port; - else - m_port = m_port_default; -} - -bool http_call::exec(const http_request &request, http_response *response) { - - //ASSERT(response); - auto &resp = *response; - m_error_what = decltype(m_error_what)(); - resp.clear(); - - try { - try { - using namespace detail; - if (!m_context) - http_call_impl(*this, request.body.data(), request.body.size(), request.content_type, resp).exec(); - else - http_call_impl(*this, request.body.data(), request.body.size(), request.content_type, resp).exec(); - return true; - } catch (const std::exception &e) { - m_error_what = e.what(); - } - } catch (...) { - m_error_what = "unknown exception"; - } - - resp.clear(); - return false; -} - -const std::string &http_call::error_what() const { - return m_error_what; -} - -void http_call::ctor_priv() { - if (m_context) { - m_context->set_default_verify_paths(); - m_context->set_options(ssl::context::default_workarounds); - } -} - -}} // namespace graphene::peerplays_sidechain - -namespace graphene { namespace peerplays_sidechain { - -rpc_client::rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug) : - debug_rpc_calls(debug), - request_id(0), - client(url) - -{ - - client.set_method("POST"); - client.set_headers("Authorization : Basic" + fc::base64_encode(user_name + ":" + password)); +rpc_client::rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls) : + url(_url), + user(_user), + password(_password), + debug_rpc_calls(_debug_rpc_calls), + request_id(0) { } std::string rpc_client::retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx) { - if (reply_str.empty()) - return std::string(); std::stringstream ss(reply_str); boost::property_tree::ptree json; boost::property_tree::read_json(ss, json); if (json.find("result") == json.not_found()) { - return std::string(); - } - auto json_result = json.get_child("result"); - if (json_result.find(array_path) == json_result.not_found()) { - return std::string(); + return ""; } - boost::property_tree::ptree array_ptree = json_result; - if (!array_path.empty()) { - array_ptree = json_result.get_child(array_path); - } - uint32_t array_el_idx = -1; - for (const auto &array_el : array_ptree) { - array_el_idx = array_el_idx + 1; - if (array_el_idx == idx) { - std::stringstream ss_res; - boost::property_tree::json_parser::write_json(ss_res, array_el.second); - return ss_res.str(); + auto json_result = json.get_child_optional("result"); + if (json_result) { + boost::property_tree::ptree array_ptree = json_result.get(); + if (!array_path.empty()) { + array_ptree = json_result.get().get_child(array_path); + } + uint32_t array_el_idx = -1; + for (const auto &array_el : array_ptree) { + array_el_idx = array_el_idx + 1; + if (array_el_idx == idx) { + std::stringstream ss_res; + boost::property_tree::json_parser::write_json(ss_res, array_el.second); + return ss_res.str(); + } } } - return std::string(); + return ""; } std::string rpc_client::retrieve_value_from_reply(std::string reply_str, std::string value_path) { - if (reply_str.empty()) - return std::string(); std::stringstream ss(reply_str); boost::property_tree::ptree json; boost::property_tree::read_json(ss, json); if (json.find("result") == json.not_found()) { - return std::string(); + return ""; } - auto json_result = json.get_child("result"); - if (json_result.find(value_path) == json_result.not_found()) { - return std::string(); + + auto json_result = json.get_child_optional("result"); + if (json_result) { + return json_result.get().get(value_path); } - return json_result.get(value_path); + + return json.get("result"); } std::string rpc_client::send_post_request(std::string method, std::string params, bool show_log) { @@ -904,7 +88,7 @@ std::string rpc_client::send_post_request(std::string method, std::string params boost::property_tree::ptree json; boost::property_tree::read_json(ss, json); - if (reply.status_code == 200) { + if (reply.status == 200) { return ss.str(); } @@ -914,104 +98,60 @@ std::string rpc_client::send_post_request(std::string method, std::string params return ""; } -//fc::http::reply rpc_client::send_post_request(std::string body, bool show_log) { -// fc::http::connection conn; -// conn.connect_to(fc::ip::endpoint(fc::ip::address(ip), port)); -// -// std::string url = "http://" + ip + ":" + std::to_string(port); -// -// //if (wallet.length() > 0) { -// // url = url + "/wallet/" + wallet; -// //} -// -// fc::http::reply reply = conn.request("POST", url, body, fc::http::headers{authorization}); -// -// if (show_log) { -// ilog("### Request URL: ${url}", ("url", url)); -// ilog("### Request: ${body}", ("body", body)); -// std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); -// ilog("### Response: ${ss}", ("ss", ss.str())); -// } -// -// return reply; -//} +static size_t write_callback(char *ptr, size_t size, size_t nmemb, rpc_reply *reply) { + size_t retval = 0; + if (reply != nullptr) { + reply->body.append(ptr, size * nmemb); + retval = size * nmemb; + } + return retval; +} -//static size_t write_callback(char *ptr, size_t size, size_t nmemb, rpc_reply *reply) { -// size_t retval = 0; -// if (reply != nullptr) { -// reply->body.append(ptr, size * nmemb); -// retval = size * nmemb; -// } -// return retval; -//} +rpc_reply rpc_client::send_post_request(std::string body, bool show_log) { -//rpc_reply rpc_client::send_post_request(std::string body, bool show_log) { -// -// struct curl_slist *headers = nullptr; -// headers = curl_slist_append(headers, "Accept: application/json"); -// headers = curl_slist_append(headers, "Content-Type: application/json"); -// headers = curl_slist_append(headers, "charset: utf-8"); -// -// CURL *curl = curl_easy_init(); -// if (ip.find("https://", 0) != 0) { -// curl_easy_setopt(curl, CURLOPT_URL, ip.c_str()); -// curl_easy_setopt(curl, CURLOPT_PORT, port); -// } else { -// std::string full_address = ip + ":" + std::to_string(port); -// curl_easy_setopt(curl, CURLOPT_URL, full_address.c_str()); -// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); -// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); -// } -// if (!user.empty()) { -// curl_easy_setopt(curl, CURLOPT_USERNAME, user.c_str()); -// curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); -// } -// -// curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); -// curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str()); -// -// //curl_easy_setopt(curl, CURLOPT_VERBOSE, true); -// -// rpc_reply reply; -// -// curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); -// curl_easy_setopt(curl, CURLOPT_WRITEDATA, &reply); -// -// curl_easy_perform(curl); -// -// curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &reply.status); -// -// curl_easy_cleanup(curl); -// curl_slist_free_all(headers); -// -// if (show_log) { -// std::string url = ip + ":" + std::to_string(port); -// ilog("### Request URL: ${url}", ("url", url)); -// ilog("### Request: ${body}", ("body", body)); -// std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); -// ilog("### Response: ${ss}", ("ss", ss.str())); -// } -// -// return reply; -//} + struct curl_slist *headers = nullptr; + headers = curl_slist_append(headers, "Accept: application/json"); + headers = curl_slist_append(headers, "Content-Type: application/json"); + headers = curl_slist_append(headers, "charset: utf-8"); -http_response rpc_client::send_post_request(const std::string &body, bool show_log) { + CURL *curl = curl_easy_init(); - http_request request(body, "application/json"); - http_response response; + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + if (url.find("https://", 0) == 0) { + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); + } - client.exec(request, &response); + if (!user.empty()) { + curl_easy_setopt(curl, CURLOPT_USERNAME, user.c_str()); + curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); + } + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str()); + + //curl_easy_setopt(curl, CURLOPT_VERBOSE, true); + + rpc_reply reply; + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &reply); + + curl_easy_perform(curl); + + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &reply.status); + + curl_easy_cleanup(curl); + curl_slist_free_all(headers); if (show_log) { - std::string url = client.is_ssl() ? "https" : "http"; - url = url + "://" + client.host() + ":" + std::to_string(client.port()) + client.path(); ilog("### Request URL: ${url}", ("url", url)); ilog("### Request: ${body}", ("body", body)); - std::stringstream ss(std::string(response.body.begin(), response.body.end())); + std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); ilog("### Response: ${ss}", ("ss", ss.str())); } - return response; + return reply; } }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp index 2ebf3380..fcf468ce 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp @@ -1,4 +1,4 @@ -#include #include < graphene / peerplays_sidechain / ethereum / decoders.hpp> +#include namespace graphene { namespace peerplays_sidechain { namespace ethereum { diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index e2db7e9f..4359a605 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -1,4 +1,4 @@ -#include #include < graphene / peerplays_sidechain / ethereum / encoders.hpp> +#include namespace graphene { namespace peerplays_sidechain { namespace ethereum { diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp index 63d218ee..11d715ba 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp @@ -3,134 +3,31 @@ #include #include -#include -#include - -//#include - namespace graphene { namespace peerplays_sidechain { -enum class url_schema_type { unknown, - http, - https, -}; - -// utl - -url_schema_type identify_url_schema_type(const std::string &schema_name); - -struct url_data { - - url_schema_type schema_type; - std::string schema; - std::string host; - uint16_t port; - std::string path; - - url_data() : - schema_type(url_schema_type::unknown), - port(0) { - } - - url_data(const std::string &url); - - void clear(); - - bool parse(const std::string &url); -}; - -struct http_request { - +struct rpc_reply { + uint16_t status; std::string body; - std::string content_type; - - http_request(const std::string &body_, const std::string &content_type_) : - body(body_), - content_type(content_type_) { - } }; -struct http_response { - - uint16_t status_code; - std::string body; - - void clear() { - status_code = 0; - body = decltype(body)(); - } -}; - -namespace detail { -template -class http_call_impl; -class tcp_socket; -class ssl_socket; -} // namespace detail - -class http_call { -public: - http_call(const url_data &url, const std::string &method = std::string(), const std::string &headers = std::string()); - ~http_call(); - - bool is_ssl() const; - - const std::string &path() const; - void set_path(const std::string &path); - void set_method(const std::string &method); - void set_headers(const std::string &headers); - const std::string &host() const; - void set_host(const std::string &host); - - uint16_t port() const; - void set_port(uint16_t port); - - bool exec(const http_request &request, http_response *response); - - const std::string &error_what() const; - -private: - template - friend class detail::http_call_impl; - friend detail::tcp_socket; - friend detail::ssl_socket; - static constexpr auto response_size_limit_bytes = 16 * 1024 * 1024; - static constexpr auto response_first_alloc_bytes = 32 * 1024; - static constexpr auto response_next_alloc_bytes = 256 * 1024; - std::string m_host; - uint16_t m_port_default; - uint16_t m_port; - std::string m_path; - std::string m_method; - std::string m_headers; - std::string m_error_what; - - boost::asio::io_service m_service; - boost::asio::ssl::context *m_context; - boost::asio::ip::tcp::endpoint m_endpoint; - - void ctor_priv(); -}; - -}} // namespace graphene::peerplays_sidechain - -namespace graphene { namespace peerplays_sidechain { - class rpc_client { public: - rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug); + rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls); protected: std::string retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx); std::string retrieve_value_from_reply(std::string reply_str, std::string value_path); std::string send_post_request(std::string method, std::string params, bool show_log); + std::string url; + std::string user; + std::string password; bool debug_rpc_calls; + uint32_t request_id; private: - http_call client; - http_response send_post_request(const std::string &body, bool show_log); + rpc_reply send_post_request(std::string body, bool show_log); }; }} // namespace graphene::peerplays_sidechain 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 964ee4a9..b9a7e927 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,5 +1,8 @@ #pragma once +#include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { }}} // namespace graphene::peerplays_sidechain::ethereum 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 8db8d59f..43fc38dc 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 @@ -1,5 +1,8 @@ #pragma once +#include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { class ethereum_function_call_encoder { 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 d8662d2a..94750cc7 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 @@ -12,11 +12,12 @@ namespace graphene { namespace peerplays_sidechain { -class ethereum_node_rpc_client : public rpc_client { +class ethereum_rpc_client : public rpc_client { public: - ethereum_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); + ethereum_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); std::string admin_node_info(); + std::string eth_get_block_by_number(std::string block_number, bool full_block); std::string net_version(); std::string get_chain_id(); @@ -41,7 +42,7 @@ private: std::string node_rpc_url; std::string node_rpc_user; std::string node_rpc_password; - ethereum_node_rpc_client *node_rpc_client; + ethereum_rpc_client *ethereum_client; ethereum::chain_id_type chain_id; ethereum::network_id_type network_id; diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 0e422961..ab0628ab 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -159,8 +159,8 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("ethereum-sidechain-enabled", bpo::value()->default_value(false), "Ethereum sidechain handler enabled"); cli.add_options()("ethereum-node-rpc-url", bpo::value()->default_value("127.0.0.1:8545"), "Ethereum node RPC URL [http[s]://]host[:port]"); - cli.add_options()("ethereum-node-rpc-user", bpo::value()->default_value("1"), "Ethereum RPC user"); - cli.add_options()("ethereum-node-rpc-password", bpo::value()->default_value("1"), "Ethereum RPC password"); + 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-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)"); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 6cbd47fc..dc27b0b8 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -22,26 +22,31 @@ namespace graphene { namespace peerplays_sidechain { -ethereum_node_rpc_client::ethereum_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : +ethereum_rpc_client::ethereum_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : rpc_client(url, user_name, password, debug_rpc_calls) { } -std::string ethereum_node_rpc_client::admin_node_info() { +std::string ethereum_rpc_client::admin_node_info() { return send_post_request("admin_nodeInfo", "", debug_rpc_calls); } -std::string ethereum_node_rpc_client::net_version() { +std::string ethereum_rpc_client::eth_get_block_by_number(std::string block_number, bool full_block) { + std::string params = "[ \"" + block_number + "\", " + (full_block ? "true" : "false") + "]"; + return send_post_request("eth_getBlockByNumber", params, debug_rpc_calls); +} + +std::string ethereum_rpc_client::net_version() { return send_post_request("net_version", "", debug_rpc_calls); } -std::string ethereum_node_rpc_client::get_chain_id() { +std::string ethereum_rpc_client::get_chain_id() { std::string reply_str = net_version(); - return retrieve_value_from_reply(reply_str, "result"); + return retrieve_value_from_reply(reply_str, ""); } -std::string ethereum_node_rpc_client::get_network_id() { +std::string ethereum_rpc_client::get_network_id() { std::string reply_str = admin_node_info(); - return retrieve_value_from_reply(reply_str, "result.protocols.eth.network"); + return retrieve_value_from_reply(reply_str, "protocols.eth.network"); } sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : @@ -76,15 +81,15 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha } } - node_rpc_client = new ethereum_node_rpc_client(node_rpc_url, node_rpc_user, node_rpc_password, debug_rpc_calls); + ethereum_client = new ethereum_rpc_client(node_rpc_url, node_rpc_user, node_rpc_password, debug_rpc_calls); - std::string chain_id_str = node_rpc_client->get_chain_id(); + std::string chain_id_str = ethereum_client->get_chain_id(); if (chain_id_str.empty()) { elog("No Ethereum node running at ${url}", ("url", node_rpc_url)); FC_ASSERT(false); } chain_id = std::stoll(chain_id_str); - std::string network_id_str = node_rpc_client->get_network_id(); + std::string network_id_str = ethereum_client->get_network_id(); network_id = std::stoll(network_id_str); ilog("Running on Ethereum network, chain id ${chain_id_str}, network id ${network_id_str}", ("chain_id_str", chain_id_str)("network_id_str", network_id_str)); @@ -123,8 +128,6 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { std::stringstream active_pw_ss(reply_str); - ilog("### process_primary_wallet: ${reply}", ("reply", reply_str)); - boost::property_tree::ptree active_pw_pt; boost::property_tree::read_json(active_pw_ss, active_pw_pt); if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { @@ -309,7 +312,7 @@ std::string sidechain_net_handler_ethereum::send_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 = 1000; + int64_t time_to_next = 5000; fc::time_point next_wakeup(now + fc::milliseconds(time_to_next)); @@ -321,6 +324,8 @@ void sidechain_net_handler_ethereum::schedule_ethereum_listener() { void sidechain_net_handler_ethereum::ethereum_listener_loop() { schedule_ethereum_listener(); + + std::string reply = ethereum_client->eth_get_block_by_number("latest", true); } void sidechain_net_handler_ethereum::handle_event(const std::string &event_data) { -- 2.45.2 From 3545efbf942cd0589a3c80f193a9d3f16fb38c5f Mon Sep 17 00:00:00 2001 From: serkixenos Date: Thu, 7 Jul 2022 18:27:47 +0200 Subject: [PATCH 27/60] Boost Beast based HTTP client for SONs --- .../peerplays_sidechain/common/rpc_client.cpp | 1034 ++--------------- .../peerplays_sidechain/common/rpc_client.hpp | 124 +- 2 files changed, 121 insertions(+), 1037 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp index d08d337b..1bbe0721 100644 --- a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp +++ b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp @@ -1,883 +1,101 @@ #include +#include #include #include -//#include - -#include -#include -#include +#include +#include +#include #include #include +#include + +#include -#include #include -#include namespace graphene { namespace peerplays_sidechain { -constexpr auto http_port = 80; -constexpr auto https_port = 443; +rpc_client::rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls) : + url(_url), + user(_user), + password(_password), + debug_rpc_calls(_debug_rpc_calls), + request_id(0) { -template -void make_trimmed(string *str) { - boost::algorithm::trim(*str); -} + std::string reg_expr = "^((?Phttps|http):\\/\\/)?(?P[a-zA-Z0-9\\-\\.]+)(:(?P\\d{1,5}))?(?P\\/.+)?"; + boost::xpressive::sregex sr = boost::xpressive::sregex::compile(reg_expr); -template -void make_lower(string *str) { - boost::algorithm::to_lower(*str); -} + boost::xpressive::smatch sm; -bool convert_hex_to_num_helper1(const std::string &str, uint32_t *value) { - try { - size_t idx; - auto v = stol(str, &idx, 16); - if (idx != str.size()) - return false; - if (value) - *value = v; - return true; - } catch (...) { - return false; - } -} - -bool convert_dec_to_num_helper1(const std::string &str, uint32_t *value) { - try { - size_t idx; - auto v = stol(str, &idx, 10); - if (idx != str.size()) - return false; - if (value) - *value = v; - return true; - } catch (...) { - return false; - } -} - -bool convert_dec_to_num_helper1(const std::string &str, uint16_t *value) { - try { - size_t idx; - auto v = stol(str, &idx, 10); - if (idx != str.size()) - return false; - if (v > std::numeric_limits::max()) - return false; - if (value) - *value = v; - return true; - } catch (...) { - return false; - } -} - -template -constexpr V ceilDiv(V value, D divider) { - return (value + divider - 1) / divider; -} - -template -constexpr V aligned(V value, A align) { - return ceilDiv(value, align) * align; -} - -template -void reserve( - Container *container, - typename Container::size_type freeSpaceRequired, - typename Container::size_type firstAlloc, - typename Container::size_type nextAlloc) { - //TSL_ASSERT(container); - auto &c = *container; - auto required = c.size() + freeSpaceRequired; - if (c.capacity() >= required) - return; - c.reserve((firstAlloc >= required) ? firstAlloc - : firstAlloc + aligned(required - firstAlloc, nextAlloc)); -} - -template -void reserve( - Container *container, - typename Container::size_type freeSpaceRequired, - typename Container::size_type alloc) { - //TSL_ASSERT(container); - auto &c = *container; - auto required = c.size() + freeSpaceRequired; - if (c.capacity() >= required) - return; - c.reserve(aligned(required, alloc)); -} - -bool is_valid(const boost::asio::ip::tcp::endpoint &ep) { - - if (ep.port() == 0) - return false; - - if (ep.address().is_unspecified()) - return false; - - return true; -} - -// utl - -url_schema_type identify_url_schema_type(const std::string &schema_name) { - // rework - auto temp = schema_name; - make_lower(&temp); - if (temp == "http") - return url_schema_type::http; - if (temp == "https") - return url_schema_type::https; - return url_schema_type::unknown; -} - -// url_data - -url_data::url_data(const std::string &url) { - if (!parse(url)) - FC_THROW("URL parse failed"); -} - -void url_data::clear() { - schema_type = url_schema_type::unknown; - schema = decltype(schema)(); - host = decltype(host)(); - port = 0; - path = decltype(path)(); -} - -bool url_data::parse(const std::string &url) { - - typedef std::string::size_type size_t; - constexpr auto npos = std::string::npos; - - size_t schema_end = url.find("://"); - size_t host_begin; - std::string temp_schema; - - if (schema_end == npos) - host_begin = 0; // no schema - else { - if (schema_end < 3) { // schema too short: less than 3 chars - return false; + if (boost::xpressive::regex_search(url, sm, sr)) { + protocol = sm["Protocol"]; + if (protocol.empty()) { + protocol = "http"; } - if (schema_end > 5) { // schema too long: more than 5 chars - return false; + + host = sm["Host"]; + if (host.empty()) { + host + "localhost"; } - host_begin = schema_end + 3; - temp_schema = url.substr(0, schema_end); - } - // ASSERT(url.size() >= host_begin); + port = sm["Port"]; + if (port.empty()) { + port = "80"; + } - if (url.size() == host_begin) // host is empty - return false; - - size_t port_sep = url.find(':', host_begin); - - if (port_sep == host_begin) - return false; - - size_t path_sep = url.find('/', host_begin); - - if (path_sep == host_begin) - return false; - - if ((port_sep != npos) && (path_sep != npos) && (port_sep > path_sep)) - port_sep = npos; - - std::string temp_port; - - if (port_sep != npos) { - auto port_index = port_sep + 1; - if (path_sep == npos) - temp_port = url.substr(port_index); - else - temp_port = url.substr(port_index, path_sep - port_index); - } - - if (temp_port.empty()) - port = 0; - else { - if (!convert_dec_to_num_helper1(temp_port, &port)) - return false; - } - - std::string temp_path; - - if (path_sep != npos) - temp_path = url.substr(path_sep); - - std::string temp_host; - - if (port_sep != npos) { - temp_host = url.substr(host_begin, port_sep - host_begin); + target = sm["Target"]; + if (target.empty()) { + target = "/"; + } } else { - if (path_sep != npos) - temp_host = url.substr(host_begin, path_sep - host_begin); - else - temp_host = url.substr(host_begin); + elog("Invalid URL: ${url}", ("url", url)); } - - schema = temp_schema; - host = temp_host; - path = temp_path; - schema_type = identify_url_schema_type(schema); - - return true; -} - -}} // namespace graphene::peerplays_sidechain - -namespace graphene { namespace peerplays_sidechain { - -using namespace boost::asio; -using error_code = boost::system::error_code; -using endpoint = ip::tcp::endpoint; - -namespace detail { - -// http_call_impl - -struct tcp_socket { - - typedef ip::tcp::socket underlying_type; - - underlying_type underlying; - - tcp_socket(http_call &call) : - underlying(call.m_service) { - } - - underlying_type &operator()() { - return underlying; - } - - void connect(const http_call &call, const endpoint &ep, error_code *ec) { - // TCP connect - underlying.connect(ep, *ec); - } - - void shutdown() { - error_code ec; - underlying.close(ec); - } -}; - -struct ssl_socket { - - typedef ssl::stream underlying_type; - - underlying_type underlying; - - ssl_socket(http_call &call) : - underlying(call.m_service, *call.m_context) { - } - - underlying_type &operator()() { - return underlying; - } - - void connect(const http_call &call, const endpoint &ep, error_code *ec) { - - auto &u = underlying; - - // TCP connect - u.lowest_layer().connect(ep, *ec); - - // SSL connect - if (!SSL_set_tlsext_host_name(u.native_handle(), call.m_host.c_str())) - FC_THROW("SSL_set_tlsext_host_name failed"); - - u.set_verify_mode(ssl::verify_peer, *ec); - u.handshake(ssl::stream_base::client, *ec); - } - - void shutdown() { - auto &u = underlying; - error_code ec; - u.shutdown(ec); - u.lowest_layer().close(ec); - } -}; - -template -class http_call_impl { -public: - http_call_impl(http_call &call, const void *body_data, size_t body_size, const std::string &content_type_, http_response &response); - void exec(); - -private: - http_call &call; - const void *body_data; - size_t body_size; - std::string content_type; - http_response &response; - - socket_type socket; - streambuf response_buf; - - int32_t content_length; - bool transfer_encoding_chunked; - -private: - void connect(); - void shutdown(); - void send_request(); - void on_header(std::string &name, std::string &value); - void on_header(); - void process_headers(); - void append_entity_body(std::istream *stream, size_t size); - void append_entity_body_2(std::istream *strm); - bool read_next_chunk(std::istream *strm); - void skip_footer(); - void read_body_chunked(); - void read_body_until_eof(); - void read_body_exact(); - void process_response(); -}; - -static const char cr = 0x0D; -static const char lf = 0x0A; -static const char *crlf = "\x0D\x0A"; -static const char *crlfcrlf = "\x0D\x0A\x0D\x0A"; -static const auto crlf_uint = (((uint16_t)lf) << 8) + cr; - -template -http_call_impl::http_call_impl(http_call &call_, const void *body_data_, size_t body_size_, const std::string &content_type_, http_response &response_) : - call(call_), - body_data(body_data_), - body_size(body_size_), - content_type(content_type_), - response(response_), - socket(call), - response_buf(http_call::response_size_limit_bytes) { -} - -template -void http_call_impl::exec() { - try { - connect(); - send_request(); - process_response(); - shutdown(); - } catch (...) { - shutdown(); - throw; - } -} - -template -void http_call_impl::connect() { - - { - error_code ec; - auto &ep = call.m_endpoint; - if (is_valid(ep)) { - socket.connect(call, ep, &ec); - if (!ec) - return; - } - } - - ip::tcp::resolver resolver(call.m_service); - - auto rng = resolver.resolve(call.m_host, std::string()); - - //ASSERT(rng.begin() != rng.end()); - - error_code ec; - - for (endpoint ep : rng) { - ep.port(call.m_port); - socket.connect(call, ep, &ec); - if (!ec) { - call.m_endpoint = ep; - return; // comment to test1 - } - } - // if (!ec) return; // uncomment to test1 - - //ASSERT(ec); - throw boost::system::system_error(ec); -} - -template -void http_call_impl::shutdown() { - socket.shutdown(); -} - -template -void http_call_impl::send_request() { - - streambuf request; - std::ostream stream(&request); - - // start string: HTTP/1.0 - - //ASSERT(!call.m_path.empty()); - - stream << call.m_method << " " << call.m_path << " HTTP/1.1" << crlf; - - // host - - stream << "Host: " << call.m_host << ":" << call.m_endpoint.port() << crlf; - - // content - - if (body_size) { - stream << "Content-Type: " << content_type << crlf; - stream << "Content-Length: " << body_size << crlf; - } - - // additional headers - - const auto &h = call.m_headers; - - if (!h.empty()) { - if (h.size() < 2) - FC_THROW("invalid headers data"); - stream << h; - // ensure headers finished correctly - if ((h.substr(h.size() - 2) != crlf)) - stream << crlf; - } - - // other - - // stream << "Accept: *\x2F*" << crlf; - stream << "Accept: text/html, application/json" << crlf; - stream << "Connection: close" << crlf; - - // end - - stream << crlf; - - // send headers - - write(socket(), request); - - // send body - - if (body_size) - write(socket(), buffer(body_data, body_size)); -} - -template -void http_call_impl::on_header(std::string &name, std::string &value) { - - if (name == "content-length") { - uint32_t u; - if (!convert_dec_to_num_helper1(value, &u)) - FC_THROW("invalid content-length header data"); - content_length = u; - return; - } - - if (name == "transfer-encoding") { - boost::algorithm::to_lower(value); - if (value == "chunked") - transfer_encoding_chunked = true; - return; - } -} - -template -void http_call_impl::process_headers() { - - std::istream stream(&response_buf); - - std::string http_version; - stream >> http_version; - stream >> response.status_code; - - make_trimmed(&http_version); - make_lower(&http_version); - - if (!stream || http_version.substr(0, 6) != "http/1") - FC_THROW("invalid response data"); - - // read/skip headers - - content_length = -1; - transfer_encoding_chunked = false; - - for (;;) { - std::string header; - if (!std::getline(stream, header, lf) || (header.size() == 1 && header[0] == cr)) - break; - auto pos = header.find(':'); - if (pos == std::string::npos) - continue; - auto name = header.substr(0, pos); - make_trimmed(&name); - boost::algorithm::to_lower(name); - auto value = header.substr(pos + 1); - make_trimmed(&value); - on_header(name, value); - } -} - -template -void http_call_impl::append_entity_body(std::istream *strm, size_t size) { - if (size == 0) - return; - auto &body = response.body; - reserve(&body, size, http_call::response_first_alloc_bytes, http_call::response_next_alloc_bytes); - auto cur = body.size(); - body.resize(cur + size); - auto p = &body[cur]; - if (!strm->read(p, size)) - FC_THROW("stream read failed"); -} - -template -void http_call_impl::append_entity_body_2(std::istream *strm) { - auto avail = response_buf.size(); - if (response.body.size() + avail > http_call::response_size_limit_bytes) - FC_THROW("response body size limit exceeded"); - append_entity_body(strm, avail); -} - -template -bool http_call_impl::read_next_chunk(std::istream *strm) { - - // content length info is used as pre-alloc hint only - // it is not used inside the reading logic - - auto &buf = response_buf; - auto &stream = *strm; - auto &body = response.body; - - read_until(socket(), buf, crlf); - - std::string chunk_header; - - if (!std::getline(stream, chunk_header, lf)) - FC_THROW("failed to read chunk size"); - - auto ext_index = chunk_header.find(':'); - - if (ext_index != std::string::npos) - chunk_header.resize(ext_index); - - make_trimmed(&chunk_header); - - uint32_t chink_size; - - if (!convert_hex_to_num_helper1(chunk_header, &chink_size)) - FC_THROW("invalid chunk size string"); - - if (body.size() + chink_size > http_call::response_size_limit_bytes) - FC_THROW("response body size limit exceeded"); - - auto avail = buf.size(); - if (avail < chink_size + 2) { - auto rest = chink_size + 2 - avail; - read(socket(), buf, transfer_at_least(rest)); - } - - append_entity_body(&stream, chink_size); - - uint16_t temp; - if (!stream.read((char *)(&temp), 2)) - FC_THROW("stream read failed"); - if (temp != crlf_uint) - FC_THROW("invalid chink end"); - - return chink_size != 0; -} - -template -void http_call_impl::skip_footer() { - // to be implemeted -} - -template -void http_call_impl::read_body_chunked() { - - std::istream stream(&response_buf); - - for (;;) { - if (!read_next_chunk(&stream)) - break; - } - - skip_footer(); -} - -template -void http_call_impl::read_body_until_eof() { - - auto &buf = response_buf; - std::istream stream(&buf); - - append_entity_body_2(&stream); - - error_code ec; - - for (;;) { - auto readed = read(socket(), buf, transfer_at_least(1), ec); - append_entity_body_2(&stream); - if (ec) - break; - if (!readed) { - //ASSERT(buf.size() == 0); - FC_THROW("logic error: read failed but no error conditon"); - } - } - if ((ec != error::eof) && - (ec != ssl::error::stream_truncated)) - throw boost::system::system_error(ec); -} - -template -void http_call_impl::read_body_exact() { - - auto &buf = response_buf; - auto &body = response.body; - - auto avail = buf.size(); - - if (avail > ((size_t)content_length)) - FC_THROW("invalid response body (content length mismatch)"); - - body.resize(content_length); - - if (avail) { - if (avail != ((size_t)buf.sgetn(&body[0], avail))) - FC_THROW("stream read failed"); - } - - auto rest = content_length - avail; - - if (rest > 0) { - auto readed = read(socket(), buffer(&body[avail], rest), transfer_exactly(rest)); - //ASSERT(readed <= rest); - if (readed < rest) - FC_THROW("logic error: read failed but no error conditon"); - } -} - -template -void http_call_impl::process_response() { - - auto &buf = response_buf; - auto &body = response.body; - - read_until(socket(), buf, crlfcrlf); - - process_headers(); - - // check content length - - if (content_length >= 0) { - if (content_length < 2) { // minimum content is "{}" - FC_THROW("invalid response body (too short)"); - } - if (content_length > http_call::response_size_limit_bytes) - FC_THROW("response body size limit exceeded"); - body.reserve(content_length); - } - - if (transfer_encoding_chunked) { - read_body_chunked(); - } else { - if (content_length < 0) - read_body_until_eof(); - else { - if (content_length > 0) - read_body_exact(); - } - } -} - -} // namespace detail - -// https_call - -http_call::http_call(const url_data &url, const std::string &method, const std::string &headers) : - m_host(url.host), - m_method(method), - m_headers(headers) { - - if (url.schema_type == url_schema_type::https) { - m_context = new boost::asio::ssl::context(ssl::context::tlsv12_client); - } else { - m_context = 0; - } - - if (url.port) - m_port_default = url.port; - else { - if (url.schema_type == url_schema_type::https) - m_port_default = https_port; - else - m_port_default = http_port; - } - - m_port = m_port_default; - - set_path(url.path); - - try { - ctor_priv(); - } catch (...) { - if (m_context) - delete m_context; - throw; - } -} - -http_call::~http_call() { - if (m_context) - delete m_context; -} - -bool http_call::is_ssl() const { - return m_context != 0; -} - -const std::string &http_call::path() const { - return m_path; -} - -void http_call::set_path(const std::string &path) { - if (path.empty()) - m_path = "/"; - else - m_path = path; -} - -void http_call::set_method(const std::string &method) { - m_method = method; -} - -void http_call::set_headers(const std::string &headers) { - m_headers = headers; -} - -const std::string &http_call::host() const { - return m_host; -} - -void http_call::set_host(const std::string &host) { - m_host = host; -} - -uint16_t http_call::port() const { - return m_port; -} - -void http_call::set_port(uint16_t port) { - if (port) - m_port = port; - else - m_port = m_port_default; -} - -bool http_call::exec(const http_request &request, http_response *response) { - - //ASSERT(response); - auto &resp = *response; - m_error_what = decltype(m_error_what)(); - resp.clear(); - - try { - try { - using namespace detail; - if (!m_context) - http_call_impl(*this, request.body.data(), request.body.size(), request.content_type, resp).exec(); - else - http_call_impl(*this, request.body.data(), request.body.size(), request.content_type, resp).exec(); - return true; - } catch (const std::exception &e) { - m_error_what = e.what(); - } - } catch (...) { - m_error_what = "unknown exception"; - } - - resp.clear(); - return false; -} - -const std::string &http_call::error_what() const { - return m_error_what; -} - -void http_call::ctor_priv() { - if (m_context) { - m_context->set_default_verify_paths(); - m_context->set_options(ssl::context::default_workarounds); - } -} - -}} // namespace graphene::peerplays_sidechain - -namespace graphene { namespace peerplays_sidechain { - -rpc_client::rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug) : - debug_rpc_calls(debug), - request_id(0), - client(url) - -{ - - client.set_method("POST"); - client.set_headers("Authorization : Basic" + fc::base64_encode(user_name + ":" + password)); } std::string rpc_client::retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx) { - if (reply_str.empty()) - return std::string(); std::stringstream ss(reply_str); boost::property_tree::ptree json; boost::property_tree::read_json(ss, json); if (json.find("result") == json.not_found()) { - return std::string(); - } - auto json_result = json.get_child("result"); - if (json_result.find(array_path) == json_result.not_found()) { - return std::string(); + return ""; } - boost::property_tree::ptree array_ptree = json_result; - if (!array_path.empty()) { - array_ptree = json_result.get_child(array_path); - } - uint32_t array_el_idx = -1; - for (const auto &array_el : array_ptree) { - array_el_idx = array_el_idx + 1; - if (array_el_idx == idx) { - std::stringstream ss_res; - boost::property_tree::json_parser::write_json(ss_res, array_el.second); - return ss_res.str(); + auto json_result = json.get_child_optional("result"); + if (json_result) { + boost::property_tree::ptree array_ptree = json_result.get(); + if (!array_path.empty()) { + array_ptree = json_result.get().get_child(array_path); + } + uint32_t array_el_idx = -1; + for (const auto &array_el : array_ptree) { + array_el_idx = array_el_idx + 1; + if (array_el_idx == idx) { + std::stringstream ss_res; + boost::property_tree::json_parser::write_json(ss_res, array_el.second); + return ss_res.str(); + } } } - return std::string(); + return ""; } std::string rpc_client::retrieve_value_from_reply(std::string reply_str, std::string value_path) { - if (reply_str.empty()) - return std::string(); std::stringstream ss(reply_str); boost::property_tree::ptree json; boost::property_tree::read_json(ss, json); if (json.find("result") == json.not_found()) { - return std::string(); + return ""; } - auto json_result = json.get_child("result"); - if (json_result.find(value_path) == json_result.not_found()) { - return std::string(); + + auto json_result = json.get_child_optional("result"); + if (json_result) { + return json_result.get().get(value_path); } - return json_result.get(value_path); + + return json.get("result"); } std::string rpc_client::send_post_request(std::string method, std::string params, bool show_log) { @@ -904,7 +122,7 @@ std::string rpc_client::send_post_request(std::string method, std::string params boost::property_tree::ptree json; boost::property_tree::read_json(ss, json); - if (reply.status_code == 200) { + if (reply.status == 200) { return ss.str(); } @@ -914,104 +132,68 @@ std::string rpc_client::send_post_request(std::string method, std::string params return ""; } -//fc::http::reply rpc_client::send_post_request(std::string body, bool show_log) { -// fc::http::connection conn; -// conn.connect_to(fc::ip::endpoint(fc::ip::address(ip), port)); -// -// std::string url = "http://" + ip + ":" + std::to_string(port); -// -// //if (wallet.length() > 0) { -// // url = url + "/wallet/" + wallet; -// //} -// -// fc::http::reply reply = conn.request("POST", url, body, fc::http::headers{authorization}); -// -// if (show_log) { -// ilog("### Request URL: ${url}", ("url", url)); -// ilog("### Request: ${body}", ("body", body)); -// std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); -// ilog("### Response: ${ss}", ("ss", ss.str())); -// } -// -// return reply; -//} +rpc_reply rpc_client::send_post_request(std::string body, bool show_log) { -//static size_t write_callback(char *ptr, size_t size, size_t nmemb, rpc_reply *reply) { -// size_t retval = 0; -// if (reply != nullptr) { -// reply->body.append(ptr, size * nmemb); -// retval = size * nmemb; -// } -// return retval; -//} + // The io_context is required for all I/O + boost::beast::net::io_context ioc; -//rpc_reply rpc_client::send_post_request(std::string body, bool show_log) { -// -// struct curl_slist *headers = nullptr; -// headers = curl_slist_append(headers, "Accept: application/json"); -// headers = curl_slist_append(headers, "Content-Type: application/json"); -// headers = curl_slist_append(headers, "charset: utf-8"); -// -// CURL *curl = curl_easy_init(); -// if (ip.find("https://", 0) != 0) { -// curl_easy_setopt(curl, CURLOPT_URL, ip.c_str()); -// curl_easy_setopt(curl, CURLOPT_PORT, port); -// } else { -// std::string full_address = ip + ":" + std::to_string(port); -// curl_easy_setopt(curl, CURLOPT_URL, full_address.c_str()); -// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); -// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); -// } -// if (!user.empty()) { -// curl_easy_setopt(curl, CURLOPT_USERNAME, user.c_str()); -// curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); -// } -// -// curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); -// curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str()); -// -// //curl_easy_setopt(curl, CURLOPT_VERBOSE, true); -// -// rpc_reply reply; -// -// curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); -// curl_easy_setopt(curl, CURLOPT_WRITEDATA, &reply); -// -// curl_easy_perform(curl); -// -// curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &reply.status); -// -// curl_easy_cleanup(curl); -// curl_slist_free_all(headers); -// -// if (show_log) { -// std::string url = ip + ":" + std::to_string(port); -// ilog("### Request URL: ${url}", ("url", url)); -// ilog("### Request: ${body}", ("body", body)); -// std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); -// ilog("### Response: ${ss}", ("ss", ss.str())); -// } -// -// return reply; -//} + // These objects perform our I/O + boost::beast::net::ip::tcp::resolver resolver(ioc); + boost::beast::tcp_stream stream(ioc); -http_response rpc_client::send_post_request(const std::string &body, bool show_log) { + // Look up the domain name + auto const results = resolver.resolve(host, port); - http_request request(body, "application/json"); - http_response response; + // Make the connection on the IP address we get from a lookup + stream.connect(results); - client.exec(request, &response); + // Set up an HTTP GET request message + boost::beast::http::request req{boost::beast::http::verb::post, target, 11}; + req.set(boost::beast::http::field::host, host + ":" + port); + req.set(boost::beast::http::field::accept, "application/json"); + req.set(boost::beast::http::field::content_type, "application/json"); + req.set(boost::beast::http::field::content_encoding, "utf-8"); + req.set(boost::beast::http::field::content_length, body.length()); + req.body() = body; + + // Send the HTTP request to the remote host + boost::beast::http::write(stream, req); + + // This buffer is used for reading and must be persisted + boost::beast::flat_buffer buffer; + + // Declare a container to hold the response + boost::beast::http::response res; + + // Receive the HTTP response + boost::beast::http::read(stream, buffer, res); + + //// Write the message to standard out + //std::cout << res << std::endl; + + // Gracefully close the socket + boost::beast::error_code ec; + stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); + + // not_connected happens sometimes + // so don't bother reporting it. + // + if (ec && ec != boost::beast::errc::not_connected) + throw boost::beast::system_error{ec}; + + std::string rbody{boost::asio::buffers_begin(res.body().data()), + boost::asio::buffers_end(res.body().data())}; + rpc_reply reply; + reply.status = 200; + reply.body = rbody; if (show_log) { - std::string url = client.is_ssl() ? "https" : "http"; - url = url + "://" + client.host() + ":" + std::to_string(client.port()) + client.path(); ilog("### Request URL: ${url}", ("url", url)); ilog("### Request: ${body}", ("body", body)); - std::stringstream ss(std::string(response.body.begin(), response.body.end())); - ilog("### Response: ${ss}", ("ss", ss.str())); + ilog("### Response: ${rbody}", ("rbody", rbody)); } - return response; + return reply; } }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp index 63d218ee..c7cc8921 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp @@ -3,134 +3,36 @@ #include #include -#include -#include - -//#include - namespace graphene { namespace peerplays_sidechain { -enum class url_schema_type { unknown, - http, - https, -}; - -// utl - -url_schema_type identify_url_schema_type(const std::string &schema_name); - -struct url_data { - - url_schema_type schema_type; - std::string schema; - std::string host; - uint16_t port; - std::string path; - - url_data() : - schema_type(url_schema_type::unknown), - port(0) { - } - - url_data(const std::string &url); - - void clear(); - - bool parse(const std::string &url); -}; - -struct http_request { - +struct rpc_reply { + uint16_t status; std::string body; - std::string content_type; - - http_request(const std::string &body_, const std::string &content_type_) : - body(body_), - content_type(content_type_) { - } }; -struct http_response { - - uint16_t status_code; - std::string body; - - void clear() { - status_code = 0; - body = decltype(body)(); - } -}; - -namespace detail { -template -class http_call_impl; -class tcp_socket; -class ssl_socket; -} // namespace detail - -class http_call { -public: - http_call(const url_data &url, const std::string &method = std::string(), const std::string &headers = std::string()); - ~http_call(); - - bool is_ssl() const; - - const std::string &path() const; - void set_path(const std::string &path); - void set_method(const std::string &method); - void set_headers(const std::string &headers); - const std::string &host() const; - void set_host(const std::string &host); - - uint16_t port() const; - void set_port(uint16_t port); - - bool exec(const http_request &request, http_response *response); - - const std::string &error_what() const; - -private: - template - friend class detail::http_call_impl; - friend detail::tcp_socket; - friend detail::ssl_socket; - static constexpr auto response_size_limit_bytes = 16 * 1024 * 1024; - static constexpr auto response_first_alloc_bytes = 32 * 1024; - static constexpr auto response_next_alloc_bytes = 256 * 1024; - std::string m_host; - uint16_t m_port_default; - uint16_t m_port; - std::string m_path; - std::string m_method; - std::string m_headers; - std::string m_error_what; - - boost::asio::io_service m_service; - boost::asio::ssl::context *m_context; - boost::asio::ip::tcp::endpoint m_endpoint; - - void ctor_priv(); -}; - -}} // namespace graphene::peerplays_sidechain - -namespace graphene { namespace peerplays_sidechain { - class rpc_client { public: - rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug); + rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls); protected: std::string retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx); std::string retrieve_value_from_reply(std::string reply_str, std::string value_path); std::string send_post_request(std::string method, std::string params, bool show_log); + std::string url; + std::string protocol; + std::string host; + std::string port; + std::string target; + + std::string user; + std::string password; bool debug_rpc_calls; + uint32_t request_id; private: - http_call client; - http_response send_post_request(const std::string &body, bool show_log); + rpc_reply send_post_request(std::string body, bool show_log); }; }} // namespace graphene::peerplays_sidechain -- 2.45.2 From 47023be7c5e613ba42bfba7eaad96094cd68bf4d Mon Sep 17 00:00:00 2001 From: serkixenos Date: Mon, 11 Jul 2022 18:30:39 +0200 Subject: [PATCH 28/60] Config file options cleanup --- .../sidechain_net_handler_bitcoin.hpp | 7 +- .../sidechain_net_handler_ethereum.hpp | 8 +- .../sidechain_net_handler_hive.hpp | 14 +-- .../peerplays_sidechain_plugin.cpp | 12 ++- .../sidechain_net_handler_bitcoin.cpp | 20 ++-- .../sidechain_net_handler_ethereum.cpp | 16 ++-- .../sidechain_net_handler_hive.cpp | 96 ++++++++++--------- 7 files changed, 92 insertions(+), 81 deletions(-) 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 6fd1fcfa..5f36e5af 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 @@ -79,7 +79,7 @@ private: uint32_t rpc_port; std::string user; std::string password; - std::string wallet; + std::string wallet_name; std::string wallet_password; bool debug_rpc_calls; @@ -130,17 +130,18 @@ private: std::string ip; uint32_t zmq_port; uint32_t rpc_port; - uint32_t bitcoin_major_version; std::string rpc_user; std::string rpc_password; - std::string wallet; + std::string wallet_name; std::string wallet_password; std::unique_ptr bitcoin_client; std::unique_ptr listener; fc::future on_changed_objects_task; + bitcoin::bitcoin_address::network network_type; + uint32_t bitcoin_major_version; std::mutex event_handler_mutex; typedef std::lock_guard scoped_lock; 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 94750cc7..745c26bb 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 @@ -39,9 +39,11 @@ public: bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); private: - std::string node_rpc_url; - std::string node_rpc_user; - std::string node_rpc_password; + std::string rpc_url; + std::string rpc_user; + std::string rpc_password; + std::string wallet_contract_address; + ethereum_rpc_client *ethereum_client; ethereum::chain_id_type chain_id; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp index 47e6bf90..a0cb6038 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp @@ -12,9 +12,9 @@ namespace graphene { namespace peerplays_sidechain { -class hive_node_rpc_client : public rpc_client { +class hive_rpc_client : public rpc_client { public: - hive_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); + hive_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); std::string account_history_api_get_transaction(std::string transaction_id); std::string block_api_get_block(uint32_t block_number); @@ -48,10 +48,12 @@ public: bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); private: - std::string node_rpc_url; - std::string node_rpc_user; - std::string node_rpc_password; - hive_node_rpc_client *node_rpc_client; + std::string rpc_url; + std::string rpc_user; + std::string rpc_password; + std::string wallet_account_name; + + hive_rpc_client *rpc_client; hive::chain_id_type chain_id; hive::network network_type; diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index ab0628ab..73bef93f 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -152,7 +152,7 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("bitcoin-node-rpc-port", bpo::value()->default_value(8332), "RPC port of Bitcoin node"); cli.add_options()("bitcoin-node-rpc-user", bpo::value()->default_value("1"), "Bitcoin RPC user"); cli.add_options()("bitcoin-node-rpc-password", bpo::value()->default_value("1"), "Bitcoin RPC password"); - cli.add_options()("bitcoin-wallet", bpo::value(), "Bitcoin wallet"); + cli.add_options()("bitcoin-wallet-name", bpo::value(), "Bitcoin wallet name"); cli.add_options()("bitcoin-wallet-password", bpo::value(), "Bitcoin wallet password"); cli.add_options()("bitcoin-private-key", bpo::value>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")), "Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)"); @@ -161,15 +161,17 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("ethereum-node-rpc-url", bpo::value()->default_value("127.0.0.1:8545"), "Ethereum node RPC URL [http[s]://]host[:port]"); 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-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)"); + cli.add_options()("ethereum-wallet-contract-address", bpo::value()->default_value("0000000000000000000000000000000000000000"), "Ethereum wallet contract address"), + 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)"); cli.add_options()("hive-sidechain-enabled", bpo::value()->default_value(false), "Hive sidechain handler enabled"); cli.add_options()("hive-node-rpc-url", bpo::value()->default_value("127.0.0.1:28090"), "Hive node RPC URL [http[s]://]host[:port]"); cli.add_options()("hive-node-rpc-user", bpo::value(), "Hive node RPC user"); cli.add_options()("hive-node-rpc-password", bpo::value(), "Hive node RPC password"); - cli.add_options()("hive-private-key", bpo::value>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", "5JNHfZYKGaomSFvd4NUdQ9qMcEAC43kujbfjueTHpVapX1Kzq2n")), - "Tuple of [Hive public key, Hive private key] (may specify multiple times)"); + cli.add_options()("hive-wallet-account-name", bpo::value()->default_value("son-account"), "Hive wallet account name"), + cli.add_options()("hive-private-key", bpo::value>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", "5JNHfZYKGaomSFvd4NUdQ9qMcEAC43kujbfjueTHpVapX1Kzq2n")), + "Tuple of [Hive public key, Hive private key] (may specify multiple times)"); cfg.add(cli); } diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 6203ff79..3141ddd6 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -25,12 +25,12 @@ namespace graphene { namespace peerplays_sidechain { // ============================================================================= -bitcoin_rpc_client::bitcoin_rpc_client(std::string _ip, uint32_t _rpc, std::string _user, std::string _password, std::string _wallet, std::string _wallet_password, bool _debug_rpc_calls) : +bitcoin_rpc_client::bitcoin_rpc_client(std::string _ip, uint32_t _rpc, std::string _user, std::string _password, std::string _wallet_name, std::string _wallet_password, bool _debug_rpc_calls) : ip(_ip), rpc_port(_rpc), user(_user), password(_password), - wallet(_wallet), + wallet_name(_wallet_name), wallet_password(_wallet_password), debug_rpc_calls(_debug_rpc_calls) { authorization.key = "Authorization"; @@ -1036,8 +1036,8 @@ fc::http::reply bitcoin_rpc_client::send_post_request(std::string body, bool sho std::string url = "http://" + ip + ":" + std::to_string(rpc_port); - if (wallet.length() > 0) { - url = url + "/wallet/" + wallet; + if (wallet_name.length() > 0) { + url = url + "/wallet/" + wallet_name; } fc::http::reply reply = conn.request("POST", url, body, fc::http::headers{authorization}); @@ -1136,9 +1136,9 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain 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(); - wallet = ""; - if (options.count("bitcoin-wallet")) { - wallet = options.at("bitcoin-wallet").as(); + wallet_name = ""; + if (options.count("bitcoin-wallet-name")) { + wallet_name = options.at("bitcoin-wallet-name").as(); } wallet_password = ""; if (options.count("bitcoin-wallet-password")) { @@ -1165,9 +1165,9 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain FC_ASSERT(false); } - bitcoin_client = std::unique_ptr(new bitcoin_rpc_client(ip, rpc_port, rpc_user, rpc_password, wallet, wallet_password, debug_rpc_calls)); - if (!wallet.empty()) { - bitcoin_client->loadwallet(wallet); + bitcoin_client = std::unique_ptr(new bitcoin_rpc_client(ip, rpc_port, rpc_user, rpc_password, wallet_name, wallet_password, debug_rpc_calls)); + if (!wallet_name.empty()) { + bitcoin_client->loadwallet(wallet_name); } std::string blockchain_info = bitcoin_client->getblockchaininfo(); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index dc27b0b8..0dde6927 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -57,18 +57,20 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha debug_rpc_calls = options.at("debug-rpc-calls").as(); } - node_rpc_url = options.at("ethereum-node-rpc-url").as(); + rpc_url = options.at("ethereum-node-rpc-url").as(); if (options.count("ethereum-node-rpc-user")) { - node_rpc_user = options.at("ethereum-node-rpc-user").as(); + rpc_user = options.at("ethereum-node-rpc-user").as(); } else { - node_rpc_user = ""; + rpc_user = ""; } if (options.count("ethereum-node-rpc-password")) { - node_rpc_password = options.at("ethereum-node-rpc-password").as(); + rpc_password = options.at("ethereum-node-rpc-password").as(); } else { - node_rpc_password = ""; + rpc_password = ""; } + wallet_contract_address = options.at("ethereum-wallet-contract-address").as(); + 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) { @@ -81,11 +83,11 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha } } - ethereum_client = new ethereum_rpc_client(node_rpc_url, node_rpc_user, node_rpc_password, debug_rpc_calls); + ethereum_client = new ethereum_rpc_client(rpc_url, rpc_user, rpc_password, debug_rpc_calls); std::string chain_id_str = ethereum_client->get_chain_id(); if (chain_id_str.empty()) { - elog("No Ethereum node running at ${url}", ("url", node_rpc_url)); + elog("No Ethereum node running at ${url}", ("url", rpc_url)); FC_ASSERT(false); } chain_id = std::stoll(chain_id_str); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp index dacd1e9e..00dcce68 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp @@ -30,21 +30,21 @@ namespace graphene { namespace peerplays_sidechain { -hive_node_rpc_client::hive_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : +hive_rpc_client::hive_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : rpc_client(url, user_name, password, debug_rpc_calls) { } -std::string hive_node_rpc_client::account_history_api_get_transaction(std::string transaction_id) { +std::string hive_rpc_client::account_history_api_get_transaction(std::string transaction_id) { std::string params = "{ \"id\": \"" + transaction_id + "\" }"; return send_post_request("account_history_api.get_transaction", params, debug_rpc_calls); } -std::string hive_node_rpc_client::block_api_get_block(uint32_t block_number) { +std::string hive_rpc_client::block_api_get_block(uint32_t block_number) { std::string params = "{ \"block_num\": " + std::to_string(block_number) + " }"; return send_post_request("block_api.get_block", params, debug_rpc_calls); } -std::string hive_node_rpc_client::condenser_api_get_accounts(std::vector accounts) { +std::string hive_rpc_client::condenser_api_get_accounts(std::vector accounts) { std::string params = ""; for (auto account : accounts) { if (!params.empty()) { @@ -56,58 +56,58 @@ std::string hive_node_rpc_client::condenser_api_get_accounts(std::vector accounts; accounts.push_back(account); std::string reply_str = condenser_api_get_accounts(accounts); return retrieve_array_value_from_reply(reply_str, "", 0); } -std::string hive_node_rpc_client::get_account_memo_key(std::string account) { +std::string hive_rpc_client::get_account_memo_key(std::string account) { std::string reply_str = get_account(account); reply_str = "{\"result\":" + reply_str + "}"; return retrieve_value_from_reply(reply_str, "memo_key"); } -std::string hive_node_rpc_client::get_chain_id() { +std::string hive_rpc_client::get_chain_id() { std::string reply_str = database_api_get_version(); return retrieve_value_from_reply(reply_str, "chain_id"); } -std::string hive_node_rpc_client::get_head_block_id() { +std::string hive_rpc_client::get_head_block_id() { std::string reply_str = database_api_get_dynamic_global_properties(); return retrieve_value_from_reply(reply_str, "head_block_id"); } -std::string hive_node_rpc_client::get_head_block_time() { +std::string hive_rpc_client::get_head_block_time() { std::string reply_str = database_api_get_dynamic_global_properties(); return retrieve_value_from_reply(reply_str, "time"); } -std::string hive_node_rpc_client::get_is_test_net() { +std::string hive_rpc_client::get_is_test_net() { std::string reply_str = condenser_api_get_config(); return retrieve_value_from_reply(reply_str, "IS_TEST_NET"); } -std::string hive_node_rpc_client::get_last_irreversible_block_num() { +std::string hive_rpc_client::get_last_irreversible_block_num() { std::string reply_str = database_api_get_dynamic_global_properties(); return retrieve_value_from_reply(reply_str, "last_irreversible_block_num"); } @@ -120,18 +120,20 @@ sidechain_net_handler_hive::sidechain_net_handler_hive(peerplays_sidechain_plugi debug_rpc_calls = options.at("debug-rpc-calls").as(); } - node_rpc_url = options.at("hive-node-rpc-url").as(); - if (options.count("hive-node-rpc-user")) { - node_rpc_user = options.at("hive-node-rpc-user").as(); + rpc_url = options.at("hive-rpc-url").as(); + if (options.count("hive-rpc-user")) { + rpc_user = options.at("hive-rpc-user").as(); } else { - node_rpc_user = ""; + rpc_user = ""; } - if (options.count("hive-node-rpc-password")) { - node_rpc_password = options.at("hive-node-rpc-password").as(); + if (options.count("hive-rpc-password")) { + rpc_password = options.at("hive-rpc-password").as(); } else { - node_rpc_password = ""; + rpc_password = ""; } + wallet_account_name = options.at("hive-wallet-account-name").as(); + if (options.count("hive-private-key")) { const std::vector pub_priv_keys = options["hive-private-key"].as>(); for (const std::string &itr_key_pair : pub_priv_keys) { @@ -144,16 +146,16 @@ sidechain_net_handler_hive::sidechain_net_handler_hive(peerplays_sidechain_plugi } } - node_rpc_client = new hive_node_rpc_client(node_rpc_url, node_rpc_user, node_rpc_password, debug_rpc_calls); + rpc_client = new hive_rpc_client(rpc_url, rpc_user, rpc_password, debug_rpc_calls); - std::string chain_id_str = node_rpc_client->get_chain_id(); + std::string chain_id_str = rpc_client->get_chain_id(); if (chain_id_str.empty()) { - elog("No Hive node running at ${url}", ("url", node_rpc_url)); + elog("No Hive node running at ${url}", ("url", rpc_url)); FC_ASSERT(false); } chain_id = chain_id_type(chain_id_str); - std::string is_test_net = node_rpc_client->get_is_test_net(); + std::string is_test_net = rpc_client->get_is_test_net(); network_type = is_test_net.compare("true") == 0 ? hive::network::testnet : hive::network::mainnet; if (network_type == hive::network::mainnet) { ilog("Running on Hive mainnet, chain id ${chain_id_str}", ("chain_id_str", chain_id_str)); @@ -223,7 +225,7 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { } if (son_sets_equal) { - address_ok = (op_obj_idx_0.get().address == "son-account"); + address_ok = (op_obj_idx_0.get().address == wallet_account_name); } if (po.proposed_transaction.operations.size() >= 2) { @@ -252,14 +254,14 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { account_auths[wallet_son.sidechain_public_keys.at(sidechain)] = wallet_son.weight; } - std::string memo_key = node_rpc_client->get_account_memo_key("son-account"); + std::string memo_key = rpc_client->get_account_memo_key(wallet_account_name); hive::authority active; active.weight_threshold = total_weight * 2 / 3 + 1; active.account_auths = account_auths; hive::account_update_operation auo; - auo.account = "son-account"; + auo.account = wallet_account_name; auo.active = active; auo.memo_key = op_trx.operations[0].get().memo_key; @@ -301,7 +303,7 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { uint64_t swdo_sidechain_amount = swdo->sidechain_amount.value; uint64_t swdo_op_idx = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-"))); - std::string tx_str = node_rpc_client->account_history_api_get_transaction(swdo_txid); + std::string tx_str = rpc_client->account_history_api_get_transaction(swdo_txid); if (tx_str != "") { std::stringstream ss_tx(tx_str); @@ -406,7 +408,7 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { } hive::transfer_operation t_op; - t_op.from = "son-account"; + t_op.from = wallet_account_name; t_op.to = swwo->withdraw_address; t_op.amount.amount = swwo->withdraw_amount; t_op.amount.symbol = symbol; @@ -493,7 +495,7 @@ void sidechain_net_handler_hive::process_primary_wallet() { account_auths[active_son.sidechain_public_keys.at(sidechain)] = active_son.weight; } - std::string memo_key = node_rpc_client->get_account_memo_key("son-account"); + std::string memo_key = rpc_client->get_account_memo_key(wallet_account_name); if (memo_key.empty()) { return; @@ -504,14 +506,14 @@ void sidechain_net_handler_hive::process_primary_wallet() { active.account_auths = account_auths; hive::account_update_operation auo; - auo.account = "son-account"; + auo.account = wallet_account_name; auo.active = active; auo.memo_key = hive::public_key_type(memo_key); - std::string block_id_str = node_rpc_client->get_head_block_id(); + std::string block_id_str = rpc_client->get_head_block_id(); hive::block_id_type head_block_id(block_id_str); - std::string head_block_time_str = node_rpc_client->get_head_block_time(); + std::string head_block_time_str = rpc_client->get_head_block_time(); time_point head_block_time = fc::time_point_sec::from_iso_string(head_block_time_str); hive::signed_transaction htrx; @@ -536,7 +538,7 @@ void sidechain_net_handler_hive::process_primary_wallet() { swu_op.payer = gpo.parameters.son_account(); swu_op.son_wallet_id = active_sw->id; swu_op.sidechain = sidechain; - swu_op.address = "son-account"; + swu_op.address = wallet_account_name; proposal_op.proposed_ops.emplace_back(swu_op); @@ -660,16 +662,16 @@ bool sidechain_net_handler_hive::process_withdrawal(const son_wallet_withdraw_ob } hive::transfer_operation t_op; - t_op.from = "son-account"; + t_op.from = wallet_account_name; t_op.to = swwo.withdraw_address; t_op.amount.amount = swwo.withdraw_amount; t_op.amount.symbol = symbol; t_op.memo = ""; - std::string block_id_str = node_rpc_client->get_head_block_id(); + std::string block_id_str = rpc_client->get_head_block_id(); hive::block_id_type head_block_id(block_id_str); - std::string head_block_time_str = node_rpc_client->get_head_block_time(); + std::string head_block_time_str = rpc_client->get_head_block_time(); time_point head_block_time = fc::time_point_sec::from_iso_string(head_block_time_str); hive::signed_transaction htrx; @@ -725,7 +727,7 @@ std::string sidechain_net_handler_hive::process_sidechain_transaction(const side hive::signed_transaction htrx; fc::raw::unpack(ss_trx, htrx, 1000); - std::string chain_id_str = node_rpc_client->get_chain_id(); + std::string chain_id_str = rpc_client->get_chain_id(); const hive::chain_id_type chain_id(chain_id_str); fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))); @@ -753,7 +755,7 @@ std::string sidechain_net_handler_hive::send_sidechain_transaction(const sidecha } std::string params = fc::json::to_string(htrx); - node_rpc_client->network_broadcast_api_broadcast_transaction(params); + rpc_client->network_broadcast_api_broadcast_transaction(params); return htrx.id().str(); } @@ -768,7 +770,7 @@ bool sidechain_net_handler_hive::settle_sidechain_transaction(const sidechain_tr return false; } - std::string tx_str = node_rpc_client->account_history_api_get_transaction(sto.sidechain_transaction); + std::string tx_str = rpc_client->account_history_api_get_transaction(sto.sidechain_transaction); if (tx_str != "") { std::stringstream ss_tx(tx_str); @@ -779,7 +781,7 @@ bool sidechain_net_handler_hive::settle_sidechain_transaction(const sidechain_tr std::string tx_txid = tx_json.get("result.transaction_id"); uint32_t tx_block_num = tx_json.get("result.block_num"); - uint32_t last_irreversible_block = std::stoul(node_rpc_client->get_last_irreversible_block_num()); + uint32_t last_irreversible_block = std::stoul(rpc_client->get_last_irreversible_block_num()); //std::string tx_address = addr.get_address(); //int64_t tx_amount = -1; @@ -815,7 +817,7 @@ void sidechain_net_handler_hive::schedule_hive_listener() { void sidechain_net_handler_hive::hive_listener_loop() { schedule_hive_listener(); - std::string reply = node_rpc_client->database_api_get_dynamic_global_properties(); + std::string reply = rpc_client->database_api_get_dynamic_global_properties(); if (!reply.empty()) { std::stringstream ss(reply); boost::property_tree::ptree json; @@ -830,7 +832,7 @@ void sidechain_net_handler_hive::hive_listener_loop() { } } - //std::string reply = node_rpc_client->get_last_irreversible_block_num(); + //std::string reply = rpc_client->get_last_irreversible_block_num(); //if (!reply.empty()) { // uint64_t last_irreversible_block = std::stoul(reply); // if (last_irreversible_block != last_block_received) { @@ -842,7 +844,7 @@ void sidechain_net_handler_hive::hive_listener_loop() { } void sidechain_net_handler_hive::handle_event(const std::string &event_data) { - std::string block = node_rpc_client->block_api_get_block(std::atoll(event_data.c_str())); + std::string block = rpc_client->block_api_get_block(std::atoll(event_data.c_str())); if (block != "") { add_to_son_listener_log("BLOCK : " + event_data); std::stringstream ss(block); @@ -867,7 +869,7 @@ void sidechain_net_handler_hive::handle_event(const std::string &event_data) { std::string from = op_value.get("from"); std::string to = op_value.get("to"); - if (to == "son-account") { + if (to == wallet_account_name) { const auto &amount_child = op_value.get_child("amount"); -- 2.45.2 From 28ac8214cae5ad1c685e576c1f2ff8509eebacc9 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Wed, 13 Jul 2022 04:18:25 +0200 Subject: [PATCH 29/60] Update boost, remove curl from sidechain plugin --- Dockerfile.18.04 | 6 +++--- libraries/CMakeLists.txt | 2 +- libraries/plugins/peerplays_sidechain/CMakeLists.txt | 2 +- libraries/plugins/peerplays_sidechain/common/rpc_client.cpp | 4 ---- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Dockerfile.18.04 b/Dockerfile.18.04 index d3fa1d75..49a06fa1 100644 --- a/Dockerfile.18.04 +++ b/Dockerfile.18.04 @@ -58,9 +58,9 @@ EXPOSE 22 WORKDIR /home/peerplays/ RUN \ - wget -c 'http://sourceforge.net/projects/boost/files/boost/1.67.0/boost_1_67_0.tar.bz2/download' -O boost_1_67_0.tar.bz2 && \ - tar xjf boost_1_67_0.tar.bz2 && \ - cd boost_1_67_0/ && \ + wget -c 'https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/boost_1_71_0.tar.bz2' -O boost_1_71_0.tar.bz2 && \ + tar xjf boost_1_71_0.tar.bz2 && \ + cd boost_1_71_0/ && \ ./bootstrap.sh && \ ./b2 install diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index dfe3d397..df872464 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,4 +1,3 @@ -add_subdirectory( vendor ) add_subdirectory( app ) add_subdirectory( chain ) add_subdirectory( db ) @@ -8,4 +7,5 @@ add_subdirectory( net ) add_subdirectory( plugins ) add_subdirectory( time ) add_subdirectory( utilities ) +add_subdirectory( vendor ) add_subdirectory( wallet ) diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index d82e874b..ca995c10 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -42,7 +42,7 @@ unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS) unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE) target_link_directories( peerplays_sidechain PUBLIC ${SHA3IUF_link_dirs} ) -target_link_libraries( peerplays_sidechain PRIVATE curl graphene_plugin zmq ${SHA3IUF_libraries} ) +target_link_libraries( peerplays_sidechain PRIVATE graphene_plugin zmq ${SHA3IUF_libraries} ) target_include_directories( peerplays_sidechain PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${SHA3IUF_include_dirs}" ) diff --git a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp index 1bbe0721..06093ce0 100644 --- a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp +++ b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp @@ -1,8 +1,6 @@ #include -#include #include -#include #include #include @@ -11,8 +9,6 @@ #include #include -#include - #include namespace graphene { namespace peerplays_sidechain { -- 2.45.2 From b2eb4a8ff9dfbe7a139d5d798ba135fdd56b7ac5 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Fri, 15 Jul 2022 07:12:43 +0200 Subject: [PATCH 30/60] Boost Beast based Websocket client --- .../peerplays_sidechain/CMakeLists.txt | 1 + .../peerplays_sidechain/common/ws_client.cpp | 210 ++++++++++++++++++ .../peerplays_sidechain/common/ws_client.hpp | 38 ++++ 3 files changed, 249 insertions(+) create mode 100644 libraries/plugins/peerplays_sidechain/common/ws_client.cpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/ws_client.hpp diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index ca995c10..679539e3 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -18,6 +18,7 @@ add_library( peerplays_sidechain bitcoin/sign_bitcoin_transaction.cpp common/rpc_client.cpp common/utils.cpp + common/ws_client.cpp ethereum/encoders.cpp ethereum/decoders.cpp ethereum/transaction.cpp diff --git a/libraries/plugins/peerplays_sidechain/common/ws_client.cpp b/libraries/plugins/peerplays_sidechain/common/ws_client.cpp new file mode 100644 index 00000000..da751563 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/common/ws_client.cpp @@ -0,0 +1,210 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace graphene { namespace peerplays_sidechain { + +ws_client::ws_client(std::string _url, std::string _user, std::string _password, bool _debug_ws_calls) : + url(_url), + user(_user), + password(_password), + debug_ws_calls(_debug_ws_calls), + request_id(0) { + + std::string reg_expr = "^((?Pwss|ws):\\/\\/)?(?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 = "ws"; + } + + host = sm["Host"]; + if (host.empty()) { + host + "localhost"; + } + + port = sm["Port"]; + if (port.empty()) { + port = "80"; + } + + target = sm["Target"]; + if (target.empty()) { + target = "/"; + } + } else { + elog("Invalid URL: ${url}", ("url", url)); + } +} + +std::string ws_client::retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx) { + std::stringstream ss(reply_str); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + if (json.find("result") == json.not_found()) { + return ""; + } + + auto json_result = json.get_child_optional("result"); + if (json_result) { + boost::property_tree::ptree array_ptree = json_result.get(); + if (!array_path.empty()) { + array_ptree = json_result.get().get_child(array_path); + } + uint32_t array_el_idx = -1; + for (const auto &array_el : array_ptree) { + array_el_idx = array_el_idx + 1; + if (array_el_idx == idx) { + std::stringstream ss_res; + boost::property_tree::json_parser::write_json(ss_res, array_el.second); + return ss_res.str(); + } + } + } + + return ""; +} + +std::string ws_client::retrieve_value_from_reply(std::string reply_str, std::string value_path) { + std::stringstream ss(reply_str); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + if (json.find("result") == json.not_found()) { + return ""; + } + + auto json_result = json.get_child_optional("result"); + if (json_result) { + return json_result.get().get(value_path); + } + + return json.get("result"); +} + +std::string ws_client::send_post_request(std::string method, std::string params, bool show_log) { + std::stringstream body; + + request_id = request_id + 1; + + body << "{ \"jsonrpc\": \"2.0\", \"id\": " << request_id << ", \"method\": \"" << method << "\""; + + if (!params.empty()) { + body << ", \"params\": " << params; + } + + body << " }"; + + const auto reply = send_post_request(body.str(), show_log); + + if (reply.body.empty()) { + wlog("RPC call ${function} failed", ("function", __FUNCTION__)); + return ""; + } + + std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + + if (reply.status == 200) { + return ss.str(); + } + + if (json.count("error") && !json.get_child("error").empty()) { + wlog("RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body.str())("msg", ss.str())); + } + return ""; +} + +ws_reply ws_client::send_post_request(std::string body, bool show_log) { + + // The io_context is required for all I/O + boost::beast::net::io_context ioc; + + // These objects perform our I/O + boost::beast::net::ip::tcp::resolver resolver(ioc); + boost::beast::websocket::stream ws{ioc}; + + // Look up the domain name + auto const results = resolver.resolve(host, port); + + //// Make the connection on the IP address we get from a lookup + //boost::beast::net::connect(ws.next_layer(), results.begin(), results.end()); + // + //// Set a decorator to change the User-Agent of the handshake + //ws.set_option(websocket::stream_base::decorator( + // [](websocket::request_type &req) { + // req.set(http::field::user_agent, + // std::string(BOOST_BEAST_VERSION_STRING) + + // " websocket-client-coro"); + // })); + + //// Set up an HTTP GET request message + //boost::beast::http::request req{boost::beast::http::verb::post, target, 11}; + //req.set(boost::beast::http::field::host, host + ":" + port); + //req.set(boost::beast::http::field::accept, "application/json"); + //req.set(boost::beast::http::field::content_type, "application/json"); + //req.set(boost::beast::http::field::content_encoding, "utf-8"); + //req.set(boost::beast::http::field::content_length, body.length()); + //req.body() = body; + + // Perform the websocket handshake + ws.handshake(host, "/"); + + // Send the message + ws.write(boost::asio::buffer(body)); + + // This buffer is used for reading and must be persisted + boost::beast::flat_buffer buffer; + + // Declare a container to hold the response + boost::beast::http::response res; + + //// Receive the HTTP response + //boost::beast::http::read(stream, buffer, res); + // + ////// Write the message to standard out + ////std::cout << res << std::endl; + // + //// Gracefully close the socket + //boost::beast::error_code ec; + //stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); + // + //// not_connected happens sometimes + //// so don't bother reporting it. + //// + //if (ec && ec != boost::beast::errc::not_connected) + // throw boost::beast::system_error{ec}; + + std::string rbody{boost::asio::buffers_begin(res.body().data()), + boost::asio::buffers_end(res.body().data())}; + ws_reply reply; + reply.status = 200; + reply.body = rbody; + + if (show_log) { + ilog("### Request URL: ${url}", ("url", url)); + ilog("### Request: ${body}", ("body", body)); + ilog("### Response: ${rbody}", ("rbody", rbody)); + } + + return reply; +} + +}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/ws_client.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/ws_client.hpp new file mode 100644 index 00000000..9a7cfca4 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/ws_client.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +namespace graphene { namespace peerplays_sidechain { + +struct ws_reply { + uint16_t status; + std::string body; +}; + +class ws_client { +public: + ws_client(std::string _url, std::string _user, std::string _password, bool _debug_ws_calls); + +protected: + std::string retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx); + std::string retrieve_value_from_reply(std::string reply_str, std::string value_path); + std::string send_post_request(std::string method, std::string params, bool show_log); + + std::string url; + std::string protocol; + std::string host; + std::string port; + std::string target; + + std::string user; + std::string password; + bool debug_ws_calls; + + uint32_t request_id; + +private: + ws_reply send_post_request(std::string body, bool show_log); +}; + +}} // namespace graphene::peerplays_sidechain -- 2.45.2 From 9de4a07ce2e17dcac3a1fa30115b5d91cc3f9ed8 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Fri, 15 Jul 2022 19:42:26 +0200 Subject: [PATCH 31/60] Try to fix docker builds --- Dockerfile | 2 +- libraries/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7a76c136..50c51c3a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ RUN \ expect \ git \ graphviz \ - libboost1.67-all-dev \ + libboost-all-dev \ libbz2-dev \ libcurl4-openssl-dev \ libncurses-dev \ diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index df872464..dfe3d397 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory( vendor ) add_subdirectory( app ) add_subdirectory( chain ) add_subdirectory( db ) @@ -7,5 +8,4 @@ add_subdirectory( net ) add_subdirectory( plugins ) add_subdirectory( time ) add_subdirectory( utilities ) -add_subdirectory( vendor ) add_subdirectory( wallet ) -- 2.45.2 From 0f4ec869134dd99f510f32df513bda6f521c03b3 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Sat, 16 Jul 2022 00:01:59 +0200 Subject: [PATCH 32/60] WEP --- .../peerplays_sidechain/common/ws_client.cpp | 58 +++++++------------ .../sidechain_net_handler_ethereum.hpp | 13 ++++- .../sidechain_net_handler_hive.hpp | 1 - .../peerplays_sidechain_plugin.cpp | 3 + .../sidechain_net_handler_ethereum.cpp | 24 ++++++-- 5 files changed, 55 insertions(+), 44 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/common/ws_client.cpp b/libraries/plugins/peerplays_sidechain/common/ws_client.cpp index da751563..b849afc1 100644 --- a/libraries/plugins/peerplays_sidechain/common/ws_client.cpp +++ b/libraries/plugins/peerplays_sidechain/common/ws_client.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -144,25 +145,21 @@ ws_reply ws_client::send_post_request(std::string body, bool show_log) { // Look up the domain name auto const results = resolver.resolve(host, port); - //// Make the connection on the IP address we get from a lookup - //boost::beast::net::connect(ws.next_layer(), results.begin(), results.end()); - // - //// Set a decorator to change the User-Agent of the handshake - //ws.set_option(websocket::stream_base::decorator( - // [](websocket::request_type &req) { - // req.set(http::field::user_agent, - // std::string(BOOST_BEAST_VERSION_STRING) + - // " websocket-client-coro"); - // })); + // Make the connection on the IP address we get from a lookup + boost::beast::net::connect(ws.next_layer(), results.begin(), results.end()); - //// Set up an HTTP GET request message - //boost::beast::http::request req{boost::beast::http::verb::post, target, 11}; - //req.set(boost::beast::http::field::host, host + ":" + port); - //req.set(boost::beast::http::field::accept, "application/json"); - //req.set(boost::beast::http::field::content_type, "application/json"); - //req.set(boost::beast::http::field::content_encoding, "utf-8"); - //req.set(boost::beast::http::field::content_length, body.length()); - //req.body() = body; + // Set a decorator to change the User-Agent of the handshake + ws.set_option(boost::beast::websocket::stream_base::decorator( + [](boost::beast::websocket::request_type &req) { + //// Set up an HTTP GET request message + //boost::beast::http::request req{boost::beast::http::verb::post, target, 11}; + //req.set(boost::beast::http::field::host, host + ":" + port); + //req.set(boost::beast::http::field::accept, "application/json"); + //req.set(boost::beast::http::field::content_type, "application/json"); + //req.set(boost::beast::http::field::content_encoding, "utf-8"); + //req.set(boost::beast::http::field::content_length, body.length()); + //req.body() = body; + })); // Perform the websocket handshake ws.handshake(host, "/"); @@ -173,27 +170,14 @@ ws_reply ws_client::send_post_request(std::string body, bool show_log) { // This buffer is used for reading and must be persisted boost::beast::flat_buffer buffer; - // Declare a container to hold the response - boost::beast::http::response res; + // Read a message into our buffer + ws.read(buffer); - //// Receive the HTTP response - //boost::beast::http::read(stream, buffer, res); - // - ////// Write the message to standard out - ////std::cout << res << std::endl; - // - //// Gracefully close the socket - //boost::beast::error_code ec; - //stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); - // - //// not_connected happens sometimes - //// so don't bother reporting it. - //// - //if (ec && ec != boost::beast::errc::not_connected) - // throw boost::beast::system_error{ec}; + // Close the WebSocket connection + ws.close(boost::beast::websocket::close_code::normal); + + std::string rbody = boost::beast::make_printable(buffer.data()); - std::string rbody{boost::asio::buffers_begin(res.body().data()), - boost::asio::buffers_end(res.body().data())}; ws_reply reply; reply.status = 200; reply.body = rbody; 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 745c26bb..0a04aff8 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 @@ -6,8 +6,8 @@ #include -#include #include +#include #include namespace graphene { namespace peerplays_sidechain { @@ -24,6 +24,11 @@ public: std::string get_network_id(); }; +class ethereum_ws_client : public ws_client { +public: + ethereum_ws_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); +}; + class sidechain_net_handler_ethereum : public sidechain_net_handler { public: sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options); @@ -42,9 +47,13 @@ private: std::string rpc_url; std::string rpc_user; std::string rpc_password; + std::string ws_url; + std::string ws_user; + std::string ws_password; std::string wallet_contract_address; - ethereum_rpc_client *ethereum_client; + ethereum_rpc_client *ethereum_client_rpc; + ethereum_ws_client *ethereum_client_ws; ethereum::chain_id_type chain_id; ethereum::network_id_type network_id; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp index a0cb6038..72539db2 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp @@ -6,7 +6,6 @@ #include -#include #include #include diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 73bef93f..0bcd84e0 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -161,6 +161,9 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("ethereum-node-rpc-url", bpo::value()->default_value("127.0.0.1:8545"), "Ethereum node RPC URL [http[s]://]host[:port]"); 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-node-ws-url", bpo::value()->default_value("127.0.0.1:8546"), "Ethereum node WS URL [ws[s]://]host[:port]"); + cli.add_options()("ethereum-node-ws-user", bpo::value(), "Ethereum WS user"); + cli.add_options()("ethereum-node-ws-password", bpo::value(), "Ethereum WS password"); cli.add_options()("ethereum-wallet-contract-address", bpo::value()->default_value("0000000000000000000000000000000000000000"), "Ethereum wallet contract address"), 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)"); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 0dde6927..c34d1ea7 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -49,6 +49,9 @@ std::string ethereum_rpc_client::get_network_id() { return retrieve_value_from_reply(reply_str, "protocols.eth.network"); } +ethereum_ws_client::ethereum_ws_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : + ws_client(url, user_name, password, debug_rpc_calls){}; + sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : sidechain_net_handler(_plugin, options) { sidechain = sidechain_type::ethereum; @@ -69,6 +72,18 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha rpc_password = ""; } + ws_url = options.at("ethereum-node-ws-url").as(); + if (options.count("ethereum-node-ws-user")) { + ws_user = options.at("ethereum-node-ws-user").as(); + } else { + ws_user = ""; + } + if (options.count("ethereum-node-ws-password")) { + rpc_password = options.at("ethereum-node-ws-password").as(); + } else { + ws_password = ""; + } + wallet_contract_address = options.at("ethereum-wallet-contract-address").as(); if (options.count("ethereum-private-key")) { @@ -83,15 +98,16 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha } } - ethereum_client = new ethereum_rpc_client(rpc_url, rpc_user, rpc_password, debug_rpc_calls); + ethereum_client_rpc = new ethereum_rpc_client(rpc_url, rpc_user, rpc_password, debug_rpc_calls); + ethereum_client_ws = new ethereum_ws_client(ws_url, ws_user, ws_password, debug_rpc_calls); - std::string chain_id_str = ethereum_client->get_chain_id(); + std::string chain_id_str = ethereum_client_rpc->get_chain_id(); if (chain_id_str.empty()) { elog("No Ethereum node running at ${url}", ("url", rpc_url)); FC_ASSERT(false); } chain_id = std::stoll(chain_id_str); - std::string network_id_str = ethereum_client->get_network_id(); + std::string network_id_str = ethereum_client_rpc->get_network_id(); network_id = std::stoll(network_id_str); ilog("Running on Ethereum network, chain id ${chain_id_str}, network id ${network_id_str}", ("chain_id_str", chain_id_str)("network_id_str", network_id_str)); @@ -327,7 +343,7 @@ void sidechain_net_handler_ethereum::schedule_ethereum_listener() { void sidechain_net_handler_ethereum::ethereum_listener_loop() { schedule_ethereum_listener(); - std::string reply = ethereum_client->eth_get_block_by_number("latest", true); + std::string reply = ethereum_client_rpc->eth_get_block_by_number("latest", true); } void sidechain_net_handler_ethereum::handle_event(const std::string &event_data) { -- 2.45.2 From f12c9f3ef9db69d83ff2e0f5963c6b2eb555e554 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Thu, 21 Jul 2022 22:01:51 +0200 Subject: [PATCH 33/60] SON for Ethereum listener, WIP --- libraries/chain/db_maint.cpp | 53 +- .../chain/hardfork.d/SON_FOR_ETHEREUM.hf | 7 + .../chain/protocol/chain_parameters.hpp | 5 + .../bitcoin/sign_bitcoin_transaction.cpp | 12 +- .../peerplays_sidechain/common/ws_client.cpp | 15 +- .../sidechain_net_handler_ethereum.hpp | 7 +- .../peerplays_sidechain_plugin.cpp | 3 - .../sidechain_net_handler.cpp | 8 + .../sidechain_net_handler_ethereum.cpp | 607 ++++++++++++++---- 9 files changed, 564 insertions(+), 153 deletions(-) create mode 100644 libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index c3f826d1..2f59a886 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -1963,7 +1963,7 @@ void database::perform_son_tasks() asset_issuer_permission_flags::override_authority; a.options.core_exchange_rate.base.amount = 100000; a.options.core_exchange_rate.base.asset_id = asset_id_type(0); - a.options.core_exchange_rate.quote.amount = 2500; // CoinMarketCap approx value + a.options.core_exchange_rate.quote.amount = 2500; a.options.core_exchange_rate.quote.asset_id = a.id; a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set @@ -1977,6 +1977,40 @@ void database::perform_son_tasks() gpo.pending_parameters->extensions.value.btc_asset = btc_asset.get_id(); }); } + // create ETH asset here because son_account is the issuer of the ETH + if (gpo.parameters.eth_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME) + { + const asset_dynamic_data_object& dyn_asset = + create([](asset_dynamic_data_object& a) { + a.current_supply = 0; + }); + + const asset_object& eth_asset = + create( [&gpo, &dyn_asset]( asset_object& a ) { + a.symbol = "ETH"; + a.precision = 8; + a.issuer = gpo.parameters.son_account(); + a.options.max_supply = GRAPHENE_MAX_SHARE_SUPPLY; + a.options.market_fee_percent = 500; // 5% + a.options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK; + a.options.flags = asset_issuer_permission_flags::charge_market_fee | + asset_issuer_permission_flags::override_authority; + a.options.core_exchange_rate.base.amount = 100000; + a.options.core_exchange_rate.base.asset_id = asset_id_type(0); + a.options.core_exchange_rate.quote.amount = 2500; + a.options.core_exchange_rate.quote.asset_id = a.id; + a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty + a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set + a.options.whitelist_markets.clear(); // might be traded with + a.options.blacklist_markets.clear(); // might not be traded with + a.dynamic_asset_data_id = dyn_asset.id; + }); + modify( gpo, [ð_asset]( global_property_object& gpo ) { + gpo.parameters.extensions.value.eth_asset = eth_asset.get_id(); + if( gpo.pending_parameters ) + gpo.pending_parameters->extensions.value.eth_asset = eth_asset.get_id(); + }); + } // create HBD asset here because son_account is the issuer of the HBD if (gpo.parameters.hbd_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_HIVE_TIME) { @@ -1997,7 +2031,7 @@ void database::perform_son_tasks() asset_issuer_permission_flags::override_authority; a.options.core_exchange_rate.base.amount = 100000; a.options.core_exchange_rate.base.asset_id = asset_id_type(0); - a.options.core_exchange_rate.quote.amount = 2500; // CoinMarketCap approx value + a.options.core_exchange_rate.quote.amount = 2500; a.options.core_exchange_rate.quote.asset_id = a.id; a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set @@ -2031,7 +2065,7 @@ void database::perform_son_tasks() asset_issuer_permission_flags::override_authority; a.options.core_exchange_rate.base.amount = 100000; a.options.core_exchange_rate.base.asset_id = asset_id_type(0); - a.options.core_exchange_rate.quote.amount = 2500; // CoinMarketCap approx value + a.options.core_exchange_rate.quote.amount = 2500; a.options.core_exchange_rate.quote.asset_id = a.id; a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set @@ -2297,14 +2331,17 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g p.pending_parameters->extensions.value.hbd_asset = p.parameters.extensions.value.hbd_asset; if( !p.pending_parameters->extensions.value.hive_asset.valid() ) p.pending_parameters->extensions.value.hive_asset = p.parameters.extensions.value.hive_asset; + if( !p.pending_parameters->extensions.value.eth_asset.valid() ) + p.pending_parameters->extensions.value.eth_asset = p.parameters.extensions.value.eth_asset; // the following parameters are not allowed to be changed. So take what is in global property - p.pending_parameters->extensions.value.hive_asset = p.parameters.extensions.value.hive_asset; - p.pending_parameters->extensions.value.hbd_asset = p.parameters.extensions.value.hbd_asset; - p.pending_parameters->extensions.value.maximum_son_count = p.parameters.extensions.value.maximum_son_count; - p.pending_parameters->extensions.value.btc_asset = p.parameters.extensions.value.btc_asset; - p.pending_parameters->extensions.value.son_account = p.parameters.extensions.value.son_account; p.pending_parameters->extensions.value.gpos_period_start = p.parameters.extensions.value.gpos_period_start; + p.pending_parameters->extensions.value.son_account = p.parameters.extensions.value.son_account; + p.pending_parameters->extensions.value.btc_asset = p.parameters.extensions.value.btc_asset; + p.pending_parameters->extensions.value.maximum_son_count = p.parameters.extensions.value.maximum_son_count; + p.pending_parameters->extensions.value.hbd_asset = p.parameters.extensions.value.hbd_asset; + p.pending_parameters->extensions.value.hive_asset = p.parameters.extensions.value.hive_asset; + p.pending_parameters->extensions.value.eth_asset = p.parameters.extensions.value.eth_asset; p.parameters = std::move(*p.pending_parameters); p.pending_parameters.reset(); diff --git a/libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf b/libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf new file mode 100644 index 00000000..72e929fe --- /dev/null +++ b/libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf @@ -0,0 +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")) +#else +#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2022-07-01T00:00:00")) +#endif +#endif diff --git a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp index 3a11e99f..94493f30 100644 --- a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp +++ b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp @@ -70,6 +70,7 @@ namespace graphene { namespace chain { optional < uint16_t > maximum_son_count = GRAPHENE_DEFAULT_MAX_SONS; ///< maximum number of active SONS optional < asset_id_type > hbd_asset = asset_id_type(); optional < asset_id_type > hive_asset = asset_id_type(); + optional < asset_id_type > eth_asset = asset_id_type(); }; struct chain_parameters @@ -220,6 +221,9 @@ namespace graphene { namespace chain { inline asset_id_type hive_asset() const { return extensions.value.hive_asset.valid() ? *extensions.value.hive_asset : asset_id_type(); } + inline asset_id_type eth_asset() const { + return extensions.value.eth_asset.valid() ? *extensions.value.eth_asset : asset_id_type(); + } private: static void safe_copy(chain_parameters& to, const chain_parameters& from); }; @@ -257,6 +261,7 @@ FC_REFLECT( graphene::chain::parameter_extension, (maximum_son_count) (hbd_asset) (hive_asset) + (eth_asset) ) FC_REFLECT( graphene::chain::chain_parameters, diff --git a/libraries/plugins/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.cpp b/libraries/plugins/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.cpp index 893f82aa..033cafe0 100644 --- a/libraries/plugins/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.cpp @@ -76,14 +76,14 @@ bool verify_sig(const bytes &sig, const bytes &pubkey, const bytes &msg, const s //! Get sig_temp FC_ASSERT(sig.size() > 70); FC_ASSERT(sig[0] == 0x30); - FC_ASSERT(sig[1] == static_cast(sig.size()-3)); + FC_ASSERT(sig[1] == static_cast(sig.size() - 3)); FC_ASSERT(sig[2] == 0x02); const uint r_size = sig[3]; - std::vector sig_temp(sig.begin()+4+(r_size-32), sig.begin()+4+r_size); - FC_ASSERT(sig[4+r_size] == 0x02); - const uint s_size = sig[5+r_size]; - FC_ASSERT(sig.size() == r_size+s_size+7); - sig_temp.insert(sig_temp.end(), sig.begin()+6+r_size, sig.end()); + std::vector sig_temp(sig.begin() + 4 + (r_size - 32), sig.begin() + 4 + r_size); + FC_ASSERT(sig[4 + r_size] == 0x02); + const uint s_size = sig[5 + r_size]; + FC_ASSERT(sig.size() == r_size + s_size + 7); + sig_temp.insert(sig_temp.end(), sig.begin() + 6 + r_size, sig.end()); std::vector pubkey_temp(pubkey.begin(), pubkey.end()); std::vector msg_temp(msg.begin(), msg.end()); diff --git a/libraries/plugins/peerplays_sidechain/common/ws_client.cpp b/libraries/plugins/peerplays_sidechain/common/ws_client.cpp index b849afc1..3292717f 100644 --- a/libraries/plugins/peerplays_sidechain/common/ws_client.cpp +++ b/libraries/plugins/peerplays_sidechain/common/ws_client.cpp @@ -176,17 +176,18 @@ ws_reply ws_client::send_post_request(std::string body, bool show_log) { // Close the WebSocket connection ws.close(boost::beast::websocket::close_code::normal); - std::string rbody = boost::beast::make_printable(buffer.data()); + //std::string rbody{boost::asio::buffers_begin(buffer), + // boost::asio::buffers_end(reading)}; ws_reply reply; reply.status = 200; - reply.body = rbody; + //reply.body = rbody; - if (show_log) { - ilog("### Request URL: ${url}", ("url", url)); - ilog("### Request: ${body}", ("body", body)); - ilog("### Response: ${rbody}", ("rbody", rbody)); - } + //if (show_log) { + // ilog("### Request URL: ${url}", ("url", url)); + // ilog("### Request: ${body}", ("body", body)); + // ilog("### Response: ${rbody}", ("rbody", rbody)); + //} return reply; } 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 0a04aff8..9b374588 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 @@ -18,6 +18,7 @@ public: std::string admin_node_info(); std::string eth_get_block_by_number(std::string block_number, bool full_block); + std::string eth_get_logs(std::string wallet_contract_address); std::string net_version(); std::string get_chain_id(); @@ -47,13 +48,9 @@ private: std::string rpc_url; std::string rpc_user; std::string rpc_password; - std::string ws_url; - std::string ws_user; - std::string ws_password; std::string wallet_contract_address; - ethereum_rpc_client *ethereum_client_rpc; - ethereum_ws_client *ethereum_client_ws; + ethereum_rpc_client *rpc_client; ethereum::chain_id_type chain_id; ethereum::network_id_type network_id; diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 0bcd84e0..73bef93f 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -161,9 +161,6 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("ethereum-node-rpc-url", bpo::value()->default_value("127.0.0.1:8545"), "Ethereum node RPC URL [http[s]://]host[:port]"); 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-node-ws-url", bpo::value()->default_value("127.0.0.1:8546"), "Ethereum node WS URL [ws[s]://]host[:port]"); - cli.add_options()("ethereum-node-ws-user", bpo::value(), "Ethereum WS user"); - cli.add_options()("ethereum-node-ws-password", bpo::value(), "Ethereum WS password"); cli.add_options()("ethereum-wallet-contract-address", bpo::value()->default_value("0000000000000000000000000000000000000000"), "Ethereum wallet contract address"), 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)"); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp index 7c87a9ef..78ad7103 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp @@ -172,18 +172,21 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ #ifdef ENABLE_PEERPLAYS_ASSET_DEPOSITS //enable_peerplays_asset_deposits = (sed.sidechain == sidechain_type::peerplays) && // (sed.sidechain_currency.compare("BTC") != 0) && + // (sed.sidechain_currency.compare("ETH") != 0) && // (sed.sidechain_currency.compare("HBD") != 0) && // (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); bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain == 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()))); @@ -240,6 +243,10 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ withdraw_currency = "BTC"; withdraw_currency_price = database.get(database.get_global_properties().parameters.btc_asset()).options.core_exchange_rate; } + if (sed.sidechain_currency == object_id_to_string(gpo.parameters.eth_asset())) { + withdraw_currency = "ETH"; + withdraw_currency_price = database.get(database.get_global_properties().parameters.eth_asset()).options.core_exchange_rate; + } if (sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset())) { withdraw_currency = "HBD"; withdraw_currency_price = database.get(database.get_global_properties().parameters.hbd_asset()).options.core_exchange_rate; @@ -648,6 +655,7 @@ void sidechain_net_handler::on_applied_block(const signed_block &b) { 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::hive) && (transfer_op.amount.asset_id == gpo.parameters.hbd_asset())) || ((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hive_asset())); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index c34d1ea7..2bbb5082 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -35,6 +35,12 @@ std::string ethereum_rpc_client::eth_get_block_by_number(std::string block_numbe return send_post_request("eth_getBlockByNumber", params, debug_rpc_calls); } +std::string ethereum_rpc_client::eth_get_logs(std::string wallet_contract_address) { + std::string params = "[{\"address\": \"" + wallet_contract_address + "\"}]"; + std::string reply_str = send_post_request("eth_getLogs", params, debug_rpc_calls); + return retrieve_value_from_reply(reply_str, ""); +} + std::string ethereum_rpc_client::net_version() { return send_post_request("net_version", "", debug_rpc_calls); } @@ -72,18 +78,6 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha rpc_password = ""; } - ws_url = options.at("ethereum-node-ws-url").as(); - if (options.count("ethereum-node-ws-user")) { - ws_user = options.at("ethereum-node-ws-user").as(); - } else { - ws_user = ""; - } - if (options.count("ethereum-node-ws-password")) { - rpc_password = options.at("ethereum-node-ws-password").as(); - } else { - ws_password = ""; - } - wallet_contract_address = options.at("ethereum-wallet-contract-address").as(); if (options.count("ethereum-private-key")) { @@ -98,16 +92,15 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha } } - ethereum_client_rpc = new ethereum_rpc_client(rpc_url, rpc_user, rpc_password, debug_rpc_calls); - ethereum_client_ws = new ethereum_ws_client(ws_url, ws_user, ws_password, debug_rpc_calls); + rpc_client = new ethereum_rpc_client(rpc_url, rpc_user, rpc_password, debug_rpc_calls); - std::string chain_id_str = ethereum_client_rpc->get_chain_id(); + std::string chain_id_str = rpc_client->get_chain_id(); if (chain_id_str.empty()) { elog("No Ethereum node running at ${url}", ("url", rpc_url)); FC_ASSERT(false); } chain_id = std::stoll(chain_id_str); - std::string network_id_str = ethereum_client_rpc->get_network_id(); + std::string network_id_str = rpc_client->get_network_id(); network_id = std::stoll(network_id_str); ilog("Running on Ethereum network, chain id ${chain_id_str}, network id ${network_id_str}", ("chain_id_str", chain_id_str)("network_id_str", network_id_str)); @@ -124,126 +117,418 @@ sidechain_net_handler_ethereum::~sidechain_net_handler_ethereum() { bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) { ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); - return true; + + bool should_approve = false; + + const chain::global_property_object &gpo = database.get_global_properties(); + + int32_t op_idx_0 = -1; + chain::operation op_obj_idx_0; + + if (po.proposed_transaction.operations.size() >= 1) { + op_idx_0 = po.proposed_transaction.operations[0].which(); + op_obj_idx_0 = po.proposed_transaction.operations[0]; + } + + int32_t op_idx_1 = -1; + chain::operation op_obj_idx_1; + (void)op_idx_1; + + if (po.proposed_transaction.operations.size() >= 2) { + op_idx_1 = po.proposed_transaction.operations[1].which(); + op_obj_idx_1 = po.proposed_transaction.operations[1]; + } + + switch (op_idx_0) { + + case chain::operation::tag::value: { + bool address_ok = false; + bool transaction_ok = false; + son_wallet_id_type swo_id = op_obj_idx_0.get().son_wallet_id; + const auto &idx = database.get_index_type().indices().get(); + const auto swo = idx.find(swo_id); + if (swo != idx.end()) { + + //auto active_sons = gpo.active_sons; + //vector wallet_sons = swo->sons; + // + //bool son_sets_equal = (active_sons.size() == wallet_sons.size()); + // + //if (son_sets_equal) { + // for (size_t i = 0; i < active_sons.size(); i++) { + // son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i); + // } + //} + // + //if (son_sets_equal) { + // address_ok = (op_obj_idx_0.get().address == wallet_account_name); + //} + // + //if (po.proposed_transaction.operations.size() >= 2) { + // object_id_type object_id = op_obj_idx_1.get().object_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); + // if (st == st_idx.end()) { + // + // std::string tx_str = ""; + // + // if (object_id.is()) { + // const auto &idx = database.get_index_type().indices().get(); + // const auto swo = idx.find(object_id); + // if (swo != idx.end()) { + // + // std::stringstream ss_trx(boost::algorithm::unhex(op_tx_str)); + // hive::signed_transaction op_trx; + // fc::raw::unpack(ss_trx, op_trx, 1000); + // + // fc::flat_map account_auths; + // uint32_t total_weight = 0; + // for (const auto &wallet_son : wallet_sons) { + // total_weight = total_weight + wallet_son.weight; + // account_auths[wallet_son.sidechain_public_keys.at(sidechain)] = wallet_son.weight; + // } + // + // std::string memo_key = rpc_client->get_account_memo_key(wallet_account_name); + // + // hive::authority active; + // active.weight_threshold = total_weight * 2 / 3 + 1; + // active.account_auths = account_auths; + // + // hive::account_update_operation auo; + // auo.account = wallet_account_name; + // auo.active = active; + // auo.memo_key = op_trx.operations[0].get().memo_key; + // + // hive::signed_transaction htrx; + // htrx.ref_block_num = op_trx.ref_block_num; + // htrx.ref_block_prefix = op_trx.ref_block_prefix; + // htrx.set_expiration(op_trx.expiration); + // + // htrx.operations.push_back(auo); + // + // std::stringstream ss; + // fc::raw::pack(ss, htrx, 1000); + // tx_str = boost::algorithm::hex(ss.str()); + // } + // } + // + // transaction_ok = (op_tx_str == tx_str); + // } + //} else { + // transaction_ok = true; + //} + } + + address_ok = true; + transaction_ok = true; + + should_approve = address_ok && + transaction_ok; + break; + } + + case chain::operation::tag::value: { + bool process_ok = false; + son_wallet_deposit_id_type swdo_id = op_obj_idx_0.get().son_wallet_deposit_id; + const auto &idx = database.get_index_type().indices().get(); + const auto swdo = idx.find(swdo_id); + if (swdo != idx.end()) { + + //std::string swdo_txid = swdo->sidechain_transaction_id; + //std::string swdo_sidechain_from = swdo->sidechain_from; + //std::string swdo_sidechain_currency = swdo->sidechain_currency; + //uint64_t swdo_sidechain_amount = swdo->sidechain_amount.value; + //uint64_t swdo_op_idx = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-"))); + // + //std::string tx_str = rpc_client->account_history_api_get_transaction(swdo_txid); + //if (tx_str != "") { + // + // std::stringstream ss_tx(tx_str); + // boost::property_tree::ptree tx; + // boost::property_tree::read_json(ss_tx, tx); + // + // uint64_t op_idx = -1; + // for (const auto &ops : tx.get_child("result.operations")) { + // const auto &op = ops.second; + // op_idx = op_idx + 1; + // if (op_idx == swdo_op_idx) { + // std::string operation_type = op.get("type"); + // + // if (operation_type == "transfer_operation") { + // const auto &op_value = op.get_child("value"); + // + // std::string sidechain_from = op_value.get("from"); + // + // const auto &amount_child = op_value.get_child("amount"); + // + // uint64_t amount = amount_child.get("amount"); + // std::string nai = amount_child.get("nai"); + // std::string sidechain_currency = ""; + // if ((nai == "@@000000013" /*?? HBD*/) || (nai == "@@000000013" /*TBD*/)) { + // sidechain_currency = "HBD"; + // } + // if ((nai == "@@000000021") /*?? HIVE*/ || (nai == "@@000000021" /*TESTS*/)) { + // sidechain_currency = "HIVE"; + // } + // + // std::string memo = op_value.get("memo"); + // boost::trim(memo); + // if (!memo.empty()) { + // sidechain_from = memo; + // } + // + // process_ok = (swdo_sidechain_from == sidechain_from) && + // (swdo_sidechain_currency == sidechain_currency) && + // (swdo_sidechain_amount == amount); + // } + // } + // } + //} + } + + process_ok = true; + + should_approve = process_ok; + break; + } + + case chain::operation::tag::value: { + bool process_ok = false; + bool transaction_ok = false; + son_wallet_withdraw_id_type swwo_id = op_obj_idx_0.get().son_wallet_withdraw_id; + const auto &idx = database.get_index_type().indices().get(); + const auto swwo = idx.find(swwo_id); + if (swwo != idx.end()) { + + //uint32_t swwo_block_num = swwo->block_num; + //std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id; + //uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1)); + // + //const auto &block = database.fetch_block_by_number(swwo_block_num); + // + //for (const auto &tx : block->transactions) { + // if (tx.id().str() == swwo_peerplays_transaction_id) { + // operation op = tx.operations[swwo_op_idx]; + // transfer_operation t_op = op.get(); + // + // price asset_price = database.get(t_op.amount.asset_id).options.core_exchange_rate; + // asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); + // + // process_ok = (t_op.to == gpo.parameters.son_account()) && + // (swwo->peerplays_from == t_op.from) && + // (swwo->peerplays_asset == peerplays_asset); + // break; + // } + //} + // + //object_id_type object_id = op_obj_idx_1.get().object_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); + //if (st == st_idx.end()) { + // + // std::string tx_str = ""; + // + // if (object_id.is()) { + // const auto &idx = database.get_index_type().indices().get(); + // const auto swwo = idx.find(object_id); + // if (swwo != idx.end()) { + // + // std::stringstream ss_trx(boost::algorithm::unhex(op_tx_str)); + // hive::signed_transaction op_trx; + // fc::raw::unpack(ss_trx, op_trx, 1000); + // + // uint64_t symbol = 0; + // if (swwo->withdraw_currency == "HBD") { + // symbol = hive::asset::hbd_symbol_ser; + // } + // if (swwo->withdraw_currency == "HIVE") { + // symbol = hive::asset::hive_symbol_ser; + // } + // + // hive::transfer_operation t_op; + // t_op.from = wallet_account_name; + // t_op.to = swwo->withdraw_address; + // t_op.amount.amount = swwo->withdraw_amount; + // t_op.amount.symbol = symbol; + // t_op.memo = ""; + // + // hive::signed_transaction htrx; + // htrx.ref_block_num = op_trx.ref_block_num; + // htrx.ref_block_prefix = op_trx.ref_block_prefix; + // htrx.set_expiration(op_trx.expiration); + // + // htrx.operations.push_back(t_op); + // + // std::stringstream ss; + // fc::raw::pack(ss, htrx, 1000); + // tx_str = boost::algorithm::hex(ss.str()); + // } + // } + // + // transaction_ok = (op_tx_str == tx_str); + //} + } + + process_ok = true; + transaction_ok = true; + + should_approve = process_ok && + transaction_ok; + break; + } + + case chain::operation::tag::value: { + should_approve = true; + son_id_type signer = op_obj_idx_0.get().signer; + std::string signature = op_obj_idx_0.get().signature; + sidechain_transaction_id_type sidechain_transaction_id = op_obj_idx_0.get().sidechain_transaction_id; + const auto &st_idx = database.get_index_type().indices().get(); + const auto sto = st_idx.find(sidechain_transaction_id); + if (sto == st_idx.end()) { + should_approve = false; + break; + } + + const auto &s_idx = database.get_index_type().indices().get(); + const auto son = s_idx.find(signer); + if (son == s_idx.end()) { + should_approve = false; + break; + } + + break; + } + + case chain::operation::tag::value: { + should_approve = true; + break; + } + + default: + should_approve = false; + elog("=================================================="); + elog("Proposal not considered for approval ${po}", ("po", po)); + elog("=================================================="); + } + + return should_approve; } void sidechain_net_handler_ethereum::process_primary_wallet() { - const auto &swi = database.get_index_type().indices().get(); - const auto &active_sw = swi.rbegin(); - if (active_sw != swi.rend()) { - - if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) || - (active_sw->addresses.at(sidechain_type::ethereum).empty())) { - - if (proposal_exists(chain::operation::tag::value, active_sw->id)) { - return; - } - - const chain::global_property_object &gpo = database.get_global_properties(); - - auto active_sons = gpo.active_sons; - string reply_str = create_primary_wallet_address(active_sons); - - std::stringstream active_pw_ss(reply_str); - - boost::property_tree::ptree active_pw_pt; - boost::property_tree::read_json(active_pw_ss, active_pw_pt); - if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { - if (!plugin.can_son_participate(chain::operation::tag::value, active_sw->id)) { - return; - } - - proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; - uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - - std::stringstream res; - boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); - - son_wallet_update_operation swu_op; - swu_op.payer = gpo.parameters.son_account(); - swu_op.son_wallet_id = active_sw->id; - swu_op.sidechain = sidechain_type::ethereum; - swu_op.address = res.str(); - - proposal_op.proposed_ops.emplace_back(swu_op); - - const auto &prev_sw = std::next(active_sw); - if (prev_sw != swi.rend()) { - 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()) { - sidechain_transaction_create_operation stc_op; - stc_op.payer = gpo.parameters.son_account(); - stc_op.object_id = prev_sw->id; - stc_op.sidechain = sidechain; - stc_op.transaction = tx_str; - stc_op.signers = prev_sw->sons; - proposal_op.proposed_ops.emplace_back(stc_op); - } - } - - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); - try { - trx.validate(); - database.push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - plugin.log_son_proposal_retry(chain::operation::tag::value, active_sw->id); - } catch (fc::exception &e) { - elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); - return; - } - } - } - } + //const auto &swi = database.get_index_type().indices().get(); + //const auto &active_sw = swi.rbegin(); + //if (active_sw != swi.rend()) { + // + // if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) || + // (active_sw->addresses.at(sidechain_type::ethereum).empty())) { + // + // if (proposal_exists(chain::operation::tag::value, active_sw->id)) { + // return; + // } + // + // const chain::global_property_object &gpo = database.get_global_properties(); + // + // auto active_sons = gpo.active_sons; + // string reply_str = create_primary_wallet_address(active_sons); + // + // std::stringstream active_pw_ss(reply_str); + // + // boost::property_tree::ptree active_pw_pt; + // boost::property_tree::read_json(active_pw_ss, active_pw_pt); + // if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { + // if (!plugin.can_son_participate(chain::operation::tag::value, active_sw->id)) { + // return; + // } + // + // proposal_create_operation proposal_op; + // proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + // uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + // proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + // + // std::stringstream res; + // boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); + // + // son_wallet_update_operation swu_op; + // swu_op.payer = gpo.parameters.son_account(); + // swu_op.son_wallet_id = active_sw->id; + // swu_op.sidechain = sidechain_type::ethereum; + // swu_op.address = res.str(); + // + // proposal_op.proposed_ops.emplace_back(swu_op); + // + // const auto &prev_sw = std::next(active_sw); + // if (prev_sw != swi.rend()) { + // 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()) { + // sidechain_transaction_create_operation stc_op; + // stc_op.payer = gpo.parameters.son_account(); + // stc_op.object_id = prev_sw->id; + // stc_op.sidechain = sidechain; + // stc_op.transaction = tx_str; + // stc_op.signers = prev_sw->sons; + // proposal_op.proposed_ops.emplace_back(stc_op); + // } + // } + // + // signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + // try { + // trx.validate(); + // database.push_transaction(trx, database::validation_steps::skip_block_size_check); + // if (plugin.app().p2p_node()) + // plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + // plugin.log_son_proposal_retry(chain::operation::tag::value, active_sw->id); + // } catch (fc::exception &e) { + // elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); + // return; + // } + // } + // } + //} } void sidechain_net_handler_ethereum::process_sidechain_addresses() { } bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_object &swdo) { + const chain::global_property_object &gpo = database.get_global_properties(); - if (proposal_exists(chain::operation::tag::value, swdo.id)) { + 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()); + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + + son_wallet_deposit_process_operation swdp_op; + swdp_op.payer = gpo.parameters.son_account(); + swdp_op.son_wallet_deposit_id = swdo.id; + proposal_op.proposed_ops.emplace_back(swdp_op); + + asset_issue_operation ai_op; + ai_op.fee = database.current_fee_schedule().calculate_fee(ai_op); + ai_op.issuer = gpo.parameters.son_account(); + ai_op.asset_to_issue = asset_to_issue; + ai_op.issue_to_account = swdo.peerplays_from; + proposal_op.proposed_ops.emplace_back(ai_op); + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + return true; + } catch (fc::exception &e) { + elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what())); return false; } - std::string tx_str = create_deposit_transaction(swdo); - - if (!tx_str.empty()) { - const chain::global_property_object &gpo = database.get_global_properties(); - - proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; - uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - - son_wallet_deposit_process_operation swdp_op; - swdp_op.payer = gpo.parameters.son_account(); - swdp_op.son_wallet_deposit_id = swdo.id; - proposal_op.proposed_ops.emplace_back(swdp_op); - - sidechain_transaction_create_operation stc_op; - stc_op.payer = gpo.parameters.son_account(); - stc_op.object_id = swdo.id; - stc_op.sidechain = sidechain; - stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons; - proposal_op.proposed_ops.emplace_back(stc_op); - - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); - try { - trx.validate(); - database.push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - return true; - } catch (fc::exception &e) { - elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what())); - return false; - } - } return false; } @@ -343,10 +628,84 @@ void sidechain_net_handler_ethereum::schedule_ethereum_listener() { void sidechain_net_handler_ethereum::ethereum_listener_loop() { schedule_ethereum_listener(); - std::string reply = ethereum_client_rpc->eth_get_block_by_number("latest", true); + std::string reply = rpc_client->eth_get_block_by_number("latest", false); + //std::string reply = rpc_client->eth_get_logs(wallet_contract_address); + if (!reply.empty()) { + std::stringstream ss(reply); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + if (json.count("result")) { + std::string head_block_number_s = json.get("result.number"); + uint64_t head_block_number = std::strtoul(head_block_number_s.c_str(), nullptr, 16); + if (head_block_number != last_block_received) { + std::string event_data = std::to_string(head_block_number); + handle_event(event_data); + last_block_received = head_block_number; + } + } + } } void sidechain_net_handler_ethereum::handle_event(const std::string &event_data) { + std::string block = rpc_client->eth_get_block_by_number("latest", true); + if (block != "") { + add_to_son_listener_log("BLOCK : " + event_data); + std::stringstream ss(block); + boost::property_tree::ptree block_json; + boost::property_tree::read_json(ss, block_json); + + size_t tx_idx = -1; + for (const auto &tx_child : block_json.get_child("result.transactions")) { + boost::property_tree::ptree tx = tx_child.second; + tx_idx = tx_idx + 1; + + std::string from = tx.get("from"); + std::string to = tx.get("to"); + + std::string cmp_to = to; + std::transform(cmp_to.begin(), cmp_to.end(), cmp_to.begin(), ::toupper); + std::string cmp_wallet_contract_address = wallet_contract_address; + std::transform(cmp_wallet_contract_address.begin(), cmp_wallet_contract_address.end(), cmp_wallet_contract_address.begin(), ::toupper); + + if (cmp_to == cmp_wallet_contract_address) { + + std::string value_s = tx.get("value"); + boost::multiprecision::uint256_t amount(value_s); + amount = amount / 100000; + amount = amount / 100000; + + 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())); + if (addr_itr == sidechain_addresses_idx.end()) { + continue; + } + + 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.sidechain_transaction_id = tx.get("hash"); + sed.sidechain_from = from; + sed.sidechain_to = to; + sed.sidechain_currency = "ETH"; + sed.sidechain_amount = amount; + sed.peerplays_from = addr_itr->sidechain_address_account; + sed.peerplays_to = database.get_global_properties().parameters.son_account(); + price eth_price = database.get(database.get_global_properties().parameters.eth_asset()).options.core_exchange_rate; + sed.peerplays_asset = asset(sed.sidechain_amount * eth_price.base.amount / eth_price.quote.amount); + + add_to_son_listener_log("TRX : " + sed.sidechain_transaction_id); + + sidechain_event_data_received(sed); + } + } + } } }} // namespace graphene::peerplays_sidechain -- 2.45.2 From 35c2d4c63f084ff41e0fa37588769c7307e46edc Mon Sep 17 00:00:00 2001 From: serkixenos Date: Tue, 26 Jul 2022 19:34:13 +0200 Subject: [PATCH 34/60] Remove WS client --- .../peerplays_sidechain/CMakeLists.txt | 1 - .../peerplays_sidechain/common/rpc_client.cpp | 2 - .../peerplays_sidechain/common/ws_client.cpp | 195 ------------------ .../peerplays_sidechain/common/ws_client.hpp | 38 ---- .../peerplays_sidechain_plugin.cpp | 6 +- 5 files changed, 3 insertions(+), 239 deletions(-) delete mode 100644 libraries/plugins/peerplays_sidechain/common/ws_client.cpp delete mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/ws_client.hpp diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index 679539e3..ca995c10 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -18,7 +18,6 @@ add_library( peerplays_sidechain bitcoin/sign_bitcoin_transaction.cpp common/rpc_client.cpp common/utils.cpp - common/ws_client.cpp ethereum/encoders.cpp ethereum/decoders.cpp ethereum/transaction.cpp diff --git a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp index 687b8ea5..357c435c 100644 --- a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp +++ b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp @@ -13,8 +13,6 @@ #include #include -#include - #include namespace graphene { namespace peerplays_sidechain { diff --git a/libraries/plugins/peerplays_sidechain/common/ws_client.cpp b/libraries/plugins/peerplays_sidechain/common/ws_client.cpp deleted file mode 100644 index 3292717f..00000000 --- a/libraries/plugins/peerplays_sidechain/common/ws_client.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace graphene { namespace peerplays_sidechain { - -ws_client::ws_client(std::string _url, std::string _user, std::string _password, bool _debug_ws_calls) : - url(_url), - user(_user), - password(_password), - debug_ws_calls(_debug_ws_calls), - request_id(0) { - - std::string reg_expr = "^((?Pwss|ws):\\/\\/)?(?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 = "ws"; - } - - host = sm["Host"]; - if (host.empty()) { - host + "localhost"; - } - - port = sm["Port"]; - if (port.empty()) { - port = "80"; - } - - target = sm["Target"]; - if (target.empty()) { - target = "/"; - } - } else { - elog("Invalid URL: ${url}", ("url", url)); - } -} - -std::string ws_client::retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx) { - std::stringstream ss(reply_str); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - if (json.find("result") == json.not_found()) { - return ""; - } - - auto json_result = json.get_child_optional("result"); - if (json_result) { - boost::property_tree::ptree array_ptree = json_result.get(); - if (!array_path.empty()) { - array_ptree = json_result.get().get_child(array_path); - } - uint32_t array_el_idx = -1; - for (const auto &array_el : array_ptree) { - array_el_idx = array_el_idx + 1; - if (array_el_idx == idx) { - std::stringstream ss_res; - boost::property_tree::json_parser::write_json(ss_res, array_el.second); - return ss_res.str(); - } - } - } - - return ""; -} - -std::string ws_client::retrieve_value_from_reply(std::string reply_str, std::string value_path) { - std::stringstream ss(reply_str); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - if (json.find("result") == json.not_found()) { - return ""; - } - - auto json_result = json.get_child_optional("result"); - if (json_result) { - return json_result.get().get(value_path); - } - - return json.get("result"); -} - -std::string ws_client::send_post_request(std::string method, std::string params, bool show_log) { - std::stringstream body; - - request_id = request_id + 1; - - body << "{ \"jsonrpc\": \"2.0\", \"id\": " << request_id << ", \"method\": \"" << method << "\""; - - if (!params.empty()) { - body << ", \"params\": " << params; - } - - body << " }"; - - const auto reply = send_post_request(body.str(), show_log); - - if (reply.body.empty()) { - wlog("RPC call ${function} failed", ("function", __FUNCTION__)); - return ""; - } - - std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - - if (reply.status == 200) { - return ss.str(); - } - - if (json.count("error") && !json.get_child("error").empty()) { - wlog("RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body.str())("msg", ss.str())); - } - return ""; -} - -ws_reply ws_client::send_post_request(std::string body, bool show_log) { - - // The io_context is required for all I/O - boost::beast::net::io_context ioc; - - // These objects perform our I/O - boost::beast::net::ip::tcp::resolver resolver(ioc); - boost::beast::websocket::stream ws{ioc}; - - // Look up the domain name - auto const results = resolver.resolve(host, port); - - // Make the connection on the IP address we get from a lookup - boost::beast::net::connect(ws.next_layer(), results.begin(), results.end()); - - // Set a decorator to change the User-Agent of the handshake - ws.set_option(boost::beast::websocket::stream_base::decorator( - [](boost::beast::websocket::request_type &req) { - //// Set up an HTTP GET request message - //boost::beast::http::request req{boost::beast::http::verb::post, target, 11}; - //req.set(boost::beast::http::field::host, host + ":" + port); - //req.set(boost::beast::http::field::accept, "application/json"); - //req.set(boost::beast::http::field::content_type, "application/json"); - //req.set(boost::beast::http::field::content_encoding, "utf-8"); - //req.set(boost::beast::http::field::content_length, body.length()); - //req.body() = body; - })); - - // Perform the websocket handshake - ws.handshake(host, "/"); - - // Send the message - ws.write(boost::asio::buffer(body)); - - // This buffer is used for reading and must be persisted - boost::beast::flat_buffer buffer; - - // Read a message into our buffer - ws.read(buffer); - - // Close the WebSocket connection - ws.close(boost::beast::websocket::close_code::normal); - - //std::string rbody{boost::asio::buffers_begin(buffer), - // boost::asio::buffers_end(reading)}; - - ws_reply reply; - reply.status = 200; - //reply.body = rbody; - - //if (show_log) { - // ilog("### Request URL: ${url}", ("url", url)); - // ilog("### Request: ${body}", ("body", body)); - // ilog("### Response: ${rbody}", ("rbody", rbody)); - //} - - return reply; -} - -}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/ws_client.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/ws_client.hpp deleted file mode 100644 index 9a7cfca4..00000000 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/ws_client.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include - -namespace graphene { namespace peerplays_sidechain { - -struct ws_reply { - uint16_t status; - std::string body; -}; - -class ws_client { -public: - ws_client(std::string _url, std::string _user, std::string _password, bool _debug_ws_calls); - -protected: - std::string retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx); - std::string retrieve_value_from_reply(std::string reply_str, std::string value_path); - std::string send_post_request(std::string method, std::string params, bool show_log); - - std::string url; - std::string protocol; - std::string host; - std::string port; - std::string target; - - std::string user; - std::string password; - bool debug_ws_calls; - - uint32_t request_id; - -private: - ws_reply send_post_request(std::string body, bool show_log); -}; - -}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 73bef93f..c3c17931 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -161,9 +161,9 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("ethereum-node-rpc-url", bpo::value()->default_value("127.0.0.1:8545"), "Ethereum node RPC URL [http[s]://]host[:port]"); 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()->default_value("0000000000000000000000000000000000000000"), "Ethereum wallet contract address"), - 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)"); + cli.add_options()("ethereum-wallet-contract-address", bpo::value()->default_value("0000000000000000000000000000000000000000"), "Ethereum wallet contract address"); + 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)"); cli.add_options()("hive-sidechain-enabled", bpo::value()->default_value(false), "Hive sidechain handler enabled"); cli.add_options()("hive-node-rpc-url", bpo::value()->default_value("127.0.0.1:28090"), "Hive node RPC URL [http[s]://]host[:port]"); -- 2.45.2 From abda10d8849080eca32a03be968211476bd05dd7 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Tue, 26 Jul 2022 19:43:32 +0200 Subject: [PATCH 35/60] Remove WS client --- .../plugins/peerplays_sidechain/common/rpc_client.cpp | 1 + .../sidechain_net_handler_ethereum.hpp | 6 ------ .../peerplays_sidechain/sidechain_net_handler_bitcoin.cpp | 8 ++++---- .../sidechain_net_handler_ethereum.cpp | 3 --- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp index 357c435c..ffa5f9a9 100644 --- a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp +++ b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp @@ -13,6 +13,7 @@ #include #include +#include #include namespace graphene { namespace peerplays_sidechain { 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 9b374588..681ceaed 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 @@ -7,7 +7,6 @@ #include #include -#include #include namespace graphene { namespace peerplays_sidechain { @@ -25,11 +24,6 @@ public: std::string get_network_id(); }; -class ethereum_ws_client : public ws_client { -public: - ethereum_ws_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); -}; - class sidechain_net_handler_ethereum : public sidechain_net_handler { public: sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 8c820363..0d3da223 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -356,13 +356,13 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain } std::string url = ip + ":" + std::to_string(rpc_port); - if (wallet.length() > 0) { - url = url + "/wallet/" + wallet; + 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.empty()) { - bitcoin_client->loadwallet(wallet); + if (!wallet_name.empty()) { + bitcoin_client->loadwallet(wallet_name); } std::string blockchain_info = bitcoin_client->getblockchaininfo(); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 2bbb5082..58d22b00 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -55,9 +55,6 @@ std::string ethereum_rpc_client::get_network_id() { return retrieve_value_from_reply(reply_str, "protocols.eth.network"); } -ethereum_ws_client::ethereum_ws_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : - ws_client(url, user_name, password, debug_rpc_calls){}; - sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : sidechain_net_handler(_plugin, options) { sidechain = sidechain_type::ethereum; -- 2.45.2 From 6f2bc4584fb73618d994f8afea89a599237ce2a9 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Wed, 27 Jul 2022 01:42:01 +0200 Subject: [PATCH 36/60] Remove WS client --- .../peerplays_sidechain/common/rpc_client.cpp | 13 +++--- .../peerplays_sidechain/common/utils.cpp | 43 +++++++++++++++++++ .../peerplays_sidechain/common/rpc_client.hpp | 8 ++-- .../peerplays_sidechain/common/utils.hpp | 7 +++ 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp index ffa5f9a9..4c1365f3 100644 --- a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp +++ b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp @@ -3,19 +3,19 @@ #include #include -#include -#include -#include - #include #include #include #include #include +#include +#include +#include -#include #include +#include + namespace graphene { namespace peerplays_sidechain { rpc_client::rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls) : @@ -52,7 +52,8 @@ rpc_client::rpc_client(std::string _url, std::string _user, std::string _passwor target = "/"; } - authorization = "Basic " + fc::base64_encode(user + ":" + password); + authorization = "Basic " + base64_encode(user + ":" + password); + results = resolver.resolve(host, port); } else { diff --git a/libraries/plugins/peerplays_sidechain/common/utils.cpp b/libraries/plugins/peerplays_sidechain/common/utils.cpp index 4491487f..580dd831 100644 --- a/libraries/plugins/peerplays_sidechain/common/utils.cpp +++ b/libraries/plugins/peerplays_sidechain/common/utils.cpp @@ -1,8 +1,51 @@ #include +#include +#include +//#include +#include + +namespace graphene { namespace peerplays_sidechain { + +const std::string base64_padding[] = {"", "==", "="}; + +std::string base64_encode(const std::string &s) { + using namespace boost::archive::iterators; + + typedef base64_from_binary> base64_enc; + + std::stringstream os; + std::copy(base64_enc(s.c_str()), base64_enc(s.c_str() + s.size()), std::ostream_iterator(os)); + os << base64_padding[s.size() % 3]; + + return os.str(); +} + +std::string base64_decode(const std::string &s) { + using namespace boost::archive::iterators; + + typedef transform_width, 8, 6> base64_dec; + + std::stringstream os; + unsigned int size = s.size(); + if (size && s[size - 1] == '=') { + --size; + if (size && s[size - 1] == '=') + --size; + } + if (size == 0) + return std::string(); + + std::copy(base64_dec(s.data()), base64_dec(s.data() + size), std::ostream_iterator(os)); + + return os.str(); +} + std::string object_id_to_string(graphene::chain::object_id_type id) { std::string object_id = fc::to_string(id.space()) + "." + fc::to_string(id.type()) + "." + fc::to_string(id.instance()); return object_id; } + +}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp index 8f4ac248..eb8eac0c 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp @@ -23,16 +23,16 @@ protected: std::string send_post_request(std::string method, std::string params, bool show_log); std::string url; + std::string user; + std::string password; + bool debug_rpc_calls; + std::string protocol; std::string host; std::string port; std::string target; std::string authorization; - std::string user; - std::string password; - bool debug_rpc_calls; - uint32_t request_id; private: 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 99c59019..066a36fe 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 @@ -2,4 +2,11 @@ #include +namespace graphene { namespace peerplays_sidechain { + +std::string base64_encode(const std::string &s); +std::string base64_decode(const std::string &s); + std::string object_id_to_string(graphene::chain::object_id_type id); + +}} // namespace graphene::peerplays_sidechain -- 2.45.2 From e9dbafb56ad0e66b3a51c048806b4984b4d9fef0 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Thu, 28 Jul 2022 10:33:59 +0300 Subject: [PATCH 37/60] Fix "hive-node-rpc-url" --- .../plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp index 00dcce68..a78b5f17 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp @@ -120,7 +120,7 @@ sidechain_net_handler_hive::sidechain_net_handler_hive(peerplays_sidechain_plugi debug_rpc_calls = options.at("debug-rpc-calls").as(); } - rpc_url = options.at("hive-rpc-url").as(); + rpc_url = options.at("hive-node-rpc-url").as(); if (options.count("hive-rpc-user")) { rpc_user = options.at("hive-rpc-user").as(); } else { -- 2.45.2 From 7629ecc8b3dfa6347b02e445a32f8ab4e4545731 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Fri, 29 Jul 2022 18:07:49 +0200 Subject: [PATCH 38/60] Improve SONs config parameter checks --- .../peerplays_sidechain_plugin.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index c3c17931..6300c8e4 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -161,7 +161,7 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("ethereum-node-rpc-url", bpo::value()->default_value("127.0.0.1:8545"), "Ethereum node RPC URL [http[s]://]host[:port]"); 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()->default_value("0000000000000000000000000000000000000000"), "Ethereum wallet contract address"); + cli.add_options()("ethereum-wallet-contract-address", bpo::value(), "Ethereum wallet contract address"); 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)"); @@ -169,7 +169,7 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("hive-node-rpc-url", bpo::value()->default_value("127.0.0.1:28090"), "Hive node RPC URL [http[s]://]host[:port]"); cli.add_options()("hive-node-rpc-user", bpo::value(), "Hive node RPC user"); cli.add_options()("hive-node-rpc-password", bpo::value(), "Hive node RPC password"); - cli.add_options()("hive-wallet-account-name", bpo::value()->default_value("son-account"), "Hive wallet account name"), + cli.add_options()("hive-wallet-account-name", bpo::value(), "Hive wallet account name"), cli.add_options()("hive-private-key", bpo::value>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", "5JNHfZYKGaomSFvd4NUdQ9qMcEAC43kujbfjueTHpVapX1Kzq2n")), "Tuple of [Hive public key, Hive private key] (may specify multiple times)"); @@ -220,25 +220,27 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt 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") && options.count("bitcoin-wallet-password") &&*/ + options.count("bitcoin-wallet-name") && options.count("bitcoin-wallet-password") && options.count("bitcoin-private-key"); - if (!config_ready_bitcoin) { + if (sidechain_enabled_bitcoin && !config_ready_bitcoin) { wlog("Haven't set up Bitcoin sidechain parameters"); } sidechain_enabled_ethereum = options.at("ethereum-sidechain-enabled").as(); config_ready_ethereum = options.count("ethereum-node-rpc-url") && /*options.count("ethereum-node-rpc-user") && options.count("ethereum-node-rpc-password") &&*/ + options.count("ethereum-wallet-contract-address") && options.count("ethereum-private-key"); - if (!config_ready_ethereum) { + if (sidechain_enabled_ethereum && !config_ready_ethereum) { wlog("Haven't set up Ethereum sidechain parameters"); } sidechain_enabled_hive = options.at("hive-sidechain-enabled").as(); config_ready_hive = options.count("hive-node-rpc-url") && /*options.count("hive-node-rpc-user") && options.count("hive-node-rpc-password") &&*/ + options.count("hive-wallet-account-name") && options.count("hive-private-key"); - if (!config_ready_hive) { + if (sidechain_enabled_hive && !config_ready_hive) { wlog("Haven't set up Hive sidechain parameters"); } -- 2.45.2 From 2fbe2ffe68b544beb825b1e6f05a870694a7f459 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Fri, 29 Jul 2022 18:48:57 +0200 Subject: [PATCH 39/60] Improve SONs config parameter checks --- CMakeLists.txt | 1 - README.md | 6 +++--- libraries/CMakeLists.txt | 2 +- .../peerplays_sidechain_plugin.cpp | 12 ++---------- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d4c2f1d..695881be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,6 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") list(GET arg_list 0 output) message("Ubuntu version is: ${output}") add_definitions(-DPEERPLAYS_UBUNTU_VERSION=${output}) - endif() # function to help with cUrl diff --git a/README.md b/README.md index a8d98021..f3d8c5b9 100644 --- a/README.md +++ b/README.md @@ -84,9 +84,9 @@ sudo apt-get install \ Install Boost libraries from source ``` -wget -c 'http://sourceforge.net/projects/boost/files/boost/1.67.0/boost_1_67_0.tar.bz2/download' -O boost_1_67_0.tar.bz2 -tar xjf boost_1_67_0.tar.bz2 -cd boost_1_67_0/ +wget -c 'https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/boost_1_71_0.tar.bz2' -O boost_1_71_0.tar.bz2 +tar xjf boost_1_71_0.tar.bz2 +cd boost_1_71_0/ ./bootstrap.sh sudo ./b2 install ``` diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index dfe3d397..df872464 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,4 +1,3 @@ -add_subdirectory( vendor ) add_subdirectory( app ) add_subdirectory( chain ) add_subdirectory( db ) @@ -8,4 +7,5 @@ add_subdirectory( net ) add_subdirectory( plugins ) add_subdirectory( time ) add_subdirectory( utilities ) +add_subdirectory( vendor ) add_subdirectory( wallet ) diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 6300c8e4..2e5742a6 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -245,22 +245,14 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt } #ifdef ENABLE_PEERPLAYS_ASSET_DEPOSITS - sidechain_enabled_peerplays = true; //options.at("peerplays-sidechain-enabled").as(); + sidechain_enabled_peerplays = true; #else sidechain_enabled_peerplays = false; #endif config_ready_peerplays = true; - if (!config_ready_peerplays) { + if (sidechain_enabled_peerplays && !config_ready_peerplays) { wlog("Haven't set up Peerplays sidechain parameters"); } - - if (!(config_ready_bitcoin && - config_ready_ethereum && - config_ready_hive && - config_ready_peerplays)) { - wlog("Haven't set up any sidechain parameters"); - throw; - } } void peerplays_sidechain_plugin_impl::plugin_startup() { -- 2.45.2 From 776dc729b5679b0d401d0821c14b26f0373ec66c Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Tue, 2 Aug 2022 11:17:16 +0300 Subject: [PATCH 40/60] UpdateOwners: 1) process_proposal 2) sign_transaction 3) send_sidechain_transaction 4) settle_sidechain_transaction --- .../sidechain_net_handler_ethereum.hpp | 10 +- .../sidechain_net_handler_ethereum.cpp | 392 +++++++++++------- 2 files changed, 243 insertions(+), 159 deletions(-) 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 681ceaed..1af1ab10 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 @@ -22,6 +22,11 @@ public: std::string get_chain_id(); std::string get_network_id(); + + std::string send_transaction(const std::string& wallet_contract_address, const std::string& owner_address, const std::string& data); + std::string get_transaction_receipt(const std::string& params); + //std::string update_owners(const std::string& wallet_contract_address, const std::string& owner_address, const std::vector>& owners_weights, const std::string& object_id); + //std::string withdraw(); }; class sidechain_net_handler_ethereum : public sidechain_net_handler { @@ -49,14 +54,11 @@ private: ethereum::chain_id_type chain_id; ethereum::network_id_type network_id; - 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_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); - std::string send_transaction(const sidechain_transaction_object &sto); uint64_t last_block_received; fc::future _listener_task; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 58d22b00..c4f3dd87 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -22,6 +23,18 @@ namespace graphene { namespace peerplays_sidechain { +std::string string_to_hex(const std::string& in) +{ + std::stringstream ss; + + ss << std::hex << std::setfill('0'); + for (size_t i = 0; in.length() > i; ++i) { + ss << std::setw(2) << static_cast(static_cast(in[i])); + } + + return ss.str(); +} + ethereum_rpc_client::ethereum_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : rpc_client(url, user_name, password, debug_rpc_calls) { } @@ -55,6 +68,43 @@ std::string ethereum_rpc_client::get_network_id() { return retrieve_value_from_reply(reply_str, "protocols.eth.network"); } +std::string ethereum_rpc_client::send_transaction(const std::string& wallet_contract_address, const std::string& owner_address, const std::string& data) { + const std::string params = "[ { \"from\": \"" + owner_address + "\", \"to\": \"" + wallet_contract_address + "\", \"data\": \"" + data + "\" } ]"; + return send_post_request("eth_sendTransaction", params, debug_rpc_calls); +} + +std::string ethereum_rpc_client::get_transaction_receipt(const std::string& params) { + return send_post_request("eth_getTransactionReceipt", "[ \"" + params + "\"]", debug_rpc_calls); +} + +/*std::string ethereum_rpc_client::update_owners(const std::string& wallet_contract_address, const std::string& owner_address, const std::vector>& owners_weights, const std::string& object_id) { + const std::string function_hash = "23ab6adf"; //! updateOwners((address,uint256)[],string) + + const std::string data = [&function_hash, &owners_weights, &object_id] { + std::string data = "0x" + function_hash; + data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), 64)).str(); + data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), ((owners_weights.size() * 2 + 3) * 32))).str(); + data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owners_weights.size())).str(); + for(const auto& owner : owners_weights) + { + data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owner.first)).str(); + data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owner.second)).str(); + } + data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), object_id.size())).str(); + data += string_to_hex(object_id) + std::string( (64 - object_id.size() * 2 % 64), '0' ); + + return data; + }(); + + const std::string params = "[ { \"from\": \"" + owner_address + "\", \"to\": \"" + wallet_contract_address + "\", \"data\": \"" + data + "\" } ]"; + return send_post_request("eth_sendTransaction", params, debug_rpc_calls); +}*/ + +/*std::string ethereum_rpc_client::withdraw() { + const std::string params = "[ { \"from\": \"0x5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12\", \"to\": \"0x3E84f248Cd00A2FDaaDfa0dC5c3ff64D8767Fb01\", \"data\": \"0xe088747b00000000000000000000000009ee460834498a4ee361beb819470061b7381b490000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312e33362e330000000000000000000000000000000000000000000000000000\" } ]"; + return send_post_request("eth_sendTransaction", params, debug_rpc_calls); +}*/ + sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : sidechain_net_handler(_plugin, options) { sidechain = sidechain_type::ethereum; @@ -146,80 +196,45 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) const auto swo = idx.find(swo_id); if (swo != idx.end()) { - //auto active_sons = gpo.active_sons; - //vector wallet_sons = swo->sons; - // - //bool son_sets_equal = (active_sons.size() == wallet_sons.size()); - // - //if (son_sets_equal) { - // for (size_t i = 0; i < active_sons.size(); i++) { - // son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i); - // } - //} - // - //if (son_sets_equal) { - // address_ok = (op_obj_idx_0.get().address == wallet_account_name); - //} - // - //if (po.proposed_transaction.operations.size() >= 2) { - // object_id_type object_id = op_obj_idx_1.get().object_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); - // if (st == st_idx.end()) { - // - // std::string tx_str = ""; - // - // if (object_id.is()) { - // const auto &idx = database.get_index_type().indices().get(); - // const auto swo = idx.find(object_id); - // if (swo != idx.end()) { - // - // std::stringstream ss_trx(boost::algorithm::unhex(op_tx_str)); - // hive::signed_transaction op_trx; - // fc::raw::unpack(ss_trx, op_trx, 1000); - // - // fc::flat_map account_auths; - // uint32_t total_weight = 0; - // for (const auto &wallet_son : wallet_sons) { - // total_weight = total_weight + wallet_son.weight; - // account_auths[wallet_son.sidechain_public_keys.at(sidechain)] = wallet_son.weight; - // } - // - // std::string memo_key = rpc_client->get_account_memo_key(wallet_account_name); - // - // hive::authority active; - // active.weight_threshold = total_weight * 2 / 3 + 1; - // active.account_auths = account_auths; - // - // hive::account_update_operation auo; - // auo.account = wallet_account_name; - // auo.active = active; - // auo.memo_key = op_trx.operations[0].get().memo_key; - // - // hive::signed_transaction htrx; - // htrx.ref_block_num = op_trx.ref_block_num; - // htrx.ref_block_prefix = op_trx.ref_block_prefix; - // htrx.set_expiration(op_trx.expiration); - // - // htrx.operations.push_back(auo); - // - // std::stringstream ss; - // fc::raw::pack(ss, htrx, 1000); - // tx_str = boost::algorithm::hex(ss.str()); - // } - // } - // - // transaction_ok = (op_tx_str == tx_str); - // } - //} else { - // transaction_ok = true; - //} - } + auto active_sons = gpo.active_sons; + vector wallet_sons = swo->sons; - address_ok = true; - transaction_ok = true; + bool son_sets_equal = (active_sons.size() == wallet_sons.size()); + + if (son_sets_equal) { + for (size_t i = 0; i < active_sons.size(); i++) { + son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i); + } + } + + if (son_sets_equal) { + address_ok = (op_obj_idx_0.get().address == wallet_contract_address); + } + + if (po.proposed_transaction.operations.size() >= 2) { + object_id_type object_id = op_obj_idx_1.get().object_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); + if (st == st_idx.end()) { + + std::string tx_str = ""; + + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swo = idx.find(object_id); + if (swo != idx.end()) { + tx_str = create_primary_wallet_transaction(gpo.active_sons, object_id.operator std::string()); + } + } + + transaction_ok = (op_tx_str == tx_str); + } + } else { + transaction_ok = true; + } + } should_approve = address_ok && transaction_ok; @@ -416,79 +431,62 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) } void sidechain_net_handler_ethereum::process_primary_wallet() { - //const auto &swi = database.get_index_type().indices().get(); - //const auto &active_sw = swi.rbegin(); - //if (active_sw != swi.rend()) { - // - // if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) || - // (active_sw->addresses.at(sidechain_type::ethereum).empty())) { - // - // if (proposal_exists(chain::operation::tag::value, active_sw->id)) { - // return; - // } - // - // const chain::global_property_object &gpo = database.get_global_properties(); - // - // auto active_sons = gpo.active_sons; - // string reply_str = create_primary_wallet_address(active_sons); - // - // std::stringstream active_pw_ss(reply_str); - // - // boost::property_tree::ptree active_pw_pt; - // boost::property_tree::read_json(active_pw_ss, active_pw_pt); - // if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { - // if (!plugin.can_son_participate(chain::operation::tag::value, active_sw->id)) { - // return; - // } - // - // proposal_create_operation proposal_op; - // proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; - // uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - // proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - // - // std::stringstream res; - // boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); - // - // son_wallet_update_operation swu_op; - // swu_op.payer = gpo.parameters.son_account(); - // swu_op.son_wallet_id = active_sw->id; - // swu_op.sidechain = sidechain_type::ethereum; - // swu_op.address = res.str(); - // - // proposal_op.proposed_ops.emplace_back(swu_op); - // - // const auto &prev_sw = std::next(active_sw); - // if (prev_sw != swi.rend()) { - // 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()) { - // sidechain_transaction_create_operation stc_op; - // stc_op.payer = gpo.parameters.son_account(); - // stc_op.object_id = prev_sw->id; - // stc_op.sidechain = sidechain; - // stc_op.transaction = tx_str; - // stc_op.signers = prev_sw->sons; - // proposal_op.proposed_ops.emplace_back(stc_op); - // } - // } - // - // signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); - // try { - // trx.validate(); - // database.push_transaction(trx, database::validation_steps::skip_block_size_check); - // if (plugin.app().p2p_node()) - // plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - // plugin.log_son_proposal_retry(chain::operation::tag::value, active_sw->id); - // } catch (fc::exception &e) { - // elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); - // return; - // } - // } - // } - //} + const auto &swi = database.get_index_type().indices().get(); + const auto &active_sw = swi.rbegin(); + if (active_sw != swi.rend()) { + + if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) || + (active_sw->addresses.at(sidechain_type::ethereum).empty())) { + + if (proposal_exists(chain::operation::tag::value, active_sw->id)) { + return; + } + + if (!plugin.can_son_participate(chain::operation::tag::value, active_sw->id)) { + return; + } + + const chain::global_property_object &gpo = database.get_global_properties(); + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + + son_wallet_update_operation swu_op; + swu_op.payer = gpo.parameters.son_account(); + swu_op.son_wallet_id = active_sw->id; + swu_op.sidechain = sidechain_type::ethereum; + swu_op.address = wallet_contract_address; + proposal_op.proposed_ops.emplace_back(swu_op); + + std::string tx_str = create_primary_wallet_transaction(gpo.active_sons, active_sw->id.operator std::string()); + if (!tx_str.empty()) { + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = active_sw->id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = gpo.active_sons; + proposal_op.proposed_ops.emplace_back(stc_op); + } + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + plugin.log_son_proposal_retry(chain::operation::tag::value, active_sw->id); + } catch (fc::exception &e) { + elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); + return; + } + } + } } void sidechain_net_handler_ethereum::process_sidechain_addresses() { + int temp = 0; } bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_object &swdo) { @@ -578,19 +576,104 @@ std::string sidechain_net_handler_ethereum::process_sidechain_transaction(const } std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sidechain_transaction_object &sto) { - return send_transaction(sto); + boost::property_tree::ptree pt; + boost::property_tree::ptree pt_array; + for(const auto& signature : sto.signatures) { + const std::string sidechain_transaction = rpc_client->send_transaction(wallet_contract_address, signature.second, sto.transaction); + + std::stringstream ss_tx(sidechain_transaction); + boost::property_tree::ptree tx_json; + boost::property_tree::read_json(ss_tx, tx_json); + if( tx_json.count("result") && !tx_json.count("error") ) { + boost::property_tree::ptree node; + node.put("son", signature.second); + node.put("result", tx_json.get("result")); + pt_array.push_back(std::make_pair("", node)); + } + else { + //! Fixme + //! How should we proceed with error in send_transaction + elog("Error in send_transaction for transaction ${id}, signature ${signature}", ("id", sto.id) ("signature", signature.second)); + } + } + pt.add_child("result_array", pt_array); + + std::stringstream ss; + boost::property_tree::json_parser::write_json(ss, pt); + return ss.str(); } bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) { - return true; + std::stringstream ss(sto.sidechain_transaction); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + + if( !json.count("result_array") ) { + return false; + } + + size_t count = 0; + for(const auto &entry : json.get_child("result_array")) { + const std::string receipt = rpc_client->get_transaction_receipt( entry.second.get("result") ); + + std::stringstream ss_receipt(receipt); + boost::property_tree::ptree json_receipt; + boost::property_tree::read_json(ss_receipt, json_receipt); + + if( json_receipt.get("result") == "null" ) { + wlog("Block is not minted yet for transaction ${id}", ("id", sto.id)); + return false; + } + + for(const auto &entry_receipt : json_receipt.get_child("result.logs")) { + if( boost::algorithm::to_lower_copy(wallet_contract_address) == entry_receipt.second.get("address") ) { + count += 1; + //! Fixme - compare data somehow? + //if( sto.transaction == entry_receipt.second.get("data") ) { + //} + } + } + } + + //! Check that we have all transactions + if(count != json.count("result_array")) { + wlog("Not all receipts received for transaction ${id}", ("id", sto.id)); + return false; + } + else + return true; + + return false; } -std::string sidechain_net_handler_ethereum::create_primary_wallet_address(const std::vector &son_pubkeys) { - return "Primary Wallet Address"; -} +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) { + FC_ASSERT(son.sidechain_public_keys.contains(sidechain_type::ethereum), "No public keys for son: ${son_id}", ("son_id", son.son_id)); + const std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); + owners_weights.emplace_back(std::make_pair(pub_key_str, son.weight)); + } -std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address) { - return "Primary-Wallet-Transaction"; + //! Create data of transaction + const std::string function_hash = "23ab6adf"; //! updateOwners((address,uint256)[],string) + + const std::string data = [&function_hash, &owners_weights, &object_id] { + std::string data = "0x" + function_hash; + data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), 64)).str(); + data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), ((owners_weights.size() * 2 + 3) * 32))).str(); + data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owners_weights.size())).str(); + for(const auto& owner : owners_weights) + { + data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owner.first)).str(); + data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owner.second)).str(); + } + data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), object_id.size())).str(); + data += string_to_hex(object_id) + std::string( (64 - object_id.size() * 2 % 64), '0' ); + + return data; + }(); + + return data; } std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) { @@ -602,12 +685,11 @@ std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const } std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) { - std::string key = get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain)); - return "Transaction-Signature-" + key; -} + //std::string key = get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain)); -std::string sidechain_net_handler_ethereum::send_transaction(const sidechain_transaction_object &sto) { - return "Transaction-ID"; + const auto& current_son = plugin.get_current_son_object(); + FC_ASSERT(current_son.sidechain_public_keys.contains(sidechain_type::ethereum), "No public keys for current son: ${account_id}", ("account_id", current_son.son_account)); + return "0x" + current_son.sidechain_public_keys.at(sidechain); } void sidechain_net_handler_ethereum::schedule_ethereum_listener() { -- 2.45.2 From 7f3e7e876a83a460ea890b0e31ca5d18432f9344 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Wed, 3 Aug 2022 11:10:30 +0300 Subject: [PATCH 41/60] Replace string_to_hex with boost::algorithm::hex --- .../sidechain_net_handler_ethereum.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index c4f3dd87..10531317 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -23,18 +23,6 @@ namespace graphene { namespace peerplays_sidechain { -std::string string_to_hex(const std::string& in) -{ - std::stringstream ss; - - ss << std::hex << std::setfill('0'); - for (size_t i = 0; in.length() > i; ++i) { - ss << std::setw(2) << static_cast(static_cast(in[i])); - } - - return ss.str(); -} - ethereum_rpc_client::ethereum_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : rpc_client(url, user_name, password, debug_rpc_calls) { } @@ -91,7 +79,7 @@ std::string ethereum_rpc_client::get_transaction_receipt(const std::string& para data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owner.second)).str(); } data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), object_id.size())).str(); - data += string_to_hex(object_id) + std::string( (64 - object_id.size() * 2 % 64), '0' ); + data += boost::algorithm::hex(object_id) + std::string( (64 - object_id.size() * 2 % 64), '0' ); return data; }(); @@ -668,7 +656,7 @@ std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(co data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owner.second)).str(); } data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), object_id.size())).str(); - data += string_to_hex(object_id) + std::string( (64 - object_id.size() * 2 % 64), '0' ); + data += boost::algorithm::hex(object_id) + std::string( (64 - object_id.size() * 2 % 64), '0' ); return data; }(); -- 2.45.2 From f6614ab122a451da8368121d51968072aa16f58c Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Thu, 4 Aug 2022 10:27:09 +0300 Subject: [PATCH 42/60] base_encoder + update_owners_encoder --- .../peerplays_sidechain/ethereum/encoders.cpp | 40 ++++++++++++++++ .../peerplays_sidechain/ethereum/encoders.hpp | 18 ++++++- .../sidechain_net_handler_ethereum.hpp | 1 - .../sidechain_net_handler_ethereum.cpp | 48 ++----------------- 4 files changed, 59 insertions(+), 48 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index 4359a605..2b8984f6 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -1,5 +1,45 @@ #include +#include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { +//! base_encoder +std::string base_encoder::encode_uint256(uint64_t value) +{ + return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str(); +} + +std::string base_encoder::encode_address(const std::string& value) +{ + return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str(); +} + +std::string base_encoder::encode_string(const std::string& value) +{ + std::string data = (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value.size())).str(); + data += boost::algorithm::hex(value) + std::string( (64 - value.size() * 2 % 64), '0' ); + return data; +} + + +//! update_owners_encoder +std::string update_owners_encoder::encode(const std::vector>& owners_weights, const std::string& object_id) const +{ + std::string data = "0x" + function_signature; + data += base_encoder::encode_uint256(64); + data += base_encoder::encode_uint256((owners_weights.size() * 2 + 3) * 32); + data += base_encoder::encode_uint256(owners_weights.size()); + for(const auto& owner : owners_weights) + { + data += base_encoder::encode_address(owner.first); + data += base_encoder::encode_uint256(owner.second); + } + data += base_encoder::encode_string(object_id); + + return data; +} + + }}} // namespace graphene::peerplays_sidechain::ethereum 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 43fc38dc..443720c1 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 @@ -5,7 +5,21 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { -class ethereum_function_call_encoder { +class base_encoder { +public: + static std::string encode_uint256(uint64_t value); + static std::string encode_address(const std::string& value); + static std::string encode_string(const std::string& value); +}; + +class update_owners_encoder { +public: + const std::string function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string) + + std::string encode(const std::vector>& owners_weights, const std::string& object_id) const; +}; + +/*class ethereum_function_call_encoder { public: enum operation_t { OPERATION_CALL, @@ -34,6 +48,6 @@ public: private: ethereum_function_call_encoder m_ethereum_function_call_encoder; -}; +};*/ }}} // namespace graphene::peerplays_sidechain::ethereum 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 1af1ab10..4dc5caff 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 @@ -25,7 +25,6 @@ public: std::string send_transaction(const std::string& wallet_contract_address, const std::string& owner_address, const std::string& data); std::string get_transaction_receipt(const std::string& params); - //std::string update_owners(const std::string& wallet_contract_address, const std::string& owner_address, const std::vector>& owners_weights, const std::string& object_id); //std::string withdraw(); }; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 10531317..03778322 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -3,9 +3,7 @@ #include #include -#include #include -#include #include #include @@ -18,8 +16,8 @@ #include #include #include +#include #include -#include namespace graphene { namespace peerplays_sidechain { @@ -65,29 +63,6 @@ std::string ethereum_rpc_client::get_transaction_receipt(const std::string& para return send_post_request("eth_getTransactionReceipt", "[ \"" + params + "\"]", debug_rpc_calls); } -/*std::string ethereum_rpc_client::update_owners(const std::string& wallet_contract_address, const std::string& owner_address, const std::vector>& owners_weights, const std::string& object_id) { - const std::string function_hash = "23ab6adf"; //! updateOwners((address,uint256)[],string) - - const std::string data = [&function_hash, &owners_weights, &object_id] { - std::string data = "0x" + function_hash; - data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), 64)).str(); - data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), ((owners_weights.size() * 2 + 3) * 32))).str(); - data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owners_weights.size())).str(); - for(const auto& owner : owners_weights) - { - data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owner.first)).str(); - data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owner.second)).str(); - } - data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), object_id.size())).str(); - data += boost::algorithm::hex(object_id) + std::string( (64 - object_id.size() * 2 % 64), '0' ); - - return data; - }(); - - const std::string params = "[ { \"from\": \"" + owner_address + "\", \"to\": \"" + wallet_contract_address + "\", \"data\": \"" + data + "\" } ]"; - return send_post_request("eth_sendTransaction", params, debug_rpc_calls); -}*/ - /*std::string ethereum_rpc_client::withdraw() { const std::string params = "[ { \"from\": \"0x5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12\", \"to\": \"0x3E84f248Cd00A2FDaaDfa0dC5c3ff64D8767Fb01\", \"data\": \"0xe088747b00000000000000000000000009ee460834498a4ee361beb819470061b7381b490000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312e33362e330000000000000000000000000000000000000000000000000000\" } ]"; return send_post_request("eth_sendTransaction", params, debug_rpc_calls); @@ -643,25 +618,8 @@ std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(co } //! Create data of transaction - const std::string function_hash = "23ab6adf"; //! updateOwners((address,uint256)[],string) - - const std::string data = [&function_hash, &owners_weights, &object_id] { - std::string data = "0x" + function_hash; - data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), 64)).str(); - data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), ((owners_weights.size() * 2 + 3) * 32))).str(); - data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owners_weights.size())).str(); - for(const auto& owner : owners_weights) - { - data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owner.first)).str(); - data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), owner.second)).str(); - } - data += (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), object_id.size())).str(); - data += boost::algorithm::hex(object_id) + std::string( (64 - object_id.size() * 2 % 64), '0' ); - - return data; - }(); - - return data; + ethereum::update_owners_encoder encoder; + return encoder.encode(owners_weights, object_id); } std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) { -- 2.45.2 From 212e5bc7ad5fdddbb4c56b63253ee2011d220629 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Thu, 4 Aug 2022 13:06:53 +0300 Subject: [PATCH 43/60] Add ethereum::transaction --- .../ethereum/transaction.cpp | 39 ++++++++++++++----- .../ethereum/transaction.hpp | 39 ++++++++++--------- .../sidechain_net_handler_ethereum.hpp | 2 +- .../sidechain_net_handler_ethereum.cpp | 31 ++++++++------- 4 files changed, 69 insertions(+), 42 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index 9bf3bf02..f2d117b5 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -1,22 +1,43 @@ #include +#include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { -std::string transaction::sign(std::string private_key) { - v = "signed"; +const transaction& transaction::sign(std::string private_key) const +{ +/* v = "signed"; r = "transaction"; s = "signed-transaction"; - return v + "|" + r + "|" + s; + return v + "|" + r + "|" + s;*/ + return *this; } -std::string transaction::serialize() { - return "serialized-transaction"; +std::string transaction::serialize() const +{ + boost::property_tree::ptree pt; + pt.put("from", from); + pt.put("to", to); + pt.put("data", data); + + std::stringstream ss; + boost::property_tree::json_parser::write_json(ss, pt); + return ss.str(); } -void transaction::deserialize(std::string raw_tx) { - block_hash = "1"; - block_number = "2"; - hash = "3"; +void transaction::deserialize(std::string raw_tx) +{ + std::stringstream ss_tx(raw_tx); + boost::property_tree::ptree tx_json; + boost::property_tree::read_json(ss_tx, tx_json); + + if(tx_json.count("from")) + from = tx_json.get("from"); + if(tx_json.count("to")) + to = tx_json.get("to"); + if(tx_json.count("data")) + data = tx_json.get("data"); } }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp index 1ce9497e..7c65b7d2 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp @@ -8,29 +8,30 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { class transaction { public: - std::string block_hash; - std::string block_number; + //std::string block_hash; + //std::string block_number; std::string from; - std::string gas; - std::string gas_price; - std::string max_fee_per_gas; - std::string max_priority_fee_per_gas; - std::string hash; - std::string input; - std::string nonce; + //std::string gas; + //std::string gas_price; + //std::string max_fee_per_gas; + //std::string max_priority_fee_per_gas; + //std::string hash; + //std::string input; + //std::string nonce; std::string to; - std::string transaction_index; - std::string value; - std::string type; - std::vector access_list; - std::string chain_id; - std::string v; - std::string r; - std::string s; + std::string data; + //std::string transaction_index; + //std::string value; + //std::string type; + //std::vector access_list; + //std::string chain_id; + //std::string v; + //std::string r; + //std::string s; - std::string sign(std::string private_key); + const transaction& sign(std::string private_key) const; - std::string serialize(); + std::string serialize() const; void deserialize(std::string raw_tx); }; 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 4dc5caff..8606c095 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 @@ -23,7 +23,7 @@ public: std::string get_chain_id(); std::string get_network_id(); - std::string send_transaction(const std::string& wallet_contract_address, const std::string& owner_address, const std::string& data); + std::string send_transaction(const std::string& params); std::string get_transaction_receipt(const std::string& params); //std::string withdraw(); }; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 03778322..1553ef50 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -54,13 +54,12 @@ std::string ethereum_rpc_client::get_network_id() { return retrieve_value_from_reply(reply_str, "protocols.eth.network"); } -std::string ethereum_rpc_client::send_transaction(const std::string& wallet_contract_address, const std::string& owner_address, const std::string& data) { - const std::string params = "[ { \"from\": \"" + owner_address + "\", \"to\": \"" + wallet_contract_address + "\", \"data\": \"" + data + "\" } ]"; - return send_post_request("eth_sendTransaction", params, debug_rpc_calls); +std::string ethereum_rpc_client::send_transaction(const std::string& params) { + return send_post_request("eth_sendTransaction", "[" + params + "]", debug_rpc_calls); } std::string ethereum_rpc_client::get_transaction_receipt(const std::string& params) { - return send_post_request("eth_getTransactionReceipt", "[ \"" + params + "\"]", debug_rpc_calls); + return send_post_request("eth_getTransactionReceipt", "[\"" + params + "\"]", debug_rpc_calls); } /*std::string ethereum_rpc_client::withdraw() { @@ -542,21 +541,22 @@ std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sid boost::property_tree::ptree pt; boost::property_tree::ptree pt_array; for(const auto& signature : sto.signatures) { - const std::string sidechain_transaction = rpc_client->send_transaction(wallet_contract_address, signature.second, sto.transaction); + const auto& transaction = signature.second; + const std::string sidechain_transaction = rpc_client->send_transaction(transaction); std::stringstream ss_tx(sidechain_transaction); boost::property_tree::ptree tx_json; boost::property_tree::read_json(ss_tx, tx_json); if( tx_json.count("result") && !tx_json.count("error") ) { boost::property_tree::ptree node; - node.put("son", signature.second); - node.put("result", tx_json.get("result")); + node.put("transaction", transaction); + node.put("transaction_receipt", tx_json.get("result")); pt_array.push_back(std::make_pair("", node)); } else { //! Fixme //! How should we proceed with error in send_transaction - elog("Error in send_transaction for transaction ${id}, signature ${signature}", ("id", sto.id) ("signature", signature.second)); + elog("Error in send_transaction for transaction ${id}, transaction ${transaction}", ("id", sto.id) ("transaction", transaction)); } } pt.add_child("result_array", pt_array); @@ -577,7 +577,7 @@ bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechai size_t count = 0; for(const auto &entry : json.get_child("result_array")) { - const std::string receipt = rpc_client->get_transaction_receipt( entry.second.get("result") ); + const std::string receipt = rpc_client->get_transaction_receipt( entry.second.get("transaction_receipt") ); std::stringstream ss_receipt(receipt); boost::property_tree::ptree json_receipt; @@ -618,8 +618,10 @@ std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(co } //! Create data of transaction + ethereum::transaction transaction; ethereum::update_owners_encoder encoder; - return encoder.encode(owners_weights, object_id); + transaction.data = encoder.encode(owners_weights, object_id); + return transaction.serialize(); } std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) { @@ -631,11 +633,14 @@ std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const } std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) { - //std::string key = get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain)); - const auto& current_son = plugin.get_current_son_object(); FC_ASSERT(current_son.sidechain_public_keys.contains(sidechain_type::ethereum), "No public keys for current son: ${account_id}", ("account_id", current_son.son_account)); - return "0x" + current_son.sidechain_public_keys.at(sidechain); + + ethereum::transaction sign_transaction; + sign_transaction.deserialize(sto.transaction); + sign_transaction.to = wallet_contract_address; + sign_transaction.from = "0x" + current_son.sidechain_public_keys.at(sidechain); + return sign_transaction.sign(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))).serialize(); } void sidechain_net_handler_ethereum::schedule_ethereum_listener() { -- 2.45.2 From 46ac4d79a3eeac0a2253080cd64db054061ca16d Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Fri, 5 Aug 2022 11:29:21 +0300 Subject: [PATCH 44/60] withdraw transaction --- .../peerplays_sidechain/ethereum/encoders.cpp | 14 +- .../peerplays_sidechain/ethereum/encoders.hpp | 10 +- .../sidechain_net_handler_ethereum.hpp | 1 - .../sidechain_net_handler_ethereum.cpp | 137 +++++++----------- 4 files changed, 72 insertions(+), 90 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index 2b8984f6..e17bbdfb 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -6,7 +6,7 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { //! base_encoder -std::string base_encoder::encode_uint256(uint64_t value) +std::string base_encoder::encode_uint256(boost::multiprecision::uint256_t value) { return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str(); } @@ -41,5 +41,17 @@ std::string update_owners_encoder::encode(const std::vector #include +#include namespace graphene { namespace peerplays_sidechain { namespace ethereum { class base_encoder { public: - static std::string encode_uint256(uint64_t value); + static std::string encode_uint256(boost::multiprecision::uint256_t value); static std::string encode_address(const std::string& value); static std::string encode_string(const std::string& value); }; @@ -19,6 +20,13 @@ public: std::string encode(const std::vector>& owners_weights, const std::string& object_id) const; }; +class withdrawal_encoder { +public: + const std::string function_signature = "e088747b"; //! withdraw(address,uint256,string) + + std::string encode(const std::string& to, boost::multiprecision::uint256_t amount, const std::string& object_id) const; +}; + /*class ethereum_function_call_encoder { public: enum operation_t { 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 8606c095..af9812d0 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 @@ -25,7 +25,6 @@ public: std::string send_transaction(const std::string& params); std::string get_transaction_receipt(const std::string& params); - //std::string withdraw(); }; class sidechain_net_handler_ethereum : public sidechain_net_handler { diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 1553ef50..c01ab57d 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -62,11 +62,6 @@ std::string ethereum_rpc_client::get_transaction_receipt(const std::string& para return send_post_request("eth_getTransactionReceipt", "[\"" + params + "\"]", debug_rpc_calls); } -/*std::string ethereum_rpc_client::withdraw() { - const std::string params = "[ { \"from\": \"0x5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12\", \"to\": \"0x3E84f248Cd00A2FDaaDfa0dC5c3ff64D8767Fb01\", \"data\": \"0xe088747b00000000000000000000000009ee460834498a4ee361beb819470061b7381b490000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312e33362e330000000000000000000000000000000000000000000000000000\" } ]"; - return send_post_request("eth_sendTransaction", params, debug_rpc_calls); -}*/ - sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : sidechain_net_handler(_plugin, options) { sidechain = sidechain_type::ethereum; @@ -275,81 +270,48 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) const auto &idx = database.get_index_type().indices().get(); const auto swwo = idx.find(swwo_id); if (swwo != idx.end()) { + uint32_t swwo_block_num = swwo->block_num; + std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id; + uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1)); - //uint32_t swwo_block_num = swwo->block_num; - //std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id; - //uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1)); - // - //const auto &block = database.fetch_block_by_number(swwo_block_num); - // - //for (const auto &tx : block->transactions) { - // if (tx.id().str() == swwo_peerplays_transaction_id) { - // operation op = tx.operations[swwo_op_idx]; - // transfer_operation t_op = op.get(); - // - // price asset_price = database.get(t_op.amount.asset_id).options.core_exchange_rate; - // asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); - // - // process_ok = (t_op.to == gpo.parameters.son_account()) && - // (swwo->peerplays_from == t_op.from) && - // (swwo->peerplays_asset == peerplays_asset); - // break; - // } - //} - // - //object_id_type object_id = op_obj_idx_1.get().object_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); - //if (st == st_idx.end()) { - // - // std::string tx_str = ""; - // - // if (object_id.is()) { - // const auto &idx = database.get_index_type().indices().get(); - // const auto swwo = idx.find(object_id); - // if (swwo != idx.end()) { - // - // std::stringstream ss_trx(boost::algorithm::unhex(op_tx_str)); - // hive::signed_transaction op_trx; - // fc::raw::unpack(ss_trx, op_trx, 1000); - // - // uint64_t symbol = 0; - // if (swwo->withdraw_currency == "HBD") { - // symbol = hive::asset::hbd_symbol_ser; - // } - // if (swwo->withdraw_currency == "HIVE") { - // symbol = hive::asset::hive_symbol_ser; - // } - // - // hive::transfer_operation t_op; - // t_op.from = wallet_account_name; - // t_op.to = swwo->withdraw_address; - // t_op.amount.amount = swwo->withdraw_amount; - // t_op.amount.symbol = symbol; - // t_op.memo = ""; - // - // hive::signed_transaction htrx; - // htrx.ref_block_num = op_trx.ref_block_num; - // htrx.ref_block_prefix = op_trx.ref_block_prefix; - // htrx.set_expiration(op_trx.expiration); - // - // htrx.operations.push_back(t_op); - // - // std::stringstream ss; - // fc::raw::pack(ss, htrx, 1000); - // tx_str = boost::algorithm::hex(ss.str()); - // } - // } - // - // transaction_ok = (op_tx_str == tx_str); - //} + const auto &block = database.fetch_block_by_number(swwo_block_num); + + for (const auto &tx : block->transactions) { + if (tx.id().str() == swwo_peerplays_transaction_id) { + operation op = tx.operations[swwo_op_idx]; + transfer_operation t_op = op.get(); + + price asset_price = database.get(t_op.amount.asset_id).options.core_exchange_rate; + asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); + + process_ok = (t_op.to == gpo.parameters.son_account()) && + (swwo->peerplays_from == t_op.from) && + (swwo->peerplays_asset == peerplays_asset); + break; + } + } + + object_id_type object_id = op_obj_idx_1.get().object_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); + if (st == st_idx.end()) { + + std::string tx_str = ""; + + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swwo = idx.find(object_id); + if (swwo != idx.end()) { + tx_str = create_withdrawal_transaction(*swwo); + } + } + + transaction_ok = (op_tx_str == tx_str); + } } - process_ok = true; - transaction_ok = true; - should_approve = process_ok && transaction_ok; break; @@ -588,18 +550,17 @@ bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechai return false; } - for(const auto &entry_receipt : json_receipt.get_child("result.logs")) { - if( boost::algorithm::to_lower_copy(wallet_contract_address) == entry_receipt.second.get("address") ) { - count += 1; - //! Fixme - compare data somehow? - //if( sto.transaction == entry_receipt.second.get("data") ) { - //} - } + if( "0x1" == json_receipt.get("result.status") ) + { + count += 1; + //! Fixme - compare data somehow? + //if( sto.transaction == entry_receipt.second.get("data") ) { + //} } } //! Check that we have all transactions - if(count != json.count("result_array")) { + if(count != json.get_child("result_array").size()) { wlog("Not all receipts received for transaction ${id}", ("id", sto.id)); return false; } @@ -617,7 +578,6 @@ std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(co owners_weights.emplace_back(std::make_pair(pub_key_str, son.weight)); } - //! Create data of transaction ethereum::transaction transaction; ethereum::update_owners_encoder encoder; transaction.data = encoder.encode(owners_weights, object_id); @@ -629,7 +589,10 @@ std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son } std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { - return "Withdrawal-Transaction"; + ethereum::transaction transaction; + ethereum::withdrawal_encoder encoder; + transaction.data = encoder.encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value*10000000000, swwo.id.operator std::string()); + return transaction.serialize(); } std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) { -- 2.45.2 From 1c1ae8848852e50a6a46b030fd4b141330c93c11 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Tue, 16 Aug 2022 10:30:14 +0300 Subject: [PATCH 45/60] Delete submodule SHA3IUF --- .gitmodules | 4 ---- libraries/CMakeLists.txt | 1 - libraries/vendor/CMakeLists.txt | 26 -------------------------- libraries/vendor/SHA3IUF | 1 - 4 files changed, 32 deletions(-) delete mode 100755 libraries/vendor/CMakeLists.txt delete mode 160000 libraries/vendor/SHA3IUF diff --git a/.gitmodules b/.gitmodules index 8a25db68..d9c387a6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,7 +7,3 @@ url = https://gitlab.com/PBSA/tools-libs/peerplays-fc.git branch = develop ignore = dirty -[submodule "libraries/vendor/SHA3IUF"] - path = libraries/vendor/SHA3IUF - url = https://github.com/brainhub/SHA3IUF.git - branch = master diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index dfe3d397..cf2355f1 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,4 +1,3 @@ -add_subdirectory( vendor ) add_subdirectory( app ) add_subdirectory( chain ) add_subdirectory( db ) diff --git a/libraries/vendor/CMakeLists.txt b/libraries/vendor/CMakeLists.txt deleted file mode 100755 index 6047e95e..00000000 --- a/libraries/vendor/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -PROJECT( SHA3IUF ) - -include(ExternalProject) - -ExternalProject_Add(project_SHA3IUF - PREFIX ${CMAKE_CURRENT_BINARY_DIR} - SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF - CONFIGURE_COMMAND cp -R ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF/. ${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build - BUILD_COMMAND make - INSTALL_COMMAND true - BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX} - LOG_BUILD ON -) - -ExternalProject_Get_Property(project_SHA3IUF binary_dir) -add_library(SHA3IUF STATIC IMPORTED) -message(STATUS "Setting up SHA3IUF to ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX}") -set_property(TARGET SHA3IUF PROPERTY IMPORTED_LOCATION ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX}) -set_property(TARGET SHA3IUF PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF) - -add_dependencies(SHA3IUF project_SHA3IUF) -install( FILES ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION lib ) - -set(SHA3IUF_libraries sha3 CACHE INTERNAL "") -set(SHA3IUF_include_dirs "${CMAKE_CURRENT_LIST_DIR}/SHA3IUF" CACHE INTERNAL "") -set(SHA3IUF_link_dirs "${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build" CACHE INTERNAL "") diff --git a/libraries/vendor/SHA3IUF b/libraries/vendor/SHA3IUF deleted file mode 160000 index fc850475..00000000 --- a/libraries/vendor/SHA3IUF +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fc8504750a5c2174a1874094dd05e6a0d8797753 -- 2.45.2 From b24b204e79345a5ad29818ca9cffe7188e038f46 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Wed, 17 Aug 2022 07:48:59 +0300 Subject: [PATCH 46/60] Add sha3 library for keccak --- libraries/CMakeLists.txt | 1 + libraries/sha3/CMakeLists.txt | 17 ++ libraries/sha3/include/sha3/memzero.h | 16 ++ libraries/sha3/include/sha3/sha3.h | 88 ++++++ libraries/sha3/memzero.c | 75 +++++ libraries/sha3/sha3.c | 397 ++++++++++++++++++++++++++ 6 files changed, 594 insertions(+) create mode 100644 libraries/sha3/CMakeLists.txt create mode 100644 libraries/sha3/include/sha3/memzero.h create mode 100644 libraries/sha3/include/sha3/sha3.h create mode 100644 libraries/sha3/memzero.c create mode 100644 libraries/sha3/sha3.c diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index cf2355f1..f28a6cee 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory( egenesis ) add_subdirectory( fc ) add_subdirectory( net ) add_subdirectory( plugins ) +add_subdirectory( sha3 ) add_subdirectory( time ) add_subdirectory( utilities ) add_subdirectory( wallet ) diff --git a/libraries/sha3/CMakeLists.txt b/libraries/sha3/CMakeLists.txt new file mode 100644 index 00000000..a54cbba3 --- /dev/null +++ b/libraries/sha3/CMakeLists.txt @@ -0,0 +1,17 @@ +file(GLOB HEADERS "include/sha3/*.h") + +add_library( sha3 + memzero.c + sha3.c +) + +target_include_directories( sha3 PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include ) +target_compile_definitions( sha3 PUBLIC USE_KECCAK=1 ) + +install( TARGETS + sha3 + + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) diff --git a/libraries/sha3/include/sha3/memzero.h b/libraries/sha3/include/sha3/memzero.h new file mode 100644 index 00000000..1e744c12 --- /dev/null +++ b/libraries/sha3/include/sha3/memzero.h @@ -0,0 +1,16 @@ +#ifndef __MEMZERO_H__ +#define __MEMZERO_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif +void memzero(void* const pnt, const size_t len); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/libraries/sha3/include/sha3/sha3.h b/libraries/sha3/include/sha3/sha3.h new file mode 100644 index 00000000..881e806c --- /dev/null +++ b/libraries/sha3/include/sha3/sha3.h @@ -0,0 +1,88 @@ +/* sha3.h - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! + */ + +#ifndef __SHA3_H__ +#define __SHA3_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define sha3_224_hash_size 28 +#define sha3_256_hash_size 32 +#define sha3_384_hash_size 48 +#define sha3_512_hash_size 64 +#define sha3_max_permutation_size 25 +#define sha3_max_rate_in_qwords 24 + +#define SHA3_224_BLOCK_LENGTH 144 +#define SHA3_256_BLOCK_LENGTH 136 +#define SHA3_384_BLOCK_LENGTH 104 +#define SHA3_512_BLOCK_LENGTH 72 + +#define SHA3_224_DIGEST_LENGTH sha3_224_hash_size +#define SHA3_256_DIGEST_LENGTH sha3_256_hash_size +#define SHA3_384_DIGEST_LENGTH sha3_384_hash_size +#define SHA3_512_DIGEST_LENGTH sha3_512_hash_size + +/** + * SHA3 Algorithm context. + */ +typedef struct SHA3_CTX +{ + /* 1600 bits algorithm hashing state */ + uint64_t hash[sha3_max_permutation_size]; + /* 1536-bit buffer for leftovers */ + uint64_t message[sha3_max_rate_in_qwords]; + /* count of bytes in the message[] buffer */ + unsigned rest; + /* size of a message block processed at once */ + unsigned block_size; +} SHA3_CTX; + +/* methods for calculating the hash function */ + +void sha3_224_Init(SHA3_CTX *ctx); +void sha3_256_Init(SHA3_CTX *ctx); +void sha3_384_Init(SHA3_CTX *ctx); +void sha3_512_Init(SHA3_CTX *ctx); +void sha3_Update(SHA3_CTX *ctx, const unsigned char* msg, size_t size); +void sha3_Final(SHA3_CTX *ctx, unsigned char* result); + +#if USE_KECCAK +#define keccak_224_Init sha3_224_Init +#define keccak_256_Init sha3_256_Init +#define keccak_384_Init sha3_384_Init +#define keccak_512_Init sha3_512_Init +#define keccak_Update sha3_Update +void keccak_Final(SHA3_CTX *ctx, unsigned char* result); +void keccak_256(const unsigned char* data, size_t len, unsigned char* digest); +void keccak_512(const unsigned char* data, size_t len, unsigned char* digest); +#endif + +void sha3_256(const unsigned char* data, size_t len, unsigned char* digest); +void sha3_512(const unsigned char* data, size_t len, unsigned char* digest); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* __SHA3_H__ */ diff --git a/libraries/sha3/memzero.c b/libraries/sha3/memzero.c new file mode 100644 index 00000000..32aa140f --- /dev/null +++ b/libraries/sha3/memzero.c @@ -0,0 +1,75 @@ +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface. +#endif +#include + +#ifdef _WIN32 +#include +#endif + +#ifdef __unix__ +#include +#include +#endif + +// C11's bounds-checking interface. +#if defined(__STDC_LIB_EXT1__) +#define HAVE_MEMSET_S 1 +#endif + +// GNU C Library version 2.25 or later. +#if defined(__GLIBC__) && \ + (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// Newlib +#if defined(__NEWLIB__) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// FreeBSD version 11.0 or later. +#if defined(__FreeBSD__) && __FreeBSD_version >= 1100037 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// OpenBSD version 5.5 or later. +#if defined(__OpenBSD__) && OpenBSD >= 201405 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// NetBSD version 7.2 or later. +#if defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 +#define HAVE_EXPLICIT_MEMSET 1 +#endif + +// Adapted from +// https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 + +void memzero(void *const pnt, const size_t len) { +#ifdef _WIN32 + SecureZeroMemory(pnt, len); +#elif defined(HAVE_MEMSET_S) + memset_s(pnt, (rsize_t)len, 0, (rsize_t)len); +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(pnt, len); +#elif defined(HAVE_EXPLICIT_MEMSET) + explicit_memset(pnt, 0, len); +#else + volatile unsigned char *volatile pnt_ = (volatile unsigned char *volatile)pnt; + size_t i = (size_t)0U; + + while (i < len) { + pnt_[i++] = 0U; + } +#endif + + // explicitly mark the memory as overwritten for the Clang MemorySanitizer + // this is only included at compile time if MemorySanitizer is enabled and + // should not come with any downsides during regular builds +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) + memset(pnt, 0, len); +#endif +#endif +} diff --git a/libraries/sha3/sha3.c b/libraries/sha3/sha3.c new file mode 100644 index 00000000..172728eb --- /dev/null +++ b/libraries/sha3/sha3.c @@ -0,0 +1,397 @@ +/* sha3.c - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! + */ + +#include +#include + +#include +#include + +#define I64(x) x##LL +#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) +#define le2me_64(x) (x) +#define IS_ALIGNED_64(p) (0 == (7 & ((long)(p)))) // [wallet-core] pointer/numerical type, for MacOS SDK 12.3 +# define me64_to_le_str(to, from, length) memcpy((to), (from), (length)) + +/* constants */ +#define NumberOfRounds 24 + +/* SHA3 (Keccak) constants for 24 rounds */ +uint64_t keccak_round_constants[NumberOfRounds] = { + I64(0x0000000000000001), I64(0x0000000000008082), I64(0x800000000000808A), I64(0x8000000080008000), + I64(0x000000000000808B), I64(0x0000000080000001), I64(0x8000000080008081), I64(0x8000000000008009), + I64(0x000000000000008A), I64(0x0000000000000088), I64(0x0000000080008009), I64(0x000000008000000A), + I64(0x000000008000808B), I64(0x800000000000008B), I64(0x8000000000008089), I64(0x8000000000008003), + I64(0x8000000000008002), I64(0x8000000000000080), I64(0x000000000000800A), I64(0x800000008000000A), + I64(0x8000000080008081), I64(0x8000000000008080), I64(0x0000000080000001), I64(0x8000000080008008) +}; + +/* Initializing a sha3 context for given number of output bits */ +static void keccak_Init(SHA3_CTX *ctx, unsigned bits) +{ + /* NB: The Keccak capacity parameter = bits * 2 */ + unsigned rate = 1600 - bits * 2; + + memzero(ctx, sizeof(SHA3_CTX)); + ctx->block_size = rate / 8; + assert(rate <= 1600 && (rate % 64) == 0); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_224_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 224); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_256_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 256); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_384_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 384); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_512_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 512); +} + +/* Keccak theta() transformation */ +static void keccak_theta(uint64_t *A) +{ + unsigned int x = 0; + uint64_t C[5] = {0}, D[5] = {0}; + + for (x = 0; x < 5; x++) { + C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20]; + } + D[0] = ROTL64(C[1], 1) ^ C[4]; + D[1] = ROTL64(C[2], 1) ^ C[0]; + D[2] = ROTL64(C[3], 1) ^ C[1]; + D[3] = ROTL64(C[4], 1) ^ C[2]; + D[4] = ROTL64(C[0], 1) ^ C[3]; + + for (x = 0; x < 5; x++) { + A[x] ^= D[x]; + A[x + 5] ^= D[x]; + A[x + 10] ^= D[x]; + A[x + 15] ^= D[x]; + A[x + 20] ^= D[x]; + } +} + +/* Keccak pi() transformation */ +static void keccak_pi(uint64_t *A) +{ + uint64_t A1 = 0; + A1 = A[1]; + A[ 1] = A[ 6]; + A[ 6] = A[ 9]; + A[ 9] = A[22]; + A[22] = A[14]; + A[14] = A[20]; + A[20] = A[ 2]; + A[ 2] = A[12]; + A[12] = A[13]; + A[13] = A[19]; + A[19] = A[23]; + A[23] = A[15]; + A[15] = A[ 4]; + A[ 4] = A[24]; + A[24] = A[21]; + A[21] = A[ 8]; + A[ 8] = A[16]; + A[16] = A[ 5]; + A[ 5] = A[ 3]; + A[ 3] = A[18]; + A[18] = A[17]; + A[17] = A[11]; + A[11] = A[ 7]; + A[ 7] = A[10]; + A[10] = A1; + /* note: A[ 0] is left as is */ +} + +/* Keccak chi() transformation */ +static void keccak_chi(uint64_t *A) +{ + int i = 0; + for (i = 0; i < 25; i += 5) { + uint64_t A0 = A[0 + i], A1 = A[1 + i]; + A[0 + i] ^= ~A1 & A[2 + i]; + A[1 + i] ^= ~A[2 + i] & A[3 + i]; + A[2 + i] ^= ~A[3 + i] & A[4 + i]; + A[3 + i] ^= ~A[4 + i] & A0; + A[4 + i] ^= ~A0 & A1; + } +} + +static void sha3_permutation(uint64_t *state) +{ + int round = 0; + for (round = 0; round < NumberOfRounds; round++) + { + keccak_theta(state); + + /* apply Keccak rho() transformation */ + state[ 1] = ROTL64(state[ 1], 1); + state[ 2] = ROTL64(state[ 2], 62); + state[ 3] = ROTL64(state[ 3], 28); + state[ 4] = ROTL64(state[ 4], 27); + state[ 5] = ROTL64(state[ 5], 36); + state[ 6] = ROTL64(state[ 6], 44); + state[ 7] = ROTL64(state[ 7], 6); + state[ 8] = ROTL64(state[ 8], 55); + state[ 9] = ROTL64(state[ 9], 20); + state[10] = ROTL64(state[10], 3); + state[11] = ROTL64(state[11], 10); + state[12] = ROTL64(state[12], 43); + state[13] = ROTL64(state[13], 25); + state[14] = ROTL64(state[14], 39); + state[15] = ROTL64(state[15], 41); + state[16] = ROTL64(state[16], 45); + state[17] = ROTL64(state[17], 15); + state[18] = ROTL64(state[18], 21); + state[19] = ROTL64(state[19], 8); + state[20] = ROTL64(state[20], 18); + state[21] = ROTL64(state[21], 2); + state[22] = ROTL64(state[22], 61); + state[23] = ROTL64(state[23], 56); + state[24] = ROTL64(state[24], 14); + + keccak_pi(state); + keccak_chi(state); + + /* apply iota(state, round) */ + *state ^= keccak_round_constants[round]; + } +} + +/** + * The core transformation. Process the specified block of data. + * + * @param hash the algorithm state + * @param block the message block to process + * @param block_size the size of the processed block in bytes + */ +static void sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t block_size) +{ + /* expanded loop */ + hash[ 0] ^= le2me_64(block[ 0]); + hash[ 1] ^= le2me_64(block[ 1]); + hash[ 2] ^= le2me_64(block[ 2]); + hash[ 3] ^= le2me_64(block[ 3]); + hash[ 4] ^= le2me_64(block[ 4]); + hash[ 5] ^= le2me_64(block[ 5]); + hash[ 6] ^= le2me_64(block[ 6]); + hash[ 7] ^= le2me_64(block[ 7]); + hash[ 8] ^= le2me_64(block[ 8]); + /* if not sha3-512 */ + if (block_size > 72) { + hash[ 9] ^= le2me_64(block[ 9]); + hash[10] ^= le2me_64(block[10]); + hash[11] ^= le2me_64(block[11]); + hash[12] ^= le2me_64(block[12]); + /* if not sha3-384 */ + if (block_size > 104) { + hash[13] ^= le2me_64(block[13]); + hash[14] ^= le2me_64(block[14]); + hash[15] ^= le2me_64(block[15]); + hash[16] ^= le2me_64(block[16]); + /* if not sha3-256 */ + if (block_size > 136) { + hash[17] ^= le2me_64(block[17]); +#ifdef FULL_SHA3_FAMILY_SUPPORT + /* if not sha3-224 */ + if (block_size > 144) { + hash[18] ^= le2me_64(block[18]); + hash[19] ^= le2me_64(block[19]); + hash[20] ^= le2me_64(block[20]); + hash[21] ^= le2me_64(block[21]); + hash[22] ^= le2me_64(block[22]); + hash[23] ^= le2me_64(block[23]); + hash[24] ^= le2me_64(block[24]); + } +#endif + } + } + } + /* make a permutation of the hash */ + sha3_permutation(hash); +} + +#define SHA3_FINALIZED 0x80000000 + +/** + * Calculate message hash. + * Can be called repeatedly with chunks of the message to be hashed. + * + * @param ctx the algorithm context containing current hashing state + * @param msg message chunk + * @param size length of the message chunk + */ +void sha3_Update(SHA3_CTX *ctx, const unsigned char *msg, size_t size) +{ + size_t idx = (size_t)ctx->rest; + size_t block_size = (size_t)ctx->block_size; + + if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */ + ctx->rest = (unsigned)((ctx->rest + size) % block_size); + + /* fill partial block */ + if (idx) { + size_t left = block_size - idx; + memcpy((char*)ctx->message + idx, msg, (size < left ? size : left)); + if (size < left) return; + + /* process partial block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + msg += left; + size -= left; + } + while (size >= block_size) { + uint64_t *aligned_message_block = NULL; + if (IS_ALIGNED_64(msg)) { + /* the most common case is processing of an already aligned message + without copying it */ + aligned_message_block = (uint64_t*)(void*)msg; + } else { + memcpy(ctx->message, msg, block_size); + aligned_message_block = ctx->message; + } + + sha3_process_block(ctx->hash, aligned_message_block, block_size); + msg += block_size; + size -= block_size; + } + if (size) { + memcpy(ctx->message, msg, size); /* save leftovers */ + } +} + +/** + * Store calculated hash into the given array. + * + * @param ctx the algorithm context containing current hashing state + * @param result calculated hash in binary form + */ +void sha3_Final(SHA3_CTX *ctx, unsigned char* result) +{ + size_t digest_length = 100 - ctx->block_size / 2; + const size_t block_size = ctx->block_size; + + if (!(ctx->rest & SHA3_FINALIZED)) + { + /* clear the rest of the data queue */ + memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x06; + ((char*)ctx->message)[block_size - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ + } + + assert(block_size > digest_length); + if (result) me64_to_le_str(result, ctx->hash, digest_length); + memzero(ctx, sizeof(SHA3_CTX)); +} + +#if USE_KECCAK +/** +* Store calculated hash into the given array. +* +* @param ctx the algorithm context containing current hashing state +* @param result calculated hash in binary form +*/ +void keccak_Final(SHA3_CTX *ctx, unsigned char* result) +{ + size_t digest_length = 100 - ctx->block_size / 2; + const size_t block_size = ctx->block_size; + + if (!(ctx->rest & SHA3_FINALIZED)) + { + /* clear the rest of the data queue */ + memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x01; + ((char*)ctx->message)[block_size - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ + } + + assert(block_size > digest_length); + if (result) me64_to_le_str(result, ctx->hash, digest_length); + memzero(ctx, sizeof(SHA3_CTX)); +} + +void keccak_256(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + keccak_256_Init(&ctx); + keccak_Update(&ctx, data, len); + keccak_Final(&ctx, digest); +} + +void keccak_512(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + keccak_512_Init(&ctx); + keccak_Update(&ctx, data, len); + keccak_Final(&ctx, digest); +} +#endif /* USE_KECCAK */ + +void sha3_256(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + sha3_256_Init(&ctx); + sha3_Update(&ctx, data, len); + sha3_Final(&ctx, digest); +} + +void sha3_512(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + sha3_512_Init(&ctx); + sha3_Update(&ctx, data, len); + sha3_Final(&ctx, digest); +} -- 2.45.2 From e6d980d0924ddc3dab8e739f7311a85abd48eeb9 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Thu, 18 Aug 2022 14:54:44 +0300 Subject: [PATCH 47/60] 1) raw_transaction 2) signed_transaction 3) rlp_encoder classes --- .../peerplays_sidechain/CMakeLists.txt | 1 + .../peerplays_sidechain/ethereum/encoders.cpp | 95 ++++++++++++ .../ethereum/transaction.cpp | 146 +++++++++++++++++- .../peerplays_sidechain/ethereum/utils.cpp | 13 ++ .../peerplays_sidechain/ethereum/encoders.hpp | 15 ++ .../ethereum/transaction.hpp | 67 +++++--- .../peerplays_sidechain/ethereum/types.hpp | 2 + .../peerplays_sidechain/ethereum/utils.hpp | 9 ++ 8 files changed, 321 insertions(+), 27 deletions(-) create mode 100644 libraries/plugins/peerplays_sidechain/ethereum/utils.cpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index ca995c10..e3449d93 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -22,6 +22,7 @@ add_library( peerplays_sidechain ethereum/decoders.cpp ethereum/transaction.cpp ethereum/types.cpp + ethereum/utils.cpp hive/asset.cpp hive/operations.cpp hive/transaction.cpp diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index e17bbdfb..218f0be5 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -1,5 +1,6 @@ #include +#include #include #include @@ -54,4 +55,98 @@ std::string withdrawal_encoder::encode(const std::string& to, boost::multiprecis } +//! rlp_encoder +std::string rlp_encoder::encode(const std::string& s) +{ + return encode_rlp(hex2bytes(s)); +} + +std::string rlp_encoder::encode_length(int len, int offset) +{ + if(len<56) + { + std::string temp; + temp=(char)(len+offset); + return temp; + } + else + { + std::string hexLength = int2Hex(len); + int lLength = hexLength.size()/2; + std::string fByte = int2Hex(offset+55+lLength); + return hex2bytes(fByte+hexLength); + } +} + +std::string rlp_encoder::hex2bytes(const std::string& s) +{ + std::string dest; + dest.resize(s.size()/2); + hex2bin(s.c_str(), &dest[0]); + return dest; +} + +std::string rlp_encoder::bytes2hex(const std::string& s) +{ + std::string dest; + for( const auto& i : s ) + dest += uchar2Hex((unsigned char)i); + + return dest; +} + +std::string rlp_encoder::encode_rlp(const std::string& s) +{ + if(s.size()==1 && (unsigned char)s[0]<128) + return s; + else + return encode_length(s.size(), 128) + s; +} + +std::string rlp_encoder::int2Hex(int n) +{ + std::stringstream stream; + stream << std::hex << n; + std::string result( stream.str() ); + if(result.size() % 2) + result = "0"+result; + return result; +} + +std::string rlp_encoder::uchar2Hex(unsigned char n) +{ + std::string dest; + dest.resize(2); + sprintf(&dest[0], "%X", n); + + if(n < (unsigned char)16) + { + dest[1] = dest[0]; + dest[0] = '0'; + } + + return dest; +} + +int rlp_encoder::char2int(char input) +{ + if(input >= '0' && input <= '9') + return input - '0'; + if(input >= 'A' && input <= 'F') + return input - 'A' + 10; + if(input >= 'a' && input <= 'f') + return input - 'a' + 10; + + return -1; +} + +void rlp_encoder::hex2bin(const char* src, char* target) +{ + while(*src && src[1]) + { + *(target++) = char2int(*src)*16 + char2int(src[1]); + src += 2; + } +} + }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index f2d117b5..8d13a648 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -1,16 +1,61 @@ #include +#include #include #include +#include +#include + +#include +#include + +#include +#include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { -const transaction& transaction::sign(std::string private_key) const + +namespace +{ + +int is_even(char last_char) +{ + switch (last_char) + { + case '0': + return 1; + case '2': + return 1; + case '4': + return 1; + case '6': + return 1; + case '8': + return 1; + case 'A': + return 1; + case 'C': + return 1; + case 'E': + return 1; + default: + return -1; + } +} + +} + +const secp256k1_context *eth_context() { + static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); + return ctx; +} + +//! transaction + +const transaction& transaction::sign(const std::string& private_key) const { -/* v = "signed"; - r = "transaction"; - s = "signed-transaction"; - return v + "|" + r + "|" + s;*/ return *this; } @@ -26,7 +71,7 @@ std::string transaction::serialize() const return ss.str(); } -void transaction::deserialize(std::string raw_tx) +void transaction::deserialize(const std::string& raw_tx) { std::stringstream ss_tx(raw_tx); boost::property_tree::ptree tx_json; @@ -40,4 +85,93 @@ void transaction::deserialize(std::string raw_tx) data = tx_json.get("data"); } +//! raw_transaction + +signed_transaction raw_transaction::sign(const std::string& private_key) const +{ + //! Prepare signed transaction + signed_transaction tr; + tr.nonce = nonce; + tr.gas_price = gas_price; + tr.gas_limit = gas_limit; + tr.to = to; + tr.value = value; + tr.data = data; + + //! Calculate keccak hash of transaction + bytes hash; + hash.resize(32); + const auto transaction_string = boost::algorithm::unhex( serialize() ); + keccak_256((const unsigned char *) transaction_string.data(), transaction_string.size(), (unsigned char *) hash.data()); + + const bytes priv_key = parse_hex(private_key); + + secp256k1_ecdsa_signature sign; + FC_ASSERT(secp256k1_ecdsa_sign(eth_context(), &sign, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), secp256k1_nonce_function_rfc6979, nullptr)); + + fc::ecc::compact_signature result; + FC_ASSERT(secp256k1_ecdsa_signature_serialize_compact(eth_context(), (unsigned char*) result.begin() + 1, &sign)); + + bytes r; + for(int i = 1; i < 33; i++) + r.emplace_back((char) result.at(i)); + bytes s; + for(int i = 33; i < 65; i++) + s.emplace_back((char) result.at(i)); + + bytes v; + if(is_even(r.back())) + v = {37}; + else + v = {38}; + + tr.v = fc::to_hex((char *)&v[0], v.size()); + tr.r = fc::to_hex((char *)&r[0], r.size()); + tr.s = fc::to_hex((char *)&s[0], s.size()); + + return tr; +} + +std::string raw_transaction::serialize() const +{ + rlp_encoder encoder; + const std::string serialized = encoder.encode(nonce) + + encoder.encode(gas_price) + + encoder.encode(gas_limit) + + encoder.encode(to) + + encoder.encode(value) + + encoder.encode(data) + + encoder.encode(chain_id) + + encoder.encode("8") + + encoder.encode("0"); + + return encoder.bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ); +} + +void raw_transaction::deserialize(const std::string& raw_tx) +{ +} + +//! signed_transaction + +std::string signed_transaction::serialize() const +{ + rlp_encoder encoder; + const std::string serialized = encoder.encode(nonce) + + encoder.encode(gas_price) + + encoder.encode(gas_limit) + + encoder.encode(to) + + encoder.encode(value) + + encoder.encode(data) + + encoder.encode(v) + + encoder.encode(r) + + encoder.encode(s); + + return encoder.bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ); +} + +void signed_transaction::deserialize(const std::string& raw_tx) +{ +} + }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp b/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp new file mode 100644 index 00000000..9d6961bc --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp @@ -0,0 +1,13 @@ +#include + +#include + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +bytes parse_hex(const std::string &str) { + bytes vec(str.size() / 2); + fc::from_hex(str, vec.data(), vec.size()); + return vec; +} + +}}} // namespace graphene::peerplays_sidechain::ethereum 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 48330aa7..7fcb15ee 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 @@ -27,6 +27,21 @@ public: std::string encode(const std::string& to, boost::multiprecision::uint256_t amount, const std::string& object_id) const; }; +class rlp_encoder { +public: + static std::string encode(const std::string& s); + static std::string encode_length(int len, int offset); + static std::string hex2bytes(const std::string& s); + static std::string bytes2hex(const std::string& s); + +private: + static std::string encode_rlp(const std::string& s); + static std::string int2Hex(int n); + static std::string uchar2Hex(unsigned char n); + static int char2int(char input); + static void hex2bin(const char* src, char* target); +}; + /*class ethereum_function_call_encoder { public: enum operation_t { diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp index 7c65b7d2..50c3e2f7 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp @@ -6,33 +6,58 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { -class transaction { +class base_transaction +{ + virtual std::string serialize() const = 0; + virtual void deserialize(const std::string& raw_tx) = 0; +}; + +class transaction : base_transaction +{ public: - //std::string block_hash; - //std::string block_number; std::string from; - //std::string gas; - //std::string gas_price; - //std::string max_fee_per_gas; - //std::string max_priority_fee_per_gas; - //std::string hash; - //std::string input; - //std::string nonce; std::string to; std::string data; - //std::string transaction_index; - //std::string value; - //std::string type; - //std::vector access_list; - //std::string chain_id; - //std::string v; - //std::string r; - //std::string s; - const transaction& sign(std::string private_key) const; + const transaction& sign(const std::string& private_key) const; - std::string serialize() const; - void deserialize(std::string raw_tx); + virtual std::string serialize() const override; + virtual void deserialize(const std::string& raw_tx) override; +}; + +class signed_transaction; +class raw_transaction : base_transaction +{ +public: + std::string nonce; + std::string gas_price; + std::string gas_limit; + std::string to; + std::string value; + std::string data; + std::string chain_id; + + signed_transaction sign(const std::string& private_key) const; + + virtual std::string serialize() const override; + virtual void deserialize(const std::string& raw_tx) override; +}; + +class signed_transaction : base_transaction +{ +public: + std::string nonce; + std::string gas_price; + std::string gas_limit; + std::string to; + std::string value; + std::string data; + std::string v; + std::string r; + std::string s; + + virtual std::string serialize() const override; + virtual void deserialize(const std::string& raw_tx) override; }; }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp index def91947..963244fa 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp @@ -7,4 +7,6 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { typedef uint64_t chain_id_type; typedef uint64_t network_id_type; +using bytes = std::vector; + }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp new file mode 100644 index 00000000..1e2c8802 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +bytes parse_hex(const std::string &str); + +}}} // namespace graphene::peerplays_sidechain::ethereum -- 2.45.2 From e3098c3fb64700a0fe213b7c5ddef508b735f234 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Fri, 19 Aug 2022 17:34:57 +0300 Subject: [PATCH 48/60] rlp_decoder class --- .../peerplays_sidechain/ethereum/decoders.cpp | 236 ++++++++++++++++++ .../peerplays_sidechain/ethereum/encoders.cpp | 30 +-- .../ethereum/transaction.cpp | 33 ++- .../peerplays_sidechain/ethereum/utils.cpp | 24 ++ .../peerplays_sidechain/ethereum/decoders.hpp | 21 ++ .../peerplays_sidechain/ethereum/encoders.hpp | 2 - .../peerplays_sidechain/ethereum/utils.hpp | 4 + 7 files changed, 317 insertions(+), 33 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp index fcf468ce..cadb3f65 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp @@ -1,5 +1,241 @@ #include +#include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { +//! rlp_decoder + +namespace +{ +const signed char p_util_hexdigit[256] = + { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 }; +} + +std::vector rlp_decoder::decode(const std::string& str) +{ + size_t consumed = 0; + const auto raw_vec = parse_hex(str); + const std::vector rlp_array = decode_rlp(raw_vec.data(), raw_vec.size(), consumed); + std::vector result_array; + for(const auto& rlp : decode_rlp(raw_vec.data(), raw_vec.size(), consumed)) + { + result_array.emplace_back( bytes2hex( rlp ) ); + } + return result_array; +} + +std::vector rlp_decoder::decode_rlp(const unsigned char *raw, size_t len, size_t& consumed) +{ + std::vector rlp_result; + + consumed = 0; + + const unsigned char* end = raw + len; + const size_t prefixlen = 1; + unsigned char ch = *raw; + + if (len < 1) + { + return rlp_result; + } + + // Case 1: [prefix is 1-byte data buffer] + if (ch <= 0x7f) + { + const unsigned char *tok_start = raw; + const unsigned char *tok_end = tok_start + prefixlen; + FC_ASSERT(tok_end <= end); + + // parsing done; assign data buffer value. + const std::vector buf{tok_start, tok_end}; + rlp_result.emplace_back( buf.cbegin(), buf.cend() ); + + consumed = buf.size(); + } + // Case 2: [prefix, including buffer length][data] + else if ((ch >= 0x80) && (ch <= 0xb7)) + { + const size_t blen = ch - 0x80; + const size_t expected = prefixlen + blen; + + if (len < expected) + return std::vector{}; + + const unsigned char *tok_start = raw + 1; + const unsigned char *tok_end = tok_start + blen; + FC_ASSERT(tok_end <= end); + + // require minimal encoding + if ((blen == 1) && (tok_start[0] <= 0x7f)) + return std::vector{}; + + // parsing done; assign data buffer value. + const std::vector buf{tok_start, tok_end}; + rlp_result.emplace_back( buf.cbegin(), buf.cend() ); + + consumed = expected; + } + // Case 3: [prefix][buffer length][data] + else if ((ch >= 0xb8) && (ch <= 0xbf)) + { + const size_t uintlen = ch - 0xb7; + size_t expected = prefixlen + uintlen; + + if (len < expected) + return std::vector{}; + + FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen); + + const unsigned char *tok_start = raw + prefixlen; + if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes + return std::vector{}; + + // read buffer length + const uint64_t slen = to_int(tok_start, uintlen); + + // validate buffer length, including possible addition overflows. + expected = prefixlen + uintlen + slen; + if ((slen < (RLP_listStart - RLP_bufferLenStart - RLP_maxUintLen)) || (expected > len) || (slen > len)) + return std::vector{}; + + // parsing done; assign data buffer value. + tok_start = raw + prefixlen + uintlen; + const unsigned char *tok_end = tok_start + slen; + const std::vector buf{tok_start, tok_end}; + rlp_result.emplace_back( buf.cbegin(), buf.cend() ); + + consumed = expected; + } + // Case 4: [prefix][list] + else if ((ch >= 0xc0) && (ch <= 0xf7)) + { + const size_t payloadlen = ch - 0xc0; + const size_t expected = prefixlen + payloadlen; + + // read list payload + const auto array = decode_array(raw, len, 0, payloadlen); + rlp_result.insert(rlp_result.end(), array.cbegin(), array.cend()); + + consumed = expected; + } + // Case 5: [prefix][list length][list] + else + { + FC_ASSERT((ch >= 0xf8) && (ch <= 0xff)); + + const size_t uintlen = ch - 0xf7; + const size_t expected = prefixlen + uintlen; + + if (len < expected) + return std::vector{}; + + FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen); + + const unsigned char *tok_start = raw + prefixlen; + if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes + return std::vector{}; + + // read list length + const size_t payloadlen = to_int(tok_start, uintlen); + + // special requirement for non-immediate length + if (payloadlen < (0x100 - RLP_listStart - RLP_maxUintLen)) + return std::vector{}; + + // read list payload + const auto array = decode_array(raw, len, uintlen, payloadlen); + rlp_result.insert(rlp_result.end(), array.cbegin(), array.cend()); + + consumed = prefixlen + uintlen + payloadlen; + } + + return rlp_result; +} + +std::vector rlp_decoder::decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen) +{ + std::vector rlp_result; + const size_t prefixlen = 1; + + // validate list length, including possible addition overflows. + const size_t expected = prefixlen + uintlen + payloadlen; + if ((expected > len) || (payloadlen > len)) + return std::vector{}; + + size_t child_len = payloadlen; + const unsigned char *list_ent = raw + prefixlen + uintlen; + + // recursively read until payloadlen bytes parsed, or error + while (child_len > 0) + { + size_t child_consumed = 0; + + const auto val = decode_rlp(list_ent, child_len, child_consumed); + rlp_result.insert(rlp_result.end(), val.cbegin(), val.cend()); + + list_ent += child_consumed; + child_len -= child_consumed; + } + + return rlp_result; +} + +uint64_t rlp_decoder::to_int(const unsigned char *raw, size_t len) +{ + if (len == 0) + return 0; + else if (len == 1) + return *raw; + else + return (raw[len - 1]) + (to_int(raw, len - 1) * 256); +} + +std::vector rlp_decoder::parse_hex(const std::string& str) +{ + return parse_hex(str.c_str()); +} + +std::vector rlp_decoder::parse_hex(const char* psz) +{ + // convert hex dump to vector + std::vector vch; + while (true) + { + while (isspace(*psz)) + psz++; + signed char c = hex_digit(*psz++); + if (c == (signed char)-1) + break; + unsigned char n = (c << 4); + c = hex_digit(*psz++); + if (c == (signed char)-1) + break; + n |= c; + vch.push_back(n); + } + return vch; +} + +signed char rlp_decoder::hex_digit(char c) +{ + return p_util_hexdigit[(unsigned char)c]; +} + }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index 218f0be5..456a1be6 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -71,9 +71,9 @@ std::string rlp_encoder::encode_length(int len, int offset) } else { - std::string hexLength = int2Hex(len); - int lLength = hexLength.size()/2; - std::string fByte = int2Hex(offset+55+lLength); + const std::string hexLength = int2Hex(len); + const int lLength = hexLength.size()/2; + const std::string fByte = int2Hex(offset+55+lLength); return hex2bytes(fByte+hexLength); } } @@ -86,15 +86,6 @@ std::string rlp_encoder::hex2bytes(const std::string& s) return dest; } -std::string rlp_encoder::bytes2hex(const std::string& s) -{ - std::string dest; - for( const auto& i : s ) - dest += uchar2Hex((unsigned char)i); - - return dest; -} - std::string rlp_encoder::encode_rlp(const std::string& s) { if(s.size()==1 && (unsigned char)s[0]<128) @@ -113,21 +104,6 @@ std::string rlp_encoder::int2Hex(int n) return result; } -std::string rlp_encoder::uchar2Hex(unsigned char n) -{ - std::string dest; - dest.resize(2); - sprintf(&dest[0], "%X", n); - - if(n < (unsigned char)16) - { - dest[1] = dest[0]; - dest[0] = '0'; - } - - return dest; -} - int rlp_encoder::char2int(char input) { if(input >= '0' && input <= '9') diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index 8d13a648..5ca8c81d 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -142,14 +143,25 @@ std::string raw_transaction::serialize() const encoder.encode(value) + encoder.encode(data) + encoder.encode(chain_id) + - encoder.encode("8") + - encoder.encode("0"); + encoder.encode("") + + encoder.encode(""); - return encoder.bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ); + return bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ); } void raw_transaction::deserialize(const std::string& raw_tx) { + rlp_decoder decoder; + const auto rlp_array = decoder.decode(raw_tx); + FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format"); + + nonce = rlp_array.at(0); + gas_price = rlp_array.at(1); + gas_limit = rlp_array.at(2); + to = rlp_array.at(3); + value = rlp_array.at(4); + data = rlp_array.at(5); + chain_id = rlp_array.at(6); } //! signed_transaction @@ -167,11 +179,24 @@ std::string signed_transaction::serialize() const encoder.encode(r) + encoder.encode(s); - return encoder.bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ); + return bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ); } void signed_transaction::deserialize(const std::string& raw_tx) { + rlp_decoder decoder; + const auto rlp_array = decoder.decode(raw_tx); + FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format"); + + nonce = rlp_array.at(0); + gas_price = rlp_array.at(1); + gas_limit = rlp_array.at(2); + to = rlp_array.at(3); + value = rlp_array.at(4); + data = rlp_array.at(5); + v = rlp_array.at(6); + r = rlp_array.at(7); + s = rlp_array.at(8); } }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp b/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp index 9d6961bc..0bfe136a 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp @@ -10,4 +10,28 @@ bytes parse_hex(const std::string &str) { return vec; } +std::string bytes2hex(const std::string& s) +{ + std::string dest; + for( const auto& i : s ) + dest += uchar2Hex((unsigned char)i); + + return dest; +} + +std::string uchar2Hex(unsigned char n) +{ + std::string dest; + dest.resize(2); + sprintf(&dest[0], "%X", n); + + if(n < (unsigned char)16) + { + dest[1] = dest[0]; + dest[0] = '0'; + } + + return dest; +} + }}} // namespace graphene::peerplays_sidechain::ethereum 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 b9a7e927..0f30038f 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 @@ -5,4 +5,25 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { +class rlp_decoder { +private: + enum RLP_constants + { + RLP_maxUintLen = 8, + RLP_bufferLenStart = 0x80, + RLP_listStart = 0xc0, + }; + +public: + static std::vector decode(const std::string& str); + +private: + static std::vector decode_rlp(const unsigned char *raw, size_t len, size_t& consumed); + static std::vector decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen); + static uint64_t to_int(const unsigned char *raw, size_t len); + static std::vector parse_hex(const std::string& str); + static std::vector parse_hex(const char* psz); + static signed char hex_digit(char c); +}; + }}} // namespace graphene::peerplays_sidechain::ethereum 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 7fcb15ee..8c92b2fe 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 @@ -32,12 +32,10 @@ public: static std::string encode(const std::string& s); static std::string encode_length(int len, int offset); static std::string hex2bytes(const std::string& s); - static std::string bytes2hex(const std::string& s); private: static std::string encode_rlp(const std::string& s); static std::string int2Hex(int n); - static std::string uchar2Hex(unsigned char n); static int char2int(char input); static void hex2bin(const char* src, char* target); }; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp index 1e2c8802..4a2e33d1 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp @@ -6,4 +6,8 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { bytes parse_hex(const std::string &str); +std::string bytes2hex(const std::string& s); + +std::string uchar2Hex(unsigned char n); + }}} // namespace graphene::peerplays_sidechain::ethereum -- 2.45.2 From adc6743ef0e2379d3d244f7dd2bec9470ede13ff Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Mon, 22 Aug 2022 10:43:53 +0300 Subject: [PATCH 49/60] 1) get_nonce 2) get_gas_price 3) get_gas_limit --- .../sidechain_net_handler_ethereum.hpp | 9 +++- .../sidechain_net_handler_ethereum.cpp | 44 ++++++++++++++++--- 2 files changed, 45 insertions(+), 8 deletions(-) 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 af9812d0..d96d7bd9 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 @@ -19,12 +19,17 @@ public: std::string eth_get_block_by_number(std::string block_number, bool full_block); std::string eth_get_logs(std::string wallet_contract_address); std::string net_version(); + std::string eth_get_transaction_count(const std::string& params); + std::string eth_gas_price(); std::string get_chain_id(); std::string get_network_id(); + std::string get_nonce(const std::string& address); + std::string get_gas_price(); + std::string get_gas_limit(); - std::string send_transaction(const std::string& params); - std::string get_transaction_receipt(const std::string& params); + std::string eth_send_transaction(const std::string& params); + std::string eth_get_transaction_receipt(const std::string& params); }; class sidechain_net_handler_ethereum : public sidechain_net_handler { diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index c01ab57d..36dd2ad3 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -44,6 +44,14 @@ std::string ethereum_rpc_client::net_version() { return send_post_request("net_version", "", debug_rpc_calls); } +std::string ethereum_rpc_client::eth_get_transaction_count(const std::string& params) { + return send_post_request("eth_getTransactionCount", params, debug_rpc_calls); +} + +std::string ethereum_rpc_client::eth_gas_price() { + return send_post_request("eth_gasPrice", "", debug_rpc_calls); +} + std::string ethereum_rpc_client::get_chain_id() { std::string reply_str = net_version(); return retrieve_value_from_reply(reply_str, ""); @@ -54,11 +62,35 @@ std::string ethereum_rpc_client::get_network_id() { return retrieve_value_from_reply(reply_str, "protocols.eth.network"); } -std::string ethereum_rpc_client::send_transaction(const std::string& params) { +std::string ethereum_rpc_client::get_nonce(const std::string& address) { + std::string reply_str = eth_get_transaction_count("[\"" + address + "\", \"latest\"]"); + return retrieve_value_from_reply(reply_str, ""); +} + +std::string ethereum_rpc_client::get_gas_price() { + std::string reply_str = eth_gas_price(); + return retrieve_value_from_reply(reply_str, ""); +} + +std::string ethereum_rpc_client::get_gas_limit() { + std::string reply_str = eth_get_block_by_number("latest", false); + if (!reply_str.empty()) { + std::stringstream ss(reply_str); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + if (json.count("result")) { + std::string gas_limit_s = json.get("result.gasLimit"); + return gas_limit_s; + } + } + return std::string{}; +} + +std::string ethereum_rpc_client::eth_send_transaction(const std::string& params) { return send_post_request("eth_sendTransaction", "[" + params + "]", debug_rpc_calls); } -std::string ethereum_rpc_client::get_transaction_receipt(const std::string& params) { +std::string ethereum_rpc_client::eth_get_transaction_receipt(const std::string& params) { return send_post_request("eth_getTransactionReceipt", "[\"" + params + "\"]", debug_rpc_calls); } @@ -504,7 +536,7 @@ std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sid boost::property_tree::ptree pt_array; for(const auto& signature : sto.signatures) { const auto& transaction = signature.second; - const std::string sidechain_transaction = rpc_client->send_transaction(transaction); + const std::string sidechain_transaction = rpc_client->eth_send_transaction(transaction); std::stringstream ss_tx(sidechain_transaction); boost::property_tree::ptree tx_json; @@ -517,8 +549,8 @@ std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sid } else { //! Fixme - //! How should we proceed with error in send_transaction - elog("Error in send_transaction for transaction ${id}, transaction ${transaction}", ("id", sto.id) ("transaction", transaction)); + //! How should we proceed with error in eth_send_transaction + elog("Error in eth_send_transaction for transaction ${id}, transaction ${transaction}", ("id", sto.id) ("transaction", transaction)); } } pt.add_child("result_array", pt_array); @@ -539,7 +571,7 @@ bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechai size_t count = 0; for(const auto &entry : json.get_child("result_array")) { - const std::string receipt = rpc_client->get_transaction_receipt( entry.second.get("transaction_receipt") ); + const std::string receipt = rpc_client->eth_get_transaction_receipt( entry.second.get("transaction_receipt") ); std::stringstream ss_receipt(receipt); boost::property_tree::ptree json_receipt; -- 2.45.2 From 6c2bf868c50764b88b68045dd9392ebb570b218c Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Mon, 22 Aug 2022 16:02:58 +0300 Subject: [PATCH 50/60] Fix signing of eth transaction. Calculate `v` value --- .../peerplays_sidechain/ethereum/encoders.cpp | 16 +-- .../ethereum/transaction.cpp | 111 ++++++------------ .../peerplays_sidechain/ethereum/utils.cpp | 20 ++++ .../peerplays_sidechain/ethereum/encoders.hpp | 1 - .../peerplays_sidechain/ethereum/utils.hpp | 26 ++++ 5 files changed, 88 insertions(+), 86 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index 456a1be6..90b05fd2 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -4,6 +4,8 @@ #include #include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { //! base_encoder @@ -71,9 +73,9 @@ std::string rlp_encoder::encode_length(int len, int offset) } else { - const std::string hexLength = int2Hex(len); + const std::string hexLength = to_hex(len); const int lLength = hexLength.size()/2; - const std::string fByte = int2Hex(offset+55+lLength); + const std::string fByte = to_hex(offset+55+lLength); return hex2bytes(fByte+hexLength); } } @@ -94,16 +96,6 @@ std::string rlp_encoder::encode_rlp(const std::string& s) return encode_length(s.size(), 128) + s; } -std::string rlp_encoder::int2Hex(int n) -{ - std::stringstream stream; - stream << std::hex << n; - std::string result( stream.str() ); - if(result.size() % 2) - result = "0"+result; - return result; -} - int rlp_encoder::char2int(char input) { if(input >= '0' && input <= '9') diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index 5ca8c81d..268256ae 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include @@ -18,36 +18,6 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { -namespace -{ - -int is_even(char last_char) -{ - switch (last_char) - { - case '0': - return 1; - case '2': - return 1; - case '4': - return 1; - case '6': - return 1; - case '8': - return 1; - case 'A': - return 1; - case 'C': - return 1; - case 'E': - return 1; - default: - return -1; - } -} - -} - const secp256k1_context *eth_context() { static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); return ctx; @@ -107,12 +77,13 @@ signed_transaction raw_transaction::sign(const std::string& private_key) const const bytes priv_key = parse_hex(private_key); - secp256k1_ecdsa_signature sign; - FC_ASSERT(secp256k1_ecdsa_sign(eth_context(), &sign, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), secp256k1_nonce_function_rfc6979, nullptr)); - + int recid = 0; + secp256k1_ecdsa_recoverable_signature sig; + FC_ASSERT(secp256k1_ecdsa_sign_recoverable(eth_context(), &sig, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), NULL, NULL)); fc::ecc::compact_signature result; - FC_ASSERT(secp256k1_ecdsa_signature_serialize_compact(eth_context(), (unsigned char*) result.begin() + 1, &sign)); + FC_ASSERT(secp256k1_ecdsa_recoverable_signature_serialize_compact(eth_context(), (unsigned char *)result.begin() + 1, &recid, &sig)); + bytes v = bytes{char(recid + from_hex(chain_id) * 2 + 35)}; bytes r; for(int i = 1; i < 33; i++) r.emplace_back((char) result.at(i)); @@ -120,12 +91,6 @@ signed_transaction raw_transaction::sign(const std::string& private_key) const for(int i = 33; i < 65; i++) s.emplace_back((char) result.at(i)); - bytes v; - if(is_even(r.back())) - v = {37}; - else - v = {38}; - tr.v = fc::to_hex((char *)&v[0], v.size()); tr.r = fc::to_hex((char *)&r[0], r.size()); tr.s = fc::to_hex((char *)&s[0], s.size()); @@ -136,13 +101,13 @@ signed_transaction raw_transaction::sign(const std::string& private_key) const std::string raw_transaction::serialize() const { rlp_encoder encoder; - const std::string serialized = encoder.encode(nonce) + - encoder.encode(gas_price) + - encoder.encode(gas_limit) + - encoder.encode(to) + - encoder.encode(value) + - encoder.encode(data) + - encoder.encode(chain_id) + + const std::string serialized = encoder.encode(remove_0x(nonce)) + + encoder.encode(remove_0x(gas_price)) + + encoder.encode(remove_0x(gas_limit)) + + encoder.encode(remove_0x(to)) + + encoder.encode(remove_0x(value)) + + encoder.encode(remove_0x(data)) + + encoder.encode(remove_0x(chain_id)) + encoder.encode("") + encoder.encode(""); @@ -155,13 +120,13 @@ void raw_transaction::deserialize(const std::string& raw_tx) const auto rlp_array = decoder.decode(raw_tx); FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format"); - nonce = rlp_array.at(0); - gas_price = rlp_array.at(1); - gas_limit = rlp_array.at(2); - to = rlp_array.at(3); - value = rlp_array.at(4); - data = rlp_array.at(5); - chain_id = rlp_array.at(6); + nonce = add_0x(rlp_array.at(0)); + gas_price = add_0x(rlp_array.at(1)); + gas_limit = add_0x(rlp_array.at(2)); + to = add_0x(rlp_array.at(3)); + value = add_0x(rlp_array.at(4)); + data = add_0x(rlp_array.at(5)); + chain_id = add_0x(rlp_array.at(6)); } //! signed_transaction @@ -169,15 +134,15 @@ void raw_transaction::deserialize(const std::string& raw_tx) std::string signed_transaction::serialize() const { rlp_encoder encoder; - const std::string serialized = encoder.encode(nonce) + - encoder.encode(gas_price) + - encoder.encode(gas_limit) + - encoder.encode(to) + - encoder.encode(value) + - encoder.encode(data) + - encoder.encode(v) + - encoder.encode(r) + - encoder.encode(s); + const std::string serialized = encoder.encode(remove_0x(nonce)) + + encoder.encode(remove_0x(gas_price)) + + encoder.encode(remove_0x(gas_limit)) + + encoder.encode(remove_0x(to)) + + encoder.encode(remove_0x(value)) + + encoder.encode(remove_0x(data)) + + encoder.encode(remove_0x(v)) + + encoder.encode(remove_0x(r)) + + encoder.encode(remove_0x(s)); return bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ); } @@ -188,15 +153,15 @@ void signed_transaction::deserialize(const std::string& raw_tx) const auto rlp_array = decoder.decode(raw_tx); FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format"); - nonce = rlp_array.at(0); - gas_price = rlp_array.at(1); - gas_limit = rlp_array.at(2); - to = rlp_array.at(3); - value = rlp_array.at(4); - data = rlp_array.at(5); - v = rlp_array.at(6); - r = rlp_array.at(7); - s = rlp_array.at(8); + nonce = add_0x(rlp_array.at(0)); + gas_price = add_0x(rlp_array.at(1)); + gas_limit = add_0x(rlp_array.at(2)); + to = add_0x(rlp_array.at(3)); + value = add_0x(rlp_array.at(4)); + data = add_0x(rlp_array.at(5)); + v = add_0x(rlp_array.at(6)); + r = add_0x(rlp_array.at(7)); + s = add_0x(rlp_array.at(8)); } }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp b/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp index 0bfe136a..04861b88 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp @@ -34,4 +34,24 @@ std::string uchar2Hex(unsigned char n) return dest; } +std::string add_0x(const std::string& s) +{ + if(s.size() > 1) { + if (s.substr(0, 2) == "0x") + return s; + } + + return "0x" + s; +} + +std::string remove_0x(const std::string& s) +{ + if(s.size() > 1) { + if (s.substr(0, 2) == "0x") + return s.substr(2); + } + + return s; +} + }}} // namespace graphene::peerplays_sidechain::ethereum 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 8c92b2fe..d3652199 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 @@ -35,7 +35,6 @@ public: private: static std::string encode_rlp(const std::string& s); - static std::string int2Hex(int n); static int char2int(char input); static void hex2bin(const char* src, char* target); }; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp index 4a2e33d1..519ed4a1 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp @@ -10,4 +10,30 @@ std::string bytes2hex(const std::string& s); std::string uchar2Hex(unsigned char n); +std::string add_0x(const std::string& s); + +std::string remove_0x(const std::string& s); + +template +std::string to_hex( const T& val ) +{ + std::stringstream stream; + stream << std::hex << val; + std::string result( stream.str() ); + if(result.size() % 2) + result = "0"+result; + return result; +} + +template +T from_hex( const std::string& s ) +{ + T val; + std::stringstream stream; + stream << std::hex << s; + stream >> val; + + return val; +} + }}} // namespace graphene::peerplays_sidechain::ethereum -- 2.45.2 From 34df0c07549e6246146a8777526354b3ad2c754b Mon Sep 17 00:00:00 2001 From: serkixenos Date: Tue, 23 Aug 2022 02:59:03 +0200 Subject: [PATCH 51/60] Fix CI/CD build --- libraries/plugins/peerplays_sidechain/CMakeLists.txt | 8 +++----- libraries/sha3/CMakeLists.txt | 7 +++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index e3449d93..687532a1 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -42,11 +42,9 @@ endif() unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS) unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE) -target_link_directories( peerplays_sidechain PUBLIC ${SHA3IUF_link_dirs} ) -target_link_libraries( peerplays_sidechain PRIVATE graphene_plugin zmq ${SHA3IUF_libraries} ) -target_include_directories( peerplays_sidechain PUBLIC - "${CMAKE_CURRENT_SOURCE_DIR}/include" - "${SHA3IUF_include_dirs}" ) +target_link_libraries( peerplays_sidechain PRIVATE graphene_plugin sha3 zmq ) +target_include_directories( peerplays_sidechain + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) install( TARGETS peerplays_sidechain diff --git a/libraries/sha3/CMakeLists.txt b/libraries/sha3/CMakeLists.txt index a54cbba3..c790323e 100644 --- a/libraries/sha3/CMakeLists.txt +++ b/libraries/sha3/CMakeLists.txt @@ -1,16 +1,15 @@ file(GLOB HEADERS "include/sha3/*.h") add_library( sha3 - memzero.c - sha3.c + memzero.c + sha3.c ) target_include_directories( sha3 PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include ) target_compile_definitions( sha3 PUBLIC USE_KECCAK=1 ) install( TARGETS - sha3 - + sha3 RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib -- 2.45.2 From b43d5b4224dc8436537b9fb0e998e968a74941ab Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Wed, 24 Aug 2022 12:51:38 +0300 Subject: [PATCH 52/60] eth_send_raw_transaction + eth_send_transaction --- .../ethereum/transaction.cpp | 10 ++-- .../sidechain_net_handler_ethereum.hpp | 1 + .../sidechain_net_handler_ethereum.cpp | 47 ++++++++++++++----- 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index 268256ae..8a5f7fdf 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -72,7 +72,7 @@ signed_transaction raw_transaction::sign(const std::string& private_key) const //! Calculate keccak hash of transaction bytes hash; hash.resize(32); - const auto transaction_string = boost::algorithm::unhex( serialize() ); + const auto transaction_string = boost::algorithm::unhex( remove_0x( serialize() ) ); keccak_256((const unsigned char *) transaction_string.data(), transaction_string.size(), (unsigned char *) hash.data()); const bytes priv_key = parse_hex(private_key); @@ -111,13 +111,13 @@ std::string raw_transaction::serialize() const encoder.encode("") + encoder.encode(""); - return bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ); + return add_0x( bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ) ); } void raw_transaction::deserialize(const std::string& raw_tx) { rlp_decoder decoder; - const auto rlp_array = decoder.decode(raw_tx); + const auto rlp_array = decoder.decode(remove_0x(raw_tx)); FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format"); nonce = add_0x(rlp_array.at(0)); @@ -144,13 +144,13 @@ std::string signed_transaction::serialize() const encoder.encode(remove_0x(r)) + encoder.encode(remove_0x(s)); - return bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ); + return add_0x( bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ) ); } void signed_transaction::deserialize(const std::string& raw_tx) { rlp_decoder decoder; - const auto rlp_array = decoder.decode(raw_tx); + const auto rlp_array = decoder.decode(remove_0x(raw_tx)); FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format"); nonce = add_0x(rlp_array.at(0)); 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 d96d7bd9..68ba2c59 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 @@ -29,6 +29,7 @@ public: std::string get_gas_limit(); std::string eth_send_transaction(const std::string& params); + std::string eth_send_raw_transaction(const std::string& params); std::string eth_get_transaction_receipt(const std::string& params); }; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 36dd2ad3..86a162f4 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -18,6 +18,9 @@ #include #include #include +#include + +//#define SEND_RAW_TRANSACTION 1 namespace graphene { namespace peerplays_sidechain { @@ -90,6 +93,10 @@ std::string ethereum_rpc_client::eth_send_transaction(const std::string& params) return send_post_request("eth_sendTransaction", "[" + params + "]", debug_rpc_calls); } +std::string ethereum_rpc_client::eth_send_raw_transaction(const std::string& params) { + return send_post_request("eth_sendRawTransaction", "[ \"" + params + "\" ]", debug_rpc_calls); +} + std::string ethereum_rpc_client::eth_get_transaction_receipt(const std::string& params) { return send_post_request("eth_getTransactionReceipt", "[\"" + params + "\"]", debug_rpc_calls); } @@ -536,7 +543,11 @@ std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sid boost::property_tree::ptree pt_array; for(const auto& signature : sto.signatures) { const auto& transaction = signature.second; - const std::string sidechain_transaction = rpc_client->eth_send_transaction(transaction); + #ifdef SEND_RAW_TRANSACTION + const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(transaction); + #else + const std::string sidechain_transaction = rpc_client->eth_send_transaction(transaction); + #endif std::stringstream ss_tx(sidechain_transaction); boost::property_tree::ptree tx_json; @@ -610,10 +621,8 @@ std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(co owners_weights.emplace_back(std::make_pair(pub_key_str, son.weight)); } - ethereum::transaction transaction; ethereum::update_owners_encoder encoder; - transaction.data = encoder.encode(owners_weights, object_id); - return transaction.serialize(); + return encoder.encode(owners_weights, object_id); } std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) { @@ -621,21 +630,35 @@ std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son } std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { - ethereum::transaction transaction; ethereum::withdrawal_encoder encoder; - transaction.data = encoder.encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value*10000000000, swwo.id.operator std::string()); - return transaction.serialize(); + return encoder.encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value*10000000000, swwo.id.operator std::string()); } std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) { const auto& current_son = plugin.get_current_son_object(); FC_ASSERT(current_son.sidechain_public_keys.contains(sidechain_type::ethereum), "No public keys for current son: ${account_id}", ("account_id", current_son.son_account)); - ethereum::transaction sign_transaction; - sign_transaction.deserialize(sto.transaction); - sign_transaction.to = wallet_contract_address; - sign_transaction.from = "0x" + current_son.sidechain_public_keys.at(sidechain); - return sign_transaction.sign(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))).serialize(); + const auto& public_key = current_son.sidechain_public_keys.at(sidechain); + + #ifdef SEND_RAW_TRANSACTION + ethereum::raw_transaction raw_tr; + raw_tr.nonce = ethereum::to_hex( ethereum::from_hex( rpc_client->get_nonce( ethereum::add_0x(public_key) ) ) + 1 ); + raw_tr.gas_price = rpc_client->get_gas_price(); + raw_tr.gas_limit = rpc_client->get_gas_limit(); + raw_tr.to = wallet_contract_address; + raw_tr.value = ""; + raw_tr.data = sto.transaction; + raw_tr.chain_id = ethereum::add_0x(ethereum::to_hex(chain_id)); + + const auto sign_tr = raw_tr.sign(get_private_key(public_key)); + return sign_tr.serialize(); + #else + ethereum::transaction sign_transaction; + sign_transaction.data = sto.transaction; + sign_transaction.to = wallet_contract_address; + sign_transaction.from = "0x" + public_key; + return sign_transaction.sign(get_private_key(public_key)).serialize(); + #endif } void sidechain_net_handler_ethereum::schedule_ethereum_listener() { -- 2.45.2 From f780fa794f9231404a36f55347e168adb761d583 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Fri, 26 Aug 2022 10:57:18 +0300 Subject: [PATCH 53/60] Fix get_nonce --- .../peerplays_sidechain/sidechain_net_handler_ethereum.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 86a162f4..734a5fcd 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -20,7 +20,7 @@ #include #include -//#define SEND_RAW_TRANSACTION 1 +#define SEND_RAW_TRANSACTION 1 namespace graphene { namespace peerplays_sidechain { @@ -642,7 +642,7 @@ std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_tra #ifdef SEND_RAW_TRANSACTION ethereum::raw_transaction raw_tr; - raw_tr.nonce = ethereum::to_hex( ethereum::from_hex( rpc_client->get_nonce( ethereum::add_0x(public_key) ) ) + 1 ); + raw_tr.nonce = ethereum::add_0x( ethereum::to_hex( ethereum::from_hex( rpc_client->get_nonce( ethereum::add_0x(public_key) ) ) ) ); raw_tr.gas_price = rpc_client->get_gas_price(); raw_tr.gas_limit = rpc_client->get_gas_limit(); raw_tr.to = wallet_contract_address; -- 2.45.2 From ab7bb9e63305bba74d5c9ce5ffc1b3e878fd86e8 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Fri, 26 Aug 2022 11:09:55 +0300 Subject: [PATCH 54/60] clang-format --- .../peerplays_sidechain/ethereum/decoders.cpp | 97 ++++++++----------- .../peerplays_sidechain/ethereum/encoders.cpp | 74 ++++++-------- .../ethereum/transaction.cpp | 49 ++++------ .../peerplays_sidechain/ethereum/utils.cpp | 21 ++-- .../peerplays_sidechain/ethereum/decoders.hpp | 17 ++-- .../peerplays_sidechain/ethereum/encoders.hpp | 18 ++-- .../ethereum/transaction.hpp | 24 ++--- .../peerplays_sidechain/ethereum/utils.hpp | 22 ++--- .../sidechain_net_handler_ethereum.hpp | 12 +-- .../sidechain_net_handler_ethereum.cpp | 91 +++++++++-------- 10 files changed, 183 insertions(+), 242 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp index cadb3f65..02f334f5 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp @@ -7,71 +7,64 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { //! rlp_decoder -namespace -{ +namespace { const signed char p_util_hexdigit[256] = - { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, - -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 }; + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; } -std::vector rlp_decoder::decode(const std::string& str) -{ +std::vector rlp_decoder::decode(const std::string &str) { size_t consumed = 0; const auto raw_vec = parse_hex(str); const std::vector rlp_array = decode_rlp(raw_vec.data(), raw_vec.size(), consumed); std::vector result_array; - for(const auto& rlp : decode_rlp(raw_vec.data(), raw_vec.size(), consumed)) - { - result_array.emplace_back( bytes2hex( rlp ) ); + for (const auto &rlp : decode_rlp(raw_vec.data(), raw_vec.size(), consumed)) { + result_array.emplace_back(bytes2hex(rlp)); } return result_array; } -std::vector rlp_decoder::decode_rlp(const unsigned char *raw, size_t len, size_t& consumed) -{ +std::vector rlp_decoder::decode_rlp(const unsigned char *raw, size_t len, size_t &consumed) { std::vector rlp_result; consumed = 0; - const unsigned char* end = raw + len; + const unsigned char *end = raw + len; const size_t prefixlen = 1; unsigned char ch = *raw; - if (len < 1) - { + if (len < 1) { return rlp_result; } // Case 1: [prefix is 1-byte data buffer] - if (ch <= 0x7f) - { + if (ch <= 0x7f) { const unsigned char *tok_start = raw; const unsigned char *tok_end = tok_start + prefixlen; FC_ASSERT(tok_end <= end); // parsing done; assign data buffer value. const std::vector buf{tok_start, tok_end}; - rlp_result.emplace_back( buf.cbegin(), buf.cend() ); + rlp_result.emplace_back(buf.cbegin(), buf.cend()); consumed = buf.size(); } // Case 2: [prefix, including buffer length][data] - else if ((ch >= 0x80) && (ch <= 0xb7)) - { + else if ((ch >= 0x80) && (ch <= 0xb7)) { const size_t blen = ch - 0x80; const size_t expected = prefixlen + blen; @@ -88,13 +81,12 @@ std::vector rlp_decoder::decode_rlp(const unsigned char *raw, size_ // parsing done; assign data buffer value. const std::vector buf{tok_start, tok_end}; - rlp_result.emplace_back( buf.cbegin(), buf.cend() ); + rlp_result.emplace_back(buf.cbegin(), buf.cend()); consumed = expected; } // Case 3: [prefix][buffer length][data] - else if ((ch >= 0xb8) && (ch <= 0xbf)) - { + else if ((ch >= 0xb8) && (ch <= 0xbf)) { const size_t uintlen = ch - 0xb7; size_t expected = prefixlen + uintlen; @@ -104,7 +96,7 @@ std::vector rlp_decoder::decode_rlp(const unsigned char *raw, size_ FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen); const unsigned char *tok_start = raw + prefixlen; - if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes + if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes return std::vector{}; // read buffer length @@ -119,13 +111,12 @@ std::vector rlp_decoder::decode_rlp(const unsigned char *raw, size_ tok_start = raw + prefixlen + uintlen; const unsigned char *tok_end = tok_start + slen; const std::vector buf{tok_start, tok_end}; - rlp_result.emplace_back( buf.cbegin(), buf.cend() ); + rlp_result.emplace_back(buf.cbegin(), buf.cend()); consumed = expected; } // Case 4: [prefix][list] - else if ((ch >= 0xc0) && (ch <= 0xf7)) - { + else if ((ch >= 0xc0) && (ch <= 0xf7)) { const size_t payloadlen = ch - 0xc0; const size_t expected = prefixlen + payloadlen; @@ -136,8 +127,7 @@ std::vector rlp_decoder::decode_rlp(const unsigned char *raw, size_ consumed = expected; } // Case 5: [prefix][list length][list] - else - { + else { FC_ASSERT((ch >= 0xf8) && (ch <= 0xff)); const size_t uintlen = ch - 0xf7; @@ -149,7 +139,7 @@ std::vector rlp_decoder::decode_rlp(const unsigned char *raw, size_ FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen); const unsigned char *tok_start = raw + prefixlen; - if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes + if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes return std::vector{}; // read list length @@ -169,8 +159,7 @@ std::vector rlp_decoder::decode_rlp(const unsigned char *raw, size_ return rlp_result; } -std::vector rlp_decoder::decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen) -{ +std::vector rlp_decoder::decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen) { std::vector rlp_result; const size_t prefixlen = 1; @@ -183,8 +172,7 @@ std::vector rlp_decoder::decode_array(const unsigned char *raw, siz const unsigned char *list_ent = raw + prefixlen + uintlen; // recursively read until payloadlen bytes parsed, or error - while (child_len > 0) - { + while (child_len > 0) { size_t child_consumed = 0; const auto val = decode_rlp(list_ent, child_len, child_consumed); @@ -197,8 +185,7 @@ std::vector rlp_decoder::decode_array(const unsigned char *raw, siz return rlp_result; } -uint64_t rlp_decoder::to_int(const unsigned char *raw, size_t len) -{ +uint64_t rlp_decoder::to_int(const unsigned char *raw, size_t len) { if (len == 0) return 0; else if (len == 1) @@ -207,17 +194,14 @@ uint64_t rlp_decoder::to_int(const unsigned char *raw, size_t len) return (raw[len - 1]) + (to_int(raw, len - 1) * 256); } -std::vector rlp_decoder::parse_hex(const std::string& str) -{ +std::vector rlp_decoder::parse_hex(const std::string &str) { return parse_hex(str.c_str()); } -std::vector rlp_decoder::parse_hex(const char* psz) -{ +std::vector rlp_decoder::parse_hex(const char *psz) { // convert hex dump to vector std::vector vch; - while (true) - { + while (true) { while (isspace(*psz)) psz++; signed char c = hex_digit(*psz++); @@ -233,8 +217,7 @@ std::vector rlp_decoder::parse_hex(const char* psz) return vch; } -signed char rlp_decoder::hex_digit(char c) -{ +signed char rlp_decoder::hex_digit(char c) { return p_util_hexdigit[(unsigned char)c]; } diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index 90b05fd2..ad42088b 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -1,41 +1,35 @@ #include -#include #include #include +#include #include namespace graphene { namespace peerplays_sidechain { namespace ethereum { //! base_encoder -std::string base_encoder::encode_uint256(boost::multiprecision::uint256_t value) -{ +std::string base_encoder::encode_uint256(boost::multiprecision::uint256_t value) { return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str(); } -std::string base_encoder::encode_address(const std::string& value) -{ +std::string base_encoder::encode_address(const std::string &value) { return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str(); } -std::string base_encoder::encode_string(const std::string& value) -{ +std::string base_encoder::encode_string(const std::string &value) { std::string data = (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value.size())).str(); - data += boost::algorithm::hex(value) + std::string( (64 - value.size() * 2 % 64), '0' ); + data += boost::algorithm::hex(value) + std::string((64 - value.size() * 2 % 64), '0'); return data; } - //! update_owners_encoder -std::string update_owners_encoder::encode(const std::vector>& owners_weights, const std::string& object_id) const -{ +std::string update_owners_encoder::encode(const std::vector> &owners_weights, const std::string &object_id) const { std::string data = "0x" + function_signature; data += base_encoder::encode_uint256(64); data += base_encoder::encode_uint256((owners_weights.size() * 2 + 3) * 32); data += base_encoder::encode_uint256(owners_weights.size()); - for(const auto& owner : owners_weights) - { + for (const auto &owner : owners_weights) { data += base_encoder::encode_address(owner.first); data += base_encoder::encode_uint256(owner.second); } @@ -45,74 +39,62 @@ std::string update_owners_encoder::encode(const std::vector= '0' && input <= '9') +int rlp_encoder::char2int(char input) { + if (input >= '0' && input <= '9') return input - '0'; - if(input >= 'A' && input <= 'F') + if (input >= 'A' && input <= 'F') return input - 'A' + 10; - if(input >= 'a' && input <= 'f') + if (input >= 'a' && input <= 'f') return input - 'a' + 10; return -1; } -void rlp_encoder::hex2bin(const char* src, char* target) -{ - while(*src && src[1]) - { - *(target++) = char2int(*src)*16 + char2int(src[1]); +void rlp_encoder::hex2bin(const char *src, char *target) { + while (*src && src[1]) { + *(target++) = char2int(*src) * 16 + char2int(src[1]); src += 2; } } diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index 8a5f7fdf..668e9639 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -10,14 +10,13 @@ #include #include -#include #include +#include #include #include namespace graphene { namespace peerplays_sidechain { namespace ethereum { - const secp256k1_context *eth_context() { static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); return ctx; @@ -25,13 +24,11 @@ const secp256k1_context *eth_context() { //! transaction -const transaction& transaction::sign(const std::string& private_key) const -{ +const transaction &transaction::sign(const std::string &private_key) const { return *this; } -std::string transaction::serialize() const -{ +std::string transaction::serialize() const { boost::property_tree::ptree pt; pt.put("from", from); pt.put("to", to); @@ -42,24 +39,22 @@ std::string transaction::serialize() const return ss.str(); } -void transaction::deserialize(const std::string& raw_tx) -{ +void transaction::deserialize(const std::string &raw_tx) { std::stringstream ss_tx(raw_tx); boost::property_tree::ptree tx_json; boost::property_tree::read_json(ss_tx, tx_json); - if(tx_json.count("from")) + if (tx_json.count("from")) from = tx_json.get("from"); - if(tx_json.count("to")) + if (tx_json.count("to")) to = tx_json.get("to"); - if(tx_json.count("data")) + if (tx_json.count("data")) data = tx_json.get("data"); } //! raw_transaction -signed_transaction raw_transaction::sign(const std::string& private_key) const -{ +signed_transaction raw_transaction::sign(const std::string &private_key) const { //! Prepare signed transaction signed_transaction tr; tr.nonce = nonce; @@ -72,8 +67,8 @@ signed_transaction raw_transaction::sign(const std::string& private_key) const //! Calculate keccak hash of transaction bytes hash; hash.resize(32); - const auto transaction_string = boost::algorithm::unhex( remove_0x( serialize() ) ); - keccak_256((const unsigned char *) transaction_string.data(), transaction_string.size(), (unsigned char *) hash.data()); + const auto transaction_string = boost::algorithm::unhex(remove_0x(serialize())); + keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data()); const bytes priv_key = parse_hex(private_key); @@ -85,11 +80,11 @@ signed_transaction raw_transaction::sign(const std::string& private_key) const bytes v = bytes{char(recid + from_hex(chain_id) * 2 + 35)}; bytes r; - for(int i = 1; i < 33; i++) - r.emplace_back((char) result.at(i)); + for (int i = 1; i < 33; i++) + r.emplace_back((char)result.at(i)); bytes s; - for(int i = 33; i < 65; i++) - s.emplace_back((char) result.at(i)); + for (int i = 33; i < 65; i++) + s.emplace_back((char)result.at(i)); tr.v = fc::to_hex((char *)&v[0], v.size()); tr.r = fc::to_hex((char *)&r[0], r.size()); @@ -98,8 +93,7 @@ signed_transaction raw_transaction::sign(const std::string& private_key) const return tr; } -std::string raw_transaction::serialize() const -{ +std::string raw_transaction::serialize() const { rlp_encoder encoder; const std::string serialized = encoder.encode(remove_0x(nonce)) + encoder.encode(remove_0x(gas_price)) + @@ -111,11 +105,10 @@ std::string raw_transaction::serialize() const encoder.encode("") + encoder.encode(""); - return add_0x( bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ) ); + return add_0x(bytes2hex(encoder.encode_length(serialized.size(), 192) + serialized)); } -void raw_transaction::deserialize(const std::string& raw_tx) -{ +void raw_transaction::deserialize(const std::string &raw_tx) { rlp_decoder decoder; const auto rlp_array = decoder.decode(remove_0x(raw_tx)); FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format"); @@ -131,8 +124,7 @@ void raw_transaction::deserialize(const std::string& raw_tx) //! signed_transaction -std::string signed_transaction::serialize() const -{ +std::string signed_transaction::serialize() const { rlp_encoder encoder; const std::string serialized = encoder.encode(remove_0x(nonce)) + encoder.encode(remove_0x(gas_price)) + @@ -144,11 +136,10 @@ std::string signed_transaction::serialize() const encoder.encode(remove_0x(r)) + encoder.encode(remove_0x(s)); - return add_0x( bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized ) ); + return add_0x(bytes2hex(encoder.encode_length(serialized.size(), 192) + serialized)); } -void signed_transaction::deserialize(const std::string& raw_tx) -{ +void signed_transaction::deserialize(const std::string &raw_tx) { rlp_decoder decoder; const auto rlp_array = decoder.decode(remove_0x(raw_tx)); FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format"); diff --git a/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp b/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp index 04861b88..ce64e1ae 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp @@ -10,23 +10,20 @@ bytes parse_hex(const std::string &str) { return vec; } -std::string bytes2hex(const std::string& s) -{ +std::string bytes2hex(const std::string &s) { std::string dest; - for( const auto& i : s ) + for (const auto &i : s) dest += uchar2Hex((unsigned char)i); return dest; } -std::string uchar2Hex(unsigned char n) -{ +std::string uchar2Hex(unsigned char n) { std::string dest; dest.resize(2); sprintf(&dest[0], "%X", n); - if(n < (unsigned char)16) - { + if (n < (unsigned char)16) { dest[1] = dest[0]; dest[0] = '0'; } @@ -34,9 +31,8 @@ std::string uchar2Hex(unsigned char n) return dest; } -std::string add_0x(const std::string& s) -{ - if(s.size() > 1) { +std::string add_0x(const std::string &s) { + if (s.size() > 1) { if (s.substr(0, 2) == "0x") return s; } @@ -44,9 +40,8 @@ std::string add_0x(const std::string& s) return "0x" + s; } -std::string remove_0x(const std::string& s) -{ - if(s.size() > 1) { +std::string remove_0x(const std::string &s) { + if (s.size() > 1) { if (s.substr(0, 2) == "0x") return s.substr(2); } 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 0f30038f..9edb6ae3 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 @@ -7,22 +7,21 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { class rlp_decoder { private: - enum RLP_constants - { - RLP_maxUintLen = 8, - RLP_bufferLenStart = 0x80, - RLP_listStart = 0xc0, + enum RLP_constants { + RLP_maxUintLen = 8, + RLP_bufferLenStart = 0x80, + RLP_listStart = 0xc0, }; public: - static std::vector decode(const std::string& str); + static std::vector decode(const std::string &str); private: - static std::vector decode_rlp(const unsigned char *raw, size_t len, size_t& consumed); + static std::vector decode_rlp(const unsigned char *raw, size_t len, size_t &consumed); static std::vector decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen); static uint64_t to_int(const unsigned char *raw, size_t len); - static std::vector parse_hex(const std::string& str); - static std::vector parse_hex(const char* psz); + static std::vector parse_hex(const std::string &str); + static std::vector parse_hex(const char *psz); static signed char hex_digit(char c); }; 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 d3652199..1ff97978 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 @@ -1,42 +1,42 @@ #pragma once +#include #include #include -#include namespace graphene { namespace peerplays_sidechain { namespace ethereum { class base_encoder { public: static std::string encode_uint256(boost::multiprecision::uint256_t value); - static std::string encode_address(const std::string& value); - static std::string encode_string(const std::string& value); + static std::string encode_address(const std::string &value); + static std::string encode_string(const std::string &value); }; class update_owners_encoder { public: const std::string function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string) - std::string encode(const std::vector>& owners_weights, const std::string& object_id) const; + std::string encode(const std::vector> &owners_weights, const std::string &object_id) const; }; class withdrawal_encoder { public: const std::string function_signature = "e088747b"; //! withdraw(address,uint256,string) - std::string encode(const std::string& to, boost::multiprecision::uint256_t amount, const std::string& object_id) const; + std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) const; }; class rlp_encoder { public: - static std::string encode(const std::string& s); + static std::string encode(const std::string &s); static std::string encode_length(int len, int offset); - static std::string hex2bytes(const std::string& s); + static std::string hex2bytes(const std::string &s); private: - static std::string encode_rlp(const std::string& s); + static std::string encode_rlp(const std::string &s); static int char2int(char input); - static void hex2bin(const char* src, char* target); + static void hex2bin(const char *src, char *target); }; /*class ethereum_function_call_encoder { diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp index 50c3e2f7..c112206b 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp @@ -6,28 +6,25 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { -class base_transaction -{ +class base_transaction { virtual std::string serialize() const = 0; - virtual void deserialize(const std::string& raw_tx) = 0; + virtual void deserialize(const std::string &raw_tx) = 0; }; -class transaction : base_transaction -{ +class transaction : base_transaction { public: std::string from; std::string to; std::string data; - const transaction& sign(const std::string& private_key) const; + const transaction &sign(const std::string &private_key) const; virtual std::string serialize() const override; - virtual void deserialize(const std::string& raw_tx) override; + virtual void deserialize(const std::string &raw_tx) override; }; class signed_transaction; -class raw_transaction : base_transaction -{ +class raw_transaction : base_transaction { public: std::string nonce; std::string gas_price; @@ -37,14 +34,13 @@ public: std::string data; std::string chain_id; - signed_transaction sign(const std::string& private_key) const; + signed_transaction sign(const std::string &private_key) const; virtual std::string serialize() const override; - virtual void deserialize(const std::string& raw_tx) override; + virtual void deserialize(const std::string &raw_tx) override; }; -class signed_transaction : base_transaction -{ +class signed_transaction : base_transaction { public: std::string nonce; std::string gas_price; @@ -57,7 +53,7 @@ public: std::string s; virtual std::string serialize() const override; - virtual void deserialize(const std::string& raw_tx) override; + virtual void deserialize(const std::string &raw_tx) override; }; }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp index 519ed4a1..b4461713 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp @@ -6,28 +6,26 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { bytes parse_hex(const std::string &str); -std::string bytes2hex(const std::string& s); +std::string bytes2hex(const std::string &s); std::string uchar2Hex(unsigned char n); -std::string add_0x(const std::string& s); +std::string add_0x(const std::string &s); -std::string remove_0x(const std::string& s); +std::string remove_0x(const std::string &s); -template -std::string to_hex( const T& val ) -{ +template +std::string to_hex(const T &val) { std::stringstream stream; stream << std::hex << val; - std::string result( stream.str() ); - if(result.size() % 2) - result = "0"+result; + std::string result(stream.str()); + if (result.size() % 2) + result = "0" + result; return result; } -template -T from_hex( const std::string& s ) -{ +template +T from_hex(const std::string &s) { T val; std::stringstream stream; stream << std::hex << s; 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 68ba2c59..3944d0a2 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 @@ -19,18 +19,18 @@ public: std::string eth_get_block_by_number(std::string block_number, bool full_block); std::string eth_get_logs(std::string wallet_contract_address); std::string net_version(); - std::string eth_get_transaction_count(const std::string& params); + std::string eth_get_transaction_count(const std::string ¶ms); std::string eth_gas_price(); std::string get_chain_id(); std::string get_network_id(); - std::string get_nonce(const std::string& address); + std::string get_nonce(const std::string &address); std::string get_gas_price(); std::string get_gas_limit(); - std::string eth_send_transaction(const std::string& params); - std::string eth_send_raw_transaction(const std::string& params); - std::string eth_get_transaction_receipt(const std::string& params); + std::string eth_send_transaction(const std::string ¶ms); + std::string eth_send_raw_transaction(const std::string ¶ms); + std::string eth_get_transaction_receipt(const std::string ¶ms); }; class sidechain_net_handler_ethereum : public sidechain_net_handler { @@ -58,7 +58,7 @@ 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); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 734a5fcd..163f2599 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -47,7 +47,7 @@ std::string ethereum_rpc_client::net_version() { return send_post_request("net_version", "", debug_rpc_calls); } -std::string ethereum_rpc_client::eth_get_transaction_count(const std::string& params) { +std::string ethereum_rpc_client::eth_get_transaction_count(const std::string ¶ms) { return send_post_request("eth_getTransactionCount", params, debug_rpc_calls); } @@ -65,7 +65,7 @@ std::string ethereum_rpc_client::get_network_id() { return retrieve_value_from_reply(reply_str, "protocols.eth.network"); } -std::string ethereum_rpc_client::get_nonce(const std::string& address) { +std::string ethereum_rpc_client::get_nonce(const std::string &address) { std::string reply_str = eth_get_transaction_count("[\"" + address + "\", \"latest\"]"); return retrieve_value_from_reply(reply_str, ""); } @@ -89,15 +89,15 @@ std::string ethereum_rpc_client::get_gas_limit() { return std::string{}; } -std::string ethereum_rpc_client::eth_send_transaction(const std::string& params) { +std::string ethereum_rpc_client::eth_send_transaction(const std::string ¶ms) { return send_post_request("eth_sendTransaction", "[" + params + "]", debug_rpc_calls); } -std::string ethereum_rpc_client::eth_send_raw_transaction(const std::string& params) { +std::string ethereum_rpc_client::eth_send_raw_transaction(const std::string ¶ms) { return send_post_request("eth_sendRawTransaction", "[ \"" + params + "\" ]", debug_rpc_calls); } -std::string ethereum_rpc_client::eth_get_transaction_receipt(const std::string& params) { +std::string ethereum_rpc_client::eth_get_transaction_receipt(const std::string ¶ms) { return send_post_request("eth_getTransactionReceipt", "[\"" + params + "\"]", debug_rpc_calls); } @@ -541,27 +541,26 @@ std::string sidechain_net_handler_ethereum::process_sidechain_transaction(const std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sidechain_transaction_object &sto) { boost::property_tree::ptree pt; boost::property_tree::ptree pt_array; - for(const auto& signature : sto.signatures) { - const auto& transaction = signature.second; - #ifdef SEND_RAW_TRANSACTION - const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(transaction); - #else - const std::string sidechain_transaction = rpc_client->eth_send_transaction(transaction); - #endif + for (const auto &signature : sto.signatures) { + const auto &transaction = signature.second; +#ifdef SEND_RAW_TRANSACTION + const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(transaction); +#else + const std::string sidechain_transaction = rpc_client->eth_send_transaction(transaction); +#endif std::stringstream ss_tx(sidechain_transaction); boost::property_tree::ptree tx_json; boost::property_tree::read_json(ss_tx, tx_json); - if( tx_json.count("result") && !tx_json.count("error") ) { + if (tx_json.count("result") && !tx_json.count("error")) { boost::property_tree::ptree node; node.put("transaction", transaction); node.put("transaction_receipt", tx_json.get("result")); pt_array.push_back(std::make_pair("", node)); - } - else { + } else { //! Fixme //! How should we proceed with error in eth_send_transaction - elog("Error in eth_send_transaction for transaction ${id}, transaction ${transaction}", ("id", sto.id) ("transaction", transaction)); + elog("Error in eth_send_transaction for transaction ${id}, transaction ${transaction}", ("id", sto.id)("transaction", transaction)); } } pt.add_child("result_array", pt_array); @@ -576,25 +575,24 @@ bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechai boost::property_tree::ptree json; boost::property_tree::read_json(ss, json); - if( !json.count("result_array") ) { + if (!json.count("result_array")) { return false; } size_t count = 0; - for(const auto &entry : json.get_child("result_array")) { - const std::string receipt = rpc_client->eth_get_transaction_receipt( entry.second.get("transaction_receipt") ); + for (const auto &entry : json.get_child("result_array")) { + const std::string receipt = rpc_client->eth_get_transaction_receipt(entry.second.get("transaction_receipt")); std::stringstream ss_receipt(receipt); boost::property_tree::ptree json_receipt; boost::property_tree::read_json(ss_receipt, json_receipt); - if( json_receipt.get("result") == "null" ) { + if (json_receipt.get("result") == "null") { wlog("Block is not minted yet for transaction ${id}", ("id", sto.id)); return false; } - if( "0x1" == json_receipt.get("result.status") ) - { + if ("0x1" == json_receipt.get("result.status")) { count += 1; //! Fixme - compare data somehow? //if( sto.transaction == entry_receipt.second.get("data") ) { @@ -603,17 +601,16 @@ bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechai } //! Check that we have all transactions - if(count != json.get_child("result_array").size()) { + if (count != json.get_child("result_array").size()) { wlog("Not all receipts received for transaction ${id}", ("id", sto.id)); return false; - } - else + } else return true; return false; } -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) { FC_ASSERT(son.sidechain_public_keys.contains(sidechain_type::ethereum), "No public keys for son: ${son_id}", ("son_id", son.son_id)); @@ -631,34 +628,34 @@ std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { ethereum::withdrawal_encoder encoder; - return encoder.encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value*10000000000, swwo.id.operator std::string()); + return encoder.encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string()); } std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) { - const auto& current_son = plugin.get_current_son_object(); + const auto ¤t_son = plugin.get_current_son_object(); FC_ASSERT(current_son.sidechain_public_keys.contains(sidechain_type::ethereum), "No public keys for current son: ${account_id}", ("account_id", current_son.son_account)); - const auto& public_key = current_son.sidechain_public_keys.at(sidechain); + const auto &public_key = current_son.sidechain_public_keys.at(sidechain); - #ifdef SEND_RAW_TRANSACTION - ethereum::raw_transaction raw_tr; - raw_tr.nonce = ethereum::add_0x( ethereum::to_hex( ethereum::from_hex( rpc_client->get_nonce( ethereum::add_0x(public_key) ) ) ) ); - raw_tr.gas_price = rpc_client->get_gas_price(); - raw_tr.gas_limit = rpc_client->get_gas_limit(); - raw_tr.to = wallet_contract_address; - raw_tr.value = ""; - raw_tr.data = sto.transaction; - raw_tr.chain_id = ethereum::add_0x(ethereum::to_hex(chain_id)); +#ifdef SEND_RAW_TRANSACTION + ethereum::raw_transaction raw_tr; + raw_tr.nonce = ethereum::add_0x(ethereum::to_hex(ethereum::from_hex(rpc_client->get_nonce(ethereum::add_0x(public_key))))); + raw_tr.gas_price = rpc_client->get_gas_price(); + raw_tr.gas_limit = rpc_client->get_gas_limit(); + raw_tr.to = wallet_contract_address; + raw_tr.value = ""; + raw_tr.data = sto.transaction; + raw_tr.chain_id = ethereum::add_0x(ethereum::to_hex(chain_id)); - const auto sign_tr = raw_tr.sign(get_private_key(public_key)); - return sign_tr.serialize(); - #else - ethereum::transaction sign_transaction; - sign_transaction.data = sto.transaction; - sign_transaction.to = wallet_contract_address; - sign_transaction.from = "0x" + public_key; - return sign_transaction.sign(get_private_key(public_key)).serialize(); - #endif + const auto sign_tr = raw_tr.sign(get_private_key(public_key)); + return sign_tr.serialize(); +#else + ethereum::transaction sign_transaction; + sign_transaction.data = sto.transaction; + sign_transaction.to = wallet_contract_address; + sign_transaction.from = "0x" + public_key; + return sign_transaction.sign(get_private_key(public_key)).serialize(); +#endif } void sidechain_net_handler_ethereum::schedule_ethereum_listener() { -- 2.45.2 From fbe263e2cb294816773d7a4fa155e0484e80c2b1 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Mon, 29 Aug 2022 13:52:37 +0300 Subject: [PATCH 55/60] Fix for nonce = 0 --- .../peerplays_sidechain/sidechain_net_handler_ethereum.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 163f2599..8ceb582b 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -67,7 +67,8 @@ std::string ethereum_rpc_client::get_network_id() { std::string ethereum_rpc_client::get_nonce(const std::string &address) { std::string reply_str = eth_get_transaction_count("[\"" + address + "\", \"latest\"]"); - return retrieve_value_from_reply(reply_str, ""); + const auto nonce_val = ethereum::from_hex(retrieve_value_from_reply(reply_str, "")); + return nonce_val == 0 ? ethereum::add_0x("0") : ethereum::add_0x(ethereum::to_hex(nonce_val)); } std::string ethereum_rpc_client::get_gas_price() { @@ -639,7 +640,7 @@ std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_tra #ifdef SEND_RAW_TRANSACTION ethereum::raw_transaction raw_tr; - raw_tr.nonce = ethereum::add_0x(ethereum::to_hex(ethereum::from_hex(rpc_client->get_nonce(ethereum::add_0x(public_key))))); + raw_tr.nonce = rpc_client->get_nonce(ethereum::add_0x(public_key)); raw_tr.gas_price = rpc_client->get_gas_price(); raw_tr.gas_limit = rpc_client->get_gas_limit(); raw_tr.to = wallet_contract_address; -- 2.45.2 From 1f3beba32acda451e79bd0eae9f2404988d3c833 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Mon, 29 Aug 2022 15:31:42 +0300 Subject: [PATCH 56/60] Don't send transaction that is not signed --- .../peerplays_sidechain/sidechain_net_handler_ethereum.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 8ceb582b..52d401cb 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -544,6 +544,11 @@ std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sid boost::property_tree::ptree pt_array; for (const auto &signature : sto.signatures) { const auto &transaction = signature.second; + + //! Check if we have this signed transaction, if not, don't send it + if(transaction.empty()) + continue; + #ifdef SEND_RAW_TRANSACTION const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(transaction); #else @@ -562,6 +567,7 @@ std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sid //! Fixme //! How should we proceed with error in eth_send_transaction elog("Error in eth_send_transaction for transaction ${id}, transaction ${transaction}", ("id", sto.id)("transaction", transaction)); + return std::string{}; //! Return empty string, as we have error in sending } } pt.add_child("result_array", pt_array); -- 2.45.2 From d6672d2d5fec3d5e460c656fffb33c50a1ec534a Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Sun, 4 Sep 2022 21:17:25 +0000 Subject: [PATCH 57/60] #424 develop merge --- .gitlab-ci.yml | 4 - libraries/app/database_api.cpp | 81 ++- libraries/chain/account_evaluator.cpp | 10 +- libraries/chain/db_block.cpp | 17 +- libraries/chain/db_getter.cpp | 64 +- libraries/chain/db_init.cpp | 49 +- libraries/chain/db_maint.cpp | 662 ++++++++++-------- libraries/chain/db_witness_schedule.cpp | 152 ++-- .../chain/include/graphene/chain/database.hpp | 41 +- .../graphene/chain/global_property_object.hpp | 16 +- .../graphene/chain/protocol/account.hpp | 20 +- .../graphene/chain/protocol/son_wallet.hpp | 2 +- .../include/graphene/chain/protocol/vote.hpp | 6 +- .../chain/sidechain_address_object.hpp | 2 +- .../include/graphene/chain/sidechain_defs.hpp | 15 +- .../chain/include/graphene/chain/son_info.hpp | 19 +- .../include/graphene/chain/son_object.hpp | 47 +- .../graphene/chain/son_wallet_object.hpp | 2 +- .../include/graphene/chain/voters_info.hpp | 12 +- .../include/graphene/chain/votes_info.hpp | 12 +- .../chain/witness_schedule_object.hpp | 2 +- .../graphene/chain/witness_scheduler.hpp | 10 +- libraries/chain/protocol/account.cpp | 19 +- .../chain/sidechain_address_evaluator.cpp | 2 +- libraries/chain/son_evaluator.cpp | 195 ++++-- libraries/chain/son_object.cpp | 4 + .../chain/son_wallet_deposit_evaluator.cpp | 10 +- libraries/chain/son_wallet_evaluator.cpp | 12 +- .../chain/son_wallet_withdraw_evaluator.cpp | 12 +- .../peerplays_sidechain/CMakeLists.txt | 2 +- .../ethereum/transaction.cpp | 157 +++-- .../ethereum/transaction.hpp | 18 + .../peerplays_sidechain_plugin.hpp | 16 +- .../sidechain_net_handler_factory.hpp | 23 + .../sidechain_net_manager.hpp | 38 - .../peerplays_sidechain_plugin.cpp | 320 +++++---- .../sidechain_net_handler.cpp | 50 +- .../sidechain_net_handler_bitcoin.cpp | 76 +- .../sidechain_net_handler_ethereum.cpp | 49 +- .../sidechain_net_handler_factory.cpp | 35 + .../sidechain_net_handler_hive.cpp | 34 +- .../sidechain_net_handler_peerplays.cpp | 14 +- .../sidechain_net_manager.cpp | 119 ---- .../wallet/include/graphene/wallet/wallet.hpp | 5 + libraries/wallet/wallet.cpp | 187 +++-- tests/cli/son.cpp | 620 +++++++++++----- .../ethereum_transaction_tests.cpp | 147 ++++ tests/tests/block_tests.cpp | 7 +- tests/tests/sidechain_addresses_test.cpp | 143 +++- tests/tests/son_operations_tests.cpp | 138 +++- tests/tests/son_wallet_tests.cpp | 9 +- 51 files changed, 2403 insertions(+), 1303 deletions(-) create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_factory.hpp delete mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_manager.hpp create mode 100644 libraries/plugins/peerplays_sidechain/sidechain_net_handler_factory.cpp delete mode 100644 libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp create mode 100644 tests/peerplays_sidechain/ethereum_transaction_tests.cpp diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cda41654..61afce6e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -44,8 +44,6 @@ test-mainnet: dockerize-mainnet: stage: dockerize - dependencies: - - test-mainnet variables: IMAGE: $CI_REGISTRY_IMAGE/mainnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA before_script: @@ -105,8 +103,6 @@ test-testnet: dockerize-testnet: stage: dockerize - dependencies: - - test-testnet variables: IMAGE: $CI_REGISTRY_IMAGE/testnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA before_script: diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 6ffee911..0a96bc26 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -2083,7 +2083,9 @@ vector database_api_impl::lookup_vote_ids(const vector &v const auto &committee_idx = _db.get_index_type().indices().get(); const auto &for_worker_idx = _db.get_index_type().indices().get(); const auto &against_worker_idx = _db.get_index_type().indices().get(); - const auto &son_idx = _db.get_index_type().indices().get(); + const auto &son_bictoin_idx = _db.get_index_type().indices().get(); + const auto &son_hive_idx = _db.get_index_type().indices().get(); + const auto &son_ethereum_idx = _db.get_index_type().indices().get(); vector result; result.reserve(votes.size()); @@ -2119,15 +2121,30 @@ vector database_api_impl::lookup_vote_ids(const vector &v } break; } - case vote_id_type::son: { - auto itr = son_idx.find(id); - if (itr != son_idx.end()) + case vote_id_type::son_bitcoin: { + auto itr = son_bictoin_idx.find(id); + if (itr != son_bictoin_idx.end()) + result.emplace_back(variant(*itr, 5)); + else + result.emplace_back(variant()); + break; + } + case vote_id_type::son_hive: { + auto itr = son_hive_idx.find(id); + if (itr != son_hive_idx.end()) + result.emplace_back(variant(*itr, 5)); + else + result.emplace_back(variant()); + break; + } + case vote_id_type::son_ethereum: { + auto itr = son_ethereum_idx.find(id); + if (itr != son_ethereum_idx.end()) result.emplace_back(variant(*itr, 5)); else result.emplace_back(variant()); break; } - case vote_id_type::VOTE_TYPE_COUNT: break; // supress unused enum value warnings default: @@ -2152,12 +2169,24 @@ vector database_api_impl::get_votes_ids(const string &account_name votes_info database_api_impl::get_votes(const string &account_name_or_id) const { votes_info result; - const auto &votes_ids = get_votes_ids(account_name_or_id); - const auto &committee_ids = get_votes_objects(votes_ids); - const auto &witness_ids = get_votes_objects(votes_ids); - const auto &for_worker_ids = get_votes_objects(votes_ids); - const auto &against_worker_ids = get_votes_objects(votes_ids); - const auto &son_ids = get_votes_objects(votes_ids, 5); + const auto votes_ids = get_votes_ids(account_name_or_id); + const auto committee_ids = get_votes_objects(votes_ids); + const auto witness_ids = get_votes_objects(votes_ids); + const auto for_worker_ids = get_votes_objects(votes_ids); + const auto against_worker_ids = get_votes_objects(votes_ids); + const auto son_ids = [this, &votes_ids]() { + flat_map> son_ids; + const auto son_bitcoin_ids = get_votes_objects(votes_ids, 5); + if (!son_bitcoin_ids.empty()) + son_ids[sidechain_type::bitcoin] = std::move(son_bitcoin_ids); + const auto son_hive_ids = get_votes_objects(votes_ids, 5); + if (!son_hive_ids.empty()) + son_ids[sidechain_type::hive] = std::move(son_hive_ids); + const auto son_ethereum_ids = get_votes_objects(votes_ids, 5); + if (!son_ethereum_ids.empty()) + son_ids[sidechain_type::ethereum] = std::move(son_ethereum_ids); + return son_ids; + }(); //! Fill votes info if (!committee_ids.empty()) { @@ -2201,11 +2230,15 @@ votes_info database_api_impl::get_votes(const string &account_name_or_id) const } if (!son_ids.empty()) { - vector votes_for_sons; - votes_for_sons.reserve(son_ids.size()); - for (const auto &son : son_ids) { - const auto &son_obj = son.as(6); - votes_for_sons.emplace_back(votes_info_object{son_obj.vote_id, son_obj.id}); + flat_map> votes_for_sons; + for (const auto &son_sidechain_ids : son_ids) { + const auto &sidechain = son_sidechain_ids.first; + const auto &sidechain_ids = son_sidechain_ids.second; + votes_for_sons[sidechain].reserve(sidechain_ids.size()); + for (const auto &son : sidechain_ids) { + const auto &son_obj = son.as(6); + votes_for_sons[sidechain].emplace_back(votes_info_object{son_obj.get_sidechain_vote_id(sidechain), son_obj.id}); + } } result.votes_for_sons = std::move(votes_for_sons); } @@ -2379,12 +2412,16 @@ voters_info database_api_impl::get_voters(const string &account_name_or_id) cons //! Info for son voters if (son_object) { - const auto &son_voters = get_voters_by_id(son_object->vote_id); - voters_info_object voters_for_son; - voters_for_son.vote_id = son_object->vote_id; - voters_for_son.voters.reserve(son_voters.size()); - for (const auto &voter : son_voters) { - voters_for_son.voters.emplace_back(voter.get_id()); + flat_map voters_for_son; + for (const auto &vote_id : son_object->sidechain_vote_ids) { + const auto &son_voters = get_voters_by_id(vote_id.second); + voters_info_object voters_for_sidechain_son; + voters_for_sidechain_son.vote_id = vote_id.second; + voters_for_sidechain_son.voters.reserve(son_voters.size()); + for (const auto &voter : son_voters) { + voters_for_sidechain_son.voters.emplace_back(voter.get_id()); + } + voters_for_son[vote_id.first] = std::move(voters_for_sidechain_son); } result.voters_for_son = std::move(voters_for_son); } diff --git a/libraries/chain/account_evaluator.cpp b/libraries/chain/account_evaluator.cpp index 3026c2f0..5f1a4416 100644 --- a/libraries/chain/account_evaluator.cpp +++ b/libraries/chain/account_evaluator.cpp @@ -68,8 +68,14 @@ void verify_account_votes( const database& db, const account_options& options ) "Voted for more witnesses than currently allowed (${c})", ("c", chain_params.maximum_witness_count) ); FC_ASSERT( options.num_committee <= chain_params.maximum_committee_count, "Voted for more committee members than currently allowed (${c})", ("c", chain_params.maximum_committee_count) ); - FC_ASSERT( options.num_son() <= chain_params.maximum_son_count(), - "Voted for more sons than currently allowed (${c})", ("c", chain_params.maximum_son_count()) ); + FC_ASSERT( chain_params.extensions.value.maximum_son_count.valid() , "Invalid maximum son count" ); + FC_ASSERT( options.extensions.value.num_son.valid() , "Invalid son number" ); + for(const auto& num_sons : *options.extensions.value.num_son) + { + FC_ASSERT( num_sons.second <= *chain_params.extensions.value.maximum_son_count, + "Voted for more sons than currently allowed (${c})", ("c", *chain_params.extensions.value.maximum_son_count) ); + } + FC_ASSERT( db.find_object(options.voting_account), "Invalid proxy account specified." ); uint32_t max_vote_id = gpo.next_available_vote_id; bool has_worker_votes = false; diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index c475813b..9606c59e 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -705,7 +705,12 @@ void database::_apply_block( const signed_block& next_block ) if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM) { update_witness_schedule(next_block); - if(global_props.active_sons.size() > 0) { + bool need_to_update_son_schedule = false; + for(const auto& active_sons : global_props.active_sons){ + if(!active_sons.second.empty()) + need_to_update_son_schedule = true; + } + if(need_to_update_son_schedule) { update_son_schedule(next_block); } } @@ -739,10 +744,18 @@ void database::_apply_block( const signed_block& next_block ) // TODO: figure out if we could collapse this function into // update_global_dynamic_data() as perhaps these methods only need // to be called for header validation? + update_maintenance_flag( maint_needed ); if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM) { update_witness_schedule(); - if(global_props.active_sons.size() > 0) { + + bool need_update_son_schedule = false; + for(const auto& active_sidechain_type : active_sidechain_types) { + if(global_props.active_sons.at(active_sidechain_type).size() > 0) { + need_update_son_schedule = true; + } + } + if(need_update_son_schedule) { update_son_schedule(); } } diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index 78740c9b..0bb9b10b 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -222,17 +222,30 @@ std::set database::get_sons_to_be_deregistered() for( auto& son : son_idx ) { - if(son.status == son_status::in_maintenance) + bool need_to_be_deregistered = true; + for(const auto& status : son.statuses) { - auto stats = son.statistics(*this); - // TODO : We need to add a function that returns if we can deregister SON - // i.e. with introduction of PW code, we have to make a decision if the SON - // is needed for release of funds from the PW - if(head_block_time() - stats.last_down_timestamp >= fc::seconds(get_global_properties().parameters.son_deregister_time())) + const auto& sidechain = status.first; + if(status.second != son_status::in_maintenance) + need_to_be_deregistered = false; + + if(need_to_be_deregistered) { - ret.insert(son.id); + auto stats = son.statistics(*this); + + // TODO : We need to add a function that returns if we can deregister SON + // i.e. with introduction of PW code, we have to make a decision if the SON + // is needed for release of funds from the PW + if (head_block_time() - stats.last_down_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time())) { + need_to_be_deregistered = false; + } } } + + if(need_to_be_deregistered) + { + ret.insert(son.id); + } } return ret; } @@ -289,28 +302,51 @@ bool database::is_son_dereg_valid( son_id_type son_id ) return false; } - return (son->status == son_status::in_maintenance && - (head_block_time() - son->statistics(*this).last_down_timestamp >= fc::seconds(get_global_properties().parameters.son_deregister_time()))); + bool status_son_dereg_valid = true; + for(const auto& status : son->statuses) + { + const auto& sidechain = status.first; + if(status.second != son_status::in_maintenance) + status_son_dereg_valid = false; + + if(status_son_dereg_valid) + { + if(head_block_time() - son->statistics(*this).last_down_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time())) + { + status_son_dereg_valid = false; + } + } + } + + return status_son_dereg_valid; } -bool database::is_son_active( son_id_type son_id ) +bool database::is_son_active( sidechain_type type, son_id_type son_id ) { const auto& son_idx = get_index_type().indices().get< by_id >(); auto son = son_idx.find( son_id ); - if(son == son_idx.end()) - { + if(son == son_idx.end()) { return false; } const global_property_object& gpo = get_global_properties(); + if(!gpo.active_sons.contains(type)) { + return false; + } + + const auto& gpo_as = gpo.active_sons.at(type); vector active_son_ids; - active_son_ids.reserve(gpo.active_sons.size()); - std::transform(gpo.active_sons.begin(), gpo.active_sons.end(), + active_son_ids.reserve(gpo_as.size()); + std::transform(gpo_as.cbegin(), gpo_as.cend(), std::inserter(active_son_ids, active_son_ids.end()), [](const son_info& swi) { return swi.son_id; }); + if(active_son_ids.empty()) { + return false; + } + auto it_son = std::find(active_son_ids.begin(), active_son_ids.end(), son_id); return (it_son != active_son_ids.end()); } diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index c4aabfa8..de398f41 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -1100,8 +1100,9 @@ void database::init_genesis(const genesis_state_type& genesis_state) FC_ASSERT( _p_witness_schedule_obj->id == witness_schedule_id_type() ); // Initialize witness schedule + #ifndef NDEBUG - const son_schedule_object& sso = + const son_schedule_object& ssohive = #endif create([&](son_schedule_object& _sso) { @@ -1120,13 +1121,51 @@ void database::init_genesis(const genesis_state_type& genesis_state) _sso.recent_slots_filled = fc::uint128::max_value(); }); - assert( sso.id == son_schedule_id_type() ); + assert( ssohive.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::hive)) ); - // Enable fees - modify(get_global_properties(), [&genesis_state](global_property_object& p) { - p.parameters.current_fees = genesis_state.initial_parameters.current_fees; +#ifndef NDEBUG + const son_schedule_object& ssobitcoin = +#endif + create([&](son_schedule_object& _sso) + { + // for scheduled + memset(_sso.rng_seed.begin(), 0, _sso.rng_seed.size()); + + witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); + + auto init_witnesses = get_global_properties().active_witnesses; + + _sso.scheduler = son_scheduler(); + _sso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1); + + + _sso.last_scheduling_block = 0; + + _sso.recent_slots_filled = fc::uint128::max_value(); }); + assert( ssobitcoin.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::bitcoin)) ); +#ifndef NDEBUG + const son_schedule_object& ssoethereum = +#endif + create([&](son_schedule_object& _sso) + { + // for scheduled + memset(_sso.rng_seed.begin(), 0, _sso.rng_seed.size()); + + witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); + + auto init_witnesses = get_global_properties().active_witnesses; + + _sso.scheduler = son_scheduler(); + _sso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1); + + + _sso.last_scheduling_block = 0; + + _sso.recent_slots_filled = fc::uint128::max_value(); + }); + assert( ssoethereum.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::ethereum)) ); // Create FBA counters create([&]( fba_accumulator_object& acc ) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 2f59a886..0825128e 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -78,26 +78,30 @@ vector> database::sort } template<> -vector> database::sort_votable_objects(size_t count) const +vector> database::sort_votable_objects(sidechain_type sidechain, size_t count) const { const auto& all_sons = get_index_type().indices().get< by_id >(); std::vector> refs; for( auto& son : all_sons ) { - if(son.has_valid_config(head_block_time()) && son.status != son_status::deregistered) + if(son.has_valid_config(head_block_time()) && son.statuses.at(sidechain) != son_status::deregistered) { refs.push_back(std::cref(son)); } } count = std::min(count, refs.size()); std::partial_sort(refs.begin(), refs.begin() + count, refs.end(), - [this](const son_object& a, const son_object& b)->bool { - share_type oa_vote = _vote_tally_buffer[a.vote_id]; - share_type ob_vote = _vote_tally_buffer[b.vote_id]; + [this, sidechain](const son_object& a, const son_object& b)->bool { + FC_ASSERT(sidechain == sidechain_type::bitcoin || sidechain == sidechain_type::hive || sidechain == sidechain_type::ethereum, "Unexpected sidechain type"); + + const share_type oa_vote = _vote_tally_buffer[a.get_sidechain_vote_id(sidechain)]; + const share_type ob_vote = _vote_tally_buffer[b.get_sidechain_vote_id(sidechain)]; + if( oa_vote != ob_vote ) return oa_vote > ob_vote; - return a.vote_id < b.vote_id; - }); + + return a.get_sidechain_vote_id(sidechain) < b.get_sidechain_vote_id(sidechain); +}); refs.resize(count, refs.front()); return refs; @@ -178,222 +182,233 @@ void database::update_worker_votes() void database::pay_sons() { - time_point_sec now = head_block_time(); + const time_point_sec now = head_block_time(); const dynamic_global_property_object& dpo = get_dynamic_global_properties(); // Current requirement is that we have to pay every 24 hours, so the following check - if( dpo.son_budget.value > 0 && ((now - dpo.last_son_payout_time) >= fc::seconds(get_global_properties().parameters.son_pay_time()))) { - assert( _son_count_histogram_buffer.size() > 0 ); - const share_type stake_target = (_total_voting_stake-_son_count_histogram_buffer[0]) / 2; - /// accounts that vote for 0 or 1 son do not get to express an opinion on - /// the number of sons to have (they abstain and are non-voting accounts) - share_type stake_tally = 0; - size_t son_count = 0; - if( stake_target > 0 ) + if( dpo.son_budget.value > 0 && ((now - dpo.last_son_payout_time) >= fc::seconds(get_global_properties().parameters.son_pay_time()))) + { + for(const auto& active_sidechain_type : active_sidechain_types) { - while( (son_count < _son_count_histogram_buffer.size() - 1) - && (stake_tally <= stake_target) ) + assert( _son_count_histogram_buffer.at(active_sidechain_type).size() > 0 ); + const share_type stake_target = (_total_voting_stake-_son_count_histogram_buffer.at(active_sidechain_type)[0]) / 2; + /// accounts that vote for 0 or 1 son do not get to express an opinion on + /// the number of sons to have (they abstain and are non-voting accounts) + share_type stake_tally = 0; + size_t son_count = 0; + if( stake_target > 0 ) { - stake_tally += _son_count_histogram_buffer[++son_count]; - } - } - const vector> sons = [this, &son_count]{ - if(head_block_time() >= HARDFORK_SON3_TIME) - return sort_votable_objects(std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count)); - else - return sort_votable_objects(get_global_properties().parameters.maximum_son_count()); - }(); - // After SON2 HF - uint64_t total_votes = 0; - for( const son_object& son : sons ) - { - total_votes += _vote_tally_buffer[son.vote_id]; - } - int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(total_votes)) - 15, 0); - auto get_weight = [&bits_to_drop]( uint64_t son_votes ) { - uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) ); - return weight; - }; - // Before SON2 HF - auto get_weight_before_son2_hf = []( uint64_t son_votes ) { - int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(son_votes)) - 15, 0); - uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) ); - return weight; - }; - uint64_t weighted_total_txs_signed = 0; - share_type son_budget = dpo.son_budget; - get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &get_weight, &now, &get_weight_before_son2_hf](const object& o) { - const son_statistics_object& s = static_cast(o); - const auto& idx = get_index_type().indices().get(); - auto son_obj = idx.find( s.owner ); - auto son_weight = get_weight(_vote_tally_buffer[son_obj->vote_id]); - if( now < HARDFORK_SON2_TIME ) { - son_weight = get_weight_before_son2_hf(_vote_tally_buffer[son_obj->vote_id]); - } - uint64_t txs_signed = 0; - for (const auto &ts : s.txs_signed) { - txs_signed = txs_signed + ts.second; - } - weighted_total_txs_signed += (txs_signed * son_weight); - }); - - // Now pay off each SON proportional to the number of transactions signed. - get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &dpo, &son_budget, &get_weight, &get_weight_before_son2_hf, &now](const object& o) { - const son_statistics_object& s = static_cast(o); - uint64_t txs_signed = 0; - for (const auto &ts : s.txs_signed) { - txs_signed = txs_signed + ts.second; + while( (son_count < _son_count_histogram_buffer.at(active_sidechain_type).size() - 1) + && (stake_tally <= stake_target) ) + { + stake_tally += _son_count_histogram_buffer.at(active_sidechain_type)[++son_count]; + } } - if(txs_signed > 0){ + const auto sons = sort_votable_objects(active_sidechain_type, + (std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count)) + ); + + // After SON2 HF + uint64_t total_votes = 0; + for( const son_object& son : sons ) + { + total_votes += _vote_tally_buffer[son.sidechain_vote_ids.at(active_sidechain_type)]; + } + const int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(total_votes)) - 15, 0); + auto get_weight = [&bits_to_drop]( uint64_t son_votes ) { + const uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) ); + return weight; + }; + // Before SON2 HF + auto get_weight_before_son2_hf = []( uint64_t son_votes ) { + const int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(son_votes)) - 15, 0); + const uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) ); + return weight; + }; + uint64_t weighted_total_txs_signed = 0; + const share_type son_budget = dpo.son_budget; + get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &get_weight, &now, &get_weight_before_son2_hf, &active_sidechain_type](const object& o) { + const son_statistics_object& s = static_cast(o); const auto& idx = get_index_type().indices().get(); - auto son_obj = idx.find( s.owner ); - auto son_weight = get_weight(_vote_tally_buffer[son_obj->vote_id]); - if( now < HARDFORK_SON2_TIME ) { - son_weight = get_weight_before_son2_hf(_vote_tally_buffer[son_obj->vote_id]); + const auto son_obj = idx.find( s.owner ); + uint16_t son_weight = 0; + if( now >= HARDFORK_SON2_TIME ) { + son_weight += get_weight(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]); } - share_type pay = (txs_signed * son_weight * son_budget.value)/weighted_total_txs_signed; - modify( *son_obj, [&]( son_object& _son_obj) - { - _son_obj.pay_son_fee(pay, *this); - }); - //Remove the amount paid out to SON from global SON Budget - modify( dpo, [&]( dynamic_global_property_object& _dpo ) - { - _dpo.son_budget -= pay; - } ); - //Reset the tx counter in each son statistics object - modify( s, [&]( son_statistics_object& _s) - { - for (const auto &ts : s.txs_signed) { - _s.txs_signed.at(ts.first) = 0; + else { + son_weight += get_weight_before_son2_hf(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]); + } + const uint64_t txs_signed = s.txs_signed.contains(active_sidechain_type) ? s.txs_signed.at(active_sidechain_type) : 0; + weighted_total_txs_signed += (txs_signed * son_weight); + }); + + // Now pay off each SON proportional to the number of transactions signed. + get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &dpo, &son_budget, &get_weight, &get_weight_before_son2_hf, &now, &active_sidechain_type](const object& o) { + const son_statistics_object& s = static_cast(o); + const uint64_t txs_signed = s.txs_signed.contains(active_sidechain_type) ? s.txs_signed.at(active_sidechain_type) : 0; + + if(txs_signed > 0){ + const auto& idx = get_index_type().indices().get(); + auto son_obj = idx.find( s.owner ); + uint16_t son_weight = 0; + if( now >= HARDFORK_SON2_TIME ) { + son_weight += get_weight(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]); } - }); - } - }); - //Note the last son pay out time - modify( dpo, [&]( dynamic_global_property_object& _dpo ) - { - _dpo.last_son_payout_time = now; - }); + else { + son_weight += get_weight_before_son2_hf(_vote_tally_buffer[son_obj->sidechain_vote_ids.at(active_sidechain_type)]); + } + const share_type pay = (txs_signed * son_weight * son_budget.value)/weighted_total_txs_signed; + modify( *son_obj, [&]( son_object& _son_obj) + { + _son_obj.pay_son_fee(pay, *this); + }); + //Remove the amount paid out to SON from global SON Budget + modify( dpo, [&]( dynamic_global_property_object& _dpo ) + { + _dpo.son_budget -= pay; + } ); + //Reset the tx counter in each son statistics object + modify( s, [&]( son_statistics_object& _s) + { + if(_s.txs_signed.contains(active_sidechain_type)) + _s.txs_signed.at(active_sidechain_type) = 0; + }); + } + }); + //Note the last son pay out time + modify( dpo, [&]( dynamic_global_property_object& _dpo ) + { + _dpo.last_son_payout_time = now; + }); + } } } -void database::update_son_metrics(const vector& curr_active_sons) +void database::update_son_metrics(const flat_map >& curr_active_sons) { - vector current_sons; + for(const auto& curr_active_sidechain_sons : curr_active_sons) { + const auto& sidechain = curr_active_sidechain_sons.first; + const auto& _curr_active_sidechain_sons = curr_active_sidechain_sons.second; - current_sons.reserve(curr_active_sons.size()); - std::transform(curr_active_sons.begin(), curr_active_sons.end(), - std::inserter(current_sons, current_sons.end()), - [](const son_info &swi) { - return swi.son_id; - }); + vector current_sons; - const auto& son_idx = get_index_type().indices().get< by_id >(); - for( auto& son : son_idx ) - { - auto& stats = son.statistics(*this); - bool is_active_son = (std::find(current_sons.begin(), current_sons.end(), son.id) != current_sons.end()); - modify( stats, [&]( son_statistics_object& _stats ) - { - if(is_active_son) { - _stats.total_voted_time = _stats.total_voted_time + get_global_properties().parameters.maintenance_interval; - } - _stats.total_downtime += _stats.current_interval_downtime; - _stats.current_interval_downtime = 0; - for (const auto &str : _stats.sidechain_txs_reported) { - _stats.sidechain_txs_reported.at(str.first) = 0; - } - }); + current_sons.reserve(_curr_active_sidechain_sons.size()); + std::transform(_curr_active_sidechain_sons.cbegin(), _curr_active_sidechain_sons.cend(), + std::inserter(current_sons, current_sons.end()), + [](const son_info &swi) { + return swi.son_id; + }); + + const auto &son_idx = get_index_type().indices().get(); + for (auto &son : son_idx) { + auto &stats = son.statistics(*this); + bool is_active_son = (std::find(current_sons.begin(), current_sons.end(), son.id) != current_sons.end()); + modify(stats, [&](son_statistics_object &_stats) { + if (is_active_son) { + _stats.total_voted_time[sidechain] = _stats.total_voted_time[sidechain] + get_global_properties().parameters.maintenance_interval; + } + _stats.total_downtime[sidechain] += _stats.current_interval_downtime[sidechain]; + _stats.current_interval_downtime[sidechain] = 0; + _stats.sidechain_txs_reported[sidechain] = 0; + }); + } } } -void database::update_son_statuses(const vector& curr_active_sons, const vector& new_active_sons) +void database::update_son_statuses( const flat_map >& curr_active_sons, + const flat_map >& new_active_sons ) { - vector current_sons, new_sons; - vector sons_to_remove, sons_to_add; - const auto& idx = get_index_type().indices().get(); + for(const auto& new_active_sidechain_sons : new_active_sons) { + const auto& sidechain = new_active_sidechain_sons.first; - current_sons.reserve(curr_active_sons.size()); - std::transform(curr_active_sons.begin(), curr_active_sons.end(), - std::inserter(current_sons, current_sons.end()), - [](const son_info &swi) { - return swi.son_id; - }); + vector current_sons, new_sons; + vector sons_to_remove, sons_to_add; + const auto &idx = get_index_type().indices().get(); - new_sons.reserve(new_active_sons.size()); - std::transform(new_active_sons.begin(), new_active_sons.end(), - std::inserter(new_sons, new_sons.end()), - [](const son_info &swi) { - return swi.son_id; - }); - - // find all cur_active_sons members that is not in new_active_sons - for_each(current_sons.begin(), current_sons.end(), - [&sons_to_remove, &new_sons](const son_id_type& si) - { - if(std::find(new_sons.begin(), new_sons.end(), si) == - new_sons.end()) - { - sons_to_remove.push_back(si); - } - } - ); - - for( const auto& sid : sons_to_remove ) - { - auto son = idx.find( sid ); - if(son == idx.end()) // SON is deleted already - continue; - // keep maintenance status for nodes becoming inactive - if(son->status == son_status::active) - { - modify( *son, [&]( son_object& obj ){ - obj.status = son_status::inactive; - }); + if(curr_active_sons.contains(sidechain)) { + current_sons.reserve(curr_active_sons.at(sidechain).size()); + std::transform(curr_active_sons.at(sidechain).cbegin(), curr_active_sons.at(sidechain).cend(), + std::inserter(current_sons, current_sons.end()), + [](const son_info &swi) { + return swi.son_id; + }); } - } - // find all new_active_sons members that is not in cur_active_sons - for_each(new_sons.begin(), new_sons.end(), - [&sons_to_add, ¤t_sons](const son_id_type& si) - { - if(std::find(current_sons.begin(), current_sons.end(), si) == - current_sons.end()) - { - sons_to_add.push_back(si); - } - } - ); + new_sons.reserve(new_active_sons.at(sidechain).size()); + std::transform(new_active_sons.at(sidechain).cbegin(), new_active_sons.at(sidechain).cend(), + std::inserter(new_sons, new_sons.end()), + [](const son_info &swi) { + return swi.son_id; + }); - for( const auto& sid : sons_to_add ) - { - auto son = idx.find( sid ); - FC_ASSERT(son != idx.end(), "Invalid SON in active list, id={sonid}.", ("sonid", sid)); - // keep maintenance status for new nodes - if(son->status == son_status::inactive) - { - modify( *son, [&]( son_object& obj ){ - obj.status = son_status::active; - }); - } - } + // find all cur_active_sons members that is not in new_active_sons + for_each(current_sons.begin(), current_sons.end(), + [&sons_to_remove, &new_sons](const son_id_type &si) { + if (std::find(new_sons.begin(), new_sons.end(), si) == + new_sons.end()) { + sons_to_remove.push_back(si); + } + }); - ilog("New SONS"); - for(size_t i = 0; i < new_sons.size(); i++) { - auto son = idx.find( new_sons[i] ); - if(son == idx.end()) // SON is deleted already + for (const auto &sid : sons_to_remove) { + auto son = idx.find(sid); + if (son == idx.end()) // SON is deleted already continue; - ilog( "${s}, status = ${ss}, total_votes = ${sv}", ("s", new_sons[i])("ss", son->status)("sv", son->total_votes) ); + // keep maintenance status for nodes becoming inactive + if (son->statuses.at(sidechain) == son_status::active) { + modify(*son, [&](son_object &obj) { + obj.statuses.at(sidechain) = son_status::inactive; + }); + } + } + + // find all new_active_sons members that is not in cur_active_sons + for_each(new_sons.begin(), new_sons.end(), + [&sons_to_add, ¤t_sons](const son_id_type &si) { + if (std::find(current_sons.begin(), current_sons.end(), si) == + current_sons.end()) { + sons_to_add.push_back(si); + } + }); + + for (const auto &sid : sons_to_add) { + auto son = idx.find(sid); + FC_ASSERT(son != idx.end(), "Invalid SON in active list, id={sonid}.", ("sonid", sid)); + // keep maintenance status for new nodes + if (son->statuses.at(sidechain) == son_status::inactive) { + modify(*son, [&](son_object &obj) { + obj.statuses.at(sidechain) = son_status::active; + }); + } + } + + ilog("New SONS for sidechain = ${sidechain}", ("sidechain", sidechain)); + for (size_t i = 0; i < new_sons.size(); i++) { + auto son = idx.find(new_sons[i]); + if (son == idx.end()) // SON is deleted already + continue; + ilog("${s}, status = ${ss}, total_votes = ${sv}", ("s", new_sons[i])("ss", son->statuses.at(sidechain))("sv", son->total_votes)); + } } - if( sons_to_remove.size() > 0 ) - { + //! Remove inactive sons (when all sidechain inactive) + vector sons_to_remove; + const auto &idx = get_index_type().indices().get(); + for(const auto& son : idx) { + bool inactive_son = true; + for(const auto& status : son.statuses) { + if (status.second != son_status::inactive) + inactive_son = false; + } + if (inactive_son) + sons_to_remove.emplace_back(son.id); + } + if (sons_to_remove.size() > 0) { remove_inactive_son_proposals(sons_to_remove); } } -void database::update_son_wallet(const vector& new_active_sons) +void database::update_son_wallet(const flat_map >& new_active_sons) { bool should_recreate_pw = true; @@ -406,8 +421,16 @@ void database::update_son_wallet(const vector& new_active_sons) bool wallet_son_sets_equal = (cur_wallet_sons.size() == new_active_sons.size()); if (wallet_son_sets_equal) { - for( size_t i = 0; i < cur_wallet_sons.size(); i++ ) { - wallet_son_sets_equal = wallet_son_sets_equal && cur_wallet_sons.at(i) == new_active_sons.at(i); + for( const auto& cur_wallet_sidechain_sons : cur_wallet_sons ) { + const auto& sidechain = cur_wallet_sidechain_sons.first; + const auto& _cur_wallet_sidechain_sons = cur_wallet_sidechain_sons.second; + + wallet_son_sets_equal = wallet_son_sets_equal && (_cur_wallet_sidechain_sons.size() == new_active_sons.at(sidechain).size()); + if (wallet_son_sets_equal) { + for (size_t i = 0; i < _cur_wallet_sidechain_sons.size(); i++) { + wallet_son_sets_equal = wallet_son_sets_equal && (_cur_wallet_sidechain_sons.at(i) == new_active_sons.at(sidechain).at(i)); + } + } } } @@ -420,14 +443,24 @@ void database::update_son_wallet(const vector& new_active_sons) } } - should_recreate_pw = should_recreate_pw && (new_active_sons.size() >= get_chain_properties().immutable_parameters.min_son_count); + bool should_recreate_pw_sidechain = false; + for(const auto& new_active_sidechain_sons : new_active_sons) { + if(new_active_sidechain_sons.second.size() >= get_chain_properties().immutable_parameters.min_son_count) + should_recreate_pw_sidechain = true; + } + should_recreate_pw = should_recreate_pw && should_recreate_pw_sidechain; if (should_recreate_pw) { // Create new son_wallet_object, to initiate wallet recreation create( [&]( son_wallet_object& obj ) { obj.valid_from = head_block_time(); obj.expires = time_point_sec::maximum(); - obj.sons.insert(obj.sons.end(), new_active_sons.begin(), new_active_sons.end()); + for(const auto& new_active_sidechain_sons : new_active_sons){ + const auto& sidechain = new_active_sidechain_sons.first; + const auto& _new_active_sidechain_sons = new_active_sidechain_sons.second; + + obj.sons[sidechain].insert(obj.sons[sidechain].end(), _new_active_sidechain_sons.cbegin(), _new_active_sidechain_sons.cend()); + } }); } } @@ -684,48 +717,87 @@ void database::update_active_sons() } assert( _son_count_histogram_buffer.size() > 0 ); - share_type stake_target = (_total_voting_stake-_son_count_histogram_buffer[0]) / 2; + for( const auto& son_count_histogram_buffer : _son_count_histogram_buffer ){ + assert( son_count_histogram_buffer.second.size() > 0 ); + } + + const flat_map 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; + }(); /// accounts that vote for 0 or 1 son do not get to express an opinion on /// the number of sons to have (they abstain and are non-voting accounts) - - share_type stake_tally = 0; - - size_t son_count = 0; - if( stake_target > 0 ) - { - while( (son_count < _son_count_histogram_buffer.size() - 1) - && (stake_tally <= stake_target) ) + flat_map 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 ) { - stake_tally += _son_count_histogram_buffer[++son_count]; + while( (son_count[sidechain] < _son_count_histogram_buffer.at(sidechain).size() - 1) + && (stake_tally[sidechain] <= stake_target_sidechain.second) ) + { + stake_tally[sidechain] += _son_count_histogram_buffer.at(sidechain)[ ++son_count[sidechain] ]; + } } } const global_property_object& gpo = get_global_properties(); - const vector> sons = [this, &son_count]{ - if(head_block_time() >= HARDFORK_SON3_TIME) - return sort_votable_objects(std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count)); - else - return sort_votable_objects(get_global_properties().parameters.maximum_son_count()); - }(); - + 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) + { + if(head_block_time() >= HARDFORK_SON3_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()); + } + } auto& local_vote_buffer_ref = _vote_tally_buffer; for( const son_object& son : all_sons ) { - if(son.status == son_status::request_maintenance) + for(const auto& status: son.statuses) { - auto& stats = son.statistics(*this); - modify( stats, [&]( son_statistics_object& _s){ - _s.last_down_timestamp = head_block_time(); + const auto& sidechain = status.first; + if(status.second == son_status::in_maintenance) + { + auto &stats = son.statistics(*this); + modify(stats, [&](son_statistics_object &_s) { + _s.last_down_timestamp[sidechain] = head_block_time(); }); + } } + modify( son, [local_vote_buffer_ref]( son_object& obj ){ - obj.total_votes = local_vote_buffer_ref[obj.vote_id]; - if(obj.status == son_status::request_maintenance) - obj.status = son_status::in_maintenance; - }); + for(const auto& sidechain_vote_id : obj.sidechain_vote_ids ){ + obj.total_votes[sidechain_vote_id.first] = local_vote_buffer_ref[sidechain_vote_id.second]; + } + for(auto& status: obj.statuses) + { + if (status.second == son_status::request_maintenance) + status.second = son_status::in_maintenance; + } + }); } // Update SON authority @@ -733,21 +805,24 @@ void database::update_active_sons() { modify( get(gpo.parameters.son_account()), [&]( account_object& a ) { + set account_ids; + for(const auto& sidechain_sons : sons) + { + for( const son_object& son : sidechain_sons.second ) + { + account_ids.emplace(son.son_account); + } + } + if( head_block_time() < HARDFORK_533_TIME ) { - map weights; a.active.weight_threshold = 0; a.active.account_auths.clear(); - for( const son_object& son : sons ) - { - weights.emplace(son.son_account, uint64_t(1)); - } - - for( const auto& weight : weights ) + for( const auto& account_id : account_ids ) { // Ensure that everyone has at least one vote. Zero weights aren't allowed. - a.active.account_auths[weight.first] += 1; + a.active.account_auths[account_id] += 1; a.active.weight_threshold += 1; } @@ -758,8 +833,10 @@ void database::update_active_sons() else { vote_counter vc; - for( const son_object& son : sons ) - vc.add( son.son_account, UINT64_C(1) ); + for( const auto& account_id : account_ids ) + { + vc.add(account_id, UINT64_C(1)); + } vc.finish_2_3( a.active ); } } ); @@ -767,22 +844,36 @@ void database::update_active_sons() // Compare current and to-be lists of active sons - auto cur_active_sons = gpo.active_sons; - vector new_active_sons; + const auto cur_active_sons = gpo.active_sons; + flat_map > new_active_sons; const auto &acc = get(gpo.parameters.son_account()); - for( const son_object& son : sons ) { - son_info swi; - swi.son_id = son.id; - swi.weight = acc.active.account_auths.at(son.son_account); - swi.signing_key = son.signing_key; - swi.sidechain_public_keys = son.sidechain_public_keys; - new_active_sons.push_back(swi); + for( const auto& sidechain_sons : sons ){ + const auto& sidechain = sidechain_sons.first; + const auto& sons_array = sidechain_sons.second; + + new_active_sons[sidechain].reserve(sons_array.size()); + for( const son_object& son : sons_array ) { + son_info swi; + swi.son_id = son.id; + swi.weight = acc.active.account_auths.at(son.son_account); + swi.signing_key = son.signing_key; + swi.public_key = son.sidechain_public_keys.at(sidechain); + new_active_sons[sidechain].push_back(swi); + } } bool son_sets_equal = (cur_active_sons.size() == new_active_sons.size()); if (son_sets_equal) { - for( size_t i = 0; i < cur_active_sons.size(); i++ ) { - son_sets_equal = son_sets_equal && cur_active_sons.at(i) == new_active_sons.at(i); + for( const auto& cur_active_sidechain_sons : cur_active_sons ){ + const auto& sidechain = cur_active_sidechain_sons.first; + const auto& _cur_active_sidechain_sons = cur_active_sidechain_sons.second; + + son_sets_equal = son_sets_equal && (_cur_active_sidechain_sons.size() == new_active_sons.at(sidechain).size()); + if (son_sets_equal) { + for (size_t i = 0; i < _cur_active_sidechain_sons.size(); i++) { + son_sets_equal = son_sets_equal && (_cur_active_sidechain_sons.at(i) == new_active_sons.at(sidechain).at(i)); + } + } } } @@ -797,28 +888,37 @@ void database::update_active_sons() modify(gpo, [&]( global_property_object& gp ){ gp.active_sons.clear(); gp.active_sons.reserve(new_active_sons.size()); - gp.active_sons.insert(gp.active_sons.end(), new_active_sons.begin(), new_active_sons.end()); - }); + for( const auto& new_active_sidechain_sons : new_active_sons ) { + const auto& sidechain = new_active_sidechain_sons.first; + const auto& _new_active_sidechain_sons = new_active_sidechain_sons.second; - const son_schedule_object& sso = son_schedule_id_type()(*this); - modify(sso, [&](son_schedule_object& _sso) - { - flat_set active_sons; - active_sons.reserve(gpo.active_sons.size()); - std::transform(gpo.active_sons.begin(), gpo.active_sons.end(), - std::inserter(active_sons, active_sons.end()), - [](const son_info& swi) { - return swi.son_id; - }); - _sso.scheduler.update(active_sons); - // similar to witness, produce schedule for sons - if(cur_active_sons.size() == 0 && new_active_sons.size() > 0) - { - witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); - for( size_t i=0; i active_sons; + active_sons.reserve(gpo.active_sons.at(active_sidechain_type).size()); + std::transform(gpo.active_sons.at(active_sidechain_type).cbegin(), gpo.active_sons.at(active_sidechain_type).cend(), + std::inserter(active_sons, active_sons.end()), + [](const son_info& swi) { + return swi.son_id; + }); + _sso.scheduler.update(active_sons); + // similar to witness, produce schedule for sons + if(cur_active_sons.at(active_sidechain_type).size() == 0 && new_active_sons.at(active_sidechain_type).size() > 0) + { + witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); + for( size_t i=0; i& target; }; + struct clear_canary_map { + clear_canary_map(flat_map >& target): target(target){} + ~clear_canary_map() { + for(auto& sidechain_target : target){ + sidechain_target.second.clear(); + } + } + private: + flat_map >& target; + }; clear_canary a(_witness_count_histogram_buffer), b(_committee_count_histogram_buffer), - d(_son_count_histogram_buffer), c(_vote_tally_buffer); + clear_canary_map d{_son_count_histogram_buffer}; perform_son_tasks(); update_top_n_authorities(*this); diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index 084c8e1d..64557bb6 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -74,21 +74,32 @@ witness_id_type database::get_scheduled_witness( uint32_t slot_num )const return wid; } -son_id_type database::get_scheduled_son( uint32_t slot_num )const +unsigned_int database::get_son_schedule_id( sidechain_type type )const +{ + static const map schedule_map = { + { sidechain_type::hive, 0 }, + { sidechain_type::bitcoin, 1 }, + { sidechain_type::ethereum, 2 } + }; + + return schedule_map.at(type); +} + +son_id_type database::get_scheduled_son( sidechain_type type, uint32_t slot_num )const { son_id_type sid; const global_property_object& gpo = get_global_properties(); if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM) { const dynamic_global_property_object& dpo = get_dynamic_global_properties(); - const son_schedule_object& sso = son_schedule_id_type()(*this); + const son_schedule_object& sso = son_schedule_id_type(get_son_schedule_id(type))(*this); uint64_t current_aslot = dpo.current_aslot + slot_num; return sso.current_shuffled_sons[ current_aslot % sso.current_shuffled_sons.size() ]; } if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM && slot_num != 0 ) { - const son_schedule_object& sso = son_schedule_id_type()(*this); + const son_schedule_object& sso = son_schedule_id_type(get_son_schedule_id(type))(*this); // ask the near scheduler who goes in the given slot bool slot_is_near = sso.scheduler.get_slot(slot_num-1, sid); if(! slot_is_near) @@ -191,36 +202,41 @@ void database::update_witness_schedule() void database::update_son_schedule() { - const son_schedule_object& sso = son_schedule_id_type()(*this); const global_property_object& gpo = get_global_properties(); - if( head_block_num() % gpo.active_sons.size() == 0 ) + for(const auto& active_sidechain_type : active_sidechain_types) { - modify( sso, [&]( son_schedule_object& _sso ) + const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(active_sidechain_type))); + if( head_block_num() % gpo.active_sons.at(active_sidechain_type).size() == 0) { - _sso.current_shuffled_sons.clear(); - _sso.current_shuffled_sons.reserve( gpo.active_sons.size() ); - - for( const son_info& w : gpo.active_sons ) - _sso.current_shuffled_sons.push_back( w.son_id ); - - auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32; - for( uint32_t i = 0; i < _sso.current_shuffled_sons.size(); ++i ) + modify( sidechain_sso, [&]( son_schedule_object& _sso ) { - /// High performance random generator - /// http://xorshift.di.unimi.it/ - uint64_t k = now_hi + uint64_t(i)*2685821657736338717ULL; - k ^= (k >> 12); - k ^= (k << 25); - k ^= (k >> 27); - k *= 2685821657736338717ULL; + _sso.current_shuffled_sons.clear(); + _sso.current_shuffled_sons.reserve( gpo.active_sons.at(active_sidechain_type).size() ); - uint32_t jmax = _sso.current_shuffled_sons.size() - i; - uint32_t j = i + k%jmax; - std::swap( _sso.current_shuffled_sons[i], - _sso.current_shuffled_sons[j] ); - } - }); + for ( const son_info &w : gpo.active_sons.at(active_sidechain_type) ) { + _sso.current_shuffled_sons.push_back(w.son_id); + } + + auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32; + + for (uint32_t i = 0; i < _sso.current_shuffled_sons.size(); ++i) + { + /// High performance random generator + /// http://xorshift.di.unimi.it/ + uint64_t k = now_hi + uint64_t(i) * 2685821657736338717ULL; + k ^= (k >> 12); + k ^= (k << 25); + k ^= (k >> 27); + k *= 2685821657736338717ULL; + + uint32_t jmax = _sso.current_shuffled_sons.size() - i; + uint32_t j = i + k % jmax; + std::swap(_sso.current_shuffled_sons[i], + _sso.current_shuffled_sons[j]); + } + }); + } } } @@ -309,7 +325,15 @@ void database::update_son_schedule(const signed_block& next_block) auto start = fc::time_point::now(); const global_property_object& gpo = get_global_properties(); const son_schedule_object& sso = get(son_schedule_id_type()); - uint32_t schedule_needs_filled = gpo.active_sons.size(); + const flat_map schedule_needs_filled = [&gpo]() + { + flat_map schedule_needs_filled; + for(const auto& sidechain_active_sons : gpo.active_sons) + { + schedule_needs_filled[sidechain_active_sons.first] = sidechain_active_sons.second.size(); + } + return schedule_needs_filled; + }(); uint32_t schedule_slot = get_slot_at_time(next_block.timestamp); // We shouldn't be able to generate _pending_block with timestamp @@ -319,48 +343,52 @@ void database::update_son_schedule(const signed_block& next_block) assert( schedule_slot > 0 ); - son_id_type first_son; - bool slot_is_near = sso.scheduler.get_slot( schedule_slot-1, first_son ); - - son_id_type son; - const dynamic_global_property_object& dpo = get_dynamic_global_properties(); assert( dpo.random.data_size() == witness_scheduler_rng::seed_length ); assert( witness_scheduler_rng::seed_length == sso.rng_seed.size() ); - modify(sso, [&](son_schedule_object& _sso) + for(const auto& active_sidechain_type : active_sidechain_types) { - _sso.slots_since_genesis += schedule_slot; - witness_scheduler_rng rng(sso.rng_seed.data, _sso.slots_since_genesis); + const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(active_sidechain_type))); + son_id_type first_son; + bool slot_is_near = sidechain_sso.scheduler.get_slot( schedule_slot-1, first_son ); + son_id_type son_id; - _sso.scheduler._min_token_count = std::max(int(gpo.active_sons.size()) / 2, 1); + modify(sidechain_sso, [&](son_schedule_object& _sso) + { + _sso.slots_since_genesis += schedule_slot; + witness_scheduler_rng rng(_sso.rng_seed.data, _sso.slots_since_genesis); + + _sso.scheduler._min_token_count = std::max(int(gpo.active_sons.at(active_sidechain_type).size()) / 2, 1); + + if( slot_is_near ) + { + uint32_t drain = schedule_slot; + while( drain > 0 ) + { + if( _sso.scheduler.size() == 0 ) + break; + _sso.scheduler.consume_schedule(); + --drain; + } + } + else + { + _sso.scheduler.reset_schedule( first_son ); + } + while( !_sso.scheduler.get_slot(schedule_needs_filled.at(active_sidechain_type), son_id) ) + { + if( _sso.scheduler.produce_schedule(rng) & emit_turn ) + memcpy(_sso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size()); + } + _sso.last_scheduling_block = next_block.block_num(); + _sso.recent_slots_filled = ( + (_sso.recent_slots_filled << 1) + + 1) << (schedule_slot - 1); + }); + } - if( slot_is_near ) - { - uint32_t drain = schedule_slot; - while( drain > 0 ) - { - if( _sso.scheduler.size() == 0 ) - break; - _sso.scheduler.consume_schedule(); - --drain; - } - } - else - { - _sso.scheduler.reset_schedule( first_son ); - } - while( !_sso.scheduler.get_slot(schedule_needs_filled, son) ) - { - if( _sso.scheduler.produce_schedule(rng) & emit_turn ) - memcpy(_sso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size()); - } - _sso.last_scheduling_block = next_block.block_num(); - _sso.recent_slots_filled = ( - (_sso.recent_slots_filled << 1) - + 1) << (schedule_slot - 1); - }); auto end = fc::time_point::now(); static uint64_t total_time = 0; static uint64_t calls = 0; diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index f62df938..eeb25167 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -245,7 +245,16 @@ namespace graphene { namespace chain { witness_id_type get_scheduled_witness(uint32_t slot_num)const; /** - * @brief Get the son scheduled for block production in a slot. + * @brief Get son schedule id for the given sidechain_type. + * + * type sidechain_type we getting schedule. + * + * returns Id of the schedule object. + */ + unsigned_int get_son_schedule_id(sidechain_type type)const; + + /** + * @brief Get the bitcoin or hive son scheduled for block production in a slot. * * slot_num always corresponds to a time in the future. * @@ -258,7 +267,7 @@ namespace graphene { namespace chain { * * Passing slot_num == 0 returns GRAPHENE_NULL_WITNESS */ - son_id_type get_scheduled_son(uint32_t slot_num)const; + son_id_type get_scheduled_son(sidechain_type type, uint32_t slot_num)const; /** * Get the time at which the given slot occurs. @@ -313,7 +322,7 @@ namespace graphene { namespace chain { fc::optional create_son_deregister_proposal( son_id_type son_id, account_id_type paying_son ); signed_transaction create_signed_transaction( const fc::ecc::private_key& signing_private_key, const operation& op ); bool is_son_dereg_valid( son_id_type son_id ); - bool is_son_active( son_id_type son_id ); + bool is_son_active( sidechain_type type, son_id_type son_id ); bool is_asset_creation_allowed(const string& symbol); time_point_sec head_block_time()const; @@ -517,6 +526,9 @@ namespace graphene { namespace chain { template vector> sort_votable_objects(size_t count)const; + template + vector> sort_votable_objects(sidechain_type sidechain, size_t count)const; + //////////////////// db_block.cpp //////////////////// public: @@ -571,13 +583,14 @@ namespace graphene { namespace chain { void perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props); void update_active_witnesses(); void update_active_committee_members(); - void update_son_metrics( const vector& 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 vector& cur_active_sons, const vector& new_active_sons ); - void update_son_wallet( const vector& 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: @@ -616,11 +629,17 @@ namespace graphene { namespace chain { uint16_t _current_op_in_trx = 0; uint32_t _current_virtual_op = 0; - vector _vote_tally_buffer; - vector _witness_count_histogram_buffer; - vector _committee_count_histogram_buffer; - vector _son_count_histogram_buffer; - uint64_t _total_voting_stake; + vector _vote_tally_buffer; + vector _witness_count_histogram_buffer; + 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){ + son_count_histogram_buffer[active_sidechain_type] = vector{}; + } + return son_count_histogram_buffer; + }(); + uint64_t _total_voting_stake; flat_map _checkpoints; diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index 53bdec08..71aba1dd 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -49,10 +49,18 @@ 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 - vector 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) + { + active_sons[active_sidechain_type] = vector(); + } + return active_sons; + }(); // n.b. witness scheduling is done by witness_schedule object }; diff --git a/libraries/chain/include/graphene/chain/protocol/account.hpp b/libraries/chain/include/graphene/chain/protocol/account.hpp index c6de2047..9c4c16d5 100644 --- a/libraries/chain/include/graphene/chain/protocol/account.hpp +++ b/libraries/chain/include/graphene/chain/protocol/account.hpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace graphene { namespace chain { @@ -39,7 +40,15 @@ namespace graphene { namespace chain { { struct ext { - optional< uint16_t > num_son = 0; + /// The number of active son members this account votes the blockchain should appoint + /// Must not exceed the actual number of son members voted for in @ref votes + optional< flat_map > num_son = []{ + flat_map num_son; + for(const auto& active_sidechain_type : active_sidechain_types){ + num_son[active_sidechain_type] = 0; + } + return num_son; + }(); }; /// The memo key is the key this account will typically use to encrypt/sign transaction memos and other non- @@ -57,14 +66,11 @@ namespace graphene { namespace chain { /// The number of active committee members this account votes the blockchain should appoint /// Must not exceed the actual number of committee members voted for in @ref votes uint16_t num_committee = 0; - /// The number of active son members this account votes the blockchain should appoint - /// Must not exceed the actual number of son members voted for in @ref votes - uint16_t num_son() const { return extensions.value.num_son.valid() ? *extensions.value.num_son : 0; } /// This is the list of vote IDs this account votes for. The weight of these votes is determined by this /// account's balance of core asset. flat_set votes; extension< ext > extensions; - + /// Whether this account is voting inline bool is_voting() const { @@ -249,7 +255,7 @@ namespace graphene { namespace chain { */ struct account_upgrade_operation : public base_operation { - struct fee_parameters_type { + struct fee_parameters_type { uint64_t membership_annual_fee = 2000 * GRAPHENE_BLOCKCHAIN_PRECISION; uint64_t membership_lifetime_fee = 10000 * GRAPHENE_BLOCKCHAIN_PRECISION; ///< the cost to upgrade to a lifetime member }; @@ -294,7 +300,7 @@ namespace graphene { namespace chain { } } // graphene::chain -FC_REFLECT(graphene::chain::account_options::ext, (num_son) ) +FC_REFLECT(graphene::chain::account_options::ext, (num_son)) FC_REFLECT(graphene::chain::account_options, (memo_key)(voting_account)(num_witness)(num_committee)(votes)(extensions)) // FC_REFLECT_TYPENAME( graphene::chain::account_whitelist_operation::account_listing) FC_REFLECT_ENUM( graphene::chain::account_whitelist_operation::account_listing, diff --git a/libraries/chain/include/graphene/chain/protocol/son_wallet.hpp b/libraries/chain/include/graphene/chain/protocol/son_wallet.hpp index 5194bed2..75c3db85 100644 --- a/libraries/chain/include/graphene/chain/protocol/son_wallet.hpp +++ b/libraries/chain/include/graphene/chain/protocol/son_wallet.hpp @@ -11,7 +11,7 @@ namespace graphene { namespace chain { asset fee; account_id_type payer; - vector sons; + flat_map > sons; account_id_type fee_payer()const { return payer; } share_type calculate_fee(const fee_parameters_type& k)const { return 0; } diff --git a/libraries/chain/include/graphene/chain/protocol/vote.hpp b/libraries/chain/include/graphene/chain/protocol/vote.hpp index 8a46954d..913f6c5b 100644 --- a/libraries/chain/include/graphene/chain/protocol/vote.hpp +++ b/libraries/chain/include/graphene/chain/protocol/vote.hpp @@ -59,7 +59,9 @@ struct vote_id_type committee, witness, worker, - son, + son_bitcoin, + son_hive, + son_ethereum, VOTE_TYPE_COUNT }; @@ -144,7 +146,7 @@ void from_variant( const fc::variant& var, graphene::chain::vote_id_type& vo, ui FC_REFLECT_TYPENAME( fc::flat_set ) -FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(son)(VOTE_TYPE_COUNT) ) +FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(son_bitcoin)(son_hive)(son_ethereum)(VOTE_TYPE_COUNT) ) FC_REFLECT( graphene::chain::vote_id_type, (content) ) GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vote_id_type ) diff --git a/libraries/chain/include/graphene/chain/sidechain_address_object.hpp b/libraries/chain/include/graphene/chain/sidechain_address_object.hpp index b8aa07c6..73be44d5 100644 --- a/libraries/chain/include/graphene/chain/sidechain_address_object.hpp +++ b/libraries/chain/include/graphene/chain/sidechain_address_object.hpp @@ -31,7 +31,7 @@ namespace graphene { namespace chain { time_point_sec expires; sidechain_address_object() : - sidechain(sidechain_type::bitcoin), + sidechain(sidechain_type::bitcoin), //! FIXME - bitcoin ??? deposit_public_key(""), deposit_address(""), withdraw_public_key(""), diff --git a/libraries/chain/include/graphene/chain/sidechain_defs.hpp b/libraries/chain/include/graphene/chain/sidechain_defs.hpp index 7f986f96..00548843 100644 --- a/libraries/chain/include/graphene/chain/sidechain_defs.hpp +++ b/libraries/chain/include/graphene/chain/sidechain_defs.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include namespace graphene { namespace chain { @@ -13,12 +14,14 @@ enum class sidechain_type { hive }; +static const std::set active_sidechain_types = {sidechain_type::bitcoin, sidechain_type::hive, sidechain_type::ethereum}; + } } FC_REFLECT_ENUM(graphene::chain::sidechain_type, - (unknown) - (bitcoin) - (ethereum) - (eos) - (hive) - (peerplays) ) + (unknown) + (bitcoin) + (ethereum) + (eos) + (hive) + (peerplays) ) \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/son_info.hpp b/libraries/chain/include/graphene/chain/son_info.hpp index 2bfecac4..75e58319 100644 --- a/libraries/chain/include/graphene/chain/son_info.hpp +++ b/libraries/chain/include/graphene/chain/son_info.hpp @@ -14,26 +14,15 @@ namespace graphene { namespace chain { son_id_type son_id; weight_type weight = 0; public_key_type signing_key; - flat_map sidechain_public_keys; + string public_key; - bool operator==(const son_info& rhs) { + bool operator==(const son_info& rhs) const { bool son_sets_equal = (son_id == rhs.son_id) && (weight == rhs.weight) && (signing_key == rhs.signing_key) && - (sidechain_public_keys.size() == rhs.sidechain_public_keys.size()); + (public_key == rhs.public_key); - if (son_sets_equal) { - bool sidechain_public_keys_equal = true; - for (size_t i = 0; i < sidechain_public_keys.size(); i++) { - const auto lhs_scpk = sidechain_public_keys.nth(i); - const auto rhs_scpk = rhs.sidechain_public_keys.nth(i); - sidechain_public_keys_equal = sidechain_public_keys_equal && - (lhs_scpk->first == rhs_scpk->first) && - (lhs_scpk->second == rhs_scpk->second); - } - son_sets_equal = son_sets_equal && sidechain_public_keys_equal; - } return son_sets_equal; } }; @@ -44,4 +33,4 @@ FC_REFLECT( graphene::chain::son_info, (son_id) (weight) (signing_key) - (sidechain_public_keys) ) + (public_key) ) diff --git a/libraries/chain/include/graphene/chain/son_object.hpp b/libraries/chain/include/graphene/chain/son_object.hpp index d0b74e79..afe7230f 100644 --- a/libraries/chain/include/graphene/chain/son_object.hpp +++ b/libraries/chain/include/graphene/chain/son_object.hpp @@ -35,15 +35,15 @@ namespace graphene { namespace chain { // Transactions signed since the last son payouts flat_map txs_signed; // Total Voted Active time i.e. duration selected as part of voted active SONs - uint64_t total_voted_time = 0; + flat_map total_voted_time; // Total Downtime barring the current down time in seconds, used for stats to present to user - uint64_t total_downtime = 0; + flat_map total_downtime; // Current Interval Downtime since last maintenance - uint64_t current_interval_downtime = 0; + flat_map current_interval_downtime; // Down timestamp, if son status is in_maintenance use this - fc::time_point_sec last_down_timestamp; + flat_map last_down_timestamp; // Last Active heartbeat timestamp - fc::time_point_sec last_active_timestamp; + flat_map last_active_timestamp; // Deregistered Timestamp fc::time_point_sec deregistered_timestamp; // Total sidechain transactions reported by SON network while SON was active @@ -64,23 +64,38 @@ namespace graphene { namespace chain { static const uint8_t type_id = son_object_type; account_id_type son_account; - vote_id_type vote_id; - uint64_t total_votes = 0; + flat_map sidechain_vote_ids; + flat_map total_votes; string url; vesting_balance_id_type deposit; public_key_type signing_key; vesting_balance_id_type pay_vb; son_statistics_id_type statistics; - son_status status = son_status::inactive; + flat_map statuses = []() + { + flat_map statuses; + for(const auto& active_sidechain_type : active_sidechain_types) + { + statuses[active_sidechain_type] = son_status::inactive; + } + return statuses; + }(); 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; + + 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); } }; struct by_account; - struct by_vote_id; + struct by_vote_id_bitcoin; + struct by_vote_id_hive; + struct by_vote_id_ethereum; using son_multi_index_type = multi_index_container< son_object, indexed_by< @@ -90,8 +105,14 @@ namespace graphene { namespace chain { ordered_unique< tag, member >, - ordered_unique< tag, - member + ordered_unique< tag, + const_mem_fun + >, + ordered_unique< tag, + const_mem_fun + >, + ordered_unique< tag, + const_mem_fun > > >; @@ -117,14 +138,14 @@ FC_REFLECT_ENUM(graphene::chain::son_status, (inactive)(active)(request_maintena FC_REFLECT_DERIVED( graphene::chain::son_object, (graphene::db::object), (son_account) - (vote_id) + (sidechain_vote_ids) (total_votes) (url) (deposit) (signing_key) (pay_vb) (statistics) - (status) + (statuses) (sidechain_public_keys) ) diff --git a/libraries/chain/include/graphene/chain/son_wallet_object.hpp b/libraries/chain/include/graphene/chain/son_wallet_object.hpp index 315def33..63b546ea 100644 --- a/libraries/chain/include/graphene/chain/son_wallet_object.hpp +++ b/libraries/chain/include/graphene/chain/son_wallet_object.hpp @@ -21,7 +21,7 @@ namespace graphene { namespace chain { time_point_sec expires; flat_map addresses; - vector sons; + flat_map > sons; }; struct by_valid_from; diff --git a/libraries/chain/include/graphene/chain/voters_info.hpp b/libraries/chain/include/graphene/chain/voters_info.hpp index 53b0e74a..86f3e9cc 100644 --- a/libraries/chain/include/graphene/chain/voters_info.hpp +++ b/libraries/chain/include/graphene/chain/voters_info.hpp @@ -19,11 +19,11 @@ namespace graphene { namespace chain { * @ingroup object */ struct voters_info { - optional voters_for_committee_member; - optional voters_for_witness; - optional > voters_for_workers; - optional > voters_against_workers; - optional voters_for_son; + optional voters_for_committee_member; + optional voters_for_witness; + optional > voters_for_workers; + optional > voters_against_workers; + optional > voters_for_son; }; } } // graphene::chain @@ -37,4 +37,4 @@ FC_REFLECT( graphene::chain::voters_info, (voters_for_witness) (voters_for_workers) (voters_against_workers) - (voters_for_son) ) \ No newline at end of file + (voters_for_son)) \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/votes_info.hpp b/libraries/chain/include/graphene/chain/votes_info.hpp index 0a515589..f405d83a 100644 --- a/libraries/chain/include/graphene/chain/votes_info.hpp +++ b/libraries/chain/include/graphene/chain/votes_info.hpp @@ -19,11 +19,11 @@ namespace graphene { namespace chain { * @ingroup object */ struct votes_info { - optional< vector< votes_info_object > > votes_for_committee_members; - optional< vector< votes_info_object > > votes_for_witnesses; - optional< vector< votes_info_object > > votes_for_workers; - optional< vector< votes_info_object > > votes_against_workers; - optional< vector< votes_info_object > > votes_for_sons; + optional< vector< votes_info_object > > votes_for_committee_members; + optional< vector< votes_info_object > > votes_for_witnesses; + optional< vector< votes_info_object > > votes_for_workers; + optional< vector< votes_info_object > > votes_against_workers; + optional< flat_map > > votes_for_sons; }; } } // graphene::chain @@ -37,4 +37,4 @@ FC_REFLECT( graphene::chain::votes_info, (votes_for_witnesses) (votes_for_workers) (votes_against_workers) - (votes_for_sons) ) \ No newline at end of file + (votes_for_sons)) \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/witness_schedule_object.hpp b/libraries/chain/include/graphene/chain/witness_schedule_object.hpp index 2eff563f..945b218d 100644 --- a/libraries/chain/include/graphene/chain/witness_schedule_object.hpp +++ b/libraries/chain/include/graphene/chain/witness_schedule_object.hpp @@ -96,7 +96,7 @@ class son_schedule_object : public graphene::db::abstract_object current_shuffled_sons; + vector current_shuffled_sons; son_scheduler scheduler; uint32_t last_scheduling_block; diff --git a/libraries/chain/include/graphene/chain/witness_scheduler.hpp b/libraries/chain/include/graphene/chain/witness_scheduler.hpp index 42dfe149..40e0e1d2 100644 --- a/libraries/chain/include/graphene/chain/witness_scheduler.hpp +++ b/libraries/chain/include/graphene/chain/witness_scheduler.hpp @@ -162,8 +162,12 @@ class generic_witness_scheduler _schedule.pop_front(); auto it = _lame_duck.find( result ); - if( it != _lame_duck.end() ) - _lame_duck.erase( it ); + if( it != _lame_duck.end() ) { + set< WitnessID > removal_set; + removal_set.insert(*it); + remove_all( removal_set ); + _lame_duck.erase(it); + } if( debug ) check_invariant(); return result; } @@ -389,7 +393,7 @@ class generic_witness_scheduler // scheduled std::deque < WitnessID > _schedule; - // in _schedule, but not to be replaced + // in _schedule, but must be removed set< WitnessID > _lame_duck; }; diff --git a/libraries/chain/protocol/account.cpp b/libraries/chain/protocol/account.cpp index b980998c..a1b7994e 100644 --- a/libraries/chain/protocol/account.cpp +++ b/libraries/chain/protocol/account.cpp @@ -174,22 +174,31 @@ void account_options::validate() const { auto needed_witnesses = num_witness; auto needed_committee = num_committee; - auto needed_sons = num_son(); + FC_ASSERT( extensions.value.num_son.valid() , "Invalid son number" ); + flat_map needed_sons = *extensions.value.num_son; for( vote_id_type id : votes ) if( id.type() == vote_id_type::witness && needed_witnesses ) --needed_witnesses; else if ( id.type() == vote_id_type::committee && needed_committee ) --needed_committee; - else if ( id.type() == vote_id_type::son && needed_sons ) - --needed_sons; + else if ( id.type() == vote_id_type::son_bitcoin && needed_sons[sidechain_type::bitcoin] ) + --needed_sons[sidechain_type::bitcoin]; + else if ( id.type() == vote_id_type::son_hive && needed_sons[sidechain_type::hive] ) + --needed_sons[sidechain_type::hive]; + 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 == 0, - "May not specify fewer SONs than the number voted for."); + FC_ASSERT( needed_sons[sidechain_type::bitcoin] == 0, + "May not specify fewer Bitcoin SONs than the number voted for."); + FC_ASSERT( needed_sons[sidechain_type::hive] == 0, + "May not specify fewer Hive SONs than the number voted for."); + 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_address_evaluator.cpp b/libraries/chain/sidechain_address_evaluator.cpp index 625ef2f0..bd97fef5 100644 --- a/libraries/chain/sidechain_address_evaluator.cpp +++ b/libraries/chain/sidechain_address_evaluator.cpp @@ -47,7 +47,7 @@ void_result update_sidechain_address_evaluator::do_evaluate(const sidechain_addr { try { const auto& sidx = db().get_index_type().indices().get(); const auto& son_obj = sidx.find(op.payer); - FC_ASSERT( son_obj != sidx.end() && db().is_son_active(son_obj->id), "Non active SON trying to update deposit address object" ); + FC_ASSERT( son_obj != sidx.end() && db().is_son_active(op.sidechain, son_obj->id), "Non active SON trying to update deposit address object" ); const auto& sdpke_idx = db().get_index_type().indices().get(); FC_ASSERT( op.deposit_address.valid() && op.deposit_public_key.valid() && op.deposit_address_data.valid(), "Update operation by SON is not valid"); FC_ASSERT( (*op.deposit_address).length() > 0 && (*op.deposit_public_key).length() > 0 && (*op.deposit_address_data).length() > 0, "SON should create a valid deposit address with valid deposit public key"); diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index 776eb065..5016ea0f 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -38,14 +38,20 @@ void_result create_son_evaluator::do_evaluate(const son_create_operation& op) object_id_type create_son_evaluator::do_apply(const son_create_operation& op) { try { - vote_id_type vote_id; - db().modify(db().get_global_properties(), [&vote_id](global_property_object& p) { - vote_id = get_next_vote_id(p, vote_id_type::son); + vote_id_type vote_id_bitcoin; + vote_id_type vote_id_hive; + 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); }); const auto& new_son_object = db().create( [&]( son_object& obj ){ obj.son_account = op.owner_account; - obj.vote_id = vote_id; + obj.sidechain_vote_ids[sidechain_type::bitcoin] = vote_id_bitcoin; + obj.sidechain_vote_ids[sidechain_type::hive] = vote_id_hive; + obj.sidechain_vote_ids[sidechain_type::ethereum] = vote_id_ethereum; obj.url = op.url; obj.deposit = op.deposit; obj.signing_key = op.signing_key; @@ -94,7 +100,8 @@ object_id_type update_son_evaluator::do_apply(const son_update_operation& op) if(op.new_signing_key.valid()) so.signing_key = *op.new_signing_key; if(op.new_sidechain_public_keys.valid()) so.sidechain_public_keys = *op.new_sidechain_public_keys; if(op.new_pay_vb.valid()) so.pay_vb = *op.new_pay_vb; - if(so.status == son_status::deregistered) so.status = son_status::inactive; + for(auto& status : so.statuses) + if(status.second == son_status::deregistered) status.second = son_status::inactive; }); } return op.son_id; @@ -127,7 +134,8 @@ void_result deregister_son_evaluator::do_apply(const son_deregister_operation& o }); db().modify(*son, [&op](son_object &so) { - so.status = son_status::deregistered; + for(auto& status : so.statuses) + status.second = son_status::deregistered; }); auto stats_obj = ss_idx.find(son->statistics); @@ -144,18 +152,28 @@ void_result son_heartbeat_evaluator::do_evaluate(const son_heartbeat_operation& { try { FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); // can be removed after HF date pass const auto& idx = db().get_index_type().indices().get(); - auto itr = idx.find(op.son_id); + const auto itr = idx.find(op.son_id); FC_ASSERT( itr != idx.end() ); FC_ASSERT(itr->son_account == op.owner_account); auto stats = itr->statistics( db() ); // Inactive SONs need not send heartbeats - FC_ASSERT((itr->status == son_status::active) || (itr->status == son_status::in_maintenance) || (itr->status == son_status::request_maintenance), "Inactive SONs need not send heartbeats"); + bool status_need_to_send_heartbeats = false; + for(const auto& status : itr->statuses) + { + if( (status.second == son_status::active) || (status.second == son_status::in_maintenance) || (status.second == son_status::request_maintenance) ) + status_need_to_send_heartbeats = true; + } + FC_ASSERT(status_need_to_send_heartbeats, "Inactive SONs need not send heartbeats"); // Account for network delays fc::time_point_sec min_ts = db().head_block_time() - fc::seconds(5 * db().block_interval()); // Account for server ntp sync difference fc::time_point_sec max_ts = db().head_block_time() + fc::seconds(5 * db().block_interval()); - FC_ASSERT(op.ts > stats.last_active_timestamp, "Heartbeat sent without waiting minimum time"); - FC_ASSERT(op.ts > stats.last_down_timestamp, "Heartbeat sent is invalid can't be <= last down timestamp"); + for(const auto& active_sidechain_type : active_sidechain_types) { + if(stats.last_active_timestamp.contains(active_sidechain_type)) + FC_ASSERT(op.ts > stats.last_active_timestamp.at(active_sidechain_type), "Heartbeat sent for sidechain = ${sidechain} without waiting minimum time", ("sidechain", active_sidechain_type)); + if(stats.last_down_timestamp.contains(active_sidechain_type)) + FC_ASSERT(op.ts > stats.last_down_timestamp.at(active_sidechain_type), "Heartbeat sent for sidechain = ${sidechain} is invalid can't be <= last down timestamp", ("sidechain", active_sidechain_type)); + } FC_ASSERT(op.ts >= min_ts, "Heartbeat ts is behind the min threshold"); FC_ASSERT(op.ts <= max_ts, "Heartbeat ts is above the max threshold"); return void_result(); @@ -164,44 +182,48 @@ void_result son_heartbeat_evaluator::do_evaluate(const son_heartbeat_operation& object_id_type son_heartbeat_evaluator::do_apply(const son_heartbeat_operation& op) { try { const auto& idx = db().get_index_type().indices().get(); - auto itr = idx.find(op.son_id); + const auto itr = idx.find(op.son_id); if(itr != idx.end()) { const global_property_object& gpo = db().get_global_properties(); - vector active_son_ids; - active_son_ids.reserve(gpo.active_sons.size()); - std::transform(gpo.active_sons.begin(), gpo.active_sons.end(), - std::inserter(active_son_ids, active_son_ids.end()), - [](const son_info& swi) { - return swi.son_id; - }); - auto it_son = std::find(active_son_ids.begin(), active_son_ids.end(), op.son_id); - bool is_son_active = true; + for(const auto& active_sidechain_sons : gpo.active_sons) { + const auto& sidechain = active_sidechain_sons.first; + const auto& active_sons = active_sidechain_sons.second; - if(it_son == active_son_ids.end()) { - is_son_active = false; - } + vector active_son_ids; + active_son_ids.reserve(active_sons.size()); + std::transform(active_sons.cbegin(), active_sons.cend(), + std::inserter(active_son_ids, active_son_ids.end()), + [](const son_info &swi) { + return swi.son_id; + }); - if(itr->status == son_status::in_maintenance) { - db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso ) - { - sso.current_interval_downtime += op.ts.sec_since_epoch() - sso.last_down_timestamp.sec_since_epoch(); - sso.last_active_timestamp = op.ts; - } ); + const auto it_son = std::find(active_son_ids.begin(), active_son_ids.end(), op.son_id); + bool is_son_active = true; - db().modify(*itr, [&is_son_active](son_object &so) { - if(is_son_active) { - so.status = son_status::active; - } else { - so.status = son_status::inactive; - } - }); - } else if ((itr->status == son_status::active) || (itr->status == son_status::request_maintenance)) { - db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso ) - { - sso.last_active_timestamp = op.ts; - } ); + if (it_son == active_son_ids.end()) { + is_son_active = false; + } + + if (itr->statuses.at(sidechain) == son_status::in_maintenance) { + db().modify(itr->statistics(db()), [&](son_statistics_object &sso) { + sso.current_interval_downtime[sidechain] += op.ts.sec_since_epoch() - sso.last_down_timestamp.at(sidechain).sec_since_epoch(); + sso.last_active_timestamp[sidechain] = op.ts; + }); + + db().modify(*itr, [&is_son_active, &sidechain](son_object &so) { + if (is_son_active) { + so.statuses[sidechain] = son_status::active; + } else { + so.statuses[sidechain] = son_status::inactive; + } + }); + } else if ((itr->statuses.at(sidechain) == son_status::active) || (itr->statuses.at(sidechain) == son_status::request_maintenance)) { + db().modify(itr->statistics(db()), [&](son_statistics_object &sso) { + sso.last_active_timestamp[sidechain] = op.ts; + }); + } } } return op.son_id; @@ -213,29 +235,40 @@ void_result son_report_down_evaluator::do_evaluate(const son_report_down_operati FC_ASSERT(op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer."); const auto& idx = db().get_index_type().indices().get(); FC_ASSERT( idx.find(op.son_id) != idx.end() ); - auto itr = idx.find(op.son_id); - auto stats = itr->statistics( db() ); - FC_ASSERT(itr->status == son_status::active || itr->status == son_status::request_maintenance, "Inactive/Deregistered/in_maintenance SONs cannot be reported on as down"); - FC_ASSERT(op.down_ts >= stats.last_active_timestamp, "down_ts should be greater than last_active_timestamp"); + const auto itr = idx.find(op.son_id); + const auto stats = itr->statistics( db() ); + bool status_need_to_report_down = false; + for(const auto& status : itr->statuses) + { + if( (status.second == son_status::active) || (status.second == son_status::request_maintenance) ) + status_need_to_report_down = true; + } + FC_ASSERT(status_need_to_report_down, "Inactive/Deregistered/in_maintenance SONs cannot be reported on as down"); + for(const auto& active_sidechain_type : active_sidechain_types) { + FC_ASSERT(op.down_ts >= stats.last_active_timestamp.at(active_sidechain_type), "sidechain = ${sidechain} down_ts should be greater than last_active_timestamp", ("sidechain", active_sidechain_type)); + } return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } object_id_type son_report_down_evaluator::do_apply(const son_report_down_operation& op) { try { const auto& idx = db().get_index_type().indices().get(); - auto itr = idx.find(op.son_id); + const auto itr = idx.find(op.son_id); if(itr != idx.end()) { - if ((itr->status == son_status::active) || (itr->status == son_status::request_maintenance)) { - db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso ) - { - sso.last_down_timestamp = op.down_ts; - }); + for( const auto& status : itr->statuses ) { + const auto& sidechain = status.first; - db().modify(*itr, [&op](son_object &so) { - so.status = son_status::in_maintenance; - }); - } + if ((status.second == son_status::active) || (status.second == son_status::request_maintenance)) { + db().modify(*itr, [&sidechain](son_object &so) { + so.statuses[sidechain] = son_status::in_maintenance; + }); + + db().modify(itr->statistics(db()), [&](son_statistics_object &sso) { + sso.last_down_timestamp[sidechain] = op.down_ts; + }); + } + } } return op.son_id; } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -249,9 +282,19 @@ void_result son_maintenance_evaluator::do_evaluate(const son_maintenance_operati FC_ASSERT( itr != idx.end() ); // Inactive SONs can't go to maintenance, toggle between active and request_maintenance states if(op.request_type == son_maintenance_request_type::request_maintenance) { - FC_ASSERT(itr->status == son_status::active, "Inactive SONs can't request for maintenance"); - } else if(op.request_type == son_maintenance_request_type::cancel_request_maintenance) { - FC_ASSERT(itr->status == son_status::request_maintenance, "Only maintenance requested SONs can cancel the request"); + bool status_active = false; + for(const auto& status : itr->statuses) { + if( (status.second == son_status::active) ) + status_active = true; + } + FC_ASSERT(status_active, "Inactive SONs can't request for maintenance"); + } else if(op.request_type == son_maintenance_request_type::cancel_request_maintenance) { + bool status_request_maintenance = false; + for(const auto& status : itr->statuses) { + if( (status.second == son_status::request_maintenance) ) + status_request_maintenance = true; + } + FC_ASSERT(status_request_maintenance, "Only maintenance requested SONs can cancel the request"); } else { FC_ASSERT(false, "Invalid maintenance operation"); } @@ -264,15 +307,33 @@ object_id_type son_maintenance_evaluator::do_apply(const son_maintenance_operati auto itr = idx.find(op.son_id); if(itr != idx.end()) { - if(itr->status == son_status::active && op.request_type == son_maintenance_request_type::request_maintenance) { - db().modify(*itr, [](son_object &so) { - so.status = son_status::request_maintenance; - }); - } else if(itr->status == son_status::request_maintenance && op.request_type == son_maintenance_request_type::cancel_request_maintenance) { - db().modify(*itr, [](son_object &so) { - so.status = son_status::active; - }); - } + bool status_active = false; + for(const auto& status : itr->statuses) { + if( (status.second == son_status::active) ) + status_active = true; + } + if(status_active && op.request_type == son_maintenance_request_type::request_maintenance) { + db().modify(*itr, [](son_object &so) { + for(auto& status : so.statuses) { + status.second = son_status::request_maintenance; + } + }); + } + else + { + bool status_request_maintenance = false; + for(const auto& status : itr->statuses) { + if( (status.second == son_status::request_maintenance) ) + status_request_maintenance = true; + } + if(status_request_maintenance && op.request_type == son_maintenance_request_type::cancel_request_maintenance) { + db().modify(*itr, [](son_object &so) { + for(auto& status : so.statuses) { + status.second = son_status::active; + } + }); + } + } } return op.son_id; } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/chain/son_object.cpp b/libraries/chain/son_object.cpp index c94a6250..e607c103 100644 --- a/libraries/chain/son_object.cpp +++ b/libraries/chain/son_object.cpp @@ -20,6 +20,10 @@ namespace graphene { namespace chain { 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); } return retval; diff --git a/libraries/chain/son_wallet_deposit_evaluator.cpp b/libraries/chain/son_wallet_deposit_evaluator.cpp index f9620282..8d0199d4 100644 --- a/libraries/chain/son_wallet_deposit_evaluator.cpp +++ b/libraries/chain/son_wallet_deposit_evaluator.cpp @@ -23,9 +23,9 @@ void_result create_son_wallet_deposit_evaluator::do_evaluate(const son_wallet_de const auto &swdo_idx = db().get_index_type().indices().get(); const auto swdo = swdo_idx.find(op.sidechain_uid); if (swdo == swdo_idx.end()) { - auto &gpo = db().get_global_properties(); + const auto &gpo = db().get_global_properties(); bool expected = false; - for (auto &si : gpo.active_sons) { + for (auto &si : gpo.active_sons.at(op.sidechain)) { if (op.son_id == si.son_id) { expected = true; break; @@ -78,8 +78,8 @@ object_id_type create_son_wallet_deposit_evaluator::do_apply(const son_wallet_de swdo.peerplays_to = op.peerplays_to; swdo.peerplays_asset = op.peerplays_asset; - auto &gpo = db().get_global_properties(); - for (auto &si : gpo.active_sons) { + const auto &gpo = db().get_global_properties(); + for (auto &si : gpo.active_sons.at(op.sidechain)) { swdo.expected_reports.insert(std::make_pair(si.son_id, si.weight)); auto stats_itr = db().get_index_type().indices().get().find(si.son_id); @@ -142,11 +142,11 @@ void_result process_son_wallet_deposit_evaluator::do_evaluate(const son_wallet_d { try{ FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." ); - FC_ASSERT(db().get_global_properties().active_sons.size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present"); const auto& idx = db().get_index_type().indices().get(); const auto& itr = idx.find(op.son_wallet_deposit_id); FC_ASSERT(itr != idx.end(), "Son wallet deposit not found"); + FC_ASSERT(db().get_global_properties().active_sons.at(itr->sidechain).size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present"); FC_ASSERT(!itr->processed, "Son wallet deposit is already processed"); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/chain/son_wallet_evaluator.cpp b/libraries/chain/son_wallet_evaluator.cpp index 0baed1cb..9b1ff1b7 100644 --- a/libraries/chain/son_wallet_evaluator.cpp +++ b/libraries/chain/son_wallet_evaluator.cpp @@ -20,8 +20,16 @@ void_result recreate_son_wallet_evaluator::do_evaluate(const son_wallet_recreate bool son_sets_equal = (cur_wallet_sons.size() == new_wallet_sons.size()); if (son_sets_equal) { - for( size_t i = 0; i < cur_wallet_sons.size(); i++ ) { - son_sets_equal = son_sets_equal && cur_wallet_sons.at(i) == new_wallet_sons.at(i); + for( const auto& cur_wallet_sidechain_sons : cur_wallet_sons ) { + const auto& sidechain = cur_wallet_sidechain_sons.first; + const auto& _cur_wallet_sidechain_sons = cur_wallet_sidechain_sons.second; + + son_sets_equal = son_sets_equal && (_cur_wallet_sidechain_sons.size() == new_wallet_sons.at(sidechain).size()); + if (son_sets_equal) { + for (size_t i = 0; i < cur_wallet_sons.size(); i++) { + son_sets_equal = son_sets_equal && _cur_wallet_sidechain_sons.at(i) == new_wallet_sons.at(sidechain).at(i); + } + } } } diff --git a/libraries/chain/son_wallet_withdraw_evaluator.cpp b/libraries/chain/son_wallet_withdraw_evaluator.cpp index 2110e49d..ae0a867b 100644 --- a/libraries/chain/son_wallet_withdraw_evaluator.cpp +++ b/libraries/chain/son_wallet_withdraw_evaluator.cpp @@ -23,15 +23,15 @@ void_result create_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_w const auto &swwo_idx = db().get_index_type().indices().get(); const auto swwo = swwo_idx.find(op.peerplays_uid); if (swwo == swwo_idx.end()) { - auto &gpo = db().get_global_properties(); + const auto &gpo = db().get_global_properties(); bool expected = false; - for (auto &si : gpo.active_sons) { + for (auto &si : gpo.active_sons.at(op.sidechain)) { if (op.son_id == si.son_id) { expected = true; break; } } - FC_ASSERT(expected, "Only active SON can create deposit"); + FC_ASSERT(expected, "Only active SON can create withdraw"); } else { bool exactly_the_same = true; exactly_the_same = exactly_the_same && (swwo->sidechain == op.sidechain); @@ -76,8 +76,8 @@ object_id_type create_son_wallet_withdraw_evaluator::do_apply(const son_wallet_w swwo.withdraw_currency = op.withdraw_currency; swwo.withdraw_amount = op.withdraw_amount; - auto &gpo = db().get_global_properties(); - for (auto &si : gpo.active_sons) { + const auto &gpo = db().get_global_properties(); + for (auto &si : gpo.active_sons.at(op.sidechain)) { swwo.expected_reports.insert(std::make_pair(si.son_id, si.weight)); auto stats_itr = db().get_index_type().indices().get().find(si.son_id); @@ -140,11 +140,11 @@ void_result process_son_wallet_withdraw_evaluator::do_evaluate(const son_wallet_ { try{ FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." ); - FC_ASSERT(db().get_global_properties().active_sons.size() >= db().get_chain_properties().immutable_parameters.min_son_count, "Min required voted SONs not present"); const auto& idx = db().get_index_type().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->processed, "Son wallet withdraw is already processed"); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index 687532a1..4f724602 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -3,7 +3,7 @@ file(GLOB_RECURSE HEADERS "include/graphene/peerplays_sidechain/*.hpp") add_library( peerplays_sidechain peerplays_sidechain_plugin.cpp sidechain_api.cpp - sidechain_net_manager.cpp + sidechain_net_handler_factory.cpp sidechain_net_handler.cpp sidechain_net_handler_bitcoin.cpp sidechain_net_handler_ethereum.cpp diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index 668e9639..a75327c3 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -12,7 +13,6 @@ #include #include -#include #include namespace graphene { namespace peerplays_sidechain { namespace ethereum { @@ -24,6 +24,16 @@ const secp256k1_context *eth_context() { //! transaction +base_transaction::base_transaction(const std::string &raw_tx) { +} + +//! transaction + +transaction::transaction(const std::string &raw_tx) : + base_transaction{raw_tx} { + deserialize(raw_tx); +} + const transaction &transaction::sign(const std::string &private_key) const { return *this; } @@ -54,6 +64,20 @@ void transaction::deserialize(const std::string &raw_tx) { //! raw_transaction +raw_transaction::raw_transaction(const std::string &raw_tx) : + base_transaction{raw_tx} { + deserialize(raw_tx); +} + +bytes raw_transaction::hash() const { + bytes hash; + hash.resize(32); + const auto transaction_string = boost::algorithm::unhex(remove_0x(serialize())); + keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data()); + + return hash; +} + signed_transaction raw_transaction::sign(const std::string &private_key) const { //! Prepare signed transaction signed_transaction tr; @@ -64,95 +88,142 @@ signed_transaction raw_transaction::sign(const std::string &private_key) const { tr.value = value; tr.data = data; - //! Calculate keccak hash of transaction - bytes hash; - hash.resize(32); - const auto transaction_string = boost::algorithm::unhex(remove_0x(serialize())); - keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data()); - const bytes priv_key = parse_hex(private_key); int recid = 0; secp256k1_ecdsa_recoverable_signature sig; - FC_ASSERT(secp256k1_ecdsa_sign_recoverable(eth_context(), &sig, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), NULL, NULL)); + FC_ASSERT(secp256k1_ecdsa_sign_recoverable(eth_context(), &sig, (const unsigned char *)hash().data(), (const unsigned char *)priv_key.data(), NULL, NULL)); fc::ecc::compact_signature result; FC_ASSERT(secp256k1_ecdsa_recoverable_signature_serialize_compact(eth_context(), (unsigned char *)result.begin() + 1, &recid, &sig)); - bytes v = bytes{char(recid + from_hex(chain_id) * 2 + 35)}; bytes r; for (int i = 1; i < 33; i++) r.emplace_back((char)result.at(i)); + + bytes v = bytes{char(recid + from_hex(chain_id) * 2 + 35)}; + bytes s; for (int i = 33; i < 65; i++) s.emplace_back((char)result.at(i)); - tr.v = fc::to_hex((char *)&v[0], v.size()); tr.r = fc::to_hex((char *)&r[0], r.size()); + tr.v = fc::to_hex((char *)&v[0], v.size()); tr.s = fc::to_hex((char *)&s[0], s.size()); return tr; } std::string raw_transaction::serialize() const { - rlp_encoder encoder; - const std::string serialized = encoder.encode(remove_0x(nonce)) + - encoder.encode(remove_0x(gas_price)) + - encoder.encode(remove_0x(gas_limit)) + - encoder.encode(remove_0x(to)) + - encoder.encode(remove_0x(value)) + - encoder.encode(remove_0x(data)) + - encoder.encode(remove_0x(chain_id)) + - encoder.encode("") + - encoder.encode(""); + const std::string serialized = rlp_encoder::encode(remove_0x(nonce)) + + rlp_encoder::encode(remove_0x(gas_price)) + + rlp_encoder::encode(remove_0x(gas_limit)) + + rlp_encoder::encode(remove_0x(to)) + + rlp_encoder::encode(remove_0x(value)) + + rlp_encoder::encode(remove_0x(data)) + + rlp_encoder::encode(remove_0x(chain_id)) + + rlp_encoder::encode("") + + rlp_encoder::encode(""); - return add_0x(bytes2hex(encoder.encode_length(serialized.size(), 192) + serialized)); + return add_0x(bytes2hex(rlp_encoder::encode_length(serialized.size(), 192) + serialized)); } void raw_transaction::deserialize(const std::string &raw_tx) { - rlp_decoder decoder; - const auto rlp_array = decoder.decode(remove_0x(raw_tx)); + const auto rlp_array = rlp_decoder::decode(remove_0x(raw_tx)); FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format"); - nonce = add_0x(rlp_array.at(0)); + nonce = !rlp_array.at(0).empty() ? add_0x(rlp_array.at(0)) : add_0x("0"); + boost::algorithm::to_lower(nonce); gas_price = add_0x(rlp_array.at(1)); + boost::algorithm::to_lower(gas_price); gas_limit = add_0x(rlp_array.at(2)); + boost::algorithm::to_lower(gas_limit); to = add_0x(rlp_array.at(3)); - value = add_0x(rlp_array.at(4)); - data = add_0x(rlp_array.at(5)); + boost::algorithm::to_lower(to); + value = !rlp_array.at(4).empty() ? add_0x(rlp_array.at(4)) : add_0x("0"); + boost::algorithm::to_lower(value); + data = !rlp_array.at(5).empty() ? add_0x(rlp_array.at(5)) : ""; + boost::algorithm::to_lower(data); chain_id = add_0x(rlp_array.at(6)); + boost::algorithm::to_lower(chain_id); } //! signed_transaction -std::string signed_transaction::serialize() const { - rlp_encoder encoder; - const std::string serialized = encoder.encode(remove_0x(nonce)) + - encoder.encode(remove_0x(gas_price)) + - encoder.encode(remove_0x(gas_limit)) + - encoder.encode(remove_0x(to)) + - encoder.encode(remove_0x(value)) + - encoder.encode(remove_0x(data)) + - encoder.encode(remove_0x(v)) + - encoder.encode(remove_0x(r)) + - encoder.encode(remove_0x(s)); +signed_transaction::signed_transaction(const std::string &raw_tx) : + base_transaction{raw_tx} { + deserialize(raw_tx); +} - return add_0x(bytes2hex(encoder.encode_length(serialized.size(), 192) + serialized)); +std::string signed_transaction::recover(const std::string &chain_id) const { + fc::ecc::compact_signature input64; + fc::from_hex(r, (char *)&input64.at(1), 32); + fc::from_hex(v, (char *)&input64.at(0), 1); + int recid = input64.at(0) - from_hex(chain_id) * 2 - 35; + fc::from_hex(s, (char *)&input64.at(33), 32); + + secp256k1_ecdsa_recoverable_signature sig; + FC_ASSERT(secp256k1_ecdsa_recoverable_signature_parse_compact(eth_context(), &sig, (const unsigned char *)&input64.data[1], recid)); + + raw_transaction tr; + tr.nonce = nonce; + tr.gas_price = gas_price; + tr.gas_limit = gas_limit; + tr.to = to; + tr.value = value; + tr.data = data; + tr.chain_id = chain_id; + + secp256k1_pubkey rawPubkey; + FC_ASSERT(secp256k1_ecdsa_recover(eth_context(), &rawPubkey, &sig, (const unsigned char *)tr.hash().data())); + + std::array pubkey; + size_t biglen = 65; + FC_ASSERT(secp256k1_ec_pubkey_serialize(eth_context(), pubkey.data(), &biglen, &rawPubkey, SECP256K1_EC_UNCOMPRESSED)); + + const std::string out = std::string(pubkey.begin(), pubkey.end()).substr(1); + bytes hash; + hash.resize(32); + keccak_256((const unsigned char *)out.data(), out.size(), (unsigned char *)hash.data()); + + return add_0x(fc::to_hex((char *)&hash[0], hash.size()).substr(24)); +} + +std::string signed_transaction::serialize() const { + const std::string serialized = rlp_encoder::encode(remove_0x(nonce)) + + rlp_encoder::encode(remove_0x(gas_price)) + + rlp_encoder::encode(remove_0x(gas_limit)) + + rlp_encoder::encode(remove_0x(to)) + + rlp_encoder::encode(remove_0x(value)) + + rlp_encoder::encode(remove_0x(data)) + + rlp_encoder::encode(remove_0x(v)) + + rlp_encoder::encode(remove_0x(r)) + + rlp_encoder::encode(remove_0x(s)); + + return add_0x(bytes2hex(rlp_encoder::encode_length(serialized.size(), 192) + serialized)); } void signed_transaction::deserialize(const std::string &raw_tx) { - rlp_decoder decoder; - const auto rlp_array = decoder.decode(remove_0x(raw_tx)); + const auto rlp_array = rlp_decoder::decode(remove_0x(raw_tx)); FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format"); - nonce = add_0x(rlp_array.at(0)); + nonce = !rlp_array.at(0).empty() ? add_0x(rlp_array.at(0)) : add_0x("0"); + boost::algorithm::to_lower(nonce); gas_price = add_0x(rlp_array.at(1)); + boost::algorithm::to_lower(gas_price); gas_limit = add_0x(rlp_array.at(2)); + boost::algorithm::to_lower(gas_limit); to = add_0x(rlp_array.at(3)); - value = add_0x(rlp_array.at(4)); - data = add_0x(rlp_array.at(5)); + boost::algorithm::to_lower(to); + value = !rlp_array.at(4).empty() ? add_0x(rlp_array.at(4)) : add_0x("0"); + boost::algorithm::to_lower(value); + data = !rlp_array.at(5).empty() ? add_0x(rlp_array.at(5)) : ""; + boost::algorithm::to_lower(data); v = add_0x(rlp_array.at(6)); + boost::algorithm::to_lower(v); r = add_0x(rlp_array.at(7)); + boost::algorithm::to_lower(r); s = add_0x(rlp_array.at(8)); + boost::algorithm::to_lower(s); } }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp index c112206b..693c7284 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp @@ -4,9 +4,15 @@ #include #include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { class base_transaction { +public: + base_transaction() = default; + base_transaction(const std::string &raw_tx); + virtual std::string serialize() const = 0; virtual void deserialize(const std::string &raw_tx) = 0; }; @@ -17,6 +23,9 @@ public: std::string to; std::string data; + transaction() = default; + transaction(const std::string &raw_tx); + const transaction &sign(const std::string &private_key) const; virtual std::string serialize() const override; @@ -34,6 +43,10 @@ public: std::string data; std::string chain_id; + raw_transaction() = default; + raw_transaction(const std::string &raw_tx); + + bytes hash() const; signed_transaction sign(const std::string &private_key) const; virtual std::string serialize() const override; @@ -52,6 +65,11 @@ public: std::string r; std::string s; + signed_transaction() = default; + signed_transaction(const std::string &raw_tx); + + std::string recover(const std::string &chain_id) const; + virtual std::string serialize() const override; virtual void deserialize(const std::string &raw_tx) override; }; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp index 92591d0a..114f9bc7 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp @@ -13,16 +13,18 @@ class peerplays_sidechain_plugin_impl; } struct son_proposal_type { - son_proposal_type(int op, son_id_type son, object_id_type object) : + son_proposal_type(int op, sidechain_type sid, son_id_type son, object_id_type object) : op_type(op), + sidechain(sid), son_id(son), object_id(object) { } int op_type; + sidechain_type sidechain; son_id_type son_id; object_id_type object_id; bool operator<(const son_proposal_type &other) const { - return std::tie(op_type, son_id, object_id) < std::tie(other.op_type, other.son_id, other.object_id); + return std::tie(op_type, sidechain, son_id, object_id) < std::tie(other.op_type, other.sidechain, other.son_id, other.object_id); } }; @@ -42,15 +44,15 @@ public: std::unique_ptr my; std::set &get_sons(); - const son_id_type get_current_son_id(); - const son_object get_current_son_object(); + const son_id_type get_current_son_id(sidechain_type sidechain); + const son_object get_current_son_object(sidechain_type sidechain); const son_object get_son_object(son_id_type son_id); - bool is_active_son(son_id_type son_id); + bool is_active_son(sidechain_type sidechain, son_id_type son_id); bool is_son_deregistered(son_id_type son_id); fc::ecc::private_key get_private_key(son_id_type son_id); fc::ecc::private_key get_private_key(chain::public_key_type public_key); - void log_son_proposal_retry(int op_type, object_id_type object_id); - bool can_son_participate(int op_type, object_id_type object_id); + void log_son_proposal_retry(sidechain_type sidechain, int op_type, object_id_type object_id); + bool can_son_participate(sidechain_type sidechain, int op_type, object_id_type object_id); std::map> get_son_listener_log(); }; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_factory.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_factory.hpp new file mode 100644 index 00000000..3aa42894 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_factory.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +#include + +#include + +namespace graphene { namespace peerplays_sidechain { + +class sidechain_net_handler_factory { +public: + sidechain_net_handler_factory(peerplays_sidechain_plugin &_plugin); + + std::unique_ptr create_handler(sidechain_type sidechain, const boost::program_options::variables_map &options) const; + +private: + peerplays_sidechain_plugin &plugin; +}; + +}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_manager.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_manager.hpp deleted file mode 100644 index 8bfda125..00000000 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_manager.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -#include - -namespace graphene { namespace peerplays_sidechain { - -class sidechain_net_manager { -public: - sidechain_net_manager(peerplays_sidechain_plugin &_plugin); - virtual ~sidechain_net_manager(); - - bool create_handler(sidechain_type sidechain, const boost::program_options::variables_map &options); - void process_proposals(); - void process_active_sons_change(); - void create_deposit_addresses(); - void process_deposits(); - void process_withdrawals(); - void process_sidechain_transactions(); - void send_sidechain_transactions(); - void settle_sidechain_transactions(); - - std::map> get_son_listener_log(); - -private: - peerplays_sidechain_plugin &plugin; - graphene::chain::database &database; - std::vector> net_handlers; - - void on_applied_block(const signed_block &b); -}; - -}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 2e5742a6..990ed15d 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -11,7 +13,7 @@ #include #include #include -#include +#include #include namespace bpo = boost::program_options; @@ -33,36 +35,36 @@ public: void plugin_shutdown(); std::set &get_sons(); - const son_id_type get_current_son_id(); - const son_object get_current_son_object(); + const son_id_type get_current_son_id(sidechain_type sidechain); + const son_object get_current_son_object(sidechain_type sidechain); const son_object get_son_object(son_id_type son_id); - bool is_active_son(son_id_type son_id); + bool is_active_son(sidechain_type sidechain, son_id_type son_id); bool is_son_deregistered(son_id_type son_id); bool is_son_deregister_op_valid(const chain::operation &op); bool is_son_down_op_valid(const chain::operation &op); bool is_valid_son_proposal(const chain::proposal_object &proposal); fc::ecc::private_key get_private_key(son_id_type son_id); fc::ecc::private_key get_private_key(chain::public_key_type public_key); - void log_son_proposal_retry(int op_type, object_id_type object_id); - bool can_son_participate(int op_type, object_id_type object_id); + void log_son_proposal_retry(sidechain_type sidechain, int op_type, object_id_type object_id); + bool can_son_participate(sidechain_type sidechain, int op_type, object_id_type object_id); std::map> get_son_listener_log(); void schedule_heartbeat_loop(); void heartbeat_loop(); void schedule_son_processing(); - void son_processing(); - void approve_proposals(); - void create_son_down_proposals(); - void create_son_deregister_proposals(); + void son_processing(sidechain_type sidechain); + void approve_proposals(sidechain_type sidechain); + void create_son_down_proposals(sidechain_type sidechain); + void create_son_deregister_proposals(sidechain_type sidechain); - void process_proposals(); - void process_active_sons_change(); - void create_deposit_addresses(); - void process_deposits(); - void process_withdrawals(); - void process_sidechain_transactions(); - void send_sidechain_transactions(); - void settle_sidechain_transactions(); + void process_proposals(sidechain_type sidechain); + void process_active_sons_change(sidechain_type sidechain); + void create_deposit_addresses(sidechain_type sidechain); + void process_deposits(sidechain_type sidechain); + void process_withdrawals(sidechain_type sidechain); + void process_sidechain_transactions(sidechain_type sidechain); + void send_sidechain_transactions(sidechain_type sidechain); + void settle_sidechain_transactions(sidechain_type sidechain); private: peerplays_sidechain_plugin &plugin; @@ -80,15 +82,19 @@ private: bool sidechain_enabled_hive; bool sidechain_enabled_peerplays; - son_id_type current_son_id; + std::map current_son_id; + std::mutex current_son_id_mutex; + std::mutex access_db_mutex; + std::mutex access_approve_prop_mutex; + std::mutex access_son_down_prop_mutex; - std::unique_ptr net_manager; + std::map> net_handlers; std::set sons; std::map private_keys; fc::future _heartbeat_task; - fc::future _son_processing_task; + std::map> _son_processing_task; std::map son_retry_count; - uint16_t retries_threshold; + uint16_t retries_threshold = 150; bool first_block_skipped; void on_applied_block(const signed_block &b); @@ -105,8 +111,20 @@ peerplays_sidechain_plugin_impl::peerplays_sidechain_plugin_impl(peerplays_sidec sidechain_enabled_ethereum(false), sidechain_enabled_hive(false), sidechain_enabled_peerplays(false), - current_son_id(son_id_type(std::numeric_limits().max())), - net_manager(nullptr), + current_son_id([] { + std::map current_son_id; + for (const auto &active_sidechain_type : active_sidechain_types) { + current_son_id.emplace(active_sidechain_type, son_id_type(std::numeric_limits().max())); + } + return current_son_id; + }()), + net_handlers([] { + std::map> net_handlers; + for (const auto &active_sidechain_type : active_sidechain_types) { + net_handlers.emplace(active_sidechain_type, nullptr); + } + return net_handlers; + }()), first_block_skipped(false) { } @@ -121,8 +139,10 @@ peerplays_sidechain_plugin_impl::~peerplays_sidechain_plugin_impl() { } try { - if (_son_processing_task.valid()) - _son_processing_task.cancel_and_wait(__FUNCTION__); + for (const auto &active_sidechain_type : active_sidechain_types) { + if (_son_processing_task.count(active_sidechain_type) != 0 && _son_processing_task.at(active_sidechain_type).valid()) + _son_processing_task.at(active_sidechain_type).wait(); + } } catch (fc::canceled_exception &) { //Expected exception. Move along. } catch (fc::exception &e) { @@ -265,25 +285,25 @@ void peerplays_sidechain_plugin_impl::plugin_startup() { elog("No sons configured! Please add SON IDs and private keys to configuration."); } - net_manager = std::unique_ptr(new sidechain_net_manager(plugin)); + sidechain_net_handler_factory net_handler_factory(plugin); if (sidechain_enabled_bitcoin && config_ready_bitcoin) { - net_manager->create_handler(sidechain_type::bitcoin, options); + net_handlers.at(sidechain_type::bitcoin) = net_handler_factory.create_handler(sidechain_type::bitcoin, options); ilog("Bitcoin sidechain handler running"); } if (sidechain_enabled_ethereum && config_ready_ethereum) { - net_manager->create_handler(sidechain_type::ethereum, options); + net_handlers.at(sidechain_type::ethereum) = net_handler_factory.create_handler(sidechain_type::ethereum, options); ilog("Ethereum sidechain handler running"); } if (sidechain_enabled_hive && config_ready_hive) { - net_manager->create_handler(sidechain_type::hive, options); + net_handlers.at(sidechain_type::hive) = net_handler_factory.create_handler(sidechain_type::hive, options); ilog("Hive sidechain handler running"); } if (sidechain_enabled_peerplays && config_ready_peerplays) { - net_manager->create_handler(sidechain_type::peerplays, options); + net_handlers.at(sidechain_type::peerplays) = net_handler_factory.create_handler(sidechain_type::peerplays, options); ilog("Peerplays sidechain handler running"); } @@ -299,12 +319,13 @@ std::set &peerplays_sidechain_plugin_impl::get_sons() { return sons; } -const son_id_type peerplays_sidechain_plugin_impl::get_current_son_id() { - return current_son_id; +const son_id_type peerplays_sidechain_plugin_impl::get_current_son_id(sidechain_type sidechain) { + const std::lock_guard lock(current_son_id_mutex); + return current_son_id.at(sidechain); } -const son_object peerplays_sidechain_plugin_impl::get_current_son_object() { - return get_son_object(current_son_id); +const son_object peerplays_sidechain_plugin_impl::get_current_son_object(sidechain_type sidechain) { + return get_son_object(get_current_son_id(sidechain)); } const son_object peerplays_sidechain_plugin_impl::get_son_object(son_id_type son_id) { @@ -315,16 +336,15 @@ const son_object peerplays_sidechain_plugin_impl::get_son_object(son_id_type son return *son_obj; } -bool peerplays_sidechain_plugin_impl::is_active_son(son_id_type son_id) { +bool peerplays_sidechain_plugin_impl::is_active_son(sidechain_type sidechain, son_id_type son_id) { const auto &idx = plugin.database().get_index_type().indices().get(); auto son_obj = idx.find(son_id); if (son_obj == idx.end()) return false; const chain::global_property_object &gpo = plugin.database().get_global_properties(); - vector active_son_ids; - active_son_ids.reserve(gpo.active_sons.size()); - std::transform(gpo.active_sons.begin(), gpo.active_sons.end(), + 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) { return swi.son_id; @@ -341,7 +361,13 @@ bool peerplays_sidechain_plugin_impl::is_son_deregistered(son_id_type son_id) { if (son_obj == idx.end()) return true; - if (son_obj->status == chain::son_status::deregistered) { + bool status_deregistered = true; + for (const auto &status : son_obj->statuses) { + if ((status.second != son_status::deregistered)) + status_deregistered = false; + } + + if (status_deregistered) { return true; } @@ -365,13 +391,23 @@ bool peerplays_sidechain_plugin_impl::is_son_down_op_valid(const chain::operatio } auto stats = son_obj->statistics(d); fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval; - fc::time_point_sec last_active_ts = ((stats.last_active_timestamp > last_maintenance_time) ? stats.last_active_timestamp : last_maintenance_time); int64_t down_threshold = gpo.parameters.son_down_time(); - if (((son_obj->status == chain::son_status::active) || (son_obj->status == chain::son_status::request_maintenance)) && - ((fc::time_point::now() - last_active_ts) > fc::seconds(down_threshold))) { - return true; + + bool status_son_down_op_valid = true; + for (const auto &status : son_obj->statuses) { + if ((status.second != son_status::active) && (status.second != son_status::request_maintenance)) + status_son_down_op_valid = false; } - return false; + if (status_son_down_op_valid) { + for (const auto &active_sidechain_type : active_sidechain_types) { + fc::time_point_sec last_active_ts = ((stats.last_active_timestamp.at(active_sidechain_type) > last_maintenance_time) ? stats.last_active_timestamp.at(active_sidechain_type) : last_maintenance_time); + if (((fc::time_point::now() - last_active_ts) <= fc::seconds(down_threshold))) { + status_son_down_op_valid = false; + } + } + } + + return status_son_down_op_valid; } fc::ecc::private_key peerplays_sidechain_plugin_impl::get_private_key(son_id_type son_id) { @@ -403,7 +439,23 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop() { chain::database &d = plugin.database(); for (son_id_type son_id : sons) { - if (is_active_son(son_id) || get_son_object(son_id).status == chain::son_status::in_maintenance) { + const auto &son_obj = get_son_object(son_id); + + //! Check that son is in_maintenance + bool status_in_maintenance = false; + for (const auto &status : son_obj.statuses) { + if ((status.second == son_status::in_maintenance)) + status_in_maintenance = true; + } + + //! Check that son is active (at least for one sidechain_type) + bool is_son_active = false; + for (const auto &active_sidechain_type : active_sidechain_types) { + if (is_active_son(active_sidechain_type, son_id)) + is_son_active = true; + } + + if (is_son_active || status_in_maintenance) { ilog("Sending heartbeat for SON ${son}", ("son", son_id)); chain::son_heartbeat_operation op; @@ -429,19 +481,23 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop() { } void peerplays_sidechain_plugin_impl::schedule_son_processing() { - fc::time_point now = fc::time_point::now(); - int64_t time_to_next_son_processing = 500000; + const auto now = std::chrono::steady_clock::now(); + static const int64_t time_to_next_son_processing = 500000; - fc::time_point next_wakeup(now + fc::microseconds(time_to_next_son_processing)); + const auto next_wakeup = now + std::chrono::microseconds(time_to_next_son_processing); - _son_processing_task = fc::schedule([this] { - son_processing(); - }, - next_wakeup, "SON Processing"); + for (const auto &active_sidechain_type : active_sidechain_types) { + _son_processing_task[active_sidechain_type] = std::async(std::launch::async, [this, next_wakeup, active_sidechain_type] { + std::this_thread::sleep_until(next_wakeup); + son_processing(active_sidechain_type); + }); + } } -void peerplays_sidechain_plugin_impl::son_processing() { - if (plugin.database().get_global_properties().active_sons.size() <= 0) { +void peerplays_sidechain_plugin_impl::son_processing(sidechain_type sidechain) { + //! Check whether we have active SONs + if (plugin.database().get_global_properties().active_sons.count(sidechain) == 0 || + plugin.database().get_global_properties().active_sons.at(sidechain).empty()) { return; } @@ -451,50 +507,55 @@ void peerplays_sidechain_plugin_impl::son_processing() { // return; // Not synced //} - fc::time_point now_fine = fc::time_point::now(); - fc::time_point_sec now = now_fine - fc::milliseconds(3000); + const fc::time_point now_fine = fc::time_point::now(); + const fc::time_point_sec now = now_fine - fc::milliseconds(3000); if (plugin.database().head_block_time() < now) { return; // Not synced } - chain::son_id_type scheduled_son_id = plugin.database().get_scheduled_son(1); - ilog("Scheduled SON: ${scheduled_son_id} Now: ${now} ", - ("scheduled_son_id", scheduled_son_id)("now", now)); + //! Get scheduled_son_id according to sidechain_type + const chain::son_id_type scheduled_son_id = plugin.database().get_scheduled_son(sidechain, 1); + ilog("Scheduled SON: ${scheduled_son_id} Sidechain: ${sidechain} Now: ${now}", + ("scheduled_son_id", scheduled_son_id)("sidechain", sidechain)("now", now)); for (son_id_type son_id : plugin.get_sons()) { if (plugin.is_son_deregistered(son_id)) { continue; } - current_son_id = son_id; + + { + const std::lock_guard lock(current_son_id_mutex); + current_son_id.at(sidechain) = son_id; + } // These tasks are executed by // - All active SONs, no matter if scheduled // - All previously active SONs - approve_proposals(); - process_proposals(); - process_sidechain_transactions(); + approve_proposals(sidechain); + process_proposals(sidechain); + process_sidechain_transactions(sidechain); - if (plugin.is_active_son(son_id)) { + if (plugin.is_active_son(sidechain, son_id)) { // Tasks that are executed by scheduled and active SON only - if (current_son_id == scheduled_son_id) { + if (get_current_son_id(sidechain) == scheduled_son_id) { - create_son_down_proposals(); + create_son_down_proposals(sidechain); - create_son_deregister_proposals(); + create_son_deregister_proposals(sidechain); - process_active_sons_change(); + process_active_sons_change(sidechain); - create_deposit_addresses(); + create_deposit_addresses(sidechain); - process_deposits(); + process_deposits(sidechain); - process_withdrawals(); + process_withdrawals(sidechain); - process_sidechain_transactions(); + process_sidechain_transactions(sidechain); - send_sidechain_transactions(); + send_sidechain_transactions(sidechain); - settle_sidechain_transactions(); + settle_sidechain_transactions(sidechain); } } } @@ -517,8 +578,8 @@ bool peerplays_sidechain_plugin_impl::is_valid_son_proposal(const chain::proposa return false; } -void peerplays_sidechain_plugin_impl::log_son_proposal_retry(int op_type, object_id_type object_id) { - son_proposal_type prop_type(op_type, get_current_son_id(), object_id); +void peerplays_sidechain_plugin_impl::log_son_proposal_retry(sidechain_type sidechain, int op_type, object_id_type object_id) { + son_proposal_type prop_type(op_type, sidechain, get_current_son_id(sidechain), object_id); auto itr = son_retry_count.find(prop_type); if (itr != son_retry_count.end()) { itr->second++; @@ -527,18 +588,27 @@ void peerplays_sidechain_plugin_impl::log_son_proposal_retry(int op_type, object } } -bool peerplays_sidechain_plugin_impl::can_son_participate(int op_type, object_id_type object_id) { - son_proposal_type prop_type(op_type, get_current_son_id(), object_id); +bool peerplays_sidechain_plugin_impl::can_son_participate(sidechain_type sidechain, int op_type, object_id_type object_id) { + son_proposal_type prop_type(op_type, sidechain, get_current_son_id(sidechain), object_id); auto itr = son_retry_count.find(prop_type); return (itr == son_retry_count.end() || itr->second < retries_threshold); } std::map> peerplays_sidechain_plugin_impl::get_son_listener_log() { - return net_manager->get_son_listener_log(); + std::map> result; + for (const auto &active_sidechain_type : active_sidechain_types) { + result.emplace(active_sidechain_type, net_handlers.at(active_sidechain_type)->get_son_listener_log()); + } + return result; } -void peerplays_sidechain_plugin_impl::approve_proposals() { - +void peerplays_sidechain_plugin_impl::approve_proposals(sidechain_type sidechain) { + // prevent approving duplicate proposals with lock for parallel execution. + // We can have the same propsals, but in the case of parallel execution we can run + // into problem of approving the same propsal since it might happens that previous + // approved proposal didn't have time or chance to populate the list of available + // active proposals which is consulted here in the code. + std::lock_guard lck(access_approve_prop_mutex); auto check_approve_proposal = [&](const chain::son_id_type &son_id, const chain::proposal_object &proposal) { if (!is_valid_son_proposal(proposal)) { return; @@ -552,6 +622,7 @@ void peerplays_sidechain_plugin_impl::approve_proposals() { fc::future fut = fc::async([&]() { try { trx.validate(); + std::lock_guard lck(access_db_mutex); plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check); if (plugin.app().p2p_node()) plugin.app().p2p_node()->broadcast(net::trx_message(trx)); @@ -571,7 +642,6 @@ void peerplays_sidechain_plugin_impl::approve_proposals() { } for (const auto proposal_id : proposals) { - const object *obj = plugin.database().find_object(proposal_id); const chain::proposal_object *proposal_ptr = dynamic_cast(obj); if (proposal_ptr == nullptr) { @@ -579,15 +649,16 @@ void peerplays_sidechain_plugin_impl::approve_proposals() { } const proposal_object proposal = *proposal_ptr; - if (proposal.available_active_approvals.find(get_current_son_object().son_account) != proposal.available_active_approvals.end()) { + if (proposal.available_active_approvals.find(get_current_son_object(sidechain).son_account) != proposal.available_active_approvals.end()) { continue; } - check_approve_proposal(get_current_son_id(), proposal); + check_approve_proposal(get_current_son_id(sidechain), proposal); } } -void peerplays_sidechain_plugin_impl::create_son_down_proposals() { +void peerplays_sidechain_plugin_impl::create_son_down_proposals(sidechain_type sidechain) { + std::lock_guard lck(access_son_down_prop_mutex); auto create_son_down_proposal = [&](chain::son_id_type son_id, fc::time_point_sec last_active_ts) { chain::database &d = plugin.database(); const chain::global_property_object &gpo = d.get_global_properties(); @@ -598,7 +669,7 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals() { son_down_op.down_ts = last_active_ts; proposal_create_operation proposal_op; - proposal_op.fee_paying_account = get_current_son_object().son_account; + proposal_op.fee_paying_account = get_current_son_object(sidechain).son_account; proposal_op.proposed_ops.emplace_back(op_wrapper(son_down_op)); uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(d.head_block_time().sec_since_epoch() + lifetime); @@ -610,24 +681,32 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals() { const chain::dynamic_global_property_object &dgpo = d.get_dynamic_global_properties(); const auto &idx = d.get_index_type().indices().get(); std::set sons_being_reported_down = d.get_sons_being_reported_down(); - chain::son_id_type my_son_id = get_current_son_id(); - for (auto son_inf : gpo.active_sons) { + chain::son_id_type my_son_id = get_current_son_id(sidechain); + + //! Fixme - check this part of the code + for (auto son_inf : gpo.active_sons.at(sidechain)) { if (my_son_id == son_inf.son_id || (sons_being_reported_down.find(son_inf.son_id) != sons_being_reported_down.end())) { continue; } auto son_obj = idx.find(son_inf.son_id); auto stats = son_obj->statistics(d); fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval; - fc::time_point_sec last_active_ts = ((stats.last_active_timestamp > last_maintenance_time) ? stats.last_active_timestamp : last_maintenance_time); + fc::time_point_sec last_active_ts = ((stats.last_active_timestamp.at(sidechain) > last_maintenance_time) ? stats.last_active_timestamp.at(sidechain) : last_maintenance_time); int64_t down_threshold = gpo.parameters.son_down_time(); - if (((son_obj->status == chain::son_status::active) || (son_obj->status == chain::son_status::request_maintenance)) && - ((fc::time_point::now() - last_active_ts) > fc::seconds(down_threshold))) { + + bool status_son_down_valid = true; + for (const auto &status : son_obj->statuses) { + if ((status.second != son_status::active) && (status.second != son_status::request_maintenance)) + status_son_down_valid = false; + } + if ((status_son_down_valid) && ((fc::time_point::now() - last_active_ts) > fc::seconds(down_threshold))) { ilog("Sending son down proposal for ${t} from ${s}", ("t", std::string(object_id_type(son_obj->id)))("s", std::string(object_id_type(my_son_id)))); chain::proposal_create_operation op = create_son_down_proposal(son_inf.son_id, last_active_ts); chain::signed_transaction trx = d.create_signed_transaction(plugin.get_private_key(get_son_object(my_son_id).signing_key), op); fc::future fut = fc::async([&]() { try { trx.validate(); + std::lock_guard lck(access_db_mutex); d.push_transaction(trx, database::validation_steps::skip_block_size_check); if (plugin.app().p2p_node()) plugin.app().p2p_node()->broadcast(net::trx_message(trx)); @@ -642,10 +721,10 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals() { } } -void peerplays_sidechain_plugin_impl::create_son_deregister_proposals() { +void peerplays_sidechain_plugin_impl::create_son_deregister_proposals(sidechain_type sidechain) { chain::database &d = plugin.database(); std::set sons_to_be_dereg = d.get_sons_to_be_deregistered(); - chain::son_id_type my_son_id = get_current_son_id(); + chain::son_id_type my_son_id = get_current_son_id(sidechain); if (sons_to_be_dereg.size() > 0) { // We shouldn't raise proposals for the SONs for which a de-reg @@ -663,6 +742,7 @@ void peerplays_sidechain_plugin_impl::create_son_deregister_proposals() { fc::future fut = fc::async([&]() { try { trx.validate(); + std::lock_guard lck(access_db_mutex); d.push_transaction(trx, database::validation_steps::skip_block_size_check); if (plugin.app().p2p_node()) plugin.app().p2p_node()->broadcast(net::trx_message(trx)); @@ -679,36 +759,36 @@ void peerplays_sidechain_plugin_impl::create_son_deregister_proposals() { } } -void peerplays_sidechain_plugin_impl::process_proposals() { - net_manager->process_proposals(); +void peerplays_sidechain_plugin_impl::process_proposals(sidechain_type sidechain) { + net_handlers.at(sidechain)->process_proposals(); } -void peerplays_sidechain_plugin_impl::process_active_sons_change() { - net_manager->process_active_sons_change(); +void peerplays_sidechain_plugin_impl::process_active_sons_change(sidechain_type sidechain) { + net_handlers.at(sidechain)->process_active_sons_change(); } -void peerplays_sidechain_plugin_impl::create_deposit_addresses() { - net_manager->create_deposit_addresses(); +void peerplays_sidechain_plugin_impl::create_deposit_addresses(sidechain_type sidechain) { + net_handlers.at(sidechain)->create_deposit_addresses(); } -void peerplays_sidechain_plugin_impl::process_deposits() { - net_manager->process_deposits(); +void peerplays_sidechain_plugin_impl::process_deposits(sidechain_type sidechain) { + net_handlers.at(sidechain)->process_deposits(); } -void peerplays_sidechain_plugin_impl::process_withdrawals() { - net_manager->process_withdrawals(); +void peerplays_sidechain_plugin_impl::process_withdrawals(sidechain_type sidechain) { + net_handlers.at(sidechain)->process_withdrawals(); } -void peerplays_sidechain_plugin_impl::process_sidechain_transactions() { - net_manager->process_sidechain_transactions(); +void peerplays_sidechain_plugin_impl::process_sidechain_transactions(sidechain_type sidechain) { + net_handlers.at(sidechain)->process_sidechain_transactions(); } -void peerplays_sidechain_plugin_impl::send_sidechain_transactions() { - net_manager->send_sidechain_transactions(); +void peerplays_sidechain_plugin_impl::send_sidechain_transactions(sidechain_type sidechain) { + net_handlers.at(sidechain)->send_sidechain_transactions(); } -void peerplays_sidechain_plugin_impl::settle_sidechain_transactions() { - net_manager->settle_sidechain_transactions(); +void peerplays_sidechain_plugin_impl::settle_sidechain_transactions(sidechain_type sidechain) { + net_handlers.at(sidechain)->settle_sidechain_transactions(); } void peerplays_sidechain_plugin_impl::on_applied_block(const signed_block &b) { @@ -761,20 +841,20 @@ std::set &peerplays_sidechain_plugin::get_sons() { return my->get_sons(); } -const son_id_type peerplays_sidechain_plugin::get_current_son_id() { - return my->get_current_son_id(); +const son_id_type peerplays_sidechain_plugin::get_current_son_id(sidechain_type sidechain) { + return my->get_current_son_id(sidechain); } -const son_object peerplays_sidechain_plugin::get_current_son_object() { - return my->get_current_son_object(); +const son_object peerplays_sidechain_plugin::get_current_son_object(sidechain_type sidechain) { + return my->get_current_son_object(sidechain); } const son_object peerplays_sidechain_plugin::get_son_object(son_id_type son_id) { return my->get_son_object(son_id); } -bool peerplays_sidechain_plugin::is_active_son(son_id_type son_id) { - return my->is_active_son(son_id); +bool peerplays_sidechain_plugin::is_active_son(sidechain_type sidechain, son_id_type son_id) { + return my->is_active_son(sidechain, son_id); } bool peerplays_sidechain_plugin::is_son_deregistered(son_id_type son_id) { @@ -789,12 +869,12 @@ fc::ecc::private_key peerplays_sidechain_plugin::get_private_key(chain::public_k return my->get_private_key(public_key); } -void peerplays_sidechain_plugin::log_son_proposal_retry(int op_type, object_id_type object_id) { - my->log_son_proposal_retry(op_type, object_id); +void peerplays_sidechain_plugin::log_son_proposal_retry(sidechain_type sidechain, int op_type, object_id_type object_id) { + my->log_son_proposal_retry(sidechain, op_type, object_id); } -bool peerplays_sidechain_plugin::can_son_participate(int op_type, object_id_type object_id) { - return my->can_son_participate(op_type, object_id); +bool peerplays_sidechain_plugin::can_son_participate(sidechain_type sidechain, int op_type, object_id_type object_id) { + return my->can_son_participate(sidechain, op_type, object_id); } std::map> peerplays_sidechain_plugin::get_son_listener_log() { diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp index 78ad7103..971df7c7 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp @@ -184,7 +184,7 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ ((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HIVE") == 0)) || enable_peerplays_asset_deposits); - bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain == sidechain_type::peerplays) && + bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain == sidechain) && //! Fixme -> sidechain_type::peerplays ((sed.sidechain_currency == object_id_to_string(gpo.parameters.btc_asset())) || (sed.sidechain_currency == object_id_to_string(gpo.parameters.eth_asset())) || (sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset())) || @@ -194,7 +194,7 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ if (deposit_condition) { for (son_id_type son_id : plugin.get_sons()) { - if (plugin.is_active_son(son_id)) { + if (plugin.is_active_son(sidechain, son_id)) { son_wallet_deposit_create_operation op; op.payer = plugin.get_son_object(son_id).son_account; @@ -260,7 +260,7 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ } for (son_id_type son_id : plugin.get_sons()) { - if (plugin.is_active_son(son_id)) { + if (plugin.is_active_son(sidechain, son_id)) { son_wallet_withdraw_create_operation op; op.payer = plugin.get_son_object(son_id).son_account; @@ -304,7 +304,7 @@ void sidechain_net_handler::process_proposals() { const auto po = idx.find(proposal_id); if (po != idx.end()) { - if (po->available_active_approvals.find(plugin.get_current_son_object().son_account) != po->available_active_approvals.end()) { + if (po->available_active_approvals.find(plugin.get_current_son_object(sidechain).son_account) != po->available_active_approvals.end()) { continue; } @@ -387,12 +387,12 @@ void sidechain_net_handler::process_proposals() { elog("=================================================="); } - if (should_process && (op_idx_0 == chain::operation::tag::value || plugin.can_son_participate(op_idx_0, object_id))) { + if (should_process && (op_idx_0 == chain::operation::tag::value || plugin.can_son_participate(sidechain, op_idx_0, object_id))) { bool should_approve = process_proposal(*po); if (should_approve) { - if (approve_proposal(po->id, plugin.get_current_son_id())) { + if (approve_proposal(po->id, plugin.get_current_son_id(sidechain))) { if (op_idx_0 != chain::operation::tag::value) { - plugin.log_son_proposal_retry(op_idx_0, object_id); + plugin.log_son_proposal_retry(sidechain, op_idx_0, object_id); } } } @@ -406,14 +406,14 @@ void sidechain_net_handler::process_active_sons_change() { } void sidechain_net_handler::create_deposit_addresses() { - if (database.get_global_properties().active_sons.size() < database.get_chain_properties().immutable_parameters.min_son_count) { + if (database.get_global_properties().active_sons.at(sidechain).size() < database.get_chain_properties().immutable_parameters.min_son_count) { return; } process_sidechain_addresses(); } void sidechain_net_handler::process_deposits() { - if (database.get_global_properties().active_sons.size() < database.get_chain_properties().immutable_parameters.min_son_count) { + if (database.get_global_properties().active_sons.at(sidechain).size() < database.get_chain_properties().immutable_parameters.min_son_count) { return; } @@ -421,7 +421,7 @@ void sidechain_net_handler::process_deposits() { const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, true, false)); std::for_each(idx_range.first, idx_range.second, [&](const son_wallet_deposit_object &swdo) { - if (swdo.id == object_id_type(0, 0, 0) || !plugin.can_son_participate(chain::operation::tag::value, swdo.id)) { + if (swdo.id == object_id_type(0, 0, 0) || !plugin.can_son_participate(sidechain, chain::operation::tag::value, swdo.id)) { return; } //Ignore the deposits which are not valid anymore, considered refunds. @@ -443,12 +443,12 @@ void sidechain_net_handler::process_deposits() { wlog("Deposit not processed: ${swdo}", ("swdo", swdo)); return; } - plugin.log_son_proposal_retry(chain::operation::tag::value, swdo.id); + plugin.log_son_proposal_retry(sidechain, chain::operation::tag::value, swdo.id); }); } void sidechain_net_handler::process_withdrawals() { - if (database.get_global_properties().active_sons.size() < database.get_chain_properties().immutable_parameters.min_son_count) { + if (database.get_global_properties().active_sons.at(sidechain).size() < database.get_chain_properties().immutable_parameters.min_son_count) { return; } @@ -456,7 +456,7 @@ void sidechain_net_handler::process_withdrawals() { const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, true, false)); std::for_each(idx_range.first, idx_range.second, [&](const son_wallet_withdraw_object &swwo) { - if (swwo.id == object_id_type(0, 0, 0) || !plugin.can_son_participate(chain::operation::tag::value, swwo.id)) { + if (swwo.id == object_id_type(0, 0, 0) || !plugin.can_son_participate(sidechain, chain::operation::tag::value, swwo.id)) { return; } @@ -468,7 +468,7 @@ void sidechain_net_handler::process_withdrawals() { wlog("Withdraw not processed: ${swwo}", ("swwo", swwo)); return; } - plugin.log_son_proposal_retry(chain::operation::tag::value, swwo.id); + plugin.log_son_proposal_retry(sidechain, chain::operation::tag::value, swwo.id); }); } @@ -477,7 +477,7 @@ void sidechain_net_handler::process_sidechain_transactions() { const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, sidechain_transaction_status::valid)); std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) { - if ((sto.id == object_id_type(0, 0, 0)) || !signer_expected(sto, plugin.get_current_son_id())) { + if ((sto.id == object_id_type(0, 0, 0)) || !signer_expected(sto, plugin.get_current_son_id(sidechain))) { return; } @@ -492,13 +492,13 @@ void sidechain_net_handler::process_sidechain_transactions() { const chain::global_property_object &gpo = database.get_global_properties(); sidechain_transaction_sign_operation sts_op; - sts_op.signer = plugin.get_current_son_id(); + sts_op.signer = plugin.get_current_son_id(sidechain); sts_op.payer = gpo.parameters.son_account(); sts_op.sidechain_transaction_id = sto.id; sts_op.signature = processed_sidechain_tx; proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); proposal_op.proposed_ops.emplace_back(sts_op); @@ -507,7 +507,7 @@ void sidechain_net_handler::process_sidechain_transactions() { return; } - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); @@ -538,11 +538,11 @@ void sidechain_net_handler::send_sidechain_transactions() { } sidechain_transaction_send_operation sts_op; - sts_op.payer = plugin.get_current_son_object().son_account; + sts_op.payer = plugin.get_current_son_object(sidechain).son_account; sts_op.sidechain_transaction_id = sto.id; sts_op.sidechain_transaction = sidechain_transaction; - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), sts_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), sts_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); @@ -567,7 +567,7 @@ void sidechain_net_handler::settle_sidechain_transactions() { return; } - if (!plugin.can_son_participate(chain::operation::tag::value, sto.object_id)) { + if (!plugin.can_son_participate(sidechain, chain::operation::tag::value, sto.object_id)) { return; } @@ -584,7 +584,7 @@ void sidechain_net_handler::settle_sidechain_transactions() { const chain::global_property_object &gpo = database.get_global_properties(); proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); @@ -612,13 +612,13 @@ void sidechain_net_handler::settle_sidechain_transactions() { } } - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); if (plugin.app().p2p_node()) plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - plugin.log_son_proposal_retry(chain::operation::tag::value, sto.object_id); + plugin.log_son_proposal_retry(sidechain, chain::operation::tag::value, sto.object_id); } catch (fc::exception &e) { elog("Sending proposal for sidechain transaction settle operation failed with exception ${e}", ("e", e.what())); } @@ -681,7 +681,7 @@ void sidechain_net_handler::on_applied_block(const signed_block &b) { sidechain_event_data sed; sed.timestamp = database.head_block_time(); sed.block_num = database.head_block_num(); - sed.sidechain = sidechain_type::peerplays; + sed.sidechain = sidechain; //! Fixme -> sidechain_type::peerplays sed.sidechain_uid = sidechain_uid; sed.sidechain_transaction_id = trx.id().str(); sed.sidechain_from = sidechain_from; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 0d3da223..cace6fb3 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -417,7 +417,7 @@ sidechain_net_handler_bitcoin::~sidechain_net_handler_bitcoin() { bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) { - // ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); + //ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id(sidechain))); bool should_approve = false; @@ -451,8 +451,8 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) const auto swo = idx.find(swo_id); if (swo != idx.end()) { - auto active_sons = gpo.active_sons; - vector wallet_sons = swo->sons; + const auto &active_sons = gpo.active_sons.at(sidechain); + vector wallet_sons = swo->sons.at(sidechain); bool son_sets_equal = (active_sons.size() == wallet_sons.size()); @@ -463,10 +463,10 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) } if (son_sets_equal) { - auto active_sons = gpo.active_sons; + const auto &active_sons = gpo.active_sons.at(sidechain); vector son_pubkeys_bitcoin; for (const son_info &si : active_sons) { - son_pubkeys_bitcoin.push_back(si.sidechain_public_keys.at(sidechain_type::bitcoin)); + son_pubkeys_bitcoin.push_back(si.public_key); } string reply_str = create_primary_wallet_address(active_sons); @@ -676,7 +676,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) read_transaction_data(sto->transaction, tx_hex, in_amounts, redeem_script); bitcoin_transaction tx = unpack(parse_hex(tx_hex)); - bitcoin::bytes pubkey = parse_hex(son->sidechain_public_keys.at(sidechain_type::bitcoin)); + bitcoin::bytes pubkey = parse_hex(son->sidechain_public_keys.at(sidechain)); vector sigs = read_byte_arrays_from_string(signature); for (size_t i = 0; i < tx.vin.size(); i++) { const auto &sighash_str = get_signature_hash(tx, parse_hex(redeem_script), static_cast(in_amounts[i]), i, 1, true).str(); @@ -706,8 +706,8 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { const auto &active_sw = swi.rbegin(); if (active_sw != swi.rend()) { - if ((active_sw->addresses.find(sidechain_type::bitcoin) == active_sw->addresses.end()) || - (active_sw->addresses.at(sidechain_type::bitcoin).empty())) { + if ((active_sw->addresses.find(sidechain) == active_sw->addresses.end()) || + (active_sw->addresses.at(sidechain).empty())) { if (proposal_exists(chain::operation::tag::value, active_sw->id)) { return; @@ -715,19 +715,19 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { const chain::global_property_object &gpo = database.get_global_properties(); - auto active_sons = gpo.active_sons; + const auto &active_sons = gpo.active_sons.at(sidechain); string reply_str = create_primary_wallet_address(active_sons); std::stringstream active_pw_ss(reply_str); boost::property_tree::ptree active_pw_pt; boost::property_tree::read_json(active_pw_ss, active_pw_pt); if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { - if (!plugin.can_son_participate(chain::operation::tag::value, active_sw->id)) { + if (!plugin.can_son_participate(sidechain, chain::operation::tag::value, active_sw->id)) { return; } proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); @@ -737,7 +737,7 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { son_wallet_update_operation swu_op; swu_op.payer = gpo.parameters.son_account(); swu_op.son_wallet_id = active_sw->id; - swu_op.sidechain = sidechain_type::bitcoin; + swu_op.sidechain = sidechain; swu_op.address = res.str(); proposal_op.proposed_ops.emplace_back(swu_op); @@ -752,18 +752,18 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { stc_op.object_id = prev_sw->id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = prev_sw->sons; + stc_op.signers = prev_sw->sons.at(sidechain); proposal_op.proposed_ops.emplace_back(stc_op); } } - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); if (plugin.app().p2p_node()) plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - plugin.log_son_proposal_retry(chain::operation::tag::value, active_sw->id); + plugin.log_son_proposal_retry(sidechain, chain::operation::tag::value, active_sw->id); } catch (fc::exception &e) { elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); return; @@ -778,9 +778,8 @@ void sidechain_net_handler_bitcoin::process_sidechain_addresses() { const chain::global_property_object &gpo = database.get_global_properties(); std::vector> pubkeys; - for (auto &son : gpo.active_sons) { - std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin); - auto pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); + for (auto &son : gpo.active_sons.at(sidechain)) { + auto pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(son.public_key))); pubkeys.push_back(std::make_pair(pubkey, son.weight)); } @@ -800,7 +799,7 @@ void sidechain_net_handler_bitcoin::process_sidechain_addresses() { if (addr.get_address() != sao.deposit_address) { sidechain_address_update_operation op; - op.payer = plugin.get_current_son_object().son_account; + op.payer = plugin.get_current_son_object(sidechain).son_account; op.sidechain_address_id = sao.id; op.sidechain_address_account = sao.sidechain_address_account; op.sidechain = sao.sidechain; @@ -810,7 +809,7 @@ void sidechain_net_handler_bitcoin::process_sidechain_addresses() { op.withdraw_public_key = sao.withdraw_public_key; op.withdraw_address = sao.withdraw_address; - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); @@ -842,7 +841,7 @@ bool sidechain_net_handler_bitcoin::process_deposit(const son_wallet_deposit_obj const chain::global_property_object &gpo = database.get_global_properties(); proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); @@ -856,10 +855,10 @@ bool sidechain_net_handler_bitcoin::process_deposit(const son_wallet_deposit_obj stc_op.object_id = swdo.id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons; + stc_op.signers = gpo.active_sons.at(sidechain); proposal_op.proposed_ops.emplace_back(stc_op); - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); @@ -886,7 +885,7 @@ bool sidechain_net_handler_bitcoin::process_withdrawal(const son_wallet_withdraw const chain::global_property_object &gpo = database.get_global_properties(); proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); @@ -900,10 +899,10 @@ bool sidechain_net_handler_bitcoin::process_withdrawal(const son_wallet_withdraw stc_op.object_id = swwo.id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons; + stc_op.signers = gpo.active_sons.at(sidechain); proposal_op.proposed_ops.emplace_back(stc_op); - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); @@ -951,8 +950,7 @@ bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain using namespace bitcoin; std::vector> pubkey_weights; for (auto si : sto.signers) { - std::string pub_key_str = si.sidechain_public_keys.at(sidechain_type::bitcoin); - auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); + auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(si.public_key))); pubkey_weights.push_back(std::make_pair(pub_key, si.weight)); } btc_weighted_multisig_address addr(pubkey_weights, network_type); @@ -1001,8 +999,7 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const s std::vector> pubkey_weights; for (auto &son : son_pubkeys) { - std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin); - auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); + auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(son.public_key))); pubkey_weights.push_back(std::make_pair(pub_key, son.weight)); } @@ -1019,7 +1016,7 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const s std::string sidechain_net_handler_bitcoin::create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address) { - const auto &address_data = prev_swo.addresses.find(sidechain_type::bitcoin); + const auto &address_data = prev_swo.addresses.find(sidechain); if (address_data == prev_swo.addresses.end()) { return ""; } @@ -1070,12 +1067,12 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_transaction(con std::string sidechain_net_handler_bitcoin::create_deposit_transaction(const son_wallet_deposit_object &swdo) { const auto &idx = database.get_index_type().indices().get(); auto obj = idx.rbegin(); - if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) { + if (obj == idx.rend() || obj->addresses.find(sidechain) == obj->addresses.end()) { return ""; } // Get redeem script for deposit address std::string redeem_script = get_redeemscript_for_userdeposit(swdo.sidechain_from); - std::string pw_address_json = obj->addresses.find(sidechain_type::bitcoin)->second; + std::string pw_address_json = obj->addresses.find(sidechain)->second; std::stringstream ss(pw_address_json); boost::property_tree::ptree json; @@ -1117,11 +1114,11 @@ std::string sidechain_net_handler_bitcoin::create_deposit_transaction(const son_ std::string sidechain_net_handler_bitcoin::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { const auto &idx = database.get_index_type().indices().get(); auto obj = idx.rbegin(); - if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) { + if (obj == idx.rend() || obj->addresses.find(sidechain) == obj->addresses.end()) { return ""; } - std::string pw_address_json = obj->addresses.find(sidechain_type::bitcoin)->second; + std::string pw_address_json = obj->addresses.find(sidechain)->second; std::stringstream ss(pw_address_json); boost::property_tree::ptree json; @@ -1186,7 +1183,7 @@ std::string sidechain_net_handler_bitcoin::create_transaction(const std::vector< std::string sidechain_net_handler_bitcoin::sign_transaction(const sidechain_transaction_object &sto) { using namespace bitcoin; - std::string pubkey = plugin.get_current_son_object().sidechain_public_keys.at(sidechain); + std::string pubkey = plugin.get_current_son_object(sidechain).sidechain_public_keys.at(sidechain); std::string prvkey = get_private_key(pubkey); std::vector in_amounts; std::string tx_hex; @@ -1302,14 +1299,13 @@ std::string sidechain_net_handler_bitcoin::get_redeemscript_for_userdeposit(cons const auto &idx = database.get_index_type().indices().get(); auto obj = idx.rbegin(); - if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) { + if (obj == idx.rend() || obj->addresses.find(sidechain) == obj->addresses.end()) { return ""; } std::vector> pubkey_weights; - for (auto &son : obj->sons) { - std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin); - auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); + for (auto &son : obj->sons.at(sidechain)) { + auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(son.public_key))); pubkey_weights.push_back(std::make_pair(pub_key, son.weight)); } auto user_pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(addr_itr->deposit_public_key))); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 52d401cb..31d1fa8a 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -160,7 +160,7 @@ sidechain_net_handler_ethereum::~sidechain_net_handler_ethereum() { } bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) { - ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); + ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id(sidechain))); bool should_approve = false; @@ -193,8 +193,8 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) const auto swo = idx.find(swo_id); if (swo != idx.end()) { - auto active_sons = gpo.active_sons; - vector wallet_sons = swo->sons; + auto active_sons = gpo.active_sons.at(sidechain); + vector wallet_sons = swo->sons.at(sidechain); bool son_sets_equal = (active_sons.size() == wallet_sons.size()); @@ -222,7 +222,7 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) const auto &idx = database.get_index_type().indices().get(); const auto swo = idx.find(object_id); if (swo != idx.end()) { - tx_str = create_primary_wallet_transaction(gpo.active_sons, object_id.operator std::string()); + tx_str = create_primary_wallet_transaction(gpo.active_sons.at(sidechain), object_id.operator std::string()); } } @@ -399,48 +399,48 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { const auto &active_sw = swi.rbegin(); if (active_sw != swi.rend()) { - if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) || - (active_sw->addresses.at(sidechain_type::ethereum).empty())) { + 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)) { return; } - if (!plugin.can_son_participate(chain::operation::tag::value, active_sw->id)) { + if (!plugin.can_son_participate(sidechain, chain::operation::tag::value, active_sw->id)) { return; } const chain::global_property_object &gpo = database.get_global_properties(); proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); son_wallet_update_operation swu_op; swu_op.payer = gpo.parameters.son_account(); swu_op.son_wallet_id = active_sw->id; - swu_op.sidechain = sidechain_type::ethereum; + swu_op.sidechain = sidechain; swu_op.address = wallet_contract_address; proposal_op.proposed_ops.emplace_back(swu_op); - std::string tx_str = create_primary_wallet_transaction(gpo.active_sons, active_sw->id.operator std::string()); + std::string tx_str = create_primary_wallet_transaction(gpo.active_sons.at(sidechain), active_sw->id.operator std::string()); if (!tx_str.empty()) { sidechain_transaction_create_operation stc_op; stc_op.payer = gpo.parameters.son_account(); stc_op.object_id = active_sw->id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons; + stc_op.signers = gpo.active_sons.at(sidechain); proposal_op.proposed_ops.emplace_back(stc_op); } - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); if (plugin.app().p2p_node()) plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - plugin.log_son_proposal_retry(chain::operation::tag::value, active_sw->id); + plugin.log_son_proposal_retry(sidechain, chain::operation::tag::value, active_sw->id); } catch (fc::exception &e) { elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); return; @@ -460,7 +460,7 @@ bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_ob asset asset_to_issue = asset(swdo.peerplays_asset.amount * asset_price.quote.amount / asset_price.base.amount, database.get_global_properties().parameters.eth_asset()); proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); @@ -476,7 +476,7 @@ bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_ob ai_op.issue_to_account = swdo.peerplays_from; proposal_op.proposed_ops.emplace_back(ai_op); - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); @@ -503,7 +503,7 @@ bool sidechain_net_handler_ethereum::process_withdrawal(const son_wallet_withdra const chain::global_property_object &gpo = database.get_global_properties(); proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); @@ -517,10 +517,10 @@ 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; + stc_op.signers = gpo.active_sons.at(sidechain); proposal_op.proposed_ops.emplace_back(stc_op); - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); @@ -546,7 +546,7 @@ std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sid const auto &transaction = signature.second; //! Check if we have this signed transaction, if not, don't send it - if(transaction.empty()) + if (transaction.empty()) continue; #ifdef SEND_RAW_TRANSACTION @@ -620,12 +620,11 @@ bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechai 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) { - FC_ASSERT(son.sidechain_public_keys.contains(sidechain_type::ethereum), "No public keys for son: ${son_id}", ("son_id", son.son_id)); - const std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); + const std::string pub_key_str = son.public_key; owners_weights.emplace_back(std::make_pair(pub_key_str, son.weight)); } - ethereum::update_owners_encoder encoder; + const ethereum::update_owners_encoder encoder; return encoder.encode(owners_weights, object_id); } @@ -634,13 +633,13 @@ std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son } std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { - ethereum::withdrawal_encoder encoder; + const ethereum::withdrawal_encoder encoder; return encoder.encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string()); } std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) { - const auto ¤t_son = plugin.get_current_son_object(); - FC_ASSERT(current_son.sidechain_public_keys.contains(sidechain_type::ethereum), "No public keys for current son: ${account_id}", ("account_id", current_son.son_account)); + const auto ¤t_son = plugin.get_current_son_object(sidechain); + FC_ASSERT(current_son.sidechain_public_keys.contains(sidechain), "No public keys for current son: ${account_id}", ("account_id", current_son.son_account)); const auto &public_key = current_son.sidechain_public_keys.at(sidechain); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_factory.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_factory.cpp new file mode 100644 index 00000000..cd6b50be --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_factory.cpp @@ -0,0 +1,35 @@ +#include + +#include +#include +#include +#include + +namespace graphene { namespace peerplays_sidechain { + +sidechain_net_handler_factory::sidechain_net_handler_factory(peerplays_sidechain_plugin &_plugin) : + plugin(_plugin) { +} + +std::unique_ptr sidechain_net_handler_factory::create_handler(sidechain_type sidechain, const boost::program_options::variables_map &options) const { + switch (sidechain) { + case sidechain_type::bitcoin: { + return std::unique_ptr(new sidechain_net_handler_bitcoin(plugin, options)); + } + case sidechain_type::hive: { + return std::unique_ptr(new sidechain_net_handler_hive(plugin, options)); + } + case sidechain_type::ethereum: { + return std::unique_ptr(new sidechain_net_handler_ethereum(plugin, options)); + } + case sidechain_type::peerplays: { + return std::unique_ptr(new sidechain_net_handler_peerplays(plugin, options)); + } + default: + assert(false); + } + + return nullptr; +} + +}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp index a78b5f17..7d3c4de9 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp @@ -180,7 +180,7 @@ sidechain_net_handler_hive::~sidechain_net_handler_hive() { } bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { - //ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); + //ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id(sidechain))); bool should_approve = false; @@ -213,8 +213,8 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { const auto swo = idx.find(swo_id); if (swo != idx.end()) { - auto active_sons = gpo.active_sons; - vector wallet_sons = swo->sons; + auto active_sons = gpo.active_sons.at(sidechain); + vector wallet_sons = swo->sons.at(sidechain); bool son_sets_equal = (active_sons.size() == wallet_sons.size()); @@ -251,7 +251,7 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { uint32_t total_weight = 0; for (const auto &wallet_son : wallet_sons) { total_weight = total_weight + wallet_son.weight; - account_auths[wallet_son.sidechain_public_keys.at(sidechain)] = wallet_son.weight; + account_auths[wallet_son.public_key] = wallet_son.weight; } std::string memo_key = rpc_client->get_account_memo_key(wallet_account_name); @@ -487,12 +487,12 @@ void sidechain_net_handler_hive::process_primary_wallet() { const chain::global_property_object &gpo = database.get_global_properties(); - auto active_sons = gpo.active_sons; + const auto &active_sons = gpo.active_sons.at(sidechain); fc::flat_map account_auths; uint32_t total_weight = 0; for (const auto &active_son : active_sons) { total_weight = total_weight + active_son.weight; - account_auths[active_son.sidechain_public_keys.at(sidechain)] = active_son.weight; + account_auths[active_son.public_key] = active_son.weight; } std::string memo_key = rpc_client->get_account_memo_key(wallet_account_name); @@ -530,7 +530,7 @@ void sidechain_net_handler_hive::process_primary_wallet() { } proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); @@ -547,11 +547,11 @@ void sidechain_net_handler_hive::process_primary_wallet() { stc_op.object_id = active_sw->id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons; + stc_op.signers = gpo.active_sons.at(sidechain); proposal_op.proposed_ops.emplace_back(stc_op); - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); @@ -575,7 +575,7 @@ void sidechain_net_handler_hive::process_sidechain_addresses() { if (sao.expires == time_point_sec::maximum()) { if (sao.deposit_address == "") { sidechain_address_update_operation op; - op.payer = plugin.get_current_son_object().son_account; + op.payer = plugin.get_current_son_object(sidechain).son_account; op.sidechain_address_id = sao.id; op.sidechain_address_account = sao.sidechain_address_account; op.sidechain = sao.sidechain; @@ -585,7 +585,7 @@ void sidechain_net_handler_hive::process_sidechain_addresses() { op.withdraw_public_key = sao.withdraw_public_key; op.withdraw_address = sao.withdraw_address; - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); @@ -617,7 +617,7 @@ bool sidechain_net_handler_hive::process_deposit(const son_wallet_deposit_object } proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); @@ -633,7 +633,7 @@ bool sidechain_net_handler_hive::process_deposit(const son_wallet_deposit_object ai_op.issue_to_account = swdo.peerplays_from; proposal_op.proposed_ops.emplace_back(ai_op); - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); @@ -690,7 +690,7 @@ bool sidechain_net_handler_hive::process_withdrawal(const son_wallet_withdraw_ob //===== proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); @@ -704,10 +704,10 @@ bool sidechain_net_handler_hive::process_withdrawal(const son_wallet_withdraw_ob stc_op.object_id = swwo.id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons; + stc_op.signers = gpo.active_sons.at(sidechain); proposal_op.proposed_ops.emplace_back(stc_op); - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); @@ -730,7 +730,7 @@ std::string sidechain_net_handler_hive::process_sidechain_transaction(const side std::string chain_id_str = rpc_client->get_chain_id(); const hive::chain_id_type chain_id(chain_id_str); - fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))); + fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object(sidechain).sidechain_public_keys.at(sidechain))); signature_type st = htrx.sign(*privkey, chain_id); std::stringstream ss_st; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp index d5a9ec32..b2945251 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp @@ -53,7 +53,7 @@ sidechain_net_handler_peerplays::~sidechain_net_handler_peerplays() { bool sidechain_net_handler_peerplays::process_proposal(const proposal_object &po) { - ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); + ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id(sidechain))); bool should_approve = false; @@ -140,7 +140,7 @@ void sidechain_net_handler_peerplays::process_sidechain_addresses() { if (sao.expires == time_point_sec::maximum()) { if (sao.deposit_address == "") { sidechain_address_update_operation op; - op.payer = plugin.get_current_son_object().son_account; + op.payer = plugin.get_current_son_object(sidechain).son_account; op.sidechain_address_id = sao.id; op.sidechain_address_account = sao.sidechain_address_account; op.sidechain = sao.sidechain; @@ -150,7 +150,7 @@ void sidechain_net_handler_peerplays::process_sidechain_addresses() { op.withdraw_public_key = sao.withdraw_public_key; op.withdraw_address = sao.withdraw_address; - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); @@ -197,15 +197,15 @@ bool sidechain_net_handler_peerplays::process_deposit(const son_wallet_deposit_o stc_op.object_id = swdo.id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons; + stc_op.signers = gpo.active_sons.at(sidechain); proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + proposal_op.fee_paying_account = plugin.get_current_son_object(sidechain).son_account; proposal_op.proposed_ops.emplace_back(stc_op); uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id(sidechain)), proposal_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); @@ -230,7 +230,7 @@ std::string sidechain_net_handler_peerplays::process_sidechain_transaction(const signed_transaction trx; fc::raw::unpack(ss_trx, trx, 1000); - fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))); + fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object(sidechain).sidechain_public_keys.at(sidechain))); signature_type st = trx.sign(*privkey, database.get_chain_id()); std::stringstream ss_st; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp deleted file mode 100644 index adb9196d..00000000 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include - -namespace graphene { namespace peerplays_sidechain { - -sidechain_net_manager::sidechain_net_manager(peerplays_sidechain_plugin &_plugin) : - plugin(_plugin), - database(_plugin.database()) { - - //database.applied_block.connect([&](const signed_block &b) { - // on_applied_block(b); - //}); -} - -sidechain_net_manager::~sidechain_net_manager() { -} - -bool sidechain_net_manager::create_handler(sidechain_type sidechain, const boost::program_options::variables_map &options) { - - bool ret_val = false; - - switch (sidechain) { - case sidechain_type::bitcoin: { - std::unique_ptr h = std::unique_ptr(new sidechain_net_handler_bitcoin(plugin, options)); - net_handlers.push_back(std::move(h)); - ret_val = true; - break; - } - case sidechain_type::ethereum: { - std::unique_ptr h = std::unique_ptr(new sidechain_net_handler_ethereum(plugin, options)); - net_handlers.push_back(std::move(h)); - ret_val = true; - break; - } - case sidechain_type::hive: { - std::unique_ptr h = std::unique_ptr(new sidechain_net_handler_hive(plugin, options)); - net_handlers.push_back(std::move(h)); - ret_val = true; - break; - } - case sidechain_type::peerplays: { - std::unique_ptr h = std::unique_ptr(new sidechain_net_handler_peerplays(plugin, options)); - net_handlers.push_back(std::move(h)); - ret_val = true; - break; - } - default: - assert(false); - } - - return ret_val; -} - -void sidechain_net_manager::process_proposals() { - for (size_t i = 0; i < net_handlers.size(); i++) { - net_handlers.at(i)->process_proposals(); - } -} - -void sidechain_net_manager::process_active_sons_change() { - for (size_t i = 0; i < net_handlers.size(); i++) { - net_handlers.at(i)->process_active_sons_change(); - } -} - -void sidechain_net_manager::create_deposit_addresses() { - for (size_t i = 0; i < net_handlers.size(); i++) { - net_handlers.at(i)->create_deposit_addresses(); - } -} - -void sidechain_net_manager::process_deposits() { - for (size_t i = 0; i < net_handlers.size(); i++) { - net_handlers.at(i)->process_deposits(); - } -} - -void sidechain_net_manager::process_withdrawals() { - for (size_t i = 0; i < net_handlers.size(); i++) { - net_handlers.at(i)->process_withdrawals(); - } -} - -void sidechain_net_manager::process_sidechain_transactions() { - for (size_t i = 0; i < net_handlers.size(); i++) { - net_handlers.at(i)->process_sidechain_transactions(); - } -} - -void sidechain_net_manager::send_sidechain_transactions() { - for (size_t i = 0; i < net_handlers.size(); i++) { - net_handlers.at(i)->send_sidechain_transactions(); - } -} - -void sidechain_net_manager::settle_sidechain_transactions() { - for (size_t i = 0; i < net_handlers.size(); i++) { - net_handlers.at(i)->settle_sidechain_transactions(); - } -} - -std::map> sidechain_net_manager::get_son_listener_log() { - std::map> result; - for (size_t i = 0; i < net_handlers.size(); i++) { - result[net_handlers.at(i)->get_sidechain()] = net_handlers.at(i)->get_son_listener_log(); - } - return result; -} - -void sidechain_net_manager::on_applied_block(const signed_block &b) { -} - -}} // namespace graphene::peerplays_sidechain diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 185db897..0086c654 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -1610,6 +1610,7 @@ class wallet_api * * @param voting_account the name or id of the account who is voting with their shares * @param son the name or id of the SONs' owner account + * @param sidechain the name of the sidechain * @param approve true if you wish to vote in favor of that SON, false to * remove your vote in favor of that SON * @param broadcast true if you wish to broadcast the transaction @@ -1617,6 +1618,7 @@ class wallet_api */ signed_transaction vote_for_son(string voting_account, string son, + sidechain_type sidechain, bool approve, bool broadcast = false); @@ -1640,6 +1642,8 @@ class wallet_api * @param sons_to_reject the names or ids of the SONs owner accounts you wish * to reject (these will be removed from the list of SONs * you currently approve). This list can be empty. + * @param sidechain the name of the sidechain + * * @param desired_number_of_sons the number of SONs you believe the network * should have. You must vote for at least this many * SONs. You can set this to 0 to abstain from @@ -1650,6 +1654,7 @@ class wallet_api signed_transaction update_son_votes(string voting_account, std::vector sons_to_approve, std::vector sons_to_reject, + sidechain_type sidechain, uint16_t desired_number_of_sons, bool broadcast = false); diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 09aa5bdc..c334ebc2 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2230,69 +2230,99 @@ public: return sign_transaction( tx, broadcast ); } FC_CAPTURE_AND_RETHROW( (owner_account) ) } + //! Fixme - do we need to specify sidechain_type as params here? map list_active_sons() - { try { - global_property_object gpo = get_global_properties(); - vector son_ids; - son_ids.reserve(gpo.active_sons.size()); - std::transform(gpo.active_sons.begin(), gpo.active_sons.end(), - std::inserter(son_ids, son_ids.end()), - [](const son_info& swi) { - return swi.son_id; - }); - std::vector> son_objects = _remote_db->get_sons(son_ids); - vector owners; - for(auto obj: son_objects) + { + try { - std::string acc_id = account_id_to_string(obj->son_account); - owners.push_back(acc_id); - } - vector< optional< account_object> > accs = _remote_db->get_accounts(owners); - std::remove_if(son_objects.begin(), son_objects.end(), - [](const fc::optional& obj) -> bool { return obj.valid(); }); - map result; - std::transform(accs.begin(), accs.end(), son_objects.begin(), - std::inserter(result, result.end()), - [](fc::optional& acct, fc::optional son) { - FC_ASSERT(acct, "Invalid active SONs list in global properties."); - return std::make_pair(string(acct->name), std::move(son->id)); - }); - return result; - } FC_CAPTURE_AND_RETHROW() } - - map get_son_network_status() - { try { - global_property_object gpo = get_global_properties(); - vector son_ids; - son_ids.reserve(gpo.active_sons.size()); - std::transform(gpo.active_sons.begin(), gpo.active_sons.end(), - std::inserter(son_ids, son_ids.end()), - [](const son_info& swi) { - return swi.son_id; - }); - - map result; - std::vector> son_objects = _remote_db->get_sons(son_ids); - for(auto son_obj: son_objects) { - string status; - if (son_obj) { - son_statistics_object sso = get_object(son_obj->statistics); - if (sso.last_active_timestamp + fc::seconds(gpo.parameters.son_heartbeat_frequency()) > time_point::now()) { - status = "OK, regular SON heartbeat"; - } else { - if (sso.last_active_timestamp + fc::seconds(gpo.parameters.son_down_time()) > time_point::now()) { - status = "OK, irregular SON heartbeat, but not triggering SON down proposal"; - } else { - status = "NOT OK, irregular SON heartbeat, triggering SON down proposal"; - } - } - } else { - status = "NOT OK, invalid SON id"; + const global_property_object& gpo = get_global_properties(); + set son_ids_set; + for(const auto& active_sidechain_type : active_sidechain_types) + { + std::transform(gpo.active_sons.at(active_sidechain_type).cbegin(), gpo.active_sons.at(active_sidechain_type).cend(), + std::inserter(son_ids_set, son_ids_set.end()), + [](const son_info &swi) { + return swi.son_id; + }); } - result[son_obj->id] = status; + vector son_ids; + son_ids.reserve(son_ids_set.size()); + for(const auto& son_id : son_ids_set) + { + son_ids.emplace_back(son_id); + } + + std::vector> son_objects = _remote_db->get_sons(son_ids); + vector owners; + for(auto obj: son_objects) + { + std::string acc_id = account_id_to_string(obj->son_account); + owners.push_back(acc_id); + } + vector< optional< account_object> > accs = _remote_db->get_accounts(owners); + std::remove_if(son_objects.begin(), son_objects.end(), + [](const fc::optional& obj) -> bool { return obj.valid(); }); + map result; + std::transform(accs.begin(), accs.end(), son_objects.begin(), + std::inserter(result, result.end()), + [](fc::optional& acct, fc::optional son) { + FC_ASSERT(acct, "Invalid active SONs list in global properties."); + return std::make_pair(string(acct->name), std::move(son->id)); + }); + return result; } - return result; - } FC_CAPTURE_AND_RETHROW() } + FC_CAPTURE_AND_RETHROW() + } + + //! Fixme - do we need to specify sidechain_type as params here? + map get_son_network_status() + { + try + { + const global_property_object& gpo = get_global_properties(); + + set son_ids_set; + for(const auto& active_sidechain_type : active_sidechain_types) { + std::transform(gpo.active_sons.at(active_sidechain_type).cbegin(), gpo.active_sons.at(active_sidechain_type).cend(), + std::inserter(son_ids_set, son_ids_set.end()), + [](const son_info &swi) { + return swi.son_id; + }); + } + vector son_ids; + son_ids.reserve(son_ids_set.size()); + std::transform(son_ids_set.cbegin(), son_ids_set.cend(), + std::inserter(son_ids, son_ids.end()), + [](const son_id_type& sit) { + return sit; + }); + + map result; + std::vector> son_objects = _remote_db->get_sons(son_ids); + for(auto son_obj: son_objects) { + string status; + if (son_obj) { + son_statistics_object sso = get_object(son_obj->statistics); + for(const auto& active_sidechain_type : active_sidechain_types) { + if (sso.last_active_timestamp.at(active_sidechain_type) + fc::seconds(gpo.parameters.son_heartbeat_frequency()) > time_point::now()) { + status = "[OK, regular SON heartbeat for sidechain " + std::to_string(static_cast(active_sidechain_type)) + "] "; + } else { + if (sso.last_active_timestamp.at(active_sidechain_type) + fc::seconds(gpo.parameters.son_down_time()) > time_point::now()) { + status = "[OK, irregular SON heartbeat, but not triggering SON down proposal for sidechain " + std::to_string(static_cast(active_sidechain_type)) + "] "; + } else { + status = "[NOT OK, irregular SON heartbeat, triggering SON down proposal for sidechain " + std::to_string(static_cast(active_sidechain_type)) + "] "; + } + } + } + } else { + status = "NOT OK, invalid SON id"; + } + result[son_obj->id] = status; + } + return result; + } + FC_CAPTURE_AND_RETHROW() + } optional get_active_son_wallet() { try { @@ -2800,6 +2830,7 @@ public: signed_transaction vote_for_son(string voting_account, string son, + sidechain_type sidechain, bool approve, bool broadcast /* = false */) { try { @@ -2813,19 +2844,20 @@ public: account_object voting_account_object = get_account(voting_account); account_id_type son_account_id = get_account_id(son); fc::optional son_obj = _remote_db->get_son_by_account_id(son_account_id); - if (!son_obj) - FC_THROW("Account ${son} is not registered as a son", ("son", son)); + FC_ASSERT(son_obj, "Account ${son} is not registered as a son", ("son", son)); + FC_ASSERT(sidechain == sidechain_type::bitcoin || sidechain == sidechain_type::hive || sidechain == sidechain_type::ethereum, "Unexpected sidechain type"); + if (approve) { - auto insert_result = voting_account_object.options.votes.insert(son_obj->vote_id); + auto insert_result = voting_account_object.options.votes.insert(son_obj->get_sidechain_vote_id(sidechain)); if (!insert_result.second) - FC_THROW("Account ${account} was already voting for son ${son}", ("account", voting_account)("son", son)); + FC_THROW("Account ${account} has already voted for son ${son} for sidechain ${sidechain}", ("account", voting_account)("son", son)("sidechain", sidechain)); } else { - unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->vote_id); + unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->get_sidechain_vote_id(sidechain)); if (!votes_removed) - FC_THROW("Account ${account} is already not voting for son ${son}", ("account", voting_account)("son", son)); + FC_THROW("Account ${account} has already unvoted for son ${son} for sidechain ${sidechain}", ("account", voting_account)("son", son)("sidechain", sidechain)); } account_update_operation account_update_op; account_update_op.account = voting_account_object.id; @@ -2842,6 +2874,7 @@ public: signed_transaction update_son_votes(string voting_account, std::vector sons_to_approve, std::vector sons_to_reject, + sidechain_type sidechain, uint16_t desired_number_of_sons, bool broadcast /* = false */) { try { @@ -2857,9 +2890,10 @@ public: { account_id_type son_owner_account_id = get_account_id(son); fc::optional son_obj = _remote_db->get_son_by_account_id(son_owner_account_id); - if (!son_obj) - FC_THROW("Account ${son} is not registered as a SON", ("son", son)); - auto insert_result = voting_account_object.options.votes.insert(son_obj->vote_id); + FC_ASSERT(son_obj, "Account ${son} is not registered as a son", ("son", son)); + FC_ASSERT(sidechain == sidechain_type::bitcoin || sidechain == sidechain_type::hive || sidechain == sidechain_type::ethereum, "Unexpected sidechain type"); + + auto insert_result = voting_account_object.options.votes.insert(son_obj->get_sidechain_vote_id(sidechain)); if (!insert_result.second) FC_THROW("Account ${account} was already voting for SON ${son}", ("account", voting_account)("son", son)); } @@ -2867,13 +2901,15 @@ public: { account_id_type son_owner_account_id = get_account_id(son); fc::optional son_obj = _remote_db->get_son_by_account_id(son_owner_account_id); - if (!son_obj) - FC_THROW("Account ${son} is not registered as a SON", ("son", son)); - unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->vote_id); + FC_ASSERT(son_obj, "Account ${son} is not registered as a son", ("son", son)); + FC_ASSERT(sidechain == sidechain_type::bitcoin || sidechain == sidechain_type::hive || sidechain == sidechain_type::ethereum, "Unexpected sidechain type"); + + unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->get_sidechain_vote_id(sidechain)); if (!votes_removed) FC_THROW("Account ${account} is already not voting for SON ${son}", ("account", voting_account)("son", son)); } - voting_account_object.options.extensions.value.num_son = desired_number_of_sons; + FC_ASSERT( voting_account_object.options.extensions.value.num_son.valid() , "Invalid son number" ); + (*voting_account_object.options.extensions.value.num_son)[sidechain] = desired_number_of_sons; account_update_operation account_update_op; account_update_op.account = voting_account_object.id; @@ -2907,6 +2943,7 @@ public: case sidechain_type::peerplays : return "peerplays"; case sidechain_type::bitcoin : return "bitcoin"; case sidechain_type::hive : return "hive"; + case sidechain_type::ethereum : return "ethereum"; default: FC_THROW("Wrong sidechain type: ${sidechain}", ("sidechain", sidechain)); } @@ -5428,19 +5465,21 @@ signed_transaction wallet_api::vote_for_committee_member(string voting_account, signed_transaction wallet_api::vote_for_son(string voting_account, string son, + sidechain_type sidechain, bool approve, bool broadcast /* = false */) { - return my->vote_for_son(voting_account, son, approve, broadcast); + return my->vote_for_son(voting_account, son, sidechain, approve, broadcast); } signed_transaction wallet_api::update_son_votes(string voting_account, std::vector sons_to_approve, std::vector sons_to_reject, + sidechain_type sidechain, uint16_t desired_number_of_sons, bool broadcast /* = false */) { - return my->update_son_votes(voting_account, sons_to_approve, sons_to_reject, desired_number_of_sons, broadcast); + return my->update_son_votes(voting_account, sons_to_approve, sons_to_reject, sidechain, desired_number_of_sons, broadcast); } signed_transaction wallet_api::sidechain_deposit_transaction( const string &son_name_or_id, diff --git a/tests/cli/son.cpp b/tests/cli/son.cpp index 38a3799b..0e5d67cf 100644 --- a/tests/cli/son.cpp +++ b/tests/cli/son.cpp @@ -128,20 +128,34 @@ BOOST_AUTO_TEST_CASE( create_sons ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; sidechain_public_keys[sidechain_type::hive] = "hive account 1"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 1"; sth.create_son("son1account", "http://son1", sidechain_public_keys); sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; sidechain_public_keys[sidechain_type::hive] = "hive account 2"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 2"; sth.create_son("son2account", "http://son2", sidechain_public_keys); auto son1_obj = con.wallet_api_ptr->get_son("son1account"); BOOST_CHECK(son1_obj.son_account == con.wallet_api_ptr->get_account_id("son1account")); BOOST_CHECK_EQUAL(son1_obj.url, "http://son1"); + BOOST_CHECK_EQUAL(son1_obj.sidechain_public_keys[sidechain_type::bitcoin], "bitcoin_address 1"); + BOOST_CHECK_EQUAL(son1_obj.sidechain_public_keys[sidechain_type::hive], "hive account 1"); + BOOST_CHECK_EQUAL(son1_obj.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); auto son2_obj = con.wallet_api_ptr->get_son("son2account"); BOOST_CHECK(son2_obj.son_account == con.wallet_api_ptr->get_account_id("son2account")); BOOST_CHECK_EQUAL(son2_obj.url, "http://son2"); + BOOST_CHECK_EQUAL(son2_obj.sidechain_public_keys[sidechain_type::bitcoin], "bitcoin_address 2"); + BOOST_CHECK_EQUAL(son2_obj.sidechain_public_keys[sidechain_type::hive], "hive account 2"); + BOOST_CHECK_EQUAL(son2_obj.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); } catch( fc::exception& e ) { BOOST_TEST_MESSAGE("SON cli wallet tests exception"); @@ -162,6 +176,7 @@ BOOST_AUTO_TEST_CASE( cli_update_son ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; sidechain_public_keys[sidechain_type::hive] = "hive account 1"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 1"; son_test_helper sth(*this); sth.create_son("sonmember", "http://sonmember", sidechain_public_keys); @@ -172,15 +187,25 @@ BOOST_AUTO_TEST_CASE( cli_update_son ) auto son_data = con.wallet_api_ptr->get_son("sonmember"); BOOST_CHECK(son_data.url == "http://sonmember"); BOOST_CHECK(son_data.son_account == sonmember_acct.get_id()); + BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::bitcoin], "bitcoin_address 1"); + BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::hive], "hive account 1"); + BOOST_CHECK_EQUAL(son_data.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); // update SON sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; sidechain_public_keys[sidechain_type::hive] = "hive account 2"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 2"; con.wallet_api_ptr->update_son("sonmember", "http://sonmember_updated", "", sidechain_public_keys, true); son_data = con.wallet_api_ptr->get_son("sonmember"); BOOST_CHECK(son_data.url == "http://sonmember_updated"); + BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::bitcoin], "bitcoin_address 2"); + BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::hive], "hive account 2"); + BOOST_CHECK_EQUAL(son_data.sidechain_public_keys[sidechain_type::ethereum], "ethereum address 2"); // update SON signing key sidechain_public_keys.clear(); @@ -208,21 +233,28 @@ BOOST_AUTO_TEST_CASE( son_voting ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; sidechain_public_keys[sidechain_type::hive] = "hive account 1"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 1"; sth.create_son("son1account", "http://son1", sidechain_public_keys); sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; sidechain_public_keys[sidechain_type::hive] = "hive account 2"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 2"; sth.create_son("son2account", "http://son2", sidechain_public_keys); + BOOST_CHECK(generate_maintenance_block()); + BOOST_TEST_MESSAGE("Voting for SONs"); son_object son1_obj; son_object son2_obj; signed_transaction vote_son1_tx; signed_transaction vote_son2_tx; - uint64_t son1_start_votes, son1_end_votes; - uint64_t son2_start_votes, son2_end_votes; + flat_map son1_start_votes, son1_end_votes; + flat_map son2_start_votes, son2_end_votes; + + //! Get nathan account + const auto nathan_account_object = con.wallet_api_ptr->get_account("nathan"); son1_obj = con.wallet_api_ptr->get_son("son1account"); son1_start_votes = son1_obj.total_votes; @@ -232,85 +264,120 @@ BOOST_AUTO_TEST_CASE( son_voting ) con.wallet_api_ptr->create_vesting_balance("nathan", "1000", "1.3.0", vesting_balance_type::gpos, true); // Vote for a son1account BOOST_TEST_MESSAGE("Voting for son1account"); - vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", true, true); + vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::bitcoin, true, true); + vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::hive, true, true); + vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::ethereum, true, true); BOOST_CHECK(generate_maintenance_block()); // Verify that the vote is there son1_obj = con.wallet_api_ptr->get_son("son1account"); son1_end_votes = son1_obj.total_votes; - BOOST_CHECK(son1_end_votes > son1_start_votes); + BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] > son1_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son1_end_votes[sidechain_type::hive] > son1_start_votes[sidechain_type::hive]); + BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] > son1_start_votes[sidechain_type::ethereum]); // Vote for a son2account BOOST_TEST_MESSAGE("Voting for son2account"); - vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", true, true); + vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::bitcoin, true, true); + vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::hive, true, true); + vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::ethereum, true, true); BOOST_CHECK(generate_maintenance_block()); // Verify that the vote is there son2_obj = con.wallet_api_ptr->get_son("son2account"); son2_end_votes = son2_obj.total_votes; - BOOST_CHECK(son2_end_votes > son2_start_votes); - - //! Get nathan account - const auto nathan_account_object = con.wallet_api_ptr->get_account("nathan"); + BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] > son2_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son2_end_votes[sidechain_type::hive] > son2_start_votes[sidechain_type::hive]); + BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] > son2_start_votes[sidechain_type::ethereum]); //! Check son1account voters - auto voters_for_son1account = con.wallet_api_ptr->get_voters("son1account"); - BOOST_REQUIRE(voters_for_son1account.voters_for_son); - BOOST_CHECK_EQUAL(voters_for_son1account.voters_for_son->voters.size(), 1); - BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account.voters_for_son->voters[0].instance, nathan_account_object.id.instance()); + auto voters_for_son1account = con.wallet_api_ptr->get_voters("son1account").voters_for_son; + BOOST_REQUIRE(voters_for_son1account); + BOOST_REQUIRE_EQUAL(voters_for_son1account->at(sidechain_type::bitcoin).voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::bitcoin).voters[0].instance, nathan_account_object.id.instance()); + BOOST_REQUIRE_EQUAL(voters_for_son1account->at(sidechain_type::hive).voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::hive).voters[0].instance, nathan_account_object.id.instance()); + BOOST_REQUIRE_EQUAL(voters_for_son1account->at(sidechain_type::ethereum).voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::ethereum).voters[0].instance, nathan_account_object.id.instance()); //! Check son2account voters - auto voters_for_son2account = con.wallet_api_ptr->get_voters("son2account"); - BOOST_REQUIRE(voters_for_son2account.voters_for_son); - BOOST_CHECK_EQUAL(voters_for_son2account.voters_for_son->voters.size(), 1); - BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account.voters_for_son->voters[0].instance, nathan_account_object.id.instance()); + auto voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son; + BOOST_REQUIRE(voters_for_son2account); + BOOST_REQUIRE_EQUAL(voters_for_son2account->at(sidechain_type::bitcoin).voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::bitcoin).voters[0].instance, nathan_account_object.id.instance()); + BOOST_REQUIRE_EQUAL(voters_for_son2account->at(sidechain_type::hive).voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::hive).voters[0].instance, nathan_account_object.id.instance()); + BOOST_REQUIRE_EQUAL(voters_for_son2account->at(sidechain_type::ethereum).voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::ethereum).voters[0].instance, nathan_account_object.id.instance()); //! Check votes of nathan - auto nathan_votes = con.wallet_api_ptr->get_votes("nathan"); - BOOST_REQUIRE(nathan_votes.votes_for_sons); - BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons->size(), 2); - BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons->at(0).id.instance(), son1_obj.id.instance()); - BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons->at(1).id.instance(), son2_obj.id.instance()); + auto nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; + BOOST_REQUIRE(nathan_votes_for_son); + BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).size(), 2); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(0).id.instance(), son1_obj.id.instance()); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(1).id.instance(), son2_obj.id.instance()); + BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 2); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son1_obj.id.instance()); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(1).id.instance(), son2_obj.id.instance()); + BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).size(), 2); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(0).id.instance(), son1_obj.id.instance()); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(1).id.instance(), son2_obj.id.instance()); // Withdraw vote for a son1account BOOST_TEST_MESSAGE("Withdraw vote for a son1account"); - vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", false, true); + vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::bitcoin, false, true); + vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::hive, false, true); + vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", sidechain_type::ethereum, false, true); BOOST_CHECK(generate_maintenance_block()); // Verify that the vote is removed son1_obj = con.wallet_api_ptr->get_son("son1account"); son1_end_votes = son1_obj.total_votes; - BOOST_CHECK(son1_end_votes == son1_start_votes); + BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son1_end_votes[sidechain_type::hive] == son1_start_votes[sidechain_type::hive]); + BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] == son1_start_votes[sidechain_type::ethereum]); //! Check son1account voters - voters_for_son1account = con.wallet_api_ptr->get_voters("son1account"); - BOOST_REQUIRE(voters_for_son1account.voters_for_son); - BOOST_CHECK_EQUAL(voters_for_son1account.voters_for_son->voters.size(), 0); + voters_for_son1account = con.wallet_api_ptr->get_voters("son1account").voters_for_son; + BOOST_REQUIRE(voters_for_son1account); + BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::bitcoin).voters.size(), 0); + BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::hive).voters.size(), 0); + BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::ethereum).voters.size(), 0); //! Check votes of nathan - nathan_votes = con.wallet_api_ptr->get_votes("nathan"); - BOOST_REQUIRE(nathan_votes.votes_for_sons); - BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons->size(), 1); - BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons->at(0).id.instance(), son2_obj.id.instance()); + nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; + BOOST_REQUIRE(nathan_votes_for_son); + BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).size(), 1); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(0).id.instance(), son2_obj.id.instance()); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 1); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son2_obj.id.instance()); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).size(), 1); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(0).id.instance(), son2_obj.id.instance()); // Withdraw vote for a son2account BOOST_TEST_MESSAGE("Withdraw vote for a son2account"); - vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", false, true); + vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::bitcoin, false, true); + vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::hive, false, true); + vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", sidechain_type::ethereum, false, true); BOOST_CHECK(generate_maintenance_block()); // Verify that the vote is removed son2_obj = con.wallet_api_ptr->get_son("son2account"); son2_end_votes = son2_obj.total_votes; - BOOST_CHECK(son2_end_votes == son2_start_votes); + BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] == son2_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son2_end_votes[sidechain_type::hive] == son2_start_votes[sidechain_type::hive]); + BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] == son2_start_votes[sidechain_type::ethereum]); //! Check son2account voters - voters_for_son2account = con.wallet_api_ptr->get_voters("son2account"); - BOOST_REQUIRE(voters_for_son2account.voters_for_son); - BOOST_CHECK_EQUAL(voters_for_son2account.voters_for_son->voters.size(), 0); + voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son; + BOOST_REQUIRE(voters_for_son2account); + BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::bitcoin).voters.size(), 0); + BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::hive).voters.size(), 0); + BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::ethereum).voters.size(), 0); //! Check votes of nathan - nathan_votes = con.wallet_api_ptr->get_votes("nathan"); - BOOST_CHECK(!nathan_votes.votes_for_sons.valid()); + nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; + BOOST_CHECK(!nathan_votes_for_son); } catch( fc::exception& e ) { BOOST_TEST_MESSAGE("SON cli wallet tests exception"); @@ -348,6 +415,7 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i); sidechain_public_keys[sidechain_type::hive] = "hive account " + fc::to_pretty_string(i); + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address " + fc::to_pretty_string(i); sth.create_son("sonaccount" + fc::to_pretty_string(i), "http://son" + fc::to_pretty_string(i), sidechain_public_keys, @@ -363,7 +431,9 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture ) con.wallet_api_ptr->create_vesting_balance("sonaccount" + fc::to_pretty_string(i), "500", "1.3.0", vesting_balance_type::gpos, true); std::string name = "sonaccount" + fc::to_pretty_string(i); - vote_tx = con.wallet_api_ptr->vote_for_son(name, name, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::bitcoin, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::hive, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::ethereum, true, true); } BOOST_CHECK(generate_maintenance_block()); @@ -371,37 +441,55 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture ) { std::string name1 = "sonaccount" + fc::to_pretty_string(i); std::string name2 = "sonaccount" + fc::to_pretty_string(i + 1); - vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::bitcoin, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::ethereum, true, true); } gpo = con.wallet_api_ptr->get_global_properties(); - BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size()); + BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).size()); + BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size()); + BOOST_TEST_MESSAGE("gpo active_sons[ethereum]: " << gpo.active_sons.at(sidechain_type::ethereum).size()); BOOST_CHECK(generate_maintenance_block()); gpo = con.wallet_api_ptr->get_global_properties(); - BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size()); + BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).size()); + BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size()); + BOOST_TEST_MESSAGE("gpo active_sons[ethereum]: " << gpo.active_sons.at(sidechain_type::ethereum).size()); for(unsigned int i = 0; i < son_number - 1; i++) { std::string name1 = "sonaccount" + fc::to_pretty_string(i + 2); std::string name2 = "sonaccount" + fc::to_pretty_string(i); - vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::bitcoin, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::ethereum, true, true); } gpo = con.wallet_api_ptr->get_global_properties(); - BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size()); + BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).size()); + BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size()); + BOOST_TEST_MESSAGE("gpo active_sons[ethereum]: " << gpo.active_sons.at(sidechain_type::ethereum).size()); BOOST_CHECK(generate_maintenance_block()); gpo = con.wallet_api_ptr->get_global_properties(); - BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size()); + BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).size()); + BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size()); + BOOST_TEST_MESSAGE("gpo active_sons[ethereum]: " << gpo.active_sons.at(sidechain_type::ethereum).size()); for(unsigned int i = 0; i < son_number - 2; i++) { std::string name1 = "sonaccount" + fc::to_pretty_string(i + 3); std::string name2 = "sonaccount" + fc::to_pretty_string(i); - vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::bitcoin, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::ethereum, true, true); } gpo = con.wallet_api_ptr->get_global_properties(); - BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size()); + BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).size()); + BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size()); + BOOST_TEST_MESSAGE("gpo active_sons[ethereum]: " << gpo.active_sons.at(sidechain_type::ethereum).size()); BOOST_CHECK(generate_maintenance_block()); - BOOST_CHECK(gpo.active_sons.size() == son_number); + BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).size() == son_number); + BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == son_number); + BOOST_CHECK(gpo.active_sons.at(sidechain_type::ethereum).size() == son_number); } catch( fc::exception& e ) { BOOST_TEST_MESSAGE("SON cli wallet tests exception"); @@ -423,11 +511,13 @@ BOOST_AUTO_TEST_CASE( list_son ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; sidechain_public_keys[sidechain_type::hive] = "hive account 1"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 1"; sth.create_son("son1account", "http://son1", sidechain_public_keys); sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; sidechain_public_keys[sidechain_type::hive] = "hive account 2"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 2"; sth.create_son("son2account", "http://son2", sidechain_public_keys); auto res = con.wallet_api_ptr->list_sons("", 100); @@ -445,9 +535,9 @@ BOOST_AUTO_TEST_CASE( list_son ) BOOST_AUTO_TEST_CASE( update_son_votes_test ) { - BOOST_TEST_MESSAGE("SON update_son_votes cli wallet tests begin"); - try - { + BOOST_TEST_MESSAGE("SON update_son_votes cli wallet tests begin"); + try + { flat_map sidechain_public_keys; son_test_helper sth(*this); @@ -455,150 +545,283 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; sidechain_public_keys[sidechain_type::hive] = "hive account 1"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 1"; sth.create_son("son1account", "http://son1", sidechain_public_keys); sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; sidechain_public_keys[sidechain_type::hive] = "hive account 2"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 2"; sth.create_son("son2account", "http://son2", sidechain_public_keys); - BOOST_TEST_MESSAGE("Vote for 2 accounts with update_son_votes"); + BOOST_CHECK(generate_maintenance_block()); - son_object son1_obj; - son_object son2_obj; - uint64_t son1_start_votes, son1_end_votes; - uint64_t son2_start_votes, son2_end_votes; + BOOST_TEST_MESSAGE("Vote for 2 accounts with update_son_votes"); - // Get votes at start - son1_obj = con.wallet_api_ptr->get_son("son1account"); - son1_start_votes = son1_obj.total_votes; - son2_obj = con.wallet_api_ptr->get_son("son2account"); - son2_start_votes = son2_obj.total_votes; + son_object son1_obj; + son_object son2_obj; + flat_map son1_start_votes, son1_end_votes; + flat_map son2_start_votes, son2_end_votes; - std::vector accepted; - std::vector rejected; - signed_transaction update_votes_tx; + //! Get nathan account + const auto nathan_account_object = con.wallet_api_ptr->get_account("nathan"); - // Vote for both SONs - accepted.clear(); - rejected.clear(); - accepted.push_back("son1account"); - accepted.push_back("son2account"); - con.wallet_api_ptr->create_vesting_balance("nathan", "1000", "1.3.0", vesting_balance_type::gpos, true); - update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, - rejected, 2, true); - generate_block(); - BOOST_CHECK(generate_maintenance_block()); + // Get votes at start + son1_obj = con.wallet_api_ptr->get_son("son1account"); + son1_start_votes = son1_obj.total_votes; + son2_obj = con.wallet_api_ptr->get_son("son2account"); + son2_start_votes = son2_obj.total_votes; - // Verify the votes - son1_obj = con.wallet_api_ptr->get_son("son1account"); - son1_end_votes = son1_obj.total_votes; - BOOST_CHECK(son1_end_votes > son1_start_votes); - son1_start_votes = son1_end_votes; - son2_obj = con.wallet_api_ptr->get_son("son2account"); - son2_end_votes = son2_obj.total_votes; - BOOST_CHECK(son2_end_votes > son2_start_votes); - son2_start_votes = son2_end_votes; + std::vector accepted; + std::vector rejected; + signed_transaction update_votes_tx; + // Vote for both SONs + accepted.clear(); + rejected.clear(); + accepted.push_back("son1account"); + accepted.push_back("son2account"); + con.wallet_api_ptr->create_vesting_balance("nathan", "1000", "1.3.0", vesting_balance_type::gpos, true); + update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::bitcoin, 2, true); + update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::hive, 2, true); + update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::ethereum, 2, true); + generate_block(); + BOOST_CHECK(generate_maintenance_block()); - // Withdraw vote for SON 1 - accepted.clear(); - rejected.clear(); - rejected.push_back("son1account"); - con.wallet_api_ptr->create_vesting_balance("nathan", "1000", "1.3.0", vesting_balance_type::gpos, true); - update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, - rejected, 1, true); - BOOST_CHECK(generate_maintenance_block()); + // Verify the votes + son1_obj = con.wallet_api_ptr->get_son("son1account"); + son1_end_votes = son1_obj.total_votes; + BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] > son1_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son1_end_votes[sidechain_type::hive] > son1_start_votes[sidechain_type::hive]); + BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] > son1_start_votes[sidechain_type::ethereum]); + son1_start_votes = son1_end_votes; + son2_obj = con.wallet_api_ptr->get_son("son2account"); + son2_end_votes = son2_obj.total_votes; + BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] > son2_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son2_end_votes[sidechain_type::hive] > son2_start_votes[sidechain_type::hive]); + BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] > son2_start_votes[sidechain_type::ethereum]); + son2_start_votes = son2_end_votes; - // Verify the votes - son1_obj = con.wallet_api_ptr->get_son("son1account"); - son1_end_votes = son1_obj.total_votes; - BOOST_CHECK(son1_end_votes < son1_start_votes); - son1_start_votes = son1_end_votes; - son2_obj = con.wallet_api_ptr->get_son("son2account"); - // voice distribution changed, SON2 now has all voices - son2_end_votes = son2_obj.total_votes; - BOOST_CHECK((son2_end_votes > son2_start_votes)); // nathan spent funds for vb, it has different voting power - son2_start_votes = son2_end_votes; + //! Check son1account voters + auto voters_for_son1account = con.wallet_api_ptr->get_voters("son1account").voters_for_son; + BOOST_REQUIRE(voters_for_son1account); + BOOST_REQUIRE_EQUAL(voters_for_son1account->at(sidechain_type::bitcoin).voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::bitcoin).voters[0].instance, nathan_account_object.id.instance()); + BOOST_REQUIRE_EQUAL(voters_for_son1account->at(sidechain_type::hive).voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::hive).voters[0].instance, nathan_account_object.id.instance()); + BOOST_REQUIRE_EQUAL(voters_for_son1account->at(sidechain_type::ethereum).voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account->at(sidechain_type::ethereum).voters[0].instance, nathan_account_object.id.instance()); - // Try to reject incorrect SON - accepted.clear(); - rejected.clear(); - rejected.push_back("son1accnt"); - BOOST_CHECK_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, - rejected, 1, true), fc::exception); - generate_block(); + //! Check son2account voters + auto voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son; + BOOST_REQUIRE(voters_for_son2account); + BOOST_REQUIRE_EQUAL(voters_for_son2account->at(sidechain_type::bitcoin).voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::bitcoin).voters[0].instance, nathan_account_object.id.instance()); + BOOST_REQUIRE_EQUAL(voters_for_son2account->at(sidechain_type::hive).voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::hive).voters[0].instance, nathan_account_object.id.instance()); + BOOST_REQUIRE_EQUAL(voters_for_son2account->at(sidechain_type::ethereum).voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account->at(sidechain_type::ethereum).voters[0].instance, nathan_account_object.id.instance()); - // Verify the votes - son1_obj = con.wallet_api_ptr->get_son("son1account"); - son1_end_votes = son1_obj.total_votes; - BOOST_CHECK(son1_end_votes == son1_start_votes); - son1_start_votes = son1_end_votes; - son2_obj = con.wallet_api_ptr->get_son("son2account"); - son2_end_votes = son2_obj.total_votes; - BOOST_CHECK(son2_end_votes == son2_start_votes); - son2_start_votes = son2_end_votes; + //! Check votes of nathan + auto nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; + BOOST_REQUIRE(nathan_votes_for_son); + BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).size(), 2); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(0).id.instance(), son1_obj.id.instance()); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(1).id.instance(), son2_obj.id.instance()); + BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 2); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son1_obj.id.instance()); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(1).id.instance(), son2_obj.id.instance()); + BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).size(), 2); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(0).id.instance(), son1_obj.id.instance()); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(1).id.instance(), son2_obj.id.instance()); - // Reject SON2 - accepted.clear(); - rejected.clear(); - rejected.push_back("son2account"); - update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, - rejected, 0, true); - BOOST_CHECK(generate_maintenance_block()); + // Withdraw vote for SON 1 + accepted.clear(); + rejected.clear(); + rejected.push_back("son1account"); + con.wallet_api_ptr->create_vesting_balance("nathan", "1000", "1.3.0", vesting_balance_type::gpos, true); + update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::bitcoin, 1, true); + update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::hive, 1, true); + update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::ethereum, 1, true); + BOOST_CHECK(generate_maintenance_block()); - // Verify the votes - son1_obj = con.wallet_api_ptr->get_son("son1account"); - son1_end_votes = son1_obj.total_votes; - BOOST_CHECK(son1_end_votes == son1_start_votes); - son1_start_votes = son1_end_votes; - son2_obj = con.wallet_api_ptr->get_son("son2account"); - son2_end_votes = son2_obj.total_votes; - BOOST_CHECK(son2_end_votes < son2_start_votes); - son2_start_votes = son2_end_votes; + // Verify the votes + son1_obj = con.wallet_api_ptr->get_son("son1account"); + son1_end_votes = son1_obj.total_votes; + BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] < son1_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son1_end_votes[sidechain_type::hive] < son1_start_votes[sidechain_type::hive]); + BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] < son1_start_votes[sidechain_type::ethereum]); + son1_start_votes = son1_end_votes; + son2_obj = con.wallet_api_ptr->get_son("son2account"); + // voice distribution changed, SON2 now has all voices + son2_end_votes = son2_obj.total_votes; + BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] > son2_start_votes[sidechain_type::bitcoin]); // nathan spent funds for vb, it has different voting power + BOOST_CHECK(son2_end_votes[sidechain_type::hive] > son2_start_votes[sidechain_type::hive]); + BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] > son2_start_votes[sidechain_type::ethereum]); + son2_start_votes = son2_end_votes; - // Try to accept and reject the same SON - accepted.clear(); - rejected.clear(); - rejected.push_back("son1accnt"); - accepted.push_back("son1accnt"); - BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, - rejected, 1, true), fc::exception); - BOOST_CHECK(generate_maintenance_block()); + //! Check son1account voters + voters_for_son1account = con.wallet_api_ptr->get_voters("son1account").voters_for_son; + BOOST_REQUIRE(voters_for_son1account); + BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::bitcoin).voters.size(), 0); + BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::hive).voters.size(), 0); + BOOST_CHECK_EQUAL(voters_for_son1account->at(sidechain_type::ethereum).voters.size(), 0); - // Verify the votes - son1_obj = con.wallet_api_ptr->get_son("son1account"); - son1_end_votes = son1_obj.total_votes; - BOOST_CHECK(son1_end_votes == son1_start_votes); - son1_start_votes = son1_end_votes; - son2_obj = con.wallet_api_ptr->get_son("son2account"); - son2_end_votes = son2_obj.total_votes; - BOOST_CHECK(son2_end_votes == son2_start_votes); - son2_start_votes = son2_end_votes; + //! Check votes of nathan + nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; + BOOST_REQUIRE(nathan_votes_for_son); + BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).size(), 1); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(0).id.instance(), son2_obj.id.instance()); + BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 1); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son2_obj.id.instance()); + BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).size(), 1); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(0).id.instance(), son2_obj.id.instance()); - // Try to accept and reject empty lists - accepted.clear(); - rejected.clear(); - BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, - rejected, 1, true), fc::exception); - BOOST_CHECK(generate_maintenance_block()); + // Try to reject incorrect SON + accepted.clear(); + rejected.clear(); + rejected.push_back("son1accnt"); + BOOST_CHECK_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::bitcoin, 1, true), fc::exception); + BOOST_CHECK_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::hive, 1, true), fc::exception); + BOOST_CHECK_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::ethereum, 1, true), fc::exception); + generate_block(); - // Verify the votes - son1_obj = con.wallet_api_ptr->get_son("son1account"); - son1_end_votes = son1_obj.total_votes; - BOOST_CHECK(son1_end_votes == son1_start_votes); - son1_start_votes = son1_end_votes; - son2_obj = con.wallet_api_ptr->get_son("son2account"); - son2_end_votes = son2_obj.total_votes; - BOOST_CHECK(son2_end_votes == son2_start_votes); - son2_start_votes = son2_end_votes; + // Verify the votes + son1_obj = con.wallet_api_ptr->get_son("son1account"); + son1_end_votes = son1_obj.total_votes; + BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son1_end_votes[sidechain_type::hive] == son1_start_votes[sidechain_type::hive]); + BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] == son1_start_votes[sidechain_type::ethereum]); + son1_start_votes = son1_end_votes; + son2_obj = con.wallet_api_ptr->get_son("son2account"); + son2_end_votes = son2_obj.total_votes; + BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] == son2_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son2_end_votes[sidechain_type::hive] == son2_start_votes[sidechain_type::hive]); + BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] == son2_start_votes[sidechain_type::ethereum]); + son2_start_votes = son2_end_votes; - } catch( fc::exception& e ) { - BOOST_TEST_MESSAGE("SON cli wallet tests exception"); - edump((e.to_detail_string())); - throw; - } - BOOST_TEST_MESSAGE("SON update_son_votes cli wallet tests end"); + //! Check votes of nathan + nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; + BOOST_REQUIRE(nathan_votes_for_son); + BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).size(), 1); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::bitcoin).at(0).id.instance(), son2_obj.id.instance()); + BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).size(), 1); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::hive).at(0).id.instance(), son2_obj.id.instance()); + BOOST_REQUIRE_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).size(), 1); + BOOST_CHECK_EQUAL(nathan_votes_for_son->at(sidechain_type::ethereum).at(0).id.instance(), son2_obj.id.instance()); + + // Reject SON2 + accepted.clear(); + rejected.clear(); + rejected.push_back("son2account"); + update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::bitcoin, 0, true); + update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::hive, 0, true); + update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::ethereum, 0, true); + BOOST_CHECK(generate_maintenance_block()); + + // Verify the votes + son1_obj = con.wallet_api_ptr->get_son("son1account"); + son1_end_votes = son1_obj.total_votes; + BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son1_end_votes[sidechain_type::hive] == son1_start_votes[sidechain_type::hive]); + BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] == son1_start_votes[sidechain_type::ethereum]); + son1_start_votes = son1_end_votes; + son2_obj = con.wallet_api_ptr->get_son("son2account"); + son2_end_votes = son2_obj.total_votes; + BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] < son2_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son2_end_votes[sidechain_type::hive] < son2_start_votes[sidechain_type::hive]); + BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] < son2_start_votes[sidechain_type::ethereum]); + son2_start_votes = son2_end_votes; + + //! Check son2account voters + voters_for_son2account = con.wallet_api_ptr->get_voters("son2account").voters_for_son; + BOOST_REQUIRE(voters_for_son2account); + BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::bitcoin).voters.size(), 0); + BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::hive).voters.size(), 0); + BOOST_CHECK_EQUAL(voters_for_son2account->at(sidechain_type::ethereum).voters.size(), 0); + + //! Check votes of nathan + nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; + BOOST_REQUIRE(!nathan_votes_for_son); + + // Try to accept and reject the same SON + accepted.clear(); + rejected.clear(); + rejected.push_back("son1accnt"); + accepted.push_back("son1accnt"); + BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::bitcoin, 1, true), fc::exception); + BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::hive, 1, true), fc::exception); + BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::ethereum, 1, true), fc::exception); + BOOST_CHECK(generate_maintenance_block()); + + // Verify the votes + son1_obj = con.wallet_api_ptr->get_son("son1account"); + son1_end_votes = son1_obj.total_votes; + BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son1_end_votes[sidechain_type::hive] == son1_start_votes[sidechain_type::hive]); + BOOST_CHECK(son1_end_votes[sidechain_type::ethereum] == son1_start_votes[sidechain_type::ethereum]); + son1_start_votes = son1_end_votes; + son2_obj = con.wallet_api_ptr->get_son("son2account"); + son2_end_votes = son2_obj.total_votes; + BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] == son2_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son2_end_votes[sidechain_type::hive] == son2_start_votes[sidechain_type::hive]); + BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] == son2_start_votes[sidechain_type::ethereum]); + son2_start_votes = son2_end_votes; + + //! Check votes of nathan + nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; + BOOST_REQUIRE(!nathan_votes_for_son); + + // Try to accept and reject empty lists + accepted.clear(); + rejected.clear(); + BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::bitcoin, 1, true), fc::exception); + BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::hive, 1, true), fc::exception); + BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted, rejected, + sidechain_type::ethereum, 1, true), fc::exception); + BOOST_CHECK(generate_maintenance_block()); + + // Verify the votes + son1_obj = con.wallet_api_ptr->get_son("son1account"); + son1_end_votes = son1_obj.total_votes; + BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son1_end_votes[sidechain_type::hive] == son1_start_votes[sidechain_type::hive]); + BOOST_CHECK(son1_end_votes[sidechain_type::bitcoin] == son1_start_votes[sidechain_type::bitcoin]); + son1_start_votes = son1_end_votes; + son2_obj = con.wallet_api_ptr->get_son("son2account"); + son2_end_votes = son2_obj.total_votes; + BOOST_CHECK(son2_end_votes[sidechain_type::bitcoin] == son2_start_votes[sidechain_type::bitcoin]); + BOOST_CHECK(son2_end_votes[sidechain_type::hive] == son2_start_votes[sidechain_type::hive]); + BOOST_CHECK(son2_end_votes[sidechain_type::ethereum] == son2_start_votes[sidechain_type::ethereum]); + son2_start_votes = son2_end_votes; + + //! Check votes of nathan + nathan_votes_for_son = con.wallet_api_ptr->get_votes("nathan").votes_for_sons; + BOOST_REQUIRE(!nathan_votes_for_son); + + } catch( fc::exception& e ) { + BOOST_TEST_MESSAGE("SON cli wallet tests exception"); + edump((e.to_detail_string())); + throw; + } + BOOST_TEST_MESSAGE("SON update_son_votes cli wallet tests end"); } BOOST_AUTO_TEST_CASE( related_functions ) @@ -607,7 +830,9 @@ BOOST_AUTO_TEST_CASE( related_functions ) try { global_property_object gpo = con.wallet_api_ptr->get_global_properties(); - BOOST_CHECK(gpo.active_sons.size() == 0); + BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).size() == 0); + BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == 0); + BOOST_CHECK(gpo.active_sons.at(sidechain_type::ethereum).size() == 0); flat_map sidechain_public_keys; @@ -616,15 +841,19 @@ BOOST_AUTO_TEST_CASE( related_functions ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; sidechain_public_keys[sidechain_type::hive] = "hive account 1"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 1"; sth.create_son("son1account", "http://son1", sidechain_public_keys); sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; sidechain_public_keys[sidechain_type::hive] = "hive account 2"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address 2"; sth.create_son("son2account", "http://son2", sidechain_public_keys); gpo = con.wallet_api_ptr->get_global_properties(); - BOOST_CHECK(gpo.active_sons.size() == 2); + BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).size() == 2); + BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == 2); + BOOST_CHECK(gpo.active_sons.at(sidechain_type::ethereum).size() == 2); } catch( fc::exception& e ) { BOOST_TEST_MESSAGE("SON cli wallet tests exception"); @@ -651,11 +880,12 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture ) flat_map sidechain_public_keys; // create son accounts - for(unsigned int i = 0; i < son_number + 1; i++) + for(unsigned int i = 1; i < son_number + 1; i++) { sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i); sidechain_public_keys[sidechain_type::hive] = "hive account " + fc::to_pretty_string(i); + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address " + fc::to_pretty_string(i); sth.create_son("sonaccount" + fc::to_pretty_string(i), "http://son" + fc::to_pretty_string(i), sidechain_public_keys, @@ -670,7 +900,9 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture ) for(unsigned int i = 1; i < son_number + 1; i++) { std::string name = "sonaccount" + fc::to_pretty_string(i); - vote_tx = con.wallet_api_ptr->vote_for_son(name, name, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::bitcoin, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::hive, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name, name, sidechain_type::ethereum, true, true); } BOOST_CHECK(generate_maintenance_block()); @@ -678,13 +910,19 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture ) { std::string name1 = "sonaccount" + fc::to_pretty_string(i); std::string name2 = "sonaccount" + fc::to_pretty_string(i + 1); - vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::bitcoin, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::hive, true, true); + vote_tx = con.wallet_api_ptr->vote_for_son(name1, name2, sidechain_type::ethereum, true, true); } BOOST_CHECK(generate_maintenance_block()); gpo = con.wallet_api_ptr->get_global_properties(); - BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size()); + BOOST_TEST_MESSAGE("gpo active_sons[bitcoin]: " << gpo.active_sons.at(sidechain_type::bitcoin).size()); + BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::hive).size()); + BOOST_TEST_MESSAGE("gpo active_sons[hive]: " << gpo.active_sons.at(sidechain_type::ethereum).size()); - BOOST_CHECK(gpo.active_sons.size() == son_number); + BOOST_CHECK(gpo.active_sons.at(sidechain_type::bitcoin).size() == son_number); + BOOST_CHECK(gpo.active_sons.at(sidechain_type::hive).size() == son_number); + BOOST_CHECK(gpo.active_sons.at(sidechain_type::ethereum).size() == son_number); map active_sons = con.wallet_api_ptr->list_active_sons(); BOOST_CHECK(active_sons.size() == son_number); @@ -724,6 +962,7 @@ BOOST_AUTO_TEST_CASE( maintenance_test ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i); sidechain_public_keys[sidechain_type::hive] = "hive account " + fc::to_pretty_string(i); + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address " + fc::to_pretty_string(i); sth.create_son("sonaccount" + fc::to_pretty_string(i), "http://son" + fc::to_pretty_string(i), sidechain_public_keys, @@ -737,12 +976,16 @@ BOOST_AUTO_TEST_CASE( maintenance_test ) con.wallet_api_ptr->transfer( "nathan", "sonaccount" + fc::to_pretty_string(i), "1000", "1.3.0", "Here are some CORE tokens for your new account", true ); con.wallet_api_ptr->create_vesting_balance("sonaccount" + fc::to_pretty_string(i), "500", "1.3.0", vesting_balance_type::gpos, true); - con.wallet_api_ptr->vote_for_son("sonaccount" + fc::to_pretty_string(i), name, true, true); + con.wallet_api_ptr->vote_for_son("sonaccount" + fc::to_pretty_string(i), name, sidechain_type::bitcoin, true, true); + con.wallet_api_ptr->vote_for_son("sonaccount" + fc::to_pretty_string(i), name, sidechain_type::hive, true, true); + con.wallet_api_ptr->vote_for_son("sonaccount" + fc::to_pretty_string(i), name, sidechain_type::ethereum, true, true); } BOOST_CHECK(generate_maintenance_block()); son_object son_obj = con.wallet_api_ptr->get_son(name); - BOOST_CHECK(son_obj.status == son_status::active); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::active); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::active); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::ethereum) == son_status::active); // put SON in maintenance mode con.wallet_api_ptr->request_son_maintenance(name, true); @@ -750,7 +993,9 @@ BOOST_AUTO_TEST_CASE( maintenance_test ) // check SON is in request_maintenance son_obj = con.wallet_api_ptr->get_son(name); - BOOST_CHECK(son_obj.status == son_status::request_maintenance); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::request_maintenance); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::request_maintenance); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::ethereum) == son_status::request_maintenance); // restore SON activity con.wallet_api_ptr->cancel_request_son_maintenance(name, true); @@ -758,7 +1003,9 @@ BOOST_AUTO_TEST_CASE( maintenance_test ) // check SON is active son_obj = con.wallet_api_ptr->get_son(name); - BOOST_CHECK(son_obj.status == son_status::active); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::active); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::active); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::ethereum) == son_status::active); // put SON in maintenance mode con.wallet_api_ptr->request_son_maintenance(name, true); @@ -766,15 +1013,18 @@ BOOST_AUTO_TEST_CASE( maintenance_test ) // check SON is in request_maintenance son_obj = con.wallet_api_ptr->get_son(name); - BOOST_CHECK(son_obj.status == son_status::request_maintenance); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::request_maintenance); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::request_maintenance); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::ethereum) == son_status::request_maintenance); // process maintenance BOOST_CHECK(generate_maintenance_block()); // check SON is in maintenance son_obj = con.wallet_api_ptr->get_son(name); - BOOST_CHECK(son_obj.status == son_status::in_maintenance); - + BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::in_maintenance); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::in_maintenance); + BOOST_CHECK(son_obj.statuses.at(sidechain_type::ethereum) == son_status::in_maintenance); } catch( fc::exception& e ) { BOOST_TEST_MESSAGE("SON cli wallet tests exception"); diff --git a/tests/peerplays_sidechain/ethereum_transaction_tests.cpp b/tests/peerplays_sidechain/ethereum_transaction_tests.cpp new file mode 100644 index 00000000..769c35b1 --- /dev/null +++ b/tests/peerplays_sidechain/ethereum_transaction_tests.cpp @@ -0,0 +1,147 @@ +#include + +#include +#include +#include + +using namespace graphene::peerplays_sidechain::ethereum; + +BOOST_AUTO_TEST_SUITE(ethereum_transaction_tests) + +BOOST_AUTO_TEST_CASE(withdrawal_encoder_test) { + const withdrawal_encoder encoder; + const auto tx = encoder.encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.0"); + BOOST_CHECK_EQUAL(tx, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000"); + + const auto tx1 = encoder.encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1"); + BOOST_CHECK_EQUAL(tx1, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); +} + +BOOST_AUTO_TEST_CASE(update_owners_encoder_test) { + std::vector> owners_weights; + owners_weights.emplace_back("5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12", 1); + owners_weights.emplace_back("76ce31bd03f601c3fc13732def921c5bac282676", 1); + + const update_owners_encoder encoder; + const auto tx = encoder.encode(owners_weights, "1.35.0"); + BOOST_CHECK_EQUAL(tx, "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"); + + owners_weights.emplace_back("09ee460834498a4ee361beb819470061b7381b49", 1); + const auto tx1 = encoder.encode(owners_weights, "1.36.1"); + BOOST_CHECK_EQUAL(tx1, "0x23ab6adf0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); +} + +BOOST_AUTO_TEST_CASE(raw_transaction_serialization_test) { + raw_transaction raw_tr; + raw_tr.nonce = "0x0"; + raw_tr.gas_price = "0x3b9aca07"; + raw_tr.gas_limit = "0x7a1200"; + raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348"; + raw_tr.value = ""; + raw_tr.data = ""; + raw_tr.chain_id = "0x21"; + + const auto tx = raw_tr.serialize(); + BOOST_CHECK_EQUAL(tx, "0xE480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C02903488080218080"); + + //! Change value + raw_tr.value = "0x1BC16D674EC80000"; + const auto tx1 = raw_tr.serialize(); + BOOST_CHECK_EQUAL(tx1, "0xEC80843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C0290348881BC16D674EC8000080218080"); + + //! Change data + raw_tr.data = "0x893d20e8"; + const auto tx2 = raw_tr.serialize(); + BOOST_CHECK_EQUAL(tx2, "0xF080843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C0290348881BC16D674EC8000084893D20E8218080"); +} + +BOOST_AUTO_TEST_CASE(raw_transaction_deserialization_test) { + const raw_transaction raw_tr{"E480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C02903488080218080"}; + + BOOST_CHECK_EQUAL(raw_tr.nonce, "0x0"); + BOOST_CHECK_EQUAL(raw_tr.gas_price, "0x3b9aca07"); + BOOST_CHECK_EQUAL(raw_tr.gas_limit, "0x7a1200"); + BOOST_CHECK_EQUAL(raw_tr.to, "0x875a7e0efe5140c80c5c822f99c02281c0290348"); + BOOST_CHECK_EQUAL(raw_tr.value, "0x0"); + BOOST_CHECK_EQUAL(raw_tr.data, ""); + BOOST_CHECK_EQUAL(raw_tr.chain_id, "0x21"); +} + +BOOST_AUTO_TEST_CASE(raw_transaction_hash_test) { + raw_transaction raw_tr; + raw_tr.nonce = "0x0"; + raw_tr.gas_price = "0x3b9aca07"; + raw_tr.gas_limit = "0x7a1200"; + raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348"; + raw_tr.value = ""; + raw_tr.data = ""; + raw_tr.chain_id = "0x21"; + + const auto tx = raw_tr.serialize(); + BOOST_CHECK_EQUAL(tx, "0xE480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C02903488080218080"); + + const auto hash = raw_tr.hash(); + const auto hash_str = fc::to_hex((char *)&hash[0], hash.size()); + BOOST_CHECK_EQUAL(hash_str, "34934410cd305f4fa4e75a2c9294d625d6fbba729b5642ed2ca757ead50bb1fb"); +} + +BOOST_AUTO_TEST_CASE(sign_transaction_test) { + raw_transaction raw_tr; + raw_tr.nonce = "0x0"; + raw_tr.gas_price = "0x3b9aca07"; + raw_tr.gas_limit = "0x7a1200"; + raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348"; + raw_tr.value = ""; + raw_tr.data = ""; + raw_tr.chain_id = "0x21"; + + const auto sign_tr = raw_tr.sign("eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060"); + BOOST_CHECK_EQUAL(sign_tr.r, "5f09de6ac850b2a9e94acd709c12d4e9adbabc6b72281ec0bbe13bca7e57c7ce"); + BOOST_CHECK_EQUAL(sign_tr.v, "65"); + BOOST_CHECK_EQUAL(sign_tr.s, "7ca5f26c5b3e25f14a32b18ac9a2a41b7c68efd3b04b118e1b1f4bf1c4e299b0"); +} + +BOOST_AUTO_TEST_CASE(sign_transaction_serialization_test) { + raw_transaction raw_tr; + raw_tr.nonce = "0x0"; + raw_tr.gas_price = "0x3b9aca07"; + raw_tr.gas_limit = "0x7a1200"; + raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348"; + raw_tr.value = ""; + raw_tr.data = ""; + raw_tr.chain_id = "0x21"; + + const auto sign_tr = raw_tr.sign("eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060"); + const auto tx = sign_tr.serialize(); + BOOST_CHECK_EQUAL(tx, "0xF86480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C0290348808065A05F09DE6AC850B2A9E94ACD709C12D4E9ADBABC6B72281EC0BBE13BCA7E57C7CEA07CA5F26C5B3E25F14A32B18AC9A2A41B7C68EFD3B04B118E1B1F4BF1C4E299B0"); +} + +BOOST_AUTO_TEST_CASE(sign_transaction_deserialization_test) { + const signed_transaction sign_tr{"0xF86480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C0290348808065A05F09DE6AC850B2A9E94ACD709C12D4E9ADBABC6B72281EC0BBE13BCA7E57C7CEA07CA5F26C5B3E25F14A32B18AC9A2A41B7C68EFD3B04B118E1B1F4BF1C4E299B0"}; + + BOOST_CHECK_EQUAL(sign_tr.nonce, "0x0"); + BOOST_CHECK_EQUAL(sign_tr.gas_price, "0x3b9aca07"); + BOOST_CHECK_EQUAL(sign_tr.gas_limit, "0x7a1200"); + BOOST_CHECK_EQUAL(sign_tr.to, "0x875a7e0efe5140c80c5c822f99c02281c0290348"); + BOOST_CHECK_EQUAL(sign_tr.value, "0x0"); + BOOST_CHECK_EQUAL(sign_tr.data, ""); +} + +BOOST_AUTO_TEST_CASE(sign_transaction_recover_test) { + const std::string chain_id = "0x21"; + + raw_transaction raw_tr; + raw_tr.nonce = "0x0"; + raw_tr.gas_price = "0x3b9aca07"; + raw_tr.gas_limit = "0x7a1200"; + raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348"; + raw_tr.value = ""; + raw_tr.data = ""; + raw_tr.chain_id = chain_id; + + const auto sign_tr = raw_tr.sign("eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060"); + const auto from = sign_tr.recover(chain_id); + BOOST_CHECK_EQUAL(from, "0x5fbbb31be52608d2f52247e8400b7fcaa9e0bc12"); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 4fb3a24d..807c495a 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -1040,14 +1040,9 @@ BOOST_FIXTURE_TEST_CASE( hardfork_son2_time, database_fixture ) generate_blocks(HARDFORK_SON3_TIME); // after this hardfork maximum son account should not reset the value - // on 7 after maintenance interval anymore. It must be GRAPHENE_DEFAULT_MAX_SONS + // on 7 after maintenance interval anymore. It must be HARDFORK_SON2_TIME BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maximum_son_count(), GRAPHENE_DEFAULT_MAX_SONS); - generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - generate_block(); - - BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maximum_son_count(), 15); - } FC_LOG_AND_RETHROW() } BOOST_FIXTURE_TEST_CASE( pop_block_twice, database_fixture ) diff --git a/tests/tests/sidechain_addresses_test.cpp b/tests/tests/sidechain_addresses_test.cpp index 755ad37f..818c1743 100644 --- a/tests/tests/sidechain_addresses_test.cpp +++ b/tests/tests/sidechain_addresses_test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include using namespace graphene::chain; using namespace graphene::chain::test; @@ -63,9 +64,135 @@ BOOST_AUTO_TEST_CASE( sidechain_address_update_test ) { INVOKE(sidechain_address_add_test); - GET_ACTOR(alice); + generate_block(); + + //! ----- BEGIN CREATE SON bob ----- + ACTORS((bob)); + upgrade_to_lifetime_member(bob); + + transfer( committee_account, bob_id, asset( 1000*GRAPHENE_BLOCKCHAIN_PRECISION ) ); + + set_expiration(db, trx); + std::string test_url = "https://create_son_test"; + + // create deposit vesting + vesting_balance_id_type deposit; + { + vesting_balance_create_operation op; + op.creator = bob_id; + op.owner = bob_id; + op.amount = asset(10*GRAPHENE_BLOCKCHAIN_PRECISION); + op.balance_type = vesting_balance_type::son; + op.policy = dormant_vesting_policy_initializer {}; + trx.clear(); + trx.operations.push_back(op); + + // amount in the son balance need to be at least 50 + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception ); + + op.amount = asset(50*GRAPHENE_BLOCKCHAIN_PRECISION); + trx.clear(); + + trx.operations.push_back(op); + processed_transaction ptx = PUSH_TX(db, trx, ~0); + deposit = ptx.operation_results[0].get(); + + auto deposit_vesting = db.get(ptx.operation_results[0].get()); + + BOOST_CHECK_EQUAL(deposit(db).balance.amount.value, 50*GRAPHENE_BLOCKCHAIN_PRECISION); + auto now = db.head_block_time(); + BOOST_CHECK_EQUAL(deposit(db).is_withdraw_allowed(now, asset(50*GRAPHENE_BLOCKCHAIN_PRECISION)), false); // cant withdraw + } + generate_block(); + set_expiration(db, trx); + + // create payment normal vesting + vesting_balance_id_type payment ; + { + vesting_balance_create_operation op; + op.creator = bob_id; + op.owner = bob_id; + op.amount = asset(1*GRAPHENE_BLOCKCHAIN_PRECISION); + op.balance_type = vesting_balance_type::normal; + op.policy = linear_vesting_policy_initializer {}; + op.validate(); + + trx.clear(); + trx.operations.push_back(op); + trx.validate(); + processed_transaction ptx = PUSH_TX(db, trx, ~0); + trx.clear(); + payment = ptx.operation_results[0].get(); + } + + generate_block(); + set_expiration(db, trx); + + // bob became son + { + flat_map sidechain_public_keys; + sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin address"; + sidechain_public_keys[sidechain_type::hive] = "hive address"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address"; + + son_create_operation op; + op.owner_account = bob_id; + op.url = test_url; + op.deposit = deposit; + op.pay_vb = payment; + op.signing_key = bob_public_key; + op.sidechain_public_keys = sidechain_public_keys; + + trx.clear(); + trx.operations.push_back(op); + sign(trx, bob_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + generate_block(); + + { + const auto &idx = db.get_index_type().indices().get(); + BOOST_REQUIRE(idx.size() == 1); + auto obj = idx.find(bob_id); + BOOST_REQUIRE(obj != idx.end()); + BOOST_CHECK(obj->url == test_url); + BOOST_CHECK(obj->signing_key == bob_public_key); + BOOST_CHECK(obj->sidechain_public_keys.at(sidechain_type::bitcoin) == "bitcoin address"); + BOOST_CHECK(obj->deposit.instance == deposit.instance.value); + BOOST_CHECK(obj->pay_vb.instance == payment.instance.value); + } + + // Note payment time just to generate enough blocks to make budget + const auto block_interval = db.get_global_properties().parameters.block_interval; + auto pay_fee_time = db.head_block_time().sec_since_epoch(); + generate_block(); + // Do maintenance from the upcoming block + auto schedule_maint = [&]() + { + db.modify( db.get_dynamic_global_properties(), [&]( dynamic_global_property_object& _dpo ) + { + _dpo.next_maintenance_time = db.head_block_time() + 1; + } ); + }; + + // Generate enough blocks to make budget + while( db.head_block_time().sec_since_epoch() - pay_fee_time < 100 * block_interval ) + { + generate_block(); + } + + // Enough blocks generated schedule maintenance now + schedule_maint(); + // This block triggers maintenance + generate_block(); + + //! ----- END CREATE SON bob ----- + + GET_ACTOR(alice); + const auto& idx = db.get_index_type().indices().get(); BOOST_REQUIRE( idx.size() == 1 ); auto obj = idx.find( boost::make_tuple( alice_id, sidechain_type::bitcoin, time_point_sec::maximum() ) ); @@ -77,19 +204,7 @@ BOOST_AUTO_TEST_CASE( sidechain_address_update_test ) { std::string new_withdraw_address = "withdraw_address"; generate_block(); - auto& son = db.create( [&]( son_object& sobj ) - { - sobj.son_account = bob_id; - sobj.statistics = db.create([&](son_statistics_object& s){s.owner = sobj.id;}).id; - }); - generate_block(); - db.modify( db.get_global_properties(), [&]( global_property_object& _gpo ) - { - son_info sinfo; - sinfo.son_id = son.id; - _gpo.active_sons.push_back(sinfo); - }); - generate_block(); + set_expiration(db, trx); { BOOST_TEST_MESSAGE("Send sidechain_address_update_operation"); trx.clear(); diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index 1e3bb7e4..a128b474 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -87,6 +87,8 @@ BOOST_AUTO_TEST_CASE( create_son_test ) { { flat_map sidechain_public_keys; sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin address"; + sidechain_public_keys[sidechain_type::hive] = "hive account"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address"; son_create_operation op; op.owner_account = alice_id; @@ -111,6 +113,8 @@ BOOST_AUTO_TEST_CASE( create_son_test ) { BOOST_CHECK( obj->url == test_url ); BOOST_CHECK( obj->signing_key == alice_public_key ); BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::bitcoin) == "bitcoin address" ); + BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::hive) == "hive account" ); + BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::ethereum) == "ethereum address" ); BOOST_CHECK( obj->deposit.instance == deposit.instance.value ); BOOST_CHECK( obj->pay_vb.instance == payment.instance.value ); } @@ -124,7 +128,9 @@ BOOST_AUTO_TEST_CASE( update_son_test ) { { flat_map sidechain_public_keys; - sidechain_public_keys[sidechain_type::bitcoin] = "new bitcoin address"; + sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin address"; + sidechain_public_keys[sidechain_type::hive] = "hive account"; + sidechain_public_keys[sidechain_type::ethereum] = "ethereum address"; son_update_operation op; op.son_id = son_id_type(0); @@ -143,7 +149,9 @@ BOOST_AUTO_TEST_CASE( update_son_test ) { auto obj = idx.find( alice_id ); BOOST_REQUIRE( obj != idx.end() ); BOOST_CHECK( obj->url == new_url ); - BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::bitcoin) == "new bitcoin address" ); + BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::bitcoin) == "bitcoin address" ); + BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::hive) == "hive account" ); + BOOST_CHECK( obj->sidechain_public_keys.at(sidechain_type::ethereum) == "ethereum address" ); } BOOST_AUTO_TEST_CASE( deregister_son_test ) { @@ -193,12 +201,16 @@ try { // Modify SON's status to active db.modify( *obj, [&]( son_object& _s) { - _s.status = son_status::in_maintenance; + _s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance; + _s.statuses[sidechain_type::hive] = son_status::in_maintenance; + _s.statuses[sidechain_type::ethereum] = son_status::in_maintenance; }); db.modify( *son_stats_obj, [&]( son_statistics_object& _s) { - _s.last_down_timestamp = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time()); + _s.last_down_timestamp[sidechain_type::bitcoin] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time()); + _s.last_down_timestamp[sidechain_type::hive] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time()); + _s.last_down_timestamp[sidechain_type::ethereum] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time()); }); auto deposit_vesting = db.get(vesting_balance_id_type(0)); @@ -218,7 +230,9 @@ try { generate_block(); BOOST_REQUIRE( idx.size() == 1 ); - BOOST_REQUIRE( obj->status == son_status::deregistered ); + BOOST_REQUIRE( obj->statuses.at(sidechain_type::bitcoin) == son_status::deregistered ); + BOOST_REQUIRE( obj->statuses.at(sidechain_type::hive) == son_status::deregistered ); + BOOST_REQUIRE( obj->statuses.at(sidechain_type::ethereum) == son_status::deregistered ); BOOST_REQUIRE( son_stats_obj->deregistered_timestamp == now ); deposit_vesting = db.get(vesting_balance_id_type(0)); @@ -493,30 +507,38 @@ BOOST_AUTO_TEST_CASE( son_pay_test ) { _s.txs_signed[sidechain_type::bitcoin] = 2; _s.txs_signed[sidechain_type::hive] = 4; + _s.txs_signed[sidechain_type::ethereum] = 6; _s.total_txs_signed[sidechain_type::bitcoin] = 2; _s.total_txs_signed[sidechain_type::hive] = 4; + _s.total_txs_signed[sidechain_type::ethereum] = 6; _s.sidechain_txs_reported[sidechain_type::bitcoin] = 4; _s.sidechain_txs_reported[sidechain_type::hive] = 8; + _s.sidechain_txs_reported[sidechain_type::ethereum] = 12; _s.total_sidechain_txs_reported[sidechain_type::bitcoin] = 4; _s.total_sidechain_txs_reported[sidechain_type::hive] = 8; + _s.total_sidechain_txs_reported[sidechain_type::ethereum] = 12; }); // Modify the transaction signed statistics of Bob's SON db.modify( *son_stats_obj2, [&]( son_statistics_object& _s) { _s.txs_signed[sidechain_type::bitcoin] = 3; _s.txs_signed[sidechain_type::hive] = 6; + _s.txs_signed[sidechain_type::ethereum] = 9; _s.total_txs_signed[sidechain_type::bitcoin] = 3; _s.total_txs_signed[sidechain_type::hive] = 6; + _s.total_txs_signed[sidechain_type::ethereum] = 9; _s.sidechain_txs_reported[sidechain_type::bitcoin] = 6; _s.sidechain_txs_reported[sidechain_type::hive] = 12; + _s.sidechain_txs_reported[sidechain_type::ethereum] = 18; _s.total_sidechain_txs_reported[sidechain_type::bitcoin] = 6; _s.total_sidechain_txs_reported[sidechain_type::hive] = 12; + _s.total_sidechain_txs_reported[sidechain_type::ethereum] = 18; }); // Note the balances before the maintenance @@ -528,21 +550,29 @@ BOOST_AUTO_TEST_CASE( son_pay_test ) // Check if the signed transaction statistics are reset for both SONs BOOST_REQUIRE_EQUAL(son_stats_obj1->txs_signed.at(sidechain_type::bitcoin), 0); BOOST_REQUIRE_EQUAL(son_stats_obj1->txs_signed.at(sidechain_type::hive), 0); + BOOST_REQUIRE_EQUAL(son_stats_obj1->txs_signed.at(sidechain_type::ethereum), 0); BOOST_REQUIRE_EQUAL(son_stats_obj2->txs_signed.at(sidechain_type::bitcoin), 0); BOOST_REQUIRE_EQUAL(son_stats_obj2->txs_signed.at(sidechain_type::hive), 0); + BOOST_REQUIRE_EQUAL(son_stats_obj2->txs_signed.at(sidechain_type::ethereum), 0); BOOST_REQUIRE_EQUAL(son_stats_obj1->sidechain_txs_reported.at(sidechain_type::bitcoin), 0); BOOST_REQUIRE_EQUAL(son_stats_obj1->sidechain_txs_reported.at(sidechain_type::hive), 0); + BOOST_REQUIRE_EQUAL(son_stats_obj1->sidechain_txs_reported.at(sidechain_type::ethereum), 0); BOOST_REQUIRE_EQUAL(son_stats_obj2->sidechain_txs_reported.at(sidechain_type::bitcoin), 0); BOOST_REQUIRE_EQUAL(son_stats_obj2->sidechain_txs_reported.at(sidechain_type::hive), 0); + BOOST_REQUIRE_EQUAL(son_stats_obj2->sidechain_txs_reported.at(sidechain_type::ethereum), 0); BOOST_REQUIRE_EQUAL(son_stats_obj1->total_txs_signed.at(sidechain_type::bitcoin), 2); BOOST_REQUIRE_EQUAL(son_stats_obj1->total_txs_signed.at(sidechain_type::hive), 4); + BOOST_REQUIRE_EQUAL(son_stats_obj1->total_txs_signed.at(sidechain_type::ethereum), 6); BOOST_REQUIRE_EQUAL(son_stats_obj2->total_txs_signed.at(sidechain_type::bitcoin), 3); BOOST_REQUIRE_EQUAL(son_stats_obj2->total_txs_signed.at(sidechain_type::hive), 6); + BOOST_REQUIRE_EQUAL(son_stats_obj2->total_txs_signed.at(sidechain_type::ethereum), 9); BOOST_REQUIRE_EQUAL(son_stats_obj1->total_sidechain_txs_reported.at(sidechain_type::bitcoin), 4); BOOST_REQUIRE_EQUAL(son_stats_obj1->total_sidechain_txs_reported.at(sidechain_type::hive), 8); + BOOST_REQUIRE_EQUAL(son_stats_obj1->total_sidechain_txs_reported.at(sidechain_type::ethereum), 12); BOOST_REQUIRE_EQUAL(son_stats_obj2->total_sidechain_txs_reported.at(sidechain_type::bitcoin), 6); BOOST_REQUIRE_EQUAL(son_stats_obj2->total_sidechain_txs_reported.at(sidechain_type::hive), 12); + BOOST_REQUIRE_EQUAL(son_stats_obj2->total_sidechain_txs_reported.at(sidechain_type::ethereum), 18); // Check that Alice and Bob are paid for signing the transactions in the previous day/cycle BOOST_REQUIRE_EQUAL(db.get_balance(obj1->son_account, asset_id_type()).amount.value, 80+obj1_balance); BOOST_REQUIRE_EQUAL(db.get_balance(obj2->son_account, asset_id_type()).amount.value, 120+obj2_balance); @@ -604,12 +634,16 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { // Modify SON's status to active db.modify( *obj, [&]( son_object& _s) { - _s.status = son_status::active; + _s.statuses[sidechain_type::bitcoin] = son_status::active; + _s.statuses[sidechain_type::hive] = son_status::active; + _s.statuses[sidechain_type::ethereum] = son_status::active; }); db.modify( *son_stats_obj, [&]( son_statistics_object& _s) { - _s.last_down_timestamp = fc::time_point_sec(db.head_block_time()); + _s.last_down_timestamp[sidechain_type::bitcoin] = fc::time_point_sec(db.head_block_time()); + _s.last_down_timestamp[sidechain_type::hive] = fc::time_point_sec(db.head_block_time()); + _s.last_down_timestamp[sidechain_type::ethereum] = fc::time_point_sec(db.head_block_time()); }); { @@ -626,7 +660,9 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { PUSH_TX( db, trx, ~0); generate_block(); trx.clear(); - BOOST_CHECK( obj->status == son_status::request_maintenance); + BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::request_maintenance); + BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::request_maintenance); + BOOST_CHECK( obj->statuses.at(sidechain_type::ethereum) == son_status::request_maintenance); } { @@ -643,16 +679,23 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { PUSH_TX( db, trx, ~0); generate_block(); trx.clear(); - BOOST_CHECK( obj->status == son_status::active); + BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::active); + BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active); + BOOST_CHECK( obj->statuses.at(sidechain_type::ethereum) == son_status::active); } // Modify SON's status to in_maintenance db.modify( *obj, [&]( son_object& _s) { - _s.status = son_status::in_maintenance; + _s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance; + _s.statuses[sidechain_type::hive] = son_status::in_maintenance; + _s.statuses[sidechain_type::ethereum] = son_status::in_maintenance; }); - uint64_t downtime = 0; + flat_map downtime; + downtime[sidechain_type::bitcoin] = 0; + downtime[sidechain_type::hive] = 0; + downtime[sidechain_type::ethereum] = 0; { generate_block(); @@ -668,16 +711,26 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { PUSH_TX( db, trx, ~0); generate_block(); trx.clear(); - BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime, op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch()); - downtime += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch(); - BOOST_CHECK( obj->status == son_status::inactive); - BOOST_CHECK( son_stats_obj->last_active_timestamp == op.ts); + BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::bitcoin), op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::bitcoin).sec_since_epoch()); + BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::hive), op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::hive).sec_since_epoch()); + 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); } // Modify SON's status to in_maintenance db.modify( *obj, [&]( son_object& _s) { - _s.status = son_status::in_maintenance; + _s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance; + _s.statuses[sidechain_type::hive] = son_status::in_maintenance; + _s.statuses[sidechain_type::ethereum] = son_status::in_maintenance; }); // SON is selected as one of the active SONs @@ -685,7 +738,9 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { { son_info son_inf; son_inf.son_id = son_id_type(0); - _gpo.active_sons.push_back(son_inf); + _gpo.active_sons[sidechain_type::bitcoin].push_back(son_inf); + _gpo.active_sons[sidechain_type::hive].push_back(son_inf); + _gpo.active_sons[sidechain_type::ethereum].push_back(son_inf); }); { @@ -702,10 +757,19 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { PUSH_TX( db, trx, ~0); generate_block(); trx.clear(); - BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime, downtime + op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch()); - downtime += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch(); - BOOST_CHECK( obj->status == son_status::active); - BOOST_CHECK( son_stats_obj->last_active_timestamp == op.ts); + + BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::bitcoin), downtime.at(sidechain_type::bitcoin) + op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::bitcoin).sec_since_epoch()); + BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::hive), downtime.at(sidechain_type::hive) + op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.at(sidechain_type::hive).sec_since_epoch()); + 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); } { @@ -722,9 +786,15 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { PUSH_TX( db, trx, ~0); generate_block(); trx.clear(); - BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime, downtime); - BOOST_CHECK( obj->status == son_status::active); - BOOST_CHECK( son_stats_obj->last_active_timestamp == op.ts); + BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::bitcoin), downtime.at(sidechain_type::bitcoin)); + BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::hive), downtime.at(sidechain_type::hive)); + BOOST_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); } } FC_LOG_AND_RETHROW() } @@ -749,7 +819,9 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) { auto son_stats_obj = sidx.find( obj->statistics ); BOOST_REQUIRE( son_stats_obj != sidx.end() ); - BOOST_CHECK( obj->status == son_status::active); + BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::active); + BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active); + BOOST_CHECK( obj->statuses.at(sidechain_type::ethereum) == son_status::active); { // Check that transaction fails if down_ts < last_active_timestamp @@ -758,7 +830,7 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) { son_report_down_operation op; op.payer = db.get_global_properties().parameters.son_account(); op.son_id = son_id_type(0); - op.down_ts = fc::time_point_sec(son_stats_obj->last_active_timestamp - fc::seconds(1)); + op.down_ts = fc::time_point_sec(son_stats_obj->last_active_timestamp.at(sidechain_type::bitcoin) - fc::seconds(1)); trx.operations.push_back(op); set_expiration(db, trx); @@ -775,7 +847,7 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) { son_report_down_operation op; op.payer = alice_id; op.son_id = son_id_type(0); - op.down_ts = son_stats_obj->last_active_timestamp; + op.down_ts = son_stats_obj->last_active_timestamp.at(sidechain_type::bitcoin); trx.operations.push_back(op); set_expiration(db, trx); @@ -792,7 +864,7 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) { son_report_down_operation op; op.payer = db.get_global_properties().parameters.son_account(); op.son_id = son_id_type(0); - op.down_ts = son_stats_obj->last_active_timestamp; + op.down_ts = son_stats_obj->last_active_timestamp.at(sidechain_type::bitcoin); trx.operations.push_back(op); set_expiration(db, trx); @@ -801,8 +873,12 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) { generate_block(); trx.clear(); - BOOST_CHECK( obj->status == son_status::in_maintenance); - BOOST_CHECK( son_stats_obj->last_down_timestamp == op.down_ts); + BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::in_maintenance); + BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::in_maintenance); + BOOST_CHECK( 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); } { @@ -812,7 +888,7 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) { son_report_down_operation op; op.payer = db.get_global_properties().parameters.son_account(); op.son_id = son_id_type(0); - op.down_ts = son_stats_obj->last_active_timestamp; + op.down_ts = son_stats_obj->last_active_timestamp.at(sidechain_type::bitcoin); trx.operations.push_back(op); set_expiration(db, trx); diff --git a/tests/tests/son_wallet_tests.cpp b/tests/tests/son_wallet_tests.cpp index cef29b54..4b1e4fe2 100644 --- a/tests/tests/son_wallet_tests.cpp +++ b/tests/tests/son_wallet_tests.cpp @@ -154,13 +154,14 @@ BOOST_AUTO_TEST_CASE( son_wallet_recreate_test ) { op.payer = db.get_global_properties().parameters.son_account(); + //! Fixme - add hive tests { son_info si; si.son_id = son_id_type(0); si.weight = 1000; si.signing_key = alice_public_key; - si.sidechain_public_keys[sidechain_type::bitcoin] = ""; - op.sons.push_back(si); + si.public_key = ""; + op.sons[sidechain_type::bitcoin].push_back(si); } { @@ -168,8 +169,8 @@ BOOST_AUTO_TEST_CASE( son_wallet_recreate_test ) { si.son_id = son_id_type(1); si.weight = 1000; si.signing_key = bob_public_key; - si.sidechain_public_keys[sidechain_type::bitcoin] = ""; - op.sons.push_back(si); + si.public_key = ""; + op.sons[sidechain_type::bitcoin].push_back(si); } trx.operations.push_back(op); -- 2.45.2 From 21c9a84971d4262f194dfc95c3774ae5f42bf894 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Mon, 5 Sep 2022 00:38:00 +0200 Subject: [PATCH 58/60] Fix build & some cosmetic changes --- libraries/chain/db_init.cpp | 52 ++++++++----------- libraries/chain/db_maint.cpp | 11 ++-- libraries/chain/db_witness_schedule.cpp | 1 - .../include/graphene/chain/sidechain_defs.hpp | 2 +- .../peerplays_sidechain/common/utils.cpp | 1 - 5 files changed, 31 insertions(+), 36 deletions(-) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 0f989685..67790d04 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -1101,28 +1101,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) // Initialize witness schedule -#ifndef NDEBUG - const son_schedule_object& ssohive = -#endif - create([&](son_schedule_object& _sso) - { - // for scheduled - memset(_sso.rng_seed.begin(), 0, _sso.rng_seed.size()); - - witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); - - auto init_witnesses = get_global_properties().active_witnesses; - - _sso.scheduler = son_scheduler(); - _sso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1); - - - _sso.last_scheduling_block = 0; - - _sso.recent_slots_filled = fc::uint128::max_value(); - }); - assert( ssohive.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::hive)) ); - #ifndef NDEBUG const son_schedule_object& ssobitcoin = #endif @@ -1133,11 +1111,11 @@ void database::init_genesis(const genesis_state_type& genesis_state) witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); - auto init_witnesses = get_global_properties().active_witnesses; + auto init_bitcoin_sons = get_global_properties().active_sons.at(sidechain_type::bitcoin); _sso.scheduler = son_scheduler(); - _sso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1); - + _sso.scheduler._min_token_count = std::max(int(init_bitcoin_sons.size()) / 2, 1); + //_sso.scheduler.update(init_bitcoin_sons); _sso.last_scheduling_block = 0; @@ -1155,11 +1133,11 @@ void database::init_genesis(const genesis_state_type& genesis_state) witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); - auto init_witnesses = get_global_properties().active_witnesses; + auto init_ethereum_sons = get_global_properties().active_sons.at(sidechain_type::ethereum); _sso.scheduler = son_scheduler(); - _sso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1); - + _sso.scheduler._min_token_count = std::max(int(init_ethereum_sons.size()) / 2, 1); + //_sso.scheduler.update(init_ethereum_sons); _sso.last_scheduling_block = 0; @@ -1167,11 +1145,27 @@ void database::init_genesis(const genesis_state_type& genesis_state) }); assert( ssoethereum.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::ethereum)) ); +#ifndef NDEBUG + const son_schedule_object& ssohive = +#endif + create([&](son_schedule_object& _sso) + { + // for scheduled + memset(_sso.rng_seed.begin(), 0, _sso.rng_seed.size()); + + witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); + + auto init_hive_sons = get_global_properties().active_sons.at(sidechain_type::hive); + + _sso.scheduler = son_scheduler(); + _sso.scheduler._min_token_count = std::max(int(init_hive_sons.size()) / 2, 1); + //_sso.scheduler.update(init_hive_sons); + _sso.last_scheduling_block = 0; _sso.recent_slots_filled = fc::uint128::max_value(); }); - assert( ssobitcoin.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::bitcoin)) ); + assert( ssohive.id == son_schedule_id_type(get_son_schedule_id(sidechain_type::hive)) ); // Create FBA counters create([&]( fba_accumulator_object& acc ) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 0825128e..9a8ed58a 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -92,7 +92,10 @@ vector> database::sort_votable_objects< count = std::min(count, refs.size()); std::partial_sort(refs.begin(), refs.begin() + count, refs.end(), [this, sidechain](const son_object& a, const son_object& b)->bool { - FC_ASSERT(sidechain == sidechain_type::bitcoin || sidechain == sidechain_type::hive || sidechain == sidechain_type::ethereum, "Unexpected sidechain type"); + FC_ASSERT(sidechain == sidechain_type::bitcoin || + sidechain == sidechain_type::ethereum || + sidechain == sidechain_type::hive, + "Unexpected sidechain type"); const share_type oa_vote = _vote_tally_buffer[a.get_sidechain_vote_id(sidechain)]; const share_type ob_vote = _vote_tally_buffer[b.get_sidechain_vote_id(sidechain)]; @@ -2044,7 +2047,7 @@ void database::perform_son_tasks() }); } // create BTC asset here because son_account is the issuer of the BTC - if (gpo.parameters.btc_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_TIME) + if (gpo.parameters.btc_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_TIME) { const asset_dynamic_data_object& dyn_asset = create([](asset_dynamic_data_object& a) { @@ -2078,7 +2081,7 @@ void database::perform_son_tasks() }); } // create ETH asset here because son_account is the issuer of the ETH - if (gpo.parameters.eth_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME) + if (gpo.parameters.eth_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME) { const asset_dynamic_data_object& dyn_asset = create([](asset_dynamic_data_object& a) { @@ -2112,7 +2115,7 @@ void database::perform_son_tasks() }); } // create HBD asset here because son_account is the issuer of the HBD - if (gpo.parameters.hbd_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_HIVE_TIME) + if (gpo.parameters.hbd_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_HIVE_TIME) { const asset_dynamic_data_object& dyn_asset = create([](asset_dynamic_data_object& a) { diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index 64557bb6..60b01fae 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -324,7 +324,6 @@ void database::update_son_schedule(const signed_block& next_block) { auto start = fc::time_point::now(); const global_property_object& gpo = get_global_properties(); - const son_schedule_object& sso = get(son_schedule_id_type()); const flat_map schedule_needs_filled = [&gpo]() { flat_map schedule_needs_filled; diff --git a/libraries/chain/include/graphene/chain/sidechain_defs.hpp b/libraries/chain/include/graphene/chain/sidechain_defs.hpp index 5e421a7c..a717f778 100644 --- a/libraries/chain/include/graphene/chain/sidechain_defs.hpp +++ b/libraries/chain/include/graphene/chain/sidechain_defs.hpp @@ -14,7 +14,7 @@ enum class sidechain_type { hive }; -static const std::set active_sidechain_types = {sidechain_type::bitcoin, sidechain_type::hive, sidechain_type::ethereum}; +static const std::set active_sidechain_types = {sidechain_type::bitcoin, sidechain_type::ethereum, sidechain_type::hive}; } } diff --git a/libraries/plugins/peerplays_sidechain/common/utils.cpp b/libraries/plugins/peerplays_sidechain/common/utils.cpp index 580dd831..5bd1dfd7 100644 --- a/libraries/plugins/peerplays_sidechain/common/utils.cpp +++ b/libraries/plugins/peerplays_sidechain/common/utils.cpp @@ -2,7 +2,6 @@ #include #include -//#include #include namespace graphene { namespace peerplays_sidechain { -- 2.45.2 From c9675042357b57a2be0ccb9a97afd41a063f8024 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Mon, 5 Sep 2022 00:59:36 +0200 Subject: [PATCH 59/60] Fix debug build --- libraries/chain/db_witness_schedule.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index 60b01fae..7cb1c89a 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -323,6 +323,9 @@ void database::update_witness_schedule(const signed_block& next_block) void database::update_son_schedule(const signed_block& next_block) { auto start = fc::time_point::now(); +#ifndef NDEBUG + const son_schedule_object& sso = get(son_schedule_id_type()); +#endif const global_property_object& gpo = get_global_properties(); const flat_map schedule_needs_filled = [&gpo]() { -- 2.45.2 From 23a7a8e80ad1c4371bf55fb6ff5ea7391f28ddea Mon Sep 17 00:00:00 2001 From: serkixenos Date: Mon, 5 Sep 2022 02:16:03 +0200 Subject: [PATCH 60/60] Fix startup sequence --- libraries/chain/db_init.cpp | 3 --- libraries/chain/db_maint.cpp | 2 ++ libraries/chain/db_witness_schedule.cpp | 6 +++--- .../peerplays_sidechain/sidechain_net_handler_ethereum.cpp | 1 - 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 67790d04..e9f3b9f5 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -1115,7 +1115,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) _sso.scheduler = son_scheduler(); _sso.scheduler._min_token_count = std::max(int(init_bitcoin_sons.size()) / 2, 1); - //_sso.scheduler.update(init_bitcoin_sons); _sso.last_scheduling_block = 0; @@ -1137,7 +1136,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) _sso.scheduler = son_scheduler(); _sso.scheduler._min_token_count = std::max(int(init_ethereum_sons.size()) / 2, 1); - //_sso.scheduler.update(init_ethereum_sons); _sso.last_scheduling_block = 0; @@ -1159,7 +1157,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) _sso.scheduler = son_scheduler(); _sso.scheduler._min_token_count = std::max(int(init_hive_sons.size()) / 2, 1); - //_sso.scheduler.update(init_hive_sons); _sso.last_scheduling_block = 0; diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 9a8ed58a..7474edac 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -721,7 +721,9 @@ void database::update_active_sons() assert( _son_count_histogram_buffer.size() > 0 ); for( const auto& son_count_histogram_buffer : _son_count_histogram_buffer ){ +#ifndef NDEBUG assert( son_count_histogram_buffer.second.size() > 0 ); +#endif } const flat_map stake_target = [this]{ diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index 7cb1c89a..b4c4bb6a 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -77,9 +77,9 @@ witness_id_type database::get_scheduled_witness( uint32_t slot_num )const unsigned_int database::get_son_schedule_id( sidechain_type type )const { static const map schedule_map = { - { sidechain_type::hive, 0 }, - { sidechain_type::bitcoin, 1 }, - { sidechain_type::ethereum, 2 } + { sidechain_type::bitcoin, 0 }, + { sidechain_type::ethereum, 1 }, + { sidechain_type::hive, 2 } }; return schedule_map.at(type); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 31d1fa8a..066c9dd8 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -450,7 +450,6 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { } void sidechain_net_handler_ethereum::process_sidechain_addresses() { - int temp = 0; } bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_object &swdo) { -- 2.45.2