diff --git a/libraries/chain/include/graphene/chain/protocol/sidechain_transaction.hpp b/libraries/chain/include/graphene/chain/protocol/sidechain_transaction.hpp index dda3298f..01a4ce74 100644 --- a/libraries/chain/include/graphene/chain/protocol/sidechain_transaction.hpp +++ b/libraries/chain/include/graphene/chain/protocol/sidechain_transaction.hpp @@ -27,6 +27,7 @@ namespace graphene { namespace chain { struct fee_parameters_type { uint64_t fee = 0; }; asset fee; + son_id_type signer; account_id_type payer; sidechain_transaction_id_type sidechain_transaction_id; @@ -73,7 +74,7 @@ FC_REFLECT( graphene::chain::sidechain_transaction_create_operation, (fee)(payer (signers) ) FC_REFLECT( graphene::chain::sidechain_transaction_sign_operation::fee_parameters_type, (fee) ) -FC_REFLECT( graphene::chain::sidechain_transaction_sign_operation, (fee)(payer) +FC_REFLECT( graphene::chain::sidechain_transaction_sign_operation, (fee)(signer)(payer) (sidechain_transaction_id) (signature) ) diff --git a/libraries/chain/sidechain_transaction_evaluator.cpp b/libraries/chain/sidechain_transaction_evaluator.cpp index 124b050d..12bf2f42 100644 --- a/libraries/chain/sidechain_transaction_evaluator.cpp +++ b/libraries/chain/sidechain_transaction_evaluator.cpp @@ -49,13 +49,14 @@ object_id_type sidechain_transaction_create_evaluator::do_apply(const sidechain_ void_result sidechain_transaction_sign_evaluator::do_evaluate(const sidechain_transaction_sign_operation &op) { try { FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); // can be removed after HF date pass + FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." ); const auto &sto_idx = db().get_index_type().indices().get(); const auto &sto_obj = sto_idx.find(op.sidechain_transaction_id); FC_ASSERT(sto_obj != sto_idx.end(), "Sidechain transaction object not found"); - const auto &son_idx = db().get_index_type().indices().get(); - const auto &son_obj = son_idx.find(op.payer); + const auto &son_idx = db().get_index_type().indices().get(); + const auto &son_obj = son_idx.find(op.signer); FC_ASSERT(son_obj != son_idx.end(), "SON object not found"); bool expected = false; @@ -76,8 +77,8 @@ object_id_type sidechain_transaction_sign_evaluator::do_apply(const sidechain_tr const auto &sto_idx = db().get_index_type().indices().get(); auto sto_obj = sto_idx.find(op.sidechain_transaction_id); - const auto &son_idx = db().get_index_type().indices().get(); - auto son_obj = son_idx.find(op.payer); + const auto &son_idx = db().get_index_type().indices().get(); + auto son_obj = son_idx.find(op.signer); db().modify(*sto_obj, [&](sidechain_transaction_object &sto) { for (size_t i = 0; i < sto.signatures.size(); i++) { diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp index dc47beda..255aa342 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp @@ -25,7 +25,7 @@ public: std::vector get_sidechain_withdraw_addresses(); std::string get_private_key(std::string public_key); - bool proposal_exists(int32_t operation_tag, const object_id_type &object_id); + bool proposal_exists(int32_t operation_tag, const object_id_type &object_id, boost::optional proposal_op = boost::none); bool approve_proposal(const proposal_id_type &proposal_id, const son_id_type &son_id); void sidechain_event_data_received(const sidechain_event_data &sed); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp index b769ddfa..6d4f85cd 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp @@ -53,7 +53,7 @@ std::string sidechain_net_handler::get_private_key(std::string public_key) { return std::string(); } -bool sidechain_net_handler::proposal_exists(int32_t operation_tag, const object_id_type &object_id) { +bool sidechain_net_handler::proposal_exists(int32_t operation_tag, const object_id_type &object_id, boost::optional proposal_op) { bool result = false; @@ -92,6 +92,16 @@ bool sidechain_net_handler::proposal_exists(int32_t operation_tag, const object_ break; } + case chain::operation::tag::value: { + if (proposal_op) { + chain::operation proposal_op_obj_0 = proposal_op.get(); + result = ((proposal_op_obj_0.get().sidechain_transaction_id == op_obj_idx_0.get().sidechain_transaction_id) && + (proposal_op_obj_0.get().signer == op_obj_idx_0.get().signer) && + (proposal_op_obj_0.get().signature == op_obj_idx_0.get().signature)); + } + break; + } + default: return false; } @@ -296,6 +306,16 @@ void sidechain_net_handler::process_proposals() { break; } + case chain::operation::tag::value: { + sidechain_transaction_id_type st_id = op_obj_idx_0.get().sidechain_transaction_id; + const auto &idx = database.get_index_type().indices().get(); + const auto sto = idx.find(st_id); + if (sto != idx.end()) { + should_process = ((sto->sidechain == sidechain) && (sto->status == sidechain_transaction_status::valid)); + } + break; + } + case chain::operation::tag::value: { sidechain_transaction_id_type st_id = op_obj_idx_0.get().sidechain_transaction_id; const auto &idx = database.get_index_type().indices().get(); @@ -394,12 +414,24 @@ void sidechain_net_handler::process_sidechain_transactions() { return; } + const chain::global_property_object &gpo = database.get_global_properties(); sidechain_transaction_sign_operation sts_op; - sts_op.payer = plugin.get_current_son_object().son_account; + sts_op.signer = plugin.get_current_son_object().id; + sts_op.payer = gpo.parameters.son_account(); sts_op.sidechain_transaction_id = sto.id; sts_op.signature = processed_sidechain_tx; - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), sts_op); + 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); + proposal_op.proposed_ops.emplace_back(sts_op); + + if (proposal_exists(chain::operation::tag::value, sto.id, proposal_op.proposed_ops[0].op)) { + return; + } + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); try { trx.validate(); database.push_transaction(trx, database::validation_steps::skip_block_size_check); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index eb7c7170..807fc0ba 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -1151,6 +1151,41 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) break; } + case chain::operation::tag::value: { + using namespace bitcoin; + should_approve = true; + son_id_type signer = op_obj_idx_0.get().signer; + std::string signature = op_obj_idx_0.get().signature; + sidechain_transaction_id_type sidechain_transaction_id = op_obj_idx_0.get().sidechain_transaction_id; + std::vector in_amounts; + std::string tx_hex; + std::string redeem_script; + const auto &st_idx = database.get_index_type().indices().get(); + const auto sto = st_idx.find(sidechain_transaction_id); + if (sto == st_idx.end()) { + should_approve = false; + break; + } + + const auto &s_idx = database.get_index_type().indices().get(); + const auto son = s_idx.find(signer); + if (son == s_idx.end()) { + should_approve = false; + break; + } + + read_transaction_data(sto->transaction, tx_hex, in_amounts, redeem_script); + bitcoin_transaction tx = unpack(parse_hex(tx_hex)); + bitcoin::bytes pubkey = parse_hex(son->sidechain_public_keys.at(sidechain_type::bitcoin)); + vector sigs = read_byte_arrays_from_string(signature); + for (size_t i = 0; i < tx.vin.size(); i++) { + const auto &sighash_str = get_signature_hash(tx, parse_hex(redeem_script), static_cast(in_amounts[i]), i, 1, true).str(); + const bitcoin::bytes &sighash_hex = parse_hex(sighash_str); + should_approve = should_approve && verify_sig(sigs[i], pubkey, sighash_hex, btc_context()); + } + break; + } + case chain::operation::tag::value: { should_approve = true; break;