Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
test_trx_retry_db.cpp File Reference
#include <boost/test/included/unit_test.hpp>
#include <sysio/chain_plugin/trx_retry_db.hpp>
#include <sysio/testing/tester.hpp>
#include <sysio/chain/controller.hpp>
#include <sysio/chain/genesis_state.hpp>
#include <sysio/chain/thread_utils.hpp>
#include <sysio/chain/transaction_metadata.hpp>
#include <sysio/chain/trace.hpp>
#include <sysio/chain/name.hpp>
#include <appbase/application.hpp>
#include <sysio/chain/plugin_interface.hpp>
#include <fc/mock_time.hpp>
#include <fc/bitutil.hpp>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem.hpp>
#include <thread>
#include <condition_variable>
#include <deque>
#include <memory>
Include dependency graph for test_trx_retry_db.cpp:

Go to the source code of this file.

Classes

struct  sysio::test::detail::testit
 

Namespaces

namespace  sysio
 
namespace  sysio::test
 
namespace  sysio::test::detail
 

Macros

#define BOOST_TEST_MODULE   transaction_retry
 

Functions

 BOOST_AUTO_TEST_CASE (trx_retry_logic)
 

Macro Definition Documentation

◆ BOOST_TEST_MODULE

#define BOOST_TEST_MODULE   transaction_retry

Definition at line 1 of file test_trx_retry_db.cpp.

Function Documentation

◆ BOOST_AUTO_TEST_CASE()

BOOST_AUTO_TEST_CASE ( trx_retry_logic )

Definition at line 199 of file test_trx_retry_db.cpp.

199 {
200 boost::filesystem::path temp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
201
202 try {
204
205 // just need a controller for trx_retry_db, doesn't actually have to do anything
206 std::optional<controller> chain;
208 {
210 chain_config.blocks_dir = temp;
211 chain_config.state_dir = temp;
212
213 const auto& genesis_chain_id = gs.compute_chain_id();
215 chain.emplace( chain_config, std::move( pfs ), genesis_chain_id );
216 chain->add_indices();
217 }
218
219 // control time by using set_now, call before spawning any threads
220 auto pnow = boost::posix_time::time_from_string("2022-04-04 4:44:44.000");
222
223 // run app() so that channels::transaction_ack work
224 std::thread app_thread( [&]() {
225 appbase::app().exec();
226 } );
227
228 size_t max_mem_usage_size = 5ul*1024*1024*1024;
229 fc::microseconds retry_interval = fc::seconds(10);
230 boost::posix_time::seconds pretry_interval = boost::posix_time::seconds(10);
231 BOOST_REQUIRE(retry_interval.count() == pretry_interval.total_microseconds());
232 fc::microseconds max_expiration_time = fc::hours(1);
233 trx_retry_db trx_retry( *chain, max_mem_usage_size, retry_interval, max_expiration_time, fc::seconds(10) );
234
235 // provide a subscriber for the transaction_ack channel
236 blocking_queue<std::pair<fc::exception_ptr, packed_transaction_ptr>> transactions_acked;
237 plugin_interface::compat::channels::transaction_ack::channel_type::handle incoming_transaction_ack_subscription =
239 [&transactions_acked]( const std::pair<fc::exception_ptr, packed_transaction_ptr>& t){
240 transactions_acked.push( t );
241 } );
242
243
244 // test get_max_expiration_time
245 BOOST_CHECK( fc::time_point::now() + fc::hours(1) == fc::time_point( trx_retry.get_max_expiration_time() ) );
246
247 //
248 // test expired, not in a block
249 //
250 auto lib = std::optional<uint16_t>{};
251 auto trx_1 = make_unique_trx(chain->get_chain_id(), fc::seconds(2), 1);
252 bool trx_1_expired = false;
253 trx_retry.track_transaction( trx_1, lib, [&trx_1_expired](const std::variant<fc::exception_ptr, std::unique_ptr<fc::variant>>& result){
254 BOOST_REQUIRE( std::holds_alternative<fc::exception_ptr>(result) );
255 BOOST_CHECK_EQUAL( std::get<fc::exception_ptr>(result)->code(), expired_tx_exception::code_value );
256 trx_1_expired = true;
257 } );
258 auto trx_2 = make_unique_trx(chain->get_chain_id(), fc::seconds(4), 2);
259 bool trx_2_expired = false;
260 trx_retry.track_transaction( trx_2, lib, [&trx_2_expired](const std::variant<fc::exception_ptr, std::unique_ptr<fc::variant>>& result){
261 BOOST_REQUIRE( std::holds_alternative<fc::exception_ptr>(result) );
262 BOOST_CHECK_EQUAL( std::get<fc::exception_ptr>(result)->code(), expired_tx_exception::code_value );
263 trx_2_expired = true;
264 } );
265 // signal block, nothing should be expired as now has not changed
266 auto bsp1 = make_block_state(1, {});
267 trx_retry.on_block_start(1);
268 trx_retry.on_accepted_block(bsp1);
269 trx_retry.on_irreversible_block(bsp1);
270 BOOST_CHECK(!trx_1_expired);
271 BOOST_CHECK(!trx_2_expired);
272 // increase time by 3 seconds to expire first
273 pnow += boost::posix_time::seconds(3);
275 // signal block, first transaction should expire
276 auto bsp2 = make_block_state(2, {});
277 trx_retry.on_block_start(2);
278 trx_retry.on_accepted_block(bsp2);
279 trx_retry.on_irreversible_block(bsp2);
280 BOOST_CHECK(trx_1_expired);
281 BOOST_CHECK(!trx_2_expired);
282 // increase time by 2 seconds to expire second
283 pnow += boost::posix_time::seconds(2);
285 // signal block, second transaction should expire
286 auto bsp3 = make_block_state(3, {});
287 trx_retry.on_block_start(3);
288 trx_retry.on_accepted_block(bsp3);
289 trx_retry.on_irreversible_block(bsp3);
290 BOOST_CHECK(trx_1_expired);
291 BOOST_CHECK(trx_2_expired);
292 BOOST_CHECK_EQUAL(0, trx_retry.size());
293
294 //
295 // test resend trx if not in block
296 //
297 auto trx_3 = make_unique_trx(chain->get_chain_id(), fc::seconds(30), 3);
298 bool trx_3_expired = false;
299 trx_retry.track_transaction( trx_3, lib, [&trx_3_expired](const std::variant<fc::exception_ptr, std::unique_ptr<fc::variant>>& result){
300 BOOST_REQUIRE( std::holds_alternative<fc::exception_ptr>(result) );
301 BOOST_CHECK_EQUAL( std::get<fc::exception_ptr>(result)->code(), expired_tx_exception::code_value );
302 trx_3_expired = true;
303 } );
304 // increase time by 1 seconds, so trx_4 retry interval diff than 3
305 pnow += boost::posix_time::seconds(1);
307 auto trx_4 = make_unique_trx(chain->get_chain_id(), fc::seconds(30), 4);
308 bool trx_4_expired = false;
309 trx_retry.track_transaction( trx_4, lib, [&trx_4_expired](const std::variant<fc::exception_ptr, std::unique_ptr<fc::variant>>& result){
310 BOOST_REQUIRE( std::holds_alternative<fc::exception_ptr>(result) );
311 BOOST_CHECK_EQUAL( std::get<fc::exception_ptr>(result)->code(), expired_tx_exception::code_value );
312 trx_4_expired = true;
313 } );
314 // increase time by interval to cause send
315 pnow += (pretry_interval - boost::posix_time::seconds(1));
317 // signal block, transaction 3 should be sent
318 auto bsp4 = make_block_state(4, {});
319 trx_retry.on_block_start(4);
320 trx_retry.on_accepted_block(bsp4);
321 BOOST_CHECK( get_id(transactions_acked.pop().second) == 3 );
322 BOOST_CHECK_EQUAL( 0, transactions_acked.size() );
323 // increase time by 1 seconds, so trx_4 is sent
324 pnow += boost::posix_time::seconds(1);
326 // signal block, transaction 4 should be sent
327 auto bsp5 = make_block_state(5, {});
328 trx_retry.on_block_start(5);
329 trx_retry.on_accepted_block(bsp5);
330 BOOST_CHECK( get_id(transactions_acked.pop().second) == 4 );
331 BOOST_CHECK_EQUAL( 0, transactions_acked.size() );
332 BOOST_CHECK(!trx_3_expired);
333 BOOST_CHECK(!trx_4_expired);
334 // go ahead and expire them now
335 pnow += boost::posix_time::seconds(30);
337 auto bsp6 = make_block_state(6, {});
338 trx_retry.on_block_start(6);
339 trx_retry.on_accepted_block(bsp6);
340 trx_retry.on_irreversible_block(bsp4);
341 trx_retry.on_irreversible_block(bsp5);
342 trx_retry.on_irreversible_block(bsp6);
343 BOOST_CHECK(trx_3_expired);
344 BOOST_CHECK(trx_4_expired);
345 BOOST_CHECK_EQUAL(0, trx_retry.size());
346
347 //
348 // test reply to user
349 //
350 auto trx_5 = make_unique_trx(chain->get_chain_id(), fc::seconds(30), 5);
351 bool trx_5_variant = false;
352 trx_retry.track_transaction( trx_5, lib, [&trx_5_variant](const std::variant<fc::exception_ptr, std::unique_ptr<fc::variant>>& result){
353 BOOST_REQUIRE( std::holds_alternative<std::unique_ptr<fc::variant>>(result) );
354 BOOST_CHECK( !!std::get<std::unique_ptr<fc::variant>>(result) );
355 trx_5_variant = true;
356 } );
357 // increase time by 1 seconds, so trx_6 retry interval diff than 5
358 pnow += boost::posix_time::seconds(1);
360 auto trx_6 = make_unique_trx(chain->get_chain_id(), fc::seconds(30), 6);
361 bool trx_6_variant = false;
362 trx_retry.track_transaction( trx_6, std::optional<uint32_t>(2), [&trx_6_variant](const std::variant<fc::exception_ptr, std::unique_ptr<fc::variant>>& result){
363 BOOST_REQUIRE( std::holds_alternative<std::unique_ptr<fc::variant>>(result) );
364 BOOST_CHECK( !!std::get<std::unique_ptr<fc::variant>>(result) );
365 trx_6_variant = true;
366 } );
367 // not in block 7, so not returned to user
368 auto bsp7 = make_block_state(7, {});
369 trx_retry.on_block_start(7);
370 trx_retry.on_accepted_block(bsp7);
371 BOOST_CHECK(!trx_5_variant);
372 BOOST_CHECK(!trx_6_variant);
373 // 5,6 in block 8
374 pnow += boost::posix_time::seconds(1); // new block, new time
376 trx_retry.on_block_start(8);
377 auto trace_5 = make_transaction_trace( trx_5, 8);
378 auto trace_6 = make_transaction_trace( trx_6, 8);
379 trx_retry.on_applied_transaction(trace_5, trx_5);
380 trx_retry.on_applied_transaction(trace_6, trx_6);
381 auto bsp8 = make_block_state(8, {trx_5, trx_6});
382 trx_retry.on_accepted_block(bsp8);
383 BOOST_CHECK(!trx_5_variant);
384 BOOST_CHECK(!trx_6_variant);
385 // need 2 blocks before 6 returned to user
386 pnow += boost::posix_time::seconds(1); // new block, new time
388 auto bsp9 = make_block_state(9, {});
389 trx_retry.on_block_start(9);
390 trx_retry.on_accepted_block(bsp9);
391 BOOST_CHECK(!trx_5_variant);
392 BOOST_CHECK(!trx_6_variant);
393 pnow += boost::posix_time::seconds(1); // new block, new time
395 auto bsp10 = make_block_state(10, {});
396 trx_retry.on_block_start(10);
397 trx_retry.on_accepted_block(bsp10);
398 BOOST_CHECK(!trx_5_variant);
399 BOOST_CHECK(trx_6_variant);
400 // now signal lib for trx_6
401 pnow += boost::posix_time::seconds(1); // new block, new time
403 auto bsp11 = make_block_state(11, {});
404 trx_retry.on_block_start(11);
405 trx_retry.on_accepted_block(bsp11);
406 BOOST_CHECK(!trx_5_variant);
407 BOOST_CHECK(trx_6_variant);
408 trx_retry.on_irreversible_block(bsp7);
409 BOOST_CHECK(!trx_5_variant);
410 BOOST_CHECK(trx_6_variant);
411 trx_retry.on_irreversible_block(bsp8);
412 BOOST_CHECK(trx_5_variant);
413 BOOST_CHECK(trx_6_variant);
414 BOOST_CHECK_EQUAL(0, trx_retry.size());
415
416 //
417 // test forking
418 //
419 auto trx_7 = make_unique_trx(chain->get_chain_id(), fc::seconds(30), 7);
420 bool trx_7_variant = false;
421 trx_retry.track_transaction( trx_7, lib, [&trx_7_variant](const std::variant<fc::exception_ptr, std::unique_ptr<fc::variant>>& result){
422 BOOST_REQUIRE( std::holds_alternative<std::unique_ptr<fc::variant>>(result) );
423 BOOST_CHECK( !!std::get<std::unique_ptr<fc::variant>>(result) );
424 trx_7_variant = true;
425 } );
426 // increase time by 1 seconds, so trx_8 retry interval diff than 7
427 pnow += boost::posix_time::seconds(1);
429 auto trx_8 = make_unique_trx(chain->get_chain_id(), fc::seconds(30), 8);
430 bool trx_8_variant = false;
431 trx_retry.track_transaction( trx_8, std::optional<uint32_t>(3), [&trx_8_variant](const std::variant<fc::exception_ptr, std::unique_ptr<fc::variant>>& result){
432 BOOST_REQUIRE( std::holds_alternative<std::unique_ptr<fc::variant>>(result) );
433 BOOST_CHECK( !!std::get<std::unique_ptr<fc::variant>>(result) );
434 trx_8_variant = true;
435 } );
436 // one to expire, will be forked out never to return
437 auto trx_9 = make_unique_trx(chain->get_chain_id(), fc::seconds(30), 9);
438 bool trx_9_expired = false;
439 trx_retry.track_transaction( trx_9, lib, [&trx_9_expired](const std::variant<fc::exception_ptr, std::unique_ptr<fc::variant>>& result){
440 BOOST_REQUIRE( std::holds_alternative<fc::exception_ptr>(result) );
441 BOOST_CHECK_EQUAL( std::get<fc::exception_ptr>(result)->code(), expired_tx_exception::code_value );
442 trx_9_expired = true;
443 } );
444
445 // not in block 12
446 auto bsp12 = make_block_state(12, {});
447 trx_retry.on_block_start(12);
448 trx_retry.on_accepted_block(bsp12);
449 BOOST_CHECK(!trx_7_variant);
450 BOOST_CHECK(!trx_8_variant);
451 BOOST_CHECK(!trx_9_expired);
452 // 7,8 in block 13
453 pnow += boost::posix_time::seconds(1); // new block, new time
455 trx_retry.on_block_start(13);
456 auto trace_7 = make_transaction_trace( trx_7, 13);
457 auto trace_8 = make_transaction_trace( trx_8, 13);
458 auto trace_9 = make_transaction_trace( trx_9, 13);
459 trx_retry.on_applied_transaction(trace_7, trx_7);
460 trx_retry.on_applied_transaction(trace_8, trx_8);
461 trx_retry.on_applied_transaction(trace_9, trx_9);
462 auto bsp13 = make_block_state(13, {trx_7, trx_8, trx_9});
463 trx_retry.on_accepted_block(bsp13);
464 BOOST_CHECK(!trx_7_variant);
465 BOOST_CHECK(!trx_8_variant);
466 BOOST_CHECK(!trx_9_expired);
467 // need 3 blocks before 8 returned to user
468 pnow += boost::posix_time::seconds(1); // new block, new time, 1st block
470 auto bsp14 = make_block_state(14, {});
471 trx_retry.on_block_start(14);
472 trx_retry.on_accepted_block(bsp14);
473 BOOST_CHECK(!trx_7_variant);
474 BOOST_CHECK(!trx_8_variant);
475 BOOST_CHECK(!trx_9_expired);
476 pnow += boost::posix_time::seconds(1); // new block, new time, 2nd block
478 auto bsp15 = make_block_state(15, {});
479 trx_retry.on_block_start(15);
480 trx_retry.on_accepted_block(bsp15);
481 BOOST_CHECK(!trx_7_variant);
482 BOOST_CHECK(!trx_8_variant);
483 BOOST_CHECK(!trx_9_expired);
484 // now fork out including 13 which had traces, trx_9 will be forked out and not re-appear
485 pnow += boost::posix_time::seconds(1); // new block, new time
487 trx_retry.on_block_start(13);
488 // should still be tracking them
489 BOOST_CHECK_EQUAL(3, trx_retry.size());
490 // now produce an empty 13
491 auto bsp13b = make_block_state(13, {}); // now 13 has no traces
492 trx_retry.on_accepted_block(bsp13b);
493 // produced another empty block
494 pnow += boost::posix_time::seconds(1); // new block, new time
496 trx_retry.on_block_start(14);
497 // now produce an empty 14
498 auto bsp14b = make_block_state(14, {}); // empty
499 trx_retry.on_accepted_block(bsp14b);
500 // produce block with 7,8
501 trx_retry.on_block_start(15);
502 auto trace_7b = make_transaction_trace( trx_7, 15);
503 auto trace_8b = make_transaction_trace( trx_8, 15);
504 trx_retry.on_applied_transaction(trace_7b, trx_7);
505 trx_retry.on_applied_transaction(trace_8b, trx_8);
506 auto bsp15b = make_block_state(15, {trx_7, trx_8});
507 trx_retry.on_accepted_block(bsp15b);
508 // need 3 blocks before 8 returned to user
509 pnow += boost::posix_time::seconds(1); // new block, new time
511 auto bsp16 = make_block_state(16, {});
512 trx_retry.on_block_start(16);
513 trx_retry.on_accepted_block(bsp16);
514 BOOST_CHECK(!trx_7_variant);
515 BOOST_CHECK(!trx_8_variant);
516 BOOST_CHECK(!trx_9_expired);
517 pnow += boost::posix_time::seconds(1); // new block, new time
519 auto bsp17 = make_block_state(17, {});
520 trx_retry.on_block_start(17);
521 trx_retry.on_accepted_block(bsp17);
522 BOOST_CHECK(!trx_7_variant);
523 BOOST_CHECK(!trx_8_variant);
524 BOOST_CHECK(!trx_9_expired);
525 pnow += boost::posix_time::seconds(1); // new block, new time, 3rd one
527 auto bsp18 = make_block_state(18, {});
528 trx_retry.on_block_start(18);
529 trx_retry.on_accepted_block(bsp18);
530 BOOST_CHECK(!trx_7_variant);
531 BOOST_CHECK(trx_8_variant);
532 BOOST_CHECK(!trx_9_expired);
533 trx_retry.on_irreversible_block(bsp9);
534 trx_retry.on_irreversible_block(bsp10);
535 trx_retry.on_irreversible_block(bsp11);
536 trx_retry.on_irreversible_block(bsp12);
537 trx_retry.on_irreversible_block(bsp13b);
538 trx_retry.on_irreversible_block(bsp14b);
539 BOOST_CHECK(!trx_7_variant);
540 BOOST_CHECK(trx_8_variant);
541 BOOST_CHECK(!trx_9_expired);
542 trx_retry.on_irreversible_block(bsp15b);
543 BOOST_CHECK(trx_7_variant);
544 BOOST_CHECK(trx_8_variant);
545 BOOST_CHECK(!trx_9_expired);
546 // verify trx_9 expires
547 pnow += boost::posix_time::seconds(21); // new block, new time, before expire
549 auto bsp19 = make_block_state(19, {});
550 trx_retry.on_block_start(19);
551 trx_retry.on_accepted_block(bsp19);
552 trx_retry.on_irreversible_block(bsp15);
553 trx_retry.on_irreversible_block(bsp16);
554 trx_retry.on_irreversible_block(bsp17);
555 trx_retry.on_irreversible_block(bsp18);
556 trx_retry.on_irreversible_block(bsp19);
557 BOOST_CHECK(trx_7_variant);
558 BOOST_CHECK(trx_8_variant);
559 BOOST_CHECK(!trx_9_expired);
560 pnow += boost::posix_time::seconds(1); // new block, new time, trx_9 now expired
562 auto bsp20 = make_block_state(20, {});
563 trx_retry.on_block_start(20);
564 trx_retry.on_accepted_block(bsp20);
565 // waits for LIB
566 BOOST_CHECK(trx_7_variant);
567 BOOST_CHECK(trx_8_variant);
568 BOOST_CHECK(!trx_9_expired);
569 trx_retry.on_irreversible_block(bsp20);
570 BOOST_CHECK(trx_7_variant);
571 BOOST_CHECK(trx_8_variant);
572 BOOST_CHECK(trx_9_expired);
573 BOOST_CHECK_EQUAL(0, trx_retry.size());
574
575 //
576 // test reply to user for num_blocks == 0
577 //
578 auto trx_10 = make_unique_trx(chain->get_chain_id(), fc::seconds(30), 10);
579 bool trx_10_variant = false;
580 trx_retry.track_transaction( trx_10, std::optional<uint32_t>(0), [&trx_10_variant](const std::variant<fc::exception_ptr, std::unique_ptr<fc::variant>>& result){
581 BOOST_REQUIRE( std::holds_alternative<std::unique_ptr<fc::variant>>(result) );
582 BOOST_CHECK( !!std::get<std::unique_ptr<fc::variant>>(result) );
583 trx_10_variant = true;
584 } );
585 auto trx_11 = make_unique_trx(chain->get_chain_id(), fc::seconds(30), 11);
586 bool trx_11_variant = false;
587 trx_retry.track_transaction( trx_11, std::optional<uint32_t>(1), [&trx_11_variant](const std::variant<fc::exception_ptr, std::unique_ptr<fc::variant>>& result){
588 BOOST_REQUIRE( std::holds_alternative<std::unique_ptr<fc::variant>>(result) );
589 BOOST_CHECK( !!std::get<std::unique_ptr<fc::variant>>(result) );
590 trx_11_variant = true;
591 } );
592 // seen in block immediately
593 trx_retry.on_block_start(21);
594 auto trace_10 = make_transaction_trace( trx_10, 21);
595 auto trace_11 = make_transaction_trace( trx_11, 21);
596 trx_retry.on_applied_transaction(trace_10, trx_10);
597 trx_retry.on_applied_transaction(trace_11, trx_11);
598 auto bsp21 = make_block_state(21, {trx_10, trx_11});
599 trx_retry.on_accepted_block(bsp21);
600 BOOST_CHECK(trx_10_variant);
601 BOOST_CHECK(!trx_11_variant);
602 pnow += boost::posix_time::seconds(1); // new block, new time
604 auto bsp22 = make_block_state(22, {});
605 trx_retry.on_block_start(22);
606 trx_retry.on_accepted_block(bsp22);
607 BOOST_CHECK(trx_10_variant);
608 BOOST_CHECK(trx_11_variant);
609 BOOST_CHECK_EQUAL(0, trx_retry.size());
610
611
612 // shutdown
613 appbase::app().quit();
614 app_thread.join();
615
616 } catch ( ... ) {
617 boost::filesystem::remove_all( temp );
618 throw;
619 }
620 boost::filesystem::remove_all( temp );
621}
auto get_channel() -> std::enable_if_t< is_channel_decl< ChannelDecl >::value, typename ChannelDecl::channel_type & >
logger & set_log_level(log_level e)
Definition logger.cpp:100
static logger get(const fc::string &name=DEFAULT_LOGGER)
Definition logger.cpp:88
constexpr int64_t count() const
Definition time.hpp:26
static void set_now(time_type t)
Definition mock_time.cpp:14
static time_point now()
Definition time.cpp:14
#define DEFAULT_LOGGER
Definition logger.hpp:7
static const Segment gs(Segment::gs)
application & app()
std::shared_ptr< exception > exception_ptr
constexpr microseconds hours(int64_t h)
Definition time.hpp:35
constexpr microseconds seconds(int64_t s)
Definition time.hpp:32
auto make_block_state(chain::block_id_type previous, uint32_t height, uint32_t slot, chain::name producer, std::vector< chain::packed_transaction > trxs)
v1 Producer-voted blockchain configuration parameters
Here is the call graph for this function: