Database API

This commit is contained in:
Srdjan Obucina 2020-06-22 21:36:42 +02:00
parent 775eac55a9
commit d0c72f7cf7
6 changed files with 138 additions and 11 deletions

View file

@ -184,6 +184,12 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
// gpos // gpos
gpos_info get_gpos_info(const account_id_type account) const; gpos_info get_gpos_info(const account_id_type account) const;
// NFT
uint64_t nft_get_balance(const account_id_type owner) const;
optional<account_id_type> nft_owner_of(const nft_id_type token_id) const;
optional<account_id_type> nft_get_approved(const nft_id_type token_id) const;
bool nft_is_approved_for_all(const account_id_type owner, const account_id_type operator_) const;
//private: //private:
const account_object* get_account_from_string( const std::string& name_or_id, const account_object* get_account_from_string( const std::string& name_or_id,
bool throw_if_not_found = true ) const; bool throw_if_not_found = true ) const;
@ -2240,6 +2246,7 @@ graphene::app::gpos_info database_api::get_gpos_info(const account_id_type accou
return my->get_gpos_info(account); return my->get_gpos_info(account);
} }
graphene::app::gpos_info database_api_impl::get_gpos_info(const account_id_type account) const graphene::app::gpos_info database_api_impl::get_gpos_info(const account_id_type account) const
{ {
FC_ASSERT( _db.head_block_time() > HARDFORK_GPOS_TIME); //Can be deleted after GPOS hardfork time FC_ASSERT( _db.head_block_time() > HARDFORK_GPOS_TIME); //Can be deleted after GPOS hardfork time
@ -2303,6 +2310,73 @@ graphene::app::gpos_info database_api_impl::get_gpos_info(const account_id_type
return result; return result;
} }
//////////////////////////////////////////////////////////////////////
// //
// NFT methods //
// //
//////////////////////////////////////////////////////////////////////
uint64_t database_api::nft_get_balance(const account_id_type owner) const
{
return my->nft_get_balance(owner);
}
uint64_t database_api_impl::nft_get_balance(const account_id_type owner) const
{
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_owner>();
const auto &idx_nft_range = idx_nft.equal_range(owner);
return std::distance(idx_nft_range.first, idx_nft_range.second);
}
optional<account_id_type> database_api::nft_owner_of(const nft_id_type token_id) const
{
return my->nft_owner_of(token_id);
}
optional<account_id_type> database_api_impl::nft_owner_of(const nft_id_type token_id) const
{
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_id>();
auto itr_nft = idx_nft.find(token_id);
if (itr_nft != idx_nft.end()) {
return itr_nft->owner;
}
return {};
}
optional<account_id_type> database_api::nft_get_approved(const nft_id_type token_id) const
{
return my->nft_get_approved(token_id);
}
optional<account_id_type> database_api_impl::nft_get_approved(const nft_id_type token_id) const
{
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_id>();
auto itr_nft = idx_nft.find(token_id);
if (itr_nft != idx_nft.end()) {
return itr_nft->approved;
}
return {};
}
bool database_api::nft_is_approved_for_all(const account_id_type owner, const account_id_type operator_) const
{
return my->nft_is_approved_for_all(owner, operator_);
}
bool database_api_impl::nft_is_approved_for_all(const account_id_type owner, const account_id_type operator_) const
{
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_owner>();
const auto &idx_nft_range = idx_nft.equal_range(owner);
if (std::distance(idx_nft_range.first, idx_nft_range.second) == 0) {
return false;
}
bool result = true;
std::for_each(idx_nft_range.first, idx_nft_range.second, [&](const nft_object &obj) {
result = result && (obj.approved == operator_);
});
return result;
}
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// // // //
// Private methods // // Private methods //

View file

@ -48,6 +48,8 @@
#include <graphene/chain/witness_object.hpp> #include <graphene/chain/witness_object.hpp>
#include <graphene/chain/tournament_object.hpp> #include <graphene/chain/tournament_object.hpp>
#include <graphene/chain/nft_object.hpp>
#include <graphene/market_history/market_history_plugin.hpp> #include <graphene/market_history/market_history_plugin.hpp>
#include <fc/api.hpp> #include <fc/api.hpp>
@ -709,6 +711,37 @@ class database_api
*/ */
gpos_info get_gpos_info(const account_id_type account) const; gpos_info get_gpos_info(const account_id_type account) const;
/////////
// NFT //
/////////
/**
* @brief Returns the number of NFT owned by account
* @param owner Owner account ID
* @return Number of NFTs owned by account
*/
uint64_t nft_get_balance(const account_id_type owner) const;
/**
* @brief Returns the NFT owner
* @param token_id NFT ID
* @return NFT owner account ID
*/
optional<account_id_type> nft_owner_of(const nft_id_type token_id) const;
/**
* @brief Returns the NFT approved account ID
* @param token_id NFT ID
* @return NFT approved account ID
*/
optional<account_id_type> nft_get_approved(const nft_id_type token_id) const;
/**
* @brief Returns operator approved state for all NFT owned by owner
* @param owner NFT owner account ID
* @param token_id NFT ID
* @return True if operator is approved for all NFT owned by owner, else False
*/
bool nft_is_approved_for_all(const account_id_type owner, const account_id_type operator_) const;
private: private:
@ -848,4 +881,11 @@ FC_API(graphene::app::database_api,
// gpos // gpos
(get_gpos_info) (get_gpos_info)
// NFT
(nft_get_balance)
(nft_owner_of)
(nft_get_approved)
(nft_is_approved_for_all)
) )

View file

@ -13,6 +13,7 @@ namespace graphene { namespace chain {
static const uint8_t type_id = nft_object_type; static const uint8_t type_id = nft_object_type;
account_id_type owner; account_id_type owner;
account_id_type approved;
vector<account_id_type> approved_operators; vector<account_id_type> approved_operators;
std::string metadata; std::string metadata;
}; };
@ -42,6 +43,7 @@ namespace graphene { namespace chain {
FC_REFLECT_DERIVED( graphene::chain::nft_object, (graphene::db::object), FC_REFLECT_DERIVED( graphene::chain::nft_object, (graphene::db::object),
(owner) (owner)
(approved)
(approved_operators) (approved_operators)
(metadata) ) (metadata) )

View file

@ -10,6 +10,7 @@ namespace graphene { namespace chain {
asset fee; asset fee;
account_id_type owner; account_id_type owner;
account_id_type approved;
vector<account_id_type> approved_operators; vector<account_id_type> approved_operators;
std::string metadata; std::string metadata;
@ -21,12 +22,14 @@ namespace graphene { namespace chain {
struct fee_parameters_type { uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; }; struct fee_parameters_type { uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee; asset fee;
account_id_type operator_;
account_id_type from; account_id_type from;
account_id_type to; account_id_type to;
nft_id_type token_id; nft_id_type token_id;
string data; string data;
account_id_type fee_payer()const { return from; } account_id_type fee_payer()const { return operator_; }
}; };
struct nft_approve_operation : public base_operation struct nft_approve_operation : public base_operation
@ -62,8 +65,8 @@ FC_REFLECT( graphene::chain::nft_safe_transfer_from_operation::fee_parameters_ty
FC_REFLECT( graphene::chain::nft_approve_operation::fee_parameters_type, (fee) ) FC_REFLECT( graphene::chain::nft_approve_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::nft_set_approval_for_all_operation::fee_parameters_type, (fee) ) FC_REFLECT( graphene::chain::nft_set_approval_for_all_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::nft_create_operation, (fee) (owner) (approved_operators) (metadata) ) FC_REFLECT( graphene::chain::nft_create_operation, (fee) (owner) (approved) (approved_operators) (metadata) )
FC_REFLECT( graphene::chain::nft_safe_transfer_from_operation, (fee) (from) (to) (token_id) (data) ) FC_REFLECT( graphene::chain::nft_safe_transfer_from_operation, (fee) (operator_) (from) (to) (token_id) (data) )
FC_REFLECT( graphene::chain::nft_approve_operation, (fee) (owner) (approved) (token_id) ) FC_REFLECT( graphene::chain::nft_approve_operation, (fee) (owner) (approved) (token_id) )
FC_REFLECT( graphene::chain::nft_set_approval_for_all_operation, (fee) (owner) (operator_) (approved) ) FC_REFLECT( graphene::chain::nft_set_approval_for_all_operation, (fee) (owner) (operator_) (approved) )

View file

@ -13,6 +13,7 @@ object_id_type nft_create_evaluator::do_apply( const nft_create_operation& op )
{ try { { try {
const auto& new_nft_object = db().create<nft_object>( [&]( nft_object& obj ){ const auto& new_nft_object = db().create<nft_object>( [&]( nft_object& obj ){
obj.owner = op.owner; obj.owner = op.owner;
obj.approved = op.approved;
obj.approved_operators = op.approved_operators; obj.approved_operators = op.approved_operators;
obj.metadata = op.metadata; obj.metadata = op.metadata;
}); });
@ -28,17 +29,21 @@ void_result nft_safe_transfer_from_evaluator::do_evaluate( const nft_safe_transf
auto itr_nft = idx_nft.find(op.token_id); auto itr_nft = idx_nft.find(op.token_id);
FC_ASSERT( itr_nft != idx_nft.end(), "NFT does not exists" ); FC_ASSERT( itr_nft != idx_nft.end(), "NFT does not exists" );
auto itr_operator = idx_acc.find(op.operator_);
FC_ASSERT( itr_operator != idx_acc.end(), "Operator account does not exists" );
auto itr_owner = idx_acc.find(itr_nft->owner); auto itr_owner = idx_acc.find(itr_nft->owner);
FC_ASSERT( itr_owner != idx_acc.end(), "Owner account does not exists" ); FC_ASSERT( itr_owner != idx_acc.end(), "Owner account does not exists" );
auto itr_from = idx_acc.find(op.from); auto itr_from = idx_acc.find(op.from);
FC_ASSERT( itr_from != idx_acc.end(), "Sender account does not exists" ); FC_ASSERT( itr_from != idx_acc.end(), "Sender account does not exists" );
FC_ASSERT( itr_from->id == itr_owner->id, "Sender account is not owner of this NFT" );
auto itr_to = idx_acc.find(op.to); auto itr_to = idx_acc.find(op.to);
FC_ASSERT( itr_to != idx_acc.end(), "Receiver account does not exists" ); FC_ASSERT( itr_to != idx_acc.end(), "Receiver account does not exists" );
auto itr_approved_op = std::find(itr_nft->approved_operators.begin(), itr_nft->approved_operators.end(), op.from); auto itr_approved_op = std::find(itr_nft->approved_operators.begin(), itr_nft->approved_operators.end(), op.operator_);
FC_ASSERT( (itr_nft->owner == itr_from->id) || (itr_approved_op != itr_nft->approved_operators.end()), "Sender is not NFT owner or approved operator" ); FC_ASSERT( (itr_nft->owner == itr_owner->id) || (itr_nft->approved == itr_operator->id) || (itr_approved_op != itr_nft->approved_operators.end()), "Operator is not NFT owner or approved operator" );
return void_result(); return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) } } FC_CAPTURE_AND_RETHROW( (op) ) }
@ -51,6 +56,7 @@ object_id_type nft_safe_transfer_from_evaluator::do_apply( const nft_safe_transf
{ {
db().modify(*itr, [&op](nft_object &obj) { db().modify(*itr, [&op](nft_object &obj) {
obj.owner = op.to; obj.owner = op.to;
obj.approved = {};
obj.approved_operators.clear(); obj.approved_operators.clear();
}); });
} }
@ -85,10 +91,11 @@ object_id_type nft_approve_evaluator::do_apply( const nft_approve_operation& op
if (itr != idx.end()) if (itr != idx.end())
{ {
db().modify(*itr, [&op](nft_object &obj) { db().modify(*itr, [&op](nft_object &obj) {
auto itr = std::find(obj.approved_operators.begin(), obj.approved_operators.end(), op.approved); obj.approved = op.approved;
if (itr == obj.approved_operators.end()) { //auto itr = std::find(obj.approved_operators.begin(), obj.approved_operators.end(), op.approved);
obj.approved_operators.push_back(op.approved); //if (itr == obj.approved_operators.end()) {
} // obj.approved_operators.push_back(op.approved);
//}
}); });
} }
return op.token_id; return op.token_id;

View file

@ -30,6 +30,7 @@ BOOST_AUTO_TEST_CASE( nft_create_test ) {
nft_create_operation op; nft_create_operation op;
op.owner = alice_id; op.owner = alice_id;
op.approved = alice_id;
op.approved_operators.push_back(operator1_id); op.approved_operators.push_back(operator1_id);
op.approved_operators.push_back(operator2_id); op.approved_operators.push_back(operator2_id);
op.metadata = "metadata"; op.metadata = "metadata";
@ -130,10 +131,10 @@ BOOST_AUTO_TEST_CASE( nft_approve_operation_test ) {
BOOST_REQUIRE( idx.size() == 1 ); BOOST_REQUIRE( idx.size() == 1 );
auto obj = idx.begin(); auto obj = idx.begin();
BOOST_REQUIRE( obj != idx.end() ); BOOST_REQUIRE( obj != idx.end() );
BOOST_CHECK( obj->approved_operators.size() == 3 ); BOOST_CHECK( obj->approved == operator3_id );
BOOST_CHECK( obj->approved_operators.size() == 2 );
BOOST_CHECK( obj->approved_operators.at(0) == operator1_id ); BOOST_CHECK( obj->approved_operators.at(0) == operator1_id );
BOOST_CHECK( obj->approved_operators.at(1) == operator2_id ); BOOST_CHECK( obj->approved_operators.at(1) == operator2_id );
BOOST_CHECK( obj->approved_operators.at(2) == operator3_id );
} }
} }