Added class sidechain_proposal_checker
This commit is contained in:
parent
0eda7025c9
commit
ec3b7e8b80
20 changed files with 508 additions and 53 deletions
|
|
@ -52,24 +52,25 @@ object_id_type bitcoin_transaction_send_evaluator::do_apply( const bitcoin_trans
|
|||
return btc_tx.id;
|
||||
}
|
||||
|
||||
std::vector< info_for_used_vin_id_type > bitcoin_transaction_send_evaluator::create_transaction_vins( bitcoin_transaction_send_operation& op )
|
||||
std::vector<fc::sha256> bitcoin_transaction_send_evaluator::create_transaction_vins( bitcoin_transaction_send_operation& op )
|
||||
{
|
||||
database& d = db();
|
||||
std::vector< info_for_used_vin_id_type > new_vins;
|
||||
std::vector<fc::sha256> new_vins;
|
||||
|
||||
for( auto itr : op.vins ){
|
||||
auto itr_id = d.create< info_for_used_vin_object >( [&]( info_for_used_vin_object& obj )
|
||||
for( auto itr : op.vins ) {
|
||||
auto info_for_used_vin_itr = d.create< info_for_used_vin_object >( [&]( info_for_used_vin_object& obj )
|
||||
{
|
||||
obj.identifier = itr.identifier;
|
||||
obj.out = itr.out;
|
||||
obj.address = itr.address;
|
||||
obj.script = itr.script;
|
||||
}).get_id();
|
||||
new_vins.push_back( itr_id );
|
||||
});
|
||||
new_vins.push_back( info_for_used_vin_itr.identifier );
|
||||
|
||||
auto obj_itr = d.i_w_info.find_info_for_vin( itr.identifier );
|
||||
if( obj_itr.valid() )
|
||||
if( obj_itr.valid() ) {
|
||||
d.i_w_info.remove_info_for_vin( *obj_itr );
|
||||
}
|
||||
}
|
||||
|
||||
return new_vins;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <sidechain/sidechain_condensing_tx.hpp>
|
||||
#include <sidechain/sign_bitcoin_transaction.hpp>
|
||||
#include <sidechain/sidechain_proposal_checker.hpp>
|
||||
|
||||
using namespace sidechain;
|
||||
|
||||
|
|
@ -129,11 +130,17 @@ void database::processing_sidechain_proposals( const witness_object& current_wit
|
|||
const auto& sidechain_proposal_idx = get_index_type<sidechain_proposal_index>().indices().get< by_id >();
|
||||
const auto& proposal_idx = get_index_type<proposal_index>().indices().get< by_id >();
|
||||
|
||||
sidechain_proposal_checker checker( *this );
|
||||
|
||||
for( auto& sidechain_proposal : sidechain_proposal_idx ) {
|
||||
|
||||
const auto& proposal = proposal_idx.find( sidechain_proposal.proposal_id );
|
||||
FC_ASSERT( proposal != proposal_idx.end() );
|
||||
|
||||
if( !checker.check_reuse( proposal->proposed_transaction.operations.back() ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch( sidechain_proposal.proposal_type ) {
|
||||
case sidechain_proposal_type::ISSUE_BTC :{
|
||||
proposal_update_operation puo;
|
||||
|
|
@ -144,8 +151,12 @@ void database::processing_sidechain_proposals( const witness_object& current_wit
|
|||
break;
|
||||
}
|
||||
case sidechain_proposal_type::SEND_BTC_TRANSACTION :{
|
||||
const auto& sign_operation = create_sign_btc_tx_operation( current_witness, private_key, proposal->id );
|
||||
_pending_tx.insert( _pending_tx.begin(), create_signed_transaction( private_key, sign_operation ) );
|
||||
bitcoin_transaction_send_operation op = proposal->proposed_transaction.operations.back().get<bitcoin_transaction_send_operation>();
|
||||
if( checker.check_bitcoin_transaction_send_operation( op ) )
|
||||
{
|
||||
const auto& sign_operation = create_sign_btc_tx_operation( current_witness, private_key, proposal->id );
|
||||
_pending_tx.insert( _pending_tx.begin(), create_signed_transaction( private_key, sign_operation ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case sidechain_proposal_type::RETURN_PBTC_BACK :{}
|
||||
|
|
@ -174,7 +185,7 @@ full_btc_transaction database::create_btc_transaction( const std::vector<info_fo
|
|||
ctx.create_pw_vout( change, pw_address.get_witness_script() );
|
||||
}
|
||||
|
||||
const uint64_t& size_fee = get_estimated_fee( ctx.get_estimate_tx_size( pw_address.witnesses_keys.size() ), estimated_feerate.load() );
|
||||
const uint64_t& size_fee = get_estimated_fee( sidechain_condensing_tx::get_estimate_tx_size( ctx.get_transaction(), pw_address.witnesses_keys.size() ), estimated_feerate.load() );
|
||||
ctx.subtract_fee( size_fee, get_sidechain_params().percent_payment_to_witnesses );
|
||||
|
||||
return std::make_pair( ctx.get_transaction(), size_fee );
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public:
|
|||
|
||||
object_id_type do_apply( const bitcoin_transaction_send_operation& op );
|
||||
|
||||
std::vector< info_for_used_vin_id_type > create_transaction_vins( bitcoin_transaction_send_operation& op );
|
||||
std::vector<fc::sha256> create_transaction_vins( bitcoin_transaction_send_operation& op );
|
||||
|
||||
void finalize_bitcoin_transaction( bitcoin_transaction_send_operation& op );
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class bitcoin_transaction_object : public abstract_object<bitcoin_transaction_ob
|
|||
|
||||
fc::sha256 pw_vin;
|
||||
|
||||
std::vector< info_for_used_vin_id_type > vins;
|
||||
std::vector< fc::sha256 > vins;
|
||||
std::vector< info_for_vout_id_type > vouts;
|
||||
|
||||
sidechain::bitcoin_transaction transaction;
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ struct bitcoin_issue_evaluator : public evaluator< bitcoin_issue_evaluator >
|
|||
|
||||
void clear_btc_transaction_information( const bitcoin_transaction_object& btc_obj );
|
||||
|
||||
std::vector<uint64_t> get_amounts_to_issue( std::vector<info_for_used_vin_id_type> vins_id );
|
||||
std::vector<uint64_t> get_amounts_to_issue( std::vector<fc::sha256> vins_identifier );
|
||||
|
||||
std::vector<account_id_type> get_accounts_to_issue( std::vector<info_for_used_vin_id_type> vins_id );
|
||||
std::vector<account_id_type> get_accounts_to_issue( std::vector<fc::sha256> vins_identifier );
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
@ -11,7 +11,7 @@ void_result bitcoin_issue_evaluator::do_evaluate( const bitcoin_issue_operation&
|
|||
|
||||
const auto& btc_trx_idx = d.get_index_type<bitcoin_transaction_index>().indices().get<by_transaction_id>();
|
||||
const auto& btc_addr_idx = d.get_index_type<bitcoin_address_index>().indices().get<by_address>();
|
||||
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
|
||||
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_identifier>();
|
||||
const auto& vouts_info_idx = d.get_index_type<info_for_vout_index>().indices().get<by_id>();
|
||||
FC_ASSERT( op.payer == db().get_sidechain_account_id() );
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ void bitcoin_issue_evaluator::add_issue( const bitcoin_transaction_object& btc_o
|
|||
void bitcoin_issue_evaluator::clear_btc_transaction_information( const bitcoin_transaction_object& btc_obj )
|
||||
{
|
||||
database& d = db();
|
||||
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
|
||||
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_identifier>();
|
||||
const auto& vouts_info_idx = d.get_index_type<info_for_vout_index>().indices().get<by_id>();
|
||||
|
||||
for( auto& vin_id : btc_obj.vins ) {
|
||||
|
|
@ -103,31 +103,31 @@ void bitcoin_issue_evaluator::clear_btc_transaction_information( const bitcoin_t
|
|||
d.remove( btc_obj );
|
||||
}
|
||||
|
||||
std::vector<uint64_t> bitcoin_issue_evaluator::get_amounts_to_issue( std::vector<info_for_used_vin_id_type> vins_id )
|
||||
std::vector<uint64_t> bitcoin_issue_evaluator::get_amounts_to_issue( std::vector<fc::sha256> vins_identifier )
|
||||
{
|
||||
database& d = db();
|
||||
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
|
||||
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_identifier>();
|
||||
|
||||
std::vector<uint64_t> result;
|
||||
|
||||
for( auto& id : vins_id ) {
|
||||
auto vin_itr = vins_info_idx.find( id );
|
||||
for( auto& identifier : vins_identifier ) {
|
||||
auto vin_itr = vins_info_idx.find( identifier );
|
||||
result.push_back( vin_itr->out.amount );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<account_id_type> bitcoin_issue_evaluator::get_accounts_to_issue( std::vector<info_for_used_vin_id_type> vins_id )
|
||||
std::vector<account_id_type> bitcoin_issue_evaluator::get_accounts_to_issue( std::vector<fc::sha256> vins_identifier )
|
||||
{
|
||||
database& d = db();
|
||||
const auto& btc_addr_idx = d.get_index_type<bitcoin_address_index>().indices().get<by_address>();
|
||||
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
|
||||
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_identifier>();
|
||||
|
||||
std::vector<account_id_type> result;
|
||||
|
||||
for( auto& id : vins_id ) {
|
||||
auto vin_itr = vins_info_idx.find( id );
|
||||
for( auto& identifier : vins_identifier ) {
|
||||
auto vin_itr = vins_info_idx.find( identifier );
|
||||
auto addr_itr = btc_addr_idx.find( vin_itr->address );
|
||||
|
||||
result.push_back( addr_itr->owner );
|
||||
|
|
|
|||
|
|
@ -2,9 +2,31 @@
|
|||
#include <sstream>
|
||||
#include <fc/crypto/base58.hpp>
|
||||
#include <sidechain/segwit_addr.hpp>
|
||||
#include <sidechain/bitcoin_script.hpp>
|
||||
|
||||
namespace sidechain {
|
||||
|
||||
bytes bitcoin_address::get_script() const
|
||||
{
|
||||
switch ( type ) {
|
||||
case payment_type::NULLDATA:
|
||||
return script_builder() << op::RETURN << raw_address;
|
||||
case payment_type::P2PK:
|
||||
return script_builder() << raw_address << op::CHECKSIG;
|
||||
case payment_type::P2PKH:
|
||||
return script_builder() << op::DUP << op::HASH160 << raw_address << op::EQUALVERIFY << op::CHECKSIG;
|
||||
case payment_type::P2SH:
|
||||
case payment_type::P2SH_WPKH:
|
||||
case payment_type::P2SH_WSH:
|
||||
return script_builder() << op::HASH160 << raw_address << op::EQUAL;
|
||||
case payment_type::P2WPKH:
|
||||
case payment_type::P2WSH:
|
||||
return script_builder() << op::_0 << raw_address;
|
||||
default:
|
||||
return raw_address;
|
||||
}
|
||||
}
|
||||
|
||||
payment_type bitcoin_address::determine_type()
|
||||
{
|
||||
if( is_p2pk() ) {
|
||||
|
|
@ -22,7 +44,7 @@ payment_type bitcoin_address::determine_type()
|
|||
}
|
||||
}
|
||||
|
||||
bytes bitcoin_address::determine_raw_address( const payment_type& type )
|
||||
bytes bitcoin_address::determine_raw_address()
|
||||
{
|
||||
bytes result;
|
||||
switch( type ) {
|
||||
|
|
@ -192,6 +214,14 @@ bool btc_multisig_segwit_address::operator==( const btc_multisig_segwit_address&
|
|||
return true;
|
||||
}
|
||||
|
||||
std::vector<public_key_type> btc_multisig_segwit_address::get_keys() {
|
||||
std::vector<public_key_type> keys;
|
||||
for( const auto& k : witnesses_keys ) {
|
||||
keys.push_back( k.second );
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
void btc_multisig_segwit_address::create_witness_script()
|
||||
{
|
||||
const auto redeem_sha256 = fc::sha256::hash( redeem_script.data(), redeem_script.size() );
|
||||
|
|
|
|||
|
|
@ -5,6 +5,37 @@
|
|||
|
||||
namespace sidechain {
|
||||
|
||||
bool out_point::operator==( const out_point& op ) const
|
||||
{
|
||||
if( this->hash == op.hash &&
|
||||
this->n == op.n )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool tx_in::operator==( const tx_in& ti ) const
|
||||
{
|
||||
if( this->prevout == ti.prevout &&
|
||||
this->scriptSig == ti.scriptSig &&
|
||||
this->nSequence == ti.nSequence )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool tx_out::operator==( const tx_out& to ) const
|
||||
{
|
||||
if( this->value == to.value &&
|
||||
this->scriptPubKey == to.scriptPubKey )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool tx_out::is_p2wsh() const
|
||||
{
|
||||
if( scriptPubKey.size() == 34 && scriptPubKey[0] == static_cast<char>(0x00) && scriptPubKey[1] == static_cast<char>(0x20) ) {
|
||||
|
|
@ -61,6 +92,18 @@ bytes tx_out::get_data_or_script() const
|
|||
return scriptPubKey;
|
||||
}
|
||||
|
||||
bool bitcoin_transaction::operator!=( const bitcoin_transaction& bt ) const
|
||||
{
|
||||
if( this->nVersion != bt.nVersion ||
|
||||
this->vin != bt.vin ||
|
||||
this->vout != bt.vout ||
|
||||
this->nLockTime != bt.nLockTime )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fc::sha256 bitcoin_transaction::get_hash() const
|
||||
{
|
||||
const auto bytes = pack( *this, true) ;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ public:
|
|||
bitcoin_address() = default;
|
||||
|
||||
bitcoin_address( const std::string& addr ) : address( addr ), type( determine_type() ),
|
||||
raw_address( determine_raw_address( type ) ) {}
|
||||
raw_address( determine_raw_address() ) {}
|
||||
|
||||
payment_type get_type() const { return type; }
|
||||
|
||||
|
|
@ -25,13 +25,15 @@ public:
|
|||
|
||||
bytes get_raw_address() const { return raw_address; }
|
||||
|
||||
bytes get_script() const;
|
||||
|
||||
private:
|
||||
|
||||
enum size_segwit_address { P2WSH = 32, P2WPKH = 20 };
|
||||
|
||||
payment_type determine_type();
|
||||
|
||||
bytes determine_raw_address( const payment_type& type );
|
||||
bytes determine_raw_address();
|
||||
|
||||
bool check_segwit_address( const size_segwit_address& size ) const;
|
||||
|
||||
|
|
@ -103,6 +105,8 @@ public:
|
|||
|
||||
bytes get_witness_script() const { return witness_script; }
|
||||
|
||||
std::vector<public_key_type> get_keys();
|
||||
|
||||
private:
|
||||
|
||||
void create_witness_script();
|
||||
|
|
|
|||
|
|
@ -8,9 +8,13 @@ struct out_point {
|
|||
uint32_t n = 0;
|
||||
out_point() = default;
|
||||
out_point( fc::sha256 _hash, uint32_t _n ) : hash( _hash ), n( _n ) {}
|
||||
bool operator==( const out_point& op ) const;
|
||||
};
|
||||
|
||||
struct tx_in {
|
||||
|
||||
bool operator==( const tx_in& ti ) const;
|
||||
|
||||
out_point prevout;
|
||||
bytes scriptSig;
|
||||
uint32_t nSequence = 0xffffffff;
|
||||
|
|
@ -21,6 +25,8 @@ struct tx_out {
|
|||
int64_t value = 0;
|
||||
bytes scriptPubKey;
|
||||
|
||||
bool operator==( const tx_out& to ) const;
|
||||
|
||||
bool is_p2wsh() const;
|
||||
|
||||
bool is_p2wpkh() const;
|
||||
|
|
@ -35,14 +41,17 @@ struct tx_out {
|
|||
};
|
||||
|
||||
struct bitcoin_transaction {
|
||||
int32_t nVersion = 1;
|
||||
std::vector<tx_in> vin;
|
||||
std::vector<tx_out> vout;
|
||||
uint32_t nLockTime = 0;
|
||||
|
||||
fc::sha256 get_hash() const;
|
||||
fc::sha256 get_txid() const;
|
||||
size_t get_vsize() const;
|
||||
bool operator!=( const bitcoin_transaction& bt ) const;
|
||||
|
||||
int32_t nVersion = 1;
|
||||
std::vector<tx_in> vin;
|
||||
std::vector<tx_out> vout;
|
||||
uint32_t nLockTime = 0;
|
||||
|
||||
fc::sha256 get_hash() const;
|
||||
fc::sha256 get_txid() const;
|
||||
size_t get_vsize() const;
|
||||
};
|
||||
|
||||
class bitcoin_transaction_builder
|
||||
|
|
|
|||
|
|
@ -22,10 +22,9 @@ struct info_for_vin
|
|||
{
|
||||
info_for_vin() = default;
|
||||
|
||||
info_for_vin( const prev_out& _out, const std::string& _address, bytes _script = bytes() ) :
|
||||
id( count_id_info_for_vin++ ), out( _out ), address( _address ), script( _script ) {
|
||||
identifier = fc::sha256::hash( out.hash_tx + std::to_string( out.n_vout ) );
|
||||
}
|
||||
info_for_vin( const prev_out& _out, const std::string& _address, bytes _script = bytes() );
|
||||
|
||||
bool operator!=( const info_for_vin& obj ) const;
|
||||
|
||||
struct comparer {
|
||||
bool operator() ( const info_for_vin& lhs, const info_for_vin& rhs ) const;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public:
|
|||
|
||||
void create_vouts_for_witness_fee( const accounts_keys& witness_active_keys, bool front = true );
|
||||
|
||||
uint64_t get_estimate_tx_size( size_t number_witness ) const;
|
||||
static uint64_t get_estimate_tx_size( bitcoin_transaction tx, size_t number_witness );
|
||||
|
||||
void subtract_fee( const uint64_t& fee, const uint16_t& witnesses_percentage );
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
#include <sidechain/types.hpp>
|
||||
#include <sidechain/input_withdrawal_info.hpp>
|
||||
#include <graphene/chain/protocol/bitcoin_transaction.hpp>
|
||||
#include <graphene/chain/protocol/operations.hpp>
|
||||
|
||||
namespace graphene { namespace chain { class database; } };
|
||||
|
||||
namespace sidechain {
|
||||
|
||||
class sidechain_proposal_checker
|
||||
{
|
||||
|
||||
public:
|
||||
sidechain_proposal_checker( graphene::chain::database& _db ) : db(_db) {}
|
||||
|
||||
bool check_bitcoin_transaction_send_operation( const bitcoin_transaction_send_operation& op );
|
||||
|
||||
bool check_reuse( const graphene::chain::operation& op );
|
||||
|
||||
private:
|
||||
|
||||
bool check_info_for_pw_vin( const info_for_vin& info_for_vin );
|
||||
|
||||
bool check_info_for_vins( const std::vector<info_for_vin>& info_for_vins );
|
||||
|
||||
bool check_info_for_vouts( const std::vector<info_for_vout_id_type>& info_for_vout_ids );
|
||||
|
||||
bool check_transaction( const bitcoin_transaction_send_operation& btc_trx_op );
|
||||
|
||||
bool check_reuse_pw_vin( const fc::sha256& pw_vin );
|
||||
|
||||
bool check_reuse_user_vins( const std::vector<fc::sha256>& user_vin_identifiers );
|
||||
|
||||
bool check_reuse_vouts( const std::vector<info_for_vout_id_type>& user_vout_ids );
|
||||
|
||||
std::set<fc::sha256> pw_vin_ident;
|
||||
std::set<fc::sha256> user_vin_ident;
|
||||
std::set<info_for_vout_id_type> vout_ids;
|
||||
|
||||
graphene::chain::database& db;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -37,6 +37,17 @@ enum class sidechain_proposal_type
|
|||
|
||||
struct prev_out
|
||||
{
|
||||
bool operator!=( const prev_out& obj ) const
|
||||
{
|
||||
if( this->hash_tx != obj.hash_tx ||
|
||||
this->n_vout != obj.n_vout ||
|
||||
this->amount != obj.amount )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string hash_tx;
|
||||
uint32_t n_vout;
|
||||
uint64_t amount;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,26 @@ namespace sidechain {
|
|||
uint64_t info_for_vin::count_id_info_for_vin = 0;
|
||||
uint64_t bitcoin_transaction_confirmations::count_id_tx_conf = 0;
|
||||
|
||||
info_for_vin::info_for_vin( const prev_out& _out, const std::string& _address, bytes _script ) :
|
||||
id( count_id_info_for_vin++ ), out( _out ), address( _address ), script( _script )
|
||||
{
|
||||
identifier = fc::sha256::hash( out.hash_tx + std::to_string( out.n_vout ) );
|
||||
}
|
||||
|
||||
bool info_for_vin::operator!=( const info_for_vin& obj ) const
|
||||
{
|
||||
if( this->identifier != obj.identifier ||
|
||||
this->out.hash_tx != obj.out.hash_tx ||
|
||||
this->out.n_vout != obj.out.n_vout ||
|
||||
this->out.amount != obj.out.amount ||
|
||||
this->address != obj.address ||
|
||||
this->script != obj.script )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool info_for_vin::comparer::operator() ( const info_for_vin& lhs, const info_for_vin& rhs ) const
|
||||
{
|
||||
if( lhs.used != rhs.used ) {
|
||||
|
|
@ -92,8 +112,6 @@ fc::optional<info_for_vin> input_withdrawal_info::find_info_for_vin( fc::sha256
|
|||
std::vector<info_for_vin> input_withdrawal_info::get_info_for_vins()
|
||||
{
|
||||
std::vector<info_for_vin> result;
|
||||
|
||||
const auto& addr_idx = db.get_index_type<bitcoin_address_index>().indices().get<by_address>();
|
||||
const auto max_vins = db.get_sidechain_params().maximum_condensing_tx_vins;
|
||||
|
||||
info_for_vins.safe_for<by_id_and_not_used>( [&]( info_for_vin_index::index<by_id_and_not_used>::type::iterator itr_b,
|
||||
|
|
@ -106,9 +124,7 @@ std::vector<info_for_vin> input_withdrawal_info::get_info_for_vins()
|
|||
vin.out.n_vout = itr_b->out.n_vout;
|
||||
vin.out.amount = itr_b->out.amount;
|
||||
vin.address = itr_b->address;
|
||||
const auto& address_itr = addr_idx.find( itr_b->address );
|
||||
FC_ASSERT( address_itr != addr_idx.end() );
|
||||
vin.script = address_itr->address.get_witness_script();
|
||||
vin.script = itr_b->script;
|
||||
|
||||
result.push_back( vin );
|
||||
++itr_b;
|
||||
|
|
|
|||
|
|
@ -49,8 +49,11 @@ void sidechain_net_manager::update_tx_infos( const std::string& block_hash )
|
|||
std::string block = bitcoin_client->receive_full_block( block_hash );
|
||||
if( block != "" ) {
|
||||
const auto& vins = extract_info_from_block( block );
|
||||
const auto& addr_idx = db->get_index_type<bitcoin_address_index>().indices().get<by_address>();
|
||||
for( const auto& v : vins ) {
|
||||
db->i_w_info.insert_info_for_vin( prev_out{ v.out.hash_tx, v.out.n_vout, v.out.amount }, v.address );
|
||||
const auto& addr_itr = addr_idx.find( v.address );
|
||||
FC_ASSERT( addr_itr != addr_idx.end() );
|
||||
db->i_w_info.insert_info_for_vin( prev_out{ v.out.hash_tx, v.out.n_vout, v.out.amount }, v.address, addr_itr->address.get_witness_script() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ void sidechain_condensing_tx::create_vouts_for_witness_fee( const accounts_keys&
|
|||
}
|
||||
}
|
||||
|
||||
uint64_t sidechain_condensing_tx::get_estimate_tx_size( size_t number_witness ) const
|
||||
uint64_t sidechain_condensing_tx::get_estimate_tx_size( bitcoin_transaction tx, size_t number_witness )
|
||||
{
|
||||
bytes temp_sig(72, 0x00);
|
||||
bytes temp_key(34, 0x00);
|
||||
|
|
@ -60,12 +60,11 @@ uint64_t sidechain_condensing_tx::get_estimate_tx_size( size_t number_witness )
|
|||
}
|
||||
|
||||
std::vector<bytes> temp_scriptWitness = { {},{temp_sig},{temp_sig},{temp_sig},{temp_sig},{temp_sig},{temp_script} };
|
||||
bitcoin_transaction temp_tx = get_transaction();
|
||||
for( auto& vin : temp_tx.vin ) {
|
||||
for( auto& vin : tx.vin ) {
|
||||
vin.scriptWitness = temp_scriptWitness;
|
||||
}
|
||||
|
||||
return temp_tx.get_vsize();
|
||||
return tx.get_vsize();
|
||||
}
|
||||
|
||||
void sidechain_condensing_tx::subtract_fee( const uint64_t& fee, const uint16_t& witnesses_percentage )
|
||||
|
|
|
|||
144
libraries/sidechain/sidechain_proposal_checker.cpp
Normal file
144
libraries/sidechain/sidechain_proposal_checker.cpp
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
#include <sidechain/sidechain_proposal_checker.hpp>
|
||||
#include <sidechain/sidechain_condensing_tx.hpp>
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/primary_wallet_vout_object.hpp>
|
||||
#include <graphene/chain/bitcoin_address_object.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/bitcoin_transaction_object.hpp>
|
||||
#include <graphene/chain/info_for_used_vin_object.hpp>
|
||||
|
||||
namespace sidechain {
|
||||
|
||||
bool sidechain_proposal_checker::check_bitcoin_transaction_send_operation( const bitcoin_transaction_send_operation& op )
|
||||
{
|
||||
bool info_for_pw_vin = check_info_for_pw_vin( op.pw_vin );
|
||||
bool info_for_vins = check_info_for_vins( op.vins );
|
||||
bool info_for_vouts = check_info_for_vouts( op.vouts );
|
||||
bool transaction = check_transaction( op );
|
||||
|
||||
return info_for_pw_vin && info_for_vins && info_for_vouts && transaction;
|
||||
}
|
||||
|
||||
bool sidechain_proposal_checker::check_reuse_pw_vin( const fc::sha256& pw_vin )
|
||||
{
|
||||
const auto& pw_vin_status = pw_vin_ident.insert( pw_vin );
|
||||
if( !pw_vin_status.second ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sidechain_proposal_checker::check_reuse_user_vins( const std::vector<fc::sha256>& user_vin_identifiers )
|
||||
{
|
||||
for( const auto& vin : user_vin_identifiers ) {
|
||||
const auto& user_vin_status = user_vin_ident.insert( vin );
|
||||
if( !user_vin_status.second ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sidechain_proposal_checker::check_reuse_vouts( const std::vector<info_for_vout_id_type>& user_vout_ids )
|
||||
{
|
||||
for( const auto& vout : user_vout_ids ) {
|
||||
const auto& user_vout_status = vout_ids.insert( vout );
|
||||
if( !user_vout_status.second ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sidechain_proposal_checker::check_reuse( const operation& op )
|
||||
{
|
||||
fc::sha256 pw_vin_identifier;
|
||||
std::vector<fc::sha256> user_vin_identifiers;
|
||||
std::vector<info_for_vout_id_type> user_vout_ids;
|
||||
|
||||
if( op.which() == operation::tag<bitcoin_transaction_send_operation>::value ) {
|
||||
bitcoin_transaction_send_operation btc_tx_send_op = op.get<bitcoin_transaction_send_operation>();
|
||||
|
||||
pw_vin_identifier = btc_tx_send_op.pw_vin.identifier;
|
||||
user_vout_ids = btc_tx_send_op.vouts;
|
||||
for( const auto& vin : btc_tx_send_op.vins ) {
|
||||
user_vin_identifiers.push_back( vin.identifier );
|
||||
}
|
||||
} else if ( op.which() == operation::tag<bitcoin_issue_operation>::value ) {
|
||||
bitcoin_issue_operation btc_issue_op = op.get<bitcoin_issue_operation>();
|
||||
const auto& bto_itr_idx = db.get_index_type<bitcoin_transaction_index>().indices().get<graphene::chain::by_transaction_id>();
|
||||
|
||||
for( const auto& id : btc_issue_op.transaction_ids ) {
|
||||
const auto& bto_itr = bto_itr_idx.find( id );
|
||||
if( bto_itr == bto_itr_idx.end() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pw_vin_identifier = bto_itr->pw_vin;
|
||||
user_vout_ids = bto_itr->vouts;
|
||||
user_vin_identifiers = bto_itr->vins;
|
||||
}
|
||||
}
|
||||
|
||||
return check_reuse_pw_vin( pw_vin_identifier ) &&
|
||||
check_reuse_user_vins( user_vin_identifiers ) &&
|
||||
check_reuse_vouts( user_vout_ids );
|
||||
}
|
||||
|
||||
bool sidechain_proposal_checker::check_info_for_pw_vin( const info_for_vin& info_for_vin )
|
||||
{
|
||||
const auto& prevout = db.pw_vout_manager.get_vout( info_for_vin.identifier );
|
||||
const auto& pw_address = db.get_latest_PW().address;
|
||||
if( !prevout.valid() || info_for_vin.out != prevout->vout ||
|
||||
info_for_vin.address != pw_address.get_address() || info_for_vin.script != pw_address.get_witness_script() ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sidechain_proposal_checker::check_info_for_vins( const std::vector<info_for_vin>& info_for_vins )
|
||||
{
|
||||
for( const auto& vin : info_for_vins ) {
|
||||
const auto& v = db.i_w_info.find_info_for_vin( vin.identifier );
|
||||
if( !v.valid() || *v != vin ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sidechain_proposal_checker::check_info_for_vouts( const std::vector<info_for_vout_id_type>& info_for_vout_ids )
|
||||
{
|
||||
const auto& info_for_vout_idx = db.get_index_type<info_for_vout_index>().indices().get<graphene::chain::by_id>();
|
||||
for( const auto& id : info_for_vout_ids ) {
|
||||
const auto& itr = info_for_vout_idx.find( id );
|
||||
if( itr == info_for_vout_idx.end() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sidechain_proposal_checker::check_transaction( const bitcoin_transaction_send_operation& btc_trx_op )
|
||||
{
|
||||
std::vector<info_for_vout> info_vouts;
|
||||
const auto& info_for_vout_idx = db.get_index_type<info_for_vout_index>().indices().get<graphene::chain::by_id>();
|
||||
for( const auto& vout_id : btc_trx_op.vouts ) {
|
||||
const auto& vout_itr = info_for_vout_idx.find( vout_id );
|
||||
if( vout_itr == info_for_vout_idx.end() ) {
|
||||
return false;
|
||||
}
|
||||
info_vouts.push_back( *vout_itr );
|
||||
}
|
||||
|
||||
const auto& temp_full_tx = db.create_btc_transaction( btc_trx_op.vins, info_vouts, btc_trx_op.pw_vin );
|
||||
|
||||
if( temp_full_tx.first != btc_trx_op.transaction || temp_full_tx.second != btc_trx_op.fee_for_size ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ BOOST_FIXTURE_TEST_SUITE( bitcoin_issue_tests, database_fixture )
|
|||
|
||||
void create_bitcoin_issue_operation_environment( database& db )
|
||||
{
|
||||
std::vector< info_for_used_vin_id_type > vins;
|
||||
std::vector< fc::sha256 > vins;
|
||||
std::vector< info_for_vout_id_type > vouts;
|
||||
|
||||
for( auto i = 0; i < 3; i++ ){
|
||||
|
|
@ -25,10 +25,10 @@ void create_bitcoin_issue_operation_environment( database& db )
|
|||
});
|
||||
|
||||
auto vin_id = db.create<info_for_used_vin_object>([&]( info_for_used_vin_object& obj ) {
|
||||
obj.identifier = fc::sha256( std::to_string( i ) );
|
||||
obj.identifier = fc::sha256( std::string( 64, std::to_string( i )[0] ) );
|
||||
obj.out.amount = 100000 + i * 100000;
|
||||
obj.address = std::to_string( i );
|
||||
}).get_id();
|
||||
});
|
||||
|
||||
auto vout_id = db.create<info_for_vout_object>([&]( info_for_vout_object& obj ) {
|
||||
obj.payer = account_id_type( i );
|
||||
|
|
@ -36,7 +36,7 @@ void create_bitcoin_issue_operation_environment( database& db )
|
|||
obj.address = std::to_string( i );
|
||||
}).get_id();
|
||||
|
||||
vins.push_back( vin_id );
|
||||
vins.push_back( vin_id.identifier );
|
||||
vouts.push_back( vout_id );
|
||||
}
|
||||
|
||||
|
|
|
|||
140
tests/tests/sidechain_proposal_checker_tests.cpp
Normal file
140
tests/tests/sidechain_proposal_checker_tests.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
#include <boost/test/unit_test.hpp>
|
||||
#include "../common/database_fixture.hpp"
|
||||
#include <sidechain/sidechain_proposal_checker.hpp>
|
||||
|
||||
using namespace sidechain;
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE( sidechain_proposal_checker_tests, database_fixture )
|
||||
|
||||
class test_environment
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
test_environment( database& db )
|
||||
{
|
||||
|
||||
for( size_t i = 1; i < 6; i++ ) {
|
||||
prev_out out{ std::string( 64, std::to_string( i )[0] ), static_cast<uint32_t>( i ), static_cast<uint64_t>( i * 10000 ) };
|
||||
db.i_w_info.insert_info_for_vin( out, std::to_string( i ), { 0x00, 0x01, 0x02 } );
|
||||
db.i_w_info.insert_info_for_vout( account_id_type( i ), "2Mt57VSFqBe7UpDad9QaYHev21E1VscAZMU", i * 5000 );
|
||||
}
|
||||
|
||||
vins = db.i_w_info.get_info_for_vins();
|
||||
pw_vin = *db.i_w_info.get_info_for_pw_vin();
|
||||
vouts = db.i_w_info.get_info_for_vouts();
|
||||
full_tx = db.create_btc_transaction( vins, vouts, pw_vin );
|
||||
}
|
||||
|
||||
std::vector<info_for_vin> vins;
|
||||
info_for_vin pw_vin;
|
||||
std::vector<info_for_vout> vouts;
|
||||
full_btc_transaction full_tx;
|
||||
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE( check_reuse_normal_test )
|
||||
{
|
||||
sidechain_proposal_checker checker( db );
|
||||
bitcoin_transaction_send_operation op;
|
||||
|
||||
op.pw_vin = info_for_vin( { std::string( 64, '1' ), 0, 0 }, "", bytes() );
|
||||
for( size_t i = 0; i < 5; i++ ) {
|
||||
op.vins.push_back( info_for_vin( { std::string( 64, std::to_string( i )[0] ), 0, 0 }, "", bytes() ) );
|
||||
op.vouts.push_back( info_for_vout_id_type( i ) );
|
||||
}
|
||||
|
||||
BOOST_CHECK( checker.check_reuse( op ) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( check_reuse_not_normal_test )
|
||||
{
|
||||
sidechain_proposal_checker checker( db );
|
||||
bitcoin_transaction_send_operation op;
|
||||
|
||||
op.pw_vin = info_for_vin( { std::string( 64, '1' ), 0, 0 }, "", bytes() );
|
||||
for( size_t i = 0; i < 5; i++ ) {
|
||||
op.vins.push_back( info_for_vin( { std::string( 64, std::to_string( i )[0] ), 0, 0 }, "", bytes() ) );
|
||||
op.vouts.push_back( info_for_vout_id_type( i ) );
|
||||
}
|
||||
|
||||
BOOST_CHECK( checker.check_reuse( op ) );
|
||||
BOOST_CHECK( !checker.check_reuse( op ) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( check_btc_tx_send_op_normal_test )
|
||||
{
|
||||
sidechain_proposal_checker checker( db );
|
||||
test_environment env( db );
|
||||
|
||||
bitcoin_transaction_send_operation op;
|
||||
op.pw_vin = env.pw_vin;
|
||||
op.vins = env.vins;
|
||||
for( const auto& vout : env.vouts ) {
|
||||
op.vouts.push_back( vout.get_id() );
|
||||
}
|
||||
op.transaction = env.full_tx.first;
|
||||
op.fee_for_size = env.full_tx.second;
|
||||
|
||||
BOOST_CHECK( checker.check_bitcoin_transaction_send_operation( op ) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( check_btc_tx_send_op_incorrect_info_for_vin_test )
|
||||
{
|
||||
sidechain_proposal_checker checker( db );
|
||||
test_environment env( db );
|
||||
|
||||
env.vins[3].out.amount = 13;
|
||||
|
||||
bitcoin_transaction_send_operation op;
|
||||
op.pw_vin = env.pw_vin;
|
||||
op.vins = env.vins;
|
||||
for( const auto& vout : env.vouts ) {
|
||||
op.vouts.push_back( vout.get_id() );
|
||||
}
|
||||
op.transaction = env.full_tx.first;
|
||||
op.fee_for_size = env.full_tx.second;
|
||||
|
||||
BOOST_CHECK( !checker.check_bitcoin_transaction_send_operation( op ) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( check_btc_tx_send_op_incorrect_info_for_pw_vin_test )
|
||||
{
|
||||
sidechain_proposal_checker checker( db );
|
||||
test_environment env( db );
|
||||
|
||||
env.pw_vin.out.amount = 13;
|
||||
|
||||
bitcoin_transaction_send_operation op;
|
||||
op.pw_vin = env.pw_vin;
|
||||
op.vins = env.vins;
|
||||
for( const auto& vout : env.vouts ) {
|
||||
op.vouts.push_back( vout.get_id() );
|
||||
}
|
||||
op.transaction = env.full_tx.first;
|
||||
op.fee_for_size = env.full_tx.second;
|
||||
|
||||
BOOST_CHECK( !checker.check_bitcoin_transaction_send_operation( op ) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( check_btc_tx_send_op_incorrect_tx_test )
|
||||
{
|
||||
sidechain_proposal_checker checker( db );
|
||||
test_environment env( db );
|
||||
|
||||
bitcoin_transaction_send_operation op;
|
||||
op.pw_vin = env.pw_vin;
|
||||
op.vins = env.vins;
|
||||
for( const auto& vout : env.vouts ) {
|
||||
op.vouts.push_back( vout.get_id() );
|
||||
}
|
||||
|
||||
env.full_tx.first.vout[0].value = 13;
|
||||
|
||||
op.transaction = env.full_tx.first;
|
||||
op.fee_for_size = env.full_tx.second;
|
||||
|
||||
BOOST_CHECK( !checker.check_bitcoin_transaction_send_operation( op ) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
Loading…
Reference in a new issue