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