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/decoders.cpp
|
||||||
ethereum/transaction.cpp
|
ethereum/transaction.cpp
|
||||||
ethereum/types.cpp
|
ethereum/types.cpp
|
||||||
|
ethereum/utils.cpp
|
||||||
hive/asset.cpp
|
hive/asset.cpp
|
||||||
hive/operations.cpp
|
hive/operations.cpp
|
||||||
hive/transaction.cpp
|
hive/transaction.cpp
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
|
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <boost/algorithm/hex.hpp>
|
#include <boost/algorithm/hex.hpp>
|
||||||
#include <boost/format.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
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,61 @@
|
||||||
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
|
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
|
||||||
|
|
||||||
|
#include <boost/algorithm/hex.hpp>
|
||||||
#include <boost/property_tree/json_parser.hpp>
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
#include <boost/property_tree/ptree.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 {
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,7 +71,7 @@ std::string transaction::serialize() const
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void transaction::deserialize(std::string raw_tx)
|
void transaction::deserialize(const std::string& raw_tx)
|
||||||
{
|
{
|
||||||
std::stringstream ss_tx(raw_tx);
|
std::stringstream ss_tx(raw_tx);
|
||||||
boost::property_tree::ptree tx_json;
|
boost::property_tree::ptree tx_json;
|
||||||
|
|
@ -40,4 +85,93 @@ void transaction::deserialize(std::string raw_tx)
|
||||||
data = tx_json.get<std::string>("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("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
|
}}} // 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;
|
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 {
|
/*class ethereum_function_call_encoder {
|
||||||
public:
|
public:
|
||||||
enum operation_t {
|
enum operation_t {
|
||||||
|
|
|
||||||
|
|
@ -6,33 +6,58 @@
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
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:
|
public:
|
||||||
//std::string block_hash;
|
|
||||||
//std::string block_number;
|
|
||||||
std::string from;
|
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 to;
|
||||||
std::string data;
|
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;
|
virtual std::string serialize() const override;
|
||||||
void deserialize(std::string raw_tx);
|
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
|
}}} // 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 chain_id_type;
|
||||||
typedef uint64_t network_id_type;
|
typedef uint64_t network_id_type;
|
||||||
|
|
||||||
|
using bytes = std::vector<char>;
|
||||||
|
|
||||||
}}} // namespace graphene::peerplays_sidechain::ethereum
|
}}} // 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