From 7b574e3db294c02e10fd3d019cd1d4e4ab85ebfb Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Tue, 30 Aug 2022 08:18:05 +0300 Subject: [PATCH 1/5] #420 - calculate hash for raw transaction as single funtion --- .../ethereum/transaction.cpp | 25 +++++++++++-------- .../ethereum/transaction.hpp | 3 +++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index 668e9639..9f160445 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -12,7 +13,6 @@ #include #include -#include #include namespace graphene { namespace peerplays_sidechain { namespace ethereum { @@ -54,6 +54,15 @@ void transaction::deserialize(const std::string &raw_tx) { //! raw_transaction +bytes raw_transaction::hash() const { + bytes hash; + hash.resize(32); + const auto transaction_string = boost::algorithm::unhex(remove_0x(serialize())); + keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data()); + + return hash; +} + signed_transaction raw_transaction::sign(const std::string &private_key) const { //! Prepare signed transaction signed_transaction tr; @@ -64,30 +73,26 @@ signed_transaction raw_transaction::sign(const std::string &private_key) const { tr.value = value; tr.data = data; - //! Calculate keccak hash of transaction - bytes hash; - hash.resize(32); - const auto transaction_string = boost::algorithm::unhex(remove_0x(serialize())); - keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data()); - const bytes priv_key = parse_hex(private_key); int recid = 0; secp256k1_ecdsa_recoverable_signature sig; - FC_ASSERT(secp256k1_ecdsa_sign_recoverable(eth_context(), &sig, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), NULL, NULL)); + FC_ASSERT(secp256k1_ecdsa_sign_recoverable(eth_context(), &sig, (const unsigned char *)hash().data(), (const unsigned char *)priv_key.data(), NULL, NULL)); fc::ecc::compact_signature result; FC_ASSERT(secp256k1_ecdsa_recoverable_signature_serialize_compact(eth_context(), (unsigned char *)result.begin() + 1, &recid, &sig)); - bytes v = bytes{char(recid + from_hex(chain_id) * 2 + 35)}; bytes r; for (int i = 1; i < 33; i++) r.emplace_back((char)result.at(i)); + + bytes v = bytes{char(recid + from_hex(chain_id) * 2 + 35)}; + bytes s; for (int i = 33; i < 65; i++) s.emplace_back((char)result.at(i)); - tr.v = fc::to_hex((char *)&v[0], v.size()); tr.r = fc::to_hex((char *)&r[0], r.size()); + tr.v = fc::to_hex((char *)&v[0], v.size()); tr.s = fc::to_hex((char *)&s[0], s.size()); return tr; 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 c112206b..b8b1aa13 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 @@ -4,6 +4,8 @@ #include #include +#include + namespace graphene { namespace peerplays_sidechain { namespace ethereum { class base_transaction { @@ -34,6 +36,7 @@ public: std::string data; std::string chain_id; + bytes hash() const; signed_transaction sign(const std::string &private_key) const; virtual std::string serialize() const override; -- 2.45.2 From db244887c27c3324ee591f4cfadd8867724ed7aa Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Tue, 30 Aug 2022 08:19:43 +0300 Subject: [PATCH 2/5] #420 - recover function for sign transaction --- .../ethereum/transaction.cpp | 34 +++++++++++++++++++ .../ethereum/transaction.hpp | 2 ++ 2 files changed, 36 insertions(+) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index 9f160445..82a81ac1 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -129,6 +129,40 @@ void raw_transaction::deserialize(const std::string &raw_tx) { //! signed_transaction +std::string signed_transaction::recover(const std::string &chain_id) const { + fc::ecc::compact_signature input64; + fc::from_hex(r, (char *)&input64.at(1), 32); + fc::from_hex(v, (char *)&input64.at(0), 1); + int recid = input64.at(0) - from_hex(chain_id) * 2 - 35; + fc::from_hex(s, (char *)&input64.at(33), 32); + + secp256k1_ecdsa_recoverable_signature sig; + FC_ASSERT(secp256k1_ecdsa_recoverable_signature_parse_compact(eth_context(), &sig, (const unsigned char *)&input64.data[1], recid)); + + raw_transaction tr; + tr.nonce = nonce; + tr.gas_price = gas_price; + tr.gas_limit = gas_limit; + tr.to = to; + tr.value = value; + tr.data = data; + tr.chain_id = chain_id; + + secp256k1_pubkey rawPubkey; + FC_ASSERT(secp256k1_ecdsa_recover(eth_context(), &rawPubkey, &sig, (const unsigned char *)tr.hash().data())); + + std::array pubkey; + size_t biglen = 65; + FC_ASSERT(secp256k1_ec_pubkey_serialize(eth_context(), pubkey.data(), &biglen, &rawPubkey, SECP256K1_EC_UNCOMPRESSED)); + + const std::string out = std::string(pubkey.begin(), pubkey.end()).substr(1); + bytes hash; + hash.resize(32); + keccak_256((const unsigned char *)out.data(), out.size(), (unsigned char *)hash.data()); + + return add_0x(fc::to_hex((char *)&hash[0], hash.size()).substr(24)); +} + std::string signed_transaction::serialize() const { rlp_encoder encoder; const std::string serialized = encoder.encode(remove_0x(nonce)) + 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 b8b1aa13..f4edf015 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 @@ -55,6 +55,8 @@ public: std::string r; std::string s; + std::string recover(const std::string &chain_id) const; + virtual std::string serialize() const override; virtual void deserialize(const std::string &raw_tx) override; }; -- 2.45.2 From c420c38cc918a8281a9329b6791f5c2eb6c1dc77 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Tue, 30 Aug 2022 08:20:30 +0300 Subject: [PATCH 3/5] #420 - serialize and deserialize functions update --- .../ethereum/transaction.cpp | 76 +++++++++++-------- .../sidechain_net_handler_ethereum.cpp | 6 +- 2 files changed, 47 insertions(+), 35 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index 82a81ac1..4bf2217f 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -99,32 +99,37 @@ signed_transaction raw_transaction::sign(const std::string &private_key) const { } std::string raw_transaction::serialize() const { - rlp_encoder encoder; - const std::string serialized = encoder.encode(remove_0x(nonce)) + - encoder.encode(remove_0x(gas_price)) + - encoder.encode(remove_0x(gas_limit)) + - encoder.encode(remove_0x(to)) + - encoder.encode(remove_0x(value)) + - encoder.encode(remove_0x(data)) + - encoder.encode(remove_0x(chain_id)) + - encoder.encode("") + - encoder.encode(""); + const std::string serialized = rlp_encoder::encode(remove_0x(nonce)) + + rlp_encoder::encode(remove_0x(gas_price)) + + rlp_encoder::encode(remove_0x(gas_limit)) + + rlp_encoder::encode(remove_0x(to)) + + rlp_encoder::encode(remove_0x(value)) + + rlp_encoder::encode(remove_0x(data)) + + rlp_encoder::encode(remove_0x(chain_id)) + + rlp_encoder::encode("") + + rlp_encoder::encode(""); - return add_0x(bytes2hex(encoder.encode_length(serialized.size(), 192) + serialized)); + return add_0x(bytes2hex(rlp_encoder::encode_length(serialized.size(), 192) + serialized)); } void raw_transaction::deserialize(const std::string &raw_tx) { - rlp_decoder decoder; - const auto rlp_array = decoder.decode(remove_0x(raw_tx)); + const auto rlp_array = rlp_decoder::decode(remove_0x(raw_tx)); FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format"); - nonce = add_0x(rlp_array.at(0)); + nonce = !rlp_array.at(0).empty() ? add_0x(rlp_array.at(0)) : add_0x("0"); + boost::algorithm::to_lower(nonce); gas_price = add_0x(rlp_array.at(1)); + boost::algorithm::to_lower(gas_price); gas_limit = add_0x(rlp_array.at(2)); + boost::algorithm::to_lower(gas_limit); to = add_0x(rlp_array.at(3)); - value = add_0x(rlp_array.at(4)); - data = add_0x(rlp_array.at(5)); + boost::algorithm::to_lower(to); + value = !rlp_array.at(4).empty() ? add_0x(rlp_array.at(4)) : add_0x("0"); + boost::algorithm::to_lower(value); + data = !rlp_array.at(5).empty() ? add_0x(rlp_array.at(5)) : ""; + boost::algorithm::to_lower(data); chain_id = add_0x(rlp_array.at(6)); + boost::algorithm::to_lower(chain_id); } //! signed_transaction @@ -164,34 +169,41 @@ std::string signed_transaction::recover(const std::string &chain_id) const { } std::string signed_transaction::serialize() const { - rlp_encoder encoder; - const std::string serialized = encoder.encode(remove_0x(nonce)) + - encoder.encode(remove_0x(gas_price)) + - encoder.encode(remove_0x(gas_limit)) + - encoder.encode(remove_0x(to)) + - encoder.encode(remove_0x(value)) + - encoder.encode(remove_0x(data)) + - encoder.encode(remove_0x(v)) + - encoder.encode(remove_0x(r)) + - encoder.encode(remove_0x(s)); + const std::string serialized = rlp_encoder::encode(remove_0x(nonce)) + + rlp_encoder::encode(remove_0x(gas_price)) + + rlp_encoder::encode(remove_0x(gas_limit)) + + rlp_encoder::encode(remove_0x(to)) + + rlp_encoder::encode(remove_0x(value)) + + rlp_encoder::encode(remove_0x(data)) + + rlp_encoder::encode(remove_0x(v)) + + rlp_encoder::encode(remove_0x(r)) + + rlp_encoder::encode(remove_0x(s)); - return add_0x(bytes2hex(encoder.encode_length(serialized.size(), 192) + serialized)); + return add_0x(bytes2hex(rlp_encoder::encode_length(serialized.size(), 192) + serialized)); } void signed_transaction::deserialize(const std::string &raw_tx) { - rlp_decoder decoder; - const auto rlp_array = decoder.decode(remove_0x(raw_tx)); + const auto rlp_array = rlp_decoder::decode(remove_0x(raw_tx)); FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format"); - nonce = add_0x(rlp_array.at(0)); + nonce = !rlp_array.at(0).empty() ? add_0x(rlp_array.at(0)) : add_0x("0"); + boost::algorithm::to_lower(nonce); gas_price = add_0x(rlp_array.at(1)); + boost::algorithm::to_lower(gas_price); gas_limit = add_0x(rlp_array.at(2)); + boost::algorithm::to_lower(gas_limit); to = add_0x(rlp_array.at(3)); - value = add_0x(rlp_array.at(4)); - data = add_0x(rlp_array.at(5)); + boost::algorithm::to_lower(to); + value = !rlp_array.at(4).empty() ? add_0x(rlp_array.at(4)) : add_0x("0"); + boost::algorithm::to_lower(value); + data = !rlp_array.at(5).empty() ? add_0x(rlp_array.at(5)) : ""; + boost::algorithm::to_lower(data); v = add_0x(rlp_array.at(6)); + boost::algorithm::to_lower(v); r = add_0x(rlp_array.at(7)); + boost::algorithm::to_lower(r); s = add_0x(rlp_array.at(8)); + boost::algorithm::to_lower(s); } }}} // namespace graphene::peerplays_sidechain::ethereum diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp index 52d401cb..038fa4f0 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_ethereum.cpp @@ -546,7 +546,7 @@ std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sid const auto &transaction = signature.second; //! Check if we have this signed transaction, if not, don't send it - if(transaction.empty()) + if (transaction.empty()) continue; #ifdef SEND_RAW_TRANSACTION @@ -625,7 +625,7 @@ std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(co owners_weights.emplace_back(std::make_pair(pub_key_str, son.weight)); } - ethereum::update_owners_encoder encoder; + const ethereum::update_owners_encoder encoder; return encoder.encode(owners_weights, object_id); } @@ -634,7 +634,7 @@ std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son } std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { - ethereum::withdrawal_encoder encoder; + const ethereum::withdrawal_encoder encoder; return encoder.encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string()); } -- 2.45.2 From 1671a7e4fcb2da6b6f9e9fdf3818e4a95cd3f928 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Tue, 30 Aug 2022 08:35:05 +0300 Subject: [PATCH 4/5] #420 - constructor for transactions from raw_tx --- .../ethereum/transaction.cpp | 20 +++++++++++++++++++ .../ethereum/transaction.hpp | 13 ++++++++++++ 2 files changed, 33 insertions(+) diff --git a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp index 4bf2217f..a75327c3 100644 --- a/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp @@ -24,6 +24,16 @@ const secp256k1_context *eth_context() { //! transaction +base_transaction::base_transaction(const std::string &raw_tx) { +} + +//! transaction + +transaction::transaction(const std::string &raw_tx) : + base_transaction{raw_tx} { + deserialize(raw_tx); +} + const transaction &transaction::sign(const std::string &private_key) const { return *this; } @@ -54,6 +64,11 @@ void transaction::deserialize(const std::string &raw_tx) { //! raw_transaction +raw_transaction::raw_transaction(const std::string &raw_tx) : + base_transaction{raw_tx} { + deserialize(raw_tx); +} + bytes raw_transaction::hash() const { bytes hash; hash.resize(32); @@ -134,6 +149,11 @@ void raw_transaction::deserialize(const std::string &raw_tx) { //! signed_transaction +signed_transaction::signed_transaction(const std::string &raw_tx) : + base_transaction{raw_tx} { + deserialize(raw_tx); +} + std::string signed_transaction::recover(const std::string &chain_id) const { fc::ecc::compact_signature input64; fc::from_hex(r, (char *)&input64.at(1), 32); 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 f4edf015..693c7284 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 @@ -9,6 +9,10 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum { class base_transaction { +public: + base_transaction() = default; + base_transaction(const std::string &raw_tx); + virtual std::string serialize() const = 0; virtual void deserialize(const std::string &raw_tx) = 0; }; @@ -19,6 +23,9 @@ public: std::string to; std::string data; + transaction() = default; + transaction(const std::string &raw_tx); + const transaction &sign(const std::string &private_key) const; virtual std::string serialize() const override; @@ -36,6 +43,9 @@ public: std::string data; std::string chain_id; + raw_transaction() = default; + raw_transaction(const std::string &raw_tx); + bytes hash() const; signed_transaction sign(const std::string &private_key) const; @@ -55,6 +65,9 @@ public: std::string r; std::string s; + signed_transaction() = default; + signed_transaction(const std::string &raw_tx); + std::string recover(const std::string &chain_id) const; virtual std::string serialize() const override; -- 2.45.2 From ed0a90d57eab0a3e1edd37d0b2d17bbca4b164d5 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Wed, 31 Aug 2022 08:25:36 +0300 Subject: [PATCH 5/5] #420 - add unit tests for ethereum functionality --- .../ethereum_transaction_tests.cpp | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 tests/peerplays_sidechain/ethereum_transaction_tests.cpp diff --git a/tests/peerplays_sidechain/ethereum_transaction_tests.cpp b/tests/peerplays_sidechain/ethereum_transaction_tests.cpp new file mode 100644 index 00000000..769c35b1 --- /dev/null +++ b/tests/peerplays_sidechain/ethereum_transaction_tests.cpp @@ -0,0 +1,147 @@ +#include + +#include +#include +#include + +using namespace graphene::peerplays_sidechain::ethereum; + +BOOST_AUTO_TEST_SUITE(ethereum_transaction_tests) + +BOOST_AUTO_TEST_CASE(withdrawal_encoder_test) { + const withdrawal_encoder encoder; + const auto tx = encoder.encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.0"); + BOOST_CHECK_EQUAL(tx, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000"); + + const auto tx1 = encoder.encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1"); + BOOST_CHECK_EQUAL(tx1, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); +} + +BOOST_AUTO_TEST_CASE(update_owners_encoder_test) { + std::vector> owners_weights; + owners_weights.emplace_back("5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12", 1); + owners_weights.emplace_back("76ce31bd03f601c3fc13732def921c5bac282676", 1); + + const update_owners_encoder encoder; + const auto tx = encoder.encode(owners_weights, "1.35.0"); + BOOST_CHECK_EQUAL(tx, "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000"); + + owners_weights.emplace_back("09ee460834498a4ee361beb819470061b7381b49", 1); + const auto tx1 = encoder.encode(owners_weights, "1.36.1"); + BOOST_CHECK_EQUAL(tx1, "0x23ab6adf0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000"); +} + +BOOST_AUTO_TEST_CASE(raw_transaction_serialization_test) { + raw_transaction raw_tr; + raw_tr.nonce = "0x0"; + raw_tr.gas_price = "0x3b9aca07"; + raw_tr.gas_limit = "0x7a1200"; + raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348"; + raw_tr.value = ""; + raw_tr.data = ""; + raw_tr.chain_id = "0x21"; + + const auto tx = raw_tr.serialize(); + BOOST_CHECK_EQUAL(tx, "0xE480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C02903488080218080"); + + //! Change value + raw_tr.value = "0x1BC16D674EC80000"; + const auto tx1 = raw_tr.serialize(); + BOOST_CHECK_EQUAL(tx1, "0xEC80843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C0290348881BC16D674EC8000080218080"); + + //! Change data + raw_tr.data = "0x893d20e8"; + const auto tx2 = raw_tr.serialize(); + BOOST_CHECK_EQUAL(tx2, "0xF080843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C0290348881BC16D674EC8000084893D20E8218080"); +} + +BOOST_AUTO_TEST_CASE(raw_transaction_deserialization_test) { + const raw_transaction raw_tr{"E480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C02903488080218080"}; + + BOOST_CHECK_EQUAL(raw_tr.nonce, "0x0"); + BOOST_CHECK_EQUAL(raw_tr.gas_price, "0x3b9aca07"); + BOOST_CHECK_EQUAL(raw_tr.gas_limit, "0x7a1200"); + BOOST_CHECK_EQUAL(raw_tr.to, "0x875a7e0efe5140c80c5c822f99c02281c0290348"); + BOOST_CHECK_EQUAL(raw_tr.value, "0x0"); + BOOST_CHECK_EQUAL(raw_tr.data, ""); + BOOST_CHECK_EQUAL(raw_tr.chain_id, "0x21"); +} + +BOOST_AUTO_TEST_CASE(raw_transaction_hash_test) { + raw_transaction raw_tr; + raw_tr.nonce = "0x0"; + raw_tr.gas_price = "0x3b9aca07"; + raw_tr.gas_limit = "0x7a1200"; + raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348"; + raw_tr.value = ""; + raw_tr.data = ""; + raw_tr.chain_id = "0x21"; + + const auto tx = raw_tr.serialize(); + BOOST_CHECK_EQUAL(tx, "0xE480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C02903488080218080"); + + const auto hash = raw_tr.hash(); + const auto hash_str = fc::to_hex((char *)&hash[0], hash.size()); + BOOST_CHECK_EQUAL(hash_str, "34934410cd305f4fa4e75a2c9294d625d6fbba729b5642ed2ca757ead50bb1fb"); +} + +BOOST_AUTO_TEST_CASE(sign_transaction_test) { + raw_transaction raw_tr; + raw_tr.nonce = "0x0"; + raw_tr.gas_price = "0x3b9aca07"; + raw_tr.gas_limit = "0x7a1200"; + raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348"; + raw_tr.value = ""; + raw_tr.data = ""; + raw_tr.chain_id = "0x21"; + + const auto sign_tr = raw_tr.sign("eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060"); + BOOST_CHECK_EQUAL(sign_tr.r, "5f09de6ac850b2a9e94acd709c12d4e9adbabc6b72281ec0bbe13bca7e57c7ce"); + BOOST_CHECK_EQUAL(sign_tr.v, "65"); + BOOST_CHECK_EQUAL(sign_tr.s, "7ca5f26c5b3e25f14a32b18ac9a2a41b7c68efd3b04b118e1b1f4bf1c4e299b0"); +} + +BOOST_AUTO_TEST_CASE(sign_transaction_serialization_test) { + raw_transaction raw_tr; + raw_tr.nonce = "0x0"; + raw_tr.gas_price = "0x3b9aca07"; + raw_tr.gas_limit = "0x7a1200"; + raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348"; + raw_tr.value = ""; + raw_tr.data = ""; + raw_tr.chain_id = "0x21"; + + const auto sign_tr = raw_tr.sign("eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060"); + const auto tx = sign_tr.serialize(); + BOOST_CHECK_EQUAL(tx, "0xF86480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C0290348808065A05F09DE6AC850B2A9E94ACD709C12D4E9ADBABC6B72281EC0BBE13BCA7E57C7CEA07CA5F26C5B3E25F14A32B18AC9A2A41B7C68EFD3B04B118E1B1F4BF1C4E299B0"); +} + +BOOST_AUTO_TEST_CASE(sign_transaction_deserialization_test) { + const signed_transaction sign_tr{"0xF86480843B9ACA07837A120094875A7E0EFE5140C80C5C822F99C02281C0290348808065A05F09DE6AC850B2A9E94ACD709C12D4E9ADBABC6B72281EC0BBE13BCA7E57C7CEA07CA5F26C5B3E25F14A32B18AC9A2A41B7C68EFD3B04B118E1B1F4BF1C4E299B0"}; + + BOOST_CHECK_EQUAL(sign_tr.nonce, "0x0"); + BOOST_CHECK_EQUAL(sign_tr.gas_price, "0x3b9aca07"); + BOOST_CHECK_EQUAL(sign_tr.gas_limit, "0x7a1200"); + BOOST_CHECK_EQUAL(sign_tr.to, "0x875a7e0efe5140c80c5c822f99c02281c0290348"); + BOOST_CHECK_EQUAL(sign_tr.value, "0x0"); + BOOST_CHECK_EQUAL(sign_tr.data, ""); +} + +BOOST_AUTO_TEST_CASE(sign_transaction_recover_test) { + const std::string chain_id = "0x21"; + + raw_transaction raw_tr; + raw_tr.nonce = "0x0"; + raw_tr.gas_price = "0x3b9aca07"; + raw_tr.gas_limit = "0x7a1200"; + raw_tr.to = "0x875a7e0eFe5140c80C5c822f99C02281C0290348"; + raw_tr.value = ""; + raw_tr.data = ""; + raw_tr.chain_id = chain_id; + + const auto sign_tr = raw_tr.sign("eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060"); + const auto from = sign_tr.recover(chain_id); + BOOST_CHECK_EQUAL(from, "0x5fbbb31be52608d2f52247e8400b7fcaa9e0bc12"); +} + +BOOST_AUTO_TEST_SUITE_END() -- 2.45.2