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:
parent
02a4fd9de1
commit
04442f8ef9
2 changed files with 43 additions and 1 deletions
15
psbt/psbt.go
15
psbt/psbt.go
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue