Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fundrawtransaction can look like extended tx format. #67

Open
rustyrussell opened this issue Apr 5, 2016 · 20 comments
Open

fundrawtransaction can look like extended tx format. #67

rustyrussell opened this issue Apr 5, 2016 · 20 comments

Comments

@rustyrussell
Copy link

Seems to cause a misparse, since you're supposed to be able to hand a 0-input tx here. Seems like a new parameter to fundrawtransaction may be needed, to a hack to try parsing both ways...

@sipa
Copy link
Owner

sipa commented Apr 5, 2016

I discovered this a few days ago as well. There is an easy solution: use
the extended format, but without witnesses.

So:

  • u32 nVersion
  • u8 marker = 0
  • u8 flags = 0
  • varint nTxins = 0
  • varint nTxouts = ...
  • CTxout txouts[nTxouts]
  • nLocktime

Pieter

@rustyrussell
Copy link
Author

Breaks backwards compatibility.

@rustyrussell
Copy link
Author

Something like rustyrussell@fa68b4a ?

@sipa
Copy link
Owner

sipa commented Apr 6, 2016 via email

@btcdrak
Copy link

btcdrak commented Apr 6, 2016

I agree with @sipa. Note that fundrawtransactions was only just released with 0.12.0 just 6 weeks ago so it cannot be in widespread use. I think we should follow the least complicated path here. In this case, the disruption, if any, is minimal and we can put a note in the upcoming 0.12.1 release that the fundrawtransaction API will change in 0.12.2.

@sipa
Copy link
Owner

sipa commented Apr 6, 2016 via email

@rustyrussell
Copy link
Author

Pieter Wuille [email protected] writes:

@btcdrak Technically, it is createrawtransaction that changed to produce
extended format transactions when there are 0 inputs in the result.
However, the only reason (that I know of) for using createrawtransaction in
that way, is in order to pass the result to fundrawtransaction.

Well, I was using fundrawtransaction without createrawtransaction
(createrawtransaction seems pretty useless to me).

But breaking createrawtransaction is pretty bad too.

Presumably these were put in place because people want to split
sendtoaddress into multiple steps (createrawtransaction,
fundrawtransaction, signrawtransaction, sendrawtransaction), implying
they're interpreting and modifying the tx somewhere along the way?

Pinging @TheBlueMatt who added these AFAICT...

@sipa
Copy link
Owner

sipa commented Apr 11, 2016 via email

@NicolasDorier
Copy link

I hit the problem in nbitcoin as l often need to serialize transaction without input. The way I fixed that is by using a bit in nversion with special meaning only if the transaction has no input. (I set and unset this bit silently during serialization and deserialisation)

See readwrite method in https://github.com/MetacoSA/NBitcoin/blob/master/NBitcoin/Transaction.cs

not sure if it helps.

@rustyrussell
Copy link
Author

Nicolas Dorier [email protected] writes:

I hit the problem in nbitcoin as l often need to serialize transaction without input. The way I fixed that is by using a bit in nversion with special meaning only if the transaction has no input. (I set and unset this bit silently during serialization and deserialisation)

See readwrite method in https://github.com/MetacoSA/NBitcoin/blob/master/NBitcoin/Transaction.cs

not sure if it helps.

I think we're better off trying the old-style deserialization if
new-style fails.

Also, I think the createrawtransaction needs a flag to say "create an
extended transaction", which is false by default.

@sipa
Copy link
Owner

sipa commented Apr 23, 2016

I really do not want to introduce guessing (creates unclear expectations) or extra flags (a terrible technical debt that we'd very much regret in a post-segwit world).

But I think there is a better solution: fundrawtransaction does not need to support new-style parsing, as it deals with transactions that don't have signatures yet, and thus, no witnesses.

So I think I can revert the change to use new-style serialization for transactions with empty vin, and make fundrawtransaction parse the input as old style.

@NicolasDorier
Copy link

By quickly checking the code, it seems fundrawtransaction can be used with some inputs, so that the caller can oblige to select some specific coins. (https://github.com/bitcoin/bitcoin/blob/0c95ebce7e67f86f62c099974dde68c8d808240b/src/wallet/wallet.cpp#L1936)

Another reason might be Bob send a partially funded transaction, then give it to Alice to complete the rest.

@sipa
Copy link
Owner

sipa commented Apr 23, 2016

Nicolas: sure, it can have inputs, but they won't carry signatures.

@NicolasDorier
Copy link

I think they might, if it is partially signed by another party for example.

Falling back to classic transaction parsing only seems to be a good solution nonetheless.
With a clear error message in case the caller passed the witness by mistake it should be ok.

@sipa
Copy link
Owner

sipa commented Apr 23, 2016

@NicolasDorier if fundrawtransaction has any effect at all (add outputs, or change inputs) it will normally invalidate all existing signatures.

@NicolasDorier
Copy link

except for AnyOneCanPay signatures. Edge case though.

@sipa
Copy link
Owner

sipa commented Apr 23, 2016

AnyOneCanPay AND (SigHashNone OR no-change-output added). Agree that we need to support that though, but parsing by default with old-style deserialization, and trying with new-style if it fails will cover everything I expect.

What I wanted to avoid was the need for guessing in general in many RPCs (or worse, P2P code), as there are places where concatenations of transactions can be given, which would lead to an exponential blowup of combimations to try, and hard to define behaviour. As long as it's limited to fundrawtransaction (AFAIK the only place where you can meaningfully pass a transaction without inputs), we're probably fine.

@sipa
Copy link
Owner

sipa commented Apr 23, 2016

Updated in commit dbe6391. Decoderawtransaction and fundrawtransaction now first try deserializing without witness, and if that fails, or does not consume the entire string that is passed in, try deserializing with the new format. Furthermore, serialization without inputs is reverted to using old serialization as well.

@rustyrussell Does that suffice as a solution for you?

@rustyrussell
Copy link
Author

Pieter Wuille [email protected] writes:

Updated in commit dbe6391. Decoderawtransaction and fundrawtransaction now first try deserializing without witness, and if that fails, or does not consume the entire string that is passed in, try deserializing with the new format. Furthermore, serialization without inputs is reverted to using old serialization as well.

@rustyrussell Does that suffice as a solution for you?

Yes. I share your distaste, but fundrawtransaction really is a corner
case.

BTW, I'm surprised tests didn't pick this up...

Ut-Ack: Rusty Russell [email protected]

Thanks!
Rusty.

@sipa
Copy link
Owner

sipa commented Apr 26, 2016

The tests did pick it. The change was intentional, so I modified them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants