Skip to main content

Replaying Transactions

The thru-replay tool can be used to replay transactions run on Thru, and supports debugging with GDB. This can help you debug crashes and other issues in your program.

Step 1: Build and run with debug information

To make it easier to debug programs, you should build your program with debug information.
In C and C++, you can do this with the SDK_EXTRAS environment variable:
SDK_EXTRAS=debug make
In addition to the .bin file, you’ll find a file at target/thruvm/bin/<program-name>.elf that contains the program’s debug information. Make a note of this file for later use. After this, upload your program in debug mode to the network, and run a transaction.
Note that this step is optional, and may not be possible if you are debugging a transaction that has already been run. However, it makes it significantly easier to debug your program.

Step 2: Prepare the command to run with GDB

Next, you’ll need to gather all the information to replay your program. You’ll need:
  • The transaction signature. It will look something like this:
    tsX2EQZzPxVgI23KmdAByeVj-yZ9JE-46q_AhjURj0vRnHdMRP3at6H_dVXDFdUtUwnW_ICnLnk0ROJWWdTIWbDh1P
    
  • For each program in your transaction, you’ll need the program’s address as well as the path to the program’s debug information. For instance:
    tafhdJHH_OVQYN4-Cimt7Y1XclSytf9Ox_iuetV8CKmz=./build/thruvm/bin/tn_token_program_rust.elf
    
    If you don’t have the debug information for a program, you can skip it. However, you won’t be able to view the source information for that program.

Step 3: Run the command

Now you can run the command to replay the transaction with GDB. You’ll need to pass the transaction signature, and for each program in your transaction, you’ll need to pass the program’s address and the path to the program’s debug information.
thru-replay --gdb \
  --signature $transaction-signature \
  --elf $program-address-1=$program-debug-info-path-1 \
  --elf $program-address-2=$program-debug-info-path-2 ...
For example:
thru-replay --gdb \
  --signature tsX2EQZzPxVgI23KmdAByeVj-yZ9JE-46q_AhjURj0vRnHdMRP3at6H_dVXDFdUtUwnW_ICnLnk0ROJWWdTIWbDh1P \
  --elf tafhdJHH_OVQYN4-Cimt7Y1XclSytf9Ox_iuetV8CKmz=./build/thruvm/bin/tn_token_program_rust.elf
You should see some output like this. You’ll be in an interactive GDB session.
Fetching transaction tsCRsKwMAupg5jUbus7GSeN8XgUS_lafAIo6YPUCfJW_zIYTgNJ5xCufxghWfiL1LGAPBWsCWHFHa0srws70WEAx38...
Fetching 3 account states at slot 66 (pre-transaction)...
Fetching state roots ending at slot 66...
--log-path not specified; using autogenerated path
Log at "/tmp/fd-0.0.0_3872496_user_machine-1_2025_12_16_17_38_45_883488412_GMT+00"
Note: RW account ta1kDh1kmoJuRkoBChLLRk-ZOvzAHFNWNrK1iDCBJToaxR not in pre-tx state - will be created by transaction
Starting debug server on port 9001...
GDB connected!
add symbol table from file "./build/thruvm/bin/tn_token_program_rust.elf" at
        .text_addr = 0x3000000
Reading symbols from ./build/thruvm/bin/tn_token_program_rust.elf...
add symbol table from file "./build/thruvm/bin/tn_token_program_rust.elf" at
        .text_addr = 0x30001000000
Reading symbols from ./build/thruvm/bin/tn_token_program_rust.elf...
Remote debugging using localhost:9001
warning: No executable has been specified and target does not support
determining executable automatically.  Try using the "file" command.
0x0000030001000000 in _start ()
(gdb) 
You can debug the program as you would normally do with GDB:
(gdb) break start
Breakpoint 1 at 0x300006c: start. (2 locations)
(gdb) c
Continuing.

Breakpoint 1.2, token_program::start (instr_data=0x0 $core::intrinsics::cold_path, instr_data_sz=0)
    at examples/token_program/main.rs:20
20      #[entry(stack_size = 8192)]