Interesting found, i checked this possible bug/problem with Bitcoin Core 0.16.2 (txindex disabled, so i just try decoderawtransaction) and few explorer/services with getrawtransaction/decoderawtransaction show different result.

I wonder if that happens because you were using/running older Bitcoin Core which don't recognize witness transaction and then you use newer client, but the client never rescan/ask for witness data to other nodes?

Interesting found, i checked this possible bug/problem with Bitcoin Core 0.16.2 (txindex disabled, so i just try decoderawtransaction) and few explorer/services with getrawtransaction/decoderawtransaction show different result.

Fails:bitcoin-cli getrawtransaction 00b09964bf7080b065e3dbc5ff91b778283d5f513008daea3d04d8ff9d5844b4Followed by using the output from this step as input to decoderawtransactionbitcoin-cli decoderawtransaction <output from getrawtransaction above>

This is a known issue and unfortunately it cannot be fixed without a fork. The issue lies with the format of a segwit transaction itself. A segwit transaction, under some circumstances, can be interpreted as either a 0 input, 1 output transaction, or as a witness transaction. Since getrawtransaction fetches transactions from blocks themselves or from the mempool, the transaction must be a valid network transaction and thus witness serialization can be attempted safely as a first step and only deserializing as non-witness if the witness deserialization fails.

However, decoderawtransaction behaves differently as it is intended to be used during the transaction creation steps. This means that it must be able to handle 0-input, 1 output transactions (which are inherently non-witness) as users may create a 0-input, 1 output transaction, decode it, and then pass it to fundrawtransaction to get inputs. But because some 0-input, 1 output transactions can be interpreted as witness transactions, and some witness transactions can be interpreted as 0-input, 1 output transactions, decoderawtransaction does not always succeed to decoding a transaction correctly. It uses some heuristics in order to decrease the number of false decodings, but sometimes, as you can clearly see, it's wrong.

Fortunately, if you know that a transaction is witness you can set the iswitness argument (added in 0.16) to true to tell it explicitly to decode the transaction as witness. You can set it to false for non-witness decoding. Not setting it uses the heuristics.

This is a known issue and unfortunately it cannot be fixed without a fork. The issue lies with the format of a segwit transaction itself. A segwit transaction, under some circumstances, can be interpreted as either a 0 input, 1 output transaction, or as a witness transaction. Since getrawtransaction fetches transactions from blocks themselves or from the mempool, the transaction must be a valid network transaction and thus witness serialization can be attempted safely as a first step and only deserializing as non-witness if the witness deserialization fails.

However, decoderawtransaction behaves differently as it is intended to be used during the transaction creation steps. This means that it must be able to handle 0-input, 1 output transactions (which are inherently non-witness) as users may create a 0-input, 1 output transaction, decode it, and then pass it to fundrawtransaction to get inputs. But because some 0-input, 1 output transactions can be interpreted as witness transactions, and some witness transactions can be interpreted as 0-input, 1 output transactions, decoderawtransaction does not always succeed to decoding a transaction correctly. It uses some heuristics in order to decrease the number of false decodings, but sometimes, as you can clearly see, it's wrong.

Thanks, very informative. I didn't know decoderawtranscaction was intended to be used during transaction creation steps.

Fortunately, if you know that a transaction is witness you can set the iswitness argument (added in 0.16) to true to tell it explicitly to decode the transaction as witness. You can set it to false for non-witness decoding. Not setting it uses the heuristics.

One last question about the heuristic in this specific case: It's pretty clear the assumption made this was a transaction without witness data is wrong based on the fact it's reporting a negative value as an amount. So shouldn't the "heuristic algoritm" reassess itself when the output generated was clearly wrong:

One last question about the heuristic in this specific case: It's pretty clear the assumption made this was a transaction without witness data is wrong based on the fact it's reporting a negative value as an amount. So shouldn't the "heuristic algoritm" reassess itself when the output generated was clearly wrong:

I might be oversimplifying things here but it seems to me this would lead to a lot less incorrect assumptions from heuristics.

Indeed, that probably would help. The heuristic currently is actually rather dumb. IIRC it decodes as non-witness first and then checks for whether there are invalid opcodes in the scripts of any inputs. We could certainly have it check the output amounts to see if they are sane (between 0 and 21 million).

This is a known issue and unfortunately it cannot be fixed without a fork. The issue lies with the format of a segwit transaction itself. A segwit transaction, under some circumstances, can be interpreted as either a 0 input, 1 output transaction, or as a witness transaction. Since getrawtransaction fetches transactions from blocks themselves or from the mempool, the transaction must be a valid network transaction and thus witness serialization can be attempted safely as a first step and only deserializing as non-witness if the witness deserialization fails.

However, decoderawtransaction behaves differently as it is intended to be used during the transaction creation steps. This means that it must be able to handle 0-input, 1 output transactions (which are inherently non-witness) as users may create a 0-input, 1 output transaction, decode it, and then pass it to fundrawtransaction to get inputs. But because some 0-input, 1 output transactions can be interpreted as witness transactions, and some witness transactions can be interpreted as 0-input, 1 output transactions, decoderawtransaction does not always succeed to decoding a transaction correctly. It uses some heuristics in order to decrease the number of false decodings, but sometimes, as you can clearly see, it's wrong.

Thanks, very informative. I didn't know decoderawtranscaction was intended to be used during transaction creation steps.

Fortunately, if you know that a transaction is witness you can set the iswitness argument (added in 0.16) to true to tell it explicitly to decode the transaction as witness. You can set it to false for non-witness decoding. Not setting it uses the heuristics.

One last question about the heuristic in this specific case: It's pretty clear the assumption made this was a transaction without witness data is wrong based on the fact it's reporting a negative value as an amount. So shouldn't the "heuristic algoritm" reassess itself when the output generated was clearly wrong:

I might be oversimplifying things here but it seems to me this would lead to a lot less incorrect assumptions from heuristics.

Nice to see this get fixed, as you commented before, no one talk about that second parameter for decoderawtransaction, the true at end makes the difference. avoiding the problem. Maybe you can change the topic to Fixed and close the thread now.

Nice to see this get fixed, as you commented before, no one talk about that second parameter for decoderawtransaction, the true at end makes the difference. avoiding the problem. Maybe you can change the topic to Fixed and close the thread now.

The problem itself isn't fixed in my opinion since the heuristic part still can result in bogus output for decoderawtransaction. The given workaround will only be usable if you can reference a transaction-id. That will not be the case if I constructed a raw transaction which I want to check with decoderawtransaction. Thread should only be closed when this is no longer the case.

This should produce the same outcome (as mentioned before and as a test):