Skip to content
This repository was archived by the owner on Aug 2, 2022. It is now read-only.
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
3 changes: 1 addition & 2 deletions libraries/chain/include/eosio/chain/account_object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,4 @@ namespace eosio { namespace chain {
CHAINBASE_SET_INDEX_TYPE(eosio::chain::account_object, eosio::chain::account_index)
CHAINBASE_SET_INDEX_TYPE(eosio::chain::account_sequence_object, eosio::chain::account_sequence_index)


FC_REFLECT(eosio::chain::account_object, (name)(vm_type)(vm_version)(code_version)(code)(creation_date))
FC_REFLECT(eosio::chain::account_object, (name)(vm_type)(vm_version)(privileged)(last_code_update)(code_version)(creation_date)(code)(abi))
Original file line number Diff line number Diff line change
Expand Up @@ -216,5 +216,8 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::index256_object, eosio::chain::index256_i
CHAINBASE_SET_INDEX_TYPE(eosio::chain::index_double_object, eosio::chain::index_double_index)
CHAINBASE_SET_INDEX_TYPE(eosio::chain::index_long_double_object, eosio::chain::index_long_double_index)

FC_REFLECT(eosio::chain::table_id_object, (id)(code)(scope)(table) )
FC_REFLECT(chainbase::oid<eosio::chain::table_id_object>, (_id))
FC_REFLECT(eosio::chain::table_id_object, (id)(code)(scope)(table)(payer)(count) )

FC_REFLECT(chainbase::oid<eosio::chain::key_value_object>, (_id))
FC_REFLECT(eosio::chain::key_value_object, (id)(t_id)(primary_key)(value)(payer) )
1 change: 1 addition & 0 deletions plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ add_subdirectory(db_size_api_plugin)
#add_subdirectory(faucet_testnet_plugin)
#add_subdirectory(mongo_db_plugin)
#add_subdirectory(sql_db_plugin)
add_subdirectory(snapshot_plugin)

# Forward variables to top level so packaging picks them up
set(CPACK_DEBIAN_PACKAGE_DEPENDS ${CPACK_DEBIAN_PACKAGE_DEPENDS} PARENT_SCOPE)
7 changes: 7 additions & 0 deletions plugins/snapshot_plugin/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
file(GLOB HEADERS "include/eosio/snapshot_plugin/*.hpp")
add_library( snapshot_plugin
snapshot_plugin.cpp
${HEADERS} )

target_link_libraries( snapshot_plugin appbase fc chain_plugin)
target_include_directories( snapshot_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <appbase/application.hpp>

#include <eosio/chain_plugin/chain_plugin.hpp>
#include <boost/signals2/connection.hpp>

namespace eosio {

using namespace appbase;

class snapshot_plugin : public appbase::plugin<snapshot_plugin> {
public:
snapshot_plugin();
virtual ~snapshot_plugin();

APPBASE_PLUGIN_REQUIRES((chain_plugin))
virtual void set_program_options(options_description&, options_description& cfg) override;

void plugin_initialize(const variables_map& options);
void plugin_startup();
void plugin_shutdown();

/**
* snapshot_version must be changed anytime there is a change
* on any of the following types:
* - eosio::types::chain_id_type
* - eosio::chain::genesis_state
* - eosio::chain::block_header_state
* - eosio::chain::account_object
* - eosio::chain::permission_object
* - eosio::chain::table_id_object
* - eosio::chain::key_value_object
*/
uint16_t snapshot_version = 0x0001;

private:
std::unique_ptr<class snapshot_plugin_impl> my;
fc::optional<boost::signals2::scoped_connection> m_irreversible_block_connection;
fc::optional<boost::signals2::scoped_connection> m_accepted_block_connection;
};

}
158 changes: 158 additions & 0 deletions plugins/snapshot_plugin/snapshot_plugin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosio/chain/asset.hpp>
#include <eosio/chain/account_object.hpp>
#include <eosio/chain/permission_object.hpp>
#include <eosio/chain/block_log.hpp>
#include <eosio/snapshot_plugin/snapshot_plugin.hpp>
#include <fc/io/raw.hpp>
#include <fc/io/json.hpp>
#include <fc/crypto/hex.hpp>
#include <fc/optional.hpp>
#include <fc/reflect/reflect.hpp>

using namespace eosio;
using namespace eosio::chain;
using namespace chainbase;
using namespace fc;
using namespace std;

struct permission {
struct name perm_name;
struct name parent;
authority required_auth;
};
FC_REFLECT( permission, (perm_name)(parent)(required_auth) )

template<typename Function>
void iterate_all_tables(const database& db, Function f)
{
const auto &idx = db.get_index<table_id_multi_index, by_code_scope_table>();
auto lower = idx.begin();
auto upper = idx.end();

for (auto itr = lower; itr != upper; ++itr) {
f(*itr);
}
}

template<typename Function>
void iterate_all_rows(const database& db, const table_id_object& t_id, Function f)
{
const auto &idx = db.get_index<key_value_index, by_scope_primary>();
decltype(t_id.id) next_tid(t_id.id._id + 1);
auto lower = idx.lower_bound(boost::make_tuple(t_id.id));
auto upper = idx.lower_bound(boost::make_tuple(next_tid));

for (auto itr = lower; itr != upper; ++itr) {
f(*itr);
}
}

namespace eosio {
static appbase::abstract_plugin& _snapshot_plugin = app().register_plugin<snapshot_plugin>();

class snapshot_plugin_impl {
public:
};

snapshot_plugin::snapshot_plugin():my(new snapshot_plugin_impl()){}
snapshot_plugin::~snapshot_plugin(){}

void snapshot_plugin::set_program_options(options_description&, options_description& cfg) {
cfg.add_options()
("snapshot-at-block", bpo::value<string>()->default_value(""), "Block hash at which to take the snapshot")
("snapshot-to", bpo::value<string>()->default_value("snapshot.json"), "Pathname of JSON file where to store the snapshot")
;
}

void snapshot_plugin::plugin_initialize(const variables_map& options) {

auto snapshot_at_block = fc::json::from_string(options.at("snapshot-at-block").as<string>()).as<block_id_type>();
auto snapshot_to = options.at("snapshot-to").as<string>();

if( snapshot_at_block != block_id_type() ) {

chain_plugin* chain_plug = app().find_plugin<chain_plugin>();
FC_ASSERT(chain_plug);
auto& chain = chain_plug->chain();
auto& db = chain.db();
const auto& config = chain_plug->chain_config();

// Take snapshot after block is applied
m_accepted_block_connection.emplace(chain.accepted_block.connect([this, snapshot_at_block, snapshot_to, &db, &config, &chain](const chain::block_state_ptr& b) {

if( b->id == snapshot_at_block ) {

ilog("Taking snapshot at block ${n} (${h})...",("h",snapshot_at_block)("n",b->block_num));

std::ofstream out;
try {
out.open(snapshot_to);
fc::raw::pack(out, snapshot_version);
fc::raw::pack(out, chain.get_chain_id());
fc::raw::pack(out, config.genesis);
fc::raw::pack(out, static_cast<block_header_state>(*b));

const auto& account_idx = db.get_index<account_index, by_name>();
uint32_t total_accounts = std::distance(account_idx.begin(), account_idx.end());
fc::raw::pack(out, total_accounts);
for (auto accnt = account_idx.begin(); accnt != account_idx.end(); ++accnt) {
fc::raw::pack(out, *accnt);
}

const auto& permissions_idx = db.get_index<permission_index,by_owner>();
uint32_t total_perms = std::distance(permissions_idx.begin(), permissions_idx.end());
fc::raw::pack(out, total_perms);
for (auto perm = permissions_idx.begin(); perm != permissions_idx.end(); ++perm) {
fc::raw::pack(out, *perm);
}

const auto &table_idx = db.get_index<table_id_multi_index, by_code_scope_table>();
uint32_t total_tables = std::distance(table_idx.begin(), table_idx.end());
fc::raw::pack(out, total_tables);
iterate_all_tables(db, [&](const table_id_object& t_id) {

uint32_t cnt = 0;
iterate_all_rows(db, t_id, [&cnt](const key_value_object& row) { cnt++; });

fc::raw::pack(out, t_id.id);
fc::raw::pack(out, t_id.code);
fc::raw::pack(out, t_id.scope);
fc::raw::pack(out, t_id.table);
fc::raw::pack(out, t_id.payer);
fc::raw::pack(out, cnt);

//fc::raw::pack(out, t_id);
//t_id.count = cnt;

iterate_all_rows(db, t_id, [&](const key_value_object& row) {
fc::raw::pack(out, row);
});
});

out.flush();
out.close();
ilog( "Snapshot saved in ${s}",("s",snapshot_to));
} catch ( ... ) {
try { fc::remove( snapshot_to); } catch (...) {}
wlog( "Failed to take snapshot");
return;
}
}

}));
}
}

void snapshot_plugin::plugin_startup() {
// Make the magic happen
}

void snapshot_plugin::plugin_shutdown() {
// OK, that's enough magic
}

}
1 change: 1 addition & 0 deletions programs/nodeos/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ target_link_libraries( nodeos
PRIVATE -Wl,${whole_archive_flag} txn_test_gen_plugin -Wl,${no_whole_archive_flag}
PRIVATE -Wl,${whole_archive_flag} db_size_api_plugin -Wl,${no_whole_archive_flag}
PRIVATE -Wl,${whole_archive_flag} producer_api_plugin -Wl,${no_whole_archive_flag}
PRIVATE -Wl,${whole_archive_flag} snapshot_plugin -Wl,${no_whole_archive_flag}
PRIVATE chain_plugin http_plugin producer_plugin http_client_plugin
PRIVATE eosio_chain fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} )

Expand Down
11 changes: 11 additions & 0 deletions tools/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,14 @@ install( FILES ${CMAKE_CURRENT_BINARY_DIR}/eosiocpp DESTINATION ${CMAKE_INSTALL_
add_executable( print_floats print_floats.cpp )
target_include_directories( print_floats PRIVATE ${Boost_INCLUDE_DIR} )
target_link_libraries( print_floats PRIVATE ${Boost_LIBRARIES} )

add_executable( snap2json snap2json.cpp )
target_include_directories( snap2json PRIVATE ${Boost_INCLUDE_DIR} )
target_link_libraries( snap2json PRIVATE eosio_chain fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} )

install( TARGETS
snap2json
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
)
Loading