Merge branch 'feature/479-one-bunch-transaction' into 'develop'

#479 - Send one transaction for all owners

See merge request PBSA/peerplays!183
This commit is contained in:
serkixenos 2022-12-01 01:53:39 +00:00
commit 5dff0830fb
9 changed files with 254 additions and 204 deletions

View file

@ -2,7 +2,6 @@
#include <boost/algorithm/hex.hpp>
#include <boost/format.hpp>
#include <stdlib.h>
#include <graphene/peerplays_sidechain/ethereum/utils.hpp>
@ -19,12 +18,16 @@ std::string base_encoder::encode_address(const std::string &value) {
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');
data += boost::algorithm::hex(value);
if (value.size() % 32 != 0) {
data += 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 {
const std::string update_owners_encoder::function_signature = "f6afbeff"; //! updateOwners_(address,(address,uint256)[],string)
std::string update_owners_encoder::encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id) {
std::string data = "0x" + function_signature;
data += base_encoder::encode_uint256(64);
data += base_encoder::encode_uint256((owners_weights.size() * 2 + 3) * 32);
@ -39,7 +42,8 @@ std::string update_owners_encoder::encode(const std::vector<std::pair<std::strin
}
//! withdrawal_encoder
std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) const {
const std::string withdrawal_encoder::function_signature = "cf7c8f6d"; //! withdraw_(address,address,uint256,string)
std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) {
std::string data = "0x" + function_signature;
data += base_encoder::encode_address(to);
data += base_encoder::encode_uint256(amount);
@ -49,6 +53,51 @@ std::string withdrawal_encoder::encode(const std::string &to, boost::multiprecis
return data;
}
//! signature_encoder
signature_encoder::signature_encoder(const std::string &function_hash) :
function_signature{function_hash} {
}
std::string signature_encoder::get_function_signature_from_transaction(const std::string &transaction) {
const std::string tr = remove_0x(transaction);
if (tr.substr(0, 8) == update_owners_encoder::function_signature)
return update_owners_function_signature;
if (tr.substr(0, 8) == withdrawal_encoder::function_signature)
return withdrawal_function_signature;
return "";
}
std::string signature_encoder::encode(const std::vector<encoded_sign_transaction> &transactions) const {
std::string data = "0x" + function_signature;
data += base_encoder::encode_uint256(32);
data += base_encoder::encode_uint256(transactions.size());
size_t offset = (transactions.size()) * 32;
for (const auto &transaction : transactions) {
data += base_encoder::encode_uint256(offset);
const auto transaction_data = remove_0x(transaction.data);
offset += 5 * 32 + transaction_data.size() / 2;
if (transaction_data.size() / 2 % 32 != 0) {
offset += 32 - transaction_data.size() / 2 % 32;
}
}
for (const auto &transaction : transactions) {
data += base_encoder::encode_uint256(4 * 32);
data += base_encoder::encode_address(transaction.sign.v);
data += base_encoder::encode_address(transaction.sign.r);
data += base_encoder::encode_address(transaction.sign.s);
const auto transaction_data = remove_0x(transaction.data);
data += base_encoder::encode_uint256(transaction_data.size() / 2);
data += transaction_data;
if (transaction_data.size() % 64 != 0) {
data += std::string((64 - transaction_data.size() % 64), '0');
}
}
return data;
}
//! rlp_encoder
std::string rlp_encoder::encode(const std::string &s) {
return encode_rlp(hex2bytes(s));

View file

@ -22,7 +22,43 @@ const secp256k1_context *eth_context() {
return ctx;
}
//! transaction
bytes keccak_hash(const std::string &data) {
bytes hash;
hash.resize(32);
const auto transaction_string = boost::algorithm::unhex(remove_0x(data));
keccak_256((const unsigned char *)transaction_string.data(), transaction_string.size(), (unsigned char *)hash.data());
return hash;
}
signature sign_hash(const bytes &hash, const std::string &chain_id, const std::string &private_key) {
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));
unsigned int v = recid + from_hex<unsigned 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));
signature eth_sig;
eth_sig.v = to_hex(v);
eth_sig.r = fc::to_hex((char *)&r[0], r.size());
eth_sig.s = fc::to_hex((char *)&s[0], s.size());
return eth_sig;
}
//! base_transaction
base_transaction::base_transaction(const std::string &raw_tx) {
}
@ -70,12 +106,7 @@ raw_transaction::raw_transaction(const std::string &raw_tx) :
}
bytes raw_transaction::hash() const {
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());
return hash;
return keccak_hash(serialize());
}
signed_transaction raw_transaction::sign(const std::string &private_key) const {
@ -88,27 +119,10 @@ signed_transaction raw_transaction::sign(const std::string &private_key) const {
tr.value = value;
tr.data = 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 r;
for (int i = 1; i < 33; i++)
r.emplace_back((char)result.at(i));
unsigned int v = recid + from_hex<unsigned int>(chain_id) * 2 + 35;
bytes s;
for (int i = 33; i < 65; i++)
s.emplace_back((char)result.at(i));
tr.r = fc::to_hex((char *)&r[0], r.size());
tr.v = to_hex(v);
tr.s = fc::to_hex((char *)&s[0], s.size());
const auto sig = sign_hash(hash(), chain_id, private_key);
tr.v = sig.v;
tr.r = sig.r;
tr.s = sig.s;
return tr;
}

View file

@ -1,5 +1,36 @@
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
signature::signature(const std::string &sign) {
deserialize(sign);
}
std::string signature::serialize() const {
boost::property_tree::ptree pt;
pt.put("v", v);
pt.put("r", r);
pt.put("s", s);
std::stringstream ss;
boost::property_tree::json_parser::write_json(ss, pt);
return ss.str();
}
void signature::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("v"))
v = tx_json.get<std::string>("v");
if (tx_json.count("r"))
r = tx_json.get<std::string>("r");
if (tx_json.count("s"))
s = tx_json.get<std::string>("s");
}
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -4,8 +4,18 @@
#include <string>
#include <vector>
#include <graphene/peerplays_sidechain/ethereum/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
const std::string update_owners_function_signature = "9d608673"; //! updateOwners((bytes,(uint8,bytes32,bytes32))[])
const std::string withdrawal_function_signature = "daac6c81"; //! withdraw((bytes,(uint8,bytes32,bytes32))[])
struct encoded_sign_transaction {
std::string data;
signature sign;
};
class base_encoder {
public:
static std::string encode_uint256(boost::multiprecision::uint256_t value);
@ -15,16 +25,27 @@ public:
class update_owners_encoder {
public:
const std::string function_signature = "23ab6adf"; //! updateOwners((address,uint256)[],string)
static const std::string function_signature;
std::string encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id) const;
static std::string encode(const std::vector<std::pair<std::string, uint16_t>> &owners_weights, const std::string &object_id);
};
class withdrawal_encoder {
public:
const std::string function_signature = "e088747b"; //! withdraw(address,uint256,string)
static const std::string function_signature;
std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id) const;
static std::string encode(const std::string &to, boost::multiprecision::uint256_t amount, const std::string &object_id);
};
class signature_encoder {
public:
const std::string function_signature;
signature_encoder(const std::string &function_hash);
static std::string get_function_signature_from_transaction(const std::string &transaction);
std::string encode(const std::vector<encoded_sign_transaction> &transactions) const;
};
class rlp_encoder {
@ -39,35 +60,4 @@ private:
static void hex2bin(const char *src, char *target);
};
/*class ethereum_function_call_encoder {
public:
enum operation_t {
OPERATION_CALL,
OPERATION_DELEGATE_CALL
};
static constexpr const char *const default_prev_addr = "0000000000000000000000000000000000000001";
std::string encode_function_signature(const std::string &function_signature);
std::string encode_address(const std::string &addr);
std::string encode_uint256(const std::string &value);
std::string encode_uint8(uint8_t value);
std::string encode_bytes(const std::string &values);
};
class safe_transaction_encoder {
public:
static constexpr const char *const default_safe_tx_gas = "0";
static constexpr const char *const default_data_gas = "0";
static constexpr const char *const default_gas_price = "0";
static constexpr const char *const default_gas_token = "0000000000000000000000000000000000000000";
static constexpr const char *const default_refund_receiver = "0000000000000000000000000000000000000000";
std::string create_safe_address(const std::vector<std::string> &owner_addresses, uint32_t threshold);
std::string build_transaction(const std::string &safe_account_addr, const std::string &value, const std::string &data, uint8_t operation, const std::string &safeTxGas, const std::string &dataGas, const std::string &gasPrice, const std::string &gasToken, const std::string &refundReceiver);
private:
ethereum_function_call_encoder m_ethereum_function_call_encoder;
};*/
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -8,6 +8,9 @@
namespace graphene { namespace peerplays_sidechain { namespace ethereum {
bytes keccak_hash(const std::string &data);
signature sign_hash(const bytes &hash, const std::string &chain_id, const std::string &private_key);
class base_transaction {
public:
base_transaction() = default;
@ -75,89 +78,3 @@ public:
};
}}} // namespace graphene::peerplays_sidechain::ethereum
// Example 1
//{
// "blockHash": "0x64a6706ecaf5a97b7f3e047abb20ff223ce82c6994d80e68fdb1fdfb38d0209c",
// "blockNumber": "0xe5827c",
// "from": "0x8614c67e085f2334010f2a28e806c6f1cc176d12",
// "gas": "0x38822",
// "gasPrice": "0xce42cba69",
// "maxFeePerGas": "0xddb4d8d16",
// "maxPriorityFeePerGas": "0x3b9aca00",
// "hash": "0xeac92ea09fa8eb3ca2fb0d156cceb38ae69d4345869d41e8e49d5ecbcbb622dc",
// "input": "0x5ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde03121500000000000000000000000000000000000000000000000000000000",
// "nonce": "0x32",
// "to": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45",
// "transactionIndex": "0xb6",
// "value": "0x2514d9d7d7d8000",
// "type": "0x2",
// "accessList": [],
// "chainId": "0x1",
// "v": "0x1",
// "r": "0x2f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28c",
// "s": "0x782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14"
//}
//
//"0xf9021332850ce42cba69830388229468b3465833fb72a70ecdf485e0e4c7bd8665fc458802514d9d7d7d8000b901a45ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde0312150000000000000000000000000000000000000000000000000000000001a02f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28ca0782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14"
//
//{
// "nonce": 50,
// "gasPrice": {
// "_hex": "0x0ce42cba69"
// },
// "gasLimit": {
// "_hex": "0x038822"
// },
// "to": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45",
// "value": {
// "_hex": "0x02514d9d7d7d8000"
// },
// "data": "0x5ae401dc0000000000000000000000000000000000000000000000000000000062bb57cf00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4472b43f300000000000000000000000000000000000000000000000002514d9d7d7d8000000000000000000000000000000000000000000007dced93dd41fd3e1f9e80c200000000000000000000000000000000000000000000000000000000000000800000000000000000000000008614c67e085f2334010f2a28e806c6f1cc176d120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000059c12ed5aaf25adbc6e15f9cc9bab2dde03121500000000000000000000000000000000000000000000000000000000",
// "v": 1,
// "r": "0x2f8d6a9c737ed98792bafc903b8f1aa54adc731bd3cf9a8b25246a1c9095a28c",
// "s": "0x782c40e64b47a221a07612c822c08763f626e53c4b00b73f4c5ba86304c43f14"
//}
// Example 2
//{
// "blockHash": "0xe2ae3afd86dc7343c7fb753441447a0a51bb19499325ad6e278256f0cd1b5894",
// "blockNumber": "0xe58271",
// "from": "0xb895ade6d337fbb8cb97f2ea7da43106c7f5cc26",
// "gas": "0x5208",
// "gasPrice": "0xe6f3b322e",
// "maxFeePerGas": "0x1322455fd3",
// "maxPriorityFeePerGas": "0x53724e00",
// "hash": "0xed29b56e52ad2d452e25b8ec70c37f59d935cd6d0f8fe8e83b256f3ffdfd3fce",
// "input": "0x",
// "nonce": "0x37",
// "to": "0x176386b6ffc469ac049f9ec1f6cc0efd1d09b373",
// "transactionIndex": "0x8a",
// "value": "0x4563918244f40000",
// "type": "0x2",
// "accessList": [],
// "chainId": "0x1",
// "v": "0x0",
// "r": "0xdcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4c",
// "s": "0x28c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a"
//}
//
//"0xf86c37850e6f3b322e82520894176386b6ffc469ac049f9ec1f6cc0efd1d09b373884563918244f400008000a0dcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4ca028c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a"
//
//{
// "nonce": 55,
// "gasPrice": {
// "_hex": "0x0e6f3b322e"
// },
// "gasLimit": {
// "_hex": "0x5208"
// },
// "to": "0x176386b6ffc469ac049f9ec1f6cc0efd1d09b373",
// "value": {
// "_hex": "0x4563918244f40000"
// },
// "data": "0x",
// "v": 0,
// "r": "0xdcc588257770e08660cb809e71b293f556cd5f5323e832d96ee896ff8830ca4c",
// "s": "0x28c7ce6a539d9318688687097a2db29e15c32ba8c085275fdd3dddf047d4bd1a"
//}

View file

@ -9,4 +9,17 @@ typedef uint64_t network_id_type;
using bytes = std::vector<char>;
class signature {
public:
std::string v;
std::string r;
std::string s;
signature() = default;
signature(const std::string &sign);
std::string serialize() const;
void deserialize(const std::string &sign);
};
}}} // namespace graphene::peerplays_sidechain::ethereum

View file

@ -19,7 +19,7 @@ std::string to_hex(const T &val, bool add_front_zero = true) {
std::stringstream stream;
stream << std::hex << val;
std::string result(stream.str());
if(add_front_zero) {
if (add_front_zero) {
if (result.size() % 2)
result = "0" + result;
}

View file

@ -585,33 +585,65 @@ std::string sidechain_net_handler_ethereum::process_sidechain_transaction(const
std::string sidechain_net_handler_ethereum::send_sidechain_transaction(const sidechain_transaction_object &sto) {
boost::property_tree::ptree pt;
boost::property_tree::ptree pt_array;
std::vector<ethereum::encoded_sign_transaction> transactions;
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())
if (signature.second.empty())
continue;
ethereum::encoded_sign_transaction transaction{sto.transaction, ethereum::signature{signature.second}};
transactions.emplace_back(transaction);
}
const auto &current_son = plugin.get_current_son_object(sidechain);
FC_ASSERT(current_son.sidechain_public_keys.contains(sidechain), "No public keys for current son: ${account_id}", ("account_id", current_son.son_account));
const auto &public_key = current_son.sidechain_public_keys.at(sidechain);
const auto function_signature = ethereum::signature_encoder::get_function_signature_from_transaction(sto.transaction);
if (function_signature.empty()) {
elog("Function signature is empty for transaction id ${id}, transaction ${transaction}", ("id", sto.id)("transaction", sto.transaction));
return std::string{}; //! Return empty string, as we have error in sending
}
const ethereum::signature_encoder encoder{function_signature};
#ifdef SEND_RAW_TRANSACTION
const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(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 = encoder.encode(transactions);
raw_tr.chain_id = ethereum::add_0x(ethereum::to_hex(chain_id));
const auto sign_tr = raw_tr.sign(get_private_key(public_key));
const std::string sidechain_transaction = rpc_client->eth_send_raw_transaction(sign_tr.serialize());
#else
const std::string sidechain_transaction = rpc_client->eth_send_transaction(transaction);
ethereum::transaction raw_tr;
raw_tr.data = encoder.encode(transactions);
raw_tr.to = wallet_contract_address;
raw_tr.from = ethereum::add_0x(public_key);
const auto sign_tr = raw_tr.sign(get_private_key(public_key));
const std::string sidechain_transaction = rpc_client->eth_send_transaction(sign_tr.serialize());
#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
}
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", sto.transaction);
node.put("sidechain_transaction", sidechain_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 ${id}, transaction ${transaction}, sidechain_transaction ${sidechain_transaction}", ("id", sto.id)("transaction", sto.transaction)("sidechain_transaction", sidechain_transaction));
return std::string{}; //! Return empty string, as we have error in sending
}
pt.add_child("result_array", pt_array);
@ -705,8 +737,7 @@ std::string sidechain_net_handler_ethereum::create_primary_wallet_transaction(co
owners_weights.emplace_back(std::make_pair(pub_key_str, son.weight));
}
const ethereum::update_owners_encoder encoder;
return encoder.encode(owners_weights, object_id);
return ethereum::update_owners_encoder::encode(owners_weights, object_id);
}
std::string sidechain_net_handler_ethereum::create_deposit_transaction(const son_wallet_deposit_object &swdo) {
@ -714,8 +745,7 @@ 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) {
const ethereum::withdrawal_encoder encoder;
return encoder.encode(swwo.withdraw_address.substr(2), swwo.withdraw_amount.value * 10000000000, swwo.id.operator std::string());
return ethereum::withdrawal_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) {
@ -724,25 +754,11 @@ std::string sidechain_net_handler_ethereum::sign_transaction(const sidechain_tra
const auto &public_key = current_son.sidechain_public_keys.at(sidechain);
#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));
//! We need to change v value according to chain_id
auto signature = ethereum::sign_hash(ethereum::keccak_hash(sto.transaction), ethereum::add_0x(ethereum::to_hex(chain_id)), get_private_key(public_key));
signature.v = ethereum::to_hex(ethereum::from_hex<unsigned int>(signature.v) - 2 * chain_id - 35 + 27);
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
return signature.serialize();
}
void sidechain_net_handler_ethereum::schedule_ethereum_listener() {

View file

@ -9,12 +9,22 @@ using namespace graphene::peerplays_sidechain::ethereum;
BOOST_AUTO_TEST_SUITE(ethereum_transaction_tests)
BOOST_AUTO_TEST_CASE(withdrawal_encoder_test) {
const withdrawal_encoder encoder;
const auto tx = encoder.encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.0");
BOOST_CHECK_EQUAL(tx, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000");
const auto tx = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.0");
BOOST_CHECK_EQUAL(tx, "0xcf7c8f6d0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E300000000000000000000000000000000000000000000000000000");
const auto tx1 = encoder.encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1");
BOOST_CHECK_EQUAL(tx1, "0xe088747b0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000");
const auto tx1 = withdrawal_encoder::encode("5fbbb31be52608d2f52247e8400b7fcaa9e0bc12", 10000000000, "1.36.1");
BOOST_CHECK_EQUAL(tx1, "0xcf7c8f6d0000000000000000000000005fbbb31be52608d2f52247e8400b7fcaa9e0bc1200000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(withdrawal_signature_encoder_test) {
const signature_encoder encoder{withdrawal_function_signature};
encoded_sign_transaction transaction;
transaction.data = "0xcf7c8f6d0000000000000000000000005c79a9f5767e3c1b926f963fa24e21d8a04289ae0000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33372E300000000000000000000000000000000000000000000000000000";
transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" );
const auto tx = encoder.encode({transaction});
BOOST_CHECK_EQUAL(tx, "0xdaac6c8100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000065ef357c2788df103d443e3c4a9e0864d6f52fbaab479684b8eb6ea09422b6b54310ca0511c6cc02402a668a73f9613c00f6f535dbd2d78468ecba540a8a0dba3d00000000000000000000000000000000000000000000000000000000000000a4cf7c8f6d0000000000000000000000005c79a9f5767e3c1b926f963fa24e21d8a04289ae0000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006312E33372E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(update_owners_encoder_test) {
@ -22,13 +32,23 @@ BOOST_AUTO_TEST_CASE(update_owners_encoder_test) {
owners_weights.emplace_back("5FbBb31BE52608D2F52247E8400B7fCaA9E0bC12", 1);
owners_weights.emplace_back("76ce31bd03f601c3fc13732def921c5bac282676", 1);
const update_owners_encoder encoder;
const auto tx = encoder.encode(owners_weights, "1.35.0");
BOOST_CHECK_EQUAL(tx, "0x23ab6adf000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000");
const auto tx = update_owners_encoder::encode(owners_weights, "1.35.0");
BOOST_CHECK_EQUAL(tx, "0xf6afbeff000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000");
owners_weights.emplace_back("09ee460834498a4ee361beb819470061b7381b49", 1);
const auto tx1 = encoder.encode(owners_weights, "1.36.1");
BOOST_CHECK_EQUAL(tx1, "0x23ab6adf0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000");
const auto tx1 = update_owners_encoder::encode(owners_weights, "1.36.1");
BOOST_CHECK_EQUAL(tx1, "0xf6afbeff0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac282676000000000000000000000000000000000000000000000000000000000000000100000000000000000000000009ee460834498a4ee361beb819470061b7381b4900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33362E310000000000000000000000000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(update_owners_signature_encoder_test) {
const signature_encoder encoder{update_owners_function_signature};
encoded_sign_transaction transaction;
transaction.data = "0xf6afbeff000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E300000000000000000000000000000000000000000000000000000";
transaction.sign = sign_hash(keccak_hash(transaction.data), "0x21", "eb5749a569e6141a3b08249d4a0d84f9ef22c67651ba29adb8eb6fd43fc83060" );
const auto tx = encoder.encode({transaction});
BOOST_CHECK_EQUAL(tx, "0x9d608673000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000665762851a05348a4900393b3f2778c5078689422e43e3a2aa9b517a4141133bd42c08169979785256a2f26d1da13e297125ee84c2d79be07212cfde592fc03dbb0000000000000000000000000000000000000000000000000000000000000124f6afbeff000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005FbBb31BE52608D2F52247E8400B7fCaA9E0bC12000000000000000000000000000000000000000000000000000000000000000100000000000000000000000076ce31bd03f601c3fc13732def921c5bac28267600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000006312E33352E30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(raw_transaction_serialization_test) {