psbt: fix deserialization with zero inputs

This is a fix/workaround for a special case that's caused by
https://github.com/btcsuite/btcd/blob/master/wire/msgtx.go#L426.
When a wire format transaction with no inputs is serialized, the wire
package assumes it's a non-witness transaction (as there is indeed no
witness data present).
But when de-serializing the same transaction, the line mentioned above
assumes that for the special case of a zero input length, the
transaction must be in the witness format, which causes the
de-serialization  to fail.
The workaround in this commit fixes this special case by just trying
to deserialize the transaction in the non-witness format too.
This commit is contained in:
Oliver Gugger 2020-03-23 09:44:06 +01:00
parent 02a4fd9de1
commit 04442f8ef9
No known key found for this signature in database
GPG key ID: 8E4256593F177720
2 changed files with 43 additions and 1 deletions

View file

@ -212,7 +212,20 @@ func NewFromRawBytes(r io.Reader, b64 bool) (*Packet, error) {
msgTx := wire.NewMsgTx(2)
err = msgTx.Deserialize(bytes.NewReader(value))
if err != nil {
return nil, err
// If there are no inputs in this yet incomplete transaction,
// the wire package still incorrectly assumes it's encoded in
// the witness format. We can fix this by just trying the non-
// witness encoding too. If that also fails, it's probably an
// invalid transaction.
msgTx = wire.NewMsgTx(2)
err2 := msgTx.DeserializeNoWitness(bytes.NewReader(value))
// If the second attempt also failed, something else is wrong
// and it probably makes more sense to return the original
// error instead of the error from the workaround.
if err2 != nil {
return nil, err
}
}
if !validateUnsignedTX(msgTx) {
return nil, ErrInvalidRawTxSigned

View file

@ -1288,3 +1288,32 @@ func TestNonWitnessToWitness(t *testing.T) {
t.Fatalf("Expected serialized transaction was not produced: %x", b.Bytes())
}
}
// TestEmptyInputSerialization tests the special serialization case for a wire
// transaction that has no inputs.
func TestEmptyInputSerialization(t *testing.T) {
// Create and serialize a new, empty PSBT. The wire package will assume
// it's a non-witness transaction, as there are no inputs.
psbt, err := New(nil, nil, 2, 0, nil)
if err != nil {
t.Fatalf("failed to create empty PSBT: %v", err)
}
var buf bytes.Buffer
err = psbt.Serialize(&buf)
if err != nil {
t.Fatalf("failed to serialize empty PSBT: %v", err)
}
// Try to deserialize the empty transaction again. The wire package will
// assume it's a witness transaction because of the special case where
// there are no inputs. This assumption is wrong and the first attempt
// will fail. But a workaround should try again to deserialize the TX
// with the non-witness format.
psbt2, err := NewFromRawBytes(&buf, false)
if err != nil {
t.Fatalf("failed to deserialize empty PSBT: %v", err)
}
if len(psbt2.UnsignedTx.TxIn) > 0 || len(psbt2.UnsignedTx.TxOut) > 0 {
t.Fatalf("deserialized transaction not empty")
}
}