peerplays_migrated/libraries/plugins/peerplays_sidechain/ethereum/transaction.cpp
2022-08-19 17:34:57 +03:00

202 lines
5.5 KiB
C++

#include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
#include <boost/algorithm/hex.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <secp256k1.h>
#include <sha3/sha3.h>
#include <fc/crypto/elliptic.hpp>
#include <fc/crypto/hex.hpp>
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
namespace
{
int is_even(char last_char)
{
switch (last_char)
{
case '0':
return 1;
case '2':
return 1;
case '4':
return 1;
case '6':
return 1;
case '8':
return 1;
case 'A':
return 1;
case 'C':
return 1;
case 'E':
return 1;
default:
return -1;
}
}
}
const secp256k1_context *eth_context() {
static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
return ctx;
}
//! transaction
const transaction& transaction::sign(const std::string& private_key) const
{
return *this;
}
std::string transaction::serialize() const
{
boost::property_tree::ptree pt;
pt.put("from", from);
pt.put("to", to);
pt.put("data", data);
std::stringstream ss;
boost::property_tree::json_parser::write_json(ss, pt);
return ss.str();
}
void transaction::deserialize(const std::string& raw_tx)
{
std::stringstream ss_tx(raw_tx);
boost::property_tree::ptree tx_json;
boost::property_tree::read_json(ss_tx, tx_json);
if(tx_json.count("from"))
from = tx_json.get<std::string>("from");
if(tx_json.count("to"))
to = tx_json.get<std::string>("to");
if(tx_json.count("data"))
data = tx_json.get<std::string>("data");
}
//! raw_transaction
signed_transaction raw_transaction::sign(const std::string& private_key) const
{
//! Prepare signed transaction
signed_transaction tr;
tr.nonce = nonce;
tr.gas_price = gas_price;
tr.gas_limit = gas_limit;
tr.to = to;
tr.value = value;
tr.data = data;
//! Calculate keccak hash of transaction
bytes hash;
hash.resize(32);
const auto transaction_string = boost::algorithm::unhex( serialize() );
keccak_256((const unsigned char *) transaction_string.data(), transaction_string.size(), (unsigned char *) hash.data());
const bytes priv_key = parse_hex(private_key);
secp256k1_ecdsa_signature sign;
FC_ASSERT(secp256k1_ecdsa_sign(eth_context(), &sign, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), secp256k1_nonce_function_rfc6979, nullptr));
fc::ecc::compact_signature result;
FC_ASSERT(secp256k1_ecdsa_signature_serialize_compact(eth_context(), (unsigned char*) result.begin() + 1, &sign));
bytes r;
for(int i = 1; i < 33; i++)
r.emplace_back((char) result.at(i));
bytes s;
for(int i = 33; i < 65; i++)
s.emplace_back((char) result.at(i));
bytes v;
if(is_even(r.back()))
v = {37};
else
v = {38};
tr.v = fc::to_hex((char *)&v[0], v.size());
tr.r = fc::to_hex((char *)&r[0], r.size());
tr.s = fc::to_hex((char *)&s[0], s.size());
return tr;
}
std::string raw_transaction::serialize() const
{
rlp_encoder encoder;
const std::string serialized = encoder.encode(nonce) +
encoder.encode(gas_price) +
encoder.encode(gas_limit) +
encoder.encode(to) +
encoder.encode(value) +
encoder.encode(data) +
encoder.encode(chain_id) +
encoder.encode("") +
encoder.encode("");
return bytes2hex( 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(raw_tx);
FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format");
nonce = rlp_array.at(0);
gas_price = rlp_array.at(1);
gas_limit = rlp_array.at(2);
to = rlp_array.at(3);
value = rlp_array.at(4);
data = rlp_array.at(5);
chain_id = rlp_array.at(6);
}
//! signed_transaction
std::string signed_transaction::serialize() const
{
rlp_encoder encoder;
const std::string serialized = encoder.encode(nonce) +
encoder.encode(gas_price) +
encoder.encode(gas_limit) +
encoder.encode(to) +
encoder.encode(value) +
encoder.encode(data) +
encoder.encode(v) +
encoder.encode(r) +
encoder.encode(s);
return bytes2hex( 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(raw_tx);
FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format");
nonce = rlp_array.at(0);
gas_price = rlp_array.at(1);
gas_limit = rlp_array.at(2);
to = rlp_array.at(3);
value = rlp_array.at(4);
data = rlp_array.at(5);
v = rlp_array.at(6);
r = rlp_array.at(7);
s = rlp_array.at(8);
}
}}} // namespace graphene::peerplays_sidechain::ethereum