bitcoinjs / bitcoinjs-lib

A javascript Bitcoin library for node.js and browsers.
MIT License
5.69k stars 2.11k forks source link

PSBT finalScriptWitness "Destructuring" #2052

Open arik-so opened 8 months ago

arik-so commented 8 months ago

Currently, bitcoin.Transaction may contain per-input witness data, and that witness data is an array of Buffer objects.

Similarly, bitcoin.Psbt can have a finalScriptWitness field, but that one is not "destructured" (for lack of a better term), but rather lives in a semi-serialized state with the encoded witness stack size concatenated with essentially a bitcoin.script.compile() of the actual witness elements.

I think it might be incredibly convenient to have the object represent the destructured witness elements. This would have the added benefit of allowing the construction of partially finalized PSBTs where some of the inputs are non-standard scripts.

junderw commented 8 months ago

Adding a getter and setter might be helpful, but if you mean partially finalized PSBTs as in "the data in the finalScriptWitness is not actually finalized" then I am against that.

The whole point of PSBT's existence was because we didn't have a representation for a "partially signed" transaction (and our TransactionBuilder was parsing a non-standardized format of the Transaction serialization)...

So by encoding a "possibly not finalized" script into finalScriptWitness we are re-creating the problem.

junderw commented 8 months ago

PSBT BIP likes to add new input data types all the time, so maybe you should propose a logical way to store the partial script. We could add it then.

I would imagine it would be hard to design, since the case where your new type of data and ie. a partialSig coexist seems unclear. You might need to restrict it to "if the input contains this thing, all data should be in it, and the following input data types must be forbidden partialSig, redeemScript, witnessScript, etc."

arik-so commented 8 months ago

Sorry, allow me to clarify. The data in the input would definitely be finalized, but merely represented in a broken down manner for easier programmatic access. By "partially finalized" I only meant that a subset of the inputs would be finalized, not that the finalScriptWitness wouldn't be final.

A getter might get the job done, too, though having to repeatedly parse the finalScriptWitness to represent it as a broken down array of witness elements might incur a performance penalty when dealing with a large transaction count.

junderw commented 8 months ago

We cache the deserialized Transaction for nonWitnessUtxo. Could probably do something similar.

This isn't difficult to code, it's just difficult from an API design perspective.

Perhaps it'd be easier to put it off until v7 and just say that the two final things are represented as scriptSig = (number | Buffer)[]; scriptWitness = Buffer[] when existing as a JS Psbt instance.

arik-so commented 8 months ago

I think those representations would work great!

And there's definitely no pressure or rush from my end; I was merely playing around with it and thought that the deconstructed representation would be more convenient and intuitive.