Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.2] Add snapshot test and refactor pending_snapshot #628

Merged
merged 1 commit into from
Jul 11, 2022
Merged
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
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()