Information storage for inputs and outputs

This commit is contained in:
Anzhy Cherrnyavski 2019-01-10 15:08:45 +03:00
parent 381946bab7
commit d18e36d459
10 changed files with 566 additions and 1 deletions

View file

@ -10,3 +10,4 @@ add_subdirectory( utilities )
add_subdirectory( app )
add_subdirectory( plugins )
add_subdirectory( wallet )
add_subdirectory( sidechain )

View file

@ -117,7 +117,8 @@ add_library( graphene_chain
)
add_dependencies( graphene_chain build_hardfork_hpp )
target_link_libraries( graphene_chain fc graphene_db )
#target_link_libraries( graphene_chain fc graphene_db )
target_link_libraries( graphene_chain fc graphene_db sidechain )
target_include_directories( graphene_chain
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include" )

View file

@ -85,6 +85,8 @@
#include <boost/algorithm/string.hpp>
#include <graphene/chain/info_for_vout_object.hpp>
namespace graphene { namespace chain {
// C++ requires that static class variables declared and initialized
@ -301,6 +303,8 @@ void database::initialize_indexes()
//add_index< primary_index<distributed_dividend_balance_object_index > >();
add_index< primary_index<pending_dividend_payout_balance_for_holder_object_index > >();
add_index< primary_index<total_distributed_dividend_balance_object_index > >();
add_index< primary_index<info_for_vout_index > >();
}
void database::init_genesis(const genesis_state_type& genesis_state)

View file

@ -0,0 +1,48 @@
#pragma once
#include <graphene/chain/protocol/types.hpp>
#include <graphene/db/generic_index.hpp>
namespace graphene { namespace chain {
class info_for_vout_object : public abstract_object<info_for_vout_object>
{
public:
static const uint8_t space_id = protocol_ids;
static const uint8_t type_id = info_for_vout_object_type;
struct comparer {
bool operator()( const info_for_vout_object& lhs, const info_for_vout_object& rhs ) const {
if( lhs.created != rhs.created )
return lhs.created < rhs.created;
return lhs.id < rhs.id;
}
};
info_for_vout_id_type get_id()const { return id; }
account_id_type payer;
// btc::payment_type addr_type;
std::string data;
uint64_t amount;
bool created = false;
};
struct by_created;
struct by_id_and_not_created;
typedef boost::multi_index_container<
info_for_vout_object,
indexed_by<
ordered_unique< tag< by_id >, member< object, object_id_type, &object::id > >,
ordered_non_unique< tag< by_created >, member< info_for_vout_object, bool, &info_for_vout_object::created > >,
ordered_non_unique<tag<by_id_and_not_created>, identity< info_for_vout_object >, info_for_vout_object::comparer >
>
> info_for_vout_multi_index_container;
typedef generic_index<info_for_vout_object, info_for_vout_multi_index_container> info_for_vout_index;
} } // graphene::chain
FC_REFLECT_DERIVED( graphene::chain::info_for_vout_object, (graphene::chain::object), (payer)(data)(amount)(created) )

View file

@ -145,6 +145,7 @@ namespace graphene { namespace chain {
betting_market_group_object_type,
betting_market_object_type,
bet_object_type,
info_for_vout_object_type,
OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types
};
@ -202,6 +203,7 @@ namespace graphene { namespace chain {
class betting_market_group_object;
class betting_market_object;
class bet_object;
class info_for_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;
@ -228,6 +230,7 @@ namespace graphene { namespace chain {
typedef object_id< protocol_ids, betting_market_group_object_type, betting_market_group_object> betting_market_group_id_type;
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;
// implementation types
class global_property_object;
@ -402,6 +405,7 @@ FC_REFLECT_ENUM( graphene::chain::object_type,
(betting_market_group_object_type)
(betting_market_object_type)
(bet_object_type)
(info_for_vout_object_type)
(OBJECT_TYPE_COUNT)
)
FC_REFLECT_ENUM( graphene::chain::impl_object_type,

View file

@ -0,0 +1,7 @@
file( GLOB SOURCES "*.cpp" )
file( GLOB HEADERS "include/*.hpp" )
add_library( sidechain STATIC ${SOURCES} ${HEADERS} )
target_link_libraries( sidechain ${Boost_LIBRARIES} fc graphene_chain )
target_include_directories( sidechain PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )

View file

@ -0,0 +1,115 @@
#pragma once
#include <string>
#include <vector>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <sidechain/thread_safe_index.hpp>
#include <fc/crypto/sha256.hpp>
#include <graphene/chain/info_for_vout_object.hpp>
#include <graphene/chain/protocol/types.hpp>
using boost::multi_index_container;
using namespace boost::multi_index;
using info_for_vout = graphene::chain::info_for_vout_object;
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;
info_for_vin( const prev_out& _out, const std::string& _address, std::vector<char> _script = std::vector<char>() ) :
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 ) );
}
struct comparer {
bool operator() ( const info_for_vin& lhs, const info_for_vin& rhs ) const;
};
static uint64_t count_id_info_for_vin;
uint64_t id;
fc::sha256 identifier;
prev_out out;
std::string address;
std::vector<char> script;
bool created = false;
};
struct by_id;
struct by_identifier;
struct by_id_and_not_created;
using info_for_vin_index = boost::multi_index_container<info_for_vin,
indexed_by<
ordered_unique<tag<by_id>, member<info_for_vin, uint64_t, &info_for_vin::id>>,
ordered_unique<tag<by_identifier>, member<info_for_vin, fc::sha256, &info_for_vin::identifier>>,
ordered_non_unique<tag<by_id_and_not_created>, identity< info_for_vin >, info_for_vin::comparer >
>
>;
class input_withdrawal_info
{
public:
using iterator_id_vin = typename info_for_vin_index::template index<by_id>::type::iterator;
using iterator_id_vout = typename graphene::chain::info_for_vout_index::index_type::template index<graphene::chain::by_id>::type::iterator;
input_withdrawal_info( graphene::chain::database& _db ) : db( _db ) {}
void insert_info_for_vin( const prev_out& out, const std::string& address, std::vector<char> script = std::vector<char>() );
void modify_info_for_vin( const info_for_vin& obj, const std::function<void( info_for_vin& e )>& func );
void mark_as_used_vin( const info_for_vin& obj );
void remove_info_for_vin( const info_for_vin& obj );
std::pair<bool, input_withdrawal_info::iterator_id_vin> find_info_for_vin( uint64_t id );
size_t size_info_for_vins() { return info_for_vins.size(); }
std::vector<info_for_vin> get_info_for_vins();
void insert_info_for_vout( const graphene::chain::account_id_type& payer, /*ayment_type addr_type,*/ const std::string& data, const uint64_t& amount );
void mark_as_used_vout( const graphene::chain::info_for_vout_object& obj );
void remove_info_for_vout( const info_for_vout& obj );
std::pair<bool, input_withdrawal_info::iterator_id_vout> find_info_for_vout( uint64_t id );
size_t size_info_for_vouts();
std::vector<info_for_vout> get_info_for_vouts();
private:
graphene::chain::database& db;
thread_safe_index<info_for_vin_index> info_for_vins;
};
}

View file

@ -0,0 +1,63 @@
#pragma once
#include <mutex>
namespace sidechain {
struct by_id;
template<class T1>
class thread_safe_index {
public:
using iterator = typename T1::iterator;
using iterator_id = typename T1::template index<by_id>::type::iterator;
std::pair<iterator,bool> insert( const typename T1::value_type& value ) {
std::lock_guard<std::recursive_mutex> locker( lock );
return data.insert( value );
}
void modify( const typename T1::value_type& obj, const std::function<void( typename T1::value_type& e)>& func ) {
std::lock_guard<std::recursive_mutex> locker( lock );
data.modify( data.iterator_to(obj), [&func]( typename T1::value_type& obj ) { func(obj); } );
}
void remove( const typename T1::value_type& obj ) {
std::lock_guard<std::recursive_mutex> locker( lock );
data.erase( data.iterator_to( obj ) );
}
size_t size() {
std::lock_guard<std::recursive_mutex> locker( lock );
return data.size();
}
std::pair<bool, iterator_id> find( uint64_t id ) {
std::lock_guard<std::recursive_mutex> locker( lock );
auto& index = data.template get<by_id>();
auto it = index.find( id );
if( it != index.end() ) {
return std::make_pair(true, it);
}
return std::make_pair(false, it);
}
template<class T2>
void safe_for(std::function<void(typename T1::template index<T2>::type::iterator itr1,
typename T1::template index<T2>::type::iterator itr2)> func) {
std::lock_guard<std::recursive_mutex> locker( lock );
auto& index = data.template get<T2>();
func(index.begin(), index.end());
}
private:
std::recursive_mutex lock;
T1 data;
};
}

View file

@ -0,0 +1,122 @@
#include <sidechain/input_withdrawal_info.hpp>
#include <graphene/chain/database.hpp>
namespace sidechain {
uint64_t info_for_vin::count_id_info_for_vin = 0;
bool info_for_vin::comparer::operator() ( const info_for_vin& lhs, const info_for_vin& rhs ) const
{
if( lhs.created != rhs.created ) {
return lhs.created < rhs.created;
}
return lhs.id < rhs.id;
}
void input_withdrawal_info::insert_info_for_vin( const prev_out& out, const std::string& address, std::vector<char> script )
{
info_for_vins.insert( info_for_vin( out, address, script ) );
}
void input_withdrawal_info::modify_info_for_vin( const info_for_vin& obj, const std::function<void( info_for_vin& e )>& func )
{
info_for_vins.modify( obj, func );
}
void input_withdrawal_info::mark_as_used_vin( const info_for_vin& obj )
{
info_for_vins.modify( obj, [&]( info_for_vin& o ) {
o.created = true;
} );
}
void input_withdrawal_info::remove_info_for_vin( const info_for_vin& obj )
{
info_for_vins.remove( obj );
}
std::pair<bool, input_withdrawal_info::iterator_id_vin> input_withdrawal_info::find_info_for_vin( uint64_t id )
{
return info_for_vins.find( id );
}
std::vector<info_for_vin> input_withdrawal_info::get_info_for_vins()
{
std::vector<info_for_vin> result;
info_for_vins.safe_for<by_id_and_not_created>( [&]( info_for_vin_index::index<by_id_and_not_created>::type::iterator itr_b,
info_for_vin_index::index<by_id_and_not_created>::type::iterator itr_e )
{
for( size_t i = 0; itr_b != itr_e && i < 5 && !itr_b->created; i++ ) { // 5 amount vins to bitcoin transaction
info_for_vin vin;
vin.identifier = itr_b->identifier;
vin.out.hash_tx = itr_b->out.hash_tx;
vin.out.n_vout = itr_b->out.n_vout;
vin.out.amount = itr_b->out.amount;
vin.address = itr_b->address;
// vin.script = get account address, from the address get the script
result.push_back( vin );
++itr_b;
}
} );
return result;
}
void input_withdrawal_info::insert_info_for_vout( const graphene::chain::account_id_type& payer, /*ayment_type addr_type,*/ const std::string& data, const uint64_t& amount )
{
db.create<graphene::chain::info_for_vout_object>([&](graphene::chain::info_for_vout_object& obj) {
obj.payer = payer;
// obj.addr_type = addr_type;
obj.data = data;
obj.amount = amount;
});
}
void input_withdrawal_info::mark_as_used_vout( const graphene::chain::info_for_vout_object& obj )
{
db.modify<graphene::chain::info_for_vout_object>( obj, [&]( graphene::chain::info_for_vout_object& o ) {
o.created = true;
});
}
void input_withdrawal_info::remove_info_for_vout( const info_for_vout& obj )
{
db.remove( obj );
}
std::pair<bool, input_withdrawal_info::iterator_id_vout> input_withdrawal_info::find_info_for_vout( uint64_t id )
{
const auto& info_for_vout_idx = db.get_index_type<graphene::chain::info_for_vout_index>().indices().get< graphene::chain::by_id >();
auto itr = info_for_vout_idx.find( graphene::chain::info_for_vout_id_type( id ) );
return std::make_pair( itr != info_for_vout_idx.end(), itr );
}
size_t input_withdrawal_info::size_info_for_vouts()
{
const auto& info_for_vout_idx = db.get_index_type<graphene::chain::info_for_vout_index>().indices().get< graphene::chain::by_id >();
return info_for_vout_idx.size();
}
std::vector<info_for_vout> input_withdrawal_info::get_info_for_vouts()
{
std::vector<info_for_vout> result;
const auto& info_for_vout_idx = db.get_index_type<graphene::chain::info_for_vout_index>().indices().get< graphene::chain::by_id_and_not_created >();
auto itr = info_for_vout_idx.begin();
for(size_t i = 0; i < 5 && itr != info_for_vout_idx.end() && !itr->created; i++) {
info_for_vout vout;
vout.payer = itr->payer;
// vout.addr_type = itr->addr_type;
vout.data = itr->data;
vout.amount = itr->amount;
result.push_back( vout );
++itr;
}
return result;
}
}

View file

@ -0,0 +1,200 @@
#include <boost/test/unit_test.hpp>
#include <sidechain/input_withdrawal_info.hpp>
#include "../common/database_fixture.hpp"
using namespace graphene::chain;
BOOST_FIXTURE_TEST_SUITE( input_withdrawal_info_tests, database_fixture )
BOOST_AUTO_TEST_CASE( input_withdrawal_info_insert_vin_test ) {
sidechain::input_withdrawal_info infos( db );
sidechain::prev_out out = { "1", 1, 13 };
infos.insert_info_for_vin( out, "addr1", { 0x01, 0x02, 0x03 } );
BOOST_CHECK( infos.size_info_for_vins() == 1 );
sidechain::info_for_vin::count_id_info_for_vin = 0;
}
BOOST_AUTO_TEST_CASE( input_withdrawal_info_many_insert_vin_test ) {
sidechain::input_withdrawal_info infos( db );
for( size_t i = 1; i <= 10; i++ ) {
sidechain::prev_out out = { std::to_string( i ), static_cast<uint32_t>( i ), static_cast< uint64_t >( i ) };
infos.insert_info_for_vin( out, "addr" + std::to_string( i ), { 0x01, 0x02, 0x03 } );
}
BOOST_CHECK( infos.size_info_for_vins() == 10 );
sidechain::info_for_vin::count_id_info_for_vin = 0;
}
BOOST_AUTO_TEST_CASE( input_withdrawal_info_id_test ) {
sidechain::input_withdrawal_info infos( db );
for( size_t i = 0; i < 10; i++ ) {
sidechain::prev_out out = { std::to_string( i ), static_cast<uint32_t>( i ), static_cast< uint64_t >( i ) };
infos.insert_info_for_vin( out, "addr" + std::to_string( i ), { 0x01, 0x02, 0x03 } );
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).first );
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->id == i );
}
sidechain::info_for_vin::count_id_info_for_vin = 0;
}
BOOST_AUTO_TEST_CASE( input_withdrawal_info_check_data_test ) {
sidechain::input_withdrawal_info infos( db );
for( size_t i = 0; i < 10; i++ ) {
sidechain::prev_out out = { std::to_string( i ), static_cast<uint32_t>( i ), static_cast< uint64_t >( i ) };
infos.insert_info_for_vin( out, "addr" + std::to_string( i ), { 0x01, 0x02, 0x03 } );
}
for( size_t i = 0; i < 10; i++ ) {
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).first );
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->id == i );
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->out.hash_tx == std::to_string( i ) );
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->out.n_vout == i );
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->out.amount == i );
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->address == "addr" + std::to_string( i ) );
std::vector<char> script = { 0x01, 0x02, 0x03 };
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->script == script );
}
sidechain::info_for_vin::count_id_info_for_vin = 0;
}
BOOST_AUTO_TEST_CASE( input_withdrawal_info_modify_test ) {
sidechain::input_withdrawal_info infos( db );
for( size_t i = 0; i < 10; i++ ) {
sidechain::prev_out out = { std::to_string( i ), static_cast<uint32_t>( i ), static_cast< uint64_t >( i ) };
infos.insert_info_for_vin( out, "addr" + std::to_string( i ), { 0x01, 0x02, 0x03 } );
}
for( size_t i = 0; i < 10; i++ ) {
if( i % 2 == 0 ) {
auto iter = infos.find_info_for_vin( static_cast< uint64_t >( i ) );
BOOST_CHECK( iter.first );
infos.modify_info_for_vin( *iter.second, [&]( sidechain::info_for_vin& obj ) {
obj.out.hash_tx = std::to_string( i + 1 );
obj.out.n_vout = i + 1;
obj.out.amount = i + 1;
obj.address = "addr" + std::to_string( i ) + std::to_string( i );
} );
}
}
for( size_t i = 0; i < 10; i++ ) {
if( i % 2 == 0 ) {
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).first );
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->id == i );
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->out.hash_tx == std::to_string( i + 1 ) );
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->out.n_vout == i + 1 );
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->out.amount == i + 1 );
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->address == "addr" + std::to_string( i ) + std::to_string( i ) );
std::vector<char> script = { 0x01, 0x02, 0x03 };
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->script == script );
}
}
sidechain::info_for_vin::count_id_info_for_vin = 0;
}
BOOST_AUTO_TEST_CASE( input_withdrawal_info_remove_vin_test ) {
sidechain::input_withdrawal_info infos( db );
for( size_t i = 0; i < 10; i++ ) {
sidechain::prev_out out = { std::to_string( i ), static_cast<uint32_t>( i ), static_cast< uint64_t >( i ) };
infos.insert_info_for_vin( out, "addr" + std::to_string( i ), { 0x01, 0x02, 0x03 } );
}
for( size_t i = 0; i < 10; i++ ) {
if( i % 2 == 0 ) {
auto iter = infos.find_info_for_vin( static_cast< uint64_t >( i ) );
BOOST_CHECK( iter.first );
infos.remove_info_for_vin( *iter.second );
}
}
for( size_t i = 0; i < 10; i++ ) {
if( i % 2 == 0 ) {
BOOST_CHECK( !infos.find_info_for_vin( static_cast< uint64_t >( i ) ).first );
} else {
BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).first );
}
}
sidechain::info_for_vin::count_id_info_for_vin = 0;
}
BOOST_AUTO_TEST_CASE( input_withdrawal_info_get_info_for_vins_test ) {
sidechain::input_withdrawal_info infos( db );
for( size_t i = 0; i < 10; i++ ) {
sidechain::prev_out out = { std::to_string( i ), static_cast<uint32_t>( i ), static_cast< uint64_t >( i ) };
infos.insert_info_for_vin( out, "addr" + std::to_string( i ), { 0x01, 0x02, 0x03 } );
}
const auto& vins = infos.get_info_for_vins();
BOOST_CHECK( vins.size() == 5 ); // 5 amount vins to bitcoin transaction
for( size_t i = 0; i < 7; i++ ) {
auto iter = infos.find_info_for_vin( static_cast< uint64_t >( i ) );
infos.mark_as_used_vin( *iter.second );
}
const auto& vins2 = infos.get_info_for_vins();
BOOST_CHECK( vins2.size() == 3 );
sidechain::info_for_vin::count_id_info_for_vin = 0;
}
BOOST_AUTO_TEST_CASE( input_withdrawal_info_insert_vout_test ) {
sidechain::input_withdrawal_info infos( db );
infos.insert_info_for_vout( account_id_type(), "1", 1 );
BOOST_CHECK( infos.size_info_for_vouts() == 1 );
}
BOOST_AUTO_TEST_CASE( input_withdrawal_info_many_insert_vout_test ) {
sidechain::input_withdrawal_info infos( db );
for( size_t i = 1; i <= 10; i++ ) {
infos.insert_info_for_vout( account_id_type(i), std::to_string( i ), static_cast<uint64_t>( i ) );
}
BOOST_CHECK( infos.size_info_for_vouts() == 10 );
}
BOOST_AUTO_TEST_CASE( input_withdrawal_info_remove_vout_test ) {
sidechain::input_withdrawal_info infos( db );
for( size_t i = 0; i < 10; i++ ) {
infos.insert_info_for_vout( account_id_type(i), std::to_string( i ), static_cast<uint64_t>( i ) );
}
for( size_t i = 0; i < 10; i++ ) {
if( i % 2 == 0 ) {
auto iter = infos.find_info_for_vout( static_cast< uint64_t >( i ) );
BOOST_CHECK( iter.first );
infos.remove_info_for_vout( *iter.second );
}
}
for( size_t i = 0; i < 10; i++ ) {
if( i % 2 == 0 ) {
BOOST_CHECK( !infos.find_info_for_vout( static_cast< uint64_t >( i ) ).first );
} else {
BOOST_CHECK( infos.find_info_for_vout( static_cast< uint64_t >( i ) ).first );
}
}
}
BOOST_AUTO_TEST_CASE( input_withdrawal_info_get_info_for_vouts_test ) {
sidechain::input_withdrawal_info infos( db );
for( size_t i = 0; i < 10; i++ ) {
infos.insert_info_for_vout( account_id_type(i), std::to_string( i ), static_cast<uint64_t>( i ) );
}
const auto& vouts = infos.get_info_for_vouts();
BOOST_CHECK( vouts.size() == 5 ); // 5 amount vouts to bitcoin transaction
for( size_t i = 0; i < 7; i++ ) {
auto iter = infos.find_info_for_vout( static_cast< uint64_t >( i ) );
infos.mark_as_used_vout( *iter.second );
}
const auto& vouts2 = infos.get_info_for_vouts();
BOOST_CHECK( vouts2.size() == 3 );
}
BOOST_AUTO_TEST_SUITE_END()