@@ -171,3 +171,91 @@ def sign_and_xdr(tb: TransactionBuilder) -> str:
171171 # 4. Invoke foo()
172172 contract_address = server .interpreter .contract_address_from_deployer_address (keypair .public_key , salt )
173173 send (sign_and_xdr (builder ().append_invoke_contract_function_op (contract_address , 'foo' , [])))
174+
175+
176+ def test_trace_transaction_returns_result_directly (server : StellarRpcServer ) -> None :
177+ """traceTransaction returns status/ledger/trace immediately, not PENDING."""
178+ keypair = Keypair .random ()
179+ account = Account (keypair .public_key , sequence = 0 )
180+
181+ envelope = (
182+ TransactionBuilder (account , Network .TESTNET_NETWORK_PASSPHRASE )
183+ .append_create_account_op (destination = keypair .public_key , starting_balance = '1000' )
184+ .set_timeout (30 )
185+ .build ()
186+ )
187+ envelope .sign (keypair )
188+
189+ result = _rpc (server .port (), 'traceTransaction' , {'transaction' : envelope .to_xdr ()})['result' ]
190+
191+ assert result ['status' ] == 'SUCCESS'
192+ assert result ['hash' ] == envelope .hash_hex ()
193+ assert 'ledger' in result
194+ assert 'trace' in result
195+ assert 'latestLedger' in result
196+
197+
198+ def test_trace_transaction_stored_for_get_transaction (server : StellarRpcServer ) -> None :
199+ """traceTransaction stores the result so getTransaction can retrieve it."""
200+ keypair = Keypair .random ()
201+ account = Account (keypair .public_key , sequence = 0 )
202+
203+ envelope = (
204+ TransactionBuilder (account , Network .TESTNET_NETWORK_PASSPHRASE )
205+ .append_create_account_op (destination = keypair .public_key , starting_balance = '1000' )
206+ .set_timeout (30 )
207+ .build ()
208+ )
209+ envelope .sign (keypair )
210+
211+ trace_result = _rpc (server .port (), 'traceTransaction' , {'transaction' : envelope .to_xdr ()})['result' ]
212+ get_result = _rpc (server .port (), 'getTransaction' , {'hash' : trace_result ['hash' ]})['result' ]
213+
214+ assert get_result ['status' ] == 'SUCCESS'
215+ assert get_result ['envelopeXdr' ] == envelope .to_xdr ()
216+
217+
218+ def test_trace_transaction_produces_trace_on_contract_invocation (server : StellarRpcServer ) -> None :
219+ """traceTransaction returns non-empty trace JSONL when a contract function is invoked."""
220+ keypair = Keypair .random ()
221+ account = Account (keypair .public_key , sequence = 0 )
222+
223+ def builder () -> TransactionBuilder :
224+ return TransactionBuilder (account , Network .TESTNET_NETWORK_PASSPHRASE )
225+
226+ def sign_and_xdr (tb : TransactionBuilder ) -> str :
227+ env = tb .set_timeout (30 ).build ()
228+ env .sign (keypair )
229+ return env .to_xdr ()
230+
231+ def send (xdr : str ) -> None :
232+ res = _rpc (server .port (), 'sendTransaction' , {'transaction' : xdr })
233+ assert res ['result' ]['status' ] == 'PENDING'
234+ tx_hash = res ['result' ]['hash' ]
235+ assert _rpc (server .port (), 'getTransaction' , {'hash' : tx_hash })['result' ]['status' ] == 'SUCCESS'
236+
237+ # Set up: create account, upload wasm, deploy contract
238+ send (sign_and_xdr (builder ().append_create_account_op (keypair .public_key , '1000' )))
239+
240+ wasm_bytecode = wat_to_wasm (EMPTY_CONTRACT_WAT )
241+ send (sign_and_xdr (builder ().append_upload_contract_wasm_op (wasm_bytecode )))
242+
243+ from stellar_sdk .utils import sha256
244+ wasm_hash = sha256 (wasm_bytecode )
245+ salt = b'\x00 ' * 32
246+ send (sign_and_xdr (builder ().append_create_contract_op (wasm_hash , keypair .public_key , None , salt )))
247+
248+ # Invoke via traceTransaction and check trace content
249+ contract_address = server .interpreter .contract_address_from_deployer_address (keypair .public_key , salt )
250+ invoke_xdr = sign_and_xdr (builder ().append_invoke_contract_function_op (contract_address , 'foo' , []))
251+ result = _rpc (server .port (), 'traceTransaction' , {'transaction' : invoke_xdr })['result' ]
252+
253+ assert result ['status' ] == 'SUCCESS'
254+ assert result ['trace' ] is not None
255+ # Trace is newline-separated JSON records; verify each line parses as JSON
256+ lines = [line for line in result ['trace' ].splitlines () if line .strip ()]
257+ assert len (lines ) > 0
258+ import json as _json
259+ for line in lines :
260+ record = _json .loads (line )
261+ assert 'instr' in record
0 commit comments