Hive transaction handling, WIP

This commit is contained in:
serkixenos 2021-03-22 17:29:35 +01:00
parent 093fdf055a
commit 7fc964103e
12 changed files with 395 additions and 35 deletions

View file

@ -15,6 +15,8 @@ add_library( peerplays_sidechain
bitcoin/utils.cpp
bitcoin/sign_bitcoin_transaction.cpp
common/rpc_client.cpp
hive/transaction.cpp
hive/types.cpp
)
if (ENABLE_DEV_FEATURES)

View file

@ -21,6 +21,20 @@ rpc_client::rpc_client(std::string _ip, uint32_t _port, std::string _user, std::
authorization.val = "Basic " + fc::base64_encode(user + ":" + password);
}
std::string rpc_client::retrieve_value_from_reply(std::string reply_str, std::string value_path) {
std::stringstream ss(reply_str);
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
if (json.find("result") == json.not_found()) {
return "";
}
auto json_result = json.get_child("result");
if (json_result.find(value_path) == json_result.not_found()) {
return "";
}
return json_result.get<std::string>(value_path);
}
std::string rpc_client::send_post_request(std::string method, std::string params, bool show_log) {
std::stringstream body;

View file

@ -0,0 +1,42 @@
#include <graphene/peerplays_sidechain/hive/transaction.hpp>
#include <fc/bitutil.hpp>
#include <fc/io/raw.hpp>
namespace graphene { namespace peerplays_sidechain { namespace hive {
digest_type transaction::sig_digest(const chain_id_type &chain_id) const {
digest_type::encoder enc;
fc::raw::pack(enc, chain_id);
fc::raw::pack(enc, *this);
return enc.result();
}
void transaction::set_expiration(fc::time_point_sec expiration_time) {
expiration = expiration_time;
}
void transaction::set_reference_block(const block_id_type &reference_block) {
ref_block_num = fc::endian_reverse_u32(reference_block._hash[0]);
ref_block_prefix = reference_block._hash[1];
}
void signed_transaction::clear() {
operations.clear();
signatures.clear();
}
const signature_type &signed_transaction::sign(const hive::private_key_type &key, const hive::chain_id_type &chain_id) {
digest_type h = sig_digest(chain_id);
signatures.push_back(key.sign_compact(h, true));
return signatures.back();
}
signature_type signed_transaction::sign(const hive::private_key_type &key, const hive::chain_id_type &chain_id) const {
digest_type::encoder enc;
fc::raw::pack(enc, chain_id);
fc::raw::pack(enc, *this);
return key.sign_compact(enc.result(), true);
}
}}} // namespace graphene::peerplays_sidechain::hive

View file

@ -0,0 +1,77 @@
#include <graphene/peerplays_sidechain/hive/types.hpp>
#include <fc/crypto/base58.hpp>
#include <fc/crypto/ripemd160.hpp>
#include <fc/exception/exception.hpp>
#include <fc/io/raw.hpp>
namespace graphene { namespace peerplays_sidechain { namespace hive {
#define ADDRESS_PREFIX "TST"
public_key_type::public_key_type() :
key_data(){};
public_key_type::public_key_type(const fc::ecc::public_key_data &data) :
key_data(data){};
public_key_type::public_key_type(const fc::ecc::public_key &pubkey) :
key_data(pubkey){};
public_key_type::public_key_type(const std::string &base58str) {
// TODO: Refactor syntactic checks into static is_valid()
// to make public_key_type API more similar to address API
std::string prefix(ADDRESS_PREFIX);
const size_t prefix_len = prefix.size();
FC_ASSERT(base58str.size() > prefix_len);
FC_ASSERT(base58str.substr(0, prefix_len) == prefix, "", ("base58str", base58str));
auto bin = fc::from_base58(base58str.substr(prefix_len));
auto bin_key = fc::raw::unpack<binary_key>(bin);
key_data = bin_key.data;
FC_ASSERT(fc::ripemd160::hash(key_data.data, key_data.size())._hash[0] == bin_key.check);
};
public_key_type::operator fc::ecc::public_key_data() const {
return key_data;
};
public_key_type::operator fc::ecc::public_key() const {
return fc::ecc::public_key(key_data);
};
public_key_type::operator std::string() const {
binary_key k;
k.data = key_data;
k.check = fc::ripemd160::hash(k.data.data, k.data.size())._hash[0];
auto data = fc::raw::pack(k);
return ADDRESS_PREFIX + fc::to_base58(data.data(), data.size());
}
bool operator==(const public_key_type &p1, const fc::ecc::public_key &p2) {
return p1.key_data == p2.serialize();
}
bool operator==(const public_key_type &p1, const public_key_type &p2) {
return p1.key_data == p2.key_data;
}
bool operator!=(const public_key_type &p1, const public_key_type &p2) {
return p1.key_data != p2.key_data;
}
}}} // namespace graphene::peerplays_sidechain::hive
namespace fc {
using namespace std;
void to_variant(const graphene::peerplays_sidechain::hive::public_key_type &var, fc::variant &vo, uint32_t max_depth) {
vo = std::string(var);
}
void from_variant(const fc::variant &var, graphene::peerplays_sidechain::hive::public_key_type &vo, uint32_t max_depth) {
vo = graphene::peerplays_sidechain::hive::public_key_type(var.as_string());
}
} // namespace fc

View file

@ -12,8 +12,8 @@ public:
rpc_client(std::string _ip, uint32_t _port, std::string _user, std::string _password);
protected:
std::string retrieve_value_from_reply(std::string reply_str, std::string value_path);
std::string send_post_request(std::string method, std::string params, bool show_log);
fc::http::reply send_post_request(std::string body, bool show_log);
std::string ip;
uint32_t port;
@ -23,6 +23,9 @@ protected:
uint32_t request_id;
fc::http::header authorization;
private:
fc::http::reply send_post_request(std::string body, bool show_log);
};
}} // namespace graphene::peerplays_sidechain

View file

@ -0,0 +1,34 @@
#pragma once
#include <cstdint>
#include <vector>
#include <fc/container/flat_fwd.hpp>
#include <graphene/peerplays_sidechain/hive/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace hive {
struct authority {
authority() {
}
enum classification {
owner = 0,
active = 1,
key = 2,
posting = 3
};
uint32_t weight_threshold = 0;
fc::flat_map<std::string, uint16_t> account_auths;
fc::flat_map<public_key_type, uint16_t> key_auths;
};
}}} // namespace graphene::peerplays_sidechain::hive
FC_REFLECT_ENUM(graphene::peerplays_sidechain::hive::authority::classification,
(owner)(active)(key)(posting))
FC_REFLECT(graphene::peerplays_sidechain::hive::authority,
(weight_threshold)(account_auths)(key_auths))

View file

@ -0,0 +1,26 @@
#pragma once
#include <cstdint>
#include <vector>
#include <fc/optional.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/peerplays_sidechain/hive/authority.hpp>
#include <graphene/peerplays_sidechain/hive/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace hive {
struct account_update_operation {
std::string account;
fc::optional<authority> owner;
fc::optional<authority> active;
fc::optional<authority> posting;
hive::public_key_type memo_key;
std::string json_metadata;
};
}}} // namespace graphene::peerplays_sidechain::hive
FC_REFLECT(graphene::peerplays_sidechain::hive::account_update_operation,
(account)(owner)(active)(posting)(memo_key)(json_metadata))

View file

@ -0,0 +1,13 @@
#pragma once
#include <graphene/peerplays_sidechain/hive/hive_operations.hpp>
namespace graphene { namespace peerplays_sidechain { namespace hive {
typedef fc::static_variant<
account_update_operation>
hive_operation;
}}} // namespace graphene::peerplays_sidechain::hive
FC_REFLECT_TYPENAME(graphene::peerplays_sidechain::hive::hive_operation)

View file

@ -0,0 +1,43 @@
#pragma once
#include <cstdint>
#include <vector>
#include <fc/container/flat_fwd.hpp>
#include <fc/time.hpp>
#include <graphene/peerplays_sidechain/hive/operations.hpp>
namespace graphene { namespace peerplays_sidechain { namespace hive {
struct transaction {
uint16_t ref_block_num = 0;
uint32_t ref_block_prefix = 0;
fc::time_point_sec expiration;
std::vector<hive_operation> operations;
extensions_type extensions;
std::vector<fc::ecc::compact_signature> signatures;
digest_type sig_digest(const chain_id_type &chain_id) const;
void set_expiration(fc::time_point_sec expiration_time);
void set_reference_block(const block_id_type &reference_block);
};
struct signed_transaction : public transaction {
std::vector<fc::ecc::compact_signature> signatures;
const signature_type &sign(const hive::private_key_type &key, const hive::chain_id_type &chain_id);
signature_type sign(const hive::private_key_type &key, const hive::chain_id_type &chain_id) const;
void clear();
};
}}} // namespace graphene::peerplays_sidechain::hive
FC_REFLECT(graphene::peerplays_sidechain::hive::transaction,
(ref_block_num)(ref_block_prefix)(expiration)(operations)(extensions))
FC_REFLECT_DERIVED(graphene::peerplays_sidechain::hive::signed_transaction,
(graphene::peerplays_sidechain::hive::transaction),
(signatures))

View file

@ -0,0 +1,61 @@
#pragma once
#include <fc/crypto/elliptic.hpp>
#include <fc/crypto/ripemd160.hpp>
namespace graphene { namespace peerplays_sidechain { namespace hive {
struct void_t {};
typedef fc::static_variant<void_t> future_extensions;
typedef fc::flat_set<future_extensions> extensions_type;
typedef fc::ecc::private_key private_key_type;
typedef fc::sha256 chain_id_type;
//typedef fixed_string<16> account_name_type;
typedef fc::ripemd160 block_id_type;
//typedef fc::ripemd160 checksum_type;
//typedef fc::ripemd160 transaction_id_type;
typedef fc::sha256 digest_type;
typedef fc::ecc::compact_signature signature_type;
//typedef safe<int64_t> share_type;
//typedef safe<uint64_t> ushare_type;
//typedef uint16_t weight_type;
//typedef uint32_t contribution_id_type;
//typedef fixed_string<32> custom_id_type;
struct public_key_type {
struct binary_key {
binary_key() {
}
uint32_t check = 0;
fc::ecc::public_key_data data;
};
fc::ecc::public_key_data key_data;
public_key_type();
public_key_type(const fc::ecc::public_key_data &data);
public_key_type(const fc::ecc::public_key &pubkey);
explicit public_key_type(const std::string &base58str);
operator fc::ecc::public_key_data() const;
operator fc::ecc::public_key() const;
explicit operator std::string() const;
friend bool operator==(const public_key_type &p1, const fc::ecc::public_key &p2);
friend bool operator==(const public_key_type &p1, const public_key_type &p2);
friend bool operator<(const public_key_type &p1, const public_key_type &p2) {
return p1.key_data < p2.key_data;
}
friend bool operator!=(const public_key_type &p1, const public_key_type &p2);
};
}}} // namespace graphene::peerplays_sidechain::hive
namespace fc {
void to_variant(const graphene::peerplays_sidechain::hive::public_key_type &var, fc::variant &vo, uint32_t max_depth = 2);
void from_variant(const fc::variant &var, graphene::peerplays_sidechain::hive::public_key_type &vo, uint32_t max_depth = 2);
} // namespace fc
FC_REFLECT(graphene::peerplays_sidechain::hive::public_key_type, (key_data))
FC_REFLECT(graphene::peerplays_sidechain::hive::public_key_type::binary_key, (data)(check))
FC_REFLECT(graphene::peerplays_sidechain::hive::void_t, )
FC_REFLECT_TYPENAME(graphene::peerplays_sidechain::hive::future_extensions)

View file

@ -17,6 +17,11 @@ public:
std::string block_api_get_block(uint32_t block_number);
std::string database_api_get_dynamic_global_properties();
std::string database_api_get_version();
std::string get_chain_id();
std::string get_head_block_id();
std::string get_head_block_time();
};
class hive_wallet_rpc_client : public rpc_client {
@ -24,11 +29,14 @@ public:
hive_wallet_rpc_client(std::string _ip, uint32_t _port, std::string _user, std::string _password);
std::string get_account(std::string account);
std::string info();
std::string lock();
std::string unlock(std::string password);
std::string update_account_auth_key(std::string account_name, std::string type, std::string public_key, std::string weight);
std::string update_account_auth_account(std::string account_name, std::string type, std::string auth_account, std::string weight);
std::string update_account_auth_threshold(std::string account_name, std::string type, std::string threshold);
std::string get_account_memo_key(std::string account);
};
class sidechain_net_handler_hive : public sidechain_net_handler {

View file

@ -13,12 +13,15 @@
#include <fc/log/logger.hpp>
#include <fc/network/ip.hpp>
#include <fc/smart_ref_impl.hpp>
#include <fc/time.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
#include <graphene/chain/protocol/son_wallet.hpp>
#include <graphene/chain/son_info.hpp>
#include <graphene/chain/son_wallet_object.hpp>
#include <graphene/peerplays_sidechain/hive/operations.hpp>
#include <graphene/peerplays_sidechain/hive/transaction.hpp>
#include <graphene/utilities/key_conversion.hpp>
namespace graphene { namespace peerplays_sidechain {
@ -36,6 +39,25 @@ std::string hive_node_rpc_client::database_api_get_dynamic_global_properties() {
return send_post_request("database_api.get_dynamic_global_properties", "", false);
}
std::string hive_node_rpc_client::database_api_get_version() {
return send_post_request("database_api.get_version", "", true);
}
std::string hive_node_rpc_client::get_chain_id() {
std::string reply_str = database_api_get_version();
return retrieve_value_from_reply(reply_str, "chain_id");
}
std::string hive_node_rpc_client::get_head_block_id() {
std::string reply_str = database_api_get_dynamic_global_properties();
return retrieve_value_from_reply(reply_str, "head_block_id");
}
std::string hive_node_rpc_client::get_head_block_time() {
std::string reply_str = database_api_get_dynamic_global_properties();
return retrieve_value_from_reply(reply_str, "time");
}
hive_wallet_rpc_client::hive_wallet_rpc_client(std::string _ip, uint32_t _port, std::string _user, std::string _password) :
rpc_client(_ip, _port, _user, _password) {
}
@ -49,6 +71,10 @@ std::string hive_wallet_rpc_client::lock() {
return send_post_request("lock", "", true);
}
std::string hive_wallet_rpc_client::info() {
return send_post_request("info", "", true);
}
std::string hive_wallet_rpc_client::unlock(std::string password) {
std::string params = "[\"" + password + "\"]";
return send_post_request("unlock", params, true);
@ -69,6 +95,11 @@ std::string hive_wallet_rpc_client::update_account_auth_threshold(std::string ac
return send_post_request("update_account_auth_account", params, true);
}
std::string hive_wallet_rpc_client::get_account_memo_key(std::string account) {
std::string reply_str = get_account(account);
return retrieve_value_from_reply(reply_str, "memo_key");
}
sidechain_net_handler_hive::sidechain_net_handler_hive(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
sidechain_net_handler(_plugin, options) {
sidechain = sidechain_type::hive;
@ -230,22 +261,53 @@ void sidechain_net_handler_hive::process_primary_wallet() {
const chain::global_property_object &gpo = database.get_global_properties();
//auto active_sons = gpo.active_sons;
//string reply_str = create_primary_wallet_address(active_sons);
auto active_sons = gpo.active_sons;
fc::flat_map<std::string, uint16_t> account_auths;
uint32_t total_weight = 0;
for (const auto &active_son : active_sons) {
total_weight = total_weight + active_son.weight;
account_auths[active_son.sidechain_public_keys.at(sidechain)] = active_son.weight;
}
//std::stringstream active_pw_ss(reply_str);
//boost::property_tree::ptree active_pw_pt;
//boost::property_tree::read_json(active_pw_ss, active_pw_pt);
//if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) {
std::string memo_key = wallet_rpc_client->get_account_memo_key("son-account");
if (memo_key.empty()) {
return;
}
hive::authority active;
active.weight_threshold = 1;
active.account_auths = account_auths;
hive::account_update_operation auo;
auo.account = "son-account";
auo.active = active;
auo.memo_key = hive::public_key_type(memo_key);
std::string block_id_str = node_rpc_client->get_head_block_id();
hive::block_id_type head_block_id(block_id_str);
std::string head_block_time_str = node_rpc_client->get_head_block_time();
time_point head_block_time = fc::time_point_sec::from_iso_string(head_block_time_str);
hive::signed_transaction htrx;
htrx.set_reference_block(head_block_id);
htrx.set_expiration(head_block_time + fc::seconds(90));
htrx.operations.push_back(auo);
ilog("TRX: ${htrx}", ("htrx", htrx));
std::string chain_id_str = node_rpc_client->get_chain_id();
const hive::chain_id_type chain_id(chain_id_str);
// create sidechain transaction for wallet update, to collect SON signatures
return; // temporary
proposal_create_operation proposal_op;
proposal_op.fee_paying_account = plugin.get_current_son_object().son_account;
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::stringstream res;
//boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result"));
son_wallet_update_operation swu_op;
swu_op.payer = gpo.parameters.son_account();
swu_op.son_wallet_id = active_sw->id;
@ -254,21 +316,6 @@ void sidechain_net_handler_hive::process_primary_wallet() {
proposal_op.proposed_ops.emplace_back(swu_op);
//const auto &prev_sw = std::next(active_sw);
//if (prev_sw != swi.rend()) {
// std::string new_pw_address = active_pw_pt.get<std::string>("result.address");
// std::string tx_str = create_primary_wallet_transaction(*prev_sw, new_pw_address);
// if (!tx_str.empty()) {
// sidechain_transaction_create_operation stc_op;
// stc_op.payer = gpo.parameters.son_account();
// stc_op.object_id = prev_sw->id;
// 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();
@ -279,7 +326,6 @@ void sidechain_net_handler_hive::process_primary_wallet() {
elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what()));
return;
}
//}
}
}
}
@ -496,15 +542,6 @@ void sidechain_net_handler_hive::handle_event(const std::string &event_data) {
}
}
//boost::property_tree::ptree transactions_json = block_json.get_child("result.block.transactions");
//ss.str("");
//boost::property_tree::write_json(ss, transactions_json);
//elog("Transactions: ${ss}", ("ss", ss.str()));
//{"jsonrpc":"2.0","result":{"block":{"previous":"00006dd6c2b98bc7d1214f61f1c797bb22edb4cd","timestamp":"2021-03-10T12:18:21","witness":"initminer","transaction_merkle_root":"55d89a7b615a4d25f32d9160ce6714a5de5f2b05","extensions":[],"witness_signature":"1f0e2115cb18d862a279de93f3d4d82df4210984e26231db206de8b37e26b2aa8048f21fc7447f842047fea7ffa2a481eede07d379bf9577ab09b5395434508d86","transactions":[{"ref_block_num":28118,"ref_block_prefix":3347823042,"expiration":"2021-03-10T12:18:48","operations":[{"type":"transfer_operation","value":{"from":"initminer","to":"deepcrypto8","amount":{"amount":"100000000","precision":3,"nai":"@@000000021"},"memo":""}}],"extensions":[],"signatures":["1f55c34b9fab328de76d7c4afd30ca1b64742f46d2aee759b66fc9b0e9d90653a44dbad1ef583c9578666abc23db0ca540f32746d7ac4ff7a6394d28a2c9ef29f3"]}],"block_id":"00006dd7a264f6a8d833ad88a7eeb3abdd483af3","signing_key":"TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4","transaction_ids":["73eb9d7a19b9bcb941500f4a9924c13fe3b94c4a"]}},"id":"block_api.get_block"}
//{"jsonrpc":"2.0","result":{"block":{"previous":"00006de5714685397129f52693504ed3abde8e44","timestamp":"2021-03-10T12:19:06","witness":"initminer","transaction_merkle_root":"8b9bcb4b0aed33624a68abdf2860e76136ae9313","extensions":[],"witness_signature":"20f0743c1c3f63230f8af615e14ca0c5143ddfde0c5cee83c24486276223ceb21e7950f1b503750aad73f979bbdf6a298c9e22a079cc1397ed9d4a6eb8aeccea79","transactions":[{"ref_block_num":28133,"ref_block_prefix":965035633,"expiration":"2021-03-10T12:19:33","operations":[{"type":"transfer_operation","value":{"from":"initminer","to":"deepcrypto8","amount":{"amount":"100000000","precision":3,"nai":"@@000000021"},"memo":""}}],"extensions":[],"signatures":["1f519b0e13ee672108670540f846ad7cef676c94e3169e2d4c3ff12b5dad6dc412154cb45677b2caa0f839b5e2826ae96d6bbf36987ab40a928c3e0081e10a082e"]}],"block_id":"00006de655bac50cb40e05fc02eaef112ccae454","signing_key":"TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4","transaction_ids":["28c09bb777827fbf41023c50600aef65e0c83a8b"]}},"id":"block_api.get_block"}
//{"jsonrpc":"2.0","result":{"block":{"previous":"00006dfe471f2224d4b6c3189c7a2a5ed261c277","timestamp":"2021-03-10T12:20:21","witness":"initminer","transaction_merkle_root":"e407272ab2e383e5fef487651d88e0c0c3617e29","extensions":[],"witness_signature":"1f48152244ad2036e3761248a93a9c38fb8c7ee8a0721f9f47ae267b63808e56c223ab15641ec2baad6be4a54db5df04ead9b7f1107dba267a89c02c49d8115fbf","transactions":[{"ref_block_num":28158,"ref_block_prefix":606216007,"expiration":"2021-03-10T12:20:48","operations":[{"type":"transfer_operation","value":{"from":"initminer","to":"deepcrypto8","amount":{"amount":"100000000","precision":3,"nai":"@@000000021"},"memo":""}}],"extensions":[],"signatures":["1f5b4c7a8695b6c68b6ee96000367ffa96c23d9f4ed8ca36f639b38351b8198d18626f3b8277ca5c92bd537c68db5f9730f3f9df59a8ce631e9dcf7ce53032796b"]}],"block_id":"00006dff4bcd9a790193924fe44d0bdc3fde1c83","signing_key":"TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4","transaction_ids":["50b8f4b268a0fa3a34698dd6f8152117343e6c06"]}},"id":"block_api.get_block"}
//const auto &vins = extract_info_from_block(block);
//const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>();