diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 3a5ebf1f..208a48a6 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include @@ -311,6 +312,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/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index d85cc093..d72c5338 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -226,3 +226,6 @@ #define TOURNAMENT_MAX_WHITELIST_LENGTH 1000 #define TOURNAMENT_MAX_START_TIME_IN_FUTURE (60*60*24*7*4) // 1 month #define TOURNAMENT_MAX_START_DELAY (60*60*24*7) // 1 week + + +#define SIDECHAIN_NUMBER_UNCONFIRMED_VINS 25 \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/primary_wallet_vout_object.hpp b/libraries/chain/include/graphene/chain/primary_wallet_vout_object.hpp new file mode 100644 index 00000000..1830a3d6 --- /dev/null +++ b/libraries/chain/include/graphene/chain/primary_wallet_vout_object.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include + +namespace graphene { namespace chain { + +class primary_wallet_vout_object : public abstract_object +{ +public: + static const uint8_t space_id = protocol_ids; + static const uint8_t type_id = primary_wallet_vout_object_type; + + struct comparer { + bool operator()(const primary_wallet_vout_object& lhs, const primary_wallet_vout_object& rhs) const; + }; + + primary_wallet_vout_id_type get_id() const { return id; } + + sidechain::prev_out vout; + fc::uint256 hash_id; // sha256(hash + n_vout) + + bool confirmed; + bool used; + +}; + +struct by_hash_id; + +typedef boost::multi_index_container< + primary_wallet_vout_object, + indexed_by< + ordered_unique< tag< by_id >, member< object, object_id_type, &object::id > >, + ordered_unique< tag< by_hash_id >, member< primary_wallet_vout_object, fc::uint256, &primary_wallet_vout_object::hash_id > > + > +> primary_wallet_vout_multi_index_container; + +typedef generic_index primary_wallet_vout_index; + +} } + +FC_REFLECT_DERIVED( graphene::chain::primary_wallet_vout_object, (graphene::chain::object), (vout)(hash_id)(confirmed)(used) ) + diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index c80aeccb..dbd8bc67 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -147,6 +147,7 @@ namespace graphene { namespace chain { bet_object_type, info_for_vout_object_type, bitcoin_address_object_type, + primary_wallet_vout_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; @@ -206,6 +207,7 @@ namespace graphene { namespace chain { class bet_object; class info_for_vout_object; class bitcoin_address_object; + class primary_wallet_vout_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; @@ -234,6 +236,7 @@ namespace graphene { namespace chain { 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; + typedef object_id< protocol_ids, primary_wallet_vout_object_type,primary_wallet_vout_object> primary_wallet_vout_id_type; // implementation types class global_property_object; @@ -410,6 +413,7 @@ FC_REFLECT_ENUM( graphene::chain::object_type, (bet_object_type) (info_for_vout_object_type) (bitcoin_address_object_type) + (primary_wallet_vout_object_type) (OBJECT_TYPE_COUNT) ) FC_REFLECT_ENUM( graphene::chain::impl_object_type, @@ -463,6 +467,7 @@ 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::primary_wallet_vout_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/include/sidechain/input_withdrawal_info.hpp b/libraries/sidechain/include/sidechain/input_withdrawal_info.hpp index bc36f123..13275f9b 100644 --- a/libraries/sidechain/include/sidechain/input_withdrawal_info.hpp +++ b/libraries/sidechain/include/sidechain/input_withdrawal_info.hpp @@ -19,13 +19,6 @@ namespace graphene { namespace chain { class database; } } namespace sidechain { -struct prev_out -{ - std::string hash_tx; - uint32_t n_vout; - uint64_t amount; -}; - struct info_for_vin { info_for_vin() = default; diff --git a/libraries/sidechain/include/sidechain/primary_wallet_vout_manager.hpp b/libraries/sidechain/include/sidechain/primary_wallet_vout_manager.hpp new file mode 100644 index 00000000..d569669d --- /dev/null +++ b/libraries/sidechain/include/sidechain/primary_wallet_vout_manager.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +#include + +namespace sidechain { + +class primary_wallet_vout_manager +{ + +public: + primary_wallet_vout_manager( graphene::chain::database& _db ) : db( _db ) {} + + bool is_reach_max_unconfirmaed_vout() const; + + fc::optional< graphene::chain::primary_wallet_vout_object > get_latest_unused_vout() const; + + void create_new_vout( const sidechain::prev_out& out ); + + void delete_vout_with_newer( fc::uint256 hash_id ); + + void confirm_vout( fc::uint256 hash_id ); + + void use_latest_vout( fc::uint256 hash_id ); + +private: + + fc::optional< graphene::chain::primary_wallet_vout_id_type > get_vout_id( fc::uint256 hash_id ) const; + + graphene::chain::database& db; + +}; + +} diff --git a/libraries/sidechain/include/sidechain/types.hpp b/libraries/sidechain/include/sidechain/types.hpp index fe7844be..2add508c 100644 --- a/libraries/sidechain/include/sidechain/types.hpp +++ b/libraries/sidechain/include/sidechain/types.hpp @@ -12,7 +12,8 @@ namespace sidechain { using bytes = std::vector; using accounts_keys = std::map< graphene::chain::account_id_type, graphene::chain::public_key_type >; -enum class payment_type { +enum class payment_type +{ NULLDATA, P2PK, P2PKH, @@ -23,6 +24,14 @@ enum class payment_type { P2SH_WSH }; +struct prev_out +{ + std::string hash_tx; + uint32_t n_vout; + uint64_t amount; +}; + } FC_REFLECT_ENUM( sidechain::payment_type, (NULLDATA)(P2PK)(P2PKH)(P2SH)(P2WPKH)(P2WSH)(P2SH_WPKH)(P2SH_WSH) ); +FC_REFLECT( sidechain::prev_out, (hash_tx)(n_vout)(amount) ); diff --git a/libraries/sidechain/primary_wallet_vout_manager.cpp b/libraries/sidechain/primary_wallet_vout_manager.cpp new file mode 100644 index 00000000..b7ae9aef --- /dev/null +++ b/libraries/sidechain/primary_wallet_vout_manager.cpp @@ -0,0 +1,97 @@ +#include +#include + +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 ); +} + +fc::optional< graphene::chain::primary_wallet_vout_object > primary_wallet_vout_manager::get_latest_unused_vout() const +{ + const auto& PW_vout_idx = db.get_index_type().indices().get< graphene::chain::by_id >(); + auto itr = PW_vout_idx.end(); + FC_ASSERT( itr != PW_vout_idx.begin() ); + + itr--; + if( itr->used ) + return fc::optional< graphene::chain::primary_wallet_vout_object >(); + return fc::optional< graphene::chain::primary_wallet_vout_object > (*itr); +} + +void primary_wallet_vout_manager::create_new_vout( const sidechain::prev_out& out ) +{ + db.create([&]( graphene::chain::primary_wallet_vout_object& obj ) { + obj.vout = out; + obj.hash_id = fc::sha256::hash( out.hash_tx + std::to_string( out.n_vout ) ); + obj.confirmed = false; + obj.used = false; + }); +} + +void primary_wallet_vout_manager::delete_vout_with_newer( fc::uint256 hash_id ) +{ + const auto& PW_vout_by_id = db.get_index_type().indices().get< graphene::chain::by_id >(); + auto vout_id = get_vout_id( hash_id ); + if( !vout_id.valid() ) + return; + + auto itr = PW_vout_by_id.find( *vout_id ); + + while( itr != PW_vout_by_id.end() ) + { + auto temp = itr; + itr++; + db.remove( *temp ); + } +} + +void primary_wallet_vout_manager::confirm_vout( fc::uint256 hash_id ) +{ + const auto& PW_vout_by_id = db.get_index_type().indices().get< graphene::chain::by_id >(); + auto vout_id = get_vout_id( hash_id ); + FC_ASSERT( vout_id.valid() ); + + auto itr = PW_vout_by_id.find( *vout_id ); + + db.modify(*itr, [&]( graphene::chain::primary_wallet_vout_object& PW_vout ) { + PW_vout.confirmed = true; + }); + + if( itr != PW_vout_by_id.begin() ){ + itr--; + FC_ASSERT( itr->confirmed == true ); + db.remove(*itr); + } +} + +void primary_wallet_vout_manager::use_latest_vout( fc::uint256 hash_id ) +{ + const auto& PW_vout_by_id = db.get_index_type().indices().get< graphene::chain::by_id >(); + auto vout_id = get_vout_id( hash_id ); + FC_ASSERT( vout_id.valid() ); + + auto itr = PW_vout_by_id.find( *vout_id ); + + db.modify(*itr, [&]( graphene::chain::primary_wallet_vout_object& PW_vout ) { + PW_vout.used = true; + }); + + if( itr != PW_vout_by_id.begin() ){ + itr--; + FC_ASSERT( itr->used == true ); + } +} + +fc::optional< graphene::chain::primary_wallet_vout_id_type > primary_wallet_vout_manager::get_vout_id( fc::uint256 hash_id ) const +{ + const auto& PW_vout_by_hash_id = db.get_index_type().indices().get< graphene::chain::by_hash_id >(); + const auto& itr_hash_id = PW_vout_by_hash_id.find( hash_id ); + if( itr_hash_id == PW_vout_by_hash_id.end() ) + return fc::optional< graphene::chain::primary_wallet_vout_id_type >(); + return fc::optional< graphene::chain::primary_wallet_vout_id_type >( itr_hash_id->get_id() ); +} + +} \ No newline at end of file diff --git a/tests/tests/bitcoin_address_obj_tests.cpp b/tests/tests/bitcoin_address_obj_tests.cpp index 81bc0bb1..aafb3039 100644 --- a/tests/tests/bitcoin_address_obj_tests.cpp +++ b/tests/tests/bitcoin_address_obj_tests.cpp @@ -9,7 +9,8 @@ using namespace graphene::chain; BOOST_FIXTURE_TEST_SUITE( bitcoin_addresses_obj_tests, database_fixture ) -BOOST_AUTO_TEST_CASE( create_bitcoin_address_test ) { +BOOST_AUTO_TEST_CASE( create_bitcoin_address_test ) +{ transaction_evaluation_state context(&db); bitcoin_address_create_operation op; diff --git a/tests/tests/bitcoin_address_tests.cpp b/tests/tests/bitcoin_address_tests.cpp index a98fa5f7..e5437d42 100644 --- a/tests/tests/bitcoin_address_tests.cpp +++ b/tests/tests/bitcoin_address_tests.cpp @@ -93,7 +93,8 @@ BOOST_AUTO_TEST_CASE( addresses_raw_test ) BOOST_CHECK( bitcoin_address( p2sh_testnet ).get_raw_address() == standard_p2sh_testnet ); } -BOOST_AUTO_TEST_CASE( create_multisig_address_test ) { +BOOST_AUTO_TEST_CASE( create_multisig_address_test ) +{ std::vector public_key1 = parse_hex( "03db643710666b862e0a97f7edbe8ef40ec2c4a29ef995c431c21ca85e35000010" ); std::vector public_key2 = parse_hex( "0320000d982c156a6f09df8c7674abddc2bb326533268ed03572916221b4417983" ); @@ -112,7 +113,8 @@ BOOST_AUTO_TEST_CASE( create_multisig_address_test ) { BOOST_CHECK( redeem_script == cma.redeem_script ); } -BOOST_AUTO_TEST_CASE( create_segwit_address_test ) { +BOOST_AUTO_TEST_CASE( create_segwit_address_test ) +{ // https://0bin.net/paste/nfnSf0HcBqBUGDto#7zJMRUhGEBkyh-eASQPEwKfNHgQ4D5KrUJRsk8MTPSa std::vector public_key1 = parse_hex( "03b3623117e988b76aaabe3d63f56a4fc88b228a71e64c4cc551d1204822fe85cb" ); std::vector public_key2 = parse_hex( "03dd823066e096f72ed617a41d3ca56717db335b1ea47a1b4c5c9dbdd0963acba6" ); diff --git a/tests/tests/input_withdrawal_info_tests.cpp b/tests/tests/input_withdrawal_info_tests.cpp index 03e00dae..9bca1ea9 100644 --- a/tests/tests/input_withdrawal_info_tests.cpp +++ b/tests/tests/input_withdrawal_info_tests.cpp @@ -8,7 +8,8 @@ using namespace sidechain; BOOST_FIXTURE_TEST_SUITE( input_withdrawal_info_tests, database_fixture ) -BOOST_AUTO_TEST_CASE( input_withdrawal_info_insert_vin_test ) { +BOOST_AUTO_TEST_CASE( input_withdrawal_info_insert_vin_test ) +{ input_withdrawal_info infos( db ); prev_out out = { "1", 1, 13 }; infos.insert_info_for_vin( out, "addr1", { 0x01, 0x02, 0x03 } ); @@ -17,7 +18,8 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_insert_vin_test ) { info_for_vin::count_id_info_for_vin = 0; } -BOOST_AUTO_TEST_CASE( input_withdrawal_info_many_insert_vin_test ) { +BOOST_AUTO_TEST_CASE( input_withdrawal_info_many_insert_vin_test ) +{ input_withdrawal_info infos( db ); for( size_t i = 1; i <= 10; i++ ) { prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; @@ -28,7 +30,8 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_many_insert_vin_test ) { info_for_vin::count_id_info_for_vin = 0; } -BOOST_AUTO_TEST_CASE( input_withdrawal_info_id_test ) { +BOOST_AUTO_TEST_CASE( input_withdrawal_info_id_test ) +{ input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; @@ -40,7 +43,8 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_id_test ) { info_for_vin::count_id_info_for_vin = 0; } -BOOST_AUTO_TEST_CASE( input_withdrawal_info_check_data_test ) { +BOOST_AUTO_TEST_CASE( input_withdrawal_info_check_data_test ) +{ input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; @@ -61,7 +65,8 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_check_data_test ) { info_for_vin::count_id_info_for_vin = 0; } -BOOST_AUTO_TEST_CASE( input_withdrawal_info_modify_test ) { +BOOST_AUTO_TEST_CASE( input_withdrawal_info_modify_test ) +{ input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; @@ -97,7 +102,8 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_modify_test ) { info_for_vin::count_id_info_for_vin = 0; } -BOOST_AUTO_TEST_CASE( input_withdrawal_info_remove_vin_test ) { +BOOST_AUTO_TEST_CASE( input_withdrawal_info_remove_vin_test ) +{ input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; @@ -123,7 +129,8 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_remove_vin_test ) { info_for_vin::count_id_info_for_vin = 0; } -BOOST_AUTO_TEST_CASE( input_withdrawal_info_get_info_for_vins_test ) { +BOOST_AUTO_TEST_CASE( input_withdrawal_info_get_info_for_vins_test ) +{ input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; @@ -144,13 +151,15 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_get_info_for_vins_test ) { info_for_vin::count_id_info_for_vin = 0; } -BOOST_AUTO_TEST_CASE( input_withdrawal_info_insert_vout_test ) { +BOOST_AUTO_TEST_CASE( input_withdrawal_info_insert_vout_test ) +{ input_withdrawal_info infos( db ); infos.insert_info_for_vout( account_id_type(), payment_type::NULLDATA, "1", 1 ); BOOST_CHECK( infos.size_info_for_vouts() == 1 ); } -BOOST_AUTO_TEST_CASE( input_withdrawal_info_many_insert_vout_test ) { +BOOST_AUTO_TEST_CASE( input_withdrawal_info_many_insert_vout_test ) +{ input_withdrawal_info infos( db ); for( size_t i = 1; i <= 10; i++ ) { infos.insert_info_for_vout( account_id_type(i), payment_type::NULLDATA, std::to_string( i ), static_cast( i ) ); @@ -158,7 +167,8 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_many_insert_vout_test ) { BOOST_CHECK( infos.size_info_for_vouts() == 10 ); } -BOOST_AUTO_TEST_CASE( input_withdrawal_info_remove_vout_test ) { +BOOST_AUTO_TEST_CASE( input_withdrawal_info_remove_vout_test ) +{ input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { infos.insert_info_for_vout( account_id_type(i), payment_type::NULLDATA, std::to_string( i ), static_cast( i ) ); @@ -181,7 +191,8 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_remove_vout_test ) { } } -BOOST_AUTO_TEST_CASE( input_withdrawal_info_get_info_for_vouts_test ) { +BOOST_AUTO_TEST_CASE( input_withdrawal_info_get_info_for_vouts_test ) +{ input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { infos.insert_info_for_vout( account_id_type(i), payment_type::NULLDATA, std::to_string( i ), static_cast( i ) ); diff --git a/tests/tests/primary_wallet_vout_manager_tests.cpp b/tests/tests/primary_wallet_vout_manager_tests.cpp new file mode 100644 index 00000000..2159b0ab --- /dev/null +++ b/tests/tests/primary_wallet_vout_manager_tests.cpp @@ -0,0 +1,147 @@ +#include +#include +#include "../common/database_fixture.hpp" +#include + +using namespace graphene::chain; +using namespace sidechain; + +BOOST_FIXTURE_TEST_SUITE( primary_wallet_vout_manager_tests, database_fixture ) + +void create_primary_wallet_vouts( primary_wallet_vout_manager& pw_vout_manager, const graphene::chain::database& db, uint32_t num ) +{ + uint64_t start_pos = 0; + const auto& idx = db.get_index_type().indices().get< graphene::chain::by_id >(); + + if( idx.begin() != idx.end() ){ + auto last_itr = --idx.end(); + start_pos = last_itr->id.instance() + 1; + } + + for( uint64_t i = start_pos; i < start_pos + num; i++ ) { + prev_out out = { std::to_string(i), i, i }; + pw_vout_manager.create_new_vout( out ); + } +} + +BOOST_AUTO_TEST_CASE( check_max_pw_vout_objects ) +{ + const auto& idx = db.get_index_type().indices().get< graphene::chain::by_id >(); + + primary_wallet_vout_manager pw_vout_manager( db ); + create_primary_wallet_vouts( pw_vout_manager, db, 1 ); + BOOST_CHECK( idx.size() == 1 ); + + create_primary_wallet_vouts( pw_vout_manager, db, 24 ); + BOOST_CHECK( idx.size() == 25 ); + BOOST_CHECK( pw_vout_manager.is_reach_max_unconfirmaed_vout() == true ); +} + +BOOST_AUTO_TEST_CASE( check_pw_vout_objects_chain ) +{ + const auto& idx = db.get_index_type().indices().get< graphene::chain::by_id >(); + primary_wallet_vout_manager pw_vout_manager( db ); + create_primary_wallet_vouts( pw_vout_manager, db, 24 ); + + auto itr = idx.begin(); + for( size_t i = 0; i < idx.size(); i++ ) { + BOOST_CHECK( itr->hash_id == fc::sha256::hash( std::to_string( i ) + std::to_string( i ))); + itr++; + } + + BOOST_CHECK( pw_vout_manager.get_latest_unused_vout().valid() ); + + auto pw_vout = *pw_vout_manager.get_latest_unused_vout(); + + BOOST_CHECK( pw_vout.vout.hash_tx == "23" ); + BOOST_CHECK( pw_vout.vout.n_vout == 23 ); + BOOST_CHECK( pw_vout.hash_id == fc::sha256::hash( "23" + std::to_string( 23 ))); +} + +BOOST_AUTO_TEST_CASE( delete_pw_vout_objects ) +{ + const auto& idx = db.get_index_type().indices().get< graphene::chain::by_id >(); + primary_wallet_vout_manager pw_vout_manager( db ); + create_primary_wallet_vouts( pw_vout_manager, db, 24 ); + + BOOST_CHECK( idx.size() == 24 ); + + pw_vout_manager.delete_vout_with_newer( fc::sha256::hash( "123" + std::to_string( 123 ))); + BOOST_CHECK( idx.size() == 24 ); + + pw_vout_manager.delete_vout_with_newer( fc::sha256::hash( "13" + std::to_string( 13 ))); + BOOST_CHECK( idx.size() == 13 ); + + auto itr = idx.begin(); + for( size_t i = 0; i < idx.size(); i++ ) { + BOOST_CHECK( itr->hash_id == fc::sha256::hash( std::to_string( i ) + std::to_string( i ))); + itr++; + } + + create_primary_wallet_vouts( pw_vout_manager, db, 8 ); + pw_vout_manager.delete_vout_with_newer( fc::sha256::hash( "20" + std::to_string( 20 ))); + BOOST_CHECK( idx.size() == 20 ); + + itr = idx.begin(); + for( size_t i = 0; i < idx.size(); i++ ) { + BOOST_CHECK( itr->hash_id == fc::sha256::hash( std::to_string( i ) + std::to_string( i ))); + itr++; + } + + pw_vout_manager.delete_vout_with_newer( fc::sha256::hash( "0" + std::to_string( 0 ))); + BOOST_CHECK( idx.size() == 0 ); +} + +BOOST_AUTO_TEST_CASE( confirm_pw_vout_objects ) +{ + const auto& idx = db.get_index_type().indices().get< graphene::chain::by_id >(); + primary_wallet_vout_manager pw_vout_manager( db ); + create_primary_wallet_vouts( pw_vout_manager, db, 2 ); + + pw_vout_manager.confirm_vout( fc::sha256::hash( "0" + std::to_string( 0 ))); + + auto itr = idx.begin(); + BOOST_CHECK( itr->confirmed == true ); + + pw_vout_manager.confirm_vout( fc::sha256::hash( "1" + std::to_string( 1 ))); + + itr++; + BOOST_CHECK( itr->confirmed == true ); + BOOST_CHECK( idx.size() == 1 ); + + create_primary_wallet_vouts( pw_vout_manager, db, 1 ); + itr++; + pw_vout_manager.confirm_vout( fc::sha256::hash( "2" + std::to_string( 2 ))); + + BOOST_CHECK( itr->confirmed == true ); + BOOST_CHECK( idx.size() == 1 ); + + GRAPHENE_REQUIRE_THROW( pw_vout_manager.confirm_vout( fc::sha256::hash( "4" + std::to_string( 4 ))), fc::exception ); + GRAPHENE_REQUIRE_THROW( pw_vout_manager.confirm_vout( fc::sha256::hash( "123" + std::to_string( 123 ))), fc::exception ); +} + +BOOST_AUTO_TEST_CASE( use_pw_vout_objects ) +{ + const auto& idx = db.get_index_type().indices().get< graphene::chain::by_id >(); + primary_wallet_vout_manager pw_vout_manager( db ); + auto itr = idx.begin(); + + create_primary_wallet_vouts( pw_vout_manager, db, 1 ); + pw_vout_manager.use_latest_vout( fc::sha256::hash( "0" + std::to_string( 0 ))); + + BOOST_CHECK( !pw_vout_manager.get_latest_unused_vout().valid() ); + BOOST_CHECK( itr->used == true ); + + create_primary_wallet_vouts( pw_vout_manager, db, 1 ); + pw_vout_manager.use_latest_vout( fc::sha256::hash( "1" + std::to_string( 1 ))); + itr++; + + BOOST_CHECK( !pw_vout_manager.get_latest_unused_vout().valid() ); + BOOST_CHECK( itr->used == true ); + + create_primary_wallet_vouts( pw_vout_manager, db, 2 ); + + GRAPHENE_REQUIRE_THROW( pw_vout_manager.use_latest_vout( fc::sha256::hash( "3" + std::to_string( 3 ))), fc::exception ); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file