I am working on the public network through the public Horizon instance: https://horizon.stellar.org/. I posted transactions to the network on April 12 using this API: https://www.stellar.org/developers/horizon/reference/endpoints/transactions-create.html.
Yesterday, I started posting a transaction on 17:23:15 UTC. 30 seconds later, on 17:23:45 a https://www.stellar.org/developers/horizon/reference/errors/timeout.html was returned. As instructed in the documentation, I retried sending the same transaction after a second delay. 30 seconds later, on 17:24:17, I got the same timeout error. Another second delay and another attempt. 30 seconds later, on 17:24:49, I got the same timeout error. My code gives up after 3 attempts.
My assumption is that if I get a timeout error, then the transaction will not be included in any ledger unless I resubmit it.
In practice I found out that my transaction https://stellar.expert/explorer/public/tx/ca4b370f0a0ff8298da3e9282282188c508015cac5b0f908b1b3bab01a7dd9fd made it into this ledger https://stellar.expert/explorer/public/ledger/29145481 which closed at 17:24:57 UTC, a few seconds after the last timeout.
This is not terribly intuitive, but it is expected behaviour. A stellar-core instance may drop your transaction after failing to include it in several ledgers (currently 3). However other distributed instances may still rebroadcast the tx. See e.g. https://github.com/stellar/stellar-core/issues/1811.
When Horizon provides you with a timeout, it means that Horizon has not had timely confirmation that your tx has made it into a ledger. It does not guarantee that the tx will never make it.
If you want to guarantee the tx will never be included beyond some time, you should set an explicit timeout (i.e. an upper timebound). For this reason, an upper timebound is a required argument in most SDKs.
Thanks @ire-and-curses.
I will add the upper timebound to our implementation as you suggested.
As a followup question, does success response on Horizon post transaction API mean a final & immutable success to include the transaction in a validated ledger or a provisional success?
I want to know if I can rely on this result to save a couple of seconds or I must wait until I can find the hash in a validated block.
You can rely on this result. Success is a consensus-level return so you don't need to look it up again. You can see this is so because the response includes the result XDR, and such XDR could only come from stellar-core after ledger application.
Can you approve that transaction_malformed results are final & immutable?
tx_failedCan you approve that transaction_failed results with transaction result_code == tx_failed like this one are final & immutable?
tx_failedWhat about transaction_failed results with transaction result_code != tx_failed?
Sample transaction results codes are:
tx_bad_authtx_no_source_accounttx_bad_seqThese are trickier since the HTTP response body includes a result XDR as you mentioned but the transaction failure will not appear on the chain like the previous case when transaction result_code == tx_failed and fees are deducted. In general, such transactions may soon be valid, if account sequence changes for example.
Can I treat such results as final and immutable?
The follow up questions are not related to this bug. Questions like this are best asked at our Q&A site so that it's easy for others to learn in the future: https://stellar.stackexchange.com/
Would you repost these questions there?
Of course.
Posted: Which Horizon “Post Transaction” responses are final and immutable?