diff --git a/CMakeLists.txt b/CMakeLists.txt index 33394953e8..56f588859b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -316,6 +316,13 @@ if(ENABLE_COVERAGE_TESTING) set(CMAKE_CXX_FLAGS "--coverage ${CMAKE_CXX_FLAGS}") endif() +# Static libraries do not link, so a library's objects need not wait for its dependency +# libraries to finish compiling, only for their generated sources. Without this the Makefile +# generator builds target-by-target: nothing in graphene_chain starts until fc/protocol are +# archived, and no plugin starts until database.cpp (the longest TU) finishes on one core. +# Cold `make -j8 vizd cli_wallet` on an 8-core laptop: 805 s -> 305 s wall, ~2.4 -> ~4.8 cores busy. +set(CMAKE_OPTIMIZE_DEPENDENCIES ON) + add_subdirectory(thirdparty) add_subdirectory(libraries) add_subdirectory(plugins) diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index f7d9b824f4..d962cab2c1 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -33,9 +33,6 @@ set_source_files_properties("${hardfork_hpp_out}" PROPERTIES GENERATED TRUE) # Include the binary include dir include_directories("${CMAKE_CURRENT_BINARY_DIR}/include") -# Variable used below in add_library -set(hardfork_hpp_file "${hardfork_hpp_out}") - ## SORT .cpp by most likely to change / break compile add_library(graphene_chain ${VIZ_LIBRARY_TYPE} @@ -104,10 +101,12 @@ add_library(graphene_chain ${VIZ_LIBRARY_TYPE} include/graphene/chain/paid_subscription_objects.hpp include/graphene/chain/pm_objects.hpp - ${hardfork_hpp_file} ) -add_dependencies(graphene_chain graphene_protocol graphene_utilities build_hardfork_hpp) +# Only the generated header is a real build-order dependency. Library-to-library order comes +# from target_link_libraries; an explicit add_dependencies here would defeat +# CMAKE_OPTIMIZE_DEPENDENCIES and make every chain TU wait for protocol to finish archiving. +add_dependencies(graphene_chain build_hardfork_hpp) target_link_libraries(graphene_chain graphene_protocol graphene_utilities fc chainbase appbase ${PATCH_MERGE_LIB}) target_include_directories(graphene_chain PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../../") diff --git a/tests/consensus_sim/CMakeLists.txt b/tests/consensus_sim/CMakeLists.txt index e286941967..9472e8d95d 100644 --- a/tests/consensus_sim/CMakeLists.txt +++ b/tests/consensus_sim/CMakeLists.txt @@ -67,6 +67,7 @@ set(SCENARIO_SOURCES scenarios/test_routable_endpoint.cpp scenarios/test_p2p_slot_scale.cpp scenarios/test_db_invariants.cpp + scenarios/test_operation_variant.cpp ) # These scenarios require an actual HF14 activation and never soft-skip. diff --git a/tests/consensus_sim/scenarios/test_operation_variant.cpp b/tests/consensus_sim/scenarios/test_operation_variant.cpp new file mode 100644 index 0000000000..1e07cdc4f3 --- /dev/null +++ b/tests/consensus_sim/scenarios/test_operation_variant.cpp @@ -0,0 +1,59 @@ +// Contract of the `operation` static_variant: every alternative round-trips through the raw +// and JSON serializers under its own tag, tags are what the type list says they are, and an +// out-of-range tag is rejected instead of dispatching into garbage. The variant index is the +// consensus op-id, so this pins the dispatch machinery itself, not any one operation. + +#include + +#include +#include + +using namespace graphene::protocol; + +BOOST_AUTO_TEST_SUITE(operation_variant) + +BOOST_AUTO_TEST_CASE(every_alternative_round_trips_under_its_tag) { + for (int i = 0; i < operation::count(); ++i) { + operation op; + op.set_which(i); + BOOST_REQUIRE_EQUAL(op.which(), i); + + auto bytes = fc::raw::pack(op); + BOOST_CHECK_EQUAL(fc::raw::unpack(bytes).which(), i); + + fc::variant v; + fc::to_variant(op, v); + operation from_json; + fc::from_variant(v, from_json); + BOOST_CHECK_EQUAL(from_json.which(), i); + + operation copied(op); + operation moved(std::move(copied)); + BOOST_CHECK_EQUAL(moved.which(), i); + operation assigned; + assigned = op; + BOOST_CHECK_EQUAL(assigned.which(), i); + } +} + +BOOST_AUTO_TEST_CASE(tags_follow_the_type_list) { + BOOST_CHECK_EQUAL(int(operation::tag::value), 0); + BOOST_CHECK_EQUAL(int(operation::tag::value), 2); + BOOST_CHECK_EQUAL(int(operation::tag::value), operation::count() - 1); + + operation op = transfer_operation(); + BOOST_CHECK_EQUAL(op.which(), int(operation::tag::value)); + op.get().memo = "x"; + BOOST_CHECK_EQUAL(op.get().memo, "x"); + BOOST_CHECK_THROW(op.get(), fc::assert_exception); +} + +BOOST_AUTO_TEST_CASE(out_of_range_tag_is_rejected) { + operation op; + BOOST_CHECK_THROW(op.set_which(operation::count()), fc::exception); + + auto bytes = fc::raw::pack(fc::unsigned_int(operation::count() + 7)); + BOOST_CHECK_THROW(fc::raw::unpack(bytes), fc::exception); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/thirdparty/fc b/thirdparty/fc index 679e89e9cd..7889e2f73a 160000 --- a/thirdparty/fc +++ b/thirdparty/fc @@ -1 +1 @@ -Subproject commit 679e89e9cd503b97b6b1d7e436418408c0f9b35a +Subproject commit 7889e2f73a3918b3855efad69869ec08952a3140