Fix signing of eth transaction. Calculate v value
This commit is contained in:
parent
adc6743ef0
commit
6c2bf868c5
5 changed files with 88 additions and 86 deletions
|
|
@ -4,6 +4,8 @@
|
||||||
#include <boost/algorithm/hex.hpp>
|
#include <boost/algorithm/hex.hpp>
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
//! base_encoder
|
//! base_encoder
|
||||||
|
|
@ -71,9 +73,9 @@ std::string rlp_encoder::encode_length(int len, int offset)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const std::string hexLength = int2Hex(len);
|
const std::string hexLength = to_hex(len);
|
||||||
const int lLength = hexLength.size()/2;
|
const int lLength = hexLength.size()/2;
|
||||||
const std::string fByte = int2Hex(offset+55+lLength);
|
const std::string fByte = to_hex(offset+55+lLength);
|
||||||
return hex2bytes(fByte+hexLength);
|
return hex2bytes(fByte+hexLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -94,16 +96,6 @@ std::string rlp_encoder::encode_rlp(const std::string& s)
|
||||||
return encode_length(s.size(), 128) + s;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rlp_encoder::char2int(char input)
|
int rlp_encoder::char2int(char input)
|
||||||
{
|
{
|
||||||
if(input >= '0' && input <= '9')
|
if(input >= '0' && input <= '9')
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
#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 <secp256k1_recovery.h>
|
||||||
#include <sha3/sha3.h>
|
#include <sha3/sha3.h>
|
||||||
|
|
||||||
#include <fc/crypto/elliptic.hpp>
|
#include <fc/crypto/elliptic.hpp>
|
||||||
|
|
@ -18,36 +18,6 @@
|
||||||
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
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() {
|
const secp256k1_context *eth_context() {
|
||||||
static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
|
static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
|
||||||
return ctx;
|
return ctx;
|
||||||
|
|
@ -107,12 +77,13 @@ signed_transaction raw_transaction::sign(const std::string& private_key) const
|
||||||
|
|
||||||
const bytes priv_key = parse_hex(private_key);
|
const bytes priv_key = parse_hex(private_key);
|
||||||
|
|
||||||
secp256k1_ecdsa_signature sign;
|
int recid = 0;
|
||||||
FC_ASSERT(secp256k1_ecdsa_sign(eth_context(), &sign, (const unsigned char *)hash.data(), (const unsigned char *)priv_key.data(), secp256k1_nonce_function_rfc6979, nullptr));
|
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::ecc::compact_signature result;
|
fc::ecc::compact_signature result;
|
||||||
FC_ASSERT(secp256k1_ecdsa_signature_serialize_compact(eth_context(), (unsigned char*) result.begin() + 1, &sign));
|
FC_ASSERT(secp256k1_ecdsa_recoverable_signature_serialize_compact(eth_context(), (unsigned char *)result.begin() + 1, &recid, &sig));
|
||||||
|
|
||||||
|
bytes v = bytes{char(recid + from_hex<int>(chain_id) * 2 + 35)};
|
||||||
bytes r;
|
bytes r;
|
||||||
for(int i = 1; i < 33; i++)
|
for(int i = 1; i < 33; i++)
|
||||||
r.emplace_back((char) result.at(i));
|
r.emplace_back((char) result.at(i));
|
||||||
|
|
@ -120,12 +91,6 @@ signed_transaction raw_transaction::sign(const std::string& private_key) const
|
||||||
for(int i = 33; i < 65; i++)
|
for(int i = 33; i < 65; i++)
|
||||||
s.emplace_back((char) result.at(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.v = fc::to_hex((char *)&v[0], v.size());
|
||||||
tr.r = fc::to_hex((char *)&r[0], r.size());
|
tr.r = fc::to_hex((char *)&r[0], r.size());
|
||||||
tr.s = fc::to_hex((char *)&s[0], s.size());
|
tr.s = fc::to_hex((char *)&s[0], s.size());
|
||||||
|
|
@ -136,13 +101,13 @@ signed_transaction raw_transaction::sign(const std::string& private_key) const
|
||||||
std::string raw_transaction::serialize() const
|
std::string raw_transaction::serialize() const
|
||||||
{
|
{
|
||||||
rlp_encoder encoder;
|
rlp_encoder encoder;
|
||||||
const std::string serialized = encoder.encode(nonce) +
|
const std::string serialized = encoder.encode(remove_0x(nonce)) +
|
||||||
encoder.encode(gas_price) +
|
encoder.encode(remove_0x(gas_price)) +
|
||||||
encoder.encode(gas_limit) +
|
encoder.encode(remove_0x(gas_limit)) +
|
||||||
encoder.encode(to) +
|
encoder.encode(remove_0x(to)) +
|
||||||
encoder.encode(value) +
|
encoder.encode(remove_0x(value)) +
|
||||||
encoder.encode(data) +
|
encoder.encode(remove_0x(data)) +
|
||||||
encoder.encode(chain_id) +
|
encoder.encode(remove_0x(chain_id)) +
|
||||||
encoder.encode("") +
|
encoder.encode("") +
|
||||||
encoder.encode("");
|
encoder.encode("");
|
||||||
|
|
||||||
|
|
@ -155,13 +120,13 @@ void raw_transaction::deserialize(const std::string& raw_tx)
|
||||||
const auto rlp_array = decoder.decode(raw_tx);
|
const auto rlp_array = decoder.decode(raw_tx);
|
||||||
FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format");
|
FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format");
|
||||||
|
|
||||||
nonce = rlp_array.at(0);
|
nonce = add_0x(rlp_array.at(0));
|
||||||
gas_price = rlp_array.at(1);
|
gas_price = add_0x(rlp_array.at(1));
|
||||||
gas_limit = rlp_array.at(2);
|
gas_limit = add_0x(rlp_array.at(2));
|
||||||
to = rlp_array.at(3);
|
to = add_0x(rlp_array.at(3));
|
||||||
value = rlp_array.at(4);
|
value = add_0x(rlp_array.at(4));
|
||||||
data = rlp_array.at(5);
|
data = add_0x(rlp_array.at(5));
|
||||||
chain_id = rlp_array.at(6);
|
chain_id = add_0x(rlp_array.at(6));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! signed_transaction
|
//! signed_transaction
|
||||||
|
|
@ -169,15 +134,15 @@ void raw_transaction::deserialize(const std::string& raw_tx)
|
||||||
std::string signed_transaction::serialize() const
|
std::string signed_transaction::serialize() const
|
||||||
{
|
{
|
||||||
rlp_encoder encoder;
|
rlp_encoder encoder;
|
||||||
const std::string serialized = encoder.encode(nonce) +
|
const std::string serialized = encoder.encode(remove_0x(nonce)) +
|
||||||
encoder.encode(gas_price) +
|
encoder.encode(remove_0x(gas_price)) +
|
||||||
encoder.encode(gas_limit) +
|
encoder.encode(remove_0x(gas_limit)) +
|
||||||
encoder.encode(to) +
|
encoder.encode(remove_0x(to)) +
|
||||||
encoder.encode(value) +
|
encoder.encode(remove_0x(value)) +
|
||||||
encoder.encode(data) +
|
encoder.encode(remove_0x(data)) +
|
||||||
encoder.encode(v) +
|
encoder.encode(remove_0x(v)) +
|
||||||
encoder.encode(r) +
|
encoder.encode(remove_0x(r)) +
|
||||||
encoder.encode(s);
|
encoder.encode(remove_0x(s));
|
||||||
|
|
||||||
return bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized );
|
return bytes2hex( encoder.encode_length(serialized.size(), 192) + serialized );
|
||||||
}
|
}
|
||||||
|
|
@ -188,15 +153,15 @@ void signed_transaction::deserialize(const std::string& raw_tx)
|
||||||
const auto rlp_array = decoder.decode(raw_tx);
|
const auto rlp_array = decoder.decode(raw_tx);
|
||||||
FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format");
|
FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format");
|
||||||
|
|
||||||
nonce = rlp_array.at(0);
|
nonce = add_0x(rlp_array.at(0));
|
||||||
gas_price = rlp_array.at(1);
|
gas_price = add_0x(rlp_array.at(1));
|
||||||
gas_limit = rlp_array.at(2);
|
gas_limit = add_0x(rlp_array.at(2));
|
||||||
to = rlp_array.at(3);
|
to = add_0x(rlp_array.at(3));
|
||||||
value = rlp_array.at(4);
|
value = add_0x(rlp_array.at(4));
|
||||||
data = rlp_array.at(5);
|
data = add_0x(rlp_array.at(5));
|
||||||
v = rlp_array.at(6);
|
v = add_0x(rlp_array.at(6));
|
||||||
r = rlp_array.at(7);
|
r = add_0x(rlp_array.at(7));
|
||||||
s = rlp_array.at(8);
|
s = add_0x(rlp_array.at(8));
|
||||||
}
|
}
|
||||||
|
|
||||||
}}} // namespace graphene::peerplays_sidechain::ethereum
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
|
||||||
|
|
@ -34,4 +34,24 @@ std::string uchar2Hex(unsigned char n)
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string add_0x(const std::string& s)
|
||||||
|
{
|
||||||
|
if(s.size() > 1) {
|
||||||
|
if (s.substr(0, 2) == "0x")
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "0x" + s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string remove_0x(const std::string& s)
|
||||||
|
{
|
||||||
|
if(s.size() > 1) {
|
||||||
|
if (s.substr(0, 2) == "0x")
|
||||||
|
return s.substr(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
}}} // namespace graphene::peerplays_sidechain::ethereum
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::string encode_rlp(const std::string& s);
|
static std::string encode_rlp(const std::string& s);
|
||||||
static std::string int2Hex(int n);
|
|
||||||
static int char2int(char input);
|
static int char2int(char input);
|
||||||
static void hex2bin(const char* src, char* target);
|
static void hex2bin(const char* src, char* target);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,30 @@ std::string bytes2hex(const std::string& s);
|
||||||
|
|
||||||
std::string uchar2Hex(unsigned char n);
|
std::string uchar2Hex(unsigned char n);
|
||||||
|
|
||||||
|
std::string add_0x(const std::string& s);
|
||||||
|
|
||||||
|
std::string remove_0x(const std::string& s);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::string to_hex( const T& val )
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << std::hex << val;
|
||||||
|
std::string result( stream.str() );
|
||||||
|
if(result.size() % 2)
|
||||||
|
result = "0"+result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T from_hex( const std::string& s )
|
||||||
|
{
|
||||||
|
T val;
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << std::hex << s;
|
||||||
|
stream >> val;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
}}} // namespace graphene::peerplays_sidechain::ethereum
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue