Merge branch 'feature/son-for-ethereum' of https://gitlab.com/PBSA/peerplays into feature/son-for-ethereum
This commit is contained in:
commit
4458965649
21 changed files with 1542 additions and 302 deletions
4
.gitmodules
vendored
4
.gitmodules
vendored
|
|
@ -7,7 +7,3 @@
|
||||||
url = https://gitlab.com/PBSA/tools-libs/peerplays-fc.git
|
url = https://gitlab.com/PBSA/tools-libs/peerplays-fc.git
|
||||||
branch = develop
|
branch = develop
|
||||||
ignore = dirty
|
ignore = dirty
|
||||||
[submodule "libraries/vendor/SHA3IUF"]
|
|
||||||
path = libraries/vendor/SHA3IUF
|
|
||||||
url = https://github.com/brainhub/SHA3IUF.git
|
|
||||||
branch = master
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ add_subdirectory( egenesis )
|
||||||
add_subdirectory( fc )
|
add_subdirectory( fc )
|
||||||
add_subdirectory( net )
|
add_subdirectory( net )
|
||||||
add_subdirectory( plugins )
|
add_subdirectory( plugins )
|
||||||
|
add_subdirectory( sha3 )
|
||||||
add_subdirectory( time )
|
add_subdirectory( time )
|
||||||
add_subdirectory( utilities )
|
add_subdirectory( utilities )
|
||||||
add_subdirectory( vendor )
|
|
||||||
add_subdirectory( wallet )
|
add_subdirectory( wallet )
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -41,11 +42,9 @@ endif()
|
||||||
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS)
|
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS)
|
||||||
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE)
|
unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE)
|
||||||
|
|
||||||
target_link_directories( peerplays_sidechain PUBLIC ${SHA3IUF_link_dirs} )
|
target_link_libraries( peerplays_sidechain PRIVATE graphene_plugin sha3 zmq )
|
||||||
target_link_libraries( peerplays_sidechain PRIVATE graphene_plugin zmq ${SHA3IUF_libraries} )
|
target_include_directories( peerplays_sidechain
|
||||||
target_include_directories( peerplays_sidechain PUBLIC
|
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
|
||||||
"${SHA3IUF_include_dirs}" )
|
|
||||||
|
|
||||||
install( TARGETS
|
install( TARGETS
|
||||||
peerplays_sidechain
|
peerplays_sidechain
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,224 @@
|
||||||
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
|
#include <graphene/peerplays_sidechain/ethereum/decoders.hpp>
|
||||||
|
|
||||||
|
#include <fc/exception/exception.hpp>
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
//! rlp_decoder
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const signed char p_util_hexdigit[256] =
|
||||||
|
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> rlp_decoder::decode(const std::string &str) {
|
||||||
|
size_t consumed = 0;
|
||||||
|
const auto raw_vec = parse_hex(str);
|
||||||
|
const std::vector<std::string> rlp_array = decode_rlp(raw_vec.data(), raw_vec.size(), consumed);
|
||||||
|
std::vector<std::string> result_array;
|
||||||
|
for (const auto &rlp : decode_rlp(raw_vec.data(), raw_vec.size(), consumed)) {
|
||||||
|
result_array.emplace_back(bytes2hex(rlp));
|
||||||
|
}
|
||||||
|
return result_array;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> rlp_decoder::decode_rlp(const unsigned char *raw, size_t len, size_t &consumed) {
|
||||||
|
std::vector<std::string> rlp_result;
|
||||||
|
|
||||||
|
consumed = 0;
|
||||||
|
|
||||||
|
const unsigned char *end = raw + len;
|
||||||
|
const size_t prefixlen = 1;
|
||||||
|
unsigned char ch = *raw;
|
||||||
|
|
||||||
|
if (len < 1) {
|
||||||
|
return rlp_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 1: [prefix is 1-byte data buffer]
|
||||||
|
if (ch <= 0x7f) {
|
||||||
|
const unsigned char *tok_start = raw;
|
||||||
|
const unsigned char *tok_end = tok_start + prefixlen;
|
||||||
|
FC_ASSERT(tok_end <= end);
|
||||||
|
|
||||||
|
// parsing done; assign data buffer value.
|
||||||
|
const std::vector<unsigned char> buf{tok_start, tok_end};
|
||||||
|
rlp_result.emplace_back(buf.cbegin(), buf.cend());
|
||||||
|
|
||||||
|
consumed = buf.size();
|
||||||
|
}
|
||||||
|
// Case 2: [prefix, including buffer length][data]
|
||||||
|
else if ((ch >= 0x80) && (ch <= 0xb7)) {
|
||||||
|
const size_t blen = ch - 0x80;
|
||||||
|
const size_t expected = prefixlen + blen;
|
||||||
|
|
||||||
|
if (len < expected)
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
const unsigned char *tok_start = raw + 1;
|
||||||
|
const unsigned char *tok_end = tok_start + blen;
|
||||||
|
FC_ASSERT(tok_end <= end);
|
||||||
|
|
||||||
|
// require minimal encoding
|
||||||
|
if ((blen == 1) && (tok_start[0] <= 0x7f))
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
// parsing done; assign data buffer value.
|
||||||
|
const std::vector<unsigned char> buf{tok_start, tok_end};
|
||||||
|
rlp_result.emplace_back(buf.cbegin(), buf.cend());
|
||||||
|
|
||||||
|
consumed = expected;
|
||||||
|
}
|
||||||
|
// Case 3: [prefix][buffer length][data]
|
||||||
|
else if ((ch >= 0xb8) && (ch <= 0xbf)) {
|
||||||
|
const size_t uintlen = ch - 0xb7;
|
||||||
|
size_t expected = prefixlen + uintlen;
|
||||||
|
|
||||||
|
if (len < expected)
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen);
|
||||||
|
|
||||||
|
const unsigned char *tok_start = raw + prefixlen;
|
||||||
|
if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
// read buffer length
|
||||||
|
const uint64_t slen = to_int(tok_start, uintlen);
|
||||||
|
|
||||||
|
// validate buffer length, including possible addition overflows.
|
||||||
|
expected = prefixlen + uintlen + slen;
|
||||||
|
if ((slen < (RLP_listStart - RLP_bufferLenStart - RLP_maxUintLen)) || (expected > len) || (slen > len))
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
// parsing done; assign data buffer value.
|
||||||
|
tok_start = raw + prefixlen + uintlen;
|
||||||
|
const unsigned char *tok_end = tok_start + slen;
|
||||||
|
const std::vector<unsigned char> buf{tok_start, tok_end};
|
||||||
|
rlp_result.emplace_back(buf.cbegin(), buf.cend());
|
||||||
|
|
||||||
|
consumed = expected;
|
||||||
|
}
|
||||||
|
// Case 4: [prefix][list]
|
||||||
|
else if ((ch >= 0xc0) && (ch <= 0xf7)) {
|
||||||
|
const size_t payloadlen = ch - 0xc0;
|
||||||
|
const size_t expected = prefixlen + payloadlen;
|
||||||
|
|
||||||
|
// read list payload
|
||||||
|
const auto array = decode_array(raw, len, 0, payloadlen);
|
||||||
|
rlp_result.insert(rlp_result.end(), array.cbegin(), array.cend());
|
||||||
|
|
||||||
|
consumed = expected;
|
||||||
|
}
|
||||||
|
// Case 5: [prefix][list length][list]
|
||||||
|
else {
|
||||||
|
FC_ASSERT((ch >= 0xf8) && (ch <= 0xff));
|
||||||
|
|
||||||
|
const size_t uintlen = ch - 0xf7;
|
||||||
|
const size_t expected = prefixlen + uintlen;
|
||||||
|
|
||||||
|
if (len < expected)
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
FC_ASSERT(uintlen > 0 && uintlen <= RLP_maxUintLen);
|
||||||
|
|
||||||
|
const unsigned char *tok_start = raw + prefixlen;
|
||||||
|
if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
// read list length
|
||||||
|
const size_t payloadlen = to_int(tok_start, uintlen);
|
||||||
|
|
||||||
|
// special requirement for non-immediate length
|
||||||
|
if (payloadlen < (0x100 - RLP_listStart - RLP_maxUintLen))
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
// read list payload
|
||||||
|
const auto array = decode_array(raw, len, uintlen, payloadlen);
|
||||||
|
rlp_result.insert(rlp_result.end(), array.cbegin(), array.cend());
|
||||||
|
|
||||||
|
consumed = prefixlen + uintlen + payloadlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rlp_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> rlp_decoder::decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen) {
|
||||||
|
std::vector<std::string> rlp_result;
|
||||||
|
const size_t prefixlen = 1;
|
||||||
|
|
||||||
|
// validate list length, including possible addition overflows.
|
||||||
|
const size_t expected = prefixlen + uintlen + payloadlen;
|
||||||
|
if ((expected > len) || (payloadlen > len))
|
||||||
|
return std::vector<std::string>{};
|
||||||
|
|
||||||
|
size_t child_len = payloadlen;
|
||||||
|
const unsigned char *list_ent = raw + prefixlen + uintlen;
|
||||||
|
|
||||||
|
// recursively read until payloadlen bytes parsed, or error
|
||||||
|
while (child_len > 0) {
|
||||||
|
size_t child_consumed = 0;
|
||||||
|
|
||||||
|
const auto val = decode_rlp(list_ent, child_len, child_consumed);
|
||||||
|
rlp_result.insert(rlp_result.end(), val.cbegin(), val.cend());
|
||||||
|
|
||||||
|
list_ent += child_consumed;
|
||||||
|
child_len -= child_consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rlp_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t rlp_decoder::to_int(const unsigned char *raw, size_t len) {
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
else if (len == 1)
|
||||||
|
return *raw;
|
||||||
|
else
|
||||||
|
return (raw[len - 1]) + (to_int(raw, len - 1) * 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> rlp_decoder::parse_hex(const std::string &str) {
|
||||||
|
return parse_hex(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> rlp_decoder::parse_hex(const char *psz) {
|
||||||
|
// convert hex dump to vector
|
||||||
|
std::vector<unsigned char> vch;
|
||||||
|
while (true) {
|
||||||
|
while (isspace(*psz))
|
||||||
|
psz++;
|
||||||
|
signed char c = hex_digit(*psz++);
|
||||||
|
if (c == (signed char)-1)
|
||||||
|
break;
|
||||||
|
unsigned char n = (c << 4);
|
||||||
|
c = hex_digit(*psz++);
|
||||||
|
if (c == (signed char)-1)
|
||||||
|
break;
|
||||||
|
n |= c;
|
||||||
|
vch.push_back(n);
|
||||||
|
}
|
||||||
|
return vch;
|
||||||
|
}
|
||||||
|
|
||||||
|
signed char rlp_decoder::hex_digit(char c) {
|
||||||
|
return p_util_hexdigit[(unsigned char)c];
|
||||||
|
}
|
||||||
|
|
||||||
}}} // namespace graphene::peerplays_sidechain::ethereum
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,102 @@
|
||||||
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
|
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
|
||||||
|
|
||||||
|
#include <boost/algorithm/hex.hpp>
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
//! base_encoder
|
||||||
|
std::string base_encoder::encode_uint256(boost::multiprecision::uint256_t value) {
|
||||||
|
return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string base_encoder::encode_address(const std::string &value) {
|
||||||
|
return (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value)).str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string base_encoder::encode_string(const std::string &value) {
|
||||||
|
std::string data = (boost::format("%x") % boost::io::group(std::setw(64), std::setfill('0'), value.size())).str();
|
||||||
|
data += boost::algorithm::hex(value) + std::string((64 - value.size() * 2 % 64), '0');
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! update_owners_encoder
|
||||||
|
std::string update_owners_encoder::encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id) const {
|
||||||
|
std::string data = "0x" + function_signature;
|
||||||
|
data += base_encoder::encode_uint256(64);
|
||||||
|
data += base_encoder::encode_uint256((owners_weights.size() * 2 + 3) * 32);
|
||||||
|
data += base_encoder::encode_uint256(owners_weights.size());
|
||||||
|
for (const auto &owner : owners_weights) {
|
||||||
|
data += base_encoder::encode_address(owner.first);
|
||||||
|
data += base_encoder::encode_uint256(owner.second);
|
||||||
|
}
|
||||||
|
data += base_encoder::encode_string(object_id);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! withdrawal_encoder
|
||||||
|
std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) const {
|
||||||
|
std::string data = "0x" + function_signature;
|
||||||
|
data += base_encoder::encode_address(to);
|
||||||
|
data += base_encoder::encode_uint256(amount);
|
||||||
|
data += base_encoder::encode_uint256(32 * 3);
|
||||||
|
data += base_encoder::encode_string(object_id);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! 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 {
|
||||||
|
const std::string hexLength = to_hex(len);
|
||||||
|
const int lLength = hexLength.size() / 2;
|
||||||
|
const std::string fByte = to_hex(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::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,22 +1,158 @@
|
||||||
#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/ptree.hpp>
|
||||||
|
|
||||||
|
#include <secp256k1_recovery.h>
|
||||||
|
#include <sha3/sha3.h>
|
||||||
|
|
||||||
|
#include <fc/crypto/elliptic.hpp>
|
||||||
|
#include <fc/crypto/hex.hpp>
|
||||||
|
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/decoders.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 {
|
||||||
|
|
||||||
std::string transaction::sign(std::string private_key) {
|
const secp256k1_context *eth_context() {
|
||||||
v = "signed";
|
static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
|
||||||
r = "transaction";
|
return ctx;
|
||||||
s = "signed-transaction";
|
|
||||||
return v + "|" + r + "|" + s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string transaction::serialize() {
|
//! transaction
|
||||||
return "serialized-transaction";
|
|
||||||
|
const transaction &transaction::sign(const std::string &private_key) const {
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void transaction::deserialize(std::string raw_tx) {
|
std::string transaction::serialize() const {
|
||||||
block_hash = "1";
|
boost::property_tree::ptree pt;
|
||||||
block_number = "2";
|
pt.put("from", from);
|
||||||
hash = "3";
|
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(remove_0x(serialize()));
|
||||||
|
keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data());
|
||||||
|
|
||||||
|
const bytes priv_key = parse_hex(private_key);
|
||||||
|
|
||||||
|
int recid = 0;
|
||||||
|
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_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;
|
||||||
|
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));
|
||||||
|
|
||||||
|
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(remove_0x(nonce)) +
|
||||||
|
encoder.encode(remove_0x(gas_price)) +
|
||||||
|
encoder.encode(remove_0x(gas_limit)) +
|
||||||
|
encoder.encode(remove_0x(to)) +
|
||||||
|
encoder.encode(remove_0x(value)) +
|
||||||
|
encoder.encode(remove_0x(data)) +
|
||||||
|
encoder.encode(remove_0x(chain_id)) +
|
||||||
|
encoder.encode("") +
|
||||||
|
encoder.encode("");
|
||||||
|
|
||||||
|
return add_0x(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(remove_0x(raw_tx));
|
||||||
|
FC_ASSERT(rlp_array.size() >= 7, "Wrong rlp format");
|
||||||
|
|
||||||
|
nonce = add_0x(rlp_array.at(0));
|
||||||
|
gas_price = add_0x(rlp_array.at(1));
|
||||||
|
gas_limit = add_0x(rlp_array.at(2));
|
||||||
|
to = add_0x(rlp_array.at(3));
|
||||||
|
value = add_0x(rlp_array.at(4));
|
||||||
|
data = add_0x(rlp_array.at(5));
|
||||||
|
chain_id = add_0x(rlp_array.at(6));
|
||||||
|
}
|
||||||
|
|
||||||
|
//! signed_transaction
|
||||||
|
|
||||||
|
std::string signed_transaction::serialize() const {
|
||||||
|
rlp_encoder encoder;
|
||||||
|
const std::string serialized = encoder.encode(remove_0x(nonce)) +
|
||||||
|
encoder.encode(remove_0x(gas_price)) +
|
||||||
|
encoder.encode(remove_0x(gas_limit)) +
|
||||||
|
encoder.encode(remove_0x(to)) +
|
||||||
|
encoder.encode(remove_0x(value)) +
|
||||||
|
encoder.encode(remove_0x(data)) +
|
||||||
|
encoder.encode(remove_0x(v)) +
|
||||||
|
encoder.encode(remove_0x(r)) +
|
||||||
|
encoder.encode(remove_0x(s));
|
||||||
|
|
||||||
|
return add_0x(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(remove_0x(raw_tx));
|
||||||
|
FC_ASSERT(rlp_array.size() >= 9, "Wrong rlp format");
|
||||||
|
|
||||||
|
nonce = add_0x(rlp_array.at(0));
|
||||||
|
gas_price = add_0x(rlp_array.at(1));
|
||||||
|
gas_limit = add_0x(rlp_array.at(2));
|
||||||
|
to = add_0x(rlp_array.at(3));
|
||||||
|
value = add_0x(rlp_array.at(4));
|
||||||
|
data = add_0x(rlp_array.at(5));
|
||||||
|
v = add_0x(rlp_array.at(6));
|
||||||
|
r = add_0x(rlp_array.at(7));
|
||||||
|
s = add_0x(rlp_array.at(8));
|
||||||
}
|
}
|
||||||
|
|
||||||
}}} // namespace graphene::peerplays_sidechain::ethereum
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
|
||||||
52
libraries/plugins/peerplays_sidechain/ethereum/utils.cpp
Normal file
52
libraries/plugins/peerplays_sidechain/ethereum/utils.cpp
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string bytes2hex(const std::string &s) {
|
||||||
|
std::string dest;
|
||||||
|
for (const auto &i : s)
|
||||||
|
dest += uchar2Hex((unsigned char)i);
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
@ -5,4 +5,24 @@
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
class rlp_decoder {
|
||||||
|
private:
|
||||||
|
enum RLP_constants {
|
||||||
|
RLP_maxUintLen = 8,
|
||||||
|
RLP_bufferLenStart = 0x80,
|
||||||
|
RLP_listStart = 0xc0,
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static std::vector<std::string> decode(const std::string &str);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::vector<std::string> decode_rlp(const unsigned char *raw, size_t len, size_t &consumed);
|
||||||
|
static std::vector<std::string> decode_array(const unsigned char *raw, size_t len, size_t uintlen, size_t payloadlen);
|
||||||
|
static uint64_t to_int(const unsigned char *raw, size_t len);
|
||||||
|
static std::vector<unsigned char> parse_hex(const std::string &str);
|
||||||
|
static std::vector<unsigned char> parse_hex(const char *psz);
|
||||||
|
static signed char hex_digit(char c);
|
||||||
|
};
|
||||||
|
|
||||||
}}} // namespace graphene::peerplays_sidechain::ethereum
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,45 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/multiprecision/cpp_int.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
class ethereum_function_call_encoder {
|
class base_encoder {
|
||||||
|
public:
|
||||||
|
static std::string encode_uint256(boost::multiprecision::uint256_t value);
|
||||||
|
static std::string encode_address(const std::string &value);
|
||||||
|
static std::string encode_string(const std::string &value);
|
||||||
|
};
|
||||||
|
|
||||||
|
class update_owners_encoder {
|
||||||
|
public:
|
||||||
|
const std::string function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string)
|
||||||
|
|
||||||
|
std::string encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class withdrawal_encoder {
|
||||||
|
public:
|
||||||
|
const std::string function_signature = "e088747b"; //! withdraw(address,uint256,string)
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::string encode_rlp(const std::string &s);
|
||||||
|
static int char2int(char input);
|
||||||
|
static void hex2bin(const char *src, char *target);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*class ethereum_function_call_encoder {
|
||||||
public:
|
public:
|
||||||
enum operation_t {
|
enum operation_t {
|
||||||
OPERATION_CALL,
|
OPERATION_CALL,
|
||||||
|
|
@ -34,6 +68,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ethereum_function_call_encoder m_ethereum_function_call_encoder;
|
ethereum_function_call_encoder m_ethereum_function_call_encoder;
|
||||||
};
|
};*/
|
||||||
|
|
||||||
}}} // namespace graphene::peerplays_sidechain::ethereum
|
}}} // namespace graphene::peerplays_sidechain::ethereum
|
||||||
|
|
|
||||||
|
|
@ -6,32 +6,54 @@
|
||||||
|
|
||||||
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 transaction_index;
|
std::string data;
|
||||||
|
|
||||||
|
const 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;
|
||||||
|
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 value;
|
||||||
std::string type;
|
std::string data;
|
||||||
std::vector<std::string> access_list;
|
|
||||||
std::string chain_id;
|
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 v;
|
||||||
std::string r;
|
std::string r;
|
||||||
std::string s;
|
std::string s;
|
||||||
|
|
||||||
std::string sign(std::string private_key);
|
virtual std::string serialize() const override;
|
||||||
|
virtual void deserialize(const std::string &raw_tx) override;
|
||||||
std::string serialize();
|
|
||||||
void deserialize(std::string raw_tx);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}}} // 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,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
|
||||||
|
|
||||||
|
bytes parse_hex(const std::string &str);
|
||||||
|
|
||||||
|
std::string bytes2hex(const std::string &s);
|
||||||
|
|
||||||
|
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
|
||||||
|
|
@ -19,9 +19,18 @@ public:
|
||||||
std::string eth_get_block_by_number(std::string block_number, bool full_block);
|
std::string eth_get_block_by_number(std::string block_number, bool full_block);
|
||||||
std::string eth_get_logs(std::string wallet_contract_address);
|
std::string eth_get_logs(std::string wallet_contract_address);
|
||||||
std::string net_version();
|
std::string net_version();
|
||||||
|
std::string eth_get_transaction_count(const std::string ¶ms);
|
||||||
|
std::string eth_gas_price();
|
||||||
|
|
||||||
std::string get_chain_id();
|
std::string get_chain_id();
|
||||||
std::string get_network_id();
|
std::string get_network_id();
|
||||||
|
std::string get_nonce(const std::string &address);
|
||||||
|
std::string get_gas_price();
|
||||||
|
std::string get_gas_limit();
|
||||||
|
|
||||||
|
std::string eth_send_transaction(const std::string ¶ms);
|
||||||
|
std::string eth_send_raw_transaction(const std::string ¶ms);
|
||||||
|
std::string eth_get_transaction_receipt(const std::string ¶ms);
|
||||||
};
|
};
|
||||||
|
|
||||||
class sidechain_net_handler_ethereum : public sidechain_net_handler {
|
class sidechain_net_handler_ethereum : public sidechain_net_handler {
|
||||||
|
|
@ -49,14 +58,11 @@ private:
|
||||||
ethereum::chain_id_type chain_id;
|
ethereum::chain_id_type chain_id;
|
||||||
ethereum::network_id_type network_id;
|
ethereum::network_id_type network_id;
|
||||||
|
|
||||||
std::string create_primary_wallet_address(const std::vector<son_info> &son_pubkeys);
|
std::string create_primary_wallet_transaction(const std::vector<son_info> &son_pubkeys, const std::string &object_id);
|
||||||
|
|
||||||
std::string create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address);
|
|
||||||
std::string create_deposit_transaction(const son_wallet_deposit_object &swdo);
|
std::string create_deposit_transaction(const son_wallet_deposit_object &swdo);
|
||||||
std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo);
|
std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo);
|
||||||
|
|
||||||
std::string sign_transaction(const sidechain_transaction_object &sto);
|
std::string sign_transaction(const sidechain_transaction_object &sto);
|
||||||
std::string send_transaction(const sidechain_transaction_object &sto);
|
|
||||||
|
|
||||||
uint64_t last_block_received;
|
uint64_t last_block_received;
|
||||||
fc::future<void> _listener_task;
|
fc::future<void> _listener_task;
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include <boost/algorithm/hex.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/format.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>
|
||||||
|
|
||||||
|
|
@ -17,8 +16,11 @@
|
||||||
#include <graphene/chain/sidechain_transaction_object.hpp>
|
#include <graphene/chain/sidechain_transaction_object.hpp>
|
||||||
#include <graphene/chain/son_info.hpp>
|
#include <graphene/chain/son_info.hpp>
|
||||||
#include <graphene/chain/son_wallet_object.hpp>
|
#include <graphene/chain/son_wallet_object.hpp>
|
||||||
|
#include <graphene/peerplays_sidechain/ethereum/encoders.hpp>
|
||||||
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
|
#include <graphene/peerplays_sidechain/ethereum/transaction.hpp>
|
||||||
#include <graphene/utilities/key_conversion.hpp>
|
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
|
||||||
|
|
||||||
|
#define SEND_RAW_TRANSACTION 1
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
|
|
@ -45,6 +47,14 @@ std::string ethereum_rpc_client::net_version() {
|
||||||
return send_post_request("net_version", "", debug_rpc_calls);
|
return send_post_request("net_version", "", debug_rpc_calls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ethereum_rpc_client::eth_get_transaction_count(const std::string ¶ms) {
|
||||||
|
return send_post_request("eth_getTransactionCount", params, debug_rpc_calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ethereum_rpc_client::eth_gas_price() {
|
||||||
|
return send_post_request("eth_gasPrice", "", debug_rpc_calls);
|
||||||
|
}
|
||||||
|
|
||||||
std::string ethereum_rpc_client::get_chain_id() {
|
std::string ethereum_rpc_client::get_chain_id() {
|
||||||
std::string reply_str = net_version();
|
std::string reply_str = net_version();
|
||||||
return retrieve_value_from_reply(reply_str, "");
|
return retrieve_value_from_reply(reply_str, "");
|
||||||
|
|
@ -55,6 +65,43 @@ std::string ethereum_rpc_client::get_network_id() {
|
||||||
return retrieve_value_from_reply(reply_str, "protocols.eth.network");
|
return retrieve_value_from_reply(reply_str, "protocols.eth.network");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ethereum_rpc_client::get_nonce(const std::string &address) {
|
||||||
|
std::string reply_str = eth_get_transaction_count("[\"" + address + "\", \"latest\"]");
|
||||||
|
const auto nonce_val = ethereum::from_hex<boost::multiprecision::uint256_t>(retrieve_value_from_reply(reply_str, ""));
|
||||||
|
return nonce_val == 0 ? ethereum::add_0x("0") : ethereum::add_0x(ethereum::to_hex(nonce_val));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ethereum_rpc_client::get_gas_price() {
|
||||||
|
std::string reply_str = eth_gas_price();
|
||||||
|
return retrieve_value_from_reply(reply_str, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ethereum_rpc_client::get_gas_limit() {
|
||||||
|
std::string reply_str = eth_get_block_by_number("latest", false);
|
||||||
|
if (!reply_str.empty()) {
|
||||||
|
std::stringstream ss(reply_str);
|
||||||
|
boost::property_tree::ptree json;
|
||||||
|
boost::property_tree::read_json(ss, json);
|
||||||
|
if (json.count("result")) {
|
||||||
|
std::string gas_limit_s = json.get<std::string>("result.gasLimit");
|
||||||
|
return gas_limit_s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::string{};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ethereum_rpc_client::eth_send_transaction(const std::string ¶ms) {
|
||||||
|
return send_post_request("eth_sendTransaction", "[" + params + "]", debug_rpc_calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ethereum_rpc_client::eth_send_raw_transaction(const std::string ¶ms) {
|
||||||
|
return send_post_request("eth_sendRawTransaction", "[ \"" + params + "\" ]", debug_rpc_calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ethereum_rpc_client::eth_get_transaction_receipt(const std::string ¶ms) {
|
||||||
|
return send_post_request("eth_getTransactionReceipt", "[\"" + params + "\"]", debug_rpc_calls);
|
||||||
|
}
|
||||||
|
|
||||||
sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
|
sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
|
||||||
sidechain_net_handler(_plugin, options) {
|
sidechain_net_handler(_plugin, options) {
|
||||||
sidechain = sidechain_type::ethereum;
|
sidechain = sidechain_type::ethereum;
|
||||||
|
|
@ -146,80 +193,45 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po)
|
||||||
const auto swo = idx.find(swo_id);
|
const auto swo = idx.find(swo_id);
|
||||||
if (swo != idx.end()) {
|
if (swo != idx.end()) {
|
||||||
|
|
||||||
//auto active_sons = gpo.active_sons;
|
auto active_sons = gpo.active_sons;
|
||||||
//vector<son_info> wallet_sons = swo->sons;
|
vector<son_info> wallet_sons = swo->sons;
|
||||||
//
|
|
||||||
//bool son_sets_equal = (active_sons.size() == wallet_sons.size());
|
|
||||||
//
|
|
||||||
//if (son_sets_equal) {
|
|
||||||
// for (size_t i = 0; i < active_sons.size(); i++) {
|
|
||||||
// son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//if (son_sets_equal) {
|
|
||||||
// address_ok = (op_obj_idx_0.get<son_wallet_update_operation>().address == wallet_account_name);
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//if (po.proposed_transaction.operations.size() >= 2) {
|
|
||||||
// object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
|
|
||||||
// std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
|
|
||||||
//
|
|
||||||
// const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
|
|
||||||
// const auto st = st_idx.find(object_id);
|
|
||||||
// if (st == st_idx.end()) {
|
|
||||||
//
|
|
||||||
// std::string tx_str = "";
|
|
||||||
//
|
|
||||||
// if (object_id.is<son_wallet_id_type>()) {
|
|
||||||
// const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
|
||||||
// const auto swo = idx.find(object_id);
|
|
||||||
// if (swo != idx.end()) {
|
|
||||||
//
|
|
||||||
// std::stringstream ss_trx(boost::algorithm::unhex(op_tx_str));
|
|
||||||
// hive::signed_transaction op_trx;
|
|
||||||
// fc::raw::unpack(ss_trx, op_trx, 1000);
|
|
||||||
//
|
|
||||||
// fc::flat_map<std::string, uint16_t> account_auths;
|
|
||||||
// uint32_t total_weight = 0;
|
|
||||||
// for (const auto &wallet_son : wallet_sons) {
|
|
||||||
// total_weight = total_weight + wallet_son.weight;
|
|
||||||
// account_auths[wallet_son.sidechain_public_keys.at(sidechain)] = wallet_son.weight;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// std::string memo_key = rpc_client->get_account_memo_key(wallet_account_name);
|
|
||||||
//
|
|
||||||
// hive::authority active;
|
|
||||||
// active.weight_threshold = total_weight * 2 / 3 + 1;
|
|
||||||
// active.account_auths = account_auths;
|
|
||||||
//
|
|
||||||
// hive::account_update_operation auo;
|
|
||||||
// auo.account = wallet_account_name;
|
|
||||||
// auo.active = active;
|
|
||||||
// auo.memo_key = op_trx.operations[0].get<hive::account_update_operation>().memo_key;
|
|
||||||
//
|
|
||||||
// hive::signed_transaction htrx;
|
|
||||||
// htrx.ref_block_num = op_trx.ref_block_num;
|
|
||||||
// htrx.ref_block_prefix = op_trx.ref_block_prefix;
|
|
||||||
// htrx.set_expiration(op_trx.expiration);
|
|
||||||
//
|
|
||||||
// htrx.operations.push_back(auo);
|
|
||||||
//
|
|
||||||
// std::stringstream ss;
|
|
||||||
// fc::raw::pack(ss, htrx, 1000);
|
|
||||||
// tx_str = boost::algorithm::hex(ss.str());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// transaction_ok = (op_tx_str == tx_str);
|
|
||||||
// }
|
|
||||||
//} else {
|
|
||||||
// transaction_ok = true;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
address_ok = true;
|
bool son_sets_equal = (active_sons.size() == wallet_sons.size());
|
||||||
transaction_ok = true;
|
|
||||||
|
if (son_sets_equal) {
|
||||||
|
for (size_t i = 0; i < active_sons.size(); i++) {
|
||||||
|
son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (son_sets_equal) {
|
||||||
|
address_ok = (op_obj_idx_0.get<son_wallet_update_operation>().address == wallet_contract_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (po.proposed_transaction.operations.size() >= 2) {
|
||||||
|
object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
|
||||||
|
std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
|
||||||
|
|
||||||
|
const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
|
||||||
|
const auto st = st_idx.find(object_id);
|
||||||
|
if (st == st_idx.end()) {
|
||||||
|
|
||||||
|
std::string tx_str = "";
|
||||||
|
|
||||||
|
if (object_id.is<son_wallet_id_type>()) {
|
||||||
|
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||||
|
const auto swo = idx.find(object_id);
|
||||||
|
if (swo != idx.end()) {
|
||||||
|
tx_str = create_primary_wallet_transaction(gpo.active_sons, object_id.operator std::string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction_ok = (op_tx_str == tx_str);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
transaction_ok = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
should_approve = address_ok &&
|
should_approve = address_ok &&
|
||||||
transaction_ok;
|
transaction_ok;
|
||||||
|
|
@ -298,81 +310,48 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po)
|
||||||
const auto &idx = database.get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
|
const auto &idx = database.get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
|
||||||
const auto swwo = idx.find(swwo_id);
|
const auto swwo = idx.find(swwo_id);
|
||||||
if (swwo != idx.end()) {
|
if (swwo != idx.end()) {
|
||||||
|
uint32_t swwo_block_num = swwo->block_num;
|
||||||
|
std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id;
|
||||||
|
uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1));
|
||||||
|
|
||||||
//uint32_t swwo_block_num = swwo->block_num;
|
const auto &block = database.fetch_block_by_number(swwo_block_num);
|
||||||
//std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id;
|
|
||||||
//uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1));
|
for (const auto &tx : block->transactions) {
|
||||||
//
|
if (tx.id().str() == swwo_peerplays_transaction_id) {
|
||||||
//const auto &block = database.fetch_block_by_number(swwo_block_num);
|
operation op = tx.operations[swwo_op_idx];
|
||||||
//
|
transfer_operation t_op = op.get<transfer_operation>();
|
||||||
//for (const auto &tx : block->transactions) {
|
|
||||||
// if (tx.id().str() == swwo_peerplays_transaction_id) {
|
price asset_price = database.get<asset_object>(t_op.amount.asset_id).options.core_exchange_rate;
|
||||||
// operation op = tx.operations[swwo_op_idx];
|
asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount);
|
||||||
// transfer_operation t_op = op.get<transfer_operation>();
|
|
||||||
//
|
process_ok = (t_op.to == gpo.parameters.son_account()) &&
|
||||||
// price asset_price = database.get<asset_object>(t_op.amount.asset_id).options.core_exchange_rate;
|
(swwo->peerplays_from == t_op.from) &&
|
||||||
// asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount);
|
(swwo->peerplays_asset == peerplays_asset);
|
||||||
//
|
break;
|
||||||
// process_ok = (t_op.to == gpo.parameters.son_account()) &&
|
}
|
||||||
// (swwo->peerplays_from == t_op.from) &&
|
}
|
||||||
// (swwo->peerplays_asset == peerplays_asset);
|
|
||||||
// break;
|
object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
|
||||||
// }
|
std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
|
||||||
//}
|
|
||||||
//
|
const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
|
||||||
//object_id_type object_id = op_obj_idx_1.get<sidechain_transaction_create_operation>().object_id;
|
const auto st = st_idx.find(object_id);
|
||||||
//std::string op_tx_str = op_obj_idx_1.get<sidechain_transaction_create_operation>().transaction;
|
if (st == st_idx.end()) {
|
||||||
//
|
|
||||||
//const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
|
std::string tx_str = "";
|
||||||
//const auto st = st_idx.find(object_id);
|
|
||||||
//if (st == st_idx.end()) {
|
if (object_id.is<son_wallet_withdraw_id_type>()) {
|
||||||
//
|
const auto &idx = database.get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
|
||||||
// std::string tx_str = "";
|
const auto swwo = idx.find(object_id);
|
||||||
//
|
if (swwo != idx.end()) {
|
||||||
// if (object_id.is<son_wallet_withdraw_id_type>()) {
|
tx_str = create_withdrawal_transaction(*swwo);
|
||||||
// const auto &idx = database.get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
|
}
|
||||||
// const auto swwo = idx.find(object_id);
|
}
|
||||||
// if (swwo != idx.end()) {
|
|
||||||
//
|
transaction_ok = (op_tx_str == tx_str);
|
||||||
// std::stringstream ss_trx(boost::algorithm::unhex(op_tx_str));
|
}
|
||||||
// hive::signed_transaction op_trx;
|
|
||||||
// fc::raw::unpack(ss_trx, op_trx, 1000);
|
|
||||||
//
|
|
||||||
// uint64_t symbol = 0;
|
|
||||||
// if (swwo->withdraw_currency == "HBD") {
|
|
||||||
// symbol = hive::asset::hbd_symbol_ser;
|
|
||||||
// }
|
|
||||||
// if (swwo->withdraw_currency == "HIVE") {
|
|
||||||
// symbol = hive::asset::hive_symbol_ser;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// hive::transfer_operation t_op;
|
|
||||||
// t_op.from = wallet_account_name;
|
|
||||||
// t_op.to = swwo->withdraw_address;
|
|
||||||
// t_op.amount.amount = swwo->withdraw_amount;
|
|
||||||
// t_op.amount.symbol = symbol;
|
|
||||||
// t_op.memo = "";
|
|
||||||
//
|
|
||||||
// hive::signed_transaction htrx;
|
|
||||||
// htrx.ref_block_num = op_trx.ref_block_num;
|
|
||||||
// htrx.ref_block_prefix = op_trx.ref_block_prefix;
|
|
||||||
// htrx.set_expiration(op_trx.expiration);
|
|
||||||
//
|
|
||||||
// htrx.operations.push_back(t_op);
|
|
||||||
//
|
|
||||||
// std::stringstream ss;
|
|
||||||
// fc::raw::pack(ss, htrx, 1000);
|
|
||||||
// tx_str = boost::algorithm::hex(ss.str());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// transaction_ok = (op_tx_str == tx_str);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
process_ok = true;
|
|
||||||
transaction_ok = true;
|
|
||||||
|
|
||||||
should_approve = process_ok &&
|
should_approve = process_ok &&
|
||||||
transaction_ok;
|
transaction_ok;
|
||||||
break;
|
break;
|
||||||
|
|
@ -416,79 +395,62 @@ bool sidechain_net_handler_ethereum::process_proposal(const proposal_object &po)
|
||||||
}
|
}
|
||||||
|
|
||||||
void sidechain_net_handler_ethereum::process_primary_wallet() {
|
void sidechain_net_handler_ethereum::process_primary_wallet() {
|
||||||
//const auto &swi = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
const auto &swi = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||||
//const auto &active_sw = swi.rbegin();
|
const auto &active_sw = swi.rbegin();
|
||||||
//if (active_sw != swi.rend()) {
|
if (active_sw != swi.rend()) {
|
||||||
//
|
|
||||||
// if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) ||
|
if ((active_sw->addresses.find(sidechain_type::ethereum) == active_sw->addresses.end()) ||
|
||||||
// (active_sw->addresses.at(sidechain_type::ethereum).empty())) {
|
(active_sw->addresses.at(sidechain_type::ethereum).empty())) {
|
||||||
//
|
|
||||||
// if (proposal_exists(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) {
|
if (proposal_exists(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) {
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// const chain::global_property_object &gpo = database.get_global_properties();
|
if (!plugin.can_son_participate(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) {
|
||||||
//
|
return;
|
||||||
// auto active_sons = gpo.active_sons;
|
}
|
||||||
// string reply_str = create_primary_wallet_address(active_sons);
|
|
||||||
//
|
const chain::global_property_object &gpo = database.get_global_properties();
|
||||||
// std::stringstream active_pw_ss(reply_str);
|
proposal_create_operation proposal_op;
|
||||||
//
|
proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
|
||||||
// boost::property_tree::ptree active_pw_pt;
|
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||||
// boost::property_tree::read_json(active_pw_ss, active_pw_pt);
|
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
||||||
// if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) {
|
|
||||||
// if (!plugin.can_son_participate(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id)) {
|
son_wallet_update_operation swu_op;
|
||||||
// return;
|
swu_op.payer = gpo.parameters.son_account();
|
||||||
// }
|
swu_op.son_wallet_id = active_sw->id;
|
||||||
//
|
swu_op.sidechain = sidechain_type::ethereum;
|
||||||
// proposal_create_operation proposal_op;
|
swu_op.address = wallet_contract_address;
|
||||||
// proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
|
proposal_op.proposed_ops.emplace_back(swu_op);
|
||||||
// uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
|
||||||
// proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
std::string tx_str = create_primary_wallet_transaction(gpo.active_sons, active_sw->id.operator std::string());
|
||||||
//
|
if (!tx_str.empty()) {
|
||||||
// std::stringstream res;
|
sidechain_transaction_create_operation stc_op;
|
||||||
// boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result"));
|
stc_op.payer = gpo.parameters.son_account();
|
||||||
//
|
stc_op.object_id = active_sw->id;
|
||||||
// son_wallet_update_operation swu_op;
|
stc_op.sidechain = sidechain;
|
||||||
// swu_op.payer = gpo.parameters.son_account();
|
stc_op.transaction = tx_str;
|
||||||
// swu_op.son_wallet_id = active_sw->id;
|
stc_op.signers = gpo.active_sons;
|
||||||
// swu_op.sidechain = sidechain_type::ethereum;
|
proposal_op.proposed_ops.emplace_back(stc_op);
|
||||||
// swu_op.address = res.str();
|
}
|
||||||
//
|
|
||||||
// proposal_op.proposed_ops.emplace_back(swu_op);
|
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||||
//
|
try {
|
||||||
// const auto &prev_sw = std::next(active_sw);
|
trx.validate();
|
||||||
// if (prev_sw != swi.rend()) {
|
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||||
// std::string new_pw_address = active_pw_pt.get<std::string>("result.address");
|
if (plugin.app().p2p_node())
|
||||||
// std::string tx_str = create_primary_wallet_transaction(*prev_sw, new_pw_address);
|
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||||
// if (!tx_str.empty()) {
|
plugin.log_son_proposal_retry(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id);
|
||||||
// sidechain_transaction_create_operation stc_op;
|
} catch (fc::exception &e) {
|
||||||
// stc_op.payer = gpo.parameters.son_account();
|
elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what()));
|
||||||
// stc_op.object_id = prev_sw->id;
|
return;
|
||||||
// stc_op.sidechain = sidechain;
|
}
|
||||||
// stc_op.transaction = tx_str;
|
}
|
||||||
// stc_op.signers = prev_sw->sons;
|
}
|
||||||
// proposal_op.proposed_ops.emplace_back(stc_op);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
|
||||||
// try {
|
|
||||||
// trx.validate();
|
|
||||||
// database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
|
||||||
// if (plugin.app().p2p_node())
|
|
||||||
// plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
|
||||||
// plugin.log_son_proposal_retry(chain::operation::tag<chain::son_wallet_update_operation>::value, active_sw->id);
|
|
||||||
// } catch (fc::exception &e) {
|
|
||||||
// elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what()));
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sidechain_net_handler_ethereum::process_sidechain_addresses() {
|
void sidechain_net_handler_ethereum::process_sidechain_addresses() {
|
||||||
|
int temp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_object &swdo) {
|
bool sidechain_net_handler_ethereum::process_deposit(const son_wallet_deposit_object &swdo) {
|
||||||
|
|
@ -578,19 +540,93 @@ std::string sidechain_net_handler_ethereum::process_sidechain_transaction(const
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sidechain_transaction_object &sto) {
|
std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sidechain_transaction_object &sto) {
|
||||||
return send_transaction(sto);
|
boost::property_tree::ptree pt;
|
||||||
|
boost::property_tree::ptree pt_array;
|
||||||
|
for (const auto &signature : sto.signatures) {
|
||||||
|
const auto &transaction = signature.second;
|
||||||
|
|
||||||
|
//! Check if we have this signed transaction, if not, don't send it
|
||||||
|
if(transaction.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#ifdef SEND_RAW_TRANSACTION
|
||||||
|
const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(transaction);
|
||||||
|
#else
|
||||||
|
const std::string sidechain_transaction = rpc_client->eth_send_transaction(transaction);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::stringstream ss_tx(sidechain_transaction);
|
||||||
|
boost::property_tree::ptree tx_json;
|
||||||
|
boost::property_tree::read_json(ss_tx, tx_json);
|
||||||
|
if (tx_json.count("result") && !tx_json.count("error")) {
|
||||||
|
boost::property_tree::ptree node;
|
||||||
|
node.put("transaction", transaction);
|
||||||
|
node.put("transaction_receipt", tx_json.get<std::string>("result"));
|
||||||
|
pt_array.push_back(std::make_pair("", node));
|
||||||
|
} else {
|
||||||
|
//! Fixme
|
||||||
|
//! How should we proceed with error in eth_send_transaction
|
||||||
|
elog("Error in eth_send_transaction for transaction ${id}, transaction ${transaction}", ("id", sto.id)("transaction", transaction));
|
||||||
|
return std::string{}; //! Return empty string, as we have error in sending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pt.add_child("result_array", pt_array);
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
boost::property_tree::json_parser::write_json(ss, pt);
|
||||||
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) {
|
bool sidechain_net_handler_ethereum::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) {
|
||||||
return true;
|
std::stringstream ss(sto.sidechain_transaction);
|
||||||
|
boost::property_tree::ptree json;
|
||||||
|
boost::property_tree::read_json(ss, json);
|
||||||
|
|
||||||
|
if (!json.count("result_array")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t count = 0;
|
||||||
|
for (const auto &entry : json.get_child("result_array")) {
|
||||||
|
const std::string receipt = rpc_client->eth_get_transaction_receipt(entry.second.get<std::string>("transaction_receipt"));
|
||||||
|
|
||||||
|
std::stringstream ss_receipt(receipt);
|
||||||
|
boost::property_tree::ptree json_receipt;
|
||||||
|
boost::property_tree::read_json(ss_receipt, json_receipt);
|
||||||
|
|
||||||
|
if (json_receipt.get<std::string>("result") == "null") {
|
||||||
|
wlog("Block is not minted yet for transaction ${id}", ("id", sto.id));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("0x1" == json_receipt.get<std::string>("result.status")) {
|
||||||
|
count += 1;
|
||||||
|
//! Fixme - compare data somehow?
|
||||||
|
//if( sto.transaction == entry_receipt.second.get<std::string>("data") ) {
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Check that we have all transactions
|
||||||
|
if (count != json.get_child("result_array").size()) {
|
||||||
|
wlog("Not all receipts received for transaction ${id}", ("id", sto.id));
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sidechain_net_handler_ethereum::create_primary_wallet_address(const std::vector<son_info> &son_pubkeys) {
|
std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const std::vector<son_info> &son_pubkeys, const std::string &object_id) {
|
||||||
return "Primary Wallet Address";
|
std::vector<std::pair<std::string, uint16_t>> owners_weights;
|
||||||
}
|
for (auto &son : son_pubkeys) {
|
||||||
|
FC_ASSERT(son.sidechain_public_keys.contains(sidechain_type::ethereum), "No public keys for son: ${son_id}", ("son_id", son.son_id));
|
||||||
|
const std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::ethereum);
|
||||||
|
owners_weights.emplace_back(std::make_pair(pub_key_str, son.weight));
|
||||||
|
}
|
||||||
|
|
||||||
std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address) {
|
ethereum::update_owners_encoder encoder;
|
||||||
return "Primary-Wallet-Transaction";
|
return encoder.encode(owners_weights, object_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) {
|
std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) {
|
||||||
|
|
@ -598,16 +634,35 @@ std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) {
|
std::string sidechain_net_handler_ethereum::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) {
|
||||||
return "Withdrawal-Transaction";
|
ethereum::withdrawal_encoder encoder;
|
||||||
|
return encoder.encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) {
|
std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_transaction_object &sto) {
|
||||||
std::string key = get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain));
|
const auto ¤t_son = plugin.get_current_son_object();
|
||||||
return "Transaction-Signature-" + key;
|
FC_ASSERT(current_son.sidechain_public_keys.contains(sidechain_type::ethereum), "No public keys for current son: ${account_id}", ("account_id", current_son.son_account));
|
||||||
}
|
|
||||||
|
|
||||||
std::string sidechain_net_handler_ethereum::send_transaction(const sidechain_transaction_object &sto) {
|
const auto &public_key = current_son.sidechain_public_keys.at(sidechain);
|
||||||
return "Transaction-ID";
|
|
||||||
|
#ifdef SEND_RAW_TRANSACTION
|
||||||
|
ethereum::raw_transaction raw_tr;
|
||||||
|
raw_tr.nonce = rpc_client->get_nonce(ethereum::add_0x(public_key));
|
||||||
|
raw_tr.gas_price = rpc_client->get_gas_price();
|
||||||
|
raw_tr.gas_limit = rpc_client->get_gas_limit();
|
||||||
|
raw_tr.to = wallet_contract_address;
|
||||||
|
raw_tr.value = "";
|
||||||
|
raw_tr.data = sto.transaction;
|
||||||
|
raw_tr.chain_id = ethereum::add_0x(ethereum::to_hex(chain_id));
|
||||||
|
|
||||||
|
const auto sign_tr = raw_tr.sign(get_private_key(public_key));
|
||||||
|
return sign_tr.serialize();
|
||||||
|
#else
|
||||||
|
ethereum::transaction sign_transaction;
|
||||||
|
sign_transaction.data = sto.transaction;
|
||||||
|
sign_transaction.to = wallet_contract_address;
|
||||||
|
sign_transaction.from = "0x" + public_key;
|
||||||
|
return sign_transaction.sign(get_private_key(public_key)).serialize();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void sidechain_net_handler_ethereum::schedule_ethereum_listener() {
|
void sidechain_net_handler_ethereum::schedule_ethereum_listener() {
|
||||||
|
|
|
||||||
16
libraries/sha3/CMakeLists.txt
Normal file
16
libraries/sha3/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
file(GLOB HEADERS "include/sha3/*.h")
|
||||||
|
|
||||||
|
add_library( sha3
|
||||||
|
memzero.c
|
||||||
|
sha3.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories( sha3 PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include )
|
||||||
|
target_compile_definitions( sha3 PUBLIC USE_KECCAK=1 )
|
||||||
|
|
||||||
|
install( TARGETS
|
||||||
|
sha3
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
)
|
||||||
16
libraries/sha3/include/sha3/memzero.h
Normal file
16
libraries/sha3/include/sha3/memzero.h
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef __MEMZERO_H__
|
||||||
|
#define __MEMZERO_H__
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void memzero(void* const pnt, const size_t len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
88
libraries/sha3/include/sha3/sha3.h
Normal file
88
libraries/sha3/include/sha3/sha3.h
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
/* sha3.h - an implementation of Secure Hash Algorithm 3 (Keccak).
|
||||||
|
* based on the
|
||||||
|
* The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011
|
||||||
|
* by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche
|
||||||
|
*
|
||||||
|
* Copyright: 2013 Aleksey Kravchenko <rhash.admin@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SHA3_H__
|
||||||
|
#define __SHA3_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define sha3_224_hash_size 28
|
||||||
|
#define sha3_256_hash_size 32
|
||||||
|
#define sha3_384_hash_size 48
|
||||||
|
#define sha3_512_hash_size 64
|
||||||
|
#define sha3_max_permutation_size 25
|
||||||
|
#define sha3_max_rate_in_qwords 24
|
||||||
|
|
||||||
|
#define SHA3_224_BLOCK_LENGTH 144
|
||||||
|
#define SHA3_256_BLOCK_LENGTH 136
|
||||||
|
#define SHA3_384_BLOCK_LENGTH 104
|
||||||
|
#define SHA3_512_BLOCK_LENGTH 72
|
||||||
|
|
||||||
|
#define SHA3_224_DIGEST_LENGTH sha3_224_hash_size
|
||||||
|
#define SHA3_256_DIGEST_LENGTH sha3_256_hash_size
|
||||||
|
#define SHA3_384_DIGEST_LENGTH sha3_384_hash_size
|
||||||
|
#define SHA3_512_DIGEST_LENGTH sha3_512_hash_size
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHA3 Algorithm context.
|
||||||
|
*/
|
||||||
|
typedef struct SHA3_CTX
|
||||||
|
{
|
||||||
|
/* 1600 bits algorithm hashing state */
|
||||||
|
uint64_t hash[sha3_max_permutation_size];
|
||||||
|
/* 1536-bit buffer for leftovers */
|
||||||
|
uint64_t message[sha3_max_rate_in_qwords];
|
||||||
|
/* count of bytes in the message[] buffer */
|
||||||
|
unsigned rest;
|
||||||
|
/* size of a message block processed at once */
|
||||||
|
unsigned block_size;
|
||||||
|
} SHA3_CTX;
|
||||||
|
|
||||||
|
/* methods for calculating the hash function */
|
||||||
|
|
||||||
|
void sha3_224_Init(SHA3_CTX *ctx);
|
||||||
|
void sha3_256_Init(SHA3_CTX *ctx);
|
||||||
|
void sha3_384_Init(SHA3_CTX *ctx);
|
||||||
|
void sha3_512_Init(SHA3_CTX *ctx);
|
||||||
|
void sha3_Update(SHA3_CTX *ctx, const unsigned char* msg, size_t size);
|
||||||
|
void sha3_Final(SHA3_CTX *ctx, unsigned char* result);
|
||||||
|
|
||||||
|
#if USE_KECCAK
|
||||||
|
#define keccak_224_Init sha3_224_Init
|
||||||
|
#define keccak_256_Init sha3_256_Init
|
||||||
|
#define keccak_384_Init sha3_384_Init
|
||||||
|
#define keccak_512_Init sha3_512_Init
|
||||||
|
#define keccak_Update sha3_Update
|
||||||
|
void keccak_Final(SHA3_CTX *ctx, unsigned char* result);
|
||||||
|
void keccak_256(const unsigned char* data, size_t len, unsigned char* digest);
|
||||||
|
void keccak_512(const unsigned char* data, size_t len, unsigned char* digest);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void sha3_256(const unsigned char* data, size_t len, unsigned char* digest);
|
||||||
|
void sha3_512(const unsigned char* data, size_t len, unsigned char* digest);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif /* __SHA3_H__ */
|
||||||
75
libraries/sha3/memzero.c
Normal file
75
libraries/sha3/memzero.c
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
#ifndef __STDC_WANT_LIB_EXT1__
|
||||||
|
#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface.
|
||||||
|
#endif
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <Windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __unix__
|
||||||
|
#include <strings.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// C11's bounds-checking interface.
|
||||||
|
#if defined(__STDC_LIB_EXT1__)
|
||||||
|
#define HAVE_MEMSET_S 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// GNU C Library version 2.25 or later.
|
||||||
|
#if defined(__GLIBC__) && \
|
||||||
|
(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))
|
||||||
|
#define HAVE_EXPLICIT_BZERO 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Newlib
|
||||||
|
#if defined(__NEWLIB__)
|
||||||
|
#define HAVE_EXPLICIT_BZERO 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// FreeBSD version 11.0 or later.
|
||||||
|
#if defined(__FreeBSD__) && __FreeBSD_version >= 1100037
|
||||||
|
#define HAVE_EXPLICIT_BZERO 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// OpenBSD version 5.5 or later.
|
||||||
|
#if defined(__OpenBSD__) && OpenBSD >= 201405
|
||||||
|
#define HAVE_EXPLICIT_BZERO 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// NetBSD version 7.2 or later.
|
||||||
|
#if defined(__NetBSD__) && __NetBSD_Version__ >= 702000000
|
||||||
|
#define HAVE_EXPLICIT_MEMSET 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Adapted from
|
||||||
|
// https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130
|
||||||
|
|
||||||
|
void memzero(void *const pnt, const size_t len) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
SecureZeroMemory(pnt, len);
|
||||||
|
#elif defined(HAVE_MEMSET_S)
|
||||||
|
memset_s(pnt, (rsize_t)len, 0, (rsize_t)len);
|
||||||
|
#elif defined(HAVE_EXPLICIT_BZERO)
|
||||||
|
explicit_bzero(pnt, len);
|
||||||
|
#elif defined(HAVE_EXPLICIT_MEMSET)
|
||||||
|
explicit_memset(pnt, 0, len);
|
||||||
|
#else
|
||||||
|
volatile unsigned char *volatile pnt_ = (volatile unsigned char *volatile)pnt;
|
||||||
|
size_t i = (size_t)0U;
|
||||||
|
|
||||||
|
while (i < len) {
|
||||||
|
pnt_[i++] = 0U;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// explicitly mark the memory as overwritten for the Clang MemorySanitizer
|
||||||
|
// this is only included at compile time if MemorySanitizer is enabled and
|
||||||
|
// should not come with any downsides during regular builds
|
||||||
|
#if defined(__has_feature)
|
||||||
|
#if __has_feature(memory_sanitizer)
|
||||||
|
memset(pnt, 0, len);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
397
libraries/sha3/sha3.c
Normal file
397
libraries/sha3/sha3.c
Normal file
|
|
@ -0,0 +1,397 @@
|
||||||
|
/* sha3.c - an implementation of Secure Hash Algorithm 3 (Keccak).
|
||||||
|
* based on the
|
||||||
|
* The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011
|
||||||
|
* by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche
|
||||||
|
*
|
||||||
|
* Copyright: 2013 Aleksey Kravchenko <rhash.admin@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sha3/sha3.h>
|
||||||
|
#include <sha3/memzero.h>
|
||||||
|
|
||||||
|
#define I64(x) x##LL
|
||||||
|
#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n))))
|
||||||
|
#define le2me_64(x) (x)
|
||||||
|
#define IS_ALIGNED_64(p) (0 == (7 & ((long)(p)))) // [wallet-core] pointer/numerical type, for MacOS SDK 12.3
|
||||||
|
# define me64_to_le_str(to, from, length) memcpy((to), (from), (length))
|
||||||
|
|
||||||
|
/* constants */
|
||||||
|
#define NumberOfRounds 24
|
||||||
|
|
||||||
|
/* SHA3 (Keccak) constants for 24 rounds */
|
||||||
|
uint64_t keccak_round_constants[NumberOfRounds] = {
|
||||||
|
I64(0x0000000000000001), I64(0x0000000000008082), I64(0x800000000000808A), I64(0x8000000080008000),
|
||||||
|
I64(0x000000000000808B), I64(0x0000000080000001), I64(0x8000000080008081), I64(0x8000000000008009),
|
||||||
|
I64(0x000000000000008A), I64(0x0000000000000088), I64(0x0000000080008009), I64(0x000000008000000A),
|
||||||
|
I64(0x000000008000808B), I64(0x800000000000008B), I64(0x8000000000008089), I64(0x8000000000008003),
|
||||||
|
I64(0x8000000000008002), I64(0x8000000000000080), I64(0x000000000000800A), I64(0x800000008000000A),
|
||||||
|
I64(0x8000000080008081), I64(0x8000000000008080), I64(0x0000000080000001), I64(0x8000000080008008)
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Initializing a sha3 context for given number of output bits */
|
||||||
|
static void keccak_Init(SHA3_CTX *ctx, unsigned bits)
|
||||||
|
{
|
||||||
|
/* NB: The Keccak capacity parameter = bits * 2 */
|
||||||
|
unsigned rate = 1600 - bits * 2;
|
||||||
|
|
||||||
|
memzero(ctx, sizeof(SHA3_CTX));
|
||||||
|
ctx->block_size = rate / 8;
|
||||||
|
assert(rate <= 1600 && (rate % 64) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize context before calculating hash.
|
||||||
|
*
|
||||||
|
* @param ctx context to initialize
|
||||||
|
*/
|
||||||
|
void sha3_224_Init(SHA3_CTX *ctx)
|
||||||
|
{
|
||||||
|
keccak_Init(ctx, 224);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize context before calculating hash.
|
||||||
|
*
|
||||||
|
* @param ctx context to initialize
|
||||||
|
*/
|
||||||
|
void sha3_256_Init(SHA3_CTX *ctx)
|
||||||
|
{
|
||||||
|
keccak_Init(ctx, 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize context before calculating hash.
|
||||||
|
*
|
||||||
|
* @param ctx context to initialize
|
||||||
|
*/
|
||||||
|
void sha3_384_Init(SHA3_CTX *ctx)
|
||||||
|
{
|
||||||
|
keccak_Init(ctx, 384);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize context before calculating hash.
|
||||||
|
*
|
||||||
|
* @param ctx context to initialize
|
||||||
|
*/
|
||||||
|
void sha3_512_Init(SHA3_CTX *ctx)
|
||||||
|
{
|
||||||
|
keccak_Init(ctx, 512);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keccak theta() transformation */
|
||||||
|
static void keccak_theta(uint64_t *A)
|
||||||
|
{
|
||||||
|
unsigned int x = 0;
|
||||||
|
uint64_t C[5] = {0}, D[5] = {0};
|
||||||
|
|
||||||
|
for (x = 0; x < 5; x++) {
|
||||||
|
C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20];
|
||||||
|
}
|
||||||
|
D[0] = ROTL64(C[1], 1) ^ C[4];
|
||||||
|
D[1] = ROTL64(C[2], 1) ^ C[0];
|
||||||
|
D[2] = ROTL64(C[3], 1) ^ C[1];
|
||||||
|
D[3] = ROTL64(C[4], 1) ^ C[2];
|
||||||
|
D[4] = ROTL64(C[0], 1) ^ C[3];
|
||||||
|
|
||||||
|
for (x = 0; x < 5; x++) {
|
||||||
|
A[x] ^= D[x];
|
||||||
|
A[x + 5] ^= D[x];
|
||||||
|
A[x + 10] ^= D[x];
|
||||||
|
A[x + 15] ^= D[x];
|
||||||
|
A[x + 20] ^= D[x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keccak pi() transformation */
|
||||||
|
static void keccak_pi(uint64_t *A)
|
||||||
|
{
|
||||||
|
uint64_t A1 = 0;
|
||||||
|
A1 = A[1];
|
||||||
|
A[ 1] = A[ 6];
|
||||||
|
A[ 6] = A[ 9];
|
||||||
|
A[ 9] = A[22];
|
||||||
|
A[22] = A[14];
|
||||||
|
A[14] = A[20];
|
||||||
|
A[20] = A[ 2];
|
||||||
|
A[ 2] = A[12];
|
||||||
|
A[12] = A[13];
|
||||||
|
A[13] = A[19];
|
||||||
|
A[19] = A[23];
|
||||||
|
A[23] = A[15];
|
||||||
|
A[15] = A[ 4];
|
||||||
|
A[ 4] = A[24];
|
||||||
|
A[24] = A[21];
|
||||||
|
A[21] = A[ 8];
|
||||||
|
A[ 8] = A[16];
|
||||||
|
A[16] = A[ 5];
|
||||||
|
A[ 5] = A[ 3];
|
||||||
|
A[ 3] = A[18];
|
||||||
|
A[18] = A[17];
|
||||||
|
A[17] = A[11];
|
||||||
|
A[11] = A[ 7];
|
||||||
|
A[ 7] = A[10];
|
||||||
|
A[10] = A1;
|
||||||
|
/* note: A[ 0] is left as is */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keccak chi() transformation */
|
||||||
|
static void keccak_chi(uint64_t *A)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (i = 0; i < 25; i += 5) {
|
||||||
|
uint64_t A0 = A[0 + i], A1 = A[1 + i];
|
||||||
|
A[0 + i] ^= ~A1 & A[2 + i];
|
||||||
|
A[1 + i] ^= ~A[2 + i] & A[3 + i];
|
||||||
|
A[2 + i] ^= ~A[3 + i] & A[4 + i];
|
||||||
|
A[3 + i] ^= ~A[4 + i] & A0;
|
||||||
|
A[4 + i] ^= ~A0 & A1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sha3_permutation(uint64_t *state)
|
||||||
|
{
|
||||||
|
int round = 0;
|
||||||
|
for (round = 0; round < NumberOfRounds; round++)
|
||||||
|
{
|
||||||
|
keccak_theta(state);
|
||||||
|
|
||||||
|
/* apply Keccak rho() transformation */
|
||||||
|
state[ 1] = ROTL64(state[ 1], 1);
|
||||||
|
state[ 2] = ROTL64(state[ 2], 62);
|
||||||
|
state[ 3] = ROTL64(state[ 3], 28);
|
||||||
|
state[ 4] = ROTL64(state[ 4], 27);
|
||||||
|
state[ 5] = ROTL64(state[ 5], 36);
|
||||||
|
state[ 6] = ROTL64(state[ 6], 44);
|
||||||
|
state[ 7] = ROTL64(state[ 7], 6);
|
||||||
|
state[ 8] = ROTL64(state[ 8], 55);
|
||||||
|
state[ 9] = ROTL64(state[ 9], 20);
|
||||||
|
state[10] = ROTL64(state[10], 3);
|
||||||
|
state[11] = ROTL64(state[11], 10);
|
||||||
|
state[12] = ROTL64(state[12], 43);
|
||||||
|
state[13] = ROTL64(state[13], 25);
|
||||||
|
state[14] = ROTL64(state[14], 39);
|
||||||
|
state[15] = ROTL64(state[15], 41);
|
||||||
|
state[16] = ROTL64(state[16], 45);
|
||||||
|
state[17] = ROTL64(state[17], 15);
|
||||||
|
state[18] = ROTL64(state[18], 21);
|
||||||
|
state[19] = ROTL64(state[19], 8);
|
||||||
|
state[20] = ROTL64(state[20], 18);
|
||||||
|
state[21] = ROTL64(state[21], 2);
|
||||||
|
state[22] = ROTL64(state[22], 61);
|
||||||
|
state[23] = ROTL64(state[23], 56);
|
||||||
|
state[24] = ROTL64(state[24], 14);
|
||||||
|
|
||||||
|
keccak_pi(state);
|
||||||
|
keccak_chi(state);
|
||||||
|
|
||||||
|
/* apply iota(state, round) */
|
||||||
|
*state ^= keccak_round_constants[round];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The core transformation. Process the specified block of data.
|
||||||
|
*
|
||||||
|
* @param hash the algorithm state
|
||||||
|
* @param block the message block to process
|
||||||
|
* @param block_size the size of the processed block in bytes
|
||||||
|
*/
|
||||||
|
static void sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t block_size)
|
||||||
|
{
|
||||||
|
/* expanded loop */
|
||||||
|
hash[ 0] ^= le2me_64(block[ 0]);
|
||||||
|
hash[ 1] ^= le2me_64(block[ 1]);
|
||||||
|
hash[ 2] ^= le2me_64(block[ 2]);
|
||||||
|
hash[ 3] ^= le2me_64(block[ 3]);
|
||||||
|
hash[ 4] ^= le2me_64(block[ 4]);
|
||||||
|
hash[ 5] ^= le2me_64(block[ 5]);
|
||||||
|
hash[ 6] ^= le2me_64(block[ 6]);
|
||||||
|
hash[ 7] ^= le2me_64(block[ 7]);
|
||||||
|
hash[ 8] ^= le2me_64(block[ 8]);
|
||||||
|
/* if not sha3-512 */
|
||||||
|
if (block_size > 72) {
|
||||||
|
hash[ 9] ^= le2me_64(block[ 9]);
|
||||||
|
hash[10] ^= le2me_64(block[10]);
|
||||||
|
hash[11] ^= le2me_64(block[11]);
|
||||||
|
hash[12] ^= le2me_64(block[12]);
|
||||||
|
/* if not sha3-384 */
|
||||||
|
if (block_size > 104) {
|
||||||
|
hash[13] ^= le2me_64(block[13]);
|
||||||
|
hash[14] ^= le2me_64(block[14]);
|
||||||
|
hash[15] ^= le2me_64(block[15]);
|
||||||
|
hash[16] ^= le2me_64(block[16]);
|
||||||
|
/* if not sha3-256 */
|
||||||
|
if (block_size > 136) {
|
||||||
|
hash[17] ^= le2me_64(block[17]);
|
||||||
|
#ifdef FULL_SHA3_FAMILY_SUPPORT
|
||||||
|
/* if not sha3-224 */
|
||||||
|
if (block_size > 144) {
|
||||||
|
hash[18] ^= le2me_64(block[18]);
|
||||||
|
hash[19] ^= le2me_64(block[19]);
|
||||||
|
hash[20] ^= le2me_64(block[20]);
|
||||||
|
hash[21] ^= le2me_64(block[21]);
|
||||||
|
hash[22] ^= le2me_64(block[22]);
|
||||||
|
hash[23] ^= le2me_64(block[23]);
|
||||||
|
hash[24] ^= le2me_64(block[24]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* make a permutation of the hash */
|
||||||
|
sha3_permutation(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SHA3_FINALIZED 0x80000000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate message hash.
|
||||||
|
* Can be called repeatedly with chunks of the message to be hashed.
|
||||||
|
*
|
||||||
|
* @param ctx the algorithm context containing current hashing state
|
||||||
|
* @param msg message chunk
|
||||||
|
* @param size length of the message chunk
|
||||||
|
*/
|
||||||
|
void sha3_Update(SHA3_CTX *ctx, const unsigned char *msg, size_t size)
|
||||||
|
{
|
||||||
|
size_t idx = (size_t)ctx->rest;
|
||||||
|
size_t block_size = (size_t)ctx->block_size;
|
||||||
|
|
||||||
|
if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */
|
||||||
|
ctx->rest = (unsigned)((ctx->rest + size) % block_size);
|
||||||
|
|
||||||
|
/* fill partial block */
|
||||||
|
if (idx) {
|
||||||
|
size_t left = block_size - idx;
|
||||||
|
memcpy((char*)ctx->message + idx, msg, (size < left ? size : left));
|
||||||
|
if (size < left) return;
|
||||||
|
|
||||||
|
/* process partial block */
|
||||||
|
sha3_process_block(ctx->hash, ctx->message, block_size);
|
||||||
|
msg += left;
|
||||||
|
size -= left;
|
||||||
|
}
|
||||||
|
while (size >= block_size) {
|
||||||
|
uint64_t *aligned_message_block = NULL;
|
||||||
|
if (IS_ALIGNED_64(msg)) {
|
||||||
|
/* the most common case is processing of an already aligned message
|
||||||
|
without copying it */
|
||||||
|
aligned_message_block = (uint64_t*)(void*)msg;
|
||||||
|
} else {
|
||||||
|
memcpy(ctx->message, msg, block_size);
|
||||||
|
aligned_message_block = ctx->message;
|
||||||
|
}
|
||||||
|
|
||||||
|
sha3_process_block(ctx->hash, aligned_message_block, block_size);
|
||||||
|
msg += block_size;
|
||||||
|
size -= block_size;
|
||||||
|
}
|
||||||
|
if (size) {
|
||||||
|
memcpy(ctx->message, msg, size); /* save leftovers */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store calculated hash into the given array.
|
||||||
|
*
|
||||||
|
* @param ctx the algorithm context containing current hashing state
|
||||||
|
* @param result calculated hash in binary form
|
||||||
|
*/
|
||||||
|
void sha3_Final(SHA3_CTX *ctx, unsigned char* result)
|
||||||
|
{
|
||||||
|
size_t digest_length = 100 - ctx->block_size / 2;
|
||||||
|
const size_t block_size = ctx->block_size;
|
||||||
|
|
||||||
|
if (!(ctx->rest & SHA3_FINALIZED))
|
||||||
|
{
|
||||||
|
/* clear the rest of the data queue */
|
||||||
|
memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest);
|
||||||
|
((char*)ctx->message)[ctx->rest] |= 0x06;
|
||||||
|
((char*)ctx->message)[block_size - 1] |= 0x80;
|
||||||
|
|
||||||
|
/* process final block */
|
||||||
|
sha3_process_block(ctx->hash, ctx->message, block_size);
|
||||||
|
ctx->rest = SHA3_FINALIZED; /* mark context as finalized */
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(block_size > digest_length);
|
||||||
|
if (result) me64_to_le_str(result, ctx->hash, digest_length);
|
||||||
|
memzero(ctx, sizeof(SHA3_CTX));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_KECCAK
|
||||||
|
/**
|
||||||
|
* Store calculated hash into the given array.
|
||||||
|
*
|
||||||
|
* @param ctx the algorithm context containing current hashing state
|
||||||
|
* @param result calculated hash in binary form
|
||||||
|
*/
|
||||||
|
void keccak_Final(SHA3_CTX *ctx, unsigned char* result)
|
||||||
|
{
|
||||||
|
size_t digest_length = 100 - ctx->block_size / 2;
|
||||||
|
const size_t block_size = ctx->block_size;
|
||||||
|
|
||||||
|
if (!(ctx->rest & SHA3_FINALIZED))
|
||||||
|
{
|
||||||
|
/* clear the rest of the data queue */
|
||||||
|
memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest);
|
||||||
|
((char*)ctx->message)[ctx->rest] |= 0x01;
|
||||||
|
((char*)ctx->message)[block_size - 1] |= 0x80;
|
||||||
|
|
||||||
|
/* process final block */
|
||||||
|
sha3_process_block(ctx->hash, ctx->message, block_size);
|
||||||
|
ctx->rest = SHA3_FINALIZED; /* mark context as finalized */
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(block_size > digest_length);
|
||||||
|
if (result) me64_to_le_str(result, ctx->hash, digest_length);
|
||||||
|
memzero(ctx, sizeof(SHA3_CTX));
|
||||||
|
}
|
||||||
|
|
||||||
|
void keccak_256(const unsigned char* data, size_t len, unsigned char* digest)
|
||||||
|
{
|
||||||
|
SHA3_CTX ctx = {0};
|
||||||
|
keccak_256_Init(&ctx);
|
||||||
|
keccak_Update(&ctx, data, len);
|
||||||
|
keccak_Final(&ctx, digest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void keccak_512(const unsigned char* data, size_t len, unsigned char* digest)
|
||||||
|
{
|
||||||
|
SHA3_CTX ctx = {0};
|
||||||
|
keccak_512_Init(&ctx);
|
||||||
|
keccak_Update(&ctx, data, len);
|
||||||
|
keccak_Final(&ctx, digest);
|
||||||
|
}
|
||||||
|
#endif /* USE_KECCAK */
|
||||||
|
|
||||||
|
void sha3_256(const unsigned char* data, size_t len, unsigned char* digest)
|
||||||
|
{
|
||||||
|
SHA3_CTX ctx = {0};
|
||||||
|
sha3_256_Init(&ctx);
|
||||||
|
sha3_Update(&ctx, data, len);
|
||||||
|
sha3_Final(&ctx, digest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sha3_512(const unsigned char* data, size_t len, unsigned char* digest)
|
||||||
|
{
|
||||||
|
SHA3_CTX ctx = {0};
|
||||||
|
sha3_512_Init(&ctx);
|
||||||
|
sha3_Update(&ctx, data, len);
|
||||||
|
sha3_Final(&ctx, digest);
|
||||||
|
}
|
||||||
26
libraries/vendor/CMakeLists.txt
vendored
26
libraries/vendor/CMakeLists.txt
vendored
|
|
@ -1,26 +0,0 @@
|
||||||
PROJECT( SHA3IUF )
|
|
||||||
|
|
||||||
include(ExternalProject)
|
|
||||||
|
|
||||||
ExternalProject_Add(project_SHA3IUF
|
|
||||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}
|
|
||||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF
|
|
||||||
CONFIGURE_COMMAND cp -R ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF/. ${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build
|
|
||||||
BUILD_COMMAND make
|
|
||||||
INSTALL_COMMAND true
|
|
||||||
BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX}
|
|
||||||
LOG_BUILD ON
|
|
||||||
)
|
|
||||||
|
|
||||||
ExternalProject_Get_Property(project_SHA3IUF binary_dir)
|
|
||||||
add_library(SHA3IUF STATIC IMPORTED)
|
|
||||||
message(STATUS "Setting up SHA3IUF to ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
|
||||||
set_property(TARGET SHA3IUF PROPERTY IMPORTED_LOCATION ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX})
|
|
||||||
set_property(TARGET SHA3IUF PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/SHA3IUF)
|
|
||||||
|
|
||||||
add_dependencies(SHA3IUF project_SHA3IUF)
|
|
||||||
install( FILES ${binary_dir}/libsha3${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION lib )
|
|
||||||
|
|
||||||
set(SHA3IUF_libraries sha3 CACHE INTERNAL "")
|
|
||||||
set(SHA3IUF_include_dirs "${CMAKE_CURRENT_LIST_DIR}/SHA3IUF" CACHE INTERNAL "")
|
|
||||||
set(SHA3IUF_link_dirs "${CMAKE_CURRENT_BINARY_DIR}/src/project_SHA3IUF-build" CACHE INTERNAL "")
|
|
||||||
1
libraries/vendor/SHA3IUF
vendored
1
libraries/vendor/SHA3IUF
vendored
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit fc8504750a5c2174a1874094dd05e6a0d8797753
|
|
||||||
Loading…
Reference in a new issue