Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SON-304] Parallelize Bitcoin transaction signing #319

Merged
merged 1 commit into from
Mar 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/sidechain_defs.hpp>
#include <graphene/chain/son_info.hpp>

namespace graphene { namespace chain {

Expand All @@ -15,7 +16,7 @@ namespace graphene { namespace chain {
sidechain_type sidechain;
object_id_type object_id;
std::string transaction;
std::vector<son_id_type> signers;
std::vector<son_info> signers;

account_id_type fee_payer()const { return payer; }
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
Expand All @@ -29,8 +30,7 @@ namespace graphene { namespace chain {
account_id_type payer;

sidechain_transaction_id_type sidechain_transaction_id;
std::string transaction;
block_id_type block;
std::string signature;
bool complete;

account_id_type fee_payer()const { return payer; }
Expand All @@ -45,6 +45,7 @@ namespace graphene { namespace chain {
account_id_type payer;

sidechain_transaction_id_type sidechain_transaction_id;
std::string sidechain_transaction;

account_id_type fee_payer()const { return payer; }
share_type calculate_fee( const fee_parameters_type& k )const { return 0; }
Expand All @@ -62,10 +63,10 @@ FC_REFLECT( graphene::chain::sidechain_transaction_create_operation, (fee)(payer
FC_REFLECT( graphene::chain::sidechain_transaction_sign_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::sidechain_transaction_sign_operation, (fee)(payer)
(sidechain_transaction_id)
(transaction)
(block)
(signature)
(complete) )

FC_REFLECT( graphene::chain::sidechain_transaction_send_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::sidechain_transaction_send_operation, (fee)(payer)
(sidechain_transaction_id) )
(sidechain_transaction_id)
(sidechain_transaction) )
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ namespace graphene { namespace chain {
sidechain_type sidechain;
object_id_type object_id;
std::string transaction;
std::vector<std::pair<son_id_type, bool>> signers;
std::vector<son_info> signers;
std::vector<std::pair<son_id_type, std::string>> signatures;
std::string sidechain_transaction;

block_id_type block;
uint32_t total_weight = 0;
uint32_t current_weight = 0;
uint32_t threshold = 0;
bool valid = false;
bool complete = false;
bool sent = false;
Expand Down Expand Up @@ -63,7 +67,11 @@ FC_REFLECT_DERIVED( graphene::chain::sidechain_transaction_object, (graphene::db
(object_id)
(transaction)
(signers)
(block)
(signatures)
(sidechain_transaction)
(total_weight)
(current_weight)
(threshold)
(valid)
(complete)
(sent) )
38 changes: 23 additions & 15 deletions libraries/chain/sidechain_transaction_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ void_result sidechain_transaction_create_evaluator::do_evaluate(const sidechain_
FC_ASSERT(sto_obj == sto_idx.end(), "Sidechain transaction for a given object is already created");

FC_ASSERT(!op.transaction.empty(), "Sidechain transaction data not set");
FC_ASSERT(op.signers.size() > 0, "Sidechain transaction signers not set");

return void_result();
} FC_CAPTURE_AND_RETHROW( ( op ) ) }
Expand All @@ -30,10 +31,16 @@ object_id_type sidechain_transaction_create_evaluator::do_apply(const sidechain_
sto.sidechain = op.sidechain;
sto.object_id = op.object_id;
sto.transaction = op.transaction;
std::transform(op.signers.begin(), op.signers.end(), std::inserter(sto.signers, sto.signers.end()), [](const son_id_type son_id) {
return std::make_pair(son_id, false);
sto.signers = op.signers;
std::transform(op.signers.begin(), op.signers.end(), std::inserter(sto.signatures, sto.signatures.end()), [](const son_info &si) {
return std::make_pair(si.son_id, std::string());
});
sto.block = db().head_block_id();
for (const auto &si : op.signers) {
sto.total_weight = sto.total_weight + si.total_votes;
}
sto.sidechain_transaction = "";
sto.current_weight = 0;
sto.threshold = sto.total_weight * 2 / 3 + 1;
sto.valid = true;
sto.complete = false;
sto.sent = false;
Expand All @@ -54,15 +61,13 @@ void_result sidechain_transaction_sign_evaluator::do_evaluate(const sidechain_tr
FC_ASSERT(son_obj != son_idx.end(), "SON object not found");

bool expected = false;
for (auto signer : sto_obj->signers) {
if (signer.first == son_obj->id) {
expected = !signer.second;
for (auto signature : sto_obj->signatures) {
if (signature.first == son_obj->id) {
expected = signature.second.empty();
}
}
FC_ASSERT(expected, "Signer not expected");

FC_ASSERT(sto_obj->block == op.block, "Sidechain transaction already signed in this block");

FC_ASSERT(sto_obj->valid, "Transaction not valid");
FC_ASSERT(!sto_obj->complete, "Transaction signing completed");
FC_ASSERT(!sto_obj->sent, "Transaction already sent");
Expand All @@ -79,14 +84,17 @@ object_id_type sidechain_transaction_sign_evaluator::do_apply(const sidechain_tr
auto son_obj = son_idx.find(op.payer);

db().modify(*sto_obj, [&](sidechain_transaction_object &sto) {
sto.transaction = op.transaction;
sto.block = db().head_block_id();
sto.complete = op.complete;
for (size_t i = 0; i < sto.signatures.size(); i++) {
if (sto.signatures.at(i).first == son_obj->id) {
sto.signatures.at(i).second = op.signature;
}
}
for (size_t i = 0; i < sto.signers.size(); i++) {
if (sto.signers.at(i).first == son_obj->id) {
sto.signers.at(i).second = true;
}
if (sto.signers.at(i).son_id == son_obj->id) {
sto.current_weight = sto.current_weight + sto.signers.at(i).total_votes;
}
}
sto.complete = op.complete;
});

db().modify(son_obj->statistics(db()), [&](son_statistics_object& sso) {
Expand Down Expand Up @@ -117,7 +125,7 @@ object_id_type sidechain_transaction_send_evaluator::do_apply(const sidechain_tr
auto sto_obj = sto_idx.find(op.sidechain_transaction_id);

db().modify(*sto_obj, [&](sidechain_transaction_object &sto) {
sto.block = db().head_block_id();
sto.sidechain_transaction = op.sidechain_transaction;
sto.sent = true;
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class sidechain_net_handler {
virtual bool process_deposit(const son_wallet_deposit_object &swdo) = 0;
virtual bool process_withdrawal(const son_wallet_withdraw_object &swwo) = 0;
virtual std::string process_sidechain_transaction(const sidechain_transaction_object &sto, bool &complete) = 0;
virtual bool send_sidechain_transaction(const sidechain_transaction_object &sto) = 0;
virtual bool send_sidechain_transaction(const sidechain_transaction_object &sto, std::string &sidechain_transaction) = 0;

protected:
peerplays_sidechain_plugin &plugin;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class bitcoin_rpc_client {
bitcoin_rpc_client(std::string _ip, uint32_t _rpc, std::string _user, std::string _password, std::string _wallet, std::string _wallet_password);

std::string addmultisigaddress(const uint32_t nrequired, const std::vector<std::string> public_keys);
std::string combinepsbt(const vector<std::string> &psbts);
std::string createpsbt(const std::vector<btc_txout> &ins, const fc::flat_map<std::string, double> outs);
std::string createrawtransaction(const std::vector<btc_txout> &ins, const fc::flat_map<std::string, double> outs);
std::string createwallet(const std::string &wallet_name);
Expand Down Expand Up @@ -86,7 +87,7 @@ class sidechain_net_handler_bitcoin : public sidechain_net_handler {
bool process_deposit(const son_wallet_deposit_object &swdo);
bool process_withdrawal(const son_wallet_withdraw_object &swwo);
std::string process_sidechain_transaction(const sidechain_transaction_object &sto, bool &complete);
bool send_sidechain_transaction(const sidechain_transaction_object &sto);
bool send_sidechain_transaction(const sidechain_transaction_object &sto, std::string &sidechain_transaction);

private:
std::string ip;
Expand All @@ -103,16 +104,19 @@ class sidechain_net_handler_bitcoin : public sidechain_net_handler {
fc::future<void> on_changed_objects_task;

std::string create_transaction(const std::vector<btc_txout> &inputs, const fc::flat_map<std::string, double> outputs);
std::string sign_transaction(const std::string &tx, bool &complete);
bool send_transaction(const std::string &tx);
std::string sign_transaction(const sidechain_transaction_object &sto, bool &complete);
bool send_transaction(const sidechain_transaction_object &sto, std::string &sidechain_transaction);

std::string create_transaction_raw(const std::vector<btc_txout> &inputs, const fc::flat_map<std::string, double> outputs);
std::string create_transaction_psbt(const std::vector<btc_txout> &inputs, const fc::flat_map<std::string, double> outputs);
std::string create_transaction_standalone(const std::vector<btc_txout> &inputs, const fc::flat_map<std::string, double> outputs);

std::string sign_transaction_raw(const std::string &tx, bool &complete);
std::string sign_transaction_psbt(const std::string &tx, bool &complete);
std::string sign_transaction_standalone(const std::string &tx, bool &complete);
std::string sign_transaction_raw(const sidechain_transaction_object &sto, bool &complete);
std::string sign_transaction_psbt(const sidechain_transaction_object &sto, bool &complete);
std::string sign_transaction_standalone(const sidechain_transaction_object &sto, bool &complete);

bool send_transaction_raw(const sidechain_transaction_object &sto, std::string &sidechain_transaction);
bool send_transaction_psbt(const sidechain_transaction_object &sto, std::string &sidechain_transaction);

void handle_event(const std::string &event_data);
std::vector<info_for_vin> extract_info_from_block(const std::string &_block);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class sidechain_net_handler_peerplays : public sidechain_net_handler {
bool process_deposit(const son_wallet_deposit_object &swdo);
bool process_withdrawal(const son_wallet_withdraw_object &swwo);
std::string process_sidechain_transaction(const sidechain_transaction_object &sto, bool &complete);
bool send_sidechain_transaction(const sidechain_transaction_object &sto);
bool send_sidechain_transaction(const sidechain_transaction_object &sto, std::string &sidechain_transaction);

private:
void on_applied_block(const signed_block &b);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,9 @@ void peerplays_sidechain_plugin_impl::son_processing() {
// Tasks that are executed by all active SONs, no matter if scheduled
// E.g. sending approvals and signing (only signing that can be done in parallel)
approve_proposals();
process_sidechain_transactions();

// Tasks that are executed by scheduled and active SON
// Tasks that are executed by scheduled and active SON only
if (current_son_id == scheduled_son_id) {

create_son_down_proposals();
Expand All @@ -375,6 +376,8 @@ void peerplays_sidechain_plugin_impl::son_processing() {
// E.g. sending approvals and signing that SON was required to do while it was active
//approve_leftover_proposals(); ???
//process_leftover_sidechain_transactions(); ???
approve_proposals();
process_sidechain_transactions();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,7 @@ void sidechain_net_handler::process_sidechain_transactions() {
sidechain_transaction_sign_operation sts_op;
sts_op.payer = plugin.get_current_son_object().son_account;
sts_op.sidechain_transaction_id = sto.id;
sts_op.transaction = processed_sidechain_tx;
sts_op.block = sto.block;
sts_op.signature = processed_sidechain_tx;
sts_op.complete = complete;

signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), sts_op);
Expand All @@ -281,7 +280,8 @@ void sidechain_net_handler::send_sidechain_transactions() {
std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) {
ilog("Sidechain transaction to send: ${sto}", ("sto", sto));

bool sent = send_sidechain_transaction(sto);
std::string sidechain_transaction = "";
bool sent = send_sidechain_transaction(sto, sidechain_transaction);

if (!sent) {
wlog("Sidechain transaction not sent: ${sto}", ("sto", sto));
Expand All @@ -291,6 +291,7 @@ void sidechain_net_handler::send_sidechain_transactions() {
sidechain_transaction_send_operation sts_op;
sts_op.payer = plugin.get_current_son_object().son_account;
sts_op.sidechain_transaction_id = sto.id;
sts_op.sidechain_transaction = sidechain_transaction;

signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), sts_op);
trx.validate();
Expand Down Expand Up @@ -320,7 +321,7 @@ std::string sidechain_net_handler::process_sidechain_transaction(const sidechain
FC_ASSERT(false, "process_sidechain_transaction not implemented");
}

bool sidechain_net_handler::send_sidechain_transaction(const sidechain_transaction_object &sto) {
bool sidechain_net_handler::send_sidechain_transaction(const sidechain_transaction_object &sto, std::string &sidechain_transaction) {
FC_ASSERT(false, "send_sidechain_transaction not implemented");
}

Expand Down
Loading