diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index d3af2f29..54e056b3 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -161,6 +161,9 @@ class database_api_impl : public std::enable_shared_from_this vector get_tournaments_by_state(tournament_id_type stop, unsigned limit, tournament_id_type start, tournament_state state); vector get_registered_tournaments(account_id_type account_filter, uint32_t limit) const; + //Sidechain + vector get_bitcoin_addresses(const account_id_type& acc_id) const; + //private: template @@ -2021,6 +2024,32 @@ vector database_api_impl::get_registered_tournaments(account return tournament_ids; } +////////////////////////////////////////////////////////////////////// +// // +// Sidechain // +// // +////////////////////////////////////////////////////////////////////// + +vector database_api::get_bitcoin_addresses(const account_id_type& acc) const +{ + return my->get_bitcoin_addresses(acc); +} + +vector database_api_impl::get_bitcoin_addresses(const account_id_type& acc) const +{ + vector result; + + const auto& btc_addr_idx = _db.get_index_type().indices().get(); + + auto itr = btc_addr_idx.lower_bound( acc ); + while( itr != btc_addr_idx.end() && itr->owner == acc ) + { + result.push_back( *itr ); + ++itr; + } + return result; +} + ////////////////////////////////////////////////////////////////////// // // // Private methods // diff --git a/libraries/app/impacted.cpp b/libraries/app/impacted.cpp index 9d64cf11..e04a246e 100644 --- a/libraries/app/impacted.cpp +++ b/libraries/app/impacted.cpp @@ -282,6 +282,10 @@ struct get_impacted_account_visitor _impacted.insert( op.affiliate ); } void operator()( const affiliate_referral_payout_operation& op ) { } + void operator()( const bitcoin_address_create_operation& op ) + { + _impacted.insert( op.payer ); + } }; void operation_get_impacted_accounts( const operation& op, flat_set& result ) diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 7b0943e4..5342f848 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -644,6 +645,11 @@ class database_api * @return the list of tournaments that a given account is registered to play in */ vector get_registered_tournaments(account_id_type account_filter, uint32_t limit) const; + + /** + * @return the list of bitcoin addresses which belong to acc_id + */ + vector get_bitcoin_addresses(const account_id_type& acc_id) const; private: std::shared_ptr< database_api_impl > my; @@ -765,4 +771,5 @@ FC_API(graphene::app::database_api, (get_tournaments_by_state) (get_tournaments ) (get_registered_tournaments) + (get_bitcoin_addresses) ) diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 44978017..4e9b719f 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -85,6 +85,7 @@ add_library( graphene_chain confidential_evaluator.cpp special_authority.cpp buyback.cpp + bitcoin_address_evaluator.cpp account_object.cpp asset_object.cpp diff --git a/libraries/chain/bitcoin_address_evaluator.cpp b/libraries/chain/bitcoin_address_evaluator.cpp new file mode 100644 index 00000000..085e7b16 --- /dev/null +++ b/libraries/chain/bitcoin_address_evaluator.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include + +namespace graphene { namespace chain { + +void_result bitcoin_address_create_evaluator::do_evaluate( const bitcoin_address_create_operation& op ) +{ + database& d = db(); + auto& acc_idx = d.get_index_type().indices().get(); + auto acc_itr = acc_idx.find( op.owner ); + FC_ASSERT( acc_itr != acc_idx.end() ); + return void_result(); +} + +object_id_type bitcoin_address_create_evaluator::do_apply( const bitcoin_address_create_operation& op ) +{ + database& d = db(); + + const auto& new_btc_address = d.create( [&]( bitcoin_address_object& a ) { + a.owner = op.owner; + //a.address = sidechain::btc_multisig_segwit_address(); + a.count_invalid_pub_key = 1; + }); + + return new_btc_address.id; +} + +public_key_type bitcoin_address_create_evaluator::pubkey_from_id( object_id_type id ) +{ + fc::ecc::public_key_data pubkey_data; + + pubkey_data.at( 0 ) = 0x02; // version + const auto hash = fc::sha256::hash( std::to_string( id.instance() ) ) ; + std::copy( hash.data(), hash.data() + hash.data_size(), pubkey_data.begin() + 1 ); + + return public_key_type( pubkey_data ); +} +} } // namespace graphene::chain diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index cda5bd6e..ac2f05d5 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -49,6 +49,8 @@ #include #include #include +#include +#include #include @@ -76,6 +78,7 @@ #include #include #include +#include #include @@ -85,7 +88,6 @@ #include -#include namespace graphene { namespace chain { @@ -239,6 +241,7 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + register_evaluator(); } void database::initialize_indexes() @@ -305,6 +308,7 @@ void database::initialize_indexes() add_index< primary_index >(); add_index< primary_index >(); + add_index< primary_index >(); } void database::init_genesis(const genesis_state_type& genesis_state) diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index 53ec524d..951af36f 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -269,6 +269,10 @@ struct get_impacted_account_visitor _impacted.insert( op.affiliate ); } void operator()( const affiliate_referral_payout_operation& op ) { } + void operator()( const bitcoin_address_create_operation& op ) + { + _impacted.insert( op.payer ); + } }; void operation_get_impacted_accounts( const operation& op, flat_set& result ) diff --git a/libraries/chain/include/graphene/chain/bitcoin_address_evaluator.hpp b/libraries/chain/include/graphene/chain/bitcoin_address_evaluator.hpp new file mode 100644 index 00000000..8055c6c5 --- /dev/null +++ b/libraries/chain/include/graphene/chain/bitcoin_address_evaluator.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +namespace graphene { namespace chain { + +class bitcoin_address_create_evaluator : public evaluator +{ +public: + typedef bitcoin_address_create_operation operation_type; + + void_result do_evaluate(const bitcoin_address_create_operation& op); + + object_id_type do_apply(const bitcoin_address_create_operation& op); + + public_key_type pubkey_from_id( object_id_type id ); +}; + +} } // graphene::chain diff --git a/libraries/chain/include/graphene/chain/bitcoin_address_object.hpp b/libraries/chain/include/graphene/chain/bitcoin_address_object.hpp new file mode 100644 index 00000000..b919223e --- /dev/null +++ b/libraries/chain/include/graphene/chain/bitcoin_address_object.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#include + +namespace graphene { namespace chain { + +using namespace sidechain; + +class bitcoin_address_object : public abstract_object +{ + public: + static const uint8_t space_id = protocol_ids; + static const uint8_t type_id = bitcoin_address_object_type; + + bitcoin_address_id_type get_id()const { return id; } + // multisig m-of-n (m = 5). Address is valid before count of changed witnesses < 5 + bool valid() { return count_invalid_pub_key < 5; } // TODO: move to global_properties + + std::string get_address() const { return address.base58_address; } + + void update_count_invalid_pub_key(const accounts_keys& incoming_wit_keys) { + count_invalid_pub_key = incoming_wit_keys.size() - address.count_intersection(incoming_wit_keys); + } + + account_id_type owner; + btc_multisig_segwit_address address; + uint8_t count_invalid_pub_key; +}; + +struct by_address; +struct by_owner; + +typedef boost::multi_index_container< + bitcoin_address_object, + indexed_by< + ordered_unique< tag, member< object, object_id_type, &object::id > >, + ordered_unique< tag, const_mem_fun< bitcoin_address_object, std::string, &bitcoin_address_object::get_address > >, + ordered_non_unique< tag, member< bitcoin_address_object, account_id_type, &bitcoin_address_object::owner > > + > +> bitcoin_address_multi_index_container; +typedef generic_index bitcoin_address_index; + +} } + +FC_REFLECT_DERIVED( graphene::chain::bitcoin_address_object, (graphene::chain::object), (owner)(address)(count_invalid_pub_key) ) + diff --git a/libraries/chain/include/graphene/chain/protocol/bitcoin_address.hpp b/libraries/chain/include/graphene/chain/protocol/bitcoin_address.hpp new file mode 100644 index 00000000..e55dc87b --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/bitcoin_address.hpp @@ -0,0 +1,26 @@ +#pragma once +#include + +namespace graphene { namespace chain { + + struct bitcoin_address_create_operation : public base_operation + { + struct fee_parameters_type { + uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION; + }; + + asset fee; + account_id_type payer; + account_id_type owner; + + account_id_type fee_payer()const { return payer; } + void validate()const {} + share_type calculate_fee( const fee_parameters_type& k )const { + return k.fee; + } + }; + +} } // graphene::chain + +FC_REFLECT( graphene::chain::bitcoin_address_create_operation::fee_parameters_type, (fee) ) +FC_REFLECT( graphene::chain::bitcoin_address_create_operation, (fee)(payer)(owner) ) diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index 104a2ec3..38e73d9c 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -44,6 +44,7 @@ #include #include #include +#include namespace graphene { namespace chain { @@ -129,7 +130,8 @@ namespace graphene { namespace chain { sport_delete_operation, event_group_delete_operation, affiliate_payout_operation, // VIRTUAL - affiliate_referral_payout_operation // VIRTUAL + affiliate_referral_payout_operation, // VIRTUAL + bitcoin_address_create_operation > operation; /// @} // operations group diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index d32c7ef4..c80aeccb 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -146,6 +146,7 @@ namespace graphene { namespace chain { betting_market_object_type, bet_object_type, info_for_vout_object_type, + bitcoin_address_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; @@ -204,11 +205,12 @@ namespace graphene { namespace chain { class betting_market_object; class bet_object; class info_for_vout_object; + class bitcoin_address_object; typedef object_id< protocol_ids, account_object_type, account_object> account_id_type; typedef object_id< protocol_ids, asset_object_type, asset_object> asset_id_type; typedef object_id< protocol_ids, force_settlement_object_type, force_settlement_object> force_settlement_id_type; - typedef object_id< protocol_ids, committee_member_object_type, committee_member_object> committee_member_id_type; + typedef object_id< protocol_ids, committee_member_object_type, committee_member_object> committee_member_id_type; typedef object_id< protocol_ids, witness_object_type, witness_object> witness_id_type; typedef object_id< protocol_ids, limit_order_object_type, limit_order_object> limit_order_id_type; typedef object_id< protocol_ids, call_order_object_type, call_order_object> call_order_id_type; @@ -231,6 +233,7 @@ namespace graphene { namespace chain { typedef object_id< protocol_ids, betting_market_object_type, betting_market_object> betting_market_id_type; typedef object_id< protocol_ids, bet_object_type, bet_object> bet_id_type; typedef object_id< protocol_ids, info_for_vout_object_type, info_for_vout_object> info_for_vout_id_type; + typedef object_id< protocol_ids, bitcoin_address_object_type, bitcoin_address_object> bitcoin_address_id_type; // implementation types class global_property_object; @@ -406,6 +409,7 @@ FC_REFLECT_ENUM( graphene::chain::object_type, (betting_market_object_type) (bet_object_type) (info_for_vout_object_type) + (bitcoin_address_object_type) (OBJECT_TYPE_COUNT) ) FC_REFLECT_ENUM( graphene::chain::impl_object_type, @@ -457,6 +461,8 @@ FC_REFLECT_TYPENAME( graphene::chain::betting_market_group_id_type ) FC_REFLECT_TYPENAME( graphene::chain::betting_market_id_type ) FC_REFLECT_TYPENAME( graphene::chain::bet_id_type ) FC_REFLECT_TYPENAME( graphene::chain::tournament_id_type ) +FC_REFLECT_TYPENAME( graphene::chain::info_for_vout_id_type ) +FC_REFLECT_TYPENAME( graphene::chain::bitcoin_address_id_type ) FC_REFLECT_TYPENAME( graphene::chain::global_property_id_type ) FC_REFLECT_TYPENAME( graphene::chain::dynamic_global_property_id_type ) FC_REFLECT_TYPENAME( graphene::chain::asset_dynamic_data_id_type ) diff --git a/libraries/sidechain/btc_multisig_address.cpp b/libraries/sidechain/btc_multisig_address.cpp index 1c996ed5..90f2ff95 100644 --- a/libraries/sidechain/btc_multisig_address.cpp +++ b/libraries/sidechain/btc_multisig_address.cpp @@ -4,14 +4,14 @@ namespace sidechain { -btc_multisig_address::btc_multisig_address( const size_t n_required, const std::map< account_id_type, public_key_type >& keys ) : +btc_multisig_address::btc_multisig_address( const size_t n_required, const accounts_keys& keys ) : keys_required ( n_required ), witnesses_keys( keys ) { create_redeem_script(); create_address(); } -size_t btc_multisig_address::count_intersection( const std::map< account_id_type, public_key_type >& keys ) const +size_t btc_multisig_address::count_intersection( const accounts_keys& keys ) const { FC_ASSERT( keys.size() > 0 ); @@ -31,7 +31,7 @@ void btc_multisig_address::create_redeem_script() FC_ASSERT( keys_required < witnesses_keys.size() ); redeem_script.clear(); redeem_script.push_back( op[keys_required - 1] ); - for( auto& key : witnesses_keys ) { + for( const auto& key : witnesses_keys ) { std::stringstream ss; ss << std::hex << key.second.key_data.size(); auto key_size_hex = sidechain::parse_hex( ss.str() ); @@ -59,7 +59,7 @@ void btc_multisig_address::create_address() address.push_back( OP_EQUAL ); } -btc_multisig_segwit_address::btc_multisig_segwit_address( const size_t n_required, const std::map< account_id_type, public_key_type >& keys ) : +btc_multisig_segwit_address::btc_multisig_segwit_address( const size_t n_required, const accounts_keys& keys ) : btc_multisig_address( n_required, keys ) { create_witness_script(); diff --git a/libraries/sidechain/include/sidechain/btc_multisig_address.hpp b/libraries/sidechain/include/sidechain/btc_multisig_address.hpp index 3e7f7e96..e25594eb 100644 --- a/libraries/sidechain/include/sidechain/btc_multisig_address.hpp +++ b/libraries/sidechain/include/sidechain/btc_multisig_address.hpp @@ -11,6 +11,7 @@ using namespace graphene::chain; namespace sidechain { const std::vector op = {0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f}; // OP_1 - OP_15 +typedef std::map< account_id_type, public_key_type > accounts_keys; class btc_multisig_address { @@ -19,9 +20,9 @@ public: btc_multisig_address() = default; - btc_multisig_address( const size_t n_required, const std::map< account_id_type, public_key_type >& keys ); + btc_multisig_address( const size_t n_required, const accounts_keys& keys ); - size_t count_intersection( const std::map< account_id_type, public_key_type >& keys ) const; + size_t count_intersection( const accounts_keys& keys ) const; virtual std::vector< char > get_hex_address() { return address; } @@ -45,7 +46,7 @@ public: size_t keys_required = 0; - const std::map< account_id_type, public_key_type > witnesses_keys; + accounts_keys witnesses_keys; }; @@ -58,7 +59,7 @@ public: btc_multisig_segwit_address() = default; - btc_multisig_segwit_address( const size_t n_required, const std::map< account_id_type, public_key_type >& keys ); + btc_multisig_segwit_address( const size_t n_required, const accounts_keys& keys ); bool operator==( const btc_multisig_segwit_address& addr ) const; diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 0ba0782b..40f24034 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -1795,6 +1795,20 @@ class wallet_api rock_paper_scissors_gesture gesture, bool broadcast); + + /** Create bitcoin multisig address for sidechain + * @param payer the id of fee payer + * @param owner the id of address owner + * @return the signed version of the transaction + */ + signed_transaction create_bitcoin_address(string payer, string owner, bool broadcast); + + /** Get all account's bitcoin addresses + * @param account_name_or_id the name or id of the account to provide information of bitcoin addresses + * @return list of bitcoin addresses + */ + vector get_bitcoin_addresses(string account_name_or_id) const; + void dbg_make_uia(string creator, string symbol); void dbg_make_mia(string creator, string symbol); void dbg_push_blocks( std::string src_filename, uint32_t count ); @@ -2031,6 +2045,8 @@ FC_API( graphene::wallet::wallet_api, (tournament_join) (tournament_leave) (rps_throw) + (create_bitcoin_address) + (get_bitcoin_addresses) (get_upcoming_tournaments) (get_tournaments) (get_tournaments_by_state) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 74c285bf..1d81a6bb 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -5756,6 +5756,28 @@ signed_transaction wallet_api::rps_throw(game_id_type game_id, return my->sign_transaction( tx, broadcast ); } +signed_transaction wallet_api::create_bitcoin_address( string payer, string owner, bool broadcast ) +{ + FC_ASSERT( !is_locked() ); + + bitcoin_address_create_operation op; + op.payer = get_account_id(payer); + op.owner = get_account_id(owner); + + signed_transaction tx; + tx.operations = { op }; + my->set_operation_fees( tx, my->_remote_db->get_global_properties().parameters.current_fees ); + tx.validate(); + + return my->sign_transaction( tx, broadcast ); +} + +vector wallet_api::get_bitcoin_addresses(string account_name_or_id) const +{ + return my->_remote_db->get_bitcoin_addresses( get_account_id(account_name_or_id) ); +} + + // default ctor necessary for FC_REFLECT signed_block_with_info::signed_block_with_info() {