Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add htlc api calls #1729

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions 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;

// HTCL
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,6 +974,12 @@ std::map<std::string, full_account> database_api_impl::get_full_accounts( const
acnt.withdraws.emplace_back(withdraw);
});

// get htlcs
auto htlc_range = _db.get_index_type<htlc_index>().indices().get<by_from_id>().equal_range(account->id);
std::for_each(htlc_range.first, htlc_range.second,
[&acnt] (const htlc_object& htlc) {
acnt.htlcs.emplace_back(htlc);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also list htlcs for which the account is the recipient?


results[account_name_or_id] = acnt;
}
Expand Down Expand Up @@ -2382,6 +2393,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 <= 101 );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When adding new API calls with limits, please make the limit configurable as in #1513

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 <= 101 );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When adding new API calls with limits, please make the limit configurable as in #1513

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
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 contarct id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: contarct

* @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 Account ID or name to get objects from
* @param start Withdraw permission objects(1.16.X) before this ID will be skipped in results. Pagination purposes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C&P error

* @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 Account ID or name to get objects from
* @param start Withdraw permission objects(1.16.X) before this ID will be skipped in results. Pagination purposes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C&P error

* @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)
)
16 changes: 15 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,19 @@ 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; }
};

};

struct by_from_id;
struct by_expiration;
struct by_to_id;
typedef multi_index_container<
htlc_object,
indexed_by<
Expand All @@ -94,8 +103,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 2 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 2 coins to Bob");
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 2 coins to Bob");
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);

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[alice.name].htlcs.size(), 0 );

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



BOOST_AUTO_TEST_SUITE_END()