-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Initial Transaction API #130
Changes from 8 commits
1476206
991165e
65c1ceb
a251af2
3122cab
69f0bb1
4a4026e
91da030
809bb82
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
file(GLOB HEADERS "include/eos/account_history_api_plugin/*.hpp") | ||
add_library( account_history_api_plugin | ||
account_history_api_plugin.cpp | ||
${HEADERS} ) | ||
|
||
target_link_libraries( account_history_api_plugin account_history_plugin chain_plugin http_plugin appbase ) | ||
target_include_directories( account_history_api_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) | ||
|
||
install( TARGETS | ||
account_history_api_plugin | ||
|
||
RUNTIME DESTINATION bin | ||
LIBRARY DESTINATION lib | ||
ARCHIVE DESTINATION lib | ||
) | ||
install( FILES ${HEADERS} DESTINATION "include/eos/account_history_api_plugin" ) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
#include <eos/account_history_api_plugin/account_history_api_plugin.hpp> | ||
#include <eos/chain/chain_controller.hpp> | ||
#include <eos/chain/exceptions.hpp> | ||
|
||
#include <fc/io/json.hpp> | ||
|
||
namespace eos { | ||
|
||
using namespace eos; | ||
|
||
account_history_api_plugin::account_history_api_plugin(){} | ||
account_history_api_plugin::~account_history_api_plugin(){} | ||
|
||
void account_history_api_plugin::set_program_options(options_description&, options_description&) {} | ||
void account_history_api_plugin::plugin_initialize(const variables_map&) {} | ||
|
||
#define CALL(api_name, api_handle, api_namespace, call_name) \ | ||
{std::string("/v1/" #api_name "/" #call_name), \ | ||
[this, api_handle](string, string body, url_response_callback cb) mutable { \ | ||
try { \ | ||
if (body.empty()) body = "{}"; \ | ||
auto result = api_handle.call_name(fc::json::from_string(body).as<api_namespace::call_name ## _params>()); \ | ||
cb(200, fc::json::to_string(result)); \ | ||
} catch (fc::eof_exception) { \ | ||
cb(400, "Invalid arguments"); \ | ||
elog("Unable to parse arguments: ${args}", ("args", body)); \ | ||
} catch (fc::exception& e) { \ | ||
cb(500, e.to_detail_string()); \ | ||
elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \ | ||
} \ | ||
}} | ||
|
||
#define CHAIN_RO_CALL(call_name) CALL(account_history, ro_api, account_history_apis::read_only, call_name) | ||
#define CHAIN_RW_CALL(call_name) CALL(account_history, rw_api, account_history_apis::read_write, call_name) | ||
|
||
void account_history_api_plugin::plugin_startup() { | ||
ilog( "starting account_history_api_plugin" ); | ||
auto ro_api = app().get_plugin<account_history_plugin>().get_read_only_api(); | ||
auto rw_api = app().get_plugin<account_history_plugin>().get_read_write_api(); | ||
|
||
app().get_plugin<http_plugin>().add_api({ | ||
CHAIN_RO_CALL(get_transaction) | ||
}); | ||
} | ||
|
||
void account_history_api_plugin::plugin_shutdown() {} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#pragma once | ||
#include <eos/account_history_plugin/account_history_plugin.hpp> | ||
#include <eos/chain_plugin/chain_plugin.hpp> | ||
#include <eos/http_plugin/http_plugin.hpp> | ||
|
||
#include <appbase/application.hpp> | ||
|
||
namespace eos { | ||
|
||
using namespace appbase; | ||
|
||
class account_history_api_plugin : public plugin<account_history_api_plugin> { | ||
public: | ||
APPBASE_PLUGIN_REQUIRES((account_history_plugin)(chain_plugin)(http_plugin)) | ||
|
||
account_history_api_plugin(); | ||
virtual ~account_history_api_plugin(); | ||
|
||
virtual void set_program_options(options_description&, options_description&) override; | ||
|
||
void plugin_initialize(const variables_map&); | ||
void plugin_startup(); | ||
void plugin_shutdown(); | ||
|
||
private: | ||
}; | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
file(GLOB HEADERS "include/eos/account_history_plugin/*.hpp") | ||
add_library( account_history_plugin | ||
account_history_plugin.cpp | ||
${HEADERS} ) | ||
|
||
target_link_libraries( account_history_plugin chain_plugin eos_chain appbase ) | ||
target_include_directories( account_history_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) | ||
|
||
install( TARGETS | ||
account_history_plugin | ||
|
||
RUNTIME DESTINATION bin | ||
LIBRARY DESTINATION lib | ||
ARCHIVE DESTINATION lib | ||
) | ||
install( FILES ${HEADERS} DESTINATION "include/eos/account_history_plugin" ) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
#include <eos/account_history_plugin/account_history_plugin.hpp> | ||
#include <eos/account_history_plugin/account_history_object.hpp> | ||
#include <eos/chain/chain_controller.hpp> | ||
#include <eos/chain/config.hpp> | ||
#include <eos/chain/exceptions.hpp> | ||
#include <eos/chain/transaction.hpp> | ||
#include <eos/chain/types.hpp> | ||
|
||
#include <fc/crypto/sha256.hpp> | ||
#include <fc/io/json.hpp> | ||
#include <fc/variant.hpp> | ||
|
||
#include <boost/multi_index/hashed_index.hpp> | ||
#include <boost/multi_index/mem_fun.hpp> | ||
#include <eos/chain/multi_index_includes.hpp> | ||
|
||
namespace fc { class variant; } | ||
|
||
namespace eos { | ||
|
||
using chain::block_id_type; | ||
using chain::ProcessedTransaction; | ||
using chain::signed_block; | ||
using boost::multi_index_container; | ||
using chain::transaction_id_type; | ||
using namespace boost::multi_index; | ||
|
||
class account_history_plugin_impl { | ||
public: | ||
ProcessedTransaction get_transaction(const chain::transaction_id_type& transaction_id) const; | ||
void applied_block(const signed_block&); | ||
chain_plugin* chain_plug; | ||
private: | ||
|
||
optional<block_id_type> find_block_id(const transaction_id_type& transaction_id) const; | ||
}; | ||
|
||
optional<block_id_type> account_history_plugin_impl::find_block_id(const transaction_id_type& transaction_id) const | ||
{ | ||
const auto& db = chain_plug->chain().get_database(); | ||
optional<block_id_type> block_id; | ||
db.with_read_lock( [&]() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does not compile:
db is a const ref, but There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe I "fixed" that (Otherwise Travis would complain). see commit d48ebab. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Were you able to get it to work, or is there an issue with my commit? I had a heck of a time getting the submodule commit correct, so it would not be a big shocker if it really didn't work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, just an old submodule. Oops :] |
||
const auto& trx_idx = db.get_index<transaction_history_multi_index, by_trx_id>(); | ||
auto transaction_history = trx_idx.find( transaction_id ); | ||
if (transaction_history != trx_idx.end()) | ||
block_id = transaction_history->block_id; | ||
} ); | ||
return block_id; | ||
} | ||
|
||
ProcessedTransaction account_history_plugin_impl::get_transaction(const chain::transaction_id_type& transaction_id) const | ||
{ | ||
auto block_id = find_block_id(transaction_id); | ||
if( block_id.valid() ) | ||
{ | ||
auto block = chain_plug->chain().fetch_block_by_id(*block_id); | ||
if (block.valid()) | ||
{ | ||
for (const auto& cycle : block->cycles) | ||
for (const auto& thread : cycle) | ||
for (const auto& trx : thread.user_input) | ||
if (trx.id() == transaction_id) | ||
return trx; | ||
} | ||
|
||
// ERROR in indexing logic | ||
FC_ASSERT(block, "Transaction with ID ${tid} was indexed as being in block ID ${bid}, but no such block was found", ("tid", transaction_id)("bid", block_id)); | ||
FC_THROW("Transaction with ID ${tid} was indexed as being in block ID ${bid}, but was not found in that block", ("tid", transaction_id)("bid", block_id)); | ||
} | ||
|
||
#warning TODO: lookup of recent transactions | ||
FC_THROW_EXCEPTION(chain::unknown_transaction_exception, | ||
"Could not find transaction for: ${id}", ("id", transaction_id.str())); | ||
} | ||
|
||
void account_history_plugin_impl::applied_block(const signed_block& block) | ||
{ | ||
const auto block_id = block.id(); | ||
auto& db = chain_plug->chain().get_mutable_database(); | ||
for (const auto& cycle : block.cycles) | ||
for (const auto& thread : cycle) | ||
for (const auto& trx : thread.user_input) { | ||
db.create<transaction_history_object>([&block_id,&trx](transaction_history_object& transaction_history) { | ||
transaction_history.block_id = block_id; | ||
transaction_history.transaction_id = trx.id(); | ||
}); | ||
} | ||
} | ||
|
||
|
||
account_history_plugin::account_history_plugin() | ||
:my(new account_history_plugin_impl()) | ||
{ | ||
} | ||
|
||
account_history_plugin::~account_history_plugin() | ||
{ | ||
} | ||
|
||
void account_history_plugin::set_program_options(options_description& cli, options_description& cfg) | ||
{ | ||
} | ||
|
||
void account_history_plugin::plugin_initialize(const variables_map& options) | ||
{ | ||
} | ||
|
||
void account_history_plugin::plugin_startup() | ||
{ | ||
my->chain_plug = app().find_plugin<chain_plugin>(); | ||
auto& db = my->chain_plug->chain().get_mutable_database(); | ||
db.add_index<transaction_history_multi_index>(); | ||
|
||
my->chain_plug->chain().applied_block.connect ([&impl = my](const signed_block& block) { | ||
impl->applied_block(block); | ||
}); | ||
} | ||
|
||
void account_history_plugin::plugin_shutdown() | ||
{ | ||
} | ||
|
||
namespace account_history_apis { | ||
|
||
read_only::get_transaction_results read_only::get_transaction(const read_only::get_transaction_params& params) const | ||
{ | ||
auto trx = account_history->get_transaction(params.transaction_id); | ||
return { account_history->chain_plug->chain().transaction_to_variant(trx) }; | ||
} | ||
|
||
} // namespace account_history_apis | ||
} // namespace eos |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#pragma once | ||
|
||
#include <chainbase/chainbase.hpp> | ||
|
||
namespace eos { | ||
using chain::block_id_type; | ||
using chain::transaction_id_type; | ||
using namespace boost::multi_index; | ||
|
||
class transaction_history_object : public chainbase::object<chain::transaction_history_object_type, transaction_history_object> { | ||
OBJECT_CTOR(transaction_history_object) | ||
|
||
id_type id; | ||
block_id_type block_id; | ||
transaction_id_type transaction_id; | ||
}; | ||
|
||
struct by_id; | ||
struct by_trx_id; | ||
using transaction_history_multi_index = chainbase::shared_multi_index_container< | ||
transaction_history_object, | ||
indexed_by< | ||
ordered_unique<tag<by_id>, BOOST_MULTI_INDEX_MEMBER(transaction_history_object, transaction_history_object::id_type, id)>, | ||
hashed_unique<tag<by_trx_id>, BOOST_MULTI_INDEX_MEMBER(transaction_history_object, transaction_id_type, transaction_id), std::hash<transaction_id_type>> | ||
> | ||
>; | ||
|
||
typedef chainbase::generic_index<transaction_history_multi_index> transaction_history_index; | ||
|
||
} | ||
|
||
CHAINBASE_SET_INDEX_TYPE( eos::transaction_history_object, eos::transaction_history_multi_index ) | ||
|
||
FC_REFLECT( eos::transaction_history_object, (block_id)(transaction_id) ) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
#pragma once | ||
#include <appbase/application.hpp> | ||
|
||
#include <eos/chain_plugin/chain_plugin.hpp> | ||
|
||
namespace fc { class variant; } | ||
|
||
namespace eos { | ||
using chain::transaction_id_type; | ||
using std::shared_ptr; | ||
using namespace appbase; | ||
using chain::Name; | ||
using fc::optional; | ||
using chain::uint128_t; | ||
|
||
typedef shared_ptr<class account_history_plugin_impl> account_history_ptr; | ||
typedef shared_ptr<const class account_history_plugin_impl> account_history_const_ptr; | ||
|
||
namespace account_history_apis { | ||
struct empty{}; | ||
|
||
class read_only { | ||
account_history_const_ptr account_history; | ||
|
||
public: | ||
read_only(account_history_const_ptr&& account_history) | ||
: account_history(account_history) {} | ||
|
||
struct get_transaction_params { | ||
chain::transaction_id_type transaction_id; | ||
}; | ||
struct get_transaction_results { | ||
fc::variant transaction; | ||
}; | ||
|
||
get_transaction_results get_transaction(const get_transaction_params& params) const; | ||
|
||
}; | ||
|
||
class read_write { | ||
account_history_ptr account_history; | ||
|
||
public: | ||
read_write(account_history_ptr account_history) : account_history(account_history) {} | ||
}; | ||
} // namespace account_history_apis | ||
|
||
class account_history_plugin : public plugin<account_history_plugin> { | ||
public: | ||
APPBASE_PLUGIN_REQUIRES((chain_plugin)) | ||
|
||
account_history_plugin(); | ||
virtual ~account_history_plugin(); | ||
|
||
virtual void set_program_options(options_description& cli, options_description& cfg) override; | ||
|
||
void plugin_initialize(const variables_map& options); | ||
void plugin_startup(); | ||
void plugin_shutdown(); | ||
|
||
account_history_apis::read_only get_read_only_api() const { return account_history_apis::read_only(account_history_const_ptr(my)); } | ||
account_history_apis::read_write get_read_write_api() { return account_history_apis::read_write(my); } | ||
|
||
private: | ||
account_history_ptr my; | ||
}; | ||
|
||
} | ||
|
||
FC_REFLECT(eos::account_history_apis::empty, ) | ||
FC_REFLECT(eos::account_history_apis::read_only::get_transaction_params, (transaction_id) ) | ||
FC_REFLECT(eos::account_history_apis::read_only::get_transaction_results, (transaction) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I apologize, I have been unclear. This comment claims the object is defined by a plugin library, but it's not a library, it's a plugin. The purpose of the comment is to make it easier to find the object without an IDE tracking references of
transaction_history_object_type
, so if it says "library" and "plugin", it's not obvious whether to look in theplugins
orlibraries
directory. This comes from a plugin, so it should only say plugin and not library.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No I apologize for not paying as close of attention to your original comment.