WIP: Major refactoring of Ethereum sidechain handler

This commit is contained in:
serkixenos 2022-06-28 23:55:19 +02:00
parent cfaf31e705
commit da46b16560
16 changed files with 276 additions and 1665 deletions

View file

@ -0,0 +1,5 @@
#include #include < graphene / peerplays_sidechain / ethereum / decoders.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -0,0 +1,5 @@
#include #include < graphene / peerplays_sidechain / ethereum / encoders.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,57 +1,22 @@
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
#include <boost/algorithm/hex.hpp>
#include <fc/bitutil.hpp>
#include <fc/io/raw.hpp>
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

View file

@ -1,73 +1,5 @@
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
#include <fc/crypto/base58.hpp>
#include <fc/crypto/ripemd160.hpp>
#include <fc/exception/exception.hpp>
#include <fc/io/raw.hpp>
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<binary_key>(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

View file

@ -1,41 +0,0 @@
#pragma once
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
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))

View file

@ -1,33 +0,0 @@
#pragma once
#include <cstdint>
#include <fc/container/flat_fwd.hpp>
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
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<ethereum::account_name_type, uint16_t> account_auths;
fc::flat_map<ethereum::public_key_type, uint16_t> 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))

View file

@ -0,0 +1,5 @@
#pragma once
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -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<std::string> &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

View file

@ -1,123 +0,0 @@
#pragma once
#include <cstdint>
#include <vector>
#include <fc/optional.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/peerplays_sidechain/ethereum/asset.hpp>
#include <graphene/peerplays_sidechain/ethereum/authority.hpp>
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
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<authority> owner;
fc::optional<authority> active;
fc::optional<authority> 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))

View file

@ -1,69 +0,0 @@
#pragma once
#include <graphene/peerplays_sidechain/ethereum/ethereum_operations.hpp>
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)

View file

@ -1,86 +1,123 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include <fc/crypto/elliptic.hpp>
#include <fc/crypto/ripemd160.hpp>
#include <fc/container/flat_fwd.hpp>
#include <fc/time.hpp>
#include <graphene/peerplays_sidechain/ethereum/operations.hpp>
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<ethereum_operation> 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<std::string> 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<SignatureStruct> 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<uint64_t> m_chainId;
mutable h256 m_hashWith; ///< Cached hash of transaction with signature.
mutable boost::optional<Address> m_sender; ///< Cached sender, determined from signature.
*/
};
class signed_transaction : public transaction {
public:
std::vector<fc::ecc::compact_signature> 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"
//}

View file

@ -1,72 +1,10 @@
#pragma once
#include <fc/crypto/elliptic.hpp>
#include <fc/crypto/ripemd160.hpp>
#include <boost/multiprecision/cpp_int.hpp>
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<void_t> future_extensions;
typedef fc::flat_set<future_extensions> 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<int64_t> share_type;
//typedef safe<uint64_t> 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)

View file

@ -3,220 +3,26 @@
#include <graphene/peerplays_sidechain/sidechain_net_handler.hpp>
#include <string>
#include <unordered_map>
#include <boost/signals2.hpp>
#include <mutex>
#include <fc/network/http/connection.hpp>
#include <fc/api.hpp>
#include <fc/log/logger.hpp>
#include <websocketpp/client.hpp>
#include <websocketpp/config/asio_client.hpp>
#include <fc/thread/thread.hpp>
#include <boost/multiprecision/cpp_int.hpp>
using namespace boost::multiprecision::literals;
using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
u256 constexpr Invalid256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_cppui256;
using byte = uint8_t;
using bytes = std::vector<byte>;
#include <graphene/peerplays_sidechain/common/rpc_client.hpp>
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
namespace graphene { namespace peerplays_sidechain {
typedef websocketpp::client<websocketpp::config::asio_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<boost::asio::ssl::context> 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 &params);
uint64_t eth_getCode(const std::string &addr);
uint64_t eth_getBalance(const std::string &addr);
uint64_t eth_sign(const string &addr, const string &message);
uint64_t eth_coinbase();
uint64_t get_list_owners(const std::string &safe_account);
uint64_t add_owner(const std::string &addr);
uint64_t remove_owner(const std::string &addr, uint32_t threshold);
std::string addmultisigaddress(const uint32_t nrequired, const std::vector<std::string> public_keys);
std::string combinepsbt(const vector<std::string> &psbts);
uint64_t createmultisig(const uint32_t nrequired, const std::vector<std::string> 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<multi_params> &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<std::string> 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<std::string> &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<fc::thread> _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<uint64_t, req_t> 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_rpc_client> eth_client;
fc::future<void> on_changed_objects_task;
std::mutex event_handler_mutex;
typedef std::lock_guard<decltype(event_handler_mutex)> scoped_lock;
ethereum::chain_id_type chain_id;
ethereum::network_id_type network_id;
std::string create_primary_wallet_address(const std::vector<son_info> &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<void> _listener_task;
boost::signals2::signal<void(const std::string &)> event_received;
void schedule_ethereum_listener();
void ethereum_listener_loop();
void handle_event(const std::string &event_data);
std::vector<info_for_vin> extract_info_from_block(const std::string &_block);
void on_changed_objects(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts);
void on_changed_objects_cb(const vector<object_id_type> &ids, const flat_set<account_id_type> &accounts);
std::vector<char> parse_hex(const std::string &str);
fc::ecc::public_key_data create_public_key_data(const std::vector<char> &public_key);
};
}} // namespace graphene::peerplays_sidechain

View file

@ -157,8 +157,12 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
cli.add_options()("bitcoin-private-key", bpo::value<vector<string>>()->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<bool>()->default_value(true), "Hive sidechain handler enabled");
cli.add_options()("ethereum-node-rpc-url", bpo::value<string>()->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<bool>()->default_value(false), "Ethereum sidechain handler enabled");
cli.add_options()("ethereum-node-rpc-url", bpo::value<string>()->default_value("127.0.0.1:8545"), "Ethereum node RPC URL [http[s]://]host[:port]");
cli.add_options()("ethereum-node-rpc-user", bpo::value<string>()->default_value("1"), "Ethereum RPC user");
cli.add_options()("ethereum-node-rpc-password", bpo::value<string>()->default_value("1"), "Ethereum RPC password");
cli.add_options()("ethereum-private-key", bpo::value<vector<string>>()->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<bool>()->default_value(false), "Hive sidechain handler enabled");
cli.add_options()("hive-node-rpc-url", bpo::value<string>()->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<bool>();
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");

View file

@ -28,8 +28,6 @@
#include <graphene/peerplays_sidechain/hive/transaction.hpp>
#include <graphene/utilities/key_conversion.hpp>
#include <boost/asio.hpp>
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) :