diff --git a/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp new file mode 100644 index 00000000..2ebf3380 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/ethereum/decoders.cpp @@ -0,0 +1,5 @@ +#include #include < graphene / peerplays_sidechain / ethereum / decoders.hpp> + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +}}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp new file mode 100644 index 00000000..e2db7e9f --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/ethereum/encoders.cpp @@ -0,0 +1,5 @@ +#include #include < graphene / peerplays_sidechain / ethereum / encoders.hpp> + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +}}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index f952dadd..9bf3bf02 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -1,57 +1,22 @@ #include -#include - -#include -#include - namespace graphene { namespace peerplays_sidechain { namespace ethereum { -digest_type transaction::digest() const { - digest_type::encoder enc; - fc::raw::pack(enc, *this); - return enc.result(); +std::string transaction::sign(std::string private_key) { + v = "signed"; + r = "transaction"; + s = "signed-transaction"; + return v + "|" + r + "|" + s; } -transaction_id_type transaction::id() const { - auto h = digest(); - transaction_id_type result; - memcpy(result._hash, h._hash, std::min(sizeof(result), sizeof(h))); - return result; +std::string transaction::serialize() { + return "serialized-transaction"; } -digest_type transaction::sig_digest(const chain_id_type &chain_id) const { - digest_type::encoder enc; - fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, *this); - return enc.result(); -} - -void transaction::set_expiration(fc::time_point_sec expiration_time) { - expiration = expiration_time; -} - -void transaction::set_reference_block(const block_id_type &reference_block) { - ref_block_num = fc::endian_reverse_u32(reference_block._hash[0]); - ref_block_prefix = reference_block._hash[1]; -} - -void signed_transaction::clear() { - operations.clear(); - signatures.clear(); -} - -const signature_type &signed_transaction::sign(const ethereum::private_key_type &key, const ethereum::chain_id_type &chain_id) { - digest_type h = sig_digest(chain_id); - signatures.push_back(key.sign_compact(h, true)); - return signatures.back(); -} - -signature_type signed_transaction::sign(const ethereum::private_key_type &key, const ethereum::chain_id_type &chain_id) const { - digest_type::encoder enc; - fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, *this); - return key.sign_compact(enc.result(), true); +void transaction::deserialize(std::string raw_tx) { + block_hash = "1"; + block_number = "2"; + hash = "3"; } }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/ethereum/types.cpp b/libraries/plugins/peerplays_sidechain/ethereum/types.cpp index 7a62cc58..f85d0e61 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/types.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/types.cpp @@ -1,73 +1,5 @@ #include -#include -#include -#include -#include - namespace graphene { namespace peerplays_sidechain { namespace ethereum { -std::string public_key_type::prefix = KEY_PREFIX_STM; - -public_key_type::public_key_type() : - key_data(){}; - -public_key_type::public_key_type(const fc::ecc::public_key_data &data) : - key_data(data){}; - -public_key_type::public_key_type(const fc::ecc::public_key &pubkey) : - key_data(pubkey){}; - -public_key_type::public_key_type(const std::string &base58str) { - const size_t prefix_len = prefix.size(); - FC_ASSERT(base58str.size() > prefix_len); - FC_ASSERT(base58str.substr(0, prefix_len) == prefix, "", ("base58str", base58str)); - auto bin = fc::from_base58(base58str.substr(prefix_len)); - auto bin_key = fc::raw::unpack(bin); - key_data = bin_key.data; - FC_ASSERT(fc::ripemd160::hash(key_data.data, key_data.size())._hash[0] == bin_key.check); -}; - -public_key_type::operator fc::ecc::public_key_data() const { - return key_data; -}; - -public_key_type::operator fc::ecc::public_key() const { - return fc::ecc::public_key(key_data); -}; - -public_key_type::operator std::string() const { - binary_key k; - k.data = key_data; - k.check = fc::ripemd160::hash(k.data.data, k.data.size())._hash[0]; - auto data = fc::raw::pack(k); - return prefix + fc::to_base58(data.data(), data.size()); -} - -bool operator==(const public_key_type &p1, const fc::ecc::public_key &p2) { - return p1.key_data == p2.serialize(); -} - -bool operator==(const public_key_type &p1, const public_key_type &p2) { - return p1.key_data == p2.key_data; -} - -bool operator!=(const public_key_type &p1, const public_key_type &p2) { - return p1.key_data != p2.key_data; -} - }}} // namespace graphene::peerplays_sidechain::ethereum - -namespace fc { - -using namespace std; - -void to_variant(const graphene::peerplays_sidechain::ethereum::public_key_type &var, fc::variant &vo, uint32_t max_depth) { - vo = std::string(var); -} - -void from_variant(const fc::variant &var, graphene::peerplays_sidechain::ethereum::public_key_type &vo, uint32_t max_depth) { - vo = graphene::peerplays_sidechain::ethereum::public_key_type(var.as_string()); -} - -} // namespace fc diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/asset.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/asset.hpp deleted file mode 100644 index 05aed34f..00000000 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/asset.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -namespace graphene { namespace peerplays_sidechain { namespace ethereum { - -#define HBD_NAI "@@000000013" -#define HBD_PRECISION 3 -#define HBD_SYMBOL_U64 (uint64_t('S') | (uint64_t('B') << 8) | (uint64_t('D') << 16)) -#define HBD_SYMBOL_SER (uint64_t(3) | (HBD_SYMBOL_U64 << 8)) - -#define HIVE_NAI "@@000000021" -#define HIVE_PRECISION 3 -#define HIVE_SYMBOL_U64 (uint64_t('S') | (uint64_t('T') << 8) | (uint64_t('E') << 16) | (uint64_t('E') << 24) | (uint64_t('M') << 32)) -#define HIVE_SYMBOL_SER (uint64_t(3) | (HIVE_SYMBOL_U64 << 8)) - -#define TBD_NAI "@@000000013" -#define TBD_PRECISION 3 -#define TBD_SYMBOL_U64 (uint64_t('T') | (uint64_t('B') << 8) | (uint64_t('D') << 16)) -#define TBD_SYMBOL_SER (uint64_t(3) | (TBD_SYMBOL_U64 << 8)) - -#define TESTS_NAI "@@000000021" -#define TESTS_PRECISION 3 -#define TESTS_SYMBOL_U64 (uint64_t('T') | (uint64_t('E') << 8) | (uint64_t('S') << 16) | (uint64_t('T') << 24) | (uint64_t('S') << 32)) -#define TESTS_SYMBOL_SER (uint64_t(3) | (TESTS_SYMBOL_U64 << 8)) - -struct asset { - static uint64_t hbd_symbol_ser; - static uint64_t ethereum_symbol_ser; - share_type amount; - uint64_t symbol; -}; - -}}} // namespace graphene::peerplays_sidechain::ethereum - -namespace fc { -void to_variant(const graphene::peerplays_sidechain::ethereum::asset &var, fc::variant &vo, uint32_t max_depth); -void from_variant(const fc::variant &var, graphene::peerplays_sidechain::ethereum::asset &vo, uint32_t max_depth); -} // namespace fc - -FC_REFLECT(graphene::peerplays_sidechain::ethereum::asset, (amount)(symbol)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/authority.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/authority.hpp deleted file mode 100644 index d4d5455f..00000000 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/authority.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -#include - -#include - -namespace graphene { namespace peerplays_sidechain { namespace ethereum { - -struct authority { - authority() { - } - - enum classification { - owner = 0, - active = 1, - key = 2, - posting = 3 - }; - - uint32_t weight_threshold = 0; - fc::flat_map account_auths; - fc::flat_map key_auths; -}; - -}}} // namespace graphene::peerplays_sidechain::ethereum - -FC_REFLECT_ENUM(graphene::peerplays_sidechain::ethereum::authority::classification, - (owner)(active)(key)(posting)) - -FC_REFLECT(graphene::peerplays_sidechain::ethereum::authority, - (weight_threshold)(account_auths)(key_auths)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/decoders.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/decoders.hpp new file mode 100644 index 00000000..964ee4a9 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/decoders.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +}}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp new file mode 100644 index 00000000..8db8d59f --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/encoders.hpp @@ -0,0 +1,36 @@ +#pragma once + +namespace graphene { namespace peerplays_sidechain { namespace ethereum { + +class ethereum_function_call_encoder { +public: + enum operation_t { + OPERATION_CALL, + OPERATION_DELEGATE_CALL + }; + + static constexpr const char *const default_prev_addr = "0000000000000000000000000000000000000001"; + + std::string encode_function_signature(const std::string &function_signature); + std::string encode_address(const std::string &addr); + std::string encode_uint256(const std::string &value); + std::string encode_uint8(uint8_t value); + std::string encode_bytes(const std::string &values); +}; + +class safe_transaction_encoder { +public: + static constexpr const char *const default_safe_tx_gas = "0"; + static constexpr const char *const default_data_gas = "0"; + static constexpr const char *const default_gas_price = "0"; + static constexpr const char *const default_gas_token = "0000000000000000000000000000000000000000"; + static constexpr const char *const default_refund_receiver = "0000000000000000000000000000000000000000"; + + std::string create_safe_address(const std::vector &owner_addresses, uint32_t threshold); + std::string build_transaction(const std::string &safe_account_addr, const std::string &value, const std::string &data, uint8_t operation, const std::string &safeTxGas, const std::string &dataGas, const std::string &gasPrice, const std::string &gasToken, const std::string &refundReceiver); + +private: + ethereum_function_call_encoder m_ethereum_function_call_encoder; +}; + +}}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/ethereum_operations.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/ethereum_operations.hpp deleted file mode 100644 index 4b8a7399..00000000 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/ethereum_operations.hpp +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include -#include -#include -#include - -namespace graphene { namespace peerplays_sidechain { namespace ethereum { - -struct vote_operation {}; -struct comment_operation {}; - -struct transfer_operation { - ethereum::account_name_type from; - ethereum::account_name_type to; - ethereum::asset amount; - std::string memo; -}; - -struct transfer_to_vesting_operation {}; -struct withdraw_vesting_operation {}; -struct limit_order_create_operation {}; -struct limit_order_cancel_operation {}; -struct feed_publish_operation {}; -struct convert_operation {}; -struct account_create_operation {}; - -struct account_update_operation { - ethereum::account_name_type account; - fc::optional owner; - fc::optional active; - fc::optional posting; - ethereum::public_key_type memo_key; - std::string json_metadata; -}; - -struct witness_update_operation {}; -struct account_witness_vote_operation {}; -struct account_witness_proxy_operation {}; -struct pow_operation {}; -struct custom_operation {}; -struct report_over_production_operation {}; -struct delete_comment_operation {}; -struct custom_json_operation {}; -struct comment_options_operation {}; -struct set_withdraw_vesting_route_operation {}; -struct limit_order_create2_operation {}; -struct claim_account_operation {}; -struct create_claimed_account_operation {}; -struct request_account_recovery_operation {}; -struct recover_account_operation {}; -struct change_recovery_account_operation {}; -struct escrow_transfer_operation {}; -struct escrow_dispute_operation {}; -struct escrow_release_operation {}; -struct pow2_operation {}; -struct escrow_approve_operation {}; -struct transfer_to_savings_operation {}; -struct transfer_from_savings_operation {}; -struct cancel_transfer_from_savings_operation {}; -struct custom_binary_operation {}; -struct decline_voting_rights_operation {}; -struct reset_account_operation {}; -struct set_reset_account_operation {}; -struct claim_reward_balance_operation {}; - -struct delegate_vesting_shares_operation { - ethereum::account_name_type delegator; - ethereum::account_name_type delegatee; - ethereum::asset vesting_shares; -}; - -}}} // namespace graphene::peerplays_sidechain::ethereum - -FC_REFLECT(graphene::peerplays_sidechain::ethereum::vote_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::comment_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::transfer_operation, - (from)(to)(amount)(memo)) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::transfer_to_vesting_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::withdraw_vesting_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::limit_order_create_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::limit_order_cancel_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::feed_publish_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::convert_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::account_create_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::account_update_operation, - (account)(owner)(active)(posting)(memo_key)(json_metadata)) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::witness_update_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::account_witness_vote_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::account_witness_proxy_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::pow_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::custom_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::report_over_production_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::delete_comment_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::custom_json_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::comment_options_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::set_withdraw_vesting_route_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::limit_order_create2_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::claim_account_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::create_claimed_account_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::request_account_recovery_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::recover_account_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::change_recovery_account_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::escrow_transfer_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::escrow_dispute_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::escrow_release_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::pow2_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::escrow_approve_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::transfer_to_savings_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::transfer_from_savings_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::cancel_transfer_from_savings_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::custom_binary_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::decline_voting_rights_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::reset_account_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::set_reset_account_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::claim_reward_balance_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::delegate_vesting_shares_operation, - (delegator)(delegatee)(vesting_shares)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp deleted file mode 100644 index e178b56d..00000000 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/operations.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include - -namespace graphene { namespace peerplays_sidechain { namespace ethereum { - -typedef fc::static_variant< - vote_operation, - comment_operation, - - transfer_operation, - transfer_to_vesting_operation, - withdraw_vesting_operation, - - limit_order_create_operation, - limit_order_cancel_operation, - - feed_publish_operation, - convert_operation, - - account_create_operation, - account_update_operation, - - witness_update_operation, - account_witness_vote_operation, - account_witness_proxy_operation, - - pow_operation, - - custom_operation, - - report_over_production_operation, - - delete_comment_operation, - custom_json_operation, - comment_options_operation, - set_withdraw_vesting_route_operation, - limit_order_create2_operation, - claim_account_operation, - create_claimed_account_operation, - request_account_recovery_operation, - recover_account_operation, - change_recovery_account_operation, - escrow_transfer_operation, - escrow_dispute_operation, - escrow_release_operation, - pow2_operation, - escrow_approve_operation, - transfer_to_savings_operation, - transfer_from_savings_operation, - cancel_transfer_from_savings_operation, - custom_binary_operation, - decline_voting_rights_operation, - reset_account_operation, - set_reset_account_operation, - claim_reward_balance_operation, - delegate_vesting_shares_operation> - ethereum_operation; - -}}} // namespace graphene::peerplays_sidechain::ethereum - -namespace fc { - -void to_variant(const graphene::peerplays_sidechain::ethereum::ethereum_operation &var, fc::variant &vo, uint32_t max_depth = 5); -void from_variant(const fc::variant &var, graphene::peerplays_sidechain::ethereum::ethereum_operation &vo, uint32_t max_depth = 5); - -} // namespace fc - -FC_REFLECT_TYPENAME(graphene::peerplays_sidechain::ethereum::ethereum_operation) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp index ae154a36..1ce9497e 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/transaction.hpp @@ -1,86 +1,123 @@ #pragma once #include +#include #include -#include -#include - -#include -#include -#include - namespace graphene { namespace peerplays_sidechain { namespace ethereum { -typedef fc::ecc::private_key private_key_type; -typedef fc::sha256 chain_id_type; class transaction { public: - uint16_t ref_block_num = 0; - uint32_t ref_block_prefix = 0; - fc::time_point_sec expiration; - std::vector operations; - extensions_type extensions; + std::string block_hash; + std::string block_number; + std::string from; + std::string gas; + std::string gas_price; + std::string max_fee_per_gas; + std::string max_priority_fee_per_gas; + std::string hash; + std::string input; + std::string nonce; + std::string to; + std::string transaction_index; + std::string value; + std::string type; + std::vector access_list; + std::string chain_id; + std::string v; + std::string r; + std::string s; - digest_type digest() const; - transaction_id_type id() const; - digest_type sig_digest(const chain_id_type &chain_id) const; + std::string sign(std::string private_key); - void set_expiration(fc::time_point_sec expiration_time); - void set_reference_block(const block_id_type &reference_block); - - /* - /// Serialises this transaction to an RLPStream. - /// @throws TransactionIsUnsigned if including signature was requested but it was not initialized - void streamRLP(RLPStream& _s, IncludeSignature _sig = WithSignature, bool _forEip155hash = false) const; - - /// @returns the RLP serialisation of this transaction. - bytes rlp(IncludeSignature _sig = WithSignature) const { RLPStream s; streamRLP(s, _sig); return s.out(); } -protected: - /// Type of transaction. - enum Type - { - NullTransaction, ///< Null transaction. - ContractCreation, ///< Transaction to create contracts - receiveAddress() is ignored. - MessageCall ///< Transaction to invoke a message call - receiveAddress() is used. - }; - - static bool isZeroSignature(u256 const& _r, u256 const& _s) { return !_r && !_s; } - - /// Clears the signature. - void clearSignature() { m_vrs = SignatureStruct(); } - - Type m_type = NullTransaction; ///< Is this a contract-creation transaction or a message-call transaction? - u256 m_nonce; ///< The transaction-count of the sender. - u256 m_value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. - Address m_receiveAddress; ///< The receiving address of the transaction. - u256 m_gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. - u256 m_gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. - bytes m_data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. - boost::optional m_vrs; ///< The signature of the transaction. Encodes the sender. - /// EIP155 value for calculating transaction hash - /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md - boost::optional m_chainId; - - mutable h256 m_hashWith; ///< Cached hash of transaction with signature. - mutable boost::optional
m_sender; ///< Cached sender, determined from signature. -*/ -}; - -class signed_transaction : public transaction { -public: - std::vector signatures; - - const signature_type &sign(const ethereum::private_key_type &key, const ethereum::chain_id_type &chain_id); - signature_type sign(const ethereum::private_key_type &key, const ethereum::chain_id_type &chain_id) const; - void clear(); + std::string serialize(); + void deserialize(std::string raw_tx); }; }}} // namespace graphene::peerplays_sidechain::ethereum -FC_REFLECT(graphene::peerplays_sidechain::ethereum::transaction, - (ref_block_num)(ref_block_prefix)(expiration)(operations)(extensions)) +// Example 1 +//{ +// "blockHash": "0x64a6706ecaf5a97b7f3e047abb20ff223ce82c6994d80e68fdb1fdfb38d0209c", +// "blockNumber": "0xe5827c", +// "from": "0x8614c67e085f2334010f2a28e806c6f1cc176d12", +// "gas": "0x38822", +// "gasPrice": "0xce42cba69", +// "maxFeePerGas": "0xddb4d8d16", +// "maxPriorityFeePerGas": "0x3b9aca00", +// "hash": "0xeac92ea09fa8eb3ca2fb0d156cceb38ae69d4345869d41e8e49d5ecbcbb622dc", +// "input": "0x5ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde03121500000000000000000000000000000000000000000000000000000000", +// "nonce": "0x32", +// "to": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45", +// "transactionIndex": "0xb6", +// "value": "0x2514d9d7d7d8000", +// "type": "0x2", +// "accessList": [], +// "chainId": "0x1", +// "v": "0x1", +// "r": "0x2f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28c", +// "s": "0x782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14" +//} +// +//"0xf9021332850ce42cba69830388229468b3465833fb72a70ecdf485e0e4c7bd8665fc458802514d9d7d7d8000b901a45ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde0312150000000000000000000000000000000000000000000000000000000001a02f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28ca0782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14" +// +//{ +// "nonce": 50, +// "gasPrice": { +// "_hex": "0x0ce42cba69" +// }, +// "gasLimit": { +// "_hex": "0x038822" +// }, +// "to": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45", +// "value": { +// "_hex": "0x02514d9d7d7d8000" +// }, +// "data": "0x5ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde03121500000000000000000000000000000000000000000000000000000000", +// "v": 1, +// "r": "0x2f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28c", +// "s": "0x782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14" +//} -FC_REFLECT_DERIVED(graphene::peerplays_sidechain::ethereum::signed_transaction, - (graphene::peerplays_sidechain::ethereum::transaction), - (signatures)) +// Example 2 +//{ +// "blockHash": "0xe2ae3afd86dc7343c7fb753441447a0a51bb19499325ad6e278256f0cd1b5894", +// "blockNumber": "0xe58271", +// "from": "0xb895ade6d337fbb8cb97f2ea7da43106c7f5cc26", +// "gas": "0x5208", +// "gasPrice": "0xe6f3b322e", +// "maxFeePerGas": "0x1322455fd3", +// "maxPriorityFeePerGas": "0x53724e00", +// "hash": "0xed29b56e52ad2d452e25b8ec70c37f59d935cd6d0f8fe8e83b256f3ffdfd3fce", +// "input": "0x", +// "nonce": "0x37", +// "to": "0x176386b6ffc469ac049f9ec1f6cc0efd1d09b373", +// "transactionIndex": "0x8a", +// "value": "0x4563918244f40000", +// "type": "0x2", +// "accessList": [], +// "chainId": "0x1", +// "v": "0x0", +// "r": "0xdcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4c", +// "s": "0x28c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a" +//} +// +//"0xf86c37850e6f3b322e82520894176386b6ffc469ac049f9ec1f6cc0efd1d09b373884563918244f400008000a0dcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4ca028c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a" +// +//{ +// "nonce": 55, +// "gasPrice": { +// "_hex": "0x0e6f3b322e" +// }, +// "gasLimit": { +// "_hex": "0x5208" +// }, +// "to": "0x176386b6ffc469ac049f9ec1f6cc0efd1d09b373", +// "value": { +// "_hex": "0x4563918244f40000" +// }, +// "data": "0x", +// "v": 0, +// "r": "0xdcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4c", +// "s": "0x28c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a" +//} diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp index f8a06c6c..def91947 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/ethereum/types.hpp @@ -1,72 +1,10 @@ #pragma once -#include -#include +#include namespace graphene { namespace peerplays_sidechain { namespace ethereum { -#define KEY_PREFIX_STM "STM" -#define KEY_PREFIX_TST "TST" - -enum network { - mainnet, - testnet -}; - -struct void_t {}; - -typedef fc::static_variant future_extensions; -typedef fc::flat_set extensions_type; - -typedef fc::ecc::private_key private_key_type; -typedef fc::sha256 chain_id_type; -typedef std::string account_name_type; -typedef fc::ripemd160 block_id_type; -//typedef fc::ripemd160 checksum_type; -typedef fc::ripemd160 transaction_id_type; -typedef fc::sha256 digest_type; -typedef fc::ecc::compact_signature signature_type; -typedef fc::safe share_type; -//typedef safe ushare_type; -//typedef uint16_t weight_type; -//typedef uint32_t contribution_id_type; -//typedef fixed_string<32> custom_id_type; - -struct public_key_type { - - static std::string prefix; - - struct binary_key { - binary_key() { - } - uint32_t check = 0; - fc::ecc::public_key_data data; - }; - fc::ecc::public_key_data key_data; - public_key_type(); - public_key_type(const fc::ecc::public_key_data &data); - public_key_type(const fc::ecc::public_key &pubkey); - explicit public_key_type(const std::string &base58str); - operator fc::ecc::public_key_data() const; - operator fc::ecc::public_key() const; - explicit operator std::string() const; - friend bool operator==(const public_key_type &p1, const fc::ecc::public_key &p2); - friend bool operator==(const public_key_type &p1, const public_key_type &p2); - friend bool operator<(const public_key_type &p1, const public_key_type &p2) { - return p1.key_data < p2.key_data; - } - friend bool operator!=(const public_key_type &p1, const public_key_type &p2); -}; +typedef uint64_t chain_id_type; +typedef uint64_t network_id_type; }}} // namespace graphene::peerplays_sidechain::ethereum - -namespace fc { -void to_variant(const graphene::peerplays_sidechain::ethereum::public_key_type &var, fc::variant &vo, uint32_t max_depth = 2); -void from_variant(const fc::variant &var, graphene::peerplays_sidechain::ethereum::public_key_type &vo, uint32_t max_depth = 2); -} // namespace fc - -FC_REFLECT(graphene::peerplays_sidechain::ethereum::public_key_type, (key_data)) -FC_REFLECT(graphene::peerplays_sidechain::ethereum::public_key_type::binary_key, (data)(check)) - -FC_REFLECT(graphene::peerplays_sidechain::ethereum::void_t, ) -FC_REFLECT_TYPENAME(graphene::peerplays_sidechain::ethereum::future_extensions) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp index 3bef8610..d8662d2a 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_ethereum.hpp @@ -3,220 +3,26 @@ #include #include -#include #include -#include - #include - -#include -#include - -#include -#include - -#include - -#include - -using namespace boost::multiprecision::literals; -using u256 = boost::multiprecision::number>; -using s256 = boost::multiprecision::number>; -u256 constexpr Invalid256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_cppui256; -using byte = uint8_t; -using bytes = std::vector; +#include +#include namespace graphene { namespace peerplays_sidechain { -typedef websocketpp::client client; - -using websocketpp::lib::bind; -using websocketpp::lib::placeholders::_1; -using websocketpp::lib::placeholders::_2; - -// pull out the type of messages sent by our config -typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr; -typedef websocketpp::lib::shared_ptr context_ptr; -typedef client::connection_ptr connection_ptr; - -class eth_rpc_client { +class ethereum_node_rpc_client : public rpc_client { public: - typedef eth_rpc_client type; + ethereum_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); - enum req_t { - ETH_CHAIN_ID, - ETH_GET_TRANSACTION_RECEIPT, - ETH_CALL, - ETH_SEND_TRANSACTION, - ETH_SEND_RAW_TRANSACTION, - ETH_GET_CODE, - ETH_GET_BALANCE, - ETH_SIGN, - ETH_COINBASE, - GET_LIST_OWNERS, - ADD_OWNER, - REMOVE_OWNER - }; + std::string admin_node_info(); + std::string net_version(); - enum class multi_type { - script, - address - }; - struct multi_params { - multi_params(multi_type _type, const std::string &_address_or_script, const std::string &_label = "") : - type{_type}, - address_or_script{_address_or_script}, - label{_label} { - } - - multi_type type; - std::string address_or_script; - std::string label; - }; - - eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); - - void start(); - void stop(); - void on_socket_init(websocketpp::connection_hdl); - void on_fail(websocketpp::connection_hdl hdl); - void on_open(websocketpp::connection_hdl hdl); - void on_message(websocketpp::connection_hdl hdl, message_ptr msg); - void on_close(websocketpp::connection_hdl); - - uint64_t get_chain_id(); - uint64_t eth_getTransactionReceipt(const std::string &tx_id); - uint64_t eth_call(const std::string &to, const std::string &data); - uint64_t eth_sendTransaction(const std::string &from, const std::string &to, const std::string &data); - uint64_t eth_sendRawTransaction(const std::string ¶ms); - uint64_t eth_getCode(const std::string &addr); - uint64_t eth_getBalance(const std::string &addr); - uint64_t eth_sign(const string &addr, const string &message); - uint64_t eth_coinbase(); - - uint64_t get_list_owners(const std::string &safe_account); - uint64_t add_owner(const std::string &addr); - uint64_t remove_owner(const std::string &addr, uint32_t threshold); - - std::string addmultisigaddress(const uint32_t nrequired, const std::vector public_keys); - std::string combinepsbt(const vector &psbts); - - uint64_t createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key); - - std::string createpsbt(); - std::string createrawtransaction(); - std::string createwallet(const std::string &wallet_name); - std::string decodepsbt(std::string const &tx_psbt); - std::string decoderawtransaction(std::string const &tx_hex); - std::string encryptwallet(const std::string &passphrase); - uint64_t estimatesmartfee(uint16_t conf_target = 128); - std::string finalizepsbt(std::string const &tx_psbt); - std::string getaddressinfo(const std::string &address); - std::string getblock(const std::string &block_hash, int32_t verbosity = 2); - std::string getrawtransaction(const std::string &txid, const bool verbose = false); - std::string getnetworkinfo(); - std::string gettransaction(const std::string &txid, const bool include_watch_only = false); - std::string getblockchaininfo(); - void importaddress(const std::string &address_or_script, const std::string &label = "", const bool rescan = true, const bool p2sh = false); - void importmulti(const std::vector &address_or_script_array, const bool rescan = true); - std::string loadwallet(const std::string &filename); - std::string sendrawtransaction(const std::string &tx_hex); - std::string signrawtransactionwithwallet(const std::string &tx_hash); - std::string unloadwallet(const std::string &filename); - std::string walletlock(); - std::string walletprocesspsbt(std::string const &tx_psbt); - bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); - - std::string chain_id; //256 bit value - std::vector owners; - std::string safe_account_addr; - -private: - /// Encodes an Ethereum transaction for exporting in JSON - class Transaction { - public: - /// JSON serialization - std::string serialize(const std::string &from, const std::string &to, const std::string &tx_id, u256 const &_value, u256 const &_gasPrice, u256 const &_gas, bytes const &_data, u256 const &_nonce = Invalid256); - - protected: - /// Type of transaction. - enum Type { - NullTransaction, ///< Null transaction. - ContractCreation, ///< Transaction to create contracts - receiveAddress() is ignored. - MessageCall ///< Transaction to invoke a message call - receiveAddress() is used. - }; - - Type m_type = NullTransaction; ///< Is this a contract-creation transaction or a message-call transaction? - u256 m_nonce; ///< The transaction-count of the sender. - u256 m_value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. - u256 m_gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. - u256 m_gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. - bytes m_data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. - }; - - class ethereum_function_call_encoder { - public: - enum operation_t { - OPERATION_CALL, - OPERATION_DELEGATE_CALL - }; - - static constexpr const char *const default_prev_addr = "0000000000000000000000000000000000000001"; - - std::string encode_function_signature(const std::string &function_signature); - std::string encode_address(const std::string &addr); - std::string encode_uint256(const std::string &value); - std::string encode_uint8(uint8_t value); - std::string encode_bytes(const std::string &values); - }; - - class safe_transaction_encoder { - public: - static constexpr const char *const default_safe_tx_gas = "0"; - static constexpr const char *const default_data_gas = "0"; - static constexpr const char *const default_gas_price = "0"; - static constexpr const char *const default_gas_token = "0000000000000000000000000000000000000000"; - static constexpr const char *const default_refund_receiver = "0000000000000000000000000000000000000000"; - - std::string create_safe_address(const std::vector &owner_addresses, uint32_t threshold); - std::string build_transaction(const std::string &safe_account_addr, const std::string &value, const std::string &data, uint8_t operation, const std::string &safeTxGas, const std::string &dataGas, const std::string &gasPrice, const std::string &gasToken, const std::string &refundReceiver); - - private: - ethereum_function_call_encoder m_ethereum_function_call_encoder; - }; - - ethereum_function_call_encoder m_ethereum_function_call_encoder; - safe_transaction_encoder m_safe_transaction_encoder; - - std::shared_ptr _thread; - std::string signature; - std::string geth_url; - uint64_t t_id; - std::string account_address; - std::string transaction_id; - uint32_t threshold; - std::unordered_map m_requests; - std::string balance; - std::string code; - - std::string ip; - uint32_t rpc_port; - std::string user; - std::string password; - std::string wallet; - std::string wallet_password; - bool debug_rpc_calls; - - fc::http::header authorization; - - client m_endpoint; - websocketpp::connection_hdl m_hdl; + std::string get_chain_id(); + std::string get_network_id(); }; -// ============================================================================= - class sidechain_net_handler_ethereum : public sidechain_net_handler { public: sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options); @@ -232,20 +38,13 @@ public: bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); private: - std::string url; - uint32_t rpc_port; + std::string node_rpc_url; + std::string node_rpc_user; + std::string node_rpc_password; + ethereum_node_rpc_client *node_rpc_client; - std::string rpc_user; - std::string rpc_password; - std::string wallet; - std::string wallet_password; - - std::unique_ptr eth_client; - - fc::future on_changed_objects_task; - - std::mutex event_handler_mutex; - typedef std::lock_guard scoped_lock; + ethereum::chain_id_type chain_id; + ethereum::network_id_type network_id; std::string create_primary_wallet_address(const std::vector &son_pubkeys); @@ -253,17 +52,15 @@ private: std::string create_deposit_transaction(const son_wallet_deposit_object &swdo); std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo); - std::string create_transaction(); std::string sign_transaction(const sidechain_transaction_object &sto); std::string send_transaction(const sidechain_transaction_object &sto); + uint64_t last_block_received; + fc::future _listener_task; + boost::signals2::signal event_received; + void schedule_ethereum_listener(); + void ethereum_listener_loop(); void handle_event(const std::string &event_data); - std::vector extract_info_from_block(const std::string &_block); - void on_changed_objects(const vector &ids, const flat_set &accounts); - void on_changed_objects_cb(const vector &ids, const flat_set &accounts); - - std::vector parse_hex(const std::string &str); - fc::ecc::public_key_data create_public_key_data(const std::vector &public_key); }; }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index aa63055a..0e422961 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -157,8 +157,12 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("bitcoin-private-key", bpo::value>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")), "Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)"); - cli.add_options()("ethereum-sidechain-enabled", bpo::value()->default_value(true), "Hive sidechain handler enabled"); - cli.add_options()("ethereum-node-rpc-url", bpo::value()->default_value("ws://127.0.0.1:8546/"), "Ethereum node RPC WS URL [ws[s]://]host[:port]"); + cli.add_options()("ethereum-sidechain-enabled", bpo::value()->default_value(false), "Ethereum sidechain handler enabled"); + cli.add_options()("ethereum-node-rpc-url", bpo::value()->default_value("127.0.0.1:8545"), "Ethereum node RPC URL [http[s]://]host[:port]"); + cli.add_options()("ethereum-node-rpc-user", bpo::value()->default_value("1"), "Ethereum RPC user"); + cli.add_options()("ethereum-node-rpc-password", bpo::value()->default_value("1"), "Ethereum RPC password"); + cli.add_options()("ethereum-private-key", bpo::value>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", "9bedac2bd8fe2a6f6528e066c67fc8ac0622e96828d40c0e820d83c5bd2b0589")), + "Tuple of [Ethereum public key, Ethereum private key] (may specify multiple times)"); cli.add_options()("hive-sidechain-enabled", bpo::value()->default_value(false), "Hive sidechain handler enabled"); cli.add_options()("hive-node-rpc-url", bpo::value()->default_value("127.0.0.1:28090"), "Hive node RPC URL [http[s]://]host[:port]"); @@ -221,9 +225,9 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt } sidechain_enabled_ethereum = options.at("ethereum-sidechain-enabled").as(); - config_ready_ethereum = options.count("ethereum-node-rpc-url"); - //options.count("ethereum-address") && - //options.count("ethereum-public-key") && options.count("ethereum-private-key"); + config_ready_ethereum = options.count("ethereum-node-rpc-url") && + /*options.count("ethereum-node-rpc-user") && options.count("ethereum-node-rpc-password") &&*/ + options.count("ethereum-private-key"); if (!config_ready_ethereum) { wlog("Haven't set up Ethereum sidechain parameters"); } @@ -247,7 +251,7 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt } if (!(config_ready_bitcoin && - /*config_ready_ethereum &&*/ + config_ready_ethereum && config_ready_hive && config_ready_peerplays)) { wlog("Haven't set up any sidechain parameters"); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 4feba5ec..6cbd47fc 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -20,479 +20,30 @@ #include #include -#include - -#include -extern "C" { -#include -} - namespace graphene { namespace peerplays_sidechain { -std::string eth_rpc_client::Transaction::serialize(const std::string &from, const std::string &to, const std::string &tx_id, u256 const &_value, u256 const &_gasPrice, u256 const &_gas, bytes const &_data, u256 const &_nonce) { - std::string m_data_str(m_data.begin(), m_data.end()); - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"account_signTransaction\",\"params\":[{\"from\": \"%1%\", \"gas\": \"%2%\", \"gasPrice\": \"%3%\", \"input\": \"%4%\", \"nonce\": \"%5%\", \"to\": \"%6%\", \"value\": \"%7%\" }],\"id\":%8%}") % from.c_str() % m_gas.str() % m_gasPrice.str() % m_data_str % m_nonce.str() % to.c_str() % m_value.str() % tx_id.c_str()); - return req; + +ethereum_node_rpc_client::ethereum_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : + rpc_client(url, user_name, password, debug_rpc_calls) { } -// ============================================================================= -std::string eth_rpc_client::ethereum_function_call_encoder::encode_function_signature(const std::string &function_signature) { - sha3_context c; - char *hash; - - sha3_Init256(static_cast(&c)); - sha3_SetFlags(&c, SHA3_FLAGS_KECCAK); - sha3_Update(&c, "abc", 3); - hash = (char *)sha3_Finalize(&c); - std::string output(hash); - output = output.substr(0, 8); - - return output; -}; - -std::string eth_rpc_client::ethereum_function_call_encoder::encode_address(const std::string &addr) { - FC_ASSERT(40 == addr.length()); - std::string output = str(boost::format("%024u") % 0) + addr; - return output; +std::string ethereum_node_rpc_client::admin_node_info() { + return send_post_request("admin_nodeInfo", "", debug_rpc_calls); } -std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint256(const std::string &value) { - FC_ASSERT(value.length() <= 64); - std::string output = std::string(64 - value.length(), '0') + value; - return output; +std::string ethereum_node_rpc_client::net_version() { + return send_post_request("net_version", "", debug_rpc_calls); } -std::string eth_rpc_client::ethereum_function_call_encoder::encode_uint8(uint8_t value) { - std::string output = str(boost::format("%02X") % value) + std::string(62, '0'); - return output; +std::string ethereum_node_rpc_client::get_chain_id() { + std::string reply_str = net_version(); + return retrieve_value_from_reply(reply_str, "result"); } -std::string eth_rpc_client::ethereum_function_call_encoder::encode_bytes(const std::string &values) { - size_t len = values.length(); - std::string output = encode_uint256((boost::format("%x") % len).str()) + values + std::string(64 - len, '0'); - return output; +std::string ethereum_node_rpc_client::get_network_id() { + std::string reply_str = admin_node_info(); + return retrieve_value_from_reply(reply_str, "result.protocols.eth.network"); } -std::string eth_rpc_client::safe_transaction_encoder::create_safe_address(const std::vector &owner_addresses, uint32_t threshold) { - //createProxyWithNonce(address,bytes,uint256) - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("createProxyWithNonce(address,bytes,uint256)"); - FC_ASSERT("1688f0b9" == method_id); - - std::string data = "0x1688f0b9000000000000000000000000d9db270c1b5e3bd161e8c8503c55ceabee70955200000000000000000000000000000000000000000000000000000000000000604fa262bd05cdef2e3d5261787ee66d9447a4036324990e04380339bec83b4c7a0000000000000000000000000000000000000000000000000000000000000264b63e800d0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000f48f2b2d2a534e402487b3ee7c18c33aec0fe5e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC1200000000000000000000000076ce31BD03f601c3fC13732deF921c5Bac28267600000000000000000000000009EE460834498a4ee361beB819470061B7381B490000000000000000000000006AEFbd09209e1eE2e0a589d31e732F69B77713D2000000000000000000000000631e128b16f9aDCF1bB6385112B1519C917D77a7000000000000000000000000cD5C788e84220E8b8934Ea4F1dC6a12009bCc91D0000000000000000000000003627C1B31525887CB9441130C831e3588765030500000000000000000000000003A13a989AF30C92AD7ABD1E6210308A6c96f3730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; - - return data; -} - -std::string eth_rpc_client::safe_transaction_encoder::build_transaction(const std::string &safe_account_addr, const std::string &value, const std::string &data, uint8_t operation, const std::string &safeTxGas, const std::string &dataGas, const std::string &gasPrice, const std::string &gasToken, const std::string &refundReceiver) { - //execTransaction method of smart contract , using safe-account address - //execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 dataGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); - FC_ASSERT("6a761202" == method_id); - //"" - std::string to = m_ethereum_function_call_encoder.encode_address(safe_account_addr); - // Value in wei - std::string value_encoded = m_ethereum_function_call_encoder.encode_uint256(value); - // 0 CALL, 1 DELEGATE_CALL - std::string operation_encoded = m_ethereum_function_call_encoder.encode_uint8(operation); - // Max gas to use in the transaction - std::string safeTxGas_encoded = m_ethereum_function_call_encoder.encode_uint256(safeTxGas); - // Gas costs not related to the transaction execution (signature check, refund payment...) - std::string dataGas_encoded = m_ethereum_function_call_encoder.encode_uint256(dataGas); - // Gas price used for the refund calculation - std::string gasPrice_encoded = m_ethereum_function_call_encoder.encode_uint256(gasPrice); - //"", Token address (hold by the Safe) to be used as a refund to the sender, if `null` is Ether - std::string gasToken_encoded = m_ethereum_function_call_encoder.encode_address(gasToken); - //"", Address of receiver of gas payment (or `null` if tx.origin) - std::string refundReceiver_encoded = m_ethereum_function_call_encoder.encode_address(refundReceiver); - - std::string message = method_id + to + value_encoded + data + operation_encoded + safeTxGas_encoded + dataGas_encoded + gasPrice_encoded + gasToken_encoded + refundReceiver_encoded; - - return message; -} - -eth_rpc_client::eth_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : - _thread(std::make_shared("eth_rpc_client")) { - geth_url = url; - user = user_name; - this->password = password; - this->debug_rpc_calls = debug_rpc_calls; - t_id = 1; - - ilog("eth_rpc_client"); - ilog("### Geth URL: ${url}", ("url", url)); - - m_endpoint.set_access_channels(websocketpp::log::alevel::none); - m_endpoint.set_error_channels(websocketpp::log::elevel::none); - - // Initialize ASIO - m_endpoint.init_asio(); - - // Register our handlers - m_endpoint.set_socket_init_handler(bind(&type::on_socket_init, this, ::_1)); - m_endpoint.set_message_handler(bind(&type::on_message, this, ::_1, ::_2)); - m_endpoint.set_open_handler(bind(&type::on_open, this, ::_1)); - m_endpoint.set_close_handler(bind(&type::on_close, this, ::_1)); - m_endpoint.set_fail_handler(bind(&type::on_fail, this, ::_1)); -} - -void eth_rpc_client::start() { - ilog("### eth_rpc_client::start uri: ${uri}", ("uri", geth_url)); - auto future = _thread->async([this] { - websocketpp::lib::error_code ec; - client::connection_ptr con = m_endpoint.get_connection(this->geth_url, ec); - m_hdl = con->get_handle(); - - if (ec) { - m_endpoint.get_alog().write(websocketpp::log::alevel::app, ec.message()); - return; - } - - m_endpoint.connect(con); - - // Start the ASIO io_service run loop - m_endpoint.run(); - }); -} - -void eth_rpc_client::stop() { - m_endpoint.close(m_hdl, websocketpp::close::status::normal, ""); -} - -void eth_rpc_client::on_socket_init(websocketpp::connection_hdl) { -} - -void eth_rpc_client::on_fail(websocketpp::connection_hdl hdl) { - client::connection_ptr con = m_endpoint.get_con_from_hdl(hdl); - - elog("Ethereum websocket fail"); - //elog("get_state: ${state}", ("state", con->get_state() ) ); - elog("get_local_close_code: ${code}", ("code", con->get_local_close_code())); - elog("get_local_close_reason: ${close}", ("close", con->get_local_close_reason())); - elog("get_remote_close_code: ${close}", ("close", con->get_remote_close_code())); - elog("get_remote_close_reason: ${close}", ("close", con->get_remote_close_reason())); - elog("get_ec().message(): ${ec}", ("ec", con->get_ec().message())); -} - -void eth_rpc_client::on_open(websocketpp::connection_hdl hdl) { - std::string str = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":84}"; - ilog("on_open: ${str}", ("str", str)); - m_endpoint.send(hdl, str.c_str(), websocketpp::frame::opcode::text); - - vector owner_addresses; - std::string private_key = ""; - createmultisig(5, owner_addresses, private_key); -} - -void eth_rpc_client::on_message(websocketpp::connection_hdl hdl, message_ptr msg) { - - ilog("on_message: ${msg}", ("msg", msg->get_payload())); - - fc::variants list = fc::json::variants_from_string(msg->get_payload()); - - ilog("json reposnse: ${list}", ("list", list)); - - const auto &b_obj = list[0].get_object().find("id"); - - if (true == list[0].get_object().contains("error")) { - elog("error in json reposnse: ${list}", ("list", list)); - return; - } - - std::string result_str = list[0].get_object().find("result")->value().as(1); - uint32_t num_owners = 0; - uint32_t i = 0; - fc::variant v; - switch (b_obj->value().as(1)) { - case ETH_CHAIN_ID: - chain_id = result_str; - break; - case ETH_GET_TRANSACTION_RECEIPT: - list = fc::json::variants_from_string(result_str); - v = list[0].get_object().find("logs")->value(); - safe_account_addr = v.get_object().find("address")->value().as(1); - break; - case ETH_CALL: - break; - case ETH_SEND_TRANSACTION: - transaction_id = result_str; - break; - case ETH_SEND_RAW_TRANSACTION: - break; - case ETH_GET_CODE: - code = result_str; - break; - case ETH_GET_BALANCE: - balance = result_str; - break; - case ETH_SIGN: - signature = result_str; - break; - case ETH_COINBASE: - account_address = result_str; - break; - case GET_LIST_OWNERS: - num_owners = (uint32_t)strtol(result_str.substr(2 + 32 + 32 - 4, 4).c_str(), NULL, 16); - owners.clear(); - for (i = 0; i < num_owners; ++i) { - owners.push_back("0x" + result_str.substr(2 + 32 + 32 + 12 + 32 * i, 20)); - } - break; - case ADD_OWNER: - break; - case REMOVE_OWNER: - break; - } -} - -void eth_rpc_client::on_close(websocketpp::connection_hdl) { - ilog("Ethereum websocket close"); -} - -uint64_t eth_rpc_client::get_chain_id() { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":%1%}") % t_id); - ilog("get_chain_id: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_CHAIN_ID; - return t_id++; -} - -uint64_t eth_rpc_client::eth_getTransactionReceipt(const std::string &tx_id) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\"%1%\"],\"id\":%2%}") % tx_id.c_str() % t_id); - ilog("eth_getTransactionReceipt: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_GET_TRANSACTION_RECEIPT; - return t_id++; -} - -uint64_t eth_rpc_client::eth_call(const std::string &to, const std::string &data) { - std::string req = str(boost::format("{\"jsonrpc\": \"2.0\", \"method\": \"eth_call\", \"params\": [{\"to\": \"%1%\", \"data\": \"%2%\"}, \"latest\"], \"id\": %3%}") % to.c_str() % data.c_str() % t_id); - ilog("eth_call: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_CALL; - - return t_id++; -} - -uint64_t eth_rpc_client::eth_sendTransaction(const std::string &from, const std::string &to, const std::string &data) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sendTransaction\", \"params\": [{\"from\": \"%1%\", \"to\": \"%2%\", \"data\": \"%3%\"}], \"id\": %4%}") % from.c_str() % to.c_str() % data.c_str() % t_id); - ilog("eth_sendTransaction: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_SEND_TRANSACTION; - - return t_id++; -} - -uint64_t eth_rpc_client::eth_sendRawTransaction(const std::string ¶ms) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"%1%\"],\"id\":%2%}") % params.c_str() % t_id); - ilog("eth_sendRawTransaction: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_SEND_RAW_TRANSACTION; - - return t_id++; -} - -uint64_t eth_rpc_client::eth_getCode(const std::string &addr) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getCode\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); - ilog("eth_getCode: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_GET_CODE; - return t_id++; -} - -uint64_t eth_rpc_client::eth_getBalance(const std::string &addr) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_getBalance\", \"params\": [\"%1%\",\"latest\"], \"id\": %2%}") % addr.c_str() % t_id); - ilog("eth_getBalance: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_GET_BALANCE; - return t_id++; -} - -uint64_t eth_rpc_client::eth_sign(const string &addr, const string &message) { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\": \"eth_sign\", \"params\": [\"%1%\",\"%2%\"], \"id\": %2%}") % addr.c_str() % message.c_str() % t_id); - ilog("eth_sign: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_SIGN; - - return t_id++; -} - -uint64_t eth_rpc_client::eth_coinbase() { - std::string req = str(boost::format("{\"jsonrpc\":\"2.0\",\"method\":\"eth_coinbase\",\"params\":[],\"id\":%1%}") % t_id); - ilog("eth_coinbase: ${req}", ("req", req.c_str())); - m_endpoint.send(m_hdl, req.c_str(), websocketpp::frame::opcode::text); - m_requests[t_id] = req_t::ETH_COINBASE; - return t_id++; -} - -uint64_t eth_rpc_client::get_list_owners(const std::string &safe_account) { - //getOwners() - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("getOwners()"); - FC_ASSERT("a0e67e2b" == method_id); - return eth_call(safe_account.c_str(), method_id); -} - -uint64_t eth_rpc_client::add_owner(const std::string &addr) { - if (std::count(owners.begin(), owners.end(), addr)) { - FC_THROW_EXCEPTION(fc::exception, "Owners allready have addr: ${addr}", ("addr", addr)); - } - - std::string method_id = m_ethereum_function_call_encoder.encode_function_signature("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)"); - //addOwnerWithThreshold(address,uint256) - std::string data_method_id = m_ethereum_function_call_encoder.encode_function_signature("addOwnerWithThreshold(address,uint256)"); - FC_ASSERT("0d582f13" == data_method_id); - std::string data = data_method_id + m_ethereum_function_call_encoder.encode_address(addr) + m_ethereum_function_call_encoder.encode_uint256((boost::format("%x") % threshold).str()); - - std::string message = m_safe_transaction_encoder.build_transaction(safe_account_addr, "0", data, ethereum_function_call_encoder::operation_t::OPERATION_CALL, m_safe_transaction_encoder.default_safe_tx_gas, m_safe_transaction_encoder.default_data_gas, m_safe_transaction_encoder.default_gas_price, m_safe_transaction_encoder.default_gas_token, m_safe_transaction_encoder.default_refund_receiver); - - uint64_t id = eth_sign(account_address, message); - - m_requests[t_id] = req_t::ADD_OWNER; - - return 0; -} - -uint64_t eth_rpc_client::remove_owner(const std::string &addr, uint32_t threshold) { - if (!std::count(owners.begin(), owners.end(), addr)) { - FC_THROW_EXCEPTION(fc::exception, "Owners does not have addr: ${addr}", ("addr", addr)); - } - - if (threshold == owners.size()) { - FC_THROW_EXCEPTION(fc::exception, "Owners size does not meet threshold: ${th}", ("th", threshold)); - } - - //removeOwner(address,address,uint256) - std::string data_method_id = m_ethereum_function_call_encoder.encode_function_signature("removeOwner(address,address,uint256)"); - FC_ASSERT("f8dc5dd9" == data_method_id); - std::string data = data_method_id + m_ethereum_function_call_encoder.encode_address(m_ethereum_function_call_encoder.default_prev_addr) + m_ethereum_function_call_encoder.encode_address(addr) + m_ethereum_function_call_encoder.encode_uint256((boost::format("%x") % threshold).str()); - - std::string message = m_safe_transaction_encoder.build_transaction(safe_account_addr, "0", data, ethereum_function_call_encoder::operation_t::OPERATION_CALL, m_safe_transaction_encoder.default_safe_tx_gas, m_safe_transaction_encoder.default_data_gas, m_safe_transaction_encoder.default_gas_price, m_safe_transaction_encoder.default_gas_token, m_safe_transaction_encoder.default_refund_receiver); - - uint64_t id = eth_sign(account_address, message); - - m_requests[t_id] = req_t::REMOVE_OWNER; - - return 0; -} - -std::string eth_rpc_client::addmultisigaddress(const uint32_t nrequired, const std::vector public_keys) { - return ""; -} - -std::string eth_rpc_client::combinepsbt(const vector &psbts) { - return ""; -} - -uint64_t eth_rpc_client::createmultisig(const uint32_t nrequired, const std::vector owner_addresses, const std::string &private_key) { - ilog("createmultisig: ${key}", ("key", private_key.c_str())); - - //That's will create - //0x5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12 - //0x76ce31BD03f601c3fC13732deF921c5Bac282676 - //0x09EE460834498a4ee361beB819470061B7381B49 - //0x6AEFbd09209e1eE2e0a589d31e732F69B77713D2 - //0x631e128b16f9aDCF1bB6385112B1519C917D77a7 - //0xcD5C788e84220E8b8934Ea4F1dC6a12009bCc91D - //0x3627C1B31525887CB9441130C831e35887650305 - //0x03A13a989AF30C92AD7ABD1E6210308A6c96f373 - - std::string from = "0xeE52b70e8D7AB5Fe661311D47e81228EAD6B06B9"; - std::string to = "0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2"; - std::string data = m_safe_transaction_encoder.create_safe_address(owner_addresses, nrequired); - - return eth_sendTransaction(from, to, data); -} - -std::string eth_rpc_client::createpsbt() { -} - -std::string eth_rpc_client::createrawtransaction() { - return ""; -} - -std::string eth_rpc_client::createwallet(const std::string &wallet_name) { - return ""; -} - -std::string eth_rpc_client::decodepsbt(std::string const &tx_psbt) { - return ""; -} - -std::string eth_rpc_client::decoderawtransaction(std::string const &tx_hex) { - return ""; -} - -std::string eth_rpc_client::encryptwallet(const std::string &passphrase) { - return ""; -} - -uint64_t eth_rpc_client::estimatesmartfee(uint16_t conf_target) { - return 20000; -} - -std::string eth_rpc_client::finalizepsbt(std::string const &tx_psbt) { - return ""; -} - -std::string eth_rpc_client::getaddressinfo(const std::string &address) { - return ""; -} - -std::string eth_rpc_client::getblock(const std::string &block_hash, int32_t verbosity) { - return ""; -} - -std::string eth_rpc_client::getnetworkinfo() { - return ""; -} - -std::string eth_rpc_client::getrawtransaction(const std::string &txid, const bool verbose) { - return ""; -} - -std::string eth_rpc_client::gettransaction(const std::string &txid, const bool include_watch_only) { - return ""; -} - -std::string eth_rpc_client::getblockchaininfo() { - return ""; -} - -void eth_rpc_client::importaddress(const std::string &address_or_script, const std::string &label, const bool rescan, const bool p2sh) { - return; -} - -void eth_rpc_client::importmulti(const std::vector &address_or_script_array, const bool rescan) { -} - -std::string eth_rpc_client::loadwallet(const std::string &filename) { - return ""; -} - -std::string eth_rpc_client::sendrawtransaction(const std::string &tx_hex) { - return ""; -} - -std::string eth_rpc_client::signrawtransactionwithwallet(const std::string &tx_hash) { - return ""; -} - -std::string eth_rpc_client::unloadwallet(const std::string &filename) { - return ""; -} - -std::string eth_rpc_client::walletlock() { - return ""; -} - -std::string eth_rpc_client::walletprocesspsbt(std::string const &tx_psbt) { - return ""; -} - -bool eth_rpc_client::walletpassphrase(const std::string &passphrase, uint32_t timeout) { - return false; -} - -// ============================================================================= - sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : sidechain_net_handler(_plugin, options) { sidechain = sidechain_type::ethereum; @@ -501,328 +52,59 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha debug_rpc_calls = options.at("debug-rpc-calls").as(); } - url = options.at("ethereum-node-rpc-url").as(); - eth_client = std::unique_ptr(new eth_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls)); - eth_client->start(); - /* - if (!wallet.empty()) { - eth_client->loadwallet(wallet); - } + node_rpc_url = options.at("ethereum-node-rpc-url").as(); + if (options.count("ethereum-node-rpc-user")) { + node_rpc_user = options.at("ethereum-node-rpc-user").as(); + } else { + node_rpc_user = ""; + } + if (options.count("ethereum-node-rpc-password")) { + node_rpc_password = options.at("ethereum-node-rpc-password").as(); + } else { + node_rpc_password = ""; + } + if (options.count("ethereum-private-key")) { + const std::vector pub_priv_keys = options["ethereum-private-key"].as>(); + for (const std::string &itr_key_pair : pub_priv_keys) { + auto key_pair = graphene::app::dejsonify>(itr_key_pair, 5); + ilog("Ethereum Public Key: ${public}", ("public", key_pair.first)); + if (!key_pair.first.length() || !key_pair.second.length()) { + FC_THROW("Invalid public private key pair."); + } + private_keys[key_pair.first] = key_pair.second; + } + } - std::thread(&sidechain_net_handler_ethereum::handle_event, this, event_data).detach(); - }); + node_rpc_client = new ethereum_node_rpc_client(node_rpc_url, node_rpc_user, node_rpc_password, debug_rpc_calls); - database.changed_objects.connect([this](const vector &ids, const flat_set &accounts) { - on_changed_objects(ids, accounts); - }); - */ + std::string chain_id_str = node_rpc_client->get_chain_id(); + if (chain_id_str.empty()) { + elog("No Ethereum node running at ${url}", ("url", node_rpc_url)); + FC_ASSERT(false); + } + chain_id = std::stoll(chain_id_str); + std::string network_id_str = node_rpc_client->get_network_id(); + network_id = std::stoll(network_id_str); + + ilog("Running on Ethereum network, chain id ${chain_id_str}, network id ${network_id_str}", ("chain_id_str", chain_id_str)("network_id_str", network_id_str)); + + last_block_received = 0; + schedule_ethereum_listener(); + event_received.connect([this](const std::string &event_data) { + std::thread(&sidechain_net_handler_ethereum::handle_event, this, event_data).detach(); + }); } sidechain_net_handler_ethereum::~sidechain_net_handler_ethereum() { - try { - if (on_changed_objects_task.valid()) { - on_changed_objects_task.cancel_and_wait(__FUNCTION__); - } - } catch (fc::canceled_exception &) { - //Expected exception. Move along. - } catch (fc::exception &e) { - edump((e.to_detail_string())); - } } bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po) { - ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); - /* - bool should_approve = false; - - const chain::global_property_object &gpo = database.get_global_properties(); - - int32_t op_idx_0 = -1; - chain::operation op_obj_idx_0; - - if (po.proposed_transaction.operations.size() >= 1) { - op_idx_0 = po.proposed_transaction.operations[0].which(); - op_obj_idx_0 = po.proposed_transaction.operations[0]; - } - - int32_t op_idx_1 = -1; - chain::operation op_obj_idx_1; - (void)op_idx_1; - - if (po.proposed_transaction.operations.size() >= 2) { - op_idx_1 = po.proposed_transaction.operations[1].which(); - op_obj_idx_1 = po.proposed_transaction.operations[1]; - } - - switch (op_idx_0) { - - case chain::operation::tag::value: { - bool address_ok = false; - bool transaction_ok = false; - std::string new_pw_address = ""; - son_wallet_id_type swo_id = op_obj_idx_0.get().son_wallet_id; - const auto &idx = database.get_index_type().indices().get(); - const auto swo = idx.find(swo_id); - if (swo != idx.end()) { - - auto active_sons = gpo.active_sons; - vector wallet_sons = swo->sons; - - bool son_sets_equal = (active_sons.size() == wallet_sons.size()); - - if (son_sets_equal) { - for (size_t i = 0; i < active_sons.size(); i++) { - son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i); - } - } - - if (son_sets_equal) { - auto active_sons = gpo.active_sons; - vector son_pubkeys_bitcoin; - for (const son_info &si : active_sons) { - son_pubkeys_bitcoin.push_back(si.sidechain_public_keys.at(sidechain_type::bitcoin)); - } - - string reply_str = create_primary_wallet_address(active_sons); - - std::stringstream active_pw_ss(reply_str); - boost::property_tree::ptree active_pw_pt; - boost::property_tree::read_json(active_pw_ss, active_pw_pt); - if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) { - std::stringstream res; - boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result")); - new_pw_address = active_pw_pt.get("result.address"); - - address_ok = (op_obj_idx_0.get().address == res.str()); - } - } - - if (po.proposed_transaction.operations.size() >= 2) { - object_id_type object_id = op_obj_idx_1.get().object_id; - std::string op_tx_str = op_obj_idx_1.get().transaction; - - const auto &st_idx = database.get_index_type().indices().get(); - const auto st = st_idx.find(object_id); - if (st == st_idx.end()) { - - std::string tx_str = ""; - - if (object_id.is()) { - const auto &idx = database.get_index_type().indices().get(); - const auto swo = idx.find(object_id); - if (swo != idx.end()) { - tx_str = create_primary_wallet_transaction(*swo, new_pw_address); - } - } - - transaction_ok = (op_tx_str == tx_str); - } -} else { - transaction_ok = true; -} -} - -should_approve = address_ok && -transaction_ok; -break; -} - -case chain::operation::tag::value: { - bool process_ok = false; - bool transaction_ok = false; - son_wallet_deposit_id_type swdo_id = op_obj_idx_0.get().son_wallet_deposit_id; - const auto &idx = database.get_index_type().indices().get(); - const auto swdo = idx.find(swdo_id); - if (swdo != idx.end()) { - - std::string swdo_txid = swdo->sidechain_transaction_id; - std::string swdo_address = swdo->sidechain_from; - uint64_t swdo_amount = swdo->sidechain_amount.value; - uint64_t swdo_vout = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-") + 1)); - - std::string tx_str = eth_client->getrawtransaction(swdo_txid, true); - std::stringstream tx_ss(tx_str); - boost::property_tree::ptree tx_json; - boost::property_tree::read_json(tx_ss, tx_json); - - if (tx_json.count("error") && tx_json.get_child("error").empty()) { - - std::string tx_txid = tx_json.get("result.txid"); - uint32_t tx_confirmations = tx_json.get("result.confirmations"); - std::string tx_address = ""; - uint64_t tx_amount = -1; - uint64_t tx_vout = -1; - - for (auto &input : tx_json.get_child("result.vout")) { - std::string tx_vout_s = input.second.get("n"); - tx_vout = std::stoll(tx_vout_s); - if (tx_vout == swdo_vout) { - if (bitcoin_major_version > 21) { - std::string address = input.second.get("scriptPubKey.address"); - if (address == swdo_address) { - tx_address = address; - } - } else { - for (auto &address : input.second.get_child("scriptPubKey.addresses")) { - if (address.second.data() == swdo_address) { - tx_address = address.second.data(); - break; - } - } - } - std::string tx_amount_s = input.second.get("value"); - tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end()); - tx_amount = std::stoll(tx_amount_s); - break; - } - } - - process_ok = (swdo_txid == tx_txid) && - (swdo_address == tx_address) && - (swdo_amount == tx_amount) && - (swdo_vout == tx_vout) && - (gpo.parameters.son_bitcoin_min_tx_confirmations() <= tx_confirmations); - } - - object_id_type object_id = op_obj_idx_1.get().object_id; - std::string op_tx_str = op_obj_idx_1.get().transaction; - - const auto &st_idx = database.get_index_type().indices().get(); - const auto st = st_idx.find(object_id); - if (st == st_idx.end()) { - - std::string tx_str = ""; - - if (object_id.is()) { - const auto &idx = database.get_index_type().indices().get(); - const auto swdo = idx.find(object_id); - if (swdo != idx.end()) { - tx_str = create_deposit_transaction(*swdo); - } - } - - transaction_ok = (op_tx_str == tx_str); - } - } - - should_approve = process_ok && - transaction_ok; - break; - } - -case chain::operation::tag::value: { - bool process_ok = false; - bool transaction_ok = false; - son_wallet_withdraw_id_type swwo_id = op_obj_idx_0.get().son_wallet_withdraw_id; - const auto &idx = database.get_index_type().indices().get(); - const auto swwo = idx.find(swwo_id); - if (swwo != idx.end()) { - - uint32_t swwo_block_num = swwo->block_num; - std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id; - uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1)); - - const auto &block = database.fetch_block_by_number(swwo_block_num); - - for (const auto &tx : block->transactions) { - if (tx.id().str() == swwo_peerplays_transaction_id) { - operation op = tx.operations[swwo_op_idx]; - transfer_operation t_op = op.get(); - - price asset_price = database.get(t_op.amount.asset_id).options.core_exchange_rate; - asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); - - process_ok = (t_op.to == gpo.parameters.son_account()) && - (swwo->peerplays_from == t_op.from) && - (swwo->peerplays_asset == peerplays_asset); - break; - } - } - - object_id_type object_id = op_obj_idx_1.get().object_id; - std::string op_tx_str = op_obj_idx_1.get().transaction; - - const auto &st_idx = database.get_index_type().indices().get(); - const auto st = st_idx.find(object_id); - if (st == st_idx.end()) { - - std::string tx_str = ""; - - if (object_id.is()) { - const auto &idx = database.get_index_type().indices().get(); - const auto swwo = idx.find(object_id); - if (swwo != idx.end()) { - tx_str = create_withdrawal_transaction(*swwo); - } - } - - transaction_ok = (op_tx_str == tx_str); - } - } - - should_approve = process_ok && - transaction_ok; - break; - } - -case chain::operation::tag::value: { - using namespace bitcoin; - should_approve = true; - son_id_type signer = op_obj_idx_0.get().signer; - std::string signature = op_obj_idx_0.get().signature; - sidechain_transaction_id_type sidechain_transaction_id = op_obj_idx_0.get().sidechain_transaction_id; - std::vector in_amounts; - std::string tx_hex; - std::string redeem_script; - const auto &st_idx = database.get_index_type().indices().get(); - const auto sto = st_idx.find(sidechain_transaction_id); - if (sto == st_idx.end()) { - should_approve = false; - break; - } - - const auto &s_idx = database.get_index_type().indices().get(); - const auto son = s_idx.find(signer); - if (son == s_idx.end()) { - should_approve = false; - break; - } - - read_transaction_data(sto->transaction, tx_hex, in_amounts, redeem_script); - bitcoin_transaction tx = unpack(parse_hex(tx_hex)); - bitcoin::bytes pubkey = parse_hex(son->sidechain_public_keys.at(sidechain_type::bitcoin)); - vector sigs = read_byte_arrays_from_string(signature); - for (size_t i = 0; i < tx.vin.size(); i++) { - const auto &sighash_str = get_signature_hash(tx, parse_hex(redeem_script), static_cast(in_amounts[i]), i, 1, true).str(); - const bitcoin::bytes &sighash_hex = parse_hex(sighash_str); - should_approve = should_approve && verify_sig(sigs[i], pubkey, sighash_hex, btc_context()); - } - break; - } - -case chain::operation::tag::value: { - should_approve = true; - break; - } - -default: -should_approve = false; -elog("=================================================="); -elog("Proposal not considered for approval ${po}", ("po", po)); -elog("=================================================="); -} - -return should_approve; -*/ - return true; } void sidechain_net_handler_ethereum::process_primary_wallet() { - ilog("### process_primary_wallet:"); - const auto &swi = database.get_index_type().indices().get(); const auto &active_sw = swi.rbegin(); if (active_sw != swi.rend()) { @@ -898,64 +180,9 @@ void sidechain_net_handler_ethereum::process_primary_wallet() { } void sidechain_net_handler_ethereum::process_sidechain_addresses() { - /* - const chain::global_property_object &gpo = database.get_global_properties(); - std::vector> pubkeys; - for (auto &son : gpo.active_sons) { - std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); - auto pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); - pubkeys.push_back(std::make_pair(pubkey, son.weight)); - } - - const auto &sidechain_addresses_idx = database.get_index_type(); - const auto &sidechain_addresses_by_sidechain_idx = sidechain_addresses_idx.indices().get(); - const auto &sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain); - std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second, - [&](const sidechain_address_object &sao) { - bool retval = true; - try { - if (sao.expires == time_point_sec::maximum()) { - auto usr_pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(sao.deposit_public_key))); - - btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys, network_type); - std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) + - "\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }"; - - if (addr.get_address() != sao.deposit_address) { - sidechain_address_update_operation op; - op.payer = plugin.get_current_son_object().son_account; - op.sidechain_address_id = sao.id; - op.sidechain_address_account = sao.sidechain_address_account; - op.sidechain = sao.sidechain; - op.deposit_public_key = sao.deposit_public_key; - op.deposit_address = addr.get_address(); - op.deposit_address_data = address_data; - op.withdraw_public_key = sao.withdraw_public_key; - op.withdraw_address = sao.withdraw_address; - - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); - try { - trx.validate(); - database.push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - retval = true; - } catch (fc::exception &e) { - elog("Sending transaction for sidechain address update operation failed with exception ${e}", ("e", e.what())); - retval = false; - } - } - } - } catch (fc::exception &e) { - retval = false; - } - return retval; - }); - */ } bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_object &swdo) { - ilog("### process_deposit:"); if (proposal_exists(chain::operation::tag::value, swdo.id)) { return false; @@ -1000,7 +227,6 @@ bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_ob } bool sidechain_net_handler_ethereum::process_withdrawal(const son_wallet_withdraw_object &swwo) { - ilog("### process_withdrawal:"); if (proposal_exists(chain::operation::tag::value, swwo.id)) { return false; @@ -1045,130 +271,59 @@ bool sidechain_net_handler_ethereum::process_withdrawal(const son_wallet_withdra } std::string sidechain_net_handler_ethereum::process_sidechain_transaction(const sidechain_transaction_object &sto) { - ilog("### process_sidechain_transaction: "); return sign_transaction(sto); } std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sidechain_transaction_object &sto) { - ilog("### send_sidechain_transaction: "); return send_transaction(sto); } bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) { - return false; -} - -std::vector sidechain_net_handler_ethereum::parse_hex(const std::string &str) { - std::vector vec(str.size() / 2); - fc::from_hex(str, vec.data(), vec.size()); - return vec; + return true; } std::string sidechain_net_handler_ethereum::create_primary_wallet_address(const std::vector &son_pubkeys) { - std::stringstream ss; - - ss << "{\"result\": {\"address\": \"" << eth_client->safe_account_addr << "\"" - << "}, "; - ss << "\"onwers\": ["; - for (auto &owner : eth_client->owners) { - ss << "\"" << owner << "\","; - } - ss.seekp(-1, std::ios_base::end); - ss << "], keys: ["; - - for (auto &son : son_pubkeys) { - std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum); - ss << "\"" << pub_key_str << "\","; - } - ss.seekp(-1, std::ios_base::end); - ss << "], "; - - ss << "\"error\":null}"; - - std::string res = ss.str(); - return res; + return "Primary Wallet Address"; } std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address) { - return ""; //create_transaction(inputs, outputs, prev_redeem_script); + return "Primary-Wallet-Transaction"; } std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) { - return ""; //create_transaction(inputs, outputs, redeem_script); + return "Deposit-Transaction"; } std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { - return ""; //create_transaction(inputs, outputs, redeem_script); -} - -std::string sidechain_net_handler_ethereum::create_transaction() { - std::string tx_raw; // = write_transaction_data(hex_tx, in_amounts, redeem_script); - return tx_raw; + return "Withdrawal-Transaction"; } std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) { - ilog("### sign_transaction: "); - - std::stringstream ss_trx(boost::algorithm::unhex(sto.transaction)); - ethereum::signed_transaction htrx; - fc::raw::unpack(ss_trx, htrx, 1000); - - std::string chain_id_str = eth_client->chain_id; //eth_rpc_client->get_chain_id(); - const ethereum::chain_id_type chain_id(chain_id_str); - - fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))); - signature_type st = htrx.sign(*privkey, chain_id); - - std::stringstream ss_st; - fc::raw::pack(ss_st, st, 1000); - std::string st_str = boost::algorithm::hex(ss_st.str()); - return st_str; + std::string key = get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain)); + return "Transaction-Signature-" + key; } std::string sidechain_net_handler_ethereum::send_transaction(const sidechain_transaction_object &sto) { - std::string res; // = eth_client->sendrawtransaction(final_tx_hex); + return "Transaction-ID"; +} - return res; +void sidechain_net_handler_ethereum::schedule_ethereum_listener() { + fc::time_point now = fc::time_point::now(); + int64_t time_to_next = 1000; + + fc::time_point next_wakeup(now + fc::milliseconds(time_to_next)); + + _listener_task = fc::schedule([this] { + ethereum_listener_loop(); + }, + next_wakeup, "SON Ethereum listener task"); +} + +void sidechain_net_handler_ethereum::ethereum_listener_loop() { + schedule_ethereum_listener(); } void sidechain_net_handler_ethereum::handle_event(const std::string &event_data) { } -std::vector sidechain_net_handler_ethereum::extract_info_from_block(const std::string &_block) { - std::stringstream ss(_block); - boost::property_tree::ptree block; - boost::property_tree::read_json(ss, block); - - std::vector result; - - return result; -} - -void sidechain_net_handler_ethereum::on_changed_objects(const vector &ids, const flat_set &accounts) { - ilog("### on_changed_objects: "); - - fc::time_point now = fc::time_point::now(); - int64_t time_to_next_changed_objects_processing = 5000; - - fc::time_point next_wakeup(now + fc::microseconds(time_to_next_changed_objects_processing)); - - on_changed_objects_task = fc::schedule([this, ids, accounts] { - on_changed_objects_cb(ids, accounts); - }, - next_wakeup, "SON Processing"); -} - -void sidechain_net_handler_ethereum::on_changed_objects_cb(const vector &ids, const flat_set &accounts) { -} - -fc::ecc::public_key_data sidechain_net_handler_ethereum::create_public_key_data(const std::vector &public_key) { - FC_ASSERT(public_key.size() == 33); - fc::ecc::public_key_data key; - for (size_t i = 0; i < 33; i++) { - key.at(i) = public_key[i]; - } - return key; -} - -// ============================================================================= }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp index d63e6743..dacd1e9e 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp @@ -28,8 +28,6 @@ #include #include -#include - namespace graphene { namespace peerplays_sidechain { hive_node_rpc_client::hive_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) :