Added bitcoin_issue_operation, bitcoin_issue_evaluator with tests
This commit is contained in:
parent
ff57653584
commit
e1d99702e4
10 changed files with 384 additions and 7 deletions
|
|
@ -298,6 +298,10 @@ struct get_impacted_account_visitor
|
|||
{
|
||||
_impacted.insert( op.payer );
|
||||
}
|
||||
void operator()( const bitcoin_issue_operation& op )
|
||||
{
|
||||
_impacted.insert( op.payer );
|
||||
}
|
||||
};
|
||||
|
||||
void operation_get_impacted_accounts( const operation& op, flat_set<account_id_type>& result )
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ add_library( graphene_chain
|
|||
buyback.cpp
|
||||
bitcoin_address_evaluator.cpp
|
||||
bitcoin_transaction_evaluator.cpp
|
||||
sidechain_evaluator.cpp
|
||||
|
||||
account_object.cpp
|
||||
asset_object.cpp
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@
|
|||
#include <graphene/chain/withdraw_pbtc_evaluator.hpp>
|
||||
#include <graphene/chain/bitcoin_address_evaluator.hpp>
|
||||
#include <graphene/chain/bitcoin_transaction_evaluator.hpp>
|
||||
#include <graphene/chain/sidechain_evaluator.hpp>
|
||||
|
||||
#include <graphene/chain/protocol/fee_schedule.hpp>
|
||||
|
||||
|
|
@ -251,6 +252,7 @@ void database::initialize_evaluators()
|
|||
register_evaluator<bitcoin_address_create_evaluator>();
|
||||
register_evaluator<bitcoin_transaction_send_evaluator>();
|
||||
register_evaluator<bitcoin_transaction_sign_evaluator>();
|
||||
register_evaluator<bitcoin_issue_evaluator>();
|
||||
}
|
||||
|
||||
void database::initialize_indexes()
|
||||
|
|
|
|||
|
|
@ -285,6 +285,10 @@ struct get_impacted_account_visitor
|
|||
{
|
||||
_impacted.insert( op.payer );
|
||||
}
|
||||
void operator()( const bitcoin_issue_operation& op )
|
||||
{
|
||||
_impacted.insert( op.payer );
|
||||
}
|
||||
};
|
||||
|
||||
void operation_get_impacted_accounts( const operation& op, flat_set<account_id_type>& result )
|
||||
|
|
|
|||
|
|
@ -14,17 +14,17 @@ class bitcoin_transaction_object : public abstract_object<bitcoin_transaction_ob
|
|||
|
||||
bitcoin_transaction_id_type get_id()const { return id; }
|
||||
|
||||
fc::optional< fc::sha256 > pw_vin;
|
||||
fc::sha256 pw_vin;
|
||||
|
||||
std::vector< info_for_used_vin_id_type > vins;
|
||||
std::vector< info_for_vout_id_type > vouts;
|
||||
std::vector< info_for_vout_id_type > vouts;
|
||||
|
||||
sidechain::bitcoin_transaction transaction;
|
||||
fc::sha256 transaction_id;
|
||||
sidechain::bitcoin_transaction transaction;
|
||||
fc::sha256 transaction_id;
|
||||
|
||||
uint64_t fee_for_size;
|
||||
uint64_t fee_for_size;
|
||||
|
||||
bool confirm = false;
|
||||
bool confirm = false;
|
||||
};
|
||||
|
||||
struct by_transaction_id;
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
#include <graphene/chain/protocol/withdraw_pbtc.hpp>
|
||||
#include <graphene/chain/protocol/bitcoin_address.hpp>
|
||||
#include <graphene/chain/protocol/bitcoin_transaction.hpp>
|
||||
#include <graphene/chain/protocol/sidechain.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
|
|
@ -136,7 +137,8 @@ namespace graphene { namespace chain {
|
|||
withdraw_pbtc_operation,
|
||||
bitcoin_address_create_operation,
|
||||
bitcoin_transaction_send_operation,
|
||||
bitcoin_transaction_sign_operation
|
||||
bitcoin_transaction_sign_operation,
|
||||
bitcoin_issue_operation
|
||||
> operation;
|
||||
|
||||
/// @} // operations group
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
#include <graphene/chain/protocol/base.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
struct bitcoin_issue_operation : public base_operation
|
||||
{
|
||||
struct fee_parameters_type {
|
||||
uint64_t fee = 0;
|
||||
};
|
||||
|
||||
asset fee;
|
||||
account_id_type payer;
|
||||
fc::sha256 transaction_id;
|
||||
|
||||
|
||||
account_id_type fee_payer()const { return payer; }
|
||||
void validate()const {}
|
||||
share_type calculate_fee( const fee_parameters_type& k )const {
|
||||
share_type fee_required = k.fee;
|
||||
return fee_required;
|
||||
}
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT( graphene::chain::bitcoin_issue_operation::fee_parameters_type, (fee)(price_per_kbyte) )
|
||||
FC_REFLECT( graphene::chain::bitcoin_issue_operation, (fee)(payer)(transaction_id) )
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/exceptions.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
struct bitcoin_issue_evaluator : public evaluator< bitcoin_issue_evaluator >
|
||||
{
|
||||
typedef bitcoin_issue_operation operation_type;
|
||||
|
||||
void_result do_evaluate( const bitcoin_issue_operation& op );
|
||||
|
||||
void_result do_apply( const bitcoin_issue_operation& op );
|
||||
|
||||
void add_issue( const bitcoin_transaction_object& btc_obj );
|
||||
|
||||
void clear_btc_transaction_information( const bitcoin_transaction_object& btc_obj );
|
||||
|
||||
std::vector<uint64_t> get_amounts_to_issue( std::vector<info_for_used_vin_id_type> vins_id );
|
||||
|
||||
std::vector<account_id_type> get_accounts_to_issue( std::vector<info_for_used_vin_id_type> vins_id );
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
134
libraries/chain/sidechain_evaluator.cpp
Normal file
134
libraries/chain/sidechain_evaluator.cpp
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
#include <graphene/chain/sidechain_evaluator.hpp>
|
||||
#include <graphene/chain/bitcoin_transaction_object.hpp>
|
||||
#include <graphene/chain/info_for_used_vin_object.hpp>
|
||||
#include <graphene/chain/bitcoin_address_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
void_result bitcoin_issue_evaluator::do_evaluate( const bitcoin_issue_operation& op )
|
||||
{
|
||||
database& d = db();
|
||||
|
||||
const auto& btc_trx_idx = d.get_index_type<bitcoin_transaction_index>().indices().get<by_transaction_id>();
|
||||
const auto& btc_addr_idx = d.get_index_type<bitcoin_address_index>().indices().get<by_address>();
|
||||
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
|
||||
const auto& vouts_info_idx = d.get_index_type<info_for_vout_index>().indices().get<by_id>();
|
||||
|
||||
FC_ASSERT( op.payer == db().get_sidechain_account_id() );
|
||||
|
||||
const auto& btc_itr = btc_trx_idx.find( op.transaction_id );
|
||||
FC_ASSERT( btc_itr != btc_trx_idx.end() );
|
||||
|
||||
for( auto& vin_id : btc_itr->vins ){
|
||||
FC_ASSERT( vins_info_idx.find( vin_id ) != vins_info_idx.end() );
|
||||
|
||||
auto addr_itr = btc_addr_idx.find( vins_info_idx.find( vin_id )->address );
|
||||
FC_ASSERT( addr_itr != btc_addr_idx.end() );
|
||||
}
|
||||
|
||||
for( auto& vout_id : btc_itr->vouts )
|
||||
FC_ASSERT( vouts_info_idx.find( vout_id ) != vouts_info_idx.end() );
|
||||
|
||||
return void_result();
|
||||
}
|
||||
|
||||
void_result bitcoin_issue_evaluator::do_apply( const bitcoin_issue_operation& op )
|
||||
{
|
||||
database& d = db();
|
||||
const auto& btc_trx_idx = d.get_index_type<bitcoin_transaction_index>().indices().get<by_transaction_id>();
|
||||
const auto& btc_obj = *btc_trx_idx.find( op.transaction_id );
|
||||
|
||||
add_issue( btc_obj );
|
||||
|
||||
d.pw_vout_manager.confirm_vout( btc_obj.pw_vin );
|
||||
|
||||
clear_btc_transaction_information( btc_obj );
|
||||
|
||||
return void_result();
|
||||
}
|
||||
|
||||
void bitcoin_issue_evaluator::add_issue( const bitcoin_transaction_object& btc_obj )
|
||||
{
|
||||
database& d = db();
|
||||
|
||||
const auto& accounts_to_issue = get_accounts_to_issue( btc_obj.vins );
|
||||
const auto& amounts_to_issue = get_amounts_to_issue( btc_obj.vins );
|
||||
|
||||
bool skip_fee_old = trx_state->skip_fee;
|
||||
bool skip_fee_schedule_check_old = trx_state->skip_fee_schedule_check;
|
||||
trx_state->skip_fee = true;
|
||||
trx_state->skip_fee_schedule_check = true;
|
||||
|
||||
for( size_t i = 0; i < accounts_to_issue.size(); i++ ){
|
||||
asset_issue_operation issue_op;
|
||||
issue_op.issuer = d.get_sidechain_account_id();
|
||||
issue_op.asset_to_issue = asset( amounts_to_issue[i], d.get_sidechain_asset_id() );
|
||||
issue_op.issue_to_account = accounts_to_issue[i];
|
||||
|
||||
d.apply_operation( *trx_state, issue_op );
|
||||
}
|
||||
|
||||
trx_state->skip_fee = skip_fee_old;
|
||||
trx_state->skip_fee_schedule_check = skip_fee_schedule_check_old;
|
||||
}
|
||||
|
||||
void bitcoin_issue_evaluator::clear_btc_transaction_information( const bitcoin_transaction_object& btc_obj )
|
||||
{
|
||||
database& d = db();
|
||||
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
|
||||
const auto& vouts_info_idx = d.get_index_type<info_for_vout_index>().indices().get<by_id>();
|
||||
|
||||
for( auto& vin_id : btc_obj.vins ) {
|
||||
auto vin_itr = vins_info_idx.find( vin_id );
|
||||
d.remove( *vin_itr );
|
||||
}
|
||||
|
||||
for( auto& vout_id : btc_obj.vouts ) {
|
||||
auto vout_itr = vouts_info_idx.find( vout_id );
|
||||
d.remove( *vout_itr );
|
||||
}
|
||||
|
||||
auto trx_approvals = d.bitcoin_confirmations.find<sidechain::by_hash>( btc_obj.transaction_id );
|
||||
if( trx_approvals.valid() ) {
|
||||
d.bitcoin_confirmations.remove<sidechain::by_hash>( btc_obj.transaction_id );
|
||||
}
|
||||
|
||||
d.remove( btc_obj );
|
||||
}
|
||||
|
||||
std::vector<uint64_t> bitcoin_issue_evaluator::get_amounts_to_issue( std::vector<info_for_used_vin_id_type> vins_id )
|
||||
{
|
||||
database& d = db();
|
||||
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
|
||||
|
||||
std::vector<uint64_t> result;
|
||||
|
||||
for( auto& id : vins_id ) {
|
||||
auto vin_itr = vins_info_idx.find( id );
|
||||
result.push_back( vin_itr->out.amount );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<account_id_type> bitcoin_issue_evaluator::get_accounts_to_issue( std::vector<info_for_used_vin_id_type> vins_id )
|
||||
{
|
||||
database& d = db();
|
||||
const auto& btc_addr_idx = d.get_index_type<bitcoin_address_index>().indices().get<by_address>();
|
||||
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
|
||||
|
||||
std::vector<account_id_type> result;
|
||||
|
||||
for( auto& id : vins_id ) {
|
||||
auto vin_itr = vins_info_idx.find( id );
|
||||
auto addr_itr = btc_addr_idx.find( vin_itr->address );
|
||||
|
||||
result.push_back( addr_itr->owner );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} } // graphene::chain
|
||||
176
tests/tests/bitcoin_issue_tests.cpp
Normal file
176
tests/tests/bitcoin_issue_tests.cpp
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
#include <boost/test/unit_test.hpp>
|
||||
#include "../common/database_fixture.hpp"
|
||||
|
||||
#include <fc/crypto/digest.hpp>
|
||||
|
||||
#include <graphene/chain/primary_wallet_vout_object.hpp>
|
||||
#include <graphene/chain/bitcoin_transaction_object.hpp>
|
||||
#include <graphene/chain/info_for_used_vin_object.hpp>
|
||||
#include <graphene/chain/info_for_vout_object.hpp>
|
||||
#include <graphene/chain/bitcoin_address_object.hpp>
|
||||
|
||||
using namespace graphene::chain;
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE( bitcoin_issue_tests, database_fixture )
|
||||
|
||||
void create_bitcoin_issue_operation_environment( database& db )
|
||||
{
|
||||
std::vector< info_for_used_vin_id_type > vins;
|
||||
std::vector< info_for_vout_id_type > vouts;
|
||||
|
||||
for( auto i = 0; i < 3; i++ ){
|
||||
db.create<bitcoin_address_object>([&]( bitcoin_address_object& obj ) {
|
||||
obj.owner = account_id_type( i );
|
||||
obj.address.address = std::to_string( i );
|
||||
});
|
||||
|
||||
auto vin_id = db.create<info_for_used_vin_object>([&]( info_for_used_vin_object& obj ) {
|
||||
obj.identifier = fc::sha256( std::to_string( i ) );
|
||||
obj.out.amount = 100000 + i * 100000;
|
||||
obj.address = std::to_string( i );
|
||||
}).get_id();
|
||||
|
||||
auto vout_id = db.create<info_for_vout_object>([&]( info_for_vout_object& obj ) {
|
||||
obj.payer = account_id_type( i );
|
||||
obj.amount = 100000 + i * 100000;
|
||||
obj.address = std::to_string( i );
|
||||
}).get_id();
|
||||
|
||||
vins.push_back( vin_id );
|
||||
vouts.push_back( vout_id );
|
||||
}
|
||||
|
||||
db.create<bitcoin_transaction_object>([&]( bitcoin_transaction_object& obj ) {
|
||||
obj.pw_vin = db.pw_vout_manager.get_latest_unused_vout()->hash_id;
|
||||
obj.vins = vins;
|
||||
obj.vouts = vouts;
|
||||
obj.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" );
|
||||
});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( check_deleting_all_btc_transaction_information )
|
||||
{
|
||||
transaction_evaluation_state context(&db);
|
||||
|
||||
const auto& btc_trx_idx = db.get_index_type<bitcoin_transaction_index>().indices().get<by_id>();
|
||||
const auto& vins_info_idx = db.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
|
||||
const auto& vouts_info_idx = db.get_index_type<info_for_vout_index>().indices().get<by_id>();
|
||||
|
||||
create_bitcoin_issue_operation_environment( db );
|
||||
db.bitcoin_confirmations.insert( sidechain::bitcoin_transaction_confirmations( fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ) ) );
|
||||
|
||||
FC_ASSERT( btc_trx_idx.size() == 1 );
|
||||
FC_ASSERT( vins_info_idx.size() == 3 );
|
||||
FC_ASSERT( vouts_info_idx.size() == 3 );
|
||||
FC_ASSERT( db.bitcoin_confirmations.size() == 1 );
|
||||
|
||||
bitcoin_issue_operation op;
|
||||
op.payer = db.get_sidechain_account_id();
|
||||
op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" );
|
||||
db.apply_operation( context, op );
|
||||
|
||||
FC_ASSERT( btc_trx_idx.size() == 0 );
|
||||
FC_ASSERT( vins_info_idx.size() == 0 );
|
||||
FC_ASSERT( vouts_info_idx.size() == 0 );
|
||||
FC_ASSERT( db.bitcoin_confirmations.size() == 0 );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( check_adding_issue_to_accounts )
|
||||
{
|
||||
transaction_evaluation_state context(&db);
|
||||
const auto& btc_trx_idx = db.get_index_type<account_balance_index>().indices().get<by_account_asset>();
|
||||
|
||||
create_bitcoin_issue_operation_environment( db );
|
||||
|
||||
bitcoin_issue_operation op;
|
||||
op.payer = db.get_sidechain_account_id();
|
||||
op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" );
|
||||
|
||||
db.apply_operation( context, op );
|
||||
|
||||
for( auto i = 0; i < 3; i++ ){
|
||||
auto itr = btc_trx_idx.find( boost::make_tuple( account_id_type( i ), db.get_sidechain_asset_id() ) );
|
||||
FC_ASSERT( itr != btc_trx_idx.end() );
|
||||
|
||||
FC_ASSERT( itr->balance == 100000 + i * 100000 );
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( check_bitcoin_issue_operation_throw )
|
||||
{
|
||||
transaction_evaluation_state context(&db);
|
||||
|
||||
const auto& btc_trx_idx = db.get_index_type<bitcoin_transaction_index>().indices().get<by_id>();
|
||||
const auto& btc_addr_idx = db.get_index_type<bitcoin_address_index>().indices().get<by_address>();
|
||||
const auto& vins_info_idx = db.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
|
||||
const auto& vouts_info_idx = db.get_index_type<info_for_vout_index>().indices().get<by_id>();
|
||||
|
||||
create_bitcoin_issue_operation_environment( db );
|
||||
db.bitcoin_confirmations.insert( sidechain::bitcoin_transaction_confirmations( fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ) ) );
|
||||
|
||||
{
|
||||
auto session = db._undo_db.start_undo_session();
|
||||
|
||||
db.remove( *vouts_info_idx.begin() );
|
||||
|
||||
bitcoin_issue_operation op;
|
||||
op.payer = db.get_sidechain_account_id();
|
||||
op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" );
|
||||
GRAPHENE_REQUIRE_THROW( db.apply_operation( context, op ) , fc::exception );
|
||||
|
||||
session.undo();
|
||||
}
|
||||
|
||||
{
|
||||
auto session = db._undo_db.start_undo_session();
|
||||
|
||||
db.remove( *vins_info_idx.begin() );
|
||||
|
||||
bitcoin_issue_operation op;
|
||||
op.payer = db.get_sidechain_account_id();
|
||||
op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" );
|
||||
GRAPHENE_REQUIRE_THROW( db.apply_operation( context, op ) , fc::exception );
|
||||
|
||||
session.undo();
|
||||
}
|
||||
|
||||
{
|
||||
auto session = db._undo_db.start_undo_session();
|
||||
|
||||
db.remove( *btc_addr_idx.begin() );
|
||||
|
||||
bitcoin_issue_operation op;
|
||||
op.payer = db.get_sidechain_account_id();
|
||||
op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" );
|
||||
GRAPHENE_REQUIRE_THROW( db.apply_operation( context, op ) , fc::exception );
|
||||
|
||||
session.undo();
|
||||
}
|
||||
|
||||
{
|
||||
auto session = db._undo_db.start_undo_session();
|
||||
|
||||
db.remove( *btc_trx_idx.begin() );
|
||||
|
||||
bitcoin_issue_operation op;
|
||||
op.payer = db.get_sidechain_account_id();
|
||||
op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" );
|
||||
GRAPHENE_REQUIRE_THROW( db.apply_operation( context, op ) , fc::exception );
|
||||
|
||||
session.undo();
|
||||
}
|
||||
|
||||
{
|
||||
auto session = db._undo_db.start_undo_session();
|
||||
|
||||
bitcoin_issue_operation op;
|
||||
op.payer = account_id_type(1);
|
||||
op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" );
|
||||
GRAPHENE_REQUIRE_THROW( db.apply_operation( context, op ) , fc::exception );
|
||||
|
||||
session.undo();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
Loading…
Reference in a new issue