Skip to content

Commit

Permalink
Merge pull request #1742 from bitshares/jmj_1713
Browse files Browse the repository at this point in the history
HTLC API Additions
  • Loading branch information
jmjatlanta authored Apr 30, 2019
2 parents f1ce877 + 7a6f442 commit c737ea5
Show file tree
Hide file tree
Showing 7 changed files with 297 additions and 3 deletions.
3 changes: 3 additions & 0 deletions libraries/app/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,9 @@ void application_impl::set_api_limit() {
if(_options->count("api-limit-get-key-references")){
_app_options.api_limit_get_key_references = _options->at("api-limit-get-key-references").as<uint64_t>();
}
if(_options->count("api-limit-get-htlc-by")) {
_app_options.api_limit_get_htlc_by = _options->at("api-limit-get-htlc-by").as<uint64_t>();
}
}

void application_impl::startup()
Expand Down
86 changes: 85 additions & 1 deletion libraries/app/database_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
vector<withdraw_permission_object> get_withdraw_permissions_by_giver(const std::string account_id_or_name, withdraw_permission_id_type start, uint32_t limit)const;
vector<withdraw_permission_object> get_withdraw_permissions_by_recipient(const std::string account_id_or_name, withdraw_permission_id_type start, uint32_t limit)const;

// HTLC
optional<htlc_object> get_htlc(htlc_id_type id) const;
vector<htlc_object> get_htlc_by_from(const std::string account_id_or_name, htlc_id_type start, uint32_t limit) const;
vector<htlc_object> get_htlc_by_to(const std::string account_id_or_name, htlc_id_type start, uint32_t limit) const;

//private:
static string price_to_string( const price& _price, const asset_object& _base, const asset_object& _quote );

Expand Down Expand Up @@ -969,7 +974,18 @@ std::map<std::string, full_account> database_api_impl::get_full_accounts( const
acnt.withdraws.emplace_back(withdraw);
});


// get htlcs
auto htlc_from_range = _db.get_index_type<htlc_index>().indices().get<by_from_id>().equal_range(account->id);
std::for_each(htlc_from_range.first, htlc_from_range.second,
[&acnt] (const htlc_object& htlc) {
acnt.htlcs.emplace_back(htlc);
});
auto htlc_to_range = _db.get_index_type<htlc_index>().indices().get<by_to_id>().equal_range(account->id);
std::for_each(htlc_to_range.first, htlc_to_range.second,
[&acnt] (const htlc_object& htlc) {
if ( std::find(acnt.htlcs.begin(), acnt.htlcs.end(), htlc) == acnt.htlcs.end() )
acnt.htlcs.emplace_back(htlc);
});
results[account_name_or_id] = acnt;
}
return results;
Expand Down Expand Up @@ -2382,6 +2398,74 @@ vector<withdraw_permission_object> database_api_impl::get_withdraw_permissions_b
return result;
}

//////////////////////////////////////////////////////////////////////
// //
// HTLC //
// //
//////////////////////////////////////////////////////////////////////

optional<htlc_object> database_api::get_htlc(htlc_id_type id)const
{
return my->get_htlc(id);
}

fc::optional<htlc_object> database_api_impl::get_htlc(htlc_id_type id) const
{
auto obj = get_objects( { id }).front();
if ( !obj.is_null() )
{
return fc::optional<htlc_object>(obj.template as<htlc_object>(GRAPHENE_MAX_NESTED_OBJECTS));
}
return fc::optional<htlc_object>();
}

vector<htlc_object> database_api::get_htlc_by_from(const std::string account_id_or_name, htlc_id_type start, uint32_t limit)const
{
return my->get_htlc_by_from(account_id_or_name, start, limit);
}

vector<htlc_object> database_api_impl::get_htlc_by_from(const std::string account_id_or_name, htlc_id_type start, uint32_t limit) const
{
FC_ASSERT( limit <= _app_options->api_limit_get_htlc_by );
vector<htlc_object> result;

const auto& htlc_idx = _db.get_index_type< htlc_index >().indices().get< by_from_id >();
auto htlc_index_end = htlc_idx.end();
const account_id_type account = get_account_from_string(account_id_or_name)->id;
auto htlc_itr = htlc_idx.lower_bound(boost::make_tuple(account, start));

while(htlc_itr != htlc_index_end && htlc_itr->transfer.from == account && result.size() < limit)
{
result.push_back(*htlc_itr);
++htlc_itr;
}
return result;
}

vector<htlc_object> database_api::get_htlc_by_to(const std::string account_id_or_name, htlc_id_type start, uint32_t limit)const
{
return my->get_htlc_by_to(account_id_or_name, start, limit);
}

vector<htlc_object> database_api_impl::get_htlc_by_to(const std::string account_id_or_name, htlc_id_type start, uint32_t limit) const
{

FC_ASSERT( limit <= _app_options->api_limit_get_htlc_by );
vector<htlc_object> result;

const auto& htlc_idx = _db.get_index_type< htlc_index >().indices().get< by_to_id >();
auto htlc_index_end = htlc_idx.end();
const account_id_type account = get_account_from_string(account_id_or_name)->id;
auto htlc_itr = htlc_idx.lower_bound(boost::make_tuple(account, start));

while(htlc_itr != htlc_index_end && htlc_itr->transfer.to == account && result.size() < limit)
{
result.push_back(*htlc_itr);
++htlc_itr;
}
return result;
}

//////////////////////////////////////////////////////////////////////
// //
// Private methods //
Expand Down
1 change: 1 addition & 0 deletions libraries/app/include/graphene/app/application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ namespace graphene { namespace app {
uint64_t api_limit_get_account_history_by_operations = 100;
uint64_t api_limit_get_asset_holders = 100;
uint64_t api_limit_get_key_references = 100;
uint64_t api_limit_get_htlc_by = 100;
};

class application
Expand Down
36 changes: 35 additions & 1 deletion libraries/app/include/graphene/app/database_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/worker_object.hpp>
#include <graphene/chain/witness_object.hpp>
#include <graphene/chain/htlc_object.hpp>

#include <graphene/market_history/market_history_plugin.hpp>

Expand Down Expand Up @@ -743,7 +744,36 @@ class database_api
*/
vector<withdraw_permission_object> get_withdraw_permissions_by_recipient(const std::string account_id_or_name, withdraw_permission_id_type start, uint32_t limit)const;

private:
//////////
// HTLC //
//////////

/**
* @brief Get HTLC object
* @param id HTLC contract id
* @return HTLC object for the id
*/
optional<htlc_object> get_htlc(htlc_id_type id) const;

/**
* @brief Get non expired HTLC objects using the sender account
* @param account_id_or_name Account ID or name to get objects from
* @param start htlc objects before this ID will be skipped in results. Pagination purposes.
* @param limit Maximum number of objects to retrieve
* @return HTLC objects for the account
*/
vector<htlc_object> get_htlc_by_from(const std::string account_id_or_name, htlc_id_type start, uint32_t limit) const;

/**
* @brief Get non expired HTLC objects using the receiver account
* @param account_id_or_name Account ID or name to get objects from
* @param start htlc objects before this ID will be skipped in results. Pagination purposes.
* @param limit Maximum number of objects to retrieve
* @return HTLC objects for the account
*/
vector<htlc_object> get_htlc_by_to(const std::string account_id_or_name, htlc_id_type start, uint32_t limit) const;

private:
std::shared_ptr< database_api_impl > my;
};

Expand Down Expand Up @@ -865,4 +895,8 @@ FC_API(graphene::app::database_api,
(get_withdraw_permissions_by_giver)
(get_withdraw_permissions_by_recipient)

// HTLC
(get_htlc)
(get_htlc_by_from)
(get_htlc_by_to)
)
2 changes: 2 additions & 0 deletions libraries/app/include/graphene/app/full_account.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ namespace graphene { namespace app {
vector<proposal_object> proposals;
vector<asset_id_type> assets;
vector<withdraw_permission_object> withdraws;
vector<htlc_object> htlcs;
};

} }
Expand All @@ -68,4 +69,5 @@ FC_REFLECT( graphene::app::full_account,
(proposals)
(assets)
(withdraws)
(htlcs)
)
18 changes: 17 additions & 1 deletion libraries/chain/include/graphene/chain/htlc_object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,21 @@ namespace graphene { namespace chain {
const result_type& operator()(const htlc_object& o)const { return o.transfer.from; }
};

/*****
* Index helper for to
*/
struct to_extractor {
typedef account_id_type result_type;
const result_type& operator()(const htlc_object& o)const { return o.transfer.to; }
};

bool operator==(const htlc_object& in) { return this->id == in.id; }

};

struct by_from_id;
struct by_expiration;
struct by_to_id;
typedef multi_index_container<
htlc_object,
indexed_by<
Expand All @@ -94,8 +105,13 @@ namespace graphene { namespace chain {
ordered_unique< tag< by_from_id >,
composite_key< htlc_object,
htlc_object::from_extractor,
member< object, object_id_type, &object::id > > >,

ordered_unique< tag< by_to_id >,
composite_key< htlc_object,
htlc_object::to_extractor,
member< object, object_id_type, &object::id > > >
>
>

> htlc_object_index_type;

Expand Down
154 changes: 154 additions & 0 deletions tests/tests/htlc_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -832,4 +832,158 @@ try {
} FC_LOG_AND_RETHROW()
}

BOOST_AUTO_TEST_CASE(htlc_database_api) {
try {

ACTORS((alice)(bob)(carl)(dan));

int64_t init_balance(100 * GRAPHENE_BLOCKCHAIN_PRECISION);

transfer( committee_account, alice_id, graphene::chain::asset(init_balance) );

generate_blocks(HARDFORK_CORE_1468_TIME);
set_expiration( db, trx );

set_committee_parameters(this);

uint16_t preimage_size = 256;
std::vector<char> pre_image(256);
std::independent_bits_engine<std::default_random_engine, CHAR_BIT, unsigned char> rbe;
std::generate(begin(pre_image), end(pre_image), std::ref(rbe));
graphene::chain::htlc_id_type alice_htlc_id_bob;
graphene::chain::htlc_id_type alice_htlc_id_carl;
graphene::chain::htlc_id_type alice_htlc_id_dan;

generate_block();
set_expiration( db, trx );
trx.clear();
// alice puts a htlc contract to bob
{
graphene::chain::htlc_create_operation create_operation;
BOOST_TEST_MESSAGE("Alice, who has 100 coins, is transferring 3 coins to Bob");
create_operation.amount = graphene::chain::asset( 3 * GRAPHENE_BLOCKCHAIN_PRECISION );
create_operation.to = bob_id;
create_operation.claim_period_seconds = 60;
create_operation.preimage_hash = hash_it<fc::sha256>( pre_image );
create_operation.preimage_size = preimage_size;
create_operation.from = alice_id;
create_operation.fee = db.get_global_properties().parameters.current_fees->calculate_fee(create_operation);
trx.operations.push_back(create_operation);
sign(trx, alice_private_key);
PUSH_TX(db, trx, ~0);
trx.clear();
set_expiration( db, trx );
graphene::chain::signed_block blk = generate_block();
processed_transaction alice_trx = blk.transactions[0];
alice_htlc_id_bob = alice_trx.operation_results[0].get<object_id_type>();
generate_block();
set_expiration( db, trx );
}

trx.clear();
// alice puts a htlc contract to carl
{
graphene::chain::htlc_create_operation create_operation;
BOOST_TEST_MESSAGE("Alice, who has 100 coins, is transferring 3 coins to Carl");
create_operation.amount = graphene::chain::asset( 3 * GRAPHENE_BLOCKCHAIN_PRECISION );
create_operation.to = carl_id;
create_operation.claim_period_seconds = 60;
create_operation.preimage_hash = hash_it<fc::sha256>( pre_image );
create_operation.preimage_size = preimage_size;
create_operation.from = alice_id;
create_operation.fee = db.get_global_properties().parameters.current_fees->calculate_fee(create_operation);
trx.operations.push_back(create_operation);
sign(trx, alice_private_key);
PUSH_TX(db, trx, ~0);
trx.clear();
set_expiration( db, trx );
graphene::chain::signed_block blk = generate_block();
processed_transaction alice_trx = blk.transactions[0];
alice_htlc_id_carl = alice_trx.operation_results[0].get<object_id_type>();
generate_block();
set_expiration( db, trx );
}

trx.clear();
// alice puts a htlc contract to dan
{
graphene::chain::htlc_create_operation create_operation;
BOOST_TEST_MESSAGE("Alice, who has 100 coins, is transferring 3 coins to Dan");
create_operation.amount = graphene::chain::asset( 3 * GRAPHENE_BLOCKCHAIN_PRECISION );
create_operation.to = dan_id;
create_operation.claim_period_seconds = 60;
create_operation.preimage_hash = hash_it<fc::sha256>( pre_image );
create_operation.preimage_size = preimage_size;
create_operation.from = alice_id;
create_operation.fee = db.get_global_properties().parameters.current_fees->calculate_fee(create_operation);
trx.operations.push_back(create_operation);
sign(trx, alice_private_key);
PUSH_TX(db, trx, ~0);
trx.clear();
set_expiration( db, trx );
graphene::chain::signed_block blk = generate_block();
processed_transaction alice_trx = blk.transactions[0];
alice_htlc_id_dan = alice_trx.operation_results[0].get<object_id_type>();
generate_block();
set_expiration( db, trx );
}

graphene::app::database_api db_api(db, &(this->app.get_options()) ) ;

auto htlc = db_api.get_htlc(alice_htlc_id_bob);
BOOST_CHECK_EQUAL( htlc->id.instance(), 0);
BOOST_CHECK_EQUAL( htlc->transfer.from.instance.value, 16 );
BOOST_CHECK_EQUAL( htlc->transfer.to.instance.value, 17 );

htlc = db_api.get_htlc(alice_htlc_id_carl);
BOOST_CHECK_EQUAL( htlc->id.instance(), 1);
BOOST_CHECK_EQUAL( htlc->transfer.from.instance.value, 16 );
BOOST_CHECK_EQUAL( htlc->transfer.to.instance.value, 18 );

htlc = db_api.get_htlc(alice_htlc_id_dan);
BOOST_CHECK_EQUAL( htlc->id.instance(), 2);
BOOST_CHECK_EQUAL( htlc->transfer.from.instance.value, 16 );
BOOST_CHECK_EQUAL( htlc->transfer.to.instance.value, 19 );

auto htlcs_alice = db_api.get_htlc_by_from(alice.name, graphene::chain::htlc_id_type(0), 100);
BOOST_CHECK_EQUAL( htlcs_alice.size(), 3 );
BOOST_CHECK_EQUAL( htlcs_alice[0].id.instance(), 0 );
BOOST_CHECK_EQUAL( htlcs_alice[1].id.instance(), 1 );
BOOST_CHECK_EQUAL( htlcs_alice[2].id.instance(), 2 );

htlcs_alice = db_api.get_htlc_by_from(alice.name, graphene::chain::htlc_id_type(1), 1);
BOOST_CHECK_EQUAL( htlcs_alice.size(), 1 );
BOOST_CHECK_EQUAL( htlcs_alice[0].id.instance(), 1 );

htlcs_alice = db_api.get_htlc_by_from(alice.name, graphene::chain::htlc_id_type(1), 2);
BOOST_CHECK_EQUAL( htlcs_alice.size(), 2 );
BOOST_CHECK_EQUAL( htlcs_alice[0].id.instance(), 1 );
BOOST_CHECK_EQUAL( htlcs_alice[1].id.instance(), 2 );

auto htlcs_bob = db_api.get_htlc_by_to(bob.name, graphene::chain::htlc_id_type(0), 100);
BOOST_CHECK_EQUAL( htlcs_bob.size(), 1 );
BOOST_CHECK_EQUAL( htlcs_bob[0].id.instance(), 0 );

auto htlcs_carl = db_api.get_htlc_by_to(carl.name, graphene::chain::htlc_id_type(0), 100);
BOOST_CHECK_EQUAL( htlcs_carl.size(), 1 );
BOOST_CHECK_EQUAL( htlcs_carl[0].id.instance(), 1 );

auto htlcs_dan = db_api.get_htlc_by_to(dan.name, graphene::chain::htlc_id_type(0), 100);
BOOST_CHECK_EQUAL( htlcs_dan.size(), 1 );
BOOST_CHECK_EQUAL( htlcs_dan[0].id.instance(), 2 );

auto full = db_api.get_full_accounts({alice.name}, false);
BOOST_CHECK_EQUAL( full[alice.name].htlcs.size(), 3 );

full = db_api.get_full_accounts({bob.name}, false);
BOOST_CHECK_EQUAL( full[bob.name].htlcs.size(), 1 );

} catch (fc::exception &e) {
edump((e.to_detail_string()));
throw;
}
}



BOOST_AUTO_TEST_SUITE_END()

0 comments on commit c737ea5

Please sign in to comment.