diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp index df763377..79e6cf17 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp @@ -59,7 +59,16 @@ public: sidechain_net_handler_bitcoin(const boost::program_options::variables_map& options); virtual ~sidechain_net_handler_bitcoin(); - void handle_block( const std::string& block_hash ); + void update_tx_infos( const std::string& block_hash ); + + void update_tx_approvals(); + + void update_estimated_fee(); + + //void send_btc_tx( const sidechain::bitcoin_transaction& trx ); + + bool connection_is_not_defined() const; + private: std::string ip; uint32_t zmq_port; @@ -71,6 +80,16 @@ private: std::unique_ptr bitcoin_client; graphene::chain::database* db; + void handle_block( const std::string& block_hash ); + + //std::vector extract_info_from_block( const std::string& _block ); + + void update_transaction_status( std::vector trx_for_check ); + + std::set get_valid_vins( const std::string tx_hash ); + + inline uint64_t parse_amount(std::string raw); + }; } } // graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 5599e48b..b1ecb56d 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -212,9 +212,160 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(const boost::progra sidechain_net_handler_bitcoin::~sidechain_net_handler_bitcoin() { } +void sidechain_net_handler_bitcoin::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().indices().get(); + for( const auto& v : vins ) { + 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() ); + } + } +} + +void sidechain_net_handler_bitcoin::update_tx_approvals() +{ + std::vector trx_for_check; + const auto& confirmations_num = db->get_sidechain_params().confirmations_num; + + db->bitcoin_confirmations.safe_for([&]( btc_tx_confirmations_index::iterator itr_b, btc_tx_confirmations_index::iterator itr_e ){ + for(auto iter = itr_b; iter != itr_e; iter++) { + db->bitcoin_confirmations.modify( iter->transaction_id, [&]( bitcoin_transaction_confirmations& obj ) { + obj.count_block++; + }); + + if( iter->count_block == confirmations_num ) { + trx_for_check.push_back( iter->transaction_id ); + } + } + }); + + update_transaction_status( trx_for_check ); + +} + +void sidechain_net_handler_bitcoin::update_estimated_fee() +{ + db->estimated_feerate = bitcoin_client->receive_estimated_fee(); +} + +//void sidechain_net_handler_bitcoin::send_btc_tx( const sidechain::bitcoin_transaction& trx ) +//{ +// std::set valid_vins; +// for( const auto& v : trx.vin ) { +// valid_vins.insert( v.prevout.hash ); +// } +// db->bitcoin_confirmations.insert( bitcoin_transaction_confirmations( trx.get_txid(), valid_vins ) ); +// +// FC_ASSERT( !bitcoin_client->connection_is_not_defined() ); +// const auto tx_hex = fc::to_hex( pack( trx ) ); +// +// bitcoin_client->send_btc_tx( tx_hex ); +//} + +bool sidechain_net_handler_bitcoin::connection_is_not_defined() const +{ + return listener->connection_is_not_defined() && bitcoin_client->connection_is_not_defined(); +} + void sidechain_net_handler_bitcoin::handle_block( const std::string& block_hash ) { ilog("peerplays sidechain plugin: sidechain_net_handler_bitcoin::handle_block"); ilog(" block_hash: ${block_hash}", ("block_hash", block_hash)); + update_tx_approvals(); + update_estimated_fee(); + update_tx_infos( block_hash ); +} + +//std::vector sidechain_net_handler_bitcoin::extract_info_from_block( const std::string& _block ) +//{ +// std::stringstream ss( _block ); +// boost::property_tree::ptree block; +// boost::property_tree::read_json( ss, block ); +// +// std::vector result; +// +// const auto& addr_idx = db->get_index_type().indices().get(); +// +// for (const auto& tx_child : block.get_child("tx")) { +// const auto& tx = tx_child.second; +// +// for ( const auto& o : tx.get_child("vout") ) { +// const auto script = o.second.get_child("scriptPubKey"); +// +// if( !script.count("addresses") ) continue; +// +// for (const auto& addr : script.get_child("addresses")) { // in which cases there can be more addresses? +// const auto address_base58 = addr.second.get_value(); +// +// if( !addr_idx.count( address_base58 ) ) continue; +// +// info_for_vin vin; +// vin.out.hash_tx = tx.get_child("txid").get_value(); +// vin.out.amount = parse_amount( o.second.get_child( "value" ).get_value() ); +// vin.out.n_vout = o.second.get_child( "n" ).get_value(); +// vin.address = address_base58; +// result.push_back( vin ); +// } +// } +// } +// +// return result; +//} + +void sidechain_net_handler_bitcoin::update_transaction_status( std::vector trx_for_check ) +{ + const auto& confirmations_num = db->get_sidechain_params().confirmations_num; + + for( const auto& trx : trx_for_check ) { + auto confirmations = bitcoin_client->receive_confirmations_tx( trx.str() ); + db->bitcoin_confirmations.modify( trx, [&]( bitcoin_transaction_confirmations& obj ) { + obj.count_block = confirmations; + }); + + if( confirmations >= confirmations_num ) { + db->bitcoin_confirmations.modify( trx, [&]( bitcoin_transaction_confirmations& obj ) { + obj.confirmed = true; + }); + + } else if( confirmations == 0 ) { + auto is_in_mempool = bitcoin_client->receive_mempool_entry_tx( trx.str() ); + + std::set valid_vins; + if( !is_in_mempool ) { + valid_vins = get_valid_vins( trx.str() ); + } + + db->bitcoin_confirmations.modify( trx, [&]( bitcoin_transaction_confirmations& obj ) { + obj.missing = !is_in_mempool; + obj.valid_vins = valid_vins; + }); + } + } +} + +std::set sidechain_net_handler_bitcoin::get_valid_vins( const std::string tx_hash ) +{ + const auto& confirmations_obj = db->bitcoin_confirmations.find( fc::sha256( tx_hash ) ); + FC_ASSERT( confirmations_obj.valid() ); + + std::set valid_vins; + for( const auto& v : confirmations_obj->valid_vins ) { + auto confirmations = bitcoin_client->receive_confirmations_tx( v.str() ); + if( confirmations == 0 ) { + continue; + } + valid_vins.insert( v ); + } + return valid_vins; +} + +// Removes dot from amount output: "50.00000000" +inline uint64_t sidechain_net_handler_bitcoin::parse_amount(std::string raw) { + raw.erase(std::remove(raw.begin(), raw.end(), '.'), raw.end()); + return std::stoll(raw); } // =============================================================================