diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index aa87d669..4fae0fd2 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -21,6 +21,7 @@ if( GRAPHENE_DISABLE_UNITY_BUILD ) db_market.cpp db_update.cpp db_witness_schedule.cpp + db_sidechain.cpp ) message( STATUS "Graphene database unity build disabled" ) else( GRAPHENE_DISABLE_UNITY_BUILD ) diff --git a/libraries/chain/bitcoin_address_evaluator.cpp b/libraries/chain/bitcoin_address_evaluator.cpp index 085e7b16..40482e62 100644 --- a/libraries/chain/bitcoin_address_evaluator.cpp +++ b/libraries/chain/bitcoin_address_evaluator.cpp @@ -8,6 +8,7 @@ namespace graphene { namespace chain { void_result bitcoin_address_create_evaluator::do_evaluate( const bitcoin_address_create_operation& op ) { database& d = db(); + FC_ASSERT( !d.is_sidechain_fork_needed() ); auto& acc_idx = d.get_index_type().indices().get(); auto acc_itr = acc_idx.find( op.owner ); FC_ASSERT( acc_itr != acc_idx.end() ); @@ -17,10 +18,15 @@ void_result bitcoin_address_create_evaluator::do_evaluate( const bitcoin_address object_id_type bitcoin_address_create_evaluator::do_apply( const bitcoin_address_create_operation& op ) { database& d = db(); + const auto pw_obj = d.get_latest_PW(); + auto witnesses_keys = pw_obj.address.witnesses_keys; const auto& new_btc_address = d.create( [&]( bitcoin_address_object& a ) { + witnesses_keys.erase( --witnesses_keys.end() ); + witnesses_keys.emplace( d.get_sidechain_account_id(), pubkey_from_id( a.id ) ); + a.owner = op.owner; - //a.address = sidechain::btc_multisig_segwit_address(); + a.address = sidechain::btc_multisig_segwit_address(5, witnesses_keys); a.count_invalid_pub_key = 1; }); diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 7711f543..e2bdfa62 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -33,4 +33,5 @@ #include "db_market.cpp" #include "db_update.cpp" #include "db_witness_schedule.cpp" -#include "db_notify.cpp" \ No newline at end of file +#include "db_notify.cpp" +#include "db_sidechain.cpp" diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 66126dbf..4eeeb499 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -573,6 +573,11 @@ void database::_apply_block( const signed_block& next_block ) uint32_t skip = get_node_properties().skip_flags; _applied_ops.clear(); + if( is_sidechain_fork_needed() ) + { + perform_sidechain_fork(); + } + FC_ASSERT( (skip & skip_merkle_check) || next_block.transaction_merkle_root == next_block.calculate_merkle_root(), "", ("next_block.transaction_merkle_root",next_block.transaction_merkle_root)("calc",next_block.calculate_merkle_root())("next_block",next_block)("id",next_block.id()) ); const witness_object& signing_witness = validate_block_header(skip, next_block); diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index 9516e256..d4593cfa 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -97,5 +97,4 @@ uint32_t database::last_non_undoable_block_num() const return head_block_num() - _undo_db.size(); } - } } diff --git a/libraries/chain/db_sidechain.cpp b/libraries/chain/db_sidechain.cpp new file mode 100644 index 00000000..d9ba8d81 --- /dev/null +++ b/libraries/chain/db_sidechain.cpp @@ -0,0 +1,107 @@ +#include +#include + +namespace graphene { namespace chain { + +std::map< account_id_type, public_key_type> database::get_active_witnesses_keys() const +{ + const auto& witnesses_by_id = get_index_type().indices().get(); + std::map< account_id_type, public_key_type > witnesses_keys; + auto& active_witnesses = get_global_properties().active_witnesses; + for( auto witness_id : active_witnesses ) { + const auto& witness_obj = witnesses_by_id.find( witness_id ); + if( witness_obj != witnesses_by_id.end() ){ + witnesses_keys.emplace( witness_obj->witness_account, witness_obj->signing_key ); + } + } + return witnesses_keys; +} + +bool database::is_sidechain_fork_needed() const +{ + const auto& params = get_global_properties().parameters.extensions.value.sidechain_parameters; + return !params.valid(); +} + +void database::perform_sidechain_fork() +{ + const auto& sidechain_account = create( [&]( account_object& obj ) { + obj.name = "sidechain_account"; + obj.statistics = create([&]( account_statistics_object& acc_stat ){ acc_stat.owner = obj.id; }).id; + obj.owner.weight_threshold = 5; + obj.active.weight_threshold = 5; + obj.membership_expiration_date = time_point_sec::maximum(); + obj.network_fee_percentage = GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE; + obj.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT - GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE; + }); + + const asset_object& new_asset = create( [&]( asset_object& obj ) { + obj.symbol = SIDECHAIN_SYMBOL; + obj.precision = SIDECHAIN_PRECISION_DIGITS; + obj.issuer = sidechain_account.get_id(); + obj.options.max_supply = SIDECHAIN_MAX_SHARE_SUPPLY; + obj.options.issuer_permissions = 0; + obj.options.flags = 0; + obj.dynamic_asset_data_id = create([&]( asset_dynamic_data_object& a ) { a.current_supply = 0; }).id; + }); + + modify( get_global_properties(), [&]( global_property_object& gpo ) { + sidechain_parameters_extension params_ext; + params_ext.managing_account = sidechain_account.get_id(); + params_ext.asset_id = new_asset.get_id(); + + gpo.parameters.extensions.value.sidechain_parameters = params_ext; + if( gpo.pending_parameters ) + gpo.pending_parameters->extensions.value.sidechain_parameters = params_ext; + }); + + auto global_properties = get_global_properties(); + const auto& witnesses_idx = get_index_type().indices().get(); + std::vector witness_accounts; + + for( auto witness_id : global_properties.active_witnesses ) { + const auto& witness_obj = witnesses_idx.find( witness_id ); + if( witness_obj != witnesses_idx.end() ) + witness_accounts.push_back( witness_obj->witness_account ); + } + + modify( sidechain_account, [&]( account_object& obj ) { + for( auto& a : witness_accounts ) { + obj.owner.add_authority( a, 1 ); + obj.active.add_authority( a, 1 ); + } + }); + + create( [&]( bitcoin_address_object& pw ) { // Create PW address + pw.address = btc_multisig_segwit_address( 5, get_active_witnesses_keys() ); + pw.owner = sidechain_account.get_id(); + pw.count_invalid_pub_key = 1; + }); +} + +const sidechain::sidechain_parameters_extension& database::get_sidechain_params() const +{ + const auto& params = get_global_properties().parameters.extensions.value.sidechain_parameters; + FC_ASSERT( params.valid() ); + return *params; +} + +const account_id_type& database::get_sidechain_account_id() const +{ + return get_sidechain_params().managing_account; +} + +const asset_id_type& database::get_sidechain_asset_id() const +{ + return get_sidechain_params().asset_id; +} + +bitcoin_address_object database::get_latest_PW() const +{ + const auto& btc_addr_idx = get_index_type().indices().get(); + auto itr = btc_addr_idx.upper_bound( get_sidechain_account_id() ); + return *(--itr); +} + + +} } \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index d72c5338..97ea517e 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -228,4 +228,12 @@ #define TOURNAMENT_MAX_START_DELAY (60*60*24*7) // 1 week -#define SIDECHAIN_NUMBER_UNCONFIRMED_VINS 25 \ No newline at end of file +////////////////////////////////////////////////////////////////////// SideChain +#define SIDECHAIN_SYMBOL "pBTC" +#define SIDECHAIN_PRECISION_DIGITS 8 +#define SIDECHAIN_MAX_SHARE_SUPPLY int64_t(21000000ll * 100000000ll) +#define SIDECHAIN_DEFAULT_NUMBER_UNCONFIRMED_VINS 25 +#define SIDECHAIN_DEFAULT_NUMBER_SIG_MULTISIG 5 +#define SIDECHAIN_DEFAULT_CONDENSING_TX_VINS_NUMBER 5 +#define SIDECHAIN_DEFAULT_CONDENSING_TX_VOUTS_NUMBER 5 +////////////////////////////////////////////////////////////////////// diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 48411d06..41225541 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -290,6 +290,7 @@ namespace graphene { namespace chain { uint32_t last_non_undoable_block_num() const; + //////////////////// db_init.cpp //////////////////// void initialize_evaluators(); @@ -508,11 +509,21 @@ namespace graphene { namespace chain { void perform_account_maintenance(std::tuple helpers); ///@} ///@} - - //////////////////// sidechain //////////////////// + //////////////////// db_sidechain.cpp //////////////////// public: + std::map< account_id_type, public_key_type> get_active_witnesses_keys() const; + bool is_sidechain_fork_needed() const; + void perform_sidechain_fork(); + bitcoin_address_object get_latest_PW() const; + + const sidechain::sidechain_parameters_extension& get_sidechain_params() const; + const account_id_type& get_sidechain_account_id() const; + const asset_id_type& get_sidechain_asset_id() const; + + sidechain::input_withdrawal_info i_w_info; + sidechain::primary_wallet_vout_manager pw_vout_manager; fc::signal send_btc_tx; diff --git a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp index b2551e44..86642716 100644 --- a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp +++ b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace graphene { namespace chain { struct fee_schedule; } } @@ -37,6 +38,7 @@ namespace graphene { namespace chain { optional< uint16_t > betting_rake_fee_percentage; optional< flat_map > permitted_betting_odds_increments; optional< uint16_t > live_betting_delay_time; + optional< sidechain::sidechain_parameters_extension > sidechain_parameters; }; struct chain_parameters diff --git a/libraries/chain/withdraw_pbtc_evaluator.cpp b/libraries/chain/withdraw_pbtc_evaluator.cpp index aaa1fb2e..ef177b16 100644 --- a/libraries/chain/withdraw_pbtc_evaluator.cpp +++ b/libraries/chain/withdraw_pbtc_evaluator.cpp @@ -10,13 +10,13 @@ void_result withdraw_pbtc_evaluator::do_evaluate(const withdraw_pbtc_operation& { database& d = db(); - // FC_ASSERT( !d.is_sidechain_fork_needed() ); + FC_ASSERT( !d.is_sidechain_fork_needed() ); FC_ASSERT( op.data.size() > 0 ); type = bitcoin_address( op.data ).get_type(); FC_ASSERT( type != payment_type::NULLDATA , "Invalid address type." ); FC_ASSERT( check_amount( op ) ); - // asset acc_balance = db().get_balance( op.payer, d.get_sidechain_asset_id() ); - // FC_ASSERT( acc_balance.amount.value >= op.amount ); + asset acc_balance = db().get_balance( op.payer, d.get_sidechain_asset_id() ); + FC_ASSERT( acc_balance.amount.value >= op.amount ); return void_result(); } diff --git a/libraries/sidechain/include/sidechain/sidechain_parameters.hpp b/libraries/sidechain/include/sidechain/sidechain_parameters.hpp new file mode 100644 index 00000000..0d67963c --- /dev/null +++ b/libraries/sidechain/include/sidechain/sidechain_parameters.hpp @@ -0,0 +1,24 @@ +#pragma once +#include + + +namespace sidechain { + + struct sidechain_parameters_extension { + uint8_t multisig_sigs_num = SIDECHAIN_DEFAULT_NUMBER_SIG_MULTISIG; + uint8_t condensing_tx_vins_num = SIDECHAIN_DEFAULT_CONDENSING_TX_VINS_NUMBER; + uint8_t condensing_tx_vouts_num = SIDECHAIN_DEFAULT_CONDENSING_TX_VOUTS_NUMBER; + + graphene::chain::account_id_type managing_account; + graphene::chain::asset_id_type asset_id; + }; + +} + +FC_REFLECT( sidechain::sidechain_parameters_extension, + (multisig_sigs_num) + (condensing_tx_vins_num) + (condensing_tx_vins_num) + (managing_account) + (asset_id) +) \ No newline at end of file diff --git a/libraries/sidechain/primary_wallet_vout_manager.cpp b/libraries/sidechain/primary_wallet_vout_manager.cpp index 6c98e7c1..9e444cc4 100644 --- a/libraries/sidechain/primary_wallet_vout_manager.cpp +++ b/libraries/sidechain/primary_wallet_vout_manager.cpp @@ -9,7 +9,7 @@ namespace sidechain { bool primary_wallet_vout_manager::is_reach_max_unconfirmaed_vout() const { const auto& PW_vout_idx = db.get_index_type().indices().get< graphene::chain::by_id >(); - return !( PW_vout_idx.size() < SIDECHAIN_NUMBER_UNCONFIRMED_VINS ); + return !( PW_vout_idx.size() < SIDECHAIN_DEFAULT_NUMBER_UNCONFIRMED_VINS ); } fc::optional< graphene::chain::primary_wallet_vout_object > primary_wallet_vout_manager::get_latest_unused_vout() const