Skip to content

Commit

Permalink
Merge pull request #628 from eosnetworkfoundation/GH-434-snapshot
Browse files Browse the repository at this point in the history
[3.2] Add snapshot test and refactor pending_snapshot
  • Loading branch information
heifner authored Jul 11, 2022
2 parents 19f1874 + 40e903c commit 82d217f
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 56 deletions.
2 changes: 1 addition & 1 deletion plugins/producer_plugin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ file(GLOB HEADERS "include/eosio/producer_plugin/*.hpp")

add_library( producer_plugin
producer_plugin.cpp
pending_snapshot.cpp
${HEADERS}
)

Expand All @@ -10,4 +11,3 @@ target_include_directories( producer_plugin
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../chain_interface/include" )

add_subdirectory( test )

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once

#include <eosio/producer_plugin/producer_plugin.hpp>

namespace eosio {

class pending_snapshot {
public:
using next_t = producer_plugin::next_function<producer_plugin::snapshot_information>;

pending_snapshot(const chain::block_id_type& block_id, next_t& next, std::string pending_path, std::string final_path)
: block_id(block_id)
, next(next)
, pending_path(pending_path)
, final_path(final_path)
{}

uint32_t get_height() const {
return chain::block_header::num_from_id(block_id);
}

static bfs::path get_final_path(const chain::block_id_type& block_id, const bfs::path& snapshots_dir) {
return snapshots_dir / fc::format_string("snapshot-${id}.bin", fc::mutable_variant_object()("id", block_id));
}

static bfs::path get_pending_path(const chain::block_id_type& block_id, const bfs::path& snapshots_dir) {
return snapshots_dir / fc::format_string(".pending-snapshot-${id}.bin", fc::mutable_variant_object()("id", block_id));
}

static bfs::path get_temp_path(const chain::block_id_type& block_id, const bfs::path& snapshots_dir) {
return snapshots_dir / fc::format_string(".incomplete-snapshot-${id}.bin", fc::mutable_variant_object()("id", block_id));
}

producer_plugin::snapshot_information finalize( const chain::controller& chain ) const;

chain::block_id_type block_id;
next_t next;
std::string pending_path;
std::string final_path;
};

} // namespace eosio
28 changes: 28 additions & 0 deletions plugins/producer_plugin/pending_snapshot.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <eosio/producer_plugin/pending_snapshot.hpp>
#include <eosio/chain/exceptions.hpp>

namespace eosio {

producer_plugin::snapshot_information pending_snapshot::finalize( const chain::controller& chain ) const {
auto block_ptr = chain.fetch_block_by_id( block_id );
auto in_chain = (bool)block_ptr;
boost::system::error_code ec;

if (!in_chain) {
bfs::remove(bfs::path(pending_path), ec);
EOS_THROW(chain::snapshot_finalization_exception,
"Snapshotted block was forked out of the chain. ID: ${block_id}",
("block_id", block_id));
}

bfs::rename(bfs::path(pending_path), bfs::path(final_path), ec);
EOS_ASSERT(!ec, chain::snapshot_finalization_exception,
"Unable to finalize valid snapshot of block number ${bn}: [code: ${ec}] ${message}",
("bn", get_height())
("ec", ec.value())
("message", ec.message()));

return {block_id, block_ptr->block_num(), block_ptr->timestamp, chain::chain_snapshot_header::current_version, final_path};
}

} // namespace eosio
56 changes: 1 addition & 55 deletions plugins/producer_plugin/producer_plugin.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <eosio/producer_plugin/producer_plugin.hpp>
#include <eosio/producer_plugin/pending_snapshot.hpp>
#include <eosio/producer_plugin/subjective_billing.hpp>
#include <eosio/chain/plugin_interface.hpp>
#include <eosio/chain/global_property_object.hpp>
Expand Down Expand Up @@ -116,61 +117,6 @@ using transaction_id_with_expiry_index = multi_index_container<

struct by_height;

class pending_snapshot {
public:
using next_t = producer_plugin::next_function<producer_plugin::snapshot_information>;

pending_snapshot(const block_id_type& block_id, next_t& next, std::string pending_path, std::string final_path)
: block_id(block_id)
, next(next)
, pending_path(pending_path)
, final_path(final_path)
{}

uint32_t get_height() const {
return block_header::num_from_id(block_id);
}

static bfs::path get_final_path(const block_id_type& block_id, const bfs::path& snapshots_dir) {
return snapshots_dir / fc::format_string("snapshot-${id}.bin", fc::mutable_variant_object()("id", block_id));
}

static bfs::path get_pending_path(const block_id_type& block_id, const bfs::path& snapshots_dir) {
return snapshots_dir / fc::format_string(".pending-snapshot-${id}.bin", fc::mutable_variant_object()("id", block_id));
}

static bfs::path get_temp_path(const block_id_type& block_id, const bfs::path& snapshots_dir) {
return snapshots_dir / fc::format_string(".incomplete-snapshot-${id}.bin", fc::mutable_variant_object()("id", block_id));
}

producer_plugin::snapshot_information finalize( const chain::controller& chain ) const {
auto block_ptr = chain.fetch_block_by_id( block_id );
auto in_chain = (bool)block_ptr;
boost::system::error_code ec;

if (!in_chain) {
bfs::remove(bfs::path(pending_path), ec);
EOS_THROW(snapshot_finalization_exception,
"Snapshotted block was forked out of the chain. ID: ${block_id}",
("block_id", block_id));
}

bfs::rename(bfs::path(pending_path), bfs::path(final_path), ec);
EOS_ASSERT(!ec, snapshot_finalization_exception,
"Unable to finalize valid snapshot of block number ${bn}: [code: ${ec}] ${message}",
("bn", get_height())
("ec", ec.value())
("message", ec.message()));

return {block_id, block_ptr->block_num(), block_ptr->timestamp, chain_snapshot_header::current_version, final_path};
}

block_id_type block_id;
next_t next;
std::string pending_path;
std::string final_path;
};

using pending_snapshot_index = multi_index_container<
pending_snapshot,
indexed_by<
Expand Down
5 changes: 5 additions & 0 deletions plugins/producer_plugin/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ add_executable( test_trx_full test_trx_full.cpp )
target_link_libraries( test_trx_full producer_plugin eosio_testing )

add_test(NAME test_trx_full COMMAND plugins/producer_plugin/test/test_trx_full WORKING_DIRECTORY ${CMAKE_BINARY_DIR})

add_executable( test_snapshot_information test_snapshot_information.cpp )
target_link_libraries( test_snapshot_information producer_plugin eosio_testing )

add_test(NAME test_snapshot_information COMMAND plugins/producer_plugin/test/test_snapshot_information WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
71 changes: 71 additions & 0 deletions plugins/producer_plugin/test/test_snapshot_information.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#define BOOST_TEST_MODULE snapshot_information
#include <boost/test/included/unit_test.hpp>

#include <fc/variant_object.hpp>

#include <eosio/chain/snapshot.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/testing/snapshot_suites.hpp>
#include <eosio/producer_plugin/producer_plugin.hpp>
#include <eosio/producer_plugin/pending_snapshot.hpp>
#include <contracts.hpp>
#include <snapshots.hpp>

using namespace eosio;
using namespace eosio::testing;
using namespace boost::system;

namespace {
eosio::producer_plugin::snapshot_information test_snap_info;
}

BOOST_AUTO_TEST_SUITE(snapshot_tests)

using next_t = eosio::producer_plugin::next_function<eosio::producer_plugin::snapshot_information>;

BOOST_AUTO_TEST_CASE_TEMPLATE(test_snapshot_information, SNAPSHOT_SUITE, snapshot_suites) {
tester chain;
const chainbase::bfs::path parent_path = chain.get_config().blocks_dir.parent_path();

chain.create_account("snapshot"_n);
chain.produce_blocks(1);
chain.set_code("snapshot"_n, contracts::snapshot_test_wasm());
chain.set_abi("snapshot"_n, contracts::snapshot_test_abi().data());
chain.produce_blocks(1);

auto block = chain.produce_block();
BOOST_REQUIRE_EQUAL(block->block_num(), 6); // ensure that test setup stays consistent with original snapshot setup
// undo the auto-pending from tester
chain.control->abort_block();

auto block2 = chain.produce_block();
BOOST_REQUIRE_EQUAL(block2->block_num(), 7); // ensure that test setup stays consistent with original snapshot setup
// undo the auto-pending from tester
chain.control->abort_block();

// write snapshot
auto write_snapshot = [&]( const bfs::path& p ) -> void {
if ( !bfs::exists( p.parent_path() ) )
bfs::create_directory( p.parent_path() );

// create the snapshot
auto snap_out = std::ofstream(p.generic_string(), (std::ios::out | std::ios::binary));
auto writer = std::make_shared<ostream_snapshot_writer>(snap_out);
(*chain.control).write_snapshot(writer);
writer->finalize();
snap_out.flush();
snap_out.close();
};

auto final_path = eosio::pending_snapshot::get_final_path(block2->previous, "../snapshots/");
auto pending_path = eosio::pending_snapshot::get_pending_path(block2->previous, "../snapshots/");

write_snapshot( pending_path );
next_t next;
eosio::pending_snapshot pending{ block2->previous, next, pending_path.generic_string(), final_path.generic_string() };
test_snap_info = pending.finalize(*chain.control);
BOOST_REQUIRE_EQUAL(test_snap_info.head_block_num, 6);
BOOST_REQUIRE_EQUAL(test_snap_info.version, chain_snapshot_header::current_version);
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit 82d217f

Please sign in to comment.