diff --git a/libraries/chain/transaction.cpp b/libraries/chain/transaction.cpp index ebd6297420f..4051ee0a0bd 100644 --- a/libraries/chain/transaction.cpp +++ b/libraries/chain/transaction.cpp @@ -484,6 +484,7 @@ packed_transaction::packed_transaction(const packed_transaction_v0& other, bool unpacked_trx(other.unpacked_trx), trx_id(other.id()) { + EOS_ASSERT( legacy, transaction_exception, "Full type of prunable_data_type is not supported" ); estimated_size = calculate_estimated_size(); } @@ -498,16 +499,18 @@ packed_transaction::packed_transaction(packed_transaction_v0&& other, bool legac unpacked_trx(std::move(other.unpacked_trx)), trx_id(other.id()) { + EOS_ASSERT( legacy, transaction_exception, "Full type of prunable_data_type is not supported" ); estimated_size = calculate_estimated_size(); } packed_transaction_v0_ptr packed_transaction::to_packed_transaction_v0() const { const auto* sigs = get_signatures(); - const auto* context_free_data = get_context_free_data(); - signed_transaction strx( transaction( get_transaction() ), + EOS_ASSERT( std::holds_alternative(prunable_data.prunable_data), transaction_exception, "Failed to get full_legacy variant in to_packed_transaction_v0" ); + auto& legacy = std::get(prunable_data.prunable_data); + return std::make_shared( packed_trx, sigs != nullptr ? *sigs : vector(), - context_free_data != nullptr ? *context_free_data : vector() ); - return std::make_shared( std::move( strx ), get_compression() ); + legacy.packed_context_free_data, + compression); } uint32_t packed_transaction::get_unprunable_size()const { diff --git a/unittests/misc_tests.cpp b/unittests/misc_tests.cpp index eedbee22861..b74a6e5c451 100644 --- a/unittests/misc_tests.cpp +++ b/unittests/misc_tests.cpp @@ -694,6 +694,14 @@ BOOST_AUTO_TEST_CASE(alphabetic_sort) } FC_LOG_AND_RETHROW() } +static void verify_packed_transaction_conversion(const packed_transaction_v0& original, const packed_transaction_v0_ptr final) { + // prunable_size and unprunable_size must be maintained + BOOST_CHECK_EQUAL(original.get_prunable_size(), final->get_prunable_size()); + BOOST_CHECK_EQUAL(original.get_unprunable_size(), final->get_unprunable_size()); + // context_free_data must be maintained + BOOST_REQUIRE_EQUAL(original.get_context_free_data().size(), final->get_context_free_data().size()); + BOOST_CHECK(std::equal(original.get_context_free_data().begin(), original.get_context_free_data().end(), final->get_context_free_data().begin())); +} BOOST_AUTO_TEST_CASE(transaction_test) { try { testing::TESTER test; @@ -826,6 +834,49 @@ BOOST_AUTO_TEST_CASE(transaction_test) { try { BOOST_CHECK( packed != fc::raw::pack( static_cast(pkt8.get_transaction()) )); BOOST_CHECK( packed == pkt8.get_packed_transaction() ); // extra maintained + // Round trip from v0 to v1 to v0 (packed_transaction_v0 to + // packed_transaction_v0) with extra packed transaction and + // extra packed context free data + auto packed_context_free_data_extra = pkt6.to_packed_transaction_v0()->get_packed_context_free_data(); + packed_context_free_data_extra.push_back('e'); + packed_context_free_data_extra.push_back('x'); + packed_context_free_data_extra.push_back('t'); + packed_context_free_data_extra.push_back('r'); + packed_context_free_data_extra.push_back('a'); + + packed_transaction_v0 pkt_v0_original( packed, *pkt6.get_signatures(),packed_context_free_data_extra, packed_transaction_v0::compression_type::none ); + packed_transaction pkt_v0_to_v1(pkt_v0_original, true); + auto pkt_v0_final = pkt_v0_to_v1.to_packed_transaction_v0(); + BOOST_CHECK_EQUAL(pkt.get_transaction().id(), pkt_v0_final->get_transaction().id()); + BOOST_CHECK( packed != fc::raw::pack( static_cast(pkt_v0_final->get_transaction()) )); + BOOST_CHECK( packed == pkt_v0_final->get_packed_transaction() ); + verify_packed_transaction_conversion(pkt_v0_original, pkt_v0_final); + + // Round trip from v0 to v1 to v0 (packed_transaction_v0 to + // packed_transaction_v0) with empty context free data + signed_transaction empty_cfd_trx; + empty_cfd_trx.context_free_actions.push_back({ {}, "eosio"_n, ""_n, bytes() }); + empty_cfd_trx.context_free_data.push_back(bytes()); + test.set_transaction_headers(empty_cfd_trx); + empty_cfd_trx.sign( test.get_private_key( "eosio"_n, "active" ), test.control->get_chain_id() ); + packed_transaction_v0 pkt_v0_empty_cfd_original(empty_cfd_trx); + packed_transaction pkt_v0_to_v1_empty_cfd(pkt_v0_empty_cfd_original, true); + auto pkt_v0_empty_cfd_final = pkt_v0_to_v1_empty_cfd.to_packed_transaction_v0(); + verify_packed_transaction_conversion(pkt_v0_empty_cfd_original, pkt_v0_empty_cfd_final); + + // Round trip from v1 to v0 to v1 (packed_transaction to packed_transaction) + // with extra packed transaction and extra packed context free data + auto pkt_v1_original {pkt_v0_to_v1}; + auto pkt_v1_to_v0 = pkt_v1_original.to_packed_transaction_v0(); + packed_transaction pkt_v1_final(*pkt_v1_to_v0, true); + + BOOST_CHECK_EQUAL(pkt.get_transaction().id(), pkt_v1_final.get_transaction().id()); + BOOST_CHECK( packed != fc::raw::pack( static_cast(pkt_v1_final.get_transaction()) )); + BOOST_CHECK( packed == pkt_v1_final.get_packed_transaction() ); + BOOST_CHECK_EQUAL(pkt_v1_original.get_prunable_size(), pkt_v1_final.get_prunable_size()); + BOOST_CHECK_EQUAL(pkt_v1_original.get_unprunable_size(), pkt_v1_final.get_unprunable_size()); + BOOST_REQUIRE_EQUAL(pkt_v1_original.get_context_free_data()->size(), pkt_v1_final.get_context_free_data()->size()); + BOOST_CHECK(std::equal(pkt_v1_original.get_context_free_data()->begin(), pkt_v1_original.get_context_free_data()->end(), pkt_v1_final.get_context_free_data()->begin())); } FC_LOG_AND_RETHROW() }