Skip to content

Conversation

@jnewbery
Copy link
Contributor

Segwit has added ambiguity for 0-input transactions (the 0 can be read as the dummy byte indicating that this is a segwit transcation).

bitcoin-tx needs to be able to parse 0-input partial transactions. This PR causes bitcoin-tx to call DecodeHexTx() with the fTryNoWitness flag set, so we attempt to deserialize the transaction as a pre-segwit transaction.

This PR also adds new test cases to verify that bitcoin-tx parses a partial transaction correctly.

@fivepiece
Copy link
Contributor

fivepiece commented Sep 29, 2016

adding my comment here instead of on the files changed tab

Is this 01000000000100000000000000000000000000 supposed to be parsed as a zero input, one output to 0x00 transaction?

01000000
00
01
  0000000000000000
  00
00000000

Wouldn't 010000000001000000000000 (which currently fails) be more suitable?

01000000
00
01
00
00
00000000

Following 01000000000000000000 behavior.
Unless there's another reason for using that one.

@jnewbery
Copy link
Contributor Author

jnewbery commented Sep 29, 2016

@fivepiece , I believe your second transaction is invalid. Commented transactions:

01000000000100000000000000000000000000 is a valid partial transaction with 0 inputs and 1 output:

01000000 // version (4 bytes)
00 // number of inputs (varint - 1 byte if value is 0)
01 // number of outputs (varint - 1 byte if value is 1)
  0000000000000000 // output 1 amount (8 bytes)
  00 // output 1 scriptSig size (varint - 1 byte if value is 0)
00000000 // nlocktime (4 bytes)

010000000001000000000000 is invalid and doesn't parse:

01000000 // version (4 bytes)
00 // number of inputs (varint - 1 byte if value is 0)
01 // number of outputs (varint - 1 byte if value is 1)
  00 // output 1 amount !!INVALID SHOULD BE 8 BYTES!!
  00 // etc
00000000

(in fact it'd be partially parsed as):

01000000 // version (4 bytes)
00 // number of inputs (varint - 1 byte if value is 0)
01 // number of outputs (varint - 1 byte if value is 1)
  000000000000.... // output 1 amount (!!INVALID expects 8 bytes - only 6 read!!)
...

Your other example 01000000000000000000 is valid as a partial transaction with 0 inputs and 0 outputs:

01000000 // version (4 bytes)
00 // number of inputs (varint - 1 byte if value is 0)
00 // number of outputs (varint - 1 byte if value is 0)
00000000 // nlocktime (4 bytes)

@fivepiece
Copy link
Contributor

fivepiece commented Sep 29, 2016

@jnewbery I guess I should clarify my question then. I was wondering why 01000000000100000000000000000000000000 was given as a test case at all, as it seems very specific.

My understanding was that you were out to implement a "blank" segwit transaction in that test, and I think 010000000001000000000000 is a better representation, because it's very similar to the non-segwit bank tx 01000000000000000000, only with the addition of the marker and flag.

[edit]
I agree that 010000000001000000000000 currently fails parsing, but I think that it shouldn't. :)

@fivepiece
Copy link
Contributor

Anyway thinking about this some more, feel free to disregard my suggestion. It's too ambiguous. Maybe the correct way is to fall back to parsing a non segwit transaction, as no inputs mean no witnesses too.

@jnewbery
Copy link
Contributor Author

jnewbery commented Sep 29, 2016

Correct. If none of the inputs have witnesses or if the witnesses are all empty, then there shouldn't be a witness structure attached to the transaction

From transaction.h:

            /* It's illegal to encode a witness when all vtxinwit entries are empty. */
            throw std::ios_base::failure("Superfluous witness record");

In this case there are no transaction inputs, so no witnesses, and so the witness dummy byte and flag shouldn't be set.

@fivepiece
Copy link
Contributor

Right re. transaction.h, also I've asked a related question about this in -dev yesterday. Initially I read that comment as a reference to actual witness data (sigs, scripts), but I see the point of not needing segwit markers at all for no input transactions.

Thanks for clearing it up.

@jnewbery
Copy link
Contributor Author

@laanwj - this very small change allows bitcoin-tx to parse partial transactions and includes a test case to cover the new functionality. Are you happy to merge this?

@laanwj
Copy link
Member

laanwj commented Oct 24, 2016

I don't like "try to parse the transaction as pre-segwit transaction" much - This implies ambiguity, can the ambiguity cause problems here?

If so I'd prefer if this was an explicit flag somewhere.

@fivepiece
Copy link
Contributor

fivepiece commented Oct 24, 2016

I'll paste this here as well, commented in #-core-dev

so specifically re. parsing partial transactions as pre-segwit (#8837), I actually hit this issue in my own toy parser and it shows in core too: http://paste.debian.net/plainh/8c80d8cd so having some flag would be great

  • I should add that with this PR the transaction from the pastebin is parsed as a zero input pay to multisig on both bitcoin-tx and bitcoin-cli

@sipa
Copy link
Member

sipa commented Oct 24, 2016

The issue is that segwit only guarantees unambiguous encoding for valid complete transactions. In places where raw transactions are expected that consume inputs that are not necessarily complete, ambiguity is possible. This is the case for the decoderawtransaction and fundrawtransaction RPCs, and for bitcoin-tx. Since inputs to those are usually in fact not signed, they should usually not have any witnesses at all, and thus (trying to) decode without seems like a reasonable default.

I do agree it's undesirable to have ambiguity in the first place, but I think a longer term solution will include a separate encoding for incomplete transactions. We may need that anyway for more complex signing such as for MAST and Schnorr, where the communication between the participants may include (primarily) information that does not end up in the final transaction.

@laanwj
Copy link
Member

laanwj commented Oct 25, 2016

I do agree it's undesirable to have ambiguity in the first place, but I think a longer term solution will include a separate encoding for incomplete transactions.

Not only a separate encoding, but it needs to be distinguishable non-ambiguously from completed transactions.

@fivepiece
Copy link
Contributor

Right ^, the difficulty is a 0 inputs, unfunded transaction looks a lot like segwit at first, then you might fail after it stops making sense, or like in the case I linked, maybe never fail.. unless there was a context to what this transaction was passed in for. (just my personal experience parsing partial transactions)

@jnewbery
Copy link
Contributor Author

jnewbery commented Nov 4, 2016

The conversation in this PR seems to have wandered a bit into the desirability of having a separate encoding for partial transactions. I agree that's a good idea, but it seems out of scope for this PR.

To clarify what this PR achieves:

  • pre V0.13.1, both bitcoin-tx and bitcoin-cli decoderawtransaction were able to parse partial transactions
  • V0.13.1 introduced ambiguity in encoding for a 0-input transactions. However, as @sipa notes above: "those are usually in fact not signed, they should usually not have any witnesses at all, and thus (trying to) decode without seems like a reasonable default."
  • decoderawtransaction was updated to attempt to parse partial transactions here: 7030d9e#diff-01aa7d1d32f1b9e5a836c9c411978918L490 . bitcoin-tx was not updated at the same time.
  • this PR makes the same change to bitcoin-tx as was made to decoderawtransaction and adds test cases. This restores the pre-v0.13.1 behaviour and brings bitcoin-tx in line with decoderawtransaction

Restore pre V0.13.1 functionality to bitcoin-tx and allow it to parse 0-input partial transactions.
@jnewbery jnewbery force-pushed the bitcoin-tx-partial-transactions branch from 0221a4f to 7451cf5 Compare November 4, 2016 09:12
@laanwj
Copy link
Member

laanwj commented Nov 7, 2016

Yes, fair enough, it's an improvement.
utACK 7451cf5

@laanwj laanwj merged commit 7451cf5 into bitcoin:master Nov 21, 2016
laanwj added a commit that referenced this pull request Nov 21, 2016
7451cf5 Allow bitcoin-tx to parse partial transactions (jnewbery)
@jnewbery jnewbery deleted the bitcoin-tx-partial-transactions branch November 21, 2016 16:47
codablock pushed a commit to codablock/dash that referenced this pull request Jan 20, 2018
7451cf5 Allow bitcoin-tx to parse partial transactions (jnewbery)
andvgal pushed a commit to energicryptocurrency/gen2-energi that referenced this pull request Jan 6, 2019
7451cf5 Allow bitcoin-tx to parse partial transactions (jnewbery)
CryptoCentric pushed a commit to absolute-community/absolute that referenced this pull request Feb 27, 2019
7451cf5 Allow bitcoin-tx to parse partial transactions (jnewbery)
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants