diff --git a/Dockerfile b/Dockerfile index 50c51c3a..3f4c62b5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,15 +11,14 @@ RUN \ apt-utils \ autoconf \ bash \ + bison \ build-essential \ ca-certificates \ - cmake \ dnsutils \ - doxygen \ expect \ + flex \ git \ graphviz \ - libboost-all-dev \ libbz2-dev \ libcurl4-openssl-dev \ libncurses-dev \ @@ -35,7 +34,6 @@ RUN \ ntp \ openssh-server \ pkg-config \ - perl \ python3 \ python3-jinja2 \ sudo \ @@ -53,6 +51,31 @@ RUN echo 'peerplays:peerplays' | chpasswd # SSH EXPOSE 22 +#=============================================================================== +# Boost setup +#=============================================================================== + +WORKDIR /home/peerplays/ + +RUN \ + wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \ + tar -xzvf boost_1_72_0.tar.gz boost_1_72_0 && \ + cd boost_1_72_0/ && \ + ./bootstrap.sh && \ + ./b2 install + +#=============================================================================== +# cmake setup +#=============================================================================== + +WORKDIR /home/peerplays/ + +RUN \ + wget -c 'https://cmake.org/files/v3.23/cmake-3.23.1-linux-x86_64.sh' -O cmake-3.23.1-linux-x86_64.sh && \ + chmod 755 ./cmake-3.23.1-linux-x86_64.sh && \ + ./cmake-3.23.1-linux-x86_64.sh --prefix=/usr/ --skip-license && \ + cmake --version + #=============================================================================== # libzmq setup #=============================================================================== @@ -85,6 +108,37 @@ RUN \ make -j$(nproc) install && \ ldconfig +#=============================================================================== +# Doxygen setup +#=============================================================================== + +WORKDIR /home/peerplays/ + +RUN \ + sudo apt install -y bison flex && \ + wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \ + tar -xvf Release_1_8_17.tar.gz && \ + cd doxygen-Release_1_8_17 && \ + mkdir build && \ + cd build && \ + cmake .. && \ + make -j$(nproc) install && \ + ldconfig + +#=============================================================================== +# Perl setup +#=============================================================================== + +WORKDIR /home/peerplays/ + +RUN \ + wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \ + tar -xvf v5.30.0.tar.gz && \ + cd perl5-5.30.0 && \ + ./Configure -des && \ + make -j$(nproc) install && \ + ldconfig + #=============================================================================== # Peerplays setup #=============================================================================== @@ -106,6 +160,9 @@ ADD . peerplays # Configure Peerplays RUN \ cd peerplays && \ + git submodule update --init --recursive && \ + git symbolic-ref --short HEAD && \ + git log --oneline -n 5 && \ mkdir build && \ cd build && \ cmake -DCMAKE_BUILD_TYPE=Release .. diff --git a/Dockerfile.18.04 b/Dockerfile.18.04 index 49a06fa1..2e153962 100644 --- a/Dockerfile.18.04 +++ b/Dockerfile.18.04 @@ -11,11 +11,12 @@ RUN \ apt-utils \ autoconf \ bash \ + bison \ build-essential \ ca-certificates \ dnsutils \ - doxygen \ expect \ + flex \ git \ graphviz \ libbz2-dev \ @@ -33,7 +34,6 @@ RUN \ ntp \ openssh-server \ pkg-config \ - perl \ python3 \ python3-jinja2 \ sudo \ @@ -58,9 +58,9 @@ EXPOSE 22 WORKDIR /home/peerplays/ RUN \ - wget -c 'https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/boost_1_71_0.tar.bz2' -O boost_1_71_0.tar.bz2 && \ - tar xjf boost_1_71_0.tar.bz2 && \ - cd boost_1_71_0/ && \ + wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz && \ + tar -xzvf boost_1_72_0.tar.gz boost_1_72_0 && \ + cd boost_1_72_0/ && \ ./bootstrap.sh && \ ./b2 install @@ -108,6 +108,37 @@ RUN \ make -j$(nproc) install && \ ldconfig +#=============================================================================== +# Doxygen setup +#=============================================================================== + +WORKDIR /home/peerplays/ + +RUN \ + sudo apt install -y bison flex && \ + wget https://github.com/doxygen/doxygen/archive/refs/tags/Release_1_8_17.tar.gz && \ + tar -xvf Release_1_8_17.tar.gz && \ + cd doxygen-Release_1_8_17 && \ + mkdir build && \ + cd build && \ + cmake .. && \ + make -j$(nproc) install && \ + ldconfig + +#=============================================================================== +# Perl setup +#=============================================================================== + +WORKDIR /home/peerplays/ + +RUN \ + wget https://github.com/Perl/perl5/archive/refs/tags/v5.30.0.tar.gz && \ + tar -xvf v5.30.0.tar.gz && \ + cd perl5-5.30.0 && \ + ./Configure -des && \ + make -j$(nproc) install && \ + ldconfig + #=============================================================================== # Peerplays setup #=============================================================================== @@ -129,6 +160,9 @@ ADD . peerplays # Configure Peerplays RUN \ cd peerplays && \ + git submodule update --init --recursive && \ + git symbolic-ref --short HEAD && \ + git log --oneline -n 5 && \ mkdir build && \ cd build && \ cmake -DCMAKE_BUILD_TYPE=Release .. diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index a385ba47..64fb82c2 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -1912,7 +1912,7 @@ map database_api_impl::get_son_network_status_by_sidechain( if (time_point_sec(sso.last_active_timestamp.at(sidechain) + fc::seconds(gpo.parameters.son_down_time())) > _db.head_block_time()) { status = "OK, irregular SON heartbeat, but not triggering SON down proposal"; } else { - status = "NOT OK, irregular SON heartbeat, triggering SON down proposal]"; + status = "NOT OK, irregular SON heartbeat, triggering SON down proposal"; } } } else { diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index 0bb9b10b..1b61ee79 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -236,7 +236,7 @@ std::set database::get_sons_to_be_deregistered() // 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())) { + if (head_block_time() - stats.last_active_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time())) { need_to_be_deregistered = false; } } @@ -311,7 +311,7 @@ bool database::is_son_dereg_valid( son_id_type son_id ) 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())) + if(head_block_time() - son->statistics(*this).last_active_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time())) { status_son_dereg_valid = false; } diff --git a/libraries/chain/hardfork.d/SIDECHAIN.hf b/libraries/chain/hardfork.d/SIDECHAIN.hf new file mode 100644 index 00000000..3a0a3990 --- /dev/null +++ b/libraries/chain/hardfork.d/SIDECHAIN.hf @@ -0,0 +1,7 @@ +#ifndef HARDFORK_SIDECHAIN_DELETE_TIME +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_SIDECHAIN_DELETE_TIME (fc::time_point_sec::from_iso_string("2022-11-16T02:00:00")) +#else +#define HARDFORK_SIDECHAIN_DELETE_TIME (fc::time_point_sec::from_iso_string("2022-11-16T02:00:00")) +#endif +#endif diff --git a/libraries/chain/sidechain_address_evaluator.cpp b/libraries/chain/sidechain_address_evaluator.cpp index 0efd54cf..3cffc61e 100644 --- a/libraries/chain/sidechain_address_evaluator.cpp +++ b/libraries/chain/sidechain_address_evaluator.cpp @@ -22,12 +22,14 @@ object_id_type add_sidechain_address_evaluator::do_apply(const sidechain_address const auto &sidechain_addresses_idx = db().get_index_type().indices().get(); const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(op.sidechain_address_account, op.sidechain, time_point_sec::maximum())); - if (addr_itr != sidechain_addresses_idx.end()) - { - //db().modify(*addr_itr, [&](sidechain_address_object &sao) { - // sao.expires = db().head_block_time(); - //}); - db().remove(*addr_itr); + if (addr_itr != sidechain_addresses_idx.end()) { + if (db().head_block_time() >= HARDFORK_SIDECHAIN_DELETE_TIME) { + db().remove(*addr_itr); + } else { + db().modify(*addr_itr, [&](sidechain_address_object &sao) { + sao.expires = db().head_block_time(); + }); + } } const auto& new_sidechain_address_object = db().create( [&]( sidechain_address_object& obj ){ @@ -106,11 +108,14 @@ void_result delete_sidechain_address_evaluator::do_apply(const sidechain_address { try { const auto& idx = db().get_index_type().indices().get(); auto sidechain_address = idx.find(op.sidechain_address_id); - if(sidechain_address != idx.end()) { - //db().modify(*sidechain_address, [&](sidechain_address_object &sao) { - // sao.expires = db().head_block_time(); - //}); - db().remove(*sidechain_address); + if (sidechain_address != idx.end()) { + if (db().head_block_time() >= HARDFORK_SIDECHAIN_DELETE_TIME) { + db().remove(*sidechain_address); + } else { + db().modify(*sidechain_address, [&](sidechain_address_object &sao) { + sao.expires = db().head_block_time(); + }); + } } return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index ad42088b..ce1e0083 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -2,7 +2,6 @@ #include #include -#include #include @@ -19,12 +18,16 @@ std::string base_encoder::encode_address(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); + if (value.size() % 32 != 0) { + data += 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 { +const std::string update_owners_encoder::function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string) +std::string update_owners_encoder::encode(const std::vector> &owners_weights, const std::string &object_id) { std::string data = "0x" + function_signature; data += base_encoder::encode_uint256(64); data += base_encoder::encode_uint256((owners_weights.size() * 2 + 3) * 32); @@ -39,7 +42,8 @@ std::string update_owners_encoder::encode(const std::vector &transactions) const { + std::string data = "0x" + function_signature; + data += base_encoder::encode_uint256(32); + data += base_encoder::encode_uint256(transactions.size()); + size_t offset = (transactions.size()) * 32; + for (const auto &transaction : transactions) { + data += base_encoder::encode_uint256(offset); + const auto transaction_data = remove_0x(transaction.data); + offset += 5 * 32 + transaction_data.size() / 2; + if (transaction_data.size() / 2 % 32 != 0) { + offset += 32 - transaction_data.size() / 2 % 32; + } + } + for (const auto &transaction : transactions) { + data += base_encoder::encode_uint256(4 * 32); + data += base_encoder::encode_address(transaction.sign.v); + data += base_encoder::encode_address(transaction.sign.r); + data += base_encoder::encode_address(transaction.sign.s); + const auto transaction_data = remove_0x(transaction.data); + data += base_encoder::encode_uint256(transaction_data.size() / 2); + data += transaction_data; + if (transaction_data.size() % 64 != 0) { + data += std::string((64 - transaction_data.size() % 64), '0'); + } + } + + return data; +} + //! rlp_encoder std::string rlp_encoder::encode(const std::string &s) { return encode_rlp(hex2bytes(s)); diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index a75327c3..9a1383df 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -22,7 +22,43 @@ const secp256k1_context *eth_context() { return ctx; } -//! transaction +bytes keccak_hash(const std::string &data) { + bytes hash; + hash.resize(32); + const auto transaction_string = boost::algorithm::unhex(remove_0x(data)); + keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data()); + + return hash; +} + +signature sign_hash(const bytes &hash, const std::string &chain_id, const std::string &private_key) { + const bytes priv_key = parse_hex(private_key); + + int recid = 0; + secp256k1_ecdsa_recoverable_signature sig; + FC_ASSERT(secp256k1_ecdsa_sign_recoverable(eth_context(), &sig, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), NULL, NULL)); + fc::ecc::compact_signature result; + FC_ASSERT(secp256k1_ecdsa_recoverable_signature_serialize_compact(eth_context(), (unsigned char *)result.begin() + 1, &recid, &sig)); + + unsigned int v = recid + from_hex(chain_id) * 2 + 35; + + 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)); + + signature eth_sig; + eth_sig.v = to_hex(v); + eth_sig.r = fc::to_hex((char *)&r[0], r.size()); + eth_sig.s = fc::to_hex((char *)&s[0], s.size()); + + return eth_sig; +} + +//! base_transaction base_transaction::base_transaction(const std::string &raw_tx) { } @@ -70,12 +106,7 @@ raw_transaction::raw_transaction(const std::string &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; + return keccak_hash(serialize()); } signed_transaction raw_transaction::sign(const std::string &private_key) const { @@ -88,27 +119,10 @@ signed_transaction raw_transaction::sign(const std::string &private_key) const { tr.value = value; tr.data = data; - const bytes priv_key = parse_hex(private_key); - - int recid = 0; - secp256k1_ecdsa_recoverable_signature sig; - FC_ASSERT(secp256k1_ecdsa_sign_recoverable(eth_context(), &sig, (const unsigned char *)hash().data(), (const unsigned char *)priv_key.data(), NULL, NULL)); - fc::ecc::compact_signature result; - FC_ASSERT(secp256k1_ecdsa_recoverable_signature_serialize_compact(eth_context(), (unsigned char *)result.begin() + 1, &recid, &sig)); - - bytes r; - for (int i = 1; i < 33; i++) - r.emplace_back((char)result.at(i)); - - bytes v = bytes{char(recid + from_hex(chain_id) * 2 + 35)}; - - bytes s; - for (int i = 33; i < 65; i++) - s.emplace_back((char)result.at(i)); - - tr.r = fc::to_hex((char *)&r[0], r.size()); - tr.v = fc::to_hex((char *)&v[0], v.size()); - tr.s = fc::to_hex((char *)&s[0], s.size()); + const auto sig = sign_hash(hash(), chain_id, private_key); + tr.v = sig.v; + tr.r = sig.r; + tr.s = sig.s; return tr; } @@ -157,8 +171,8 @@ signed_transaction::signed_transaction(const std::string &raw_tx) : std::string signed_transaction::recover(const std::string &chain_id) const { fc::ecc::compact_signature input64; fc::from_hex(r, (char *)&input64.at(1), 32); - fc::from_hex(v, (char *)&input64.at(0), 1); - int recid = input64.at(0) - from_hex(chain_id) * 2 - 35; + const int recid = from_hex(v) - from_hex(chain_id) * 2 - 35; + fc::from_hex(std::to_string(recid), (char *)&input64.at(0), 1); fc::from_hex(s, (char *)&input64.at(33), 32); secp256k1_ecdsa_recoverable_signature sig; @@ -196,8 +210,8 @@ std::string signed_transaction::serialize() const { 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)); + rlp_encoder::encode(remove_leading_00(remove_0x(r))) + + rlp_encoder::encode(remove_leading_00(remove_0x(s))); return add_0x(bytes2hex(rlp_encoder::encode_length(serialized.size(), 192) + serialized)); } @@ -220,9 +234,9 @@ void signed_transaction::deserialize(const std::string &raw_tx) { boost::algorithm::to_lower(data); v = add_0x(rlp_array.at(6)); boost::algorithm::to_lower(v); - r = add_0x(rlp_array.at(7)); + r = add_0x(add_leading_00(rlp_array.at(7))); boost::algorithm::to_lower(r); - s = add_0x(rlp_array.at(8)); + s = add_0x(add_leading_00(rlp_array.at(8))); boost::algorithm::to_lower(s); } diff --git a/libraries/plugins/peerplays_sidechain/ethereum/types.cpp b/libraries/plugins/peerplays_sidechain/ethereum/types.cpp index f85d0e61..e33e0c4a 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/types.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/types.cpp @@ -1,5 +1,36 @@ #include +#include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { +signature::signature(const std::string &sign) { + deserialize(sign); +} + +std::string signature::serialize() const { + boost::property_tree::ptree pt; + pt.put("v", v); + pt.put("r", r); + pt.put("s", s); + + std::stringstream ss; + boost::property_tree::json_parser::write_json(ss, pt); + return ss.str(); +} + +void signature::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("v")) + v = tx_json.get("v"); + if (tx_json.count("r")) + r = tx_json.get("r"); + if (tx_json.count("s")) + s = tx_json.get("s"); +} + }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp b/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp index ce64e1ae..0f34cd9c 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/utils.cpp @@ -49,4 +49,24 @@ std::string remove_0x(const std::string &s) { return s; } +std::string add_leading_00(const std::string &s) { + std::string result = s; + + while (result.size() < 64) { + result = "00" + result; + } + + return result; +} + +std::string remove_leading_00(const std::string &s) { + std::string result = s; + + while (result.size() > 1 && result.substr(0, 2) == "00") { + result = result.substr(2); + } + + return result; +} + }}} // 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 1ff97978..ce02f7ed 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 @@ -4,8 +4,18 @@ #include #include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { +const std::string update_owners_function_signature = "9d608673"; //! updateOwners((bytes,(uint8,bytes32,bytes32))[]) +const std::string withdrawal_function_signature = "daac6c81"; //! withdraw((bytes,(uint8,bytes32,bytes32))[]) + +struct encoded_sign_transaction { + std::string data; + signature sign; +}; + class base_encoder { public: static std::string encode_uint256(boost::multiprecision::uint256_t value); @@ -15,16 +25,27 @@ public: class update_owners_encoder { public: - const std::string function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string) + static const std::string function_signature; - std::string encode(const std::vector> &owners_weights, const std::string &object_id) const; + static std::string encode(const std::vector> &owners_weights, const std::string &object_id); }; class withdrawal_encoder { public: - const std::string function_signature = "e088747b"; //! withdraw(address,uint256,string) + static const std::string function_signature; - std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) const; + static std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id); +}; + +class signature_encoder { +public: + const std::string function_signature; + + signature_encoder(const std::string &function_hash); + + static std::string get_function_signature_from_transaction(const std::string &transaction); + + std::string encode(const std::vector &transactions) const; }; class rlp_encoder { @@ -39,35 +60,4 @@ private: static void hex2bin(const char *src, char *target); }; -/*class ethereum_function_call_encoder { -public: - enum operation_t { - OPERATION_CALL, - OPERATION_DELEGATE_CALL - }; - - static constexpr const char *const default_prev_addr = "0000000000000000000000000000000000000001"; - - std::string encode_function_signature(const std::string &function_signature); - std::string encode_address(const std::string &addr); - std::string encode_uint256(const std::string &value); - std::string encode_uint8(uint8_t value); - std::string encode_bytes(const std::string &values); -}; - -class safe_transaction_encoder { -public: - static constexpr const char *const default_safe_tx_gas = "0"; - static constexpr const char *const default_data_gas = "0"; - static constexpr const char *const default_gas_price = "0"; - static constexpr const char *const default_gas_token = "0000000000000000000000000000000000000000"; - static constexpr const char *const default_refund_receiver = "0000000000000000000000000000000000000000"; - - std::string create_safe_address(const std::vector &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/transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp index 693c7284..77ef444b 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,6 +8,9 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { +bytes keccak_hash(const std::string &data); +signature sign_hash(const bytes &hash, const std::string &chain_id, const std::string &private_key); + class base_transaction { public: base_transaction() = default; @@ -75,89 +78,3 @@ public: }; }}} // namespace graphene::peerplays_sidechain::ethereum - -// Example 1 -//{ -// "blockHash": "0x64a6706ecaf5a97b7f3e047abb20ff223ce82c6994d80e68fdb1fdfb38d0209c", -// "blockNumber": "0xe5827c", -// "from": "0x8614c67e085f2334010f2a28e806c6f1cc176d12", -// "gas": "0x38822", -// "gasPrice": "0xce42cba69", -// "maxFeePerGas": "0xddb4d8d16", -// "maxPriorityFeePerGas": "0x3b9aca00", -// "hash": "0xeac92ea09fa8eb3ca2fb0d156cceb38ae69d4345869d41e8e49d5ecbcbb622dc", -// "input": "0x5ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde03121500000000000000000000000000000000000000000000000000000000", -// "nonce": "0x32", -// "to": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45", -// "transactionIndex": "0xb6", -// "value": "0x2514d9d7d7d8000", -// "type": "0x2", -// "accessList": [], -// "chainId": "0x1", -// "v": "0x1", -// "r": "0x2f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28c", -// "s": "0x782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14" -//} -// -//"0xf9021332850ce42cba69830388229468b3465833fb72a70ecdf485e0e4c7bd8665fc458802514d9d7d7d8000b901a45ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde0312150000000000000000000000000000000000000000000000000000000001a02f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28ca0782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14" -// -//{ -// "nonce": 50, -// "gasPrice": { -// "_hex": "0x0ce42cba69" -// }, -// "gasLimit": { -// "_hex": "0x038822" -// }, -// "to": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45", -// "value": { -// "_hex": "0x02514d9d7d7d8000" -// }, -// "data": "0x5ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde03121500000000000000000000000000000000000000000000000000000000", -// "v": 1, -// "r": "0x2f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28c", -// "s": "0x782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14" -//} - -// Example 2 -//{ -// "blockHash": "0xe2ae3afd86dc7343c7fb753441447a0a51bb19499325ad6e278256f0cd1b5894", -// "blockNumber": "0xe58271", -// "from": "0xb895ade6d337fbb8cb97f2ea7da43106c7f5cc26", -// "gas": "0x5208", -// "gasPrice": "0xe6f3b322e", -// "maxFeePerGas": "0x1322455fd3", -// "maxPriorityFeePerGas": "0x53724e00", -// "hash": "0xed29b56e52ad2d452e25b8ec70c37f59d935cd6d0f8fe8e83b256f3ffdfd3fce", -// "input": "0x", -// "nonce": "0x37", -// "to": "0x176386b6ffc469ac049f9ec1f6cc0efd1d09b373", -// "transactionIndex": "0x8a", -// "value": "0x4563918244f40000", -// "type": "0x2", -// "accessList": [], -// "chainId": "0x1", -// "v": "0x0", -// "r": "0xdcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4c", -// "s": "0x28c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a" -//} -// -//"0xf86c37850e6f3b322e82520894176386b6ffc469ac049f9ec1f6cc0efd1d09b373884563918244f400008000a0dcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4ca028c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a" -// -//{ -// "nonce": 55, -// "gasPrice": { -// "_hex": "0x0e6f3b322e" -// }, -// "gasLimit": { -// "_hex": "0x5208" -// }, -// "to": "0x176386b6ffc469ac049f9ec1f6cc0efd1d09b373", -// "value": { -// "_hex": "0x4563918244f40000" -// }, -// "data": "0x", -// "v": 0, -// "r": "0xdcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4c", -// "s": "0x28c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a" -//} 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 963244fa..3acc8b8f 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 @@ -9,4 +9,17 @@ typedef uint64_t network_id_type; using bytes = std::vector; +class signature { +public: + std::string v; + std::string r; + std::string s; + + signature() = default; + signature(const std::string &sign); + + std::string serialize() const; + void deserialize(const std::string &sign); +}; + }}} // 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 b4461713..4ac70094 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 @@ -14,13 +14,19 @@ std::string add_0x(const std::string &s); std::string remove_0x(const std::string &s); +std::string add_leading_00(const std::string &s); + +std::string remove_leading_00(const std::string &s); + template -std::string to_hex(const T &val) { +std::string to_hex(const T &val, bool add_front_zero = true) { std::stringstream stream; stream << std::hex << val; std::string result(stream.str()); - if (result.size() % 2) - result = "0" + result; + if (add_front_zero) { + if (result.size() % 2) + result = "0" + result; + } return result; } 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 114f9bc7..d890ae68 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 @@ -54,6 +54,7 @@ public: 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(); + optional estimate_withdrawal_transaction_fee(sidechain_type sidechain); }; }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_api.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_api.hpp index b4636537..5d6df6af 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_api.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_api.hpp @@ -26,9 +26,10 @@ public: std::shared_ptr my; std::map> get_son_listener_log(); + optional estimate_withdrawal_transaction_fee(sidechain_type sidechain); }; }} // namespace graphene::peerplays_sidechain FC_API(graphene::peerplays_sidechain::sidechain_api, - (get_son_listener_log)) + (get_son_listener_log)(estimate_withdrawal_transaction_fee)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp index edff1b45..836a1f05 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp @@ -20,10 +20,11 @@ public: sidechain_net_handler(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options); virtual ~sidechain_net_handler(); - sidechain_type get_sidechain(); - std::vector get_sidechain_deposit_addresses(); - std::vector get_sidechain_withdraw_addresses(); - std::string get_private_key(std::string public_key); + sidechain_type get_sidechain() const; + std::vector get_sidechain_deposit_addresses() const; + std::vector get_sidechain_withdraw_addresses() const; + std::vector get_sidechain_transaction_objects(sidechain_transaction_status status) const; + std::string get_private_key(std::string public_key) const; bool proposal_exists(int32_t operation_tag, const object_id_type &object_id, boost::optional proposal_op = boost::none); bool signer_expected(const sidechain_transaction_object &sto, son_id_type signer); @@ -50,6 +51,7 @@ public: void add_to_son_listener_log(std::string trx_id); std::vector get_son_listener_log(); + virtual optional estimate_withdrawal_transaction_fee() const = 0; protected: peerplays_sidechain_plugin &plugin; 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 b5accca2..e2e1446d 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 @@ -188,6 +188,7 @@ public: 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); + virtual optional estimate_withdrawal_transaction_fee() const override; private: std::string bitcoin_node_ip; 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 3944d0a2..e6e8f298 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 @@ -15,18 +15,21 @@ class ethereum_rpc_client : public rpc_client { public: ethereum_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); - std::string admin_node_info(); + std::string eth_blockNumber(); 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 eth_chainId(); std::string net_version(); std::string eth_get_transaction_count(const std::string ¶ms); std::string eth_gas_price(); + std::string eth_estimateGas(const std::string ¶ms); 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 get_estimate_gas(const std::string ¶ms); std::string eth_send_transaction(const std::string ¶ms); std::string eth_send_raw_transaction(const std::string ¶ms); @@ -46,6 +49,7 @@ public: 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); + virtual optional estimate_withdrawal_transaction_fee() const override; private: std::string rpc_url; @@ -69,7 +73,7 @@ private: boost::signals2::signal event_received; void schedule_ethereum_listener(); void ethereum_listener_loop(); - void handle_event(const std::string &event_data); + void handle_event(const std::string &block_number); }; }} // namespace graphene::peerplays_sidechain 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 72539db2..440a2520 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 @@ -45,6 +45,7 @@ public: 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); + virtual optional estimate_withdrawal_transaction_fee() const override; private: std::string rpc_url; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp index 69eea1a9..139db7bf 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp @@ -19,6 +19,7 @@ public: 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); + virtual optional estimate_withdrawal_transaction_fee() const override; private: }; diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 2798a5ef..d6e179bc 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -48,6 +48,7 @@ public: 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(); + optional estimate_withdrawal_transaction_fee(sidechain_type sidechain); void schedule_heartbeat_loop(); void heartbeat_loop(); @@ -631,6 +632,15 @@ std::map> peerplays_sidechain_plugin_im return result; } +optional peerplays_sidechain_plugin_impl::estimate_withdrawal_transaction_fee(sidechain_type sidechain) { + if (!net_handlers.at(sidechain)) { + wlog("Net handler is null for sidechain: ${sidechain}", ("sidechain", sidechain)); + return optional(); + } + + return net_handlers.at(sidechain)->estimate_withdrawal_transaction_fee(); +} + 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 @@ -927,4 +937,8 @@ std::map> peerplays_sidechain_plugin::g return my->get_son_listener_log(); } +optional peerplays_sidechain_plugin::estimate_withdrawal_transaction_fee(sidechain_type sidechain) { + return my->estimate_withdrawal_transaction_fee(sidechain); +} + }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_api.cpp b/libraries/plugins/peerplays_sidechain/sidechain_api.cpp index 2a85d034..833d91ff 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_api.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_api.cpp @@ -12,6 +12,7 @@ public: std::shared_ptr get_plugin(); std::map> get_son_listener_log(); + optional estimate_withdrawal_transaction_fee(sidechain_type sidechain); private: app::application &app; @@ -32,6 +33,10 @@ std::map> sidechain_api_impl::get_son_l return get_plugin()->get_son_listener_log(); } +optional sidechain_api_impl::estimate_withdrawal_transaction_fee(sidechain_type sidechain) { + return get_plugin()->estimate_withdrawal_transaction_fee(sidechain); +} + } // namespace detail sidechain_api::sidechain_api(graphene::app::application &_app) : @@ -45,4 +50,8 @@ std::map> sidechain_api::get_son_listen return my->get_son_listener_log(); } +optional sidechain_api::estimate_withdrawal_transaction_fee(sidechain_type sidechain) { + return my->estimate_withdrawal_transaction_fee(sidechain); +} + }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp index 971df7c7..38345935 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp @@ -21,11 +21,11 @@ sidechain_net_handler::sidechain_net_handler(peerplays_sidechain_plugin &_plugin sidechain_net_handler::~sidechain_net_handler() { } -sidechain_type sidechain_net_handler::get_sidechain() { +sidechain_type sidechain_net_handler::get_sidechain() const { return sidechain; } -std::vector sidechain_net_handler::get_sidechain_deposit_addresses() { +std::vector sidechain_net_handler::get_sidechain_deposit_addresses() const { std::vector result; const auto &sidechain_addresses_idx = database.get_index_type(); @@ -38,7 +38,7 @@ std::vector sidechain_net_handler::get_sidechain_deposit_addresses( return result; } -std::vector sidechain_net_handler::get_sidechain_withdraw_addresses() { +std::vector sidechain_net_handler::get_sidechain_withdraw_addresses() const { std::vector result; const auto &sidechain_addresses_idx = database.get_index_type(); @@ -51,7 +51,20 @@ std::vector sidechain_net_handler::get_sidechain_withdraw_addresses return result; } -std::string sidechain_net_handler::get_private_key(std::string public_key) { +std::vector sidechain_net_handler::get_sidechain_transaction_objects(sidechain_transaction_status status) const { + std::vector result; + + const auto &idx = database.get_index_type().indices().get(); + const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, status)); + std::for_each(idx_range.first, idx_range.second, + [&result](const sidechain_transaction_object &sto) { + result.push_back(sto); + }); + + return result; +} + +std::string sidechain_net_handler::get_private_key(std::string public_key) const { auto private_key_itr = private_keys.find(public_key); if (private_key_itr != private_keys.end()) { return private_key_itr->second; @@ -473,10 +486,9 @@ void sidechain_net_handler::process_withdrawals() { } void sidechain_net_handler::process_sidechain_transactions() { - const auto &idx = database.get_index_type().indices().get(); - const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, sidechain_transaction_status::valid)); + const auto stos = get_sidechain_transaction_objects(sidechain_transaction_status::valid); - std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) { + std::for_each(stos.cbegin(), stos.cend(), [&](const sidechain_transaction_object &sto) { if ((sto.id == object_id_type(0, 0, 0)) || !signer_expected(sto, plugin.get_current_son_id(sidechain))) { return; } @@ -520,10 +532,9 @@ void sidechain_net_handler::process_sidechain_transactions() { } void sidechain_net_handler::send_sidechain_transactions() { - const auto &idx = database.get_index_type().indices().get(); - const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, sidechain_transaction_status::complete)); + const auto stos = get_sidechain_transaction_objects(sidechain_transaction_status::complete); - std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) { + std::for_each(stos.cbegin(), stos.cend(), [&](const sidechain_transaction_object &sto) { if (sto.id == object_id_type(0, 0, 0)) { return; } @@ -555,10 +566,9 @@ void sidechain_net_handler::send_sidechain_transactions() { } void sidechain_net_handler::settle_sidechain_transactions() { - const auto &idx = database.get_index_type().indices().get(); - const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, sidechain_transaction_status::sent)); + const auto stos = get_sidechain_transaction_objects(sidechain_transaction_status::sent); - std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) { + std::for_each(stos.cbegin(), stos.cend(), [&](const sidechain_transaction_object &sto) { if (sto.id == object_id_type(0, 0, 0)) { return; } diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 470aadd6..5045fda2 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -1253,6 +1253,11 @@ bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain return false; } +optional sidechain_net_handler_bitcoin::estimate_withdrawal_transaction_fee() const { + wlog("estimate_withdrawal_transaction_fee not implemented for sidechain: ${sidechain}", ("sidechain", sidechain)); + return optional{}; +} + std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const std::vector &son_pubkeys) { using namespace bitcoin; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 02ec5bce..a237c4f4 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -28,8 +28,9 @@ ethereum_rpc_client::ethereum_rpc_client(const std::string &url, const std::stri rpc_client(url, user_name, password, debug_rpc_calls) { } -std::string ethereum_rpc_client::admin_node_info() { - return send_post_request("admin_nodeInfo", "", debug_rpc_calls); +std::string ethereum_rpc_client::eth_blockNumber() { + const std::string reply_str = send_post_request("eth_blockNumber", "", debug_rpc_calls); + return retrieve_value_from_reply(reply_str, ""); } std::string ethereum_rpc_client::eth_get_block_by_number(std::string block_number, bool full_block) { @@ -43,6 +44,10 @@ std::string ethereum_rpc_client::eth_get_logs(std::string wallet_contract_addres return retrieve_value_from_reply(reply_str, ""); } +std::string ethereum_rpc_client::eth_chainId() { + return send_post_request("eth_chainId", "", debug_rpc_calls); +} + std::string ethereum_rpc_client::net_version() { return send_post_request("net_version", "", debug_rpc_calls); } @@ -55,18 +60,23 @@ std::string ethereum_rpc_client::eth_gas_price() { return send_post_request("eth_gasPrice", "", debug_rpc_calls); } +std::string ethereum_rpc_client::eth_estimateGas(const std::string ¶ms) { + return send_post_request("eth_estimateGas", params, debug_rpc_calls); +} + std::string ethereum_rpc_client::get_chain_id() { + const std::string reply_str = eth_chainId(); + const auto chain_id_string = retrieve_value_from_reply(reply_str, ""); + return chain_id_string.empty() ? "" : std::to_string(ethereum::from_hex(chain_id_string)); +} + +std::string ethereum_rpc_client::get_network_id() { const std::string reply_str = net_version(); return retrieve_value_from_reply(reply_str, ""); } -std::string ethereum_rpc_client::get_network_id() { - const std::string reply_str = admin_node_info(); - return retrieve_value_from_reply(reply_str, "protocols.eth.network"); -} - std::string ethereum_rpc_client::get_nonce(const std::string &address) { - const std::string reply_str = eth_get_transaction_count("[\"" + address + "\", \"latest\"]"); + const std::string reply_str = eth_get_transaction_count("[\"" + address + "\", \"pending\"]"); const auto nonce_string = retrieve_value_from_reply(reply_str, ""); if (!nonce_string.empty()) { const auto nonce_val = ethereum::from_hex(nonce_string); @@ -94,6 +104,11 @@ std::string ethereum_rpc_client::get_gas_limit() { return std::string{}; } +std::string ethereum_rpc_client::get_estimate_gas(const std::string ¶ms) { + const std::string reply_str = eth_estimateGas(params); + return retrieve_value_from_reply(reply_str, ""); +} + std::string ethereum_rpc_client::eth_send_transaction(const std::string ¶ms) { return send_post_request("eth_sendTransaction", "[" + params + "]", debug_rpc_calls); } @@ -158,7 +173,8 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha 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; + const auto block_number = rpc_client->eth_blockNumber(); + last_block_received = !block_number.empty() ? ethereum::from_hex(block_number) : 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(); @@ -569,33 +585,65 @@ 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; + + std::vector transactions; 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()) + if (signature.second.empty()) continue; + ethereum::encoded_sign_transaction transaction{sto.transaction, ethereum::signature{signature.second}}; + transactions.emplace_back(transaction); + } + + 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); + + const auto function_signature = ethereum::signature_encoder::get_function_signature_from_transaction(sto.transaction); + if (function_signature.empty()) { + elog("Function signature is empty for transaction id ${id}, transaction ${transaction}", ("id", sto.id)("transaction", sto.transaction)); + return std::string{}; //! Return empty string, as we have error in sending + } + + const ethereum::signature_encoder encoder{function_signature}; #ifdef SEND_RAW_TRANSACTION - const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(transaction); + ethereum::raw_transaction raw_tr; + raw_tr.nonce = rpc_client->get_nonce(ethereum::add_0x(public_key)); + raw_tr.gas_price = rpc_client->get_gas_price(); + raw_tr.gas_limit = rpc_client->get_gas_limit(); + raw_tr.to = wallet_contract_address; + raw_tr.value = ""; + raw_tr.data = encoder.encode(transactions); + raw_tr.chain_id = ethereum::add_0x(ethereum::to_hex(chain_id)); + + const auto sign_tr = raw_tr.sign(get_private_key(public_key)); + const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(sign_tr.serialize()); #else - const std::string sidechain_transaction = rpc_client->eth_send_transaction(transaction); + ethereum::transaction raw_tr; + raw_tr.data = encoder.encode(transactions); + raw_tr.to = wallet_contract_address; + raw_tr.from = ethereum::add_0x(public_key); + + const auto sign_tr = raw_tr.sign(get_private_key(public_key)); + const std::string sidechain_transaction = rpc_client->eth_send_transaction(sign_tr.serialize()); #endif - std::stringstream ss_tx(sidechain_transaction); - boost::property_tree::ptree tx_json; - boost::property_tree::read_json(ss_tx, tx_json); - if (tx_json.count("result") && !tx_json.count("error")) { - boost::property_tree::ptree node; - node.put("transaction", transaction); - node.put("transaction_receipt", tx_json.get("result")); - pt_array.push_back(std::make_pair("", node)); - } else { - //! Fixme - //! How should we proceed with error in eth_send_transaction - elog("Error in eth_send_transaction for transaction ${id}, transaction ${transaction}", ("id", sto.id)("transaction", transaction)); - return std::string{}; //! Return empty string, as we have error in sending - } + std::stringstream ss_tx(sidechain_transaction); + boost::property_tree::ptree tx_json; + boost::property_tree::read_json(ss_tx, tx_json); + if (tx_json.count("result") && !tx_json.count("error")) { + boost::property_tree::ptree node; + node.put("transaction", sto.transaction); + node.put("sidechain_transaction", sidechain_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 eth_send_transaction + elog("Error in eth send transaction for transaction id ${id}, transaction ${transaction}, sidechain_transaction ${sidechain_transaction}", ("id", sto.id)("transaction", sto.transaction)("sidechain_transaction", sidechain_transaction)); + return std::string{}; //! Return empty string, as we have error in sending } pt.add_child("result_array", pt_array); @@ -638,12 +686,59 @@ bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechai if (count != json.get_child("result_array").size()) { wlog("Not all receipts received for transaction ${id}", ("id", sto.id)); return false; - } else + } else { + if (sto.object_id.is()) { + settle_amount = asset(0, database.get_global_properties().parameters.eth_asset()); + } + + if (sto.object_id.is()) { + auto swwo = database.get(sto.object_id); + settle_amount = asset(swwo.withdraw_amount, database.get_global_properties().parameters.eth_asset()); + } + return true; + } return false; } +optional sidechain_net_handler_ethereum::estimate_withdrawal_transaction_fee() const { + const auto &gpo = database.get_global_properties(); + if (gpo.active_sons.at(sidechain).empty()) { + wlog("No active sons for sidechain: ${sidechain}", ("sidechain", sidechain)); + return optional{}; + } + + const auto &active_son = gpo.active_sons.at(sidechain).at(0); + const auto &s_idx = database.get_index_type().indices().get(); + const auto son = s_idx.find(active_son.son_id); + if (son == s_idx.end()) { + wlog("Can't find son for id: ${son_id}", ("son_id", active_son.son_id)); + return optional{}; + } + + if (!son->sidechain_public_keys.contains(sidechain)) { + wlog("No public keys for current son: ${account_id}", ("account_id", son->son_account)); + return optional{}; + } + + const auto &assets_by_symbol = database.get_index_type().indices().get(); + auto asset_itr = assets_by_symbol.find("ETH"); + if (asset_itr == assets_by_symbol.end()) { + wlog("Could not find asset matching ETH"); + return optional{}; + } + + const auto &public_key = son->sidechain_public_keys.at(sidechain); + const auto data = ethereum::withdrawal_encoder::encode(public_key, 1 * 10000000000, son_wallet_withdraw_id_type{0}.operator object_id_type().operator std::string()); + const std::string params = "[{\"from\":\"" + ethereum::add_0x(public_key) + "\", \"to\":\"" + wallet_contract_address + "\", \"data\":\"" + data + "\"}]"; + + const auto estimate_gas = ethereum::from_hex(rpc_client->get_estimate_gas(params)); + const auto gas_price = ethereum::from_hex(rpc_client->get_gas_price()); + const auto eth_gas_fee = double(estimate_gas * gas_price) / double{1000000000000000000}; + return asset_itr->amount_from_string(std::to_string(eth_gas_fee)); +} + 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) { @@ -651,8 +746,7 @@ std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(co owners_weights.emplace_back(std::make_pair(pub_key_str, son.weight)); } - const ethereum::update_owners_encoder encoder; - return encoder.encode(owners_weights, object_id); + return ethereum::update_owners_encoder::encode(owners_weights, object_id); } std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) { @@ -660,8 +754,7 @@ 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) { - const ethereum::withdrawal_encoder encoder; - return encoder.encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string()); + return ethereum::withdrawal_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) { @@ -670,25 +763,11 @@ std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_tra const auto &public_key = current_son.sidechain_public_keys.at(sidechain); -#ifdef SEND_RAW_TRANSACTION - ethereum::raw_transaction raw_tr; - raw_tr.nonce = rpc_client->get_nonce(ethereum::add_0x(public_key)); - raw_tr.gas_price = rpc_client->get_gas_price(); - raw_tr.gas_limit = rpc_client->get_gas_limit(); - raw_tr.to = wallet_contract_address; - raw_tr.value = ""; - raw_tr.data = sto.transaction; - raw_tr.chain_id = ethereum::add_0x(ethereum::to_hex(chain_id)); + //! We need to change v value according to chain_id + auto signature = ethereum::sign_hash(ethereum::keccak_hash(sto.transaction), ethereum::add_0x(ethereum::to_hex(chain_id)), get_private_key(public_key)); + signature.v = ethereum::to_hex(ethereum::from_hex(signature.v) - 2 * chain_id - 35 + 27); - 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 + return signature.serialize(); } void sidechain_net_handler_ethereum::schedule_ethereum_listener() { @@ -706,32 +785,43 @@ void sidechain_net_handler_ethereum::schedule_ethereum_listener() { void sidechain_net_handler_ethereum::ethereum_listener_loop() { schedule_ethereum_listener(); - const std::string reply = rpc_client->eth_get_block_by_number("latest", false); + const auto reply = rpc_client->eth_blockNumber(); //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; + uint64_t head_block_number = ethereum::from_hex(reply); + + if (head_block_number != last_block_received) { + //! Check that current block number is greater than last one + if (head_block_number < last_block_received) { + wlog("Head block ${head_block_number} is greater than last received block ${last_block_received}", ("head_block_number", head_block_number)("last_block_received", last_block_received)); + return; } + + //! Send event data for all blocks that passed + for (uint64_t i = last_block_received + 1; i <= head_block_number; ++i) { + const std::string block_number = ethereum::add_0x(ethereum::to_hex(i, false)); + handle_event(block_number); + } + + last_block_received = head_block_number; } } } -void sidechain_net_handler_ethereum::handle_event(const std::string &event_data) { - const std::string block = rpc_client->eth_get_block_by_number("latest", true); +void sidechain_net_handler_ethereum::handle_event(const std::string &block_number) { + const std::string block = rpc_client->eth_get_block_by_number(block_number, true); if (block != "") { - add_to_son_listener_log("BLOCK : " + event_data); + add_to_son_listener_log("BLOCK : " + block_number); std::stringstream ss(block); boost::property_tree::ptree block_json; boost::property_tree::read_json(ss, block_json); + if (block_json.get("result") == "null") { + wlog("No data for block ${block_number}", ("block_number", block_number)); + return; + } + size_t tx_idx = -1; for (const auto &tx_child : block_json.get_child("result.transactions")) { boost::property_tree::ptree tx = tx_child.second; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp index a4c06175..873fa08e 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp @@ -256,13 +256,14 @@ bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { const 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::authority a; + a.weight_threshold = total_weight * 2 / 3 + 1; + a.account_auths = account_auths; hive::account_update_operation auo; auo.account = wallet_account_name; - auo.active = active; + auo.owner = a; + auo.active = a; auo.memo_key = op_trx.operations[0].get().memo_key; hive::signed_transaction htrx; @@ -505,13 +506,14 @@ void sidechain_net_handler_hive::process_primary_wallet() { return; } - hive::authority active; - active.weight_threshold = total_weight * 2 / 3 + 1; - active.account_auths = account_auths; + hive::authority a; + a.weight_threshold = total_weight * 2 / 3 + 1; + a.account_auths = account_auths; hive::account_update_operation auo; auo.account = wallet_account_name; - auo.active = active; + auo.owner = a; + auo.active = a; auo.memo_key = hive::public_key_type(memo_key); const std::string block_id_str = rpc_client->get_head_block_id(); @@ -546,12 +548,27 @@ void sidechain_net_handler_hive::process_primary_wallet() { proposal_op.proposed_ops.emplace_back(swu_op); + const auto signers = [this, &prev_sw, &active_sw, &swi] { + std::vector signers; + //! Check if we don't have any previous set of active SONs use the current one + if (prev_sw != swi.rend()) { + if (!prev_sw->sons.at(sidechain).empty()) + signers = prev_sw->sons.at(sidechain); + else + signers = active_sw->sons.at(sidechain); + } else { + signers = active_sw->sons.at(sidechain); + } + + return signers; + }(); + sidechain_transaction_create_operation stc_op; stc_op.payer = gpo.parameters.son_account(); stc_op.object_id = active_sw->id; stc_op.sidechain = sidechain; stc_op.transaction = tx_str; - stc_op.signers = gpo.active_sons.at(sidechain); + stc_op.signers = signers; proposal_op.proposed_ops.emplace_back(stc_op); @@ -806,6 +823,11 @@ bool sidechain_net_handler_hive::settle_sidechain_transaction(const sidechain_tr return false; } +optional sidechain_net_handler_hive::estimate_withdrawal_transaction_fee() const { + wlog("estimate_withdrawal_transaction_fee not implemented for sidechain: ${sidechain}", ("sidechain", sidechain)); + return optional{}; +} + void sidechain_net_handler_hive::schedule_hive_listener() { fc::time_point now = fc::time_point::now(); int64_t time_to_next = 1000; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp index b2945251..76fbbb3e 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp @@ -290,4 +290,9 @@ bool sidechain_net_handler_peerplays::settle_sidechain_transaction(const sidecha return true; } +optional sidechain_net_handler_peerplays::estimate_withdrawal_transaction_fee() const { + wlog("estimate_withdrawal_transaction_fee not implemented for sidechain: ${sidechain}", ("sidechain", sidechain)); + return optional{}; +} + }} // namespace graphene::peerplays_sidechain diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index aac79252..a7807596 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -980,13 +980,13 @@ class wallet_api * * @return true if the label was set, otherwise false */ - bool set_key_label( public_key_type, string label ); + bool set_key_label( public_key_type key, string label ); /** Get label of a public key. * @param key a public key * @return the label if already set by \c set_key_label(), or an empty string if not set */ - string get_key_label( public_key_type )const; + string get_key_label( public_key_type key )const; /* Get the public key associated with a given label. * @param label a label @@ -2676,6 +2676,19 @@ class wallet_api */ std::map> get_son_listener_log() const; + /** + * @brief Estimate transaction fee for withdrawal + * @param sidechain Sidechain type (bitcoin, HIVE, etc) + * @return Transaction fee + */ + optional estimate_withdrawal_transaction_fee(sidechain_type sidechain) const; + + /** + * @brief Estimate gas fee for withdrawal transaction for ETH + * @return Gas fee in ETH + */ + std::string eth_estimate_withdrawal_transaction_fee() const; + fc::signal lock_changed; std::shared_ptr my; void encrypt_keys(); @@ -2976,4 +2989,6 @@ FC_API( graphene::wallet::wallet_api, (get_voters_by_id) (get_voters) (get_son_listener_log) + (estimate_withdrawal_transaction_fee) + (eth_estimate_withdrawal_transaction_fee) ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index d8d79c4b..7eefae27 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -3291,6 +3291,25 @@ public: return sign_transaction(trx, broadcast); } FC_CAPTURE_AND_RETHROW((order_id)) } + sidechain_type get_sidechain_type_from_asset(asset_id_type asset_id) const + { + const auto& gpo = _remote_db->get_global_properties(); + + if(asset_id == gpo.parameters.btc_asset()) + return sidechain_type::bitcoin; + + if(asset_id == gpo.parameters.eth_asset()) + return sidechain_type::ethereum; + + if(asset_id == gpo.parameters.hbd_asset()) + return sidechain_type::hive; + + if(asset_id == gpo.parameters.hive_asset()) + return sidechain_type::hive; + + return sidechain_type::unknown; + } + signed_transaction transfer(string from, string to, string amount, string asset_symbol, string memo, bool broadcast = false) { try { @@ -3323,6 +3342,19 @@ public: set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees); tx.validate(); + //! For sidechain withdrawal check if amount is greater than fee + if(to_id == _remote_db->get_global_properties().parameters.son_account()) { + const auto sidechain = get_sidechain_type_from_asset(asset_obj->id); + const auto transaction_fee = estimate_withdrawal_transaction_fee(sidechain); + + if(transaction_fee) { + if (*transaction_fee >= xfer_op.amount) { + FC_THROW("Transaction fee: ${sidechain_fee}, is greater than transferred amount ${amount}", + ("sidechain_fee", get_asset(transaction_fee->asset_id).amount_to_pretty_string(transaction_fee->amount))("amount", get_asset(xfer_op.amount.asset_id).amount_to_pretty_string(xfer_op.amount.amount))); + } + } + } + return sign_transaction(tx, broadcast); } FC_CAPTURE_AND_RETHROW( (from)(to)(amount)(asset_symbol)(memo)(broadcast) ) } @@ -4222,6 +4254,31 @@ public: FC_CAPTURE_AND_RETHROW() } + optional estimate_withdrawal_transaction_fee(sidechain_type sidechain) + { + use_sidechain_api(); + try + { + return (*_remote_sidechain)->estimate_withdrawal_transaction_fee(sidechain); + } + FC_CAPTURE_AND_RETHROW() + } + + std::string eth_estimate_withdrawal_transaction_fee() + { + try + { + const auto transaction_fee = estimate_withdrawal_transaction_fee(sidechain_type::ethereum); + if(transaction_fee) + { + return get_asset(transaction_fee->asset_id).amount_to_pretty_string(transaction_fee->amount); + } + + return "Can't get fee value"; + } + FC_CAPTURE_AND_RETHROW() + } + string _wallet_filename; wallet_data _wallet; @@ -7273,6 +7330,16 @@ std::map> wallet_api::get_son_listener_ return my->get_son_listener_log(); } +optional wallet_api::estimate_withdrawal_transaction_fee(sidechain_type sidechain) const +{ + return my->estimate_withdrawal_transaction_fee(sidechain); +} + +std::string wallet_api::eth_estimate_withdrawal_transaction_fee() const +{ + return my->eth_estimate_withdrawal_transaction_fee(); +} + // default ctor necessary for FC_REFLECT signed_block_with_info::signed_block_with_info( const signed_block& block ) : signed_block( block ) diff --git a/tests/cli/son.cpp b/tests/cli/son.cpp index 7858664c..83db8d48 100644 --- a/tests/cli/son.cpp +++ b/tests/cli/son.cpp @@ -1313,7 +1313,7 @@ BOOST_FIXTURE_TEST_CASE( get_son_network_status, cli_fixture ) (inner_iter->first == gpo.active_sons.at(sidechain_type::ethereum).at(0).son_id)) { BOOST_TEST_MESSAGE("status: "<< inner_iter->second); - BOOST_CHECK(inner_iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal]"); + BOOST_CHECK(inner_iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal"); } else if((inner_iter->first == gpo.active_sons.at(sidechain_type::bitcoin).at(1).son_id) && (inner_iter->first == gpo.active_sons.at(sidechain_type::hive).at(1).son_id) && @@ -1342,14 +1342,14 @@ BOOST_FIXTURE_TEST_CASE( get_son_network_status, cli_fixture ) (inner_iter->first == gpo.active_sons.at(sidechain_type::ethereum).at(0).son_id)) { BOOST_TEST_MESSAGE("status: "<< inner_iter->second); - BOOST_CHECK(inner_iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal]"); + BOOST_CHECK(inner_iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal"); } else if((inner_iter->first == gpo.active_sons.at(sidechain_type::bitcoin).at(1).son_id) && (inner_iter->first == gpo.active_sons.at(sidechain_type::hive).at(1).son_id) && (inner_iter->first == gpo.active_sons.at(sidechain_type::ethereum).at(1).son_id)) { BOOST_TEST_MESSAGE("status: "<< inner_iter->second); - BOOST_CHECK(inner_iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal]"); + BOOST_CHECK(inner_iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal"); } else{ BOOST_TEST_MESSAGE("status: "<< inner_iter->second); @@ -1517,7 +1517,7 @@ BOOST_FIXTURE_TEST_CASE( get_son_network_status_by_sidechain, cli_fixture ) (iter->first == gpo.active_sons.at(sidechain_type::ethereum).at(0).son_id)) { BOOST_TEST_MESSAGE("status: "<< iter->second); - BOOST_CHECK(iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal]"); + BOOST_CHECK(iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal"); } else if((iter->first == gpo.active_sons.at(sidechain_type::bitcoin).at(1).son_id) && (iter->first == gpo.active_sons.at(sidechain_type::hive).at(1).son_id) && @@ -1545,14 +1545,14 @@ BOOST_FIXTURE_TEST_CASE( get_son_network_status_by_sidechain, cli_fixture ) (iter->first == gpo.active_sons.at(sidechain_type::ethereum).at(0).son_id)) { BOOST_TEST_MESSAGE("status: "<< iter->second); - BOOST_CHECK(iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal]"); + BOOST_CHECK(iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal"); } else if((iter->first == gpo.active_sons.at(sidechain_type::bitcoin).at(1).son_id) && (iter->first == gpo.active_sons.at(sidechain_type::hive).at(1).son_id) && (iter->first == gpo.active_sons.at(sidechain_type::ethereum).at(1).son_id)) { BOOST_TEST_MESSAGE("status: "<< iter->second); - BOOST_CHECK(iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal]"); + BOOST_CHECK(iter->second == "NOT OK, irregular SON heartbeat, triggering SON down proposal"); } else{ BOOST_TEST_MESSAGE("status: "<< iter->second); diff --git a/tests/peerplays_sidechain/ethereum_transaction_tests.cpp b/tests/peerplays_sidechain/ethereum_transaction_tests.cpp index 769c35b1..47cc090c 100644 --- a/tests/peerplays_sidechain/ethereum_transaction_tests.cpp +++ b/tests/peerplays_sidechain/ethereum_transaction_tests.cpp @@ -9,28 +9,48 @@ 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"); + const auto tx = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.0"); BOOST_CHECK_EQUAL(tx, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000"); - const auto tx1 = encoder.encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1"); + const auto tx1 = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1"); BOOST_CHECK_EQUAL(tx1, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); } +BOOST_AUTO_TEST_CASE(withdrawal_signature_encoder_test) { + const signature_encoder encoder{withdrawal_function_signature}; + + encoded_sign_transaction transaction; + transaction.data = "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000"; + transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" ); + + const auto tx = encoder.encode({transaction}); + BOOST_CHECK_EQUAL(tx, "0xdaac6c8100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000065c4622d2ff2b2d89c5c6f8225ab0f979bc69d4fcd4fd47db757b66fb8a39e2bc5522be5d101aa11e66da78db973f136b323be10bd107ff0b648f06b4c71ef2a4f00000000000000000000000000000000000000000000000000000000000000a4e088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); +} + 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"); + const auto tx = update_owners_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"); + const auto tx1 = update_owners_encoder::encode(owners_weights, "1.36.1"); BOOST_CHECK_EQUAL(tx1, "0x23ab6adf0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); } +BOOST_AUTO_TEST_CASE(update_owners_signature_encoder_test) { + const signature_encoder encoder{update_owners_function_signature}; + + encoded_sign_transaction transaction; + transaction.data = "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"; + transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" ); + + const auto tx = encoder.encode({transaction}); + BOOST_CHECK_EQUAL(tx, "0x9d6086730000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006698877eafa525c1a55f6b5e0a7187dfae484c97d9f77c4421a00276a9408a3e713d24402b44c05a883142fcffa84e1a802be37c17bb360f6f4810eb0415c8bbfd000000000000000000000000000000000000000000000000000000000000012423ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); +} + BOOST_AUTO_TEST_CASE(raw_transaction_serialization_test) { raw_transaction raw_tr; raw_tr.nonce = "0x0"; diff --git a/tests/tests/sidechain_addresses_test.cpp b/tests/tests/sidechain_addresses_test.cpp index 5f4885e6..8c3229d3 100644 --- a/tests/tests/sidechain_addresses_test.cpp +++ b/tests/tests/sidechain_addresses_test.cpp @@ -244,6 +244,9 @@ BOOST_AUTO_TEST_CASE( sidechain_address_delete_test ) { BOOST_TEST_MESSAGE("sidechain_address_delete_test"); + generate_blocks(HARDFORK_SIDECHAIN_DELETE_TIME); + generate_block(); + INVOKE(sidechain_address_add_test); GET_ACTOR(alice); @@ -266,18 +269,12 @@ BOOST_AUTO_TEST_CASE( sidechain_address_delete_test ) { sign(trx, alice_private_key); PUSH_TX(db, trx, ~0); } - //time_point_sec now = db.head_block_time(); - generate_block(); + generate_block(); { BOOST_TEST_MESSAGE("Check sidechain_address_delete_operation results"); 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() ) ); - //BOOST_REQUIRE( obj == idx.end() ); - //auto expired_obj = idx.find( boost::make_tuple( alice_id, sidechain_type::bitcoin, now ) ); - //BOOST_REQUIRE( expired_obj != idx.end() ); BOOST_REQUIRE( idx.size() == 0 ); } } @@ -286,6 +283,9 @@ BOOST_AUTO_TEST_CASE(sidechain_address_delete_create_test) { BOOST_TEST_MESSAGE("sidechain_address_delete_create_test"); + generate_blocks(HARDFORK_SIDECHAIN_DELETE_TIME); + generate_block(); + INVOKE(sidechain_address_add_test); GET_ACTOR(alice); diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index a128b474..23ddfd1c 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -208,9 +208,9 @@ try { db.modify( *son_stats_obj, [&]( son_statistics_object& _s) { - _s.last_down_timestamp[sidechain_type::bitcoin] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time()); - _s.last_down_timestamp[sidechain_type::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()); + _s.last_active_timestamp[sidechain_type::bitcoin] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time()); + _s.last_active_timestamp[sidechain_type::hive] = fc::time_point_sec(db.head_block_time() - db.get_global_properties().parameters.son_deregister_time()); + _s.last_active_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));