From b7113c4ff3495c6bb310ed60505dcbb3654c6316 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Mon, 28 Nov 2022 09:35:00 +0200 Subject: [PATCH 01/12] #478 - fix information warning --- libraries/wallet/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 6b1b2eb1..7eefae27 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -3349,7 +3349,7 @@ public: if(transaction_fee) { if (*transaction_fee >= xfer_op.amount) { - FC_THROW("Transaction fee: ${sidechain_fee}, would be grater than transfer amount ${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))); } } From c3eab0a80b015cea267ca9b283dc7c9e85aebce8 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Thu, 1 Dec 2022 01:53:39 +0000 Subject: [PATCH 02/12] #479 - Send one transaction for all owners --- .../peerplays_sidechain/ethereum/encoders.cpp | 57 ++++++++++- .../ethereum/transaction.cpp | 70 ++++++++------ .../peerplays_sidechain/ethereum/types.cpp | 31 ++++++ .../peerplays_sidechain/ethereum/encoders.hpp | 60 +++++------- .../ethereum/transaction.hpp | 89 +---------------- .../peerplays_sidechain/ethereum/types.hpp | 13 +++ .../peerplays_sidechain/ethereum/utils.hpp | 2 +- .../sidechain_net_handler_ethereum.cpp | 96 +++++++++++-------- .../ethereum_transaction_tests.cpp | 40 ++++++-- 9 files changed, 254 insertions(+), 204 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index ad42088b..feab921f 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 = "f6afbeff"; //! updateOwners_(address,(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 e243670d..dd1179b4 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)); - - unsigned int v = 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 = to_hex(v); - 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; } 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/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 13a89278..b2db9331 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 @@ -19,7 +19,7 @@ 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(add_front_zero) { + if (add_front_zero) { if (result.size() % 2) result = "0" + result; } diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index c827a721..951228d5 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -585,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); @@ -705,8 +737,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) { @@ -714,8 +745,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) { @@ -724,25 +754,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() { diff --git a/tests/peerplays_sidechain/ethereum_transaction_tests.cpp b/tests/peerplays_sidechain/ethereum_transaction_tests.cpp index 769c35b1..5bcc0543 100644 --- a/tests/peerplays_sidechain/ethereum_transaction_tests.cpp +++ b/tests/peerplays_sidechain/ethereum_transaction_tests.cpp @@ -9,12 +9,22 @@ using namespace graphene::peerplays_sidechain::ethereum; BOOST_AUTO_TEST_SUITE(ethereum_transaction_tests) BOOST_AUTO_TEST_CASE(withdrawal_encoder_test) { - const withdrawal_encoder encoder; - const auto tx = encoder.encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.0"); - BOOST_CHECK_EQUAL(tx, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000"); + const auto tx = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.0"); + BOOST_CHECK_EQUAL(tx, "0xcf7c8f6d0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000"); - const auto tx1 = encoder.encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1"); - BOOST_CHECK_EQUAL(tx1, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); + const auto tx1 = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1"); + BOOST_CHECK_EQUAL(tx1, "0xcf7c8f6d0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); +} + +BOOST_AUTO_TEST_CASE(withdrawal_signature_encoder_test) { + const signature_encoder encoder{withdrawal_function_signature}; + + encoded_sign_transaction transaction; + transaction.data = "0xcf7c8f6d0000000000000000000000005c79a9f5767e3c1b926f963fa24e21d8a04289ae0000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33372E300000000000000000000000000000000000000000000000000000"; + transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" ); + + const auto tx = encoder.encode({transaction}); + BOOST_CHECK_EQUAL(tx, "0xdaac6c8100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000065ef357c2788df103d443e3c4a9e0864d6f52fbaab479684b8eb6ea09422b6b54310ca0511c6cc02402a668a73f9613c00f6f535dbd2d78468ecba540a8a0dba3d00000000000000000000000000000000000000000000000000000000000000a4cf7c8f6d0000000000000000000000005c79a9f5767e3c1b926f963fa24e21d8a04289ae0000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33372E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); } BOOST_AUTO_TEST_CASE(update_owners_encoder_test) { @@ -22,13 +32,23 @@ BOOST_AUTO_TEST_CASE(update_owners_encoder_test) { owners_weights.emplace_back("5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12", 1); owners_weights.emplace_back("76ce31bd03f601c3fc13732def921c5bac282676", 1); - const update_owners_encoder encoder; - const auto tx = encoder.encode(owners_weights, "1.35.0"); - BOOST_CHECK_EQUAL(tx, "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"); + const auto tx = update_owners_encoder::encode(owners_weights, "1.35.0"); + BOOST_CHECK_EQUAL(tx, "0xf6afbeff000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"); owners_weights.emplace_back("09ee460834498a4ee361beb819470061b7381b49", 1); - const auto tx1 = encoder.encode(owners_weights, "1.36.1"); - BOOST_CHECK_EQUAL(tx1, "0x23ab6adf0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); + const auto tx1 = update_owners_encoder::encode(owners_weights, "1.36.1"); + BOOST_CHECK_EQUAL(tx1, "0xf6afbeff0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); +} + +BOOST_AUTO_TEST_CASE(update_owners_signature_encoder_test) { + const signature_encoder encoder{update_owners_function_signature}; + + encoded_sign_transaction transaction; + transaction.data = "0xf6afbeff000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"; + transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" ); + + const auto tx = encoder.encode({transaction}); + BOOST_CHECK_EQUAL(tx, "0x9d608673000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000665762851a05348a4900393b3f2778c5078689422e43e3a2aa9b517a4141133bd42c08169979785256a2f26d1da13e297125ee84c2d79be07212cfde592fc03dbb0000000000000000000000000000000000000000000000000000000000000124f6afbeff000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); } BOOST_AUTO_TEST_CASE(raw_transaction_serialization_test) { From 42b3890a7c3e9abfa79dd24baef68d50466e2068 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Tue, 6 Dec 2022 12:17:09 +0000 Subject: [PATCH 03/12] #482 burn eth from son account --- .../sidechain_net_handler_ethereum.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 951228d5..8faa5cdd 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -686,8 +686,18 @@ 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; } From ab1e08a7566ab5dd62322909a7b473492b65f029 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Thu, 8 Dec 2022 14:02:53 +0000 Subject: [PATCH 04/12] #479 one bunch transaction --- .../peerplays_sidechain/ethereum/encoders.cpp | 4 ++-- .../sidechain_net_handler_ethereum.cpp | 3 +-- .../ethereum_transaction_tests.cpp | 16 ++++++++-------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp index feab921f..ce1e0083 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -26,7 +26,7 @@ std::string base_encoder::encode_string(const std::string &value) { } //! update_owners_encoder -const std::string update_owners_encoder::function_signature = "f6afbeff"; //! updateOwners_(address,(address,uint256)[],string) +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); @@ -42,7 +42,7 @@ std::string update_owners_encoder::encode(const std::vector sidechain_net_handler_ethereum::estimate_withdrawal_transaction_ } const auto &public_key = son->sidechain_public_keys.at(sidechain); - const ethereum::withdrawal_encoder encoder; - const auto data = encoder.encode(public_key, 1 * 10000000000, son_wallet_withdraw_id_type{0}.operator object_id_type().operator std::string()); + const auto data = ethereum::withdrawal_encoder::encode(public_key, 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)); diff --git a/tests/peerplays_sidechain/ethereum_transaction_tests.cpp b/tests/peerplays_sidechain/ethereum_transaction_tests.cpp index 5bcc0543..47cc090c 100644 --- a/tests/peerplays_sidechain/ethereum_transaction_tests.cpp +++ b/tests/peerplays_sidechain/ethereum_transaction_tests.cpp @@ -10,21 +10,21 @@ BOOST_AUTO_TEST_SUITE(ethereum_transaction_tests) BOOST_AUTO_TEST_CASE(withdrawal_encoder_test) { const auto tx = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.0"); - BOOST_CHECK_EQUAL(tx, "0xcf7c8f6d0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(tx, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000"); const auto tx1 = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1"); - BOOST_CHECK_EQUAL(tx1, "0xcf7c8f6d0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); + 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 = "0xcf7c8f6d0000000000000000000000005c79a9f5767e3c1b926f963fa24e21d8a04289ae0000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33372E300000000000000000000000000000000000000000000000000000"; + transaction.data = "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000"; transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" ); const auto tx = encoder.encode({transaction}); - BOOST_CHECK_EQUAL(tx, "0xdaac6c8100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000065ef357c2788df103d443e3c4a9e0864d6f52fbaab479684b8eb6ea09422b6b54310ca0511c6cc02402a668a73f9613c00f6f535dbd2d78468ecba540a8a0dba3d00000000000000000000000000000000000000000000000000000000000000a4cf7c8f6d0000000000000000000000005c79a9f5767e3c1b926f963fa24e21d8a04289ae0000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33372E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(tx, "0xdaac6c8100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000065c4622d2ff2b2d89c5c6f8225ab0f979bc69d4fcd4fd47db757b66fb8a39e2bc5522be5d101aa11e66da78db973f136b323be10bd107ff0b648f06b4c71ef2a4f00000000000000000000000000000000000000000000000000000000000000a4e088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); } BOOST_AUTO_TEST_CASE(update_owners_encoder_test) { @@ -33,22 +33,22 @@ BOOST_AUTO_TEST_CASE(update_owners_encoder_test) { owners_weights.emplace_back("76ce31bd03f601c3fc13732def921c5bac282676", 1); const auto tx = update_owners_encoder::encode(owners_weights, "1.35.0"); - BOOST_CHECK_EQUAL(tx, "0xf6afbeff000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(tx, "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"); owners_weights.emplace_back("09ee460834498a4ee361beb819470061b7381b49", 1); const auto tx1 = update_owners_encoder::encode(owners_weights, "1.36.1"); - BOOST_CHECK_EQUAL(tx1, "0xf6afbeff0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); + 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 = "0xf6afbeff000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"; + transaction.data = "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"; transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" ); const auto tx = encoder.encode({transaction}); - BOOST_CHECK_EQUAL(tx, "0x9d608673000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000665762851a05348a4900393b3f2778c5078689422e43e3a2aa9b517a4141133bd42c08169979785256a2f26d1da13e297125ee84c2d79be07212cfde592fc03dbb0000000000000000000000000000000000000000000000000000000000000124f6afbeff000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(tx, "0x9d6086730000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006698877eafa525c1a55f6b5e0a7187dfae484c97d9f77c4421a00276a9408a3e713d24402b44c05a883142fcffa84e1a802be37c17bb360f6f4810eb0415c8bbfd000000000000000000000000000000000000000000000000000000000000012423ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); } BOOST_AUTO_TEST_CASE(raw_transaction_serialization_test) { From 4883dfe38d0eb3dfa71fcc2203b220a802e3453f Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Thu, 8 Dec 2022 14:03:14 +0000 Subject: [PATCH 05/12] #484 multiple eth withdrawals --- .../ethereum/transaction.cpp | 8 ++--- .../peerplays_sidechain/ethereum/utils.cpp | 20 +++++++++++ .../peerplays_sidechain/ethereum/utils.hpp | 4 +++ .../sidechain_net_handler.hpp | 9 ++--- .../sidechain_net_handler.cpp | 36 ++++++++++++------- .../sidechain_net_handler_ethereum.cpp | 2 +- 6 files changed, 57 insertions(+), 22 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index dd1179b4..9a1383df 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -210,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)); } @@ -234,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/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/utils.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/utils.hpp index b2db9331..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,6 +14,10 @@ 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, bool add_front_zero = true) { std::stringstream stream; 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 fc295b4c..0e7e2fc1 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); 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_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 8faa5cdd..358c352c 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -76,7 +76,7 @@ std::string ethereum_rpc_client::get_network_id() { } 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); From d387e324fe515924197fa6d695c4a296c20eef8a Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Wed, 14 Dec 2022 15:52:28 +0200 Subject: [PATCH 06/12] #489 - Fix error message --- libraries/wallet/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 7eefae27..16a9cb38 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -3349,7 +3349,7 @@ public: if(transaction_fee) { if (*transaction_fee >= xfer_op.amount) { - FC_THROW("Transaction fee: ${sidechain_fee}, is greater than transferred amount ${amount}", + FC_THROW("Transaction fee: ${sidechain_fee}, is greater than or equal to the 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))); } } From 578edc56d864a4637c9ef8dc2cb8efc3edcdae53 Mon Sep 17 00:00:00 2001 From: timur <12267899-timur.5@users.noreply.gitlab.com> Date: Fri, 16 Dec 2022 00:34:33 +0000 Subject: [PATCH 07/12] Fix Ubuntu 18 build --- Dockerfile | 65 +++++++++++++++++-- Dockerfile.18.04 | 44 +++++++++++-- .../wallet/include/graphene/wallet/wallet.hpp | 4 +- 3 files changed, 102 insertions(+), 11 deletions(-) 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/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 6a0b5ee5..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 From bb7c534b10b114cbf3571f54a20f5ca8cba6e255 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Fri, 16 Dec 2022 04:27:31 +0100 Subject: [PATCH 08/12] Update Hive's son-account owner authority on primary wallet update --- .../sidechain_net_handler_hive.cpp | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp index 63ae22c6..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); From ca69a692cce0b660806b699b6a1fb1b1b536c5ea Mon Sep 17 00:00:00 2001 From: timur <12267899-timur.5@users.noreply.gitlab.com> Date: Wed, 21 Dec 2022 17:45:42 +0000 Subject: [PATCH 09/12] Add or revive a few NFT-listing APIs --- libraries/app/database_api.cpp | 61 ++- .../app/include/graphene/app/database_api.hpp | 16 +- .../include/graphene/chain/nft_object.hpp | 3 + .../wallet/include/graphene/wallet/wallet.hpp | 24 +- libraries/wallet/wallet.cpp | 23 +- tests/tests/nft_tests.cpp | 361 +++++++++++++----- 6 files changed, 384 insertions(+), 104 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 64fb82c2..e22e1dc4 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -269,8 +269,9 @@ public: uint64_t nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const; nft_object nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const; nft_object nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const; - vector nft_get_all_tokens() const; - vector nft_get_tokens_by_owner(const account_id_type owner) const; + vector nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const; + vector nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const; + vector nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const; // Marketplace vector list_offers(const offer_id_type lower_id, uint32_t limit) const; @@ -291,6 +292,7 @@ public: uint32_t api_limit_get_limit_orders_by_account = 101; uint32_t api_limit_get_order_book = 50; uint32_t api_limit_all_offers_count = 100; + uint32_t api_limit_nft_tokens = 100; uint32_t api_limit_lookup_accounts = 1000; uint32_t api_limit_lookup_witness_accounts = 1000; uint32_t api_limit_lookup_committee_member_accounts = 1000; @@ -3102,30 +3104,61 @@ nft_object database_api_impl::nft_token_of_owner_by_index(const nft_metadata_id_ return {}; } -vector database_api::nft_get_all_tokens() const { - return my->nft_get_all_tokens(); +vector database_api::nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const { + return my->nft_get_all_tokens(lower_id, limit); } -vector database_api_impl::nft_get_all_tokens() const { +vector database_api_impl::nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_nft_tokens, + "Number of queried nft tokens can not be greater than ${configured_limit}", + ("configured_limit", api_limit_nft_tokens)); + const auto &idx_nft = _db.get_index_type().indices().get(); vector result; - for (auto itr = idx_nft.begin(); itr != idx_nft.end(); ++itr) { - result.push_back(*itr); - } + result.reserve(limit); + auto itr = idx_nft.lower_bound(lower_id); + while (limit-- && itr != idx_nft.end()) + result.emplace_back(*itr++); return result; } -vector database_api::nft_get_tokens_by_owner(const account_id_type owner) const { - return my->nft_get_tokens_by_owner(owner); +vector database_api::nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const { + return my->nft_get_tokens_by_owner(owner, lower_id, limit); } -vector database_api_impl::nft_get_tokens_by_owner(const account_id_type owner) const { +vector database_api_impl::nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_nft_tokens, + "Number of queried nft tokens can not be greater than ${configured_limit}", + ("configured_limit", api_limit_nft_tokens)); const auto &idx_nft = _db.get_index_type().indices().get(); auto idx_nft_range = idx_nft.equal_range(owner); vector result; - for (auto itr = idx_nft_range.first; itr != idx_nft_range.second; ++itr) { - result.push_back(*itr); - } + result.reserve(limit); + auto itr = std::find_if(idx_nft_range.first, idx_nft_range.second, [&lower_id](const nft_object &obj) { + return !(obj.id.instance() < lower_id.instance); + }); + while (limit-- && itr != idx_nft_range.second) + result.emplace_back(*itr++); + return result; +} + +vector database_api::nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const { + return my->nft_get_metadata_by_owner(owner, lower_id, limit); +} + +vector database_api_impl::nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_nft_tokens, + "Number of queried nft metadata objects can not be greater than ${configured_limit}", + ("configured_limit", api_limit_nft_tokens)); + const auto &idx_nft = _db.get_index_type().indices().get(); + auto idx_nft_range = idx_nft.equal_range(owner); + vector result; + result.reserve(limit); + auto itr = std::find_if(idx_nft_range.first, idx_nft_range.second, [&lower_id](const nft_metadata_object &obj) { + return !(obj.id.instance() < lower_id.instance); + }); + while (limit-- && itr != idx_nft_range.second) + result.emplace_back(*itr++); return result; } diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index b53c8eeb..55da8e5f 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -1027,14 +1027,25 @@ public: * @brief Returns list of all available NTF's * @return List of all available NFT's */ - vector nft_get_all_tokens() const; + vector nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const; /** * @brief Returns NFT's owned by owner * @param owner NFT owner + * @param lower_id ID of the first NFT to return + * @param limit Maximum number of results to return * @return List of NFT owned by owner */ - vector nft_get_tokens_by_owner(const account_id_type owner) const; + vector nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const; + + /** + * @brief Returns NFT metadata owned by owner + * @param owner NFT owner + * @param lower_id ID of the first NFT metadata to return + * @param limit Maximum number of results to return + * @return List of NFT owned by owner + */ + vector nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const; ////////////////// // MARKET PLACE // @@ -1249,6 +1260,7 @@ FC_API(graphene::app::database_api, (nft_token_of_owner_by_index) (nft_get_all_tokens) (nft_get_tokens_by_owner) + (nft_get_metadata_by_owner) // Marketplace (list_offers) diff --git a/libraries/chain/include/graphene/chain/nft_object.hpp b/libraries/chain/include/graphene/chain/nft_object.hpp index fe026da5..a54992c4 100644 --- a/libraries/chain/include/graphene/chain/nft_object.hpp +++ b/libraries/chain/include/graphene/chain/nft_object.hpp @@ -130,6 +130,9 @@ namespace graphene { namespace chain { std::greater< uint32_t >, std::greater< object_id_type > > + >, + ordered_non_unique< tag, + member > > >; diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index a7807596..3d8d5b06 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -2571,9 +2571,29 @@ class wallet_api /** * @brief Returns all tokens + * @param limit the maximum number of NFT objects to return (max: 100) + * @param lower_id ID of the first NFT object to include in the list. * @return Returns vector of NFT objects, empty vector if none */ - vector nft_get_all_tokens() const; + vector nft_get_all_tokens(uint32_t limit, optional lower_id) const; + + /** + * @brief Returns all tokens owned by owner + * @param owner NFT owner account ID + * @param limit the maximum number of NFT objects to return (max: 100) + * @param lower_id ID of the first NFT object to include in the list. + * @return Returns vector of NFT objects, empty vector if none + */ + vector nft_get_tokens_by_owner(account_id_type owner, uint32_t limit, optional lower_id) const; + + /** + * @brief Returns all NFT metadata objects owned by owner + * @param owner NFT owner account ID + * @param limit the maximum number of NFT metadata objects to return (max: 100) + * @param lower_id ID of the first NFT metadata object to include in the list. + * @return Returns vector of NFT metadata objects, empty vector if none + */ + vector nft_get_metadata_by_owner(account_id_type owner, uint32_t limit, optional lower_id) const; signed_transaction nft_lottery_buy_ticket( nft_metadata_id_type lottery, account_id_type buyer, uint64_t tickets_to_buy, bool broadcast ); signed_transaction create_offer(set item_ids, @@ -2943,6 +2963,8 @@ FC_API( graphene::wallet::wallet_api, (nft_get_approved) (nft_is_approved_for_all) (nft_get_all_tokens) + (nft_get_tokens_by_owner) + (nft_get_metadata_by_owner) (nft_lottery_buy_ticket) (create_offer) (create_bid) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 7eefae27..bf239679 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -7027,9 +7027,28 @@ bool wallet_api::nft_is_approved_for_all(string owner_account_id_or_name, string return my->_remote_db->nft_is_approved_for_all(owner_account.id, operator_account.id); } -vector wallet_api::nft_get_all_tokens() const +vector wallet_api::nft_get_all_tokens(uint32_t limit, optional lower_id) const { - return my->_remote_db->nft_get_all_tokens(); + nft_id_type lb_id; + if(lower_id) + lb_id = *lower_id; + return my->_remote_db->nft_get_all_tokens(lb_id, limit); +} + +vector wallet_api::nft_get_tokens_by_owner(account_id_type owner, uint32_t limit, optional lower_id) const +{ + nft_id_type lb_id; + if(lower_id) + lb_id = *lower_id; + return my->_remote_db->nft_get_tokens_by_owner(owner, lb_id, limit); +} + +vector wallet_api::nft_get_metadata_by_owner(account_id_type owner, uint32_t limit, optional lower_id) const +{ + nft_metadata_id_type lb_id; + if(lower_id) + lb_id = *lower_id; + return my->_remote_db->nft_get_metadata_by_owner(owner, lb_id, limit); } signed_transaction wallet_api::nft_lottery_buy_ticket( nft_metadata_id_type lottery, account_id_type buyer, uint64_t tickets_to_buy, bool broadcast ) diff --git a/tests/tests/nft_tests.cpp b/tests/tests/nft_tests.cpp index b8fd19ea..83643eed 100644 --- a/tests/tests/nft_tests.cpp +++ b/tests/tests/nft_tests.cpp @@ -4,76 +4,204 @@ #include #include +#include + using namespace graphene::chain; using namespace graphene::chain::test; + +class nft_test_helper +{ + database_fixture& fixture_; + +public: + nft_test_helper(database_fixture& fixture): + fixture_(fixture) + { + fixture_.generate_blocks(HARDFORK_NFT_TIME); + fixture_.generate_block(); + fixture_.generate_block(); + set_expiration(fixture_.db, fixture_.trx); + } + + nft_metadata_object create_metadata(const std::string& name, const std::string& symbol, const std::string& uri, const account_id_type& owner, const fc::ecc::private_key &priv_key) + { + const auto& idx_by_id = fixture_.db.get_index_type().indices().get(); + size_t obj_count0 = idx_by_id.size(); + + fixture_.generate_block(); + + signed_transaction trx; + set_expiration(fixture_.db, trx); + + nft_metadata_create_operation op; + op.owner = owner; + op.symbol = symbol; + op.base_uri = uri; + op.name = name; + op.is_transferable = true; + BOOST_CHECK_NO_THROW(op.validate()); + trx.operations.push_back(op); + fixture_.sign(trx, priv_key); + PUSH_TX(fixture_.db, trx, ~0); + fixture_.generate_block(); + + BOOST_REQUIRE( idx_by_id.size() == obj_count0 + 1 ); // one more metadata created + + const auto& idx_by_name = fixture_.db.get_index_type().indices().get(); + auto obj = idx_by_name.find(name); + BOOST_CHECK( obj->owner == owner ); + BOOST_CHECK( obj->name == name ); + BOOST_CHECK( obj->symbol == symbol ); + BOOST_CHECK( obj->base_uri == uri ); + return *obj; + } + + + nft_object mint(const nft_metadata_id_type& metadata, const account_id_type& owner, const account_id_type& payer, + const fc::optional& approved, const std::vector& approved_operators, + const fc::ecc::private_key &priv_key) + { + const auto& idx_by_id = fixture_.db.get_index_type().indices().get(); + size_t obj_count0 = idx_by_id.size(); + + fixture_.generate_block(); + + signed_transaction trx; + set_expiration(fixture_.db, trx); + + nft_mint_operation op; + op.nft_metadata_id = metadata; + op.payer = payer; + op.owner = owner; + if (approved) + op.approved = *approved; + op.approved_operators = approved_operators; + + trx.operations.push_back(op); + fixture_.sign(trx, priv_key); + PUSH_TX(fixture_.db, trx, ~0); + + fixture_.generate_block(); + + BOOST_REQUIRE(idx_by_id.size() == obj_count0 + 1); // one more created + + auto obj = idx_by_id.rbegin(); + + BOOST_REQUIRE(obj != idx_by_id.rend()); + BOOST_CHECK(obj->owner == owner); + BOOST_CHECK(obj->approved_operators.size() == approved_operators.size()); + BOOST_CHECK(obj->approved_operators == approved_operators); + + return *obj; + } +}; + + BOOST_FIXTURE_TEST_SUITE( nft_tests, database_fixture ) + +BOOST_AUTO_TEST_CASE( nft_metadata_name_validation_test ) { + BOOST_TEST_MESSAGE("nft_metadata_name_validation_test"); + ACTORS((mdowner)); + nft_metadata_create_operation op; + op.owner = mdowner_id; + op.symbol = "NFT"; + op.base_uri = "http://nft.example.com"; + op.name = "123"; + op.is_transferable = true; + BOOST_CHECK_THROW(op.validate(), fc::exception); + op.name = ""; + BOOST_CHECK_THROW(op.validate(), fc::exception); + op.name = "1ab"; + BOOST_CHECK_THROW(op.validate(), fc::exception); + op.name = ".abc"; + BOOST_CHECK_THROW(op.validate(), fc::exception); + op.name = "abc."; + BOOST_CHECK_THROW(op.validate(), fc::exception); + op.name = "ABC"; + BOOST_CHECK_NO_THROW(op.validate()); + op.name = "abcdefghijklmnopq"; + BOOST_CHECK_THROW(op.validate(), fc::exception); + op.name = "ab"; + BOOST_CHECK_THROW(op.validate(), fc::exception); + op.name = "***"; + BOOST_CHECK_THROW(op.validate(), fc::exception); + op.name = "a12"; + BOOST_CHECK_NO_THROW(op.validate()); + op.name = "a1b"; + BOOST_CHECK_NO_THROW(op.validate()); + op.name = "abc"; + BOOST_CHECK_NO_THROW(op.validate()); + op.name = "abc123defg12345"; + BOOST_CHECK_NO_THROW(op.validate()); + op.name = "NFT Test"; + BOOST_CHECK_NO_THROW(op.validate()); +} + + BOOST_AUTO_TEST_CASE( nft_metadata_create_test ) { BOOST_TEST_MESSAGE("nft_metadata_create_test"); - generate_blocks(HARDFORK_NFT_TIME); - generate_block(); - generate_block(); - set_expiration(db, trx); - + nft_test_helper nfth(*this); ACTORS((mdowner)); + nfth.create_metadata("NFT Test", "NFT", "http://nft.example.com", mdowner_id, mdowner_private_key); +} - generate_block(); - set_expiration(db, trx); +BOOST_AUTO_TEST_CASE( nft_metadata_listing_test ) { + + BOOST_TEST_MESSAGE("nft_metadata_listing_test"); + + nft_test_helper nfth(*this); + + ACTORS((mdowner1)); + ACTORS((mdowner2)); + + // prepare metadata set + for (int i=0; i < 200; i++) { - BOOST_TEST_MESSAGE("Send nft_metadata_create_operation"); - - nft_metadata_create_operation op; - op.owner = mdowner_id; - op.symbol = "NFT"; - op.base_uri = "http://nft.example.com"; - op.name = "123"; - op.is_transferable = true; - BOOST_CHECK_THROW(op.validate(), fc::exception); - op.name = ""; - BOOST_CHECK_THROW(op.validate(), fc::exception); - op.name = "1ab"; - BOOST_CHECK_THROW(op.validate(), fc::exception); - op.name = ".abc"; - BOOST_CHECK_THROW(op.validate(), fc::exception); - op.name = "abc."; - BOOST_CHECK_THROW(op.validate(), fc::exception); - op.name = "ABC"; - BOOST_CHECK_NO_THROW(op.validate()); - op.name = "abcdefghijklmnopq"; - BOOST_CHECK_THROW(op.validate(), fc::exception); - op.name = "ab"; - BOOST_CHECK_THROW(op.validate(), fc::exception); - op.name = "***"; - BOOST_CHECK_THROW(op.validate(), fc::exception); - op.name = "a12"; - BOOST_CHECK_NO_THROW(op.validate()); - op.name = "a1b"; - BOOST_CHECK_NO_THROW(op.validate()); - op.name = "abc"; - BOOST_CHECK_NO_THROW(op.validate()); - op.name = "abc123defg12345"; - BOOST_CHECK_NO_THROW(op.validate()); - op.name = "NFT Test"; - trx.operations.push_back(op); - sign(trx, mdowner_private_key); - PUSH_TX(db, trx, ~0); + string sfx = fc::to_pretty_string(i); + nft_metadata_object md = nfth.create_metadata("NFT Test " + sfx, "NFT" + sfx, "http://nft.example.com", mdowner1_id, mdowner1_private_key); + BOOST_REQUIRE(md.id == nft_metadata_id_type(i)); + } + for (int i=200; i < 250; i++) + { + string sfx = fc::to_pretty_string(i); + nft_metadata_object md = nfth.create_metadata("NFT Test " + sfx, "NFT" + sfx, "http://nft.example.com", mdowner2_id, mdowner2_private_key); + BOOST_REQUIRE(md.id == nft_metadata_id_type(i)); } - generate_block(); - BOOST_TEST_MESSAGE("Check nft_metadata_create_operation results"); + graphene::app::database_api db_api(db); + vector listed; - const auto& idx = db.get_index_type().indices().get(); - BOOST_REQUIRE( idx.size() == 1 ); - auto obj = idx.begin(); - BOOST_REQUIRE( obj != idx.end() ); - BOOST_CHECK( obj->owner == mdowner_id ); - BOOST_CHECK( obj->name == "NFT Test" ); - BOOST_CHECK( obj->symbol == "NFT" ); - BOOST_CHECK( obj->base_uri == "http://nft.example.com" ); + // first 100 returned + listed = db_api.nft_get_metadata_by_owner(mdowner1_id, nft_metadata_id_type(0), 100); + BOOST_REQUIRE(listed.size() == 100); + BOOST_REQUIRE(listed[ 0].id == nft_metadata_id_type( 0)); + BOOST_REQUIRE(listed[99].id == nft_metadata_id_type(99)); + + // 100 starting from 50 + listed = db_api.nft_get_metadata_by_owner(mdowner1_id, nft_metadata_id_type(50), 100); + BOOST_REQUIRE(listed.size() == 100); + BOOST_REQUIRE(listed[ 0].id == nft_metadata_id_type( 50)); + BOOST_REQUIRE(listed[99].id == nft_metadata_id_type(149)); + + // the last 5 must be returned + listed = db_api.nft_get_metadata_by_owner(mdowner1_id, nft_metadata_id_type(195), 10); + BOOST_REQUIRE(listed.size() == 5); + BOOST_REQUIRE(listed[0].id == nft_metadata_id_type(195)); + BOOST_REQUIRE(listed[4].id == nft_metadata_id_type(199)); + + // too much requested at once + BOOST_CHECK_THROW(db_api.nft_get_metadata_by_owner(mdowner1_id, nft_metadata_id_type(0), 101), fc::exception); + + // the last 40 must be returned + listed = db_api.nft_get_metadata_by_owner(mdowner2_id, nft_metadata_id_type(210), 100); + BOOST_REQUIRE(listed.size() == 40); + BOOST_REQUIRE(listed[ 0].id == nft_metadata_id_type(210)); + BOOST_REQUIRE(listed[39].id == nft_metadata_id_type(249)); } @@ -120,49 +248,112 @@ BOOST_AUTO_TEST_CASE( nft_mint_test ) { generate_block(); set_expiration(db, trx); - INVOKE(nft_metadata_create_test); + nft_test_helper nfth(*this); + ACTORS((mdowner)); ACTORS((alice)); ACTORS((bob)); ACTORS((operator1)); ACTORS((operator2)); - GET_ACTOR(mdowner); + nft_metadata_object md = nfth.create_metadata("NFT Test", "NFT", "http://nft.example.com", mdowner_id, mdowner_private_key); - generate_block(); - set_expiration(db, trx); + nfth.mint(md.id, alice_id, mdowner_id, alice_id, {operator1_id, operator2_id}, alice_private_key); +} + +BOOST_AUTO_TEST_CASE( nft_object_listing_test ) { + + BOOST_TEST_MESSAGE("nft_object_listing_test"); + + nft_test_helper nfth(*this); + + ACTORS((mdowner1)); + ACTORS((mdowner2)); + ACTORS((alice)); + ACTORS((bob)); + + nft_metadata_object md1 = nfth.create_metadata("NFT Test 1", "NFT1", "http://nft.example.com", mdowner1_id, mdowner1_private_key); + nft_metadata_object md2 = nfth.create_metadata("NFT Test 2", "NFT2", "http://nft.example.com", mdowner2_id, mdowner2_private_key); + + // create NFT objects: 200 owned by alice and 200 by bob + for (int i=0; i < 200; i++) { - BOOST_TEST_MESSAGE("Send nft_mint_operation"); - - const auto& idx = db.get_index_type().indices().get(); - BOOST_REQUIRE( idx.size() == 1 ); - auto nft_md_obj = idx.begin(); - - nft_mint_operation op; - op.payer = mdowner_id; - op.nft_metadata_id = nft_md_obj->id; - op.owner = alice_id; - op.approved = alice_id; - op.approved_operators.push_back(operator1_id); - op.approved_operators.push_back(operator2_id); - - trx.operations.push_back(op); - sign(trx, alice_private_key); - PUSH_TX(db, trx, ~0); + nft_object nft = nfth.mint(md1.id, alice_id, mdowner1_id, alice_id, {}, alice_private_key); + BOOST_REQUIRE(nft.id == nft_id_type(i)); + } + for (int i=200; i < 250; i++) + { + nft_object nft = nfth.mint(md1.id, bob_id, mdowner1_id, bob_id, {}, bob_private_key); + BOOST_REQUIRE(nft.id == nft_id_type(i)); } - generate_block(); - BOOST_TEST_MESSAGE("Check nft_mint_operation results"); + graphene::app::database_api db_api(db); + vector listed; - const auto& idx = db.get_index_type().indices().get(); - BOOST_REQUIRE( idx.size() == 1 ); - auto obj = idx.begin(); - BOOST_REQUIRE( obj != idx.end() ); - BOOST_CHECK( obj->owner == alice_id ); - BOOST_CHECK( obj->approved_operators.size() == 2 ); - BOOST_CHECK( obj->approved_operators.at(0) == operator1_id ); - BOOST_CHECK( obj->approved_operators.at(1) == operator2_id ); + // + // listing all tokens: + // + // first 100 returned, all alice's + listed = db_api.nft_get_all_tokens(nft_id_type(0), 100); + BOOST_REQUIRE(listed.size() == 100); + BOOST_REQUIRE(listed[ 0].id == nft_id_type( 0)); + BOOST_REQUIRE(listed[99].id == nft_id_type(99)); + BOOST_REQUIRE(all_of(listed.begin(), listed.end(), [alice_id](const nft_object &obj){ return obj.owner == alice_id; })); + + // 100 starting from 50, all alice's + listed = db_api.nft_get_all_tokens(nft_id_type(50), 100); + BOOST_REQUIRE(listed.size() == 100); + BOOST_REQUIRE(listed[ 0].id == nft_id_type( 50)); + BOOST_REQUIRE(listed[99].id == nft_id_type(149)); + BOOST_REQUIRE(all_of(listed.begin(), listed.end(), [alice_id](const nft_object &obj){ return obj.owner == alice_id; })); + + // the last 5 must be returned, all bob's + listed = db_api.nft_get_all_tokens(nft_id_type(245), 10); + BOOST_REQUIRE(listed.size() == 5); + BOOST_REQUIRE(listed[0].id == nft_id_type(245)); + BOOST_REQUIRE(listed[4].id == nft_id_type(249)); + BOOST_REQUIRE(all_of(listed.begin(), listed.end(), [bob_id](const nft_object &obj){ return obj.owner == bob_id; })); + + // 10 from the middle of the set, half alice's, half bob's + listed = db_api.nft_get_all_tokens(nft_id_type(195), 10); + BOOST_REQUIRE(listed.size() == 10); + BOOST_REQUIRE(listed[0].id == nft_id_type(195)); + BOOST_REQUIRE(listed[9].id == nft_id_type(204)); + BOOST_REQUIRE(listed[0].owner == alice_id); + BOOST_REQUIRE(listed[4].owner == alice_id); + BOOST_REQUIRE(listed[5].owner == bob_id); + BOOST_REQUIRE(listed[9].owner == bob_id); + + // too much requested at once + BOOST_CHECK_THROW(db_api.nft_get_all_tokens(nft_id_type(0), 101), fc::exception); + + // + // listing tokens by owner: + // + // first 100 alice's + listed = db_api.nft_get_tokens_by_owner(alice_id, nft_id_type(0), 100); + BOOST_REQUIRE(listed.size() == 100); + BOOST_REQUIRE(all_of(listed.begin(), listed.end(), [alice_id](const nft_object &obj){ return obj.owner == alice_id; })); + BOOST_REQUIRE(listed[ 0].id == nft_id_type( 0)); + BOOST_REQUIRE(listed[99].id == nft_id_type(99)); + + // the last 5 alice's must be returned + listed = db_api.nft_get_tokens_by_owner(alice_id, nft_id_type(195), 10); + BOOST_REQUIRE(listed.size() == 5); + BOOST_REQUIRE(all_of(listed.begin(), listed.end(), [alice_id](const nft_object &obj){ return obj.owner == alice_id; })); + BOOST_REQUIRE(listed[0].id == nft_id_type(195)); + BOOST_REQUIRE(listed[4].id == nft_id_type(199)); + + // all 50 bob's + listed = db_api.nft_get_tokens_by_owner(bob_id, nft_id_type(0), 60); + BOOST_REQUIRE(listed.size() == 50); + BOOST_REQUIRE(all_of(listed.begin(), listed.end(), [bob_id](const nft_object &obj){ return obj.owner == bob_id; })); + BOOST_REQUIRE(listed[ 0].id == nft_id_type(200)); + BOOST_REQUIRE(listed[49].id == nft_id_type(249)); + + // too much requested at once + BOOST_CHECK_THROW(db_api.nft_get_tokens_by_owner(alice_id, nft_id_type(0), 101), fc::exception); } From d264398a6f7293ec1e30df3b9717e0e52d6e6efe Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Fri, 23 Dec 2022 15:37:15 +0200 Subject: [PATCH 10/12] #499 - son_wallet_deposit_process_operation approve fix --- libraries/app/database_api.cpp | 10 +- .../sidechain_net_handler_ethereum.hpp | 1 + .../sidechain_net_handler_ethereum.cpp | 132 ++++++++---------- 3 files changed, 67 insertions(+), 76 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index e22e1dc4..30f2e2df 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -3135,10 +3135,10 @@ vector database_api_impl::nft_get_tokens_by_owner(const account_id_t vector result; result.reserve(limit); auto itr = std::find_if(idx_nft_range.first, idx_nft_range.second, [&lower_id](const nft_object &obj) { - return !(obj.id.instance() < lower_id.instance); - }); + return !(obj.id.instance() < lower_id.instance); + }); while (limit-- && itr != idx_nft_range.second) - result.emplace_back(*itr++); + result.emplace_back(*itr++); return result; } @@ -3155,8 +3155,8 @@ vector database_api_impl::nft_get_metadata_by_owner(const a vector result; result.reserve(limit); auto itr = std::find_if(idx_nft_range.first, idx_nft_range.second, [&lower_id](const nft_metadata_object &obj) { - return !(obj.id.instance() < lower_id.instance); - }); + return !(obj.id.instance() < lower_id.instance); + }); while (limit-- && itr != idx_nft_range.second) result.emplace_back(*itr++); return result; 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 e6e8f298..8bc463ab 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 @@ -34,6 +34,7 @@ public: std::string eth_send_transaction(const std::string ¶ms); std::string eth_send_raw_transaction(const std::string ¶ms); std::string eth_get_transaction_receipt(const std::string ¶ms); + std::string eth_get_transaction_by_hash(const std::string ¶ms); }; class sidechain_net_handler_ethereum : public sidechain_net_handler { diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index a237c4f4..6fe4a91d 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -121,6 +121,10 @@ std::string ethereum_rpc_client::eth_get_transaction_receipt(const std::string & return send_post_request("eth_getTransactionReceipt", "[\"" + params + "\"]", debug_rpc_calls); } +std::string ethereum_rpc_client::eth_get_transaction_by_hash(const std::string ¶ms) { + return send_post_request("eth_getTransactionByHash", "[\"" + params + "\"]", debug_rpc_calls); +} + sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : sidechain_net_handler(_plugin, options) { sidechain = sidechain_type::ethereum; @@ -213,13 +217,13 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) 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 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.at(sidechain); - vector wallet_sons = swo->sons.at(sidechain); + const auto active_sons = gpo.active_sons.at(sidechain); + const vector wallet_sons = swo->sons.at(sidechain); bool son_sets_equal = (active_sons.size() == wallet_sons.size()); @@ -234,8 +238,8 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) } if (po.proposed_transaction.operations.size() >= 2) { - object_id_type object_id = op_obj_idx_1.get().object_id; - std::string op_tx_str = op_obj_idx_1.get().transaction; + const object_id_type object_id = op_obj_idx_1.get().object_id; + const std::string op_tx_str = op_obj_idx_1.get().transaction; const auto &st_idx = database.get_index_type().indices().get(); const auto st = st_idx.find(object_id); @@ -265,64 +269,45 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) 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 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); - // } - // } - // } - //} - } + const std::string swdo_txid = swdo->sidechain_transaction_id; + const std::string swdo_sidechain_from = swdo->sidechain_from; + const std::string swdo_sidechain_currency = swdo->sidechain_currency; + const uint64_t swdo_sidechain_amount = swdo->sidechain_amount.value; - process_ok = true; + const std::string tx_str = rpc_client->eth_get_transaction_by_hash(swdo_txid); + if (tx_str != "") { + + std::stringstream ss_tx(tx_str); + boost::property_tree::ptree tx; + boost::property_tree::read_json(ss_tx, tx); + + if (tx.get("result") != "null") { + + const std::string sidechain_from = tx.get("result.from"); + const std::string sidechain_to = tx.get("result.to"); + const std::string value_s = tx.get("result.value"); + boost::multiprecision::uint256_t amount(value_s); + amount = amount / 100000; + amount = amount / 100000; + const fc::safe sidechain_amount = amount; + + std::string cmp_sidechain_to = sidechain_to; + std::transform(cmp_sidechain_to.begin(), cmp_sidechain_to.end(), cmp_sidechain_to.begin(), ::toupper); + std::string cmp_wallet_contract_address = wallet_contract_address; + std::transform(cmp_wallet_contract_address.begin(), cmp_wallet_contract_address.end(), cmp_wallet_contract_address.begin(), ::toupper); + + process_ok = (swdo_sidechain_from == sidechain_from) && + (cmp_sidechain_to == cmp_wallet_contract_address) && + (swdo_sidechain_currency == "ETH") && + (swdo_sidechain_amount == sidechain_amount.value); + } + } + } should_approve = process_ok; break; @@ -331,23 +316,23 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) 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 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 uint32_t swwo_block_num = swwo->block_num; + const std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id; + const 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(); + const operation op = tx.operations[swwo_op_idx]; + const 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); + const price asset_price = database.get(t_op.amount.asset_id).options.core_exchange_rate; + const 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) && @@ -356,8 +341,8 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) } } - object_id_type object_id = op_obj_idx_1.get().object_id; - std::string op_tx_str = op_obj_idx_1.get().transaction; + const object_id_type object_id = op_obj_idx_1.get().object_id; + const std::string op_tx_str = op_obj_idx_1.get().transaction; const auto &st_idx = database.get_index_type().indices().get(); const auto st = st_idx.find(object_id); @@ -384,9 +369,9 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) 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 son_id_type signer = op_obj_idx_0.get().signer; + const std::string signature = op_obj_idx_0.get().signature; + const 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()) { @@ -497,6 +482,11 @@ void sidechain_net_handler_ethereum::process_sidechain_addresses() { } bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_object &swdo) { + + if (proposal_exists(chain::operation::tag::value, swdo.id)) { + return false; + } + const chain::global_property_object &gpo = database.get_global_properties(); price asset_price = database.get(database.get_global_properties().parameters.eth_asset()).options.core_exchange_rate; From 674b38910d785d33a3eb233524360df799a70e68 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Wed, 28 Dec 2022 08:23:29 +0100 Subject: [PATCH 11/12] Streamline get_block API from database and cli wallet --- libraries/app/database_api.cpp | 33 ++++++++++++++++--- .../app/include/graphene/app/database_api.hpp | 19 +++++++++++ .../wallet/include/graphene/wallet/wallet.hpp | 22 ++++--------- libraries/wallet/wallet.cpp | 22 ++++--------- 4 files changed, 60 insertions(+), 36 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index e22e1dc4..ef48a88d 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -71,6 +71,17 @@ std::string object_id_to_string(object_id_type id) { return object_id; } +signed_block_with_info::signed_block_with_info(){}; + +signed_block_with_info::signed_block_with_info(const signed_block &block) : + signed_block(block) { + block_id = id(); + signing_key = signee(); + transaction_ids.reserve(transactions.size()); + for (const processed_transaction &tx : transactions) + transaction_ids.push_back(tx.id()); +} + class database_api_impl : public std::enable_shared_from_this { public: database_api_impl(graphene::chain::database &db); @@ -89,6 +100,7 @@ public: optional get_block_header(uint32_t block_num) const; map> get_block_header_batch(const vector block_nums) const; optional get_block(uint32_t block_num) const; + optional get_block2(uint32_t block_num) const; vector> get_blocks(uint32_t block_num_from, uint32_t block_num_to) const; processed_transaction get_transaction(uint32_t block_num, uint32_t trx_in_block) const; @@ -532,6 +544,17 @@ optional database_api_impl::get_block(uint32_t block_num) const { return _db.fetch_block_by_number(block_num); } +optional database_api::get_block2(uint32_t block_num) const { + return my->get_block2(block_num); +} + +optional database_api_impl::get_block2(uint32_t block_num) const { + auto result = _db.fetch_block_by_number(block_num); + if (result) + return signed_block_with_info(*result); + return {}; +} + vector> database_api::get_blocks(uint32_t block_num_from, uint32_t block_num_to) const { return my->get_blocks(block_num_from, block_num_to); } @@ -3135,10 +3158,10 @@ vector database_api_impl::nft_get_tokens_by_owner(const account_id_t vector result; result.reserve(limit); auto itr = std::find_if(idx_nft_range.first, idx_nft_range.second, [&lower_id](const nft_object &obj) { - return !(obj.id.instance() < lower_id.instance); - }); + return !(obj.id.instance() < lower_id.instance); + }); while (limit-- && itr != idx_nft_range.second) - result.emplace_back(*itr++); + result.emplace_back(*itr++); return result; } @@ -3155,8 +3178,8 @@ vector database_api_impl::nft_get_metadata_by_owner(const a vector result; result.reserve(limit); auto itr = std::find_if(idx_nft_range.first, idx_nft_range.second, [&lower_id](const nft_metadata_object &obj) { - return !(obj.id.instance() < lower_id.instance); - }); + return !(obj.id.instance() < lower_id.instance); + }); while (limit-- && itr != idx_nft_range.second) result.emplace_back(*itr++); return result; diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 55da8e5f..948b6d55 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -82,6 +82,15 @@ using namespace std; class database_api_impl; +struct signed_block_with_info : public signed_block { + signed_block_with_info(); + signed_block_with_info(const signed_block &block); + signed_block_with_info(const signed_block_with_info &block) = default; + block_id_type block_id; + public_key_type signing_key; + vector transaction_ids; +}; + struct order { double price; double quote; @@ -202,6 +211,13 @@ public: */ optional get_block(uint32_t block_num) const; + /** + * @brief Retrieve a full, signed block, with some extra info + * @param block_num Height of the block to be returned + * @return the referenced block, or null if no matching block was found + */ + optional get_block2(uint32_t block_num) const; + /** * @brief Retrieve a list of signed blocks * @param block_num_from start @@ -1075,6 +1091,8 @@ extern template class fc::api; // clang-format off +FC_REFLECT_DERIVED(graphene::app::signed_block_with_info, (graphene::chain::signed_block), (block_id)(signing_key)(transaction_ids)); + FC_REFLECT(graphene::app::order, (price)(quote)(base)); FC_REFLECT(graphene::app::order_book, (base)(quote)(bids)(asks)); FC_REFLECT(graphene::app::market_ticker, (base)(quote)(latest)(lowest_ask)(highest_bid)(percent_change)(base_volume)(quote_volume)); @@ -1097,6 +1115,7 @@ FC_API(graphene::app::database_api, (get_block_header) (get_block_header_batch) (get_block) + (get_block2) (get_blocks) (get_transaction) (get_recent_transaction_by_id) diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 3d8d5b06..6d97f647 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -191,17 +191,6 @@ struct worker_vote_delta flat_set vote_abstain; }; -struct signed_block_with_info : public signed_block -{ - signed_block_with_info(); - signed_block_with_info( const signed_block& block ); - signed_block_with_info( const signed_block_with_info& block ) = default; - - block_id_type block_id; - public_key_type signing_key; - vector< transaction_id_type > transaction_ids; -}; - struct vesting_balance_object_with_info : public vesting_balance_object { vesting_balance_object_with_info(); @@ -276,7 +265,12 @@ class wallet_api * @param num height of the block to retrieve * @returns info about the block, or null if not found */ - optional get_block( uint32_t num ); + optional get_block( uint32_t num ); + /** Returns info about a specified block, with some extra info. + * @param num height of the block to retrieve + * @returns info about the block, or null if not found + */ + optional get_block2( uint32_t num ); /** Get signed blocks * @param block_num_from The lowest block number * @param block_num_to The highest block number @@ -2762,9 +2756,6 @@ FC_REFLECT( graphene::wallet::worker_vote_delta, (vote_abstain) ) -FC_REFLECT_DERIVED( graphene::wallet::signed_block_with_info, (graphene::chain::signed_block), - (block_id)(signing_key)(transaction_ids) ) - FC_REFLECT_DERIVED( graphene::wallet::vesting_balance_object_with_info, (graphene::chain::vesting_balance_object), (allowed_withdraw)(allowed_withdraw_time) ) @@ -2882,6 +2873,7 @@ FC_API( graphene::wallet::wallet_api, (get_account) (get_account_id) (get_block) + (get_block2) (get_blocks) (get_account_count) (get_account_history) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 237815c1..794e8692 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -4549,11 +4549,16 @@ bool wallet_api::copy_wallet_file(string destination_filename) return my->copy_wallet_file(destination_filename); } -optional wallet_api::get_block(uint32_t num) +optional wallet_api::get_block(uint32_t num) { return my->_remote_db->get_block(num); } +optional wallet_api::get_block2(uint32_t num) +{ + return my->_remote_db->get_block2(num); +} + vector> wallet_api::get_blocks(uint32_t block_num_from, uint32_t block_num_to) const { return my->_remote_db->get_blocks(block_num_from, block_num_to); @@ -7289,10 +7294,6 @@ vector wallet_api::get_account_roles_by_owner(string owner_ account_object owner_account = my->get_account(owner_account_id_or_name); return my->_remote_db->get_account_roles_by_owner(owner_account.id); } -// default ctor necessary for FC_REFLECT -signed_block_with_info::signed_block_with_info() -{ -} order_book wallet_api::get_order_book( const string& base, const string& quote, unsigned limit ) { @@ -7359,17 +7360,6 @@ 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 ) -{ - block_id = id(); - signing_key = signee(); - transaction_ids.reserve( transactions.size() ); - for( const processed_transaction& tx : transactions ) - transaction_ids.push_back( tx.id() ); -} - vesting_balance_object_with_info::vesting_balance_object_with_info() : vesting_balance_object() { From 68fbd6f40bb012bc2c7ceab496f92d7467caa350 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Wed, 28 Dec 2022 07:44:29 +0000 Subject: [PATCH 12/12] #496 process primary wallet --- libraries/chain/db_getter.cpp | 13 +++--- libraries/chain/db_maint.cpp | 5 ++- libraries/chain/son_evaluator.cpp | 5 ++- .../peerplays_sidechain_plugin.cpp | 44 ++++++++++++------- 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index 1b61ee79..4dc72649 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -236,8 +236,10 @@ 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_active_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time())) { - need_to_be_deregistered = false; + if(stats.last_active_timestamp.contains(sidechain)) { + 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,9 +313,10 @@ bool database::is_son_dereg_valid( son_id_type son_id ) if(status_son_dereg_valid) { - 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; + if(son->statistics(*this).last_active_timestamp.contains(sidechain)) { + 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/db_maint.cpp b/libraries/chain/db_maint.cpp index 8673362d..f7b30caf 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -310,7 +310,10 @@ void database::update_son_metrics(const flat_mapstatuses.at(sidechain) == son_status::in_maintenance) { db().modify(itr->statistics(db()), [&](son_statistics_object &sso) { - sso.current_interval_downtime[sidechain] += op.ts.sec_since_epoch() - sso.last_down_timestamp.at(sidechain).sec_since_epoch(); + sso.current_interval_downtime[sidechain] += op.ts.sec_since_epoch() - (sso.last_down_timestamp.contains(sidechain) ? sso.last_down_timestamp.at(sidechain).sec_since_epoch() : op.ts.sec_since_epoch()); sso.last_active_timestamp[sidechain] = op.ts; }); @@ -245,7 +245,8 @@ void_result son_report_down_evaluator::do_evaluate(const son_report_down_operati } FC_ASSERT(status_need_to_report_down, "Inactive/Deregistered/in_maintenance SONs cannot be reported on as down"); for(const auto& active_sidechain_type : active_sidechain_types) { - FC_ASSERT(op.down_ts >= stats.last_active_timestamp.at(active_sidechain_type), "sidechain = ${sidechain} down_ts should be greater than last_active_timestamp", ("sidechain", active_sidechain_type)); + if(stats.last_active_timestamp.contains(active_sidechain_type)) + FC_ASSERT(op.down_ts >= stats.last_active_timestamp.at(active_sidechain_type), "sidechain = ${sidechain} down_ts should be greater than last_active_timestamp", ("sidechain", active_sidechain_type)); } return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index c8da6ce6..541b8537 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -398,14 +398,14 @@ bool peerplays_sidechain_plugin_impl::is_son_down_op_valid(const chain::operatio const chain::global_property_object &gpo = d.get_global_properties(); const chain::dynamic_global_property_object &dgpo = d.get_dynamic_global_properties(); const auto &idx = d.get_index_type().indices().get(); - son_report_down_operation down_op = op.get(); - auto son_obj = idx.find(down_op.son_id); + const son_report_down_operation down_op = op.get(); + const auto son_obj = idx.find(down_op.son_id); if (son_obj == idx.end()) { return false; } - auto stats = son_obj->statistics(d); - fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval; - int64_t down_threshold = gpo.parameters.son_down_time(); + const auto stats = son_obj->statistics(d); + const fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval; + const int64_t down_threshold = gpo.parameters.son_down_time(); bool status_son_down_op_valid = true; for (const auto &status : son_obj->statuses) { @@ -414,9 +414,11 @@ bool peerplays_sidechain_plugin_impl::is_son_down_op_valid(const chain::operatio } if (status_son_down_op_valid) { for (const auto &active_sidechain_type : active_sidechain_types) { - fc::time_point_sec last_active_ts = ((stats.last_active_timestamp.at(active_sidechain_type) > last_maintenance_time) ? stats.last_active_timestamp.at(active_sidechain_type) : last_maintenance_time); - if (((fc::time_point::now() - last_active_ts) <= fc::seconds(down_threshold))) { - status_son_down_op_valid = false; + if (stats.last_active_timestamp.contains(active_sidechain_type)) { + const fc::time_point_sec last_active_ts = ((stats.last_active_timestamp.at(active_sidechain_type) > last_maintenance_time) ? stats.last_active_timestamp.at(active_sidechain_type) : last_maintenance_time); + if (((fc::time_point::now() - last_active_ts) <= fc::seconds(down_threshold))) { + status_son_down_op_valid = false; + } } } } @@ -705,7 +707,7 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals(sidechain_type s proposal_create_operation proposal_op; proposal_op.fee_paying_account = get_current_son_object(sidechain).son_account; proposal_op.proposed_ops.emplace_back(op_wrapper(son_down_op)); - uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + const uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(d.head_block_time().sec_since_epoch() + lifetime); return proposal_op; }; @@ -714,19 +716,27 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals(sidechain_type s const chain::global_property_object &gpo = d.get_global_properties(); const chain::dynamic_global_property_object &dgpo = d.get_dynamic_global_properties(); const auto &idx = d.get_index_type().indices().get(); - std::set sons_being_reported_down = d.get_sons_being_reported_down(); - chain::son_id_type my_son_id = get_current_son_id(sidechain); + const std::set sons_being_reported_down = d.get_sons_being_reported_down(); + const chain::son_id_type my_son_id = get_current_son_id(sidechain); //! Fixme - check this part of the code for (auto son_inf : gpo.active_sons.at(sidechain)) { if (my_son_id == son_inf.son_id || (sons_being_reported_down.find(son_inf.son_id) != sons_being_reported_down.end())) { continue; } - auto son_obj = idx.find(son_inf.son_id); - auto stats = son_obj->statistics(d); - fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval; - fc::time_point_sec last_active_ts = ((stats.last_active_timestamp.at(sidechain) > last_maintenance_time) ? stats.last_active_timestamp.at(sidechain) : last_maintenance_time); - int64_t down_threshold = gpo.parameters.son_down_time(); + + const auto son_obj = idx.find(son_inf.son_id); + const auto stats = son_obj->statistics(d); + const fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval; + const fc::time_point_sec last_active_ts = [&stats, &sidechain, &last_maintenance_time] { + fc::time_point_sec last_active_ts; + if (stats.last_active_timestamp.contains(sidechain)) { + last_active_ts = (stats.last_active_timestamp.at(sidechain) > last_maintenance_time) ? stats.last_active_timestamp.at(sidechain) : last_maintenance_time; + } else + last_active_ts = last_maintenance_time; + return last_active_ts; + }(); + const int64_t down_threshold = gpo.parameters.son_down_time(); bool status_son_down_valid = true; for (const auto &status : son_obj->statuses) { @@ -756,7 +766,7 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals(sidechain_type s } void peerplays_sidechain_plugin_impl::create_son_deregister_proposals(sidechain_type sidechain) { - const std::lock_guard lck{access_son_down_prop_mutex}; + const std::lock_guard lck{access_son_deregister_prop_mutex}; chain::database &d = plugin.database(); std::set sons_to_be_dereg = d.get_sons_to_be_deregistered(); chain::son_id_type my_son_id = get_current_son_id(sidechain);