1) raw_transaction

2) signed_transaction
3) rlp_encoder classes
This commit is contained in:
Vlad Dobromyslov 2022-08-18 14:54:44 +03:00
parent b24b204e79
commit e6d980d092
8 changed files with 321 additions and 27 deletions

View file

@ -22,6 +22,7 @@ add_library( peerplays_sidechain
ethereum/decoders.cpp
ethereum/transaction.cpp
ethereum/types.cpp
ethereum/utils.cpp
hive/asset.cpp
hive/operations.cpp
hive/transaction.cpp

View file

@ -1,5 +1,6 @@
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
#include <stdlib.h>
#include <boost/algorithm/hex.hpp>
#include <boost/format.hpp>
@ -54,4 +55,98 @@ std::string withdrawal_encoder::encode(const std::string& to, boost::multiprecis
}
//! rlp_encoder
std::string rlp_encoder::encode(const std::string& s)
{
return encode_rlp(hex2bytes(s));
}
std::string rlp_encoder::encode_length(int len, int offset)
{
if(len<56)
{
std::string temp;
temp=(char)(len+offset);
return temp;
}
else
{
std::string hexLength = int2Hex(len);
int lLength = hexLength.size()/2;
std::string fByte = int2Hex(offset+55+lLength);
return hex2bytes(fByte+hexLength);
}
}
std::string rlp_encoder::hex2bytes(const std::string& s)
{
std::string dest;
dest.resize(s.size()/2);
hex2bin(s.c_str(), &dest[0]);
return dest;
}
std::string rlp_encoder::bytes2hex(const std::string& s)
{
std::string dest;
for( const auto& i : s )
dest += uchar2Hex((unsigned char)i);
return dest;
}
std::string rlp_encoder::encode_rlp(const std::string& s)
{
if(s.size()==1 && (unsigned char)s[0]<128)
return s;
else
return encode_length(s.size(), 128) + s;
}
std::string rlp_encoder::int2Hex(int n)
{
std::stringstream stream;
stream << std::hex << n;
std::string result( stream.str() );
if(result.size() % 2)
result = "0"+result;
return result;
}
std::string rlp_encoder::uchar2Hex(unsigned char n)
{
std::string dest;
dest.resize(2);
sprintf(&dest[0], "%X", n);
if(n < (unsigned char)16)
{
dest[1] = dest[0];
dest[0] = '0';
}
return dest;
}
int rlp_encoder::char2int(char input)
{
if(input >= '0' && input <= '9')
return input - '0';
if(input >= 'A' && input <= 'F')
return input - 'A' + 10;
if(input >= 'a' && input <= 'f')
return input - 'a' + 10;
return -1;
}
void rlp_encoder::hex2bin(const char* src, char* target)
{
while(*src && src[1])
{
*(target++) = char2int(*src)*16 + char2int(src[1]);
src += 2;
}
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -1,16 +1,61 @@
#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/types.hpp>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
const transaction& transaction::sign(std::string private_key) const
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
{
/* v = "signed";
r = "transaction";
s = "signed-transaction";
return v + "|" + r + "|" + s;*/
return *this;
}
@ -26,7 +71,7 @@ std::string transaction::serialize() const
return ss.str();
}
void transaction::deserialize(std::string raw_tx)
void transaction::deserialize(const std::string& raw_tx)
{
std::stringstream ss_tx(raw_tx);
boost::property_tree::ptree tx_json;
@ -40,4 +85,93 @@ void transaction::deserialize(std::string raw_tx)
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("8") +
encoder.encode("0");
return encoder.bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized );
}
void raw_transaction::deserialize(const std::string& raw_tx)
{
}
//! 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 encoder.bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized );
}
void signed_transaction::deserialize(const std::string& raw_tx)
{
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -0,0 +1,13 @@
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
#include <fc/crypto/hex.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
bytes parse_hex(const std::string &str) {
bytes vec(str.size() / 2);
fc::from_hex(str, vec.data(), vec.size());
return vec;
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -27,6 +27,21 @@ public:
std::string encode(const std::string& to, boost::multiprecision::uint256_t amount, const std::string& object_id) const;
};
class rlp_encoder {
public:
static std::string encode(const std::string& s);
static std::string encode_length(int len, int offset);
static std::string hex2bytes(const std::string& s);
static std::string bytes2hex(const std::string& s);
private:
static std::string encode_rlp(const std::string& s);
static std::string int2Hex(int n);
static std::string uchar2Hex(unsigned char n);
static int char2int(char input);
static void hex2bin(const char* src, char* target);
};
/*class ethereum_function_call_encoder {
public:
enum operation_t {

View file

@ -6,33 +6,58 @@
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
class transaction {
class base_transaction
{
virtual std::string serialize() const = 0;
virtual void deserialize(const std::string& raw_tx) = 0;
};
class transaction : base_transaction
{
public:
//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 data;
//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;
const transaction& sign(std::string private_key) const;
const transaction& sign(const std::string& private_key) const;
std::string serialize() const;
void deserialize(std::string raw_tx);
virtual std::string serialize() const override;
virtual void deserialize(const std::string& raw_tx) override;
};
class signed_transaction;
class raw_transaction : base_transaction
{
public:
std::string nonce;
std::string gas_price;
std::string gas_limit;
std::string to;
std::string value;
std::string data;
std::string chain_id;
signed_transaction sign(const std::string& private_key) const;
virtual std::string serialize() const override;
virtual void deserialize(const std::string& raw_tx) override;
};
class signed_transaction : base_transaction
{
public:
std::string nonce;
std::string gas_price;
std::string gas_limit;
std::string to;
std::string value;
std::string data;
std::string v;
std::string r;
std::string s;
virtual std::string serialize() const override;
virtual void deserialize(const std::string& raw_tx) override;
};
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -7,4 +7,6 @@ namespace graphene { namespace peerplays_sidechain { namespace ethereum {
typedef uint64_t chain_id_type;
typedef uint64_t network_id_type;
using bytes = std::vector<char>;
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -0,0 +1,9 @@
#pragma once
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
bytes parse_hex(const std::string &str);
}}} // namespace graphene::peerplays_sidechain::ethereum