1) raw_transaction
2) signed_transaction 3) rlp_encoder classes
This commit is contained in:
parent
b24b204e79
commit
e6d980d092
8 changed files with 321 additions and 27 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
13
libraries/plugins/peerplays_sidechain/ethereum/utils.cpp
Normal file
13
libraries/plugins/peerplays_sidechain/ethereum/utils.cpp
Normal 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
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in a new issue