Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Merge pull request #130 from brianjohnson5972/master
Browse files Browse the repository at this point in the history
Initial Transaction API
  • Loading branch information
nathanielhourt authored Aug 8, 2017
2 parents 867a538 + 809bb82 commit 4a18bde
Show file tree
Hide file tree
Showing 14 changed files with 371 additions and 9 deletions.
1 change: 1 addition & 0 deletions libraries/chain/include/eos/chain/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ namespace eos { namespace chain {
FC_DECLARE_DERIVED_EXCEPTION( tx_missing_scope, eos::chain::transaction_exception, 3030008, "missing required scope" )
FC_DECLARE_DERIVED_EXCEPTION( tx_missing_recipient, eos::chain::transaction_exception, 3030009, "missing required recipient" )
FC_DECLARE_DERIVED_EXCEPTION( checktime_exceeded, eos::chain::transaction_exception, 3030010, "allotted processing time was exceeded" )
FC_DECLARE_DERIVED_EXCEPTION( unknown_transaction_exception, eos::chain::transaction_exception, 3030011, "unknown transaction" )

FC_DECLARE_DERIVED_EXCEPTION( invalid_pts_address, eos::chain::utility_exception, 3060001, "invalid pts address" )
FC_DECLARE_DERIVED_EXCEPTION( insufficient_feeds, eos::chain::chain_exception, 37006, "insufficient feeds" )
Expand Down
2 changes: 2 additions & 0 deletions libraries/chain/include/eos/chain/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ namespace eos { namespace chain {
transaction_object_type,
producer_object_type,
chain_property_object_type,
transaction_history_object_type, ///< Defined by account_history_plugin
balance_object_type, ///< Defined by native_contract library
staked_balance_object_type, ///< Defined by native_contract library
producer_votes_object_type, ///< Defined by native_contract library
Expand Down Expand Up @@ -216,6 +217,7 @@ FC_REFLECT_ENUM(eos::chain::object_type,
(transaction_object_type)
(producer_object_type)
(chain_property_object_type)
(transaction_history_object_type)
(balance_object_type)
(staked_balance_object_type)
(producer_votes_object_type)
Expand Down
2 changes: 1 addition & 1 deletion libraries/chainbase
2 changes: 2 additions & 0 deletions plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ add_subdirectory(database_plugin)
add_subdirectory(chain_plugin)
add_subdirectory(chain_api_plugin)
add_subdirectory(producer_plugin)
add_subdirectory(account_history_plugin)
add_subdirectory(account_history_api_plugin)
16 changes: 16 additions & 0 deletions plugins/account_history_api_plugin/CMakeLists.txt
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" )
48 changes: 48 additions & 0 deletions plugins/account_history_api_plugin/account_history_api_plugin.cpp
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:
};

}
16 changes: 16 additions & 0 deletions plugins/account_history_plugin/CMakeLists.txt
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" )
132 changes: 132 additions & 0 deletions plugins/account_history_plugin/account_history_plugin.cpp
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( [&]() {
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) )
Loading

0 comments on commit 4a18bde

Please sign in to comment.