From fb51a455e75ade51385e00995ca7779e99930bfa Mon Sep 17 00:00:00 2001 From: Victor Camacho Date: Wed, 19 Aug 2020 18:46:32 -0400 Subject: [PATCH 1/7] GH-597 Merge pull request #9253 from EOSIO/feature/ship-unit-tests - WIP Additional ShIP unit tests --- unittests/CMakeLists.txt | 2 +- unittests/state_history_tests.cpp | 822 ++++++++++++++++++++++++++++++ 2 files changed, 823 insertions(+), 1 deletion(-) create mode 100644 unittests/state_history_tests.cpp diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 6d64ceec97..8462ce1780 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -39,7 +39,7 @@ add_custom_command( file(GLOB UNIT_TESTS "*.cpp") # find all unit test suites add_executable( unit_test ${UNIT_TESTS} protocol_feature_digest_tests.cpp) # build unit tests as one executable -target_link_libraries( unit_test eosio_chain_wrap chainbase eosio_testing fc appbase ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( unit_test eosio_chain_wrap state_history chainbase eosio_testing fc appbase ${PLATFORM_SPECIFIC_LIBS} ) target_compile_options(unit_test PUBLIC -DDISABLE_EOSLIB_SERIALIZE) target_include_directories( unit_test PUBLIC diff --git a/unittests/state_history_tests.cpp b/unittests/state_history_tests.cpp new file mode 100644 index 0000000000..977dab6770 --- /dev/null +++ b/unittests/state_history_tests.cpp @@ -0,0 +1,822 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_cfd_transaction.hpp" +#include + +#pragma push_macro("N") +#undef N +#include +#include +#pragma pop_macro("N") + +using namespace eosio; +using namespace testing; +using namespace chain; +using namespace std::literals; + +extern const char* const state_history_plugin_abi; + +struct state_history_config { + chainbase::bfs::path log_dir; + chainbase::bfs::path retained_dir; + chainbase::bfs::path archive_dir; + uint32_t stride = UINT32_MAX; + uint32_t max_retained_files = 10; +}; + +struct state_history_abi_serializer { + tester& chain; + abi_serializer sr; + + state_history_abi_serializer(tester& chn) + : chain(chn) + , sr(fc::json::from_string(state_history_plugin_abi).as(), + abi_serializer::create_yield_function(chain.abi_serializer_max_time)) {} + + fc::variant deserialize(const chain::bytes& data, const char* type) { + fc::datastream strm(data.data(), data.size()); + auto result = + sr.binary_to_variant(type, strm, abi_serializer::create_yield_function(chain.abi_serializer_max_time)); + BOOST_CHECK(data.size() == strm.tellp()); + return result; + } +}; + +BOOST_AUTO_TEST_SUITE(test_state_history) + +BOOST_AUTO_TEST_CASE(test_trace_converter) { + + tester chain; + using namespace eosio::state_history; + + state_history::trace_converter converter; + std::map on_disk_log_entries; + + chain.control->applied_transaction.connect( + [&](std::tuple t) { + converter.add_transaction(std::get<0>(t), std::get<1>(t)); + }); + + chain.control->accepted_block.connect([&](const block_state_ptr& bs) { + converter.pack(chain.control->db(), true, bs); + }); + + chain.control->block_start.connect([&](uint32_t block_num) { + }); + + deploy_test_api(chain); + auto cfd_trace = push_test_cfd_transaction(chain); + chain.produce_blocks(1); + + BOOST_CHECK(on_disk_log_entries.size()); + + // Now deserialize the on disk trace log and make sure that the cfd exists + auto& cfd_entry = on_disk_log_entries.at(cfd_trace->block_num); + BOOST_REQUIRE(!get_prunable_data_from_traces_bin(cfd_entry, cfd_trace->id).contains()); + + // prune the cfd for the block + std::vector ids{cfd_trace->id}; + fc::datastream rw_strm(cfd_entry.data(), cfd_entry.size()); + state_history::trace_converter::prune_traces(rw_strm, cfd_entry.size(), ids); + BOOST_CHECK(ids.size() == 0); + + // read the pruned trace and make sure it's pruned + BOOST_CHECK(get_prunable_data_from_traces_bin(cfd_entry, cfd_trace->id).contains()); +} + +BOOST_AUTO_TEST_CASE(test_trace_log) { + namespace bfs = boost::filesystem; + tester chain; + + scoped_temp_path state_history_dir; + fc::create_directories(state_history_dir.path); + state_history_traces_log log({ .log_dir = state_history_dir.path }); + + chain.control->applied_transaction.connect( + [&](std::tuple t) { + log.add_transaction(std::get<0>(t), std::get<1>(t)); + }); + + chain.control->accepted_block.connect([&](const block_state_ptr& bs) { log.store(chain.control->db(), bs); }); + chain.control->block_start.connect([&](uint32_t block_num) { log.block_start(block_num); } ); + + deploy_test_api(chain); + auto cfd_trace = push_test_cfd_transaction(chain); + chain.produce_blocks(1); + + auto traces = log.get_traces(cfd_trace->block_num); + BOOST_REQUIRE(traces.size()); + + BOOST_REQUIRE(!get_prunable_data_from_traces(traces, cfd_trace->id).contains()); + + std::vector ids{cfd_trace->id}; + log.prune_transactions(cfd_trace->block_num, ids); + BOOST_REQUIRE(ids.empty()); + + // we assume the nodeos has to be stopped while running, it can only be read + // correctly with restart + state_history_traces_log new_log({ .log_dir = state_history_dir.path }); + auto pruned_traces = new_log.get_traces(cfd_trace->block_num); + BOOST_REQUIRE(pruned_traces.size()); + + BOOST_CHECK(get_prunable_data_from_traces(pruned_traces, cfd_trace->id).contains()); +} + +BOOST_AUTO_TEST_CASE(test_chain_state_log) { + + namespace bfs = boost::filesystem; + tester chain; + + scoped_temp_path state_history_dir; + fc::create_directories(state_history_dir.path); + state_history_chain_state_log log({ .log_dir = state_history_dir.path }); + + uint32_t last_accepted_block_num = 0; + + chain.control->accepted_block.connect([&](const block_state_ptr& block_state) { + log.store(chain.control->db(), block_state); + last_accepted_block_num = block_state->block_num; + }); + + chain.produce_blocks(10); + + chain::bytes entry = log.get_log_entry(last_accepted_block_num); + std::vector deltas; + eosio::input_stream deltas_bin{entry.data(), entry.data() + entry.size()}; + BOOST_CHECK_NO_THROW(from_bin(deltas, deltas_bin)); +} + + +struct state_history_tester_logs { + state_history_tester_logs(const state_history_config& config) + : traces_log(config) , chain_state_log(config) {} + + state_history_traces_log traces_log; + state_history_chain_state_log chain_state_log; +}; + +struct state_history_tester : state_history_tester_logs, tester { + state_history_tester(const state_history_config& config) + : state_history_tester_logs(config), tester ([&](eosio::chain::controller& control) { + control.applied_transaction.connect( + [&](std::tuple t) { + traces_log.add_transaction(std::get<0>(t), std::get<1>(t)); + }); + + control.accepted_block.connect([&](const block_state_ptr& bs) { + traces_log.store(control.db(), bs); + chain_state_log.store(control.db(), bs); + }); + control.block_start.connect([&](uint32_t block_num) { traces_log.block_start(block_num); } ); + }) {} +}; + + +BOOST_AUTO_TEST_CASE(test_splitted_log) { + namespace bfs = boost::filesystem; + + scoped_temp_path state_history_dir; + fc::create_directories(state_history_dir.path); + + state_history_config config{ + .log_dir = state_history_dir.path, + .retained_dir = "retained", + .archive_dir = "archive", + .stride = 20, + .max_retained_files = 5 + }; + + state_history_tester chain(config); + chain.produce_blocks(50); + + deploy_test_api(chain); + auto cfd_trace = push_test_cfd_transaction(chain); + + chain.produce_blocks(100); + + + auto log_dir = state_history_dir.path; + auto archive_dir = log_dir / "archive"; + auto retained_dir = log_dir / "retained"; + + BOOST_CHECK(bfs::exists( archive_dir / "trace_history-2-20.log" )); + BOOST_CHECK(bfs::exists( archive_dir / "trace_history-2-20.index" )); + BOOST_CHECK(bfs::exists( archive_dir / "trace_history-21-40.log" )); + BOOST_CHECK(bfs::exists( archive_dir / "trace_history-21-40.index" )); + + BOOST_CHECK(bfs::exists( archive_dir / "chain_state_history-2-20.log" )); + BOOST_CHECK(bfs::exists( archive_dir / "chain_state_history-2-20.index" )); + BOOST_CHECK(bfs::exists( archive_dir / "chain_state_history-21-40.log" )); + BOOST_CHECK(bfs::exists( archive_dir / "chain_state_history-21-40.index" )); + + BOOST_CHECK(bfs::exists( retained_dir / "trace_history-41-60.log" )); + BOOST_CHECK(bfs::exists( retained_dir / "trace_history-41-60.index" )); + BOOST_CHECK(bfs::exists( retained_dir / "trace_history-61-80.log" )); + BOOST_CHECK(bfs::exists( retained_dir / "trace_history-61-80.index" )); + BOOST_CHECK(bfs::exists( retained_dir / "trace_history-81-100.log" )); + BOOST_CHECK(bfs::exists( retained_dir / "trace_history-81-100.index" )); + BOOST_CHECK(bfs::exists( retained_dir / "trace_history-101-120.log" )); + BOOST_CHECK(bfs::exists( retained_dir / "trace_history-101-120.index" )); + BOOST_CHECK(bfs::exists( retained_dir / "trace_history-121-140.log" )); + BOOST_CHECK(bfs::exists( retained_dir / "trace_history-121-140.index" )); + + BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-41-60.log" )); + BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-41-60.index" )); + BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-61-80.log" )); + BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-61-80.index" )); + BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-81-100.log" )); + BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-81-100.index" )); + BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-101-120.log" )); + BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-101-120.index" )); + BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-121-140.log" )); + BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-121-140.index" )); + + BOOST_CHECK(chain.traces_log.get_traces(10).empty()); + BOOST_CHECK(chain.traces_log.get_traces(100).size()); + BOOST_CHECK(chain.traces_log.get_traces(140).size()); + BOOST_CHECK(chain.traces_log.get_traces(150).size()); + BOOST_CHECK(chain.traces_log.get_traces(160).empty()); + + BOOST_CHECK(chain.chain_state_log.get_log_entry(10).empty()); + BOOST_CHECK(chain.chain_state_log.get_log_entry(100).size()); + BOOST_CHECK(chain.chain_state_log.get_log_entry(140).size()); + BOOST_CHECK(chain.chain_state_log.get_log_entry(150).size()); + BOOST_CHECK(chain.chain_state_log.get_log_entry(160).empty()); + + auto traces = chain.traces_log.get_traces(cfd_trace->block_num); + BOOST_REQUIRE(traces.size()); + + BOOST_REQUIRE(!get_prunable_data_from_traces(traces, cfd_trace->id).contains()); + + std::vector ids{cfd_trace->id}; + chain.traces_log.prune_transactions(cfd_trace->block_num, ids); + BOOST_REQUIRE(ids.empty()); + + // we assume the nodeos has to be stopped while running, it can only be read + // correctly with restart + state_history_traces_log new_log(config); + auto pruned_traces = new_log.get_traces(cfd_trace->block_num); + BOOST_REQUIRE(pruned_traces.size()); + + BOOST_CHECK(get_prunable_data_from_traces(pruned_traces, cfd_trace->id).contains()); +} + + +BOOST_AUTO_TEST_CASE(test_corrupted_log_recovery) { + namespace bfs = boost::filesystem; + + scoped_temp_path state_history_dir; + fc::create_directories(state_history_dir.path); + + state_history_config config{ + .log_dir = state_history_dir.path, + .archive_dir = "archive", + .stride = 100, + .max_retained_files = 5 + }; + + state_history_tester chain(config); + chain.produce_blocks(50); + chain.close(); + + // write a few random bytes to block log indicating the last block entry is incomplete + fc::cfile logfile; + logfile.set_file_path(state_history_dir.path / "trace_history.log"); + logfile.open("ab"); + const char random_data[] = "12345678901231876983271649837"; + logfile.write(random_data, sizeof(random_data)); + + bfs::remove_all(chain.get_config().blog.log_dir/"reversible"); + + state_history_tester new_chain(config); + new_chain.produce_blocks(50); + + BOOST_CHECK(new_chain.traces_log.get_traces(10).size()); + BOOST_CHECK(new_chain.chain_state_log.get_log_entry(10).size()); +} + + +BOOST_AUTO_TEST_CASE(test_state_result_abi) { + using namespace state_history; + + tester chain; + + transaction_trace_cache trace_cache; + std::map history; + fc::optional prev_block; + + chain.control->applied_transaction.connect( + [&](std::tuple t) { + trace_cache.add_transaction(std::get<0>(t), std::get<1>(t)); + }); + + chain.control->accepted_block.connect([&](const block_state_ptr& block_state) { + auto& control = chain.control; + + fc::datastream> strm; + trace_converter::pack(strm, control->db(), false, trace_cache.prepare_traces(block_state), + compression_type::none); + strm.seekp(0); + + get_blocks_result_v1 message; + message.head = block_position{control->head_block_num(), control->head_block_id()}; + message.last_irreversible = + state_history::block_position{control->last_irreversible_block_num(), control->last_irreversible_block_id()}; + message.this_block = state_history::block_position{block_state->block->block_num(), block_state->id}; + message.prev_block = prev_block; + message.block = block_state->block; + std::vector traces; + state_history::trace_converter::unpack(strm, traces); + message.traces = traces; + message.deltas = fc::raw::pack(state_history::create_deltas(control->db(), !prev_block)); + + prev_block = message.this_block; + history[control->head_block_num()] = fc::raw::pack(state_history::state_result{message}); + }); + + deploy_test_api(chain); + auto cfd_trace = push_test_cfd_transaction(chain); + chain.produce_blocks(1); + + state_history_abi_serializer serializer(chain); + + for (auto& [key, value] : history) { + { + // check the validity of the abi string + auto result = serializer.deserialize(value, "result"); + + auto& result_variant = result.get_array(); + BOOST_CHECK(result_variant[0].as_string() == "get_blocks_result_v1"); + auto& get_blocks_result_v1 = result_variant[1].get_object(); + + chain::bytes traces_bin; + fc::from_variant(get_blocks_result_v1["traces"], traces_bin); + BOOST_CHECK_NO_THROW( serializer.deserialize(traces_bin, "transaction_trace[]") ); + + chain::bytes deltas_bin; + fc::from_variant(get_blocks_result_v1["deltas"], deltas_bin); + BOOST_CHECK_NO_THROW( serializer.deserialize(deltas_bin, "table_delta[]")); + } + { + // check the validity of abieos ship_protocol type definitions + eosio::input_stream bin{value.data(), value.data() + value.size()}; + eosio::ship_protocol::result result; + BOOST_CHECK_NO_THROW(from_bin(result, bin)); + BOOST_CHECK(bin.remaining() == 0); + + auto& blocks_result_v1 = std::get(result); + + std::vector traces; + BOOST_CHECK_NO_THROW(blocks_result_v1.traces.unpack(traces)); + + std::vector deltas; + BOOST_CHECK_NO_THROW(blocks_result_v1.deltas.unpack(deltas)); + } + } +} + + + +BOOST_AUTO_TEST_CASE(test_traces_present) +{ + namespace bfs = boost::filesystem; + tester chain; + deploy_test_api(chain); + + scoped_temp_path state_history_dir; + fc::create_directories(state_history_dir.path); + state_history_config config; + config.log_dir = state_history_dir.path; + state_history_traces_log log(config); + + bool onblock_test_executed = false; + + chain.control->applied_transaction.connect( + [&](std::tuple t) { + const transaction_trace_ptr &trace_ptr = std::get<0>(t); + const chain::packed_transaction_ptr &transaction = std::get<1>(t); + log.add_transaction(trace_ptr, transaction); + + // see issue #9159 + if (!trace_ptr->action_traces.empty() && trace_ptr->action_traces[0].act.name == "onblock"_n) { + BOOST_CHECK(chain::is_onblock(*trace_ptr)); + trace_ptr->action_traces.clear(); + BOOST_CHECK(!chain::is_onblock(*trace_ptr)); + onblock_test_executed = true; + } + }); + chain.control->accepted_block.connect([&](const block_state_ptr& bs) { log.store(chain.control->db(), bs); }); + + auto tr_ptr = chain.create_account("newacc"_n); + + chain.produce_block(); + + BOOST_CHECK(onblock_test_executed); + + auto traces = log.get_traces(tr_ptr->block_num); + BOOST_REQUIRE_EQUAL(traces.size(), 1); + + auto trace_itr = std::find_if(traces.begin(), traces.end(), [tr_ptr](const state_history::transaction_trace& v) { + return v.get().id == tr_ptr->id; + }); + + BOOST_REQUIRE(trace_itr != traces.end()); + + auto &action_traces = trace_itr->get().action_traces; + + auto new_account_action_itr = std::find_if(action_traces.begin(), action_traces.end(), [](const state_history::action_trace& v) { + return v.get().act.name == "newaccount"_n.to_uint64_t(); + }); + + BOOST_REQUIRE(new_account_action_itr != action_traces.end()); +} + + +class table_deltas_tester : public tester { +public: + using tester::tester; + using deltas_vector = vector; + + pair find_table_delta(const std::string &name) { + v = eosio::state_history::create_deltas(control->db(), false);; + + auto find_by_name = [&name](const auto& x) { + return x.name == name; + }; + + auto it = std::find_if(v.begin(), v.end(), find_by_name); + + return make_pair(it != v.end(), it); + } + + template + vector deserialize_data(deltas_vector::iterator &it) { + vector result; + for(int i=0; i < it->rows.obj.size(); i++) { + eosio::input_stream stream{it->rows.obj[i].second.data(), it->rows.obj[i].second.size()}; + result.push_back(std::get(eosio::from_bin(stream))); + } + return result; + } + +private: + deltas_vector v; +}; + +BOOST_AUTO_TEST_CASE(test_deltas_account_creation) { + table_deltas_tester chain; + chain.produce_block(); + + // Check that no account table deltas are present + BOOST_REQUIRE_EQUAL(chain.find_table_delta("account").first, false); + + // Create new account + chain.create_account("newacc"_n); + + // Verify that a new record for the new account in the state delta of the block + auto result = chain.find_table_delta("account"); + BOOST_REQUIRE(result.first); + auto &it_account = result.second; + BOOST_REQUIRE_EQUAL(it_account->rows.obj.size(), 1); + + auto accounts = chain.deserialize_data(it_account); + BOOST_REQUIRE_EQUAL(accounts[0].name.to_string(), "newacc"); + +} + +BOOST_AUTO_TEST_CASE(test_deltas_account_metadata) { + table_deltas_tester chain; + chain.produce_block(); + + chain.create_account("newacc"_n); + + // Spot onto account metadata + auto result = chain.find_table_delta("account_metadata"); + BOOST_REQUIRE(result.first); + auto &it_account_metadata = result.second; + BOOST_REQUIRE_EQUAL(it_account_metadata->rows.obj.size(), 1); + + auto accounts_metadata = chain.deserialize_data(it_account_metadata); + BOOST_REQUIRE_EQUAL(accounts_metadata[0].name.to_string(), "newacc"); + BOOST_REQUIRE_EQUAL(accounts_metadata[0].privileged, false); + +} + + +BOOST_AUTO_TEST_CASE(test_deltas_account_permission) { + table_deltas_tester chain; + chain.produce_block(); + + chain.create_account(N(newacc)); + + // Check that the permissions of this new account are in the delta + vector expected_permission_names{ "owner", "active" }; + auto result = chain.find_table_delta("permission"); + BOOST_REQUIRE(result.first); + auto &it_permission = result.second; + BOOST_REQUIRE_EQUAL(it_permission->rows.obj.size(), 2); + auto accounts_permissions = chain.deserialize_data(it_permission); + for(int i = 0; i < accounts_permissions.size(); i++) + { + BOOST_REQUIRE_EQUAL(it_permission->rows.obj[i].first, true); + BOOST_REQUIRE_EQUAL(accounts_permissions[i].owner.to_string(), "newacc"); + BOOST_REQUIRE_EQUAL(accounts_permissions[i].name.to_string(), expected_permission_names[i]); + } +} + + +BOOST_AUTO_TEST_CASE(test_deltas_account_permission_creation_and_deletion) { + table_deltas_tester chain; + chain.produce_block(); + + chain.create_account(N(newacc)); + + auto& authorization_manager = chain.control->get_authorization_manager(); + const permission_object* ptr = authorization_manager.find_permission( {N(newacc), N(active)} ); + BOOST_REQUIRE(ptr != nullptr); + + // Create new permission + chain.set_authority(N(newacc), N(mypermission), ptr->auth, N(active)); + + const permission_object* ptr_sub = authorization_manager.find_permission( {N(newacc), N(mypermission)} ); + BOOST_REQUIRE(ptr_sub != nullptr); + + // Verify that the new permission is present in the state delta + std::vector expected_permission_names{ "owner", "active", "mypermission" }; + auto result = chain.find_table_delta("permission"); + BOOST_REQUIRE(result.first); + auto &it_permission = result.second; + BOOST_REQUIRE_EQUAL(it_permission->rows.obj.size(), 3); + BOOST_REQUIRE_EQUAL(it_permission->rows.obj[2].first, true); + auto accounts_permissions = chain.deserialize_data(it_permission); + BOOST_REQUIRE_EQUAL(accounts_permissions[2].owner.to_string(), "newacc"); + BOOST_REQUIRE_EQUAL(accounts_permissions[2].name.to_string(), "mypermission"); + BOOST_REQUIRE_EQUAL(accounts_permissions[2].parent.to_string(), "active"); + + chain.produce_block(); + + // Delete the permission + chain.delete_authority(N(newacc), N(mypermission)); + + result = chain.find_table_delta("permission"); + BOOST_REQUIRE(result.first); + auto &it_permission_del = result.second; + BOOST_REQUIRE_EQUAL(it_permission_del->rows.obj.size(), 1); + BOOST_REQUIRE_EQUAL(it_permission_del->rows.obj[0].first, false); + accounts_permissions = chain.deserialize_data(it_permission_del); + BOOST_REQUIRE_EQUAL(accounts_permissions[0].owner.to_string(), "newacc"); + BOOST_REQUIRE_EQUAL(accounts_permissions[0].name.to_string(), "mypermission"); + BOOST_REQUIRE_EQUAL(accounts_permissions[0].parent.to_string(), "active"); +} + + + + +BOOST_AUTO_TEST_CASE(test_deltas_account_permission_modification) { + table_deltas_tester chain; + chain.produce_block(); + + chain.create_account(N(newacc)); + chain.produce_block(); + public_key_type keys[] = { + public_key_type("PUB_WA_WdCPfafVNxVMiW5ybdNs83oWjenQXvSt1F49fg9mv7qrCiRwHj5b38U3ponCFWxQTkDsMC"s), // Test for correct serialization of WA key, see issue #9087 + public_key_type("PUB_K1_12wkBET2rRgE8pahuaczxKbmv7ciehqsne57F9gtzf1PVb7Rf7o"s), + public_key_type("PUB_R1_6FPFZqw5ahYrR9jD96yDbbDNTdKtNqRbze6oTDLntrsANgQKZu"s)}; + const int K1_storage_type_which_value = 0; + + for(auto &key: keys) { + // Modify the permission authority + auto wa_authority = authority(1, {key_weight{key, 1}}, {}); + chain.set_authority(N(newacc), N(active), wa_authority, N(owner)); + + auto result = chain.find_table_delta("permission"); + BOOST_REQUIRE(result.first); + + auto &it_permission = result.second; + BOOST_REQUIRE_EQUAL(it_permission->rows.obj.size(), 1); + auto accounts_permissions = chain.deserialize_data(it_permission); + BOOST_REQUIRE_EQUAL(accounts_permissions[0].owner.to_string(), "newacc"); + BOOST_REQUIRE_EQUAL(accounts_permissions[0].name.to_string(), "active"); + BOOST_REQUIRE_EQUAL(accounts_permissions[0].auth.keys.size(), 1); + if(key.which() != K1_storage_type_which_value) + BOOST_REQUIRE_EQUAL(public_key_to_string(accounts_permissions[0].auth.keys[0].key), key.to_string()); + else + BOOST_REQUIRE_EQUAL(public_key_to_string(accounts_permissions[0].auth.keys[0].key), "PUB_K1_12wkBET2rRgE8pahuaczxKbmv7ciehqsne57F9gtzf1PVb7Rf7o"); + + chain.produce_block(); + } +} + + + +BOOST_AUTO_TEST_CASE(test_deltas_permission_link) { + table_deltas_tester chain; + chain.produce_block(); + + chain.create_account(N(newacc)); + + // Spot onto permission_link + const auto spending_priv_key = chain.get_private_key(N(newacc), "spending"); + const auto spending_pub_key = spending_priv_key.get_public_key(); + + chain.set_authority(N(newacc), N(spending), spending_pub_key, N(active)); + chain.link_authority(N(newacc), N(eosio), N(spending), N(reqauth)); + chain.push_reqauth(N(newacc), { permission_level{N(newacc), N(spending)} }, { spending_priv_key }); + + auto result = chain.find_table_delta("permission_link"); + BOOST_REQUIRE(result.first); + auto &it_permission_link = result.second; + BOOST_REQUIRE_EQUAL(it_permission_link->rows.obj.size(), 1); + auto permission_links = chain.deserialize_data(it_permission_link); + BOOST_REQUIRE_EQUAL(permission_links[0].account.to_string(), "newacc"); + BOOST_REQUIRE_EQUAL(permission_links[0].message_type.to_string(), "reqauth"); + BOOST_REQUIRE_EQUAL(permission_links[0].required_permission.to_string(), "spending"); +} + + + +BOOST_AUTO_TEST_CASE(test_deltas_global_property_history) { + // Assuming max transaction delay is 45 days (default in config.hpp) + table_deltas_tester chain; + + // Change max_transaction_delay to 60 sec + auto params = chain.control->get_global_properties().configuration; + params.max_transaction_delay = 60; + chain.push_action( config::system_account_name, N(setparams), config::system_account_name, + mutable_variant_object() + ("params", params) ); + + // Deserialize and spot onto some data + auto result = chain.find_table_delta("global_property"); + BOOST_REQUIRE(result.first); + auto &it_global_property = result.second; + BOOST_REQUIRE_EQUAL(it_global_property->rows.obj.size(), 1); + auto global_properties = chain.deserialize_data(it_global_property); + auto configuration = std::get(global_properties[0].configuration); + BOOST_REQUIRE_EQUAL(configuration.max_transaction_delay, 60); +} + + + +BOOST_AUTO_TEST_CASE(test_deltas_protocol_feature_history) { + table_deltas_tester chain(setup_policy::none); + const auto &pfm = chain.control->get_protocol_feature_manager(); + + chain.produce_block(); + + auto d = pfm.get_builtin_digest(builtin_protocol_feature_t::preactivate_feature); + BOOST_REQUIRE(d); + + // Activate PREACTIVATE_FEATURE. + chain.schedule_protocol_features_wo_preactivation({*d}); + + chain.produce_block(); + + // Now the latest bios contract can be set. + chain.set_before_producer_authority_bios_contract(); + + // Spot onto some data of the protocol state table delta + auto result = chain.find_table_delta("protocol_state"); + BOOST_REQUIRE(result.first); + auto &it_protocol_state = result.second; + BOOST_REQUIRE_EQUAL(it_protocol_state->rows.obj.size(), 1); + auto protocol_states = chain.deserialize_data(it_protocol_state); + auto protocol_feature = std::get(protocol_states[0].activated_protocol_features[0]); + + auto digest_byte_array = protocol_feature.feature_digest.extract_as_byte_array(); + char digest_array[digest_byte_array.size()]; + for(int i=0; i < digest_byte_array.size(); i++) digest_array[i] = digest_byte_array[i]; + eosio::chain::digest_type digest_in_delta(digest_array, digest_byte_array.size()); + + BOOST_REQUIRE_EQUAL(digest_in_delta, *d); +} + + + +BOOST_AUTO_TEST_CASE(test_deltas_contract) { + table_deltas_tester chain; + chain.produce_block(); + + chain.create_account(N(tester)); + + chain.set_code(N(tester), contracts::get_table_test_wasm()); + chain.set_abi(N(tester), contracts::get_table_test_abi().data()); + + chain.produce_block(); + + auto trace = chain.push_action(N(tester), N(addhashobj), N(tester), mutable_variant_object()("hashinput", "hello" )); + + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + + trace = chain.push_action(N(tester), N(addnumobj), N(tester), mutable_variant_object()("input", 2)); + + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + + // Spot onto contract_table + auto result = chain.find_table_delta("contract_table"); + BOOST_REQUIRE(result.first); + auto &it_contract_table = result.second; + BOOST_REQUIRE_EQUAL(it_contract_table->rows.obj.size(), 6); + auto contract_tables = chain.deserialize_data(it_contract_table); + BOOST_REQUIRE_EQUAL(contract_tables[0].table.to_string(), "hashobjs"); + BOOST_REQUIRE_EQUAL(contract_tables[1].table.to_string(), "hashobjs....1"); + BOOST_REQUIRE_EQUAL(contract_tables[2].table.to_string(), "numobjs"); + BOOST_REQUIRE_EQUAL(contract_tables[3].table.to_string(), "numobjs.....1"); + BOOST_REQUIRE_EQUAL(contract_tables[4].table.to_string(), "numobjs.....2"); + BOOST_REQUIRE_EQUAL(contract_tables[5].table.to_string(), "numobjs.....3"); + + // Spot onto contract_row + result = chain.find_table_delta("contract_row"); + BOOST_REQUIRE(result.first); + auto &it_contract_row = result.second; + BOOST_REQUIRE_EQUAL(it_contract_row->rows.obj.size(), 2); + auto contract_rows = chain.deserialize_data(it_contract_row); + BOOST_REQUIRE_EQUAL(contract_rows[0].table.to_string(), "hashobjs"); + BOOST_REQUIRE_EQUAL(contract_rows[1].table.to_string(), "numobjs"); + + // Spot onto contract_index256 + result = chain.find_table_delta("contract_index256"); + BOOST_REQUIRE(result.first); + auto &it_contract_index256 = result.second; + BOOST_REQUIRE_EQUAL(it_contract_index256->rows.obj.size(), 2); + auto contract_indices = chain.deserialize_data(it_contract_index256); + BOOST_REQUIRE_EQUAL(contract_indices[0].table.to_string(), "hashobjs"); + BOOST_REQUIRE_EQUAL(contract_indices[1].table.to_string(), "hashobjs....1"); +} + + +BOOST_AUTO_TEST_CASE(test_deltas_resources_history) { + table_deltas_tester chain; + chain.produce_block(); + + chain.create_accounts({ "eosio.token"_n, "eosio.ram"_n, "eosio.ramfee"_n, "eosio.stake"_n}); + + chain.produce_blocks( 100 ); + + chain.set_code( "eosio.token"_n, contracts::eosio_token_wasm() ); + chain.set_abi( "eosio.token"_n, contracts::eosio_token_abi().data() ); + + chain.produce_block(); + + chain.push_action("eosio.token"_n, "create"_n, "eosio.token"_n, mutable_variant_object() + ("issuer", "eosio.token" ) + ("maximum_supply", core_from_string("1000000000.0000") ) + ); + + chain.push_action("eosio.token"_n, "issue"_n, "eosio.token"_n, fc::mutable_variant_object() + ("to", "eosio") + ("quantity", core_from_string("90.0000")) + ("memo", "for stuff") + ); + + chain.produce_blocks(10); + + chain.set_code( config::system_account_name, contracts::eosio_system_wasm() ); + chain.set_abi( config::system_account_name, contracts::eosio_system_abi().data() ); + + chain.push_action(config::system_account_name, "init"_n, config::system_account_name, + mutable_variant_object() + ("version", 0) + ("core", CORE_SYM_STR)); + + signed_transaction trx; + chain.set_transaction_headers(trx); + + authority owner_auth; + owner_auth = authority( chain.get_public_key( "alice"_n, "owner" ) ); + + trx.actions.emplace_back( vector{{config::system_account_name,config::active_name}}, + newaccount{ + .creator = config::system_account_name, + .name = "alice"_n, + .owner = owner_auth, + .active = authority( chain.get_public_key( "alice"_n, "active" ) )}); + + trx.actions.emplace_back( chain.get_action( config::system_account_name, "buyram"_n, vector{{config::system_account_name,config::active_name}}, + mutable_variant_object() + ("payer", config::system_account_name) + ("receiver", "alice"_n) + ("quant", core_from_string("1.0000")))); + + trx.actions.emplace_back( chain.get_action( config::system_account_name, "delegatebw"_n, vector{{config::system_account_name,config::active_name}}, + mutable_variant_object() + ("from", config::system_account_name) + ("receiver", "alice"_n) + ("stake_net_quantity", core_from_string("10.0000") ) + ("stake_cpu_quantity", core_from_string("10.0000") ) + ("transfer", 0 ))); + + chain.set_transaction_headers(trx); + trx.sign( chain.get_private_key( config::system_account_name, "active" ), chain.control->get_chain_id() ); + chain.push_transaction( trx ); + +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file From 8d360aafaabadd8f485531b2bc52c64305dcbfeb Mon Sep 17 00:00:00 2001 From: Chris Gundlach Date: Thu, 7 Jul 2022 08:51:13 -0500 Subject: [PATCH 2/7] added missing abi libraries --- unittests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 8462ce1780..f81b8870e2 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -39,7 +39,7 @@ add_custom_command( file(GLOB UNIT_TESTS "*.cpp") # find all unit test suites add_executable( unit_test ${UNIT_TESTS} protocol_feature_digest_tests.cpp) # build unit tests as one executable -target_link_libraries( unit_test eosio_chain_wrap state_history chainbase eosio_testing fc appbase ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( unit_test eosio_chain_wrap state_history chainbase eosio_testing fc appbase abieos ship_abi ${PLATFORM_SPECIFIC_LIBS} ) target_compile_options(unit_test PUBLIC -DDISABLE_EOSLIB_SERIALIZE) target_include_directories( unit_test PUBLIC From 01ec3856f8fb1e9a9f43f7e0aa0db52c7cd27104 Mon Sep 17 00:00:00 2001 From: Chris Gundlach Date: Thu, 7 Jul 2022 10:54:46 -0500 Subject: [PATCH 3/7] cleaned up N() to _n issues --- unittests/state_history_tests.cpp | 58 ++++++++++++++++++------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/unittests/state_history_tests.cpp b/unittests/state_history_tests.cpp index 977dab6770..30b3e52a91 100644 --- a/unittests/state_history_tests.cpp +++ b/unittests/state_history_tests.cpp @@ -16,9 +16,8 @@ #include #pragma pop_macro("N") -using namespace eosio; -using namespace testing; -using namespace chain; +using namespace eosio::chain; +using namespace eosio::testing; using namespace std::literals; extern const char* const state_history_plugin_abi; @@ -51,6 +50,7 @@ struct state_history_abi_serializer { BOOST_AUTO_TEST_SUITE(test_state_history) +/* BOOST_AUTO_TEST_CASE(test_trace_converter) { tester chain; @@ -90,7 +90,9 @@ BOOST_AUTO_TEST_CASE(test_trace_converter) { // read the pruned trace and make sure it's pruned BOOST_CHECK(get_prunable_data_from_traces_bin(cfd_entry, cfd_trace->id).contains()); } +*/ +/* BOOST_AUTO_TEST_CASE(test_trace_log) { namespace bfs = boost::filesystem; tester chain; @@ -128,7 +130,9 @@ BOOST_AUTO_TEST_CASE(test_trace_log) { BOOST_CHECK(get_prunable_data_from_traces(pruned_traces, cfd_trace->id).contains()); } +*/ +/* BOOST_AUTO_TEST_CASE(test_chain_state_log) { namespace bfs = boost::filesystem; @@ -152,8 +156,9 @@ BOOST_AUTO_TEST_CASE(test_chain_state_log) { eosio::input_stream deltas_bin{entry.data(), entry.data() + entry.size()}; BOOST_CHECK_NO_THROW(from_bin(deltas, deltas_bin)); } +*/ - +/* struct state_history_tester_logs { state_history_tester_logs(const state_history_config& config) : traces_log(config) , chain_state_log(config) {} @@ -161,7 +166,9 @@ struct state_history_tester_logs { state_history_traces_log traces_log; state_history_chain_state_log chain_state_log; }; +*/ +/* struct state_history_tester : state_history_tester_logs, tester { state_history_tester(const state_history_config& config) : state_history_tester_logs(config), tester ([&](eosio::chain::controller& control) { @@ -177,8 +184,9 @@ struct state_history_tester : state_history_tester_logs, tester { control.block_start.connect([&](uint32_t block_num) { traces_log.block_start(block_num); } ); }) {} }; +*/ - +/* BOOST_AUTO_TEST_CASE(test_splitted_log) { namespace bfs = boost::filesystem; @@ -267,6 +275,7 @@ BOOST_AUTO_TEST_CASE(test_splitted_log) { BOOST_CHECK(get_prunable_data_from_traces(pruned_traces, cfd_trace->id).contains()); } +*/ BOOST_AUTO_TEST_CASE(test_corrupted_log_recovery) { @@ -514,7 +523,7 @@ BOOST_AUTO_TEST_CASE(test_deltas_account_permission) { table_deltas_tester chain; chain.produce_block(); - chain.create_account(N(newacc)); + chain.create_account("newacc"_n); // Check that the permissions of this new account are in the delta vector expected_permission_names{ "owner", "active" }; @@ -536,16 +545,16 @@ BOOST_AUTO_TEST_CASE(test_deltas_account_permission_creation_and_deletion) { table_deltas_tester chain; chain.produce_block(); - chain.create_account(N(newacc)); + chain.create_account("newacc"_n); auto& authorization_manager = chain.control->get_authorization_manager(); - const permission_object* ptr = authorization_manager.find_permission( {N(newacc), N(active)} ); + const permission_object* ptr = authorization_manager.find_permission( {"newacc"_n, "active"_n} ); BOOST_REQUIRE(ptr != nullptr); // Create new permission - chain.set_authority(N(newacc), N(mypermission), ptr->auth, N(active)); + chain.set_authority("newacc"_n, "mypermission"_n, ptr->auth, "active"_n)); - const permission_object* ptr_sub = authorization_manager.find_permission( {N(newacc), N(mypermission)} ); + const permission_object* ptr_sub = authorization_manager.find_permission( {"newacc"_n, "mypermission"_n} ); BOOST_REQUIRE(ptr_sub != nullptr); // Verify that the new permission is present in the state delta @@ -563,7 +572,7 @@ BOOST_AUTO_TEST_CASE(test_deltas_account_permission_creation_and_deletion) { chain.produce_block(); // Delete the permission - chain.delete_authority(N(newacc), N(mypermission)); + chain.delete_authority("newacc"_n, "mypermission"_n); result = chain.find_table_delta("permission"); BOOST_REQUIRE(result.first); @@ -583,7 +592,7 @@ BOOST_AUTO_TEST_CASE(test_deltas_account_permission_modification) { table_deltas_tester chain; chain.produce_block(); - chain.create_account(N(newacc)); + chain.create_account("newacc"_n); chain.produce_block(); public_key_type keys[] = { public_key_type("PUB_WA_WdCPfafVNxVMiW5ybdNs83oWjenQXvSt1F49fg9mv7qrCiRwHj5b38U3ponCFWxQTkDsMC"s), // Test for correct serialization of WA key, see issue #9087 @@ -594,7 +603,7 @@ BOOST_AUTO_TEST_CASE(test_deltas_account_permission_modification) { for(auto &key: keys) { // Modify the permission authority auto wa_authority = authority(1, {key_weight{key, 1}}, {}); - chain.set_authority(N(newacc), N(active), wa_authority, N(owner)); + chain.set_authority("newacc"_n, "active"_n, wa_authority, "owner"_n); auto result = chain.find_table_delta("permission"); BOOST_REQUIRE(result.first); @@ -620,15 +629,16 @@ BOOST_AUTO_TEST_CASE(test_deltas_permission_link) { table_deltas_tester chain; chain.produce_block(); - chain.create_account(N(newacc)); + chain.create_account("newacc"_n); // Spot onto permission_link - const auto spending_priv_key = chain.get_private_key(N(newacc), "spending"); + const auto spending_priv_key = chain.get_private_key("newacc"_n, "spending"); const auto spending_pub_key = spending_priv_key.get_public_key(); - chain.set_authority(N(newacc), N(spending), spending_pub_key, N(active)); - chain.link_authority(N(newacc), N(eosio), N(spending), N(reqauth)); - chain.push_reqauth(N(newacc), { permission_level{N(newacc), N(spending)} }, { spending_priv_key }); + chain.set_authority("newacc"_n, "spending"_n, spending_pub_key, "active"_n); + chain.link_authority("newacc"_n, "eosio"_n, "spending"_n, "reqauth"_n); + chain.push_reqauth("newacc"_n, { permission_level{"newacc"_n, "spending"_n} }, { spending_priv_key }); + auto result = chain.find_table_delta("permission_link"); BOOST_REQUIRE(result.first); @@ -649,7 +659,7 @@ BOOST_AUTO_TEST_CASE(test_deltas_global_property_history) { // Change max_transaction_delay to 60 sec auto params = chain.control->get_global_properties().configuration; params.max_transaction_delay = 60; - chain.push_action( config::system_account_name, N(setparams), config::system_account_name, + chain.push_action( config::system_account_name, "setparams"_n, config::system_account_name, mutable_variant_object() ("params", params) ); @@ -704,18 +714,18 @@ BOOST_AUTO_TEST_CASE(test_deltas_contract) { table_deltas_tester chain; chain.produce_block(); - chain.create_account(N(tester)); + chain.create_account("tester"_n)); - chain.set_code(N(tester), contracts::get_table_test_wasm()); - chain.set_abi(N(tester), contracts::get_table_test_abi().data()); + chain.set_code("tester"_n, contracts::get_table_test_wasm()); + chain.set_abi("tester"_n, contracts::get_table_test_abi().data()); chain.produce_block(); - auto trace = chain.push_action(N(tester), N(addhashobj), N(tester), mutable_variant_object()("hashinput", "hello" )); + auto trace = chain.push_action("tester"_n, "addhashobj"_n, "tester"_n, mutable_variant_object()("hashinput", "hello" )); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); - trace = chain.push_action(N(tester), N(addnumobj), N(tester), mutable_variant_object()("input", 2)); + trace = chain.push_action("tester"_n, "addnumobj"_n, "tester"_n, mutable_variant_object()("input", 2)); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); From d3220529d13dd7aefbb0b49080f3089eebce4382 Mon Sep 17 00:00:00 2001 From: Chris Gundlach Date: Fri, 8 Jul 2022 09:17:00 -0500 Subject: [PATCH 4/7] GH-597 various fixes to align with Mandel codebase --- unittests/state_history_tests.cpp | 151 +++++++++++++++++++----------- 1 file changed, 98 insertions(+), 53 deletions(-) diff --git a/unittests/state_history_tests.cpp b/unittests/state_history_tests.cpp index 30b3e52a91..fb4ed7ed9f 100644 --- a/unittests/state_history_tests.cpp +++ b/unittests/state_history_tests.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "test_cfd_transaction.hpp" #include @@ -21,14 +22,54 @@ using namespace eosio::testing; using namespace std::literals; extern const char* const state_history_plugin_abi; +/* +eosio::ship_protocol::prunable_data_type::prunable_data_t +get_prunable_data_from_traces(std::vector& traces, + const transaction_id_type& id) { + auto cfd_trace_itr = + std::find_if(traces.begin(), traces.end(), [id](const eosio::ship_protocol::transaction_trace& v) { + return std::get(v).id == id; + }); + + // make sure the trace with cfd can be found + BOOST_REQUIRE(cfd_trace_itr != traces.end()); + BOOST_REQUIRE(std::holds_alternative(*cfd_trace_itr)); + auto trace_v0 = std::get(*cfd_trace_itr); + BOOST_REQUIRE(trace_v0.partial); + BOOST_REQUIRE(std::holds_alternative(*trace_v0.partial)); + return std::get(*trace_v0.partial).prunable_data->prunable_data; +} +*/ -struct state_history_config { - chainbase::bfs::path log_dir; - chainbase::bfs::path retained_dir; - chainbase::bfs::path archive_dir; - uint32_t stride = UINT32_MAX; - uint32_t max_retained_files = 10; -}; +bool operator==(const eosio::checksum256& lhs, const transaction_id_type& rhs) { + return memcmp(lhs.extract_as_byte_array().data(), rhs.data(), rhs.data_size()) == 0; +} + +auto get_prunable_data_from_traces(std::vector& traces, + const transaction_id_type& id) { + auto cfd_trace_itr = + std::find_if(traces.begin(), traces.end(), [id](const eosio::ship_protocol::transaction_trace& v) { + return std::get(v).id == id; + }); + + // make sure the trace with cfd can be found + BOOST_REQUIRE(cfd_trace_itr != traces.end()); + BOOST_REQUIRE(std::holds_alternative(*cfd_trace_itr)); + auto trace_v0 = std::get(*cfd_trace_itr); + BOOST_REQUIRE(trace_v0.partial); + BOOST_REQUIRE(std::holds_alternative(*trace_v0.partial)); + return std::get(*trace_v0.partial).prunable_data->prunable_data; +} + +eosio::ship_protocol::prunable_data_type::prunable_data_t get_prunable_data_from_traces_bin(const std::vector& entry, + const transaction_id_type& id) { + fc::datastream strm(entry.data(), entry.size()); + std::vector traces; + /* Where is the equivalent for this? + eosio::state_history::trace_converter::unpack(strm, traces); + */ + return get_prunable_data_from_traces(traces, id); +} struct state_history_abi_serializer { tester& chain; @@ -39,7 +80,7 @@ struct state_history_abi_serializer { , sr(fc::json::from_string(state_history_plugin_abi).as(), abi_serializer::create_yield_function(chain.abi_serializer_max_time)) {} - fc::variant deserialize(const chain::bytes& data, const char* type) { + fc::variant deserialize(const eosio::chain::bytes& data, const char* type) { fc::datastream strm(data.data(), data.size()); auto result = sr.binary_to_variant(type, strm, abi_serializer::create_yield_function(chain.abi_serializer_max_time)); @@ -50,14 +91,14 @@ struct state_history_abi_serializer { BOOST_AUTO_TEST_SUITE(test_state_history) -/* + BOOST_AUTO_TEST_CASE(test_trace_converter) { tester chain; using namespace eosio::state_history; - state_history::trace_converter converter; - std::map on_disk_log_entries; + trace_converter converter; + std::map on_disk_log_entries; chain.control->applied_transaction.connect( [&](std::tuple t) { @@ -79,18 +120,20 @@ BOOST_AUTO_TEST_CASE(test_trace_converter) { // Now deserialize the on disk trace log and make sure that the cfd exists auto& cfd_entry = on_disk_log_entries.at(cfd_trace->block_num); - BOOST_REQUIRE(!get_prunable_data_from_traces_bin(cfd_entry, cfd_trace->id).contains()); + BOOST_REQUIRE(!std::holds_alternative(get_prunable_data_from_traces_bin(cfd_entry, cfd_trace->id))); +/* Do we need this? // prune the cfd for the block std::vector ids{cfd_trace->id}; fc::datastream rw_strm(cfd_entry.data(), cfd_entry.size()); - state_history::trace_converter::prune_traces(rw_strm, cfd_entry.size(), ids); + eosio::state_history::trace_converter::prune_traces(rw_strm, cfd_entry.size(), ids); BOOST_CHECK(ids.size() == 0); // read the pruned trace and make sure it's pruned - BOOST_CHECK(get_prunable_data_from_traces_bin(cfd_entry, cfd_trace->id).contains()); -} + BOOST_CHECK(get_prunable_data_from_traces_bin(cfd_entry, cfd_trace->id).contains()); */ +} + /* BOOST_AUTO_TEST_CASE(test_trace_log) { @@ -132,7 +175,7 @@ BOOST_AUTO_TEST_CASE(test_trace_log) { } */ -/* +/* Do we need this? BOOST_AUTO_TEST_CASE(test_chain_state_log) { namespace bfs = boost::filesystem; @@ -160,33 +203,33 @@ BOOST_AUTO_TEST_CASE(test_chain_state_log) { /* struct state_history_tester_logs { - state_history_tester_logs(const state_history_config& config) - : traces_log(config) , chain_state_log(config) {} + state_history_tester_logs(const state_history_config& config) {} +// : traces_log(config) , chain_state_log(config) {} - state_history_traces_log traces_log; - state_history_chain_state_log chain_state_log; +// state_history_traces_log traces_log; +// state_history_chain_state_log chain_state_log; }; -*/ -/* + + struct state_history_tester : state_history_tester_logs, tester { state_history_tester(const state_history_config& config) : state_history_tester_logs(config), tester ([&](eosio::chain::controller& control) { control.applied_transaction.connect( [&](std::tuple t) { - traces_log.add_transaction(std::get<0>(t), std::get<1>(t)); +// traces_log.add_transaction(std::get<0>(t), std::get<1>(t)); }); control.accepted_block.connect([&](const block_state_ptr& bs) { - traces_log.store(control.db(), bs); - chain_state_log.store(control.db(), bs); +// traces_log.store(control.db(), bs); +// chain_state_log.store(control.db(), bs); }); control.block_start.connect([&](uint32_t block_num) { traces_log.block_start(block_num); } ); }) {} }; */ -/* +/* Do we need this? BOOST_AUTO_TEST_CASE(test_splitted_log) { namespace bfs = boost::filesystem; @@ -283,15 +326,16 @@ BOOST_AUTO_TEST_CASE(test_corrupted_log_recovery) { scoped_temp_path state_history_dir; fc::create_directories(state_history_dir.path); - +/* state_history_config config{ .log_dir = state_history_dir.path, .archive_dir = "archive", .stride = 100, .max_retained_files = 5 }; +*/ - state_history_tester chain(config); + tester chain; chain.produce_blocks(50); chain.close(); @@ -302,24 +346,25 @@ BOOST_AUTO_TEST_CASE(test_corrupted_log_recovery) { const char random_data[] = "12345678901231876983271649837"; logfile.write(random_data, sizeof(random_data)); - bfs::remove_all(chain.get_config().blog.log_dir/"reversible"); + bfs::remove_all(chain.get_config().blocks_dir/"reversible"); - state_history_tester new_chain(config); + tester new_chain; new_chain.produce_blocks(50); - BOOST_CHECK(new_chain.traces_log.get_traces(10).size()); - BOOST_CHECK(new_chain.chain_state_log.get_log_entry(10).size()); +// What do we need to do to verify? +// BOOST_CHECK(new_chain.traces_log.get_traces(10).size()); +// BOOST_CHECK(new_chain.chain_state_log.get_log_entry(10).size()); } - +/* It seems like this one needs to be re-written due to underlying differences between mandel and eosio BOOST_AUTO_TEST_CASE(test_state_result_abi) { - using namespace state_history; + using namespace eosio::state_history; tester chain; - transaction_trace_cache trace_cache; - std::map history; - fc::optional prev_block; + trace_converter trace_cache; + std::map history; + std::optional prev_block; chain.control->applied_transaction.connect( [&](std::tuple t) { @@ -330,24 +375,24 @@ BOOST_AUTO_TEST_CASE(test_state_result_abi) { auto& control = chain.control; fc::datastream> strm; - trace_converter::pack(strm, control->db(), false, trace_cache.prepare_traces(block_state), - compression_type::none); + trace_cache.pack(control->db(), false, block_state); + strm.seekp(0); - get_blocks_result_v1 message; + eosio::state_history::get_blocks_result_v0 message; message.head = block_position{control->head_block_num(), control->head_block_id()}; message.last_irreversible = - state_history::block_position{control->last_irreversible_block_num(), control->last_irreversible_block_id()}; - message.this_block = state_history::block_position{block_state->block->block_num(), block_state->id}; + eosio::state_history::block_position{control->last_irreversible_block_num(), control->last_irreversible_block_id()}; + message.this_block = eosio::state_history::block_position{block_state->block->block_num(), block_state->id}; message.prev_block = prev_block; message.block = block_state->block; - std::vector traces; - state_history::trace_converter::unpack(strm, traces); + std::vector traces; + eosio::state_history::trace_converter::unpack(strm, traces); message.traces = traces; - message.deltas = fc::raw::pack(state_history::create_deltas(control->db(), !prev_block)); + message.deltas = fc::raw::pack(eosio::state_history::create_deltas(control->db(), !prev_block)); prev_block = message.this_block; - history[control->head_block_num()] = fc::raw::pack(state_history::state_result{message}); + history[control->head_block_num()] = fc::raw::pack(eosio::state_history::state_result{message}); }); deploy_test_api(chain); @@ -365,11 +410,11 @@ BOOST_AUTO_TEST_CASE(test_state_result_abi) { BOOST_CHECK(result_variant[0].as_string() == "get_blocks_result_v1"); auto& get_blocks_result_v1 = result_variant[1].get_object(); - chain::bytes traces_bin; + eosio::chain::bytes traces_bin; fc::from_variant(get_blocks_result_v1["traces"], traces_bin); BOOST_CHECK_NO_THROW( serializer.deserialize(traces_bin, "transaction_trace[]") ); - chain::bytes deltas_bin; + eosio::chain::bytes deltas_bin; fc::from_variant(get_blocks_result_v1["deltas"], deltas_bin); BOOST_CHECK_NO_THROW( serializer.deserialize(deltas_bin, "table_delta[]")); } @@ -390,9 +435,9 @@ BOOST_AUTO_TEST_CASE(test_state_result_abi) { } } } +*/ - - +/* what is equivalent to state_history_traces_log in mandel BOOST_AUTO_TEST_CASE(test_traces_present) { namespace bfs = boost::filesystem; @@ -446,7 +491,7 @@ BOOST_AUTO_TEST_CASE(test_traces_present) BOOST_REQUIRE(new_account_action_itr != action_traces.end()); } - +*/ class table_deltas_tester : public tester { public: @@ -552,7 +597,7 @@ BOOST_AUTO_TEST_CASE(test_deltas_account_permission_creation_and_deletion) { BOOST_REQUIRE(ptr != nullptr); // Create new permission - chain.set_authority("newacc"_n, "mypermission"_n, ptr->auth, "active"_n)); + chain.set_authority("newacc"_n, "mypermission"_n, ptr->auth, "active"_n); const permission_object* ptr_sub = authorization_manager.find_permission( {"newacc"_n, "mypermission"_n} ); BOOST_REQUIRE(ptr_sub != nullptr); @@ -714,7 +759,7 @@ BOOST_AUTO_TEST_CASE(test_deltas_contract) { table_deltas_tester chain; chain.produce_block(); - chain.create_account("tester"_n)); + chain.create_account("tester"_n); chain.set_code("tester"_n, contracts::get_table_test_wasm()); chain.set_abi("tester"_n, contracts::get_table_test_abi().data()); From 5698ab021da0e541efa92c08059de8c4a565ef04 Mon Sep 17 00:00:00 2001 From: Chris Gundlach Date: Fri, 8 Jul 2022 09:35:42 -0500 Subject: [PATCH 5/7] GH-597 removed ship_abi from cmake --- unittests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index f81b8870e2..c552d65d1f 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -39,7 +39,7 @@ add_custom_command( file(GLOB UNIT_TESTS "*.cpp") # find all unit test suites add_executable( unit_test ${UNIT_TESTS} protocol_feature_digest_tests.cpp) # build unit tests as one executable -target_link_libraries( unit_test eosio_chain_wrap state_history chainbase eosio_testing fc appbase abieos ship_abi ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( unit_test eosio_chain_wrap state_history chainbase eosio_testing fc appbase abieos ${PLATFORM_SPECIFIC_LIBS} ) target_compile_options(unit_test PUBLIC -DDISABLE_EOSLIB_SERIALIZE) target_include_directories( unit_test PUBLIC From 03be094a6ad536cf4ed9796d35914c469918bb6b Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 8 Jul 2022 11:58:28 -0500 Subject: [PATCH 6/7] GH-625 Remove non-applicable ship tests. --- unittests/state_history_tests.cpp | 476 +----------------------------- 1 file changed, 1 insertion(+), 475 deletions(-) diff --git a/unittests/state_history_tests.cpp b/unittests/state_history_tests.cpp index fb4ed7ed9f..6b8dd755fd 100644 --- a/unittests/state_history_tests.cpp +++ b/unittests/state_history_tests.cpp @@ -11,488 +11,21 @@ #include "test_cfd_transaction.hpp" #include -#pragma push_macro("N") -#undef N #include #include -#pragma pop_macro("N") using namespace eosio::chain; using namespace eosio::testing; using namespace std::literals; extern const char* const state_history_plugin_abi; -/* -eosio::ship_protocol::prunable_data_type::prunable_data_t -get_prunable_data_from_traces(std::vector& traces, - const transaction_id_type& id) { - auto cfd_trace_itr = - std::find_if(traces.begin(), traces.end(), [id](const eosio::ship_protocol::transaction_trace& v) { - return std::get(v).id == id; - }); - - // make sure the trace with cfd can be found - BOOST_REQUIRE(cfd_trace_itr != traces.end()); - BOOST_REQUIRE(std::holds_alternative(*cfd_trace_itr)); - auto trace_v0 = std::get(*cfd_trace_itr); - BOOST_REQUIRE(trace_v0.partial); - BOOST_REQUIRE(std::holds_alternative(*trace_v0.partial)); - return std::get(*trace_v0.partial).prunable_data->prunable_data; -} -*/ bool operator==(const eosio::checksum256& lhs, const transaction_id_type& rhs) { return memcmp(lhs.extract_as_byte_array().data(), rhs.data(), rhs.data_size()) == 0; } -auto get_prunable_data_from_traces(std::vector& traces, - const transaction_id_type& id) { - auto cfd_trace_itr = - std::find_if(traces.begin(), traces.end(), [id](const eosio::ship_protocol::transaction_trace& v) { - return std::get(v).id == id; - }); - - // make sure the trace with cfd can be found - BOOST_REQUIRE(cfd_trace_itr != traces.end()); - BOOST_REQUIRE(std::holds_alternative(*cfd_trace_itr)); - auto trace_v0 = std::get(*cfd_trace_itr); - BOOST_REQUIRE(trace_v0.partial); - BOOST_REQUIRE(std::holds_alternative(*trace_v0.partial)); - return std::get(*trace_v0.partial).prunable_data->prunable_data; -} - -eosio::ship_protocol::prunable_data_type::prunable_data_t get_prunable_data_from_traces_bin(const std::vector& entry, - const transaction_id_type& id) { - fc::datastream strm(entry.data(), entry.size()); - std::vector traces; - /* Where is the equivalent for this? - eosio::state_history::trace_converter::unpack(strm, traces); - */ - return get_prunable_data_from_traces(traces, id); -} - -struct state_history_abi_serializer { - tester& chain; - abi_serializer sr; - - state_history_abi_serializer(tester& chn) - : chain(chn) - , sr(fc::json::from_string(state_history_plugin_abi).as(), - abi_serializer::create_yield_function(chain.abi_serializer_max_time)) {} - - fc::variant deserialize(const eosio::chain::bytes& data, const char* type) { - fc::datastream strm(data.data(), data.size()); - auto result = - sr.binary_to_variant(type, strm, abi_serializer::create_yield_function(chain.abi_serializer_max_time)); - BOOST_CHECK(data.size() == strm.tellp()); - return result; - } -}; - BOOST_AUTO_TEST_SUITE(test_state_history) - -BOOST_AUTO_TEST_CASE(test_trace_converter) { - - tester chain; - using namespace eosio::state_history; - - trace_converter converter; - std::map on_disk_log_entries; - - chain.control->applied_transaction.connect( - [&](std::tuple t) { - converter.add_transaction(std::get<0>(t), std::get<1>(t)); - }); - - chain.control->accepted_block.connect([&](const block_state_ptr& bs) { - converter.pack(chain.control->db(), true, bs); - }); - - chain.control->block_start.connect([&](uint32_t block_num) { - }); - - deploy_test_api(chain); - auto cfd_trace = push_test_cfd_transaction(chain); - chain.produce_blocks(1); - - BOOST_CHECK(on_disk_log_entries.size()); - - // Now deserialize the on disk trace log and make sure that the cfd exists - auto& cfd_entry = on_disk_log_entries.at(cfd_trace->block_num); - BOOST_REQUIRE(!std::holds_alternative(get_prunable_data_from_traces_bin(cfd_entry, cfd_trace->id))); - -/* Do we need this? - // prune the cfd for the block - std::vector ids{cfd_trace->id}; - fc::datastream rw_strm(cfd_entry.data(), cfd_entry.size()); - eosio::state_history::trace_converter::prune_traces(rw_strm, cfd_entry.size(), ids); - BOOST_CHECK(ids.size() == 0); - - // read the pruned trace and make sure it's pruned - BOOST_CHECK(get_prunable_data_from_traces_bin(cfd_entry, cfd_trace->id).contains()); -*/ -} - - -/* -BOOST_AUTO_TEST_CASE(test_trace_log) { - namespace bfs = boost::filesystem; - tester chain; - - scoped_temp_path state_history_dir; - fc::create_directories(state_history_dir.path); - state_history_traces_log log({ .log_dir = state_history_dir.path }); - - chain.control->applied_transaction.connect( - [&](std::tuple t) { - log.add_transaction(std::get<0>(t), std::get<1>(t)); - }); - - chain.control->accepted_block.connect([&](const block_state_ptr& bs) { log.store(chain.control->db(), bs); }); - chain.control->block_start.connect([&](uint32_t block_num) { log.block_start(block_num); } ); - - deploy_test_api(chain); - auto cfd_trace = push_test_cfd_transaction(chain); - chain.produce_blocks(1); - - auto traces = log.get_traces(cfd_trace->block_num); - BOOST_REQUIRE(traces.size()); - - BOOST_REQUIRE(!get_prunable_data_from_traces(traces, cfd_trace->id).contains()); - - std::vector ids{cfd_trace->id}; - log.prune_transactions(cfd_trace->block_num, ids); - BOOST_REQUIRE(ids.empty()); - - // we assume the nodeos has to be stopped while running, it can only be read - // correctly with restart - state_history_traces_log new_log({ .log_dir = state_history_dir.path }); - auto pruned_traces = new_log.get_traces(cfd_trace->block_num); - BOOST_REQUIRE(pruned_traces.size()); - - BOOST_CHECK(get_prunable_data_from_traces(pruned_traces, cfd_trace->id).contains()); -} -*/ - -/* Do we need this? -BOOST_AUTO_TEST_CASE(test_chain_state_log) { - - namespace bfs = boost::filesystem; - tester chain; - - scoped_temp_path state_history_dir; - fc::create_directories(state_history_dir.path); - state_history_chain_state_log log({ .log_dir = state_history_dir.path }); - - uint32_t last_accepted_block_num = 0; - - chain.control->accepted_block.connect([&](const block_state_ptr& block_state) { - log.store(chain.control->db(), block_state); - last_accepted_block_num = block_state->block_num; - }); - - chain.produce_blocks(10); - - chain::bytes entry = log.get_log_entry(last_accepted_block_num); - std::vector deltas; - eosio::input_stream deltas_bin{entry.data(), entry.data() + entry.size()}; - BOOST_CHECK_NO_THROW(from_bin(deltas, deltas_bin)); -} -*/ - -/* -struct state_history_tester_logs { - state_history_tester_logs(const state_history_config& config) {} -// : traces_log(config) , chain_state_log(config) {} - -// state_history_traces_log traces_log; -// state_history_chain_state_log chain_state_log; -}; - - - -struct state_history_tester : state_history_tester_logs, tester { - state_history_tester(const state_history_config& config) - : state_history_tester_logs(config), tester ([&](eosio::chain::controller& control) { - control.applied_transaction.connect( - [&](std::tuple t) { -// traces_log.add_transaction(std::get<0>(t), std::get<1>(t)); - }); - - control.accepted_block.connect([&](const block_state_ptr& bs) { -// traces_log.store(control.db(), bs); -// chain_state_log.store(control.db(), bs); - }); - control.block_start.connect([&](uint32_t block_num) { traces_log.block_start(block_num); } ); - }) {} -}; -*/ - -/* Do we need this? -BOOST_AUTO_TEST_CASE(test_splitted_log) { - namespace bfs = boost::filesystem; - - scoped_temp_path state_history_dir; - fc::create_directories(state_history_dir.path); - - state_history_config config{ - .log_dir = state_history_dir.path, - .retained_dir = "retained", - .archive_dir = "archive", - .stride = 20, - .max_retained_files = 5 - }; - - state_history_tester chain(config); - chain.produce_blocks(50); - - deploy_test_api(chain); - auto cfd_trace = push_test_cfd_transaction(chain); - - chain.produce_blocks(100); - - - auto log_dir = state_history_dir.path; - auto archive_dir = log_dir / "archive"; - auto retained_dir = log_dir / "retained"; - - BOOST_CHECK(bfs::exists( archive_dir / "trace_history-2-20.log" )); - BOOST_CHECK(bfs::exists( archive_dir / "trace_history-2-20.index" )); - BOOST_CHECK(bfs::exists( archive_dir / "trace_history-21-40.log" )); - BOOST_CHECK(bfs::exists( archive_dir / "trace_history-21-40.index" )); - - BOOST_CHECK(bfs::exists( archive_dir / "chain_state_history-2-20.log" )); - BOOST_CHECK(bfs::exists( archive_dir / "chain_state_history-2-20.index" )); - BOOST_CHECK(bfs::exists( archive_dir / "chain_state_history-21-40.log" )); - BOOST_CHECK(bfs::exists( archive_dir / "chain_state_history-21-40.index" )); - - BOOST_CHECK(bfs::exists( retained_dir / "trace_history-41-60.log" )); - BOOST_CHECK(bfs::exists( retained_dir / "trace_history-41-60.index" )); - BOOST_CHECK(bfs::exists( retained_dir / "trace_history-61-80.log" )); - BOOST_CHECK(bfs::exists( retained_dir / "trace_history-61-80.index" )); - BOOST_CHECK(bfs::exists( retained_dir / "trace_history-81-100.log" )); - BOOST_CHECK(bfs::exists( retained_dir / "trace_history-81-100.index" )); - BOOST_CHECK(bfs::exists( retained_dir / "trace_history-101-120.log" )); - BOOST_CHECK(bfs::exists( retained_dir / "trace_history-101-120.index" )); - BOOST_CHECK(bfs::exists( retained_dir / "trace_history-121-140.log" )); - BOOST_CHECK(bfs::exists( retained_dir / "trace_history-121-140.index" )); - - BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-41-60.log" )); - BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-41-60.index" )); - BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-61-80.log" )); - BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-61-80.index" )); - BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-81-100.log" )); - BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-81-100.index" )); - BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-101-120.log" )); - BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-101-120.index" )); - BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-121-140.log" )); - BOOST_CHECK(bfs::exists( retained_dir / "chain_state_history-121-140.index" )); - - BOOST_CHECK(chain.traces_log.get_traces(10).empty()); - BOOST_CHECK(chain.traces_log.get_traces(100).size()); - BOOST_CHECK(chain.traces_log.get_traces(140).size()); - BOOST_CHECK(chain.traces_log.get_traces(150).size()); - BOOST_CHECK(chain.traces_log.get_traces(160).empty()); - - BOOST_CHECK(chain.chain_state_log.get_log_entry(10).empty()); - BOOST_CHECK(chain.chain_state_log.get_log_entry(100).size()); - BOOST_CHECK(chain.chain_state_log.get_log_entry(140).size()); - BOOST_CHECK(chain.chain_state_log.get_log_entry(150).size()); - BOOST_CHECK(chain.chain_state_log.get_log_entry(160).empty()); - - auto traces = chain.traces_log.get_traces(cfd_trace->block_num); - BOOST_REQUIRE(traces.size()); - - BOOST_REQUIRE(!get_prunable_data_from_traces(traces, cfd_trace->id).contains()); - - std::vector ids{cfd_trace->id}; - chain.traces_log.prune_transactions(cfd_trace->block_num, ids); - BOOST_REQUIRE(ids.empty()); - - // we assume the nodeos has to be stopped while running, it can only be read - // correctly with restart - state_history_traces_log new_log(config); - auto pruned_traces = new_log.get_traces(cfd_trace->block_num); - BOOST_REQUIRE(pruned_traces.size()); - - BOOST_CHECK(get_prunable_data_from_traces(pruned_traces, cfd_trace->id).contains()); -} -*/ - - -BOOST_AUTO_TEST_CASE(test_corrupted_log_recovery) { - namespace bfs = boost::filesystem; - - scoped_temp_path state_history_dir; - fc::create_directories(state_history_dir.path); -/* - state_history_config config{ - .log_dir = state_history_dir.path, - .archive_dir = "archive", - .stride = 100, - .max_retained_files = 5 - }; -*/ - - tester chain; - chain.produce_blocks(50); - chain.close(); - - // write a few random bytes to block log indicating the last block entry is incomplete - fc::cfile logfile; - logfile.set_file_path(state_history_dir.path / "trace_history.log"); - logfile.open("ab"); - const char random_data[] = "12345678901231876983271649837"; - logfile.write(random_data, sizeof(random_data)); - - bfs::remove_all(chain.get_config().blocks_dir/"reversible"); - - tester new_chain; - new_chain.produce_blocks(50); - -// What do we need to do to verify? -// BOOST_CHECK(new_chain.traces_log.get_traces(10).size()); -// BOOST_CHECK(new_chain.chain_state_log.get_log_entry(10).size()); -} - -/* It seems like this one needs to be re-written due to underlying differences between mandel and eosio -BOOST_AUTO_TEST_CASE(test_state_result_abi) { - using namespace eosio::state_history; - - tester chain; - - trace_converter trace_cache; - std::map history; - std::optional prev_block; - - chain.control->applied_transaction.connect( - [&](std::tuple t) { - trace_cache.add_transaction(std::get<0>(t), std::get<1>(t)); - }); - - chain.control->accepted_block.connect([&](const block_state_ptr& block_state) { - auto& control = chain.control; - - fc::datastream> strm; - trace_cache.pack(control->db(), false, block_state); - - strm.seekp(0); - - eosio::state_history::get_blocks_result_v0 message; - message.head = block_position{control->head_block_num(), control->head_block_id()}; - message.last_irreversible = - eosio::state_history::block_position{control->last_irreversible_block_num(), control->last_irreversible_block_id()}; - message.this_block = eosio::state_history::block_position{block_state->block->block_num(), block_state->id}; - message.prev_block = prev_block; - message.block = block_state->block; - std::vector traces; - eosio::state_history::trace_converter::unpack(strm, traces); - message.traces = traces; - message.deltas = fc::raw::pack(eosio::state_history::create_deltas(control->db(), !prev_block)); - - prev_block = message.this_block; - history[control->head_block_num()] = fc::raw::pack(eosio::state_history::state_result{message}); - }); - - deploy_test_api(chain); - auto cfd_trace = push_test_cfd_transaction(chain); - chain.produce_blocks(1); - - state_history_abi_serializer serializer(chain); - - for (auto& [key, value] : history) { - { - // check the validity of the abi string - auto result = serializer.deserialize(value, "result"); - - auto& result_variant = result.get_array(); - BOOST_CHECK(result_variant[0].as_string() == "get_blocks_result_v1"); - auto& get_blocks_result_v1 = result_variant[1].get_object(); - - eosio::chain::bytes traces_bin; - fc::from_variant(get_blocks_result_v1["traces"], traces_bin); - BOOST_CHECK_NO_THROW( serializer.deserialize(traces_bin, "transaction_trace[]") ); - - eosio::chain::bytes deltas_bin; - fc::from_variant(get_blocks_result_v1["deltas"], deltas_bin); - BOOST_CHECK_NO_THROW( serializer.deserialize(deltas_bin, "table_delta[]")); - } - { - // check the validity of abieos ship_protocol type definitions - eosio::input_stream bin{value.data(), value.data() + value.size()}; - eosio::ship_protocol::result result; - BOOST_CHECK_NO_THROW(from_bin(result, bin)); - BOOST_CHECK(bin.remaining() == 0); - - auto& blocks_result_v1 = std::get(result); - - std::vector traces; - BOOST_CHECK_NO_THROW(blocks_result_v1.traces.unpack(traces)); - - std::vector deltas; - BOOST_CHECK_NO_THROW(blocks_result_v1.deltas.unpack(deltas)); - } - } -} -*/ - -/* what is equivalent to state_history_traces_log in mandel -BOOST_AUTO_TEST_CASE(test_traces_present) -{ - namespace bfs = boost::filesystem; - tester chain; - deploy_test_api(chain); - - scoped_temp_path state_history_dir; - fc::create_directories(state_history_dir.path); - state_history_config config; - config.log_dir = state_history_dir.path; - state_history_traces_log log(config); - - bool onblock_test_executed = false; - - chain.control->applied_transaction.connect( - [&](std::tuple t) { - const transaction_trace_ptr &trace_ptr = std::get<0>(t); - const chain::packed_transaction_ptr &transaction = std::get<1>(t); - log.add_transaction(trace_ptr, transaction); - - // see issue #9159 - if (!trace_ptr->action_traces.empty() && trace_ptr->action_traces[0].act.name == "onblock"_n) { - BOOST_CHECK(chain::is_onblock(*trace_ptr)); - trace_ptr->action_traces.clear(); - BOOST_CHECK(!chain::is_onblock(*trace_ptr)); - onblock_test_executed = true; - } - }); - chain.control->accepted_block.connect([&](const block_state_ptr& bs) { log.store(chain.control->db(), bs); }); - - auto tr_ptr = chain.create_account("newacc"_n); - - chain.produce_block(); - - BOOST_CHECK(onblock_test_executed); - - auto traces = log.get_traces(tr_ptr->block_num); - BOOST_REQUIRE_EQUAL(traces.size(), 1); - - auto trace_itr = std::find_if(traces.begin(), traces.end(), [tr_ptr](const state_history::transaction_trace& v) { - return v.get().id == tr_ptr->id; - }); - - BOOST_REQUIRE(trace_itr != traces.end()); - - auto &action_traces = trace_itr->get().action_traces; - - auto new_account_action_itr = std::find_if(action_traces.begin(), action_traces.end(), [](const state_history::action_trace& v) { - return v.get().act.name == "newaccount"_n.to_uint64_t(); - }); - - BOOST_REQUIRE(new_account_action_itr != action_traces.end()); -} -*/ - class table_deltas_tester : public tester { public: using tester::tester; @@ -631,8 +164,6 @@ BOOST_AUTO_TEST_CASE(test_deltas_account_permission_creation_and_deletion) { } - - BOOST_AUTO_TEST_CASE(test_deltas_account_permission_modification) { table_deltas_tester chain; chain.produce_block(); @@ -669,7 +200,6 @@ BOOST_AUTO_TEST_CASE(test_deltas_account_permission_modification) { } - BOOST_AUTO_TEST_CASE(test_deltas_permission_link) { table_deltas_tester chain; chain.produce_block(); @@ -696,7 +226,6 @@ BOOST_AUTO_TEST_CASE(test_deltas_permission_link) { } - BOOST_AUTO_TEST_CASE(test_deltas_global_property_history) { // Assuming max transaction delay is 45 days (default in config.hpp) table_deltas_tester chain; @@ -714,12 +243,11 @@ BOOST_AUTO_TEST_CASE(test_deltas_global_property_history) { auto &it_global_property = result.second; BOOST_REQUIRE_EQUAL(it_global_property->rows.obj.size(), 1); auto global_properties = chain.deserialize_data(it_global_property); - auto configuration = std::get(global_properties[0].configuration); + auto configuration = std::get(global_properties[0].configuration); BOOST_REQUIRE_EQUAL(configuration.max_transaction_delay, 60); } - BOOST_AUTO_TEST_CASE(test_deltas_protocol_feature_history) { table_deltas_tester chain(setup_policy::none); const auto &pfm = chain.control->get_protocol_feature_manager(); @@ -754,7 +282,6 @@ BOOST_AUTO_TEST_CASE(test_deltas_protocol_feature_history) { } - BOOST_AUTO_TEST_CASE(test_deltas_contract) { table_deltas_tester chain; chain.produce_block(); @@ -871,7 +398,6 @@ BOOST_AUTO_TEST_CASE(test_deltas_resources_history) { chain.set_transaction_headers(trx); trx.sign( chain.get_private_key( config::system_account_name, "active" ), chain.control->get_chain_id() ); chain.push_transaction( trx ); - } BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file From 1db602aa46a633a4f26f861cb211b127adc7e582 Mon Sep 17 00:00:00 2001 From: Chris Gundlach Date: Fri, 8 Jul 2022 12:02:25 -0500 Subject: [PATCH 7/7] re-implement state_history_tester_logs --- unittests/state_history_tests.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/unittests/state_history_tests.cpp b/unittests/state_history_tests.cpp index fb4ed7ed9f..08ddc0fca9 100644 --- a/unittests/state_history_tests.cpp +++ b/unittests/state_history_tests.cpp @@ -201,17 +201,29 @@ BOOST_AUTO_TEST_CASE(test_chain_state_log) { } */ -/* -struct state_history_tester_logs { - state_history_tester_logs(const state_history_config& config) {} -// : traces_log(config) , chain_state_log(config) {} +struct state_history_log_config { + const char* const name; + std::string log_filename; + std::string index_filename; + std::optional prune; +}; -// state_history_traces_log traces_log; -// state_history_chain_state_log chain_state_log; +struct state_history_tester_config { + state_history_log_config traces; + state_history_log_config chain_state; }; +struct state_history_tester_logs { + state_history_tester_logs(const state_history_tester_config& config) : + traces_log(config.traces.name, config.traces.log_filename, config.traces.index_filename, config.traces.prune), + chain_state_log(config.traces.name, config.traces.log_filename, config.traces.index_filename, config.traces.prune){} + + eosio::state_history_log traces_log; + eosio::state_history_log chain_state_log; +}; +/* struct state_history_tester : state_history_tester_logs, tester { state_history_tester(const state_history_config& config) : state_history_tester_logs(config), tester ([&](eosio::chain::controller& control) {