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:
commit
5dff0830fb
9 changed files with 254 additions and 204 deletions
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ¤t_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() {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue