Prevent incorrect signatures to be added to transaction

This commit is contained in:
satyakoneru 2020-04-20 18:12:58 +00:00
parent d3385b28cb
commit 2a2440acf9
5 changed files with 78 additions and 9 deletions

View file

@ -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) )

View file

@ -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<sidechain_transaction_index>().indices().get<by_id>();
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<son_index>().indices().get<by_account>();
const auto &son_obj = son_idx.find(op.payer);
const auto &son_idx = db().get_index_type<son_index>().indices().get<by_id>();
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<sidechain_transaction_index>().indices().get<by_id>();
auto sto_obj = sto_idx.find(op.sidechain_transaction_id);
const auto &son_idx = db().get_index_type<son_index>().indices().get<by_account>();
auto son_obj = son_idx.find(op.payer);
const auto &son_idx = db().get_index_type<son_index>().indices().get<by_id>();
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++) {

View file

@ -25,7 +25,7 @@ public:
std::vector<std::string> 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<chain::operation &> 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);

View file

@ -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<chain::operation &> 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<chain::sidechain_transaction_sign_operation>::value: {
if (proposal_op) {
chain::operation proposal_op_obj_0 = proposal_op.get();
result = ((proposal_op_obj_0.get<sidechain_transaction_sign_operation>().sidechain_transaction_id == op_obj_idx_0.get<sidechain_transaction_sign_operation>().sidechain_transaction_id) &&
(proposal_op_obj_0.get<sidechain_transaction_sign_operation>().signer == op_obj_idx_0.get<sidechain_transaction_sign_operation>().signer) &&
(proposal_op_obj_0.get<sidechain_transaction_sign_operation>().signature == op_obj_idx_0.get<sidechain_transaction_sign_operation>().signature));
}
break;
}
default:
return false;
}
@ -296,6 +306,16 @@ void sidechain_net_handler::process_proposals() {
break;
}
case chain::operation::tag<chain::sidechain_transaction_sign_operation>::value: {
sidechain_transaction_id_type st_id = op_obj_idx_0.get<sidechain_transaction_sign_operation>().sidechain_transaction_id;
const auto &idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_id>();
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<chain::sidechain_transaction_settle_operation>::value: {
sidechain_transaction_id_type st_id = op_obj_idx_0.get<sidechain_transaction_settle_operation>().sidechain_transaction_id;
const auto &idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_id>();
@ -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<chain::sidechain_transaction_sign_operation>::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);

View file

@ -1151,6 +1151,41 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
break;
}
case chain::operation::tag<chain::sidechain_transaction_sign_operation>::value: {
using namespace bitcoin;
should_approve = true;
son_id_type signer = op_obj_idx_0.get<sidechain_transaction_sign_operation>().signer;
std::string signature = op_obj_idx_0.get<sidechain_transaction_sign_operation>().signature;
sidechain_transaction_id_type sidechain_transaction_id = op_obj_idx_0.get<sidechain_transaction_sign_operation>().sidechain_transaction_id;
std::vector<uint64_t> in_amounts;
std::string tx_hex;
std::string redeem_script;
const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_id>();
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<son_index>().indices().get<by_id>();
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<bitcoin::bytes> 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<int64_t>(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<chain::sidechain_transaction_settle_operation>::value: {
should_approve = true;
break;