psbt: move to top-level module, use v2, remove btcutil dep
What changed, and why it matters
This commit is a routine code reorganization: it moves the PSBT (Partially Signed Bitcoin Transaction) package from a nested location under btcutil to a top-level module, updates internal import paths to use v2 module versions, and removes a dependency on btcutil. The diff shows files being deleted from btcutil/psbt and equivalent files being added under psbt/. There is no indication of a security bug fix, vulnerability patch, or behavior change intended to address an exploit.
No security action required. Treat as a normal dependency/module refactor. Consumers of the library should update their import paths from github.com/btcsuite/btcd/btcutil/psbt to github.com/btcsuite/btcd/psbt and verify compatibility with the v2 module versions.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change is a refactor/migration: the PSBT implementation is relocated from github.com/btcsuite/btcd/btcutil/psbt to github.com/btcsuite/btcd/psbt, go.mod/go.sum files are updated accordingly, and imports are switched to /v2 submodules (e.g., btcutil/v2, wire/v2, txscript/v2, chainhash/v2). The deleted and added source files appear to be the same PSBT logic with only import path adjustments. No security-relevant logic changes, bug fixes, or hardening are visible in the supplied diff.
Changed components
btcd PSBT packagebtcutil/psbt modulepsbt top-level modulego.mod / go.sum dependency graphInspect captured patch +6245 / −6226
diff --git a/btcutil/psbt/bip32.go b/btcutil/psbt/bip32.go
deleted file mode 100644
index 4f9bb57..0000000
--- a/btcutil/psbt/bip32.go
+++ /dev/null
@@ -1,156 +0,0 @@
-package psbt
-
-import (
- "bytes"
- "encoding/binary"
-
- "github.com/btcsuite/btcd/btcutil/base58"
- "github.com/btcsuite/btcd/btcutil/hdkeychain"
- "github.com/btcsuite/btcd/chaincfg/chainhash"
-)
-
-const (
- // uint32Size is the size of a uint32 in bytes.
- uint32Size = 4
-)
-
-// Bip32Derivation encapsulates the data for the input and output
-// Bip32Derivation key-value fields.
-//
-// TODO(roasbeef): use hdkeychain here instead?
-type Bip32Derivation struct {
- // PubKey is the raw pubkey serialized in compressed format.
- PubKey []byte
-
- // MasterKeyFingerprint is the fingerprint of the master pubkey.
- MasterKeyFingerprint uint32
-
- // Bip32Path is the BIP 32 path with child index as a distinct integer.
- Bip32Path []uint32
-}
-
-// checkValid ensures that the PubKey in the Bip32Derivation struct is valid.
-func (pb *Bip32Derivation) checkValid() bool {
- return validatePubkey(pb.PubKey)
-}
-
-// Bip32Sorter implements sort.Interface for the Bip32Derivation struct.
-type Bip32Sorter []*Bip32Derivation
-
-func (s Bip32Sorter) Len() int { return len(s) }
-
-func (s Bip32Sorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
-func (s Bip32Sorter) Less(i, j int) bool {
- return bytes.Compare(s[i].PubKey, s[j].PubKey) < 0
-}
-
-// ReadBip32Derivation deserializes a byte slice containing chunks of 4 byte
-// little endian encodings of uint32 values, the first of which is the
-// MasterKeyFingerprint and the remainder of which are the derivation path.
-func ReadBip32Derivation(path []byte) (uint32, []uint32, error) {
- // BIP-0174 defines the derivation path being encoded as
- // "<32-bit uint> <32-bit uint>*"
- // with the asterisk meaning 0 to n times. Which in turn means that an
- // empty path is valid, only the key fingerprint is mandatory.
- if len(path) < uint32Size || len(path)%uint32Size != 0 {
- return 0, nil, ErrInvalidPsbtFormat
- }
-
- masterKeyInt := binary.LittleEndian.Uint32(path[:uint32Size])
-
- var paths []uint32
- for i := uint32Size; i < len(path); i += uint32Size {
- paths = append(paths, binary.LittleEndian.Uint32(
- path[i:i+uint32Size],
- ))
- }
-
- return masterKeyInt, paths, nil
-}
-
-// SerializeBIP32Derivation takes a master key fingerprint as defined in BIP32,
-// along with a path specified as a list of uint32 values, and returns a
-// bytestring specifying the derivation in the format required by BIP174: //
-// master key fingerprint (4) || child index (4) || child index (4) || ....
-func SerializeBIP32Derivation(masterKeyFingerprint uint32,
- bip32Path []uint32) []byte {
-
- var masterKeyBytes [uint32Size]byte
- binary.LittleEndian.PutUint32(masterKeyBytes[:], masterKeyFingerprint)
-
- derivationPath := make([]byte, 0, uint32Size+uint32Size*len(bip32Path))
- derivationPath = append(derivationPath, masterKeyBytes[:]...)
- for _, path := range bip32Path {
- var pathBytes [uint32Size]byte
- binary.LittleEndian.PutUint32(pathBytes[:], path)
- derivationPath = append(derivationPath, pathBytes[:]...)
- }
-
- return derivationPath
-}
-
-// XPub is a struct that encapsulates an extended public key, as defined in
-// BIP-0032.
-type XPub struct {
- // ExtendedKey is the serialized extended public key as defined in
- // BIP-0032.
- ExtendedKey []byte
-
- // MasterFingerprint is the fingerprint of the master pubkey.
- MasterKeyFingerprint uint32
-
- // Bip32Path is the derivation path of the key, with hardened elements
- // having the 0x80000000 offset added, as defined in BIP-0032. The
- // number of path elements must match the depth provided in the extended
- // public key.
- Bip32Path []uint32
-}
-
-// ReadXPub deserializes a byte slice containing an extended public key and a
-// BIP-0032 derivation path.
-func ReadXPub(keyData []byte, path []byte) (*XPub, error) {
- xPub, err := DecodeExtendedKey(keyData)
- if err != nil {
- return nil, ErrInvalidPsbtFormat
- }
- numPathElements := xPub.Depth()
-
- // The path also contains the master key fingerprint,
- expectedSize := int(uint32Size * (numPathElements + 1))
- if len(path) != expectedSize {
- return nil, ErrInvalidPsbtFormat
- }
-
- masterKeyFingerprint, bip32Path, err := ReadBip32Derivation(path)
- if err != nil {
- return nil, err
- }
-
- return &XPub{
- ExtendedKey: keyData,
- MasterKeyFingerprint: masterKeyFingerprint,
- Bip32Path: bip32Path,
- }, nil
-}
-
-// EncodeExtendedKey serializes an extended key to a byte slice, without the
-// checksum.
-func EncodeExtendedKey(key *hdkeychain.ExtendedKey) []byte {
- serializedKey := key.String()
- decodedKey := base58.Decode(serializedKey)
- return decodedKey[:len(decodedKey)-uint32Size]
-}
-
-// DecodeExtendedKey deserializes an extended key from a byte slice that does
-// not contain the checksum.
-func DecodeExtendedKey(encodedKey []byte) (*hdkeychain.ExtendedKey, error) {
- checkSum := chainhash.DoubleHashB(encodedKey)[:uint32Size]
- serializedBytes := append(encodedKey, checkSum...)
- xPub, err := hdkeychain.NewKeyFromString(base58.Encode(serializedBytes))
- if err != nil {
- return nil, err
- }
-
- return xPub, nil
-}
diff --git a/btcutil/psbt/bip32_test.go b/btcutil/psbt/bip32_test.go
deleted file mode 100644
index 88caa5c..0000000
--- a/btcutil/psbt/bip32_test.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package psbt
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-// TestReadBip32Derivation tests the ReadBip32Derivation function to ensure
-// it correctly deserializes the BIP32 derivation path and master key
-// fingerprint from a byte slice.
-func TestReadBip32Derivation(t *testing.T) {
- tests := []struct {
- name string
- path []byte
- expectFingerprint uint32
- expectPath []uint32
- expectErr error
- }{
- {
- name: "valid path with multiple derivations",
- path: []byte{
- 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x03, 0x00, 0x00, 0x00},
- expectFingerprint: 1,
- expectPath: []uint32{2, 3},
- },
- {
- name: "valid path with single derivation",
- path: []byte{
- 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- },
- expectFingerprint: 1,
- expectPath: []uint32{2},
- },
- {
- name: "valid path with no derivations",
- path: []byte{
- 0x01, 0x00, 0x00, 0x00,
- },
- expectFingerprint: 1,
- expectPath: nil,
- },
- {
- name: "invalid path length",
- path: []byte{
- 0x01, 0x00, 0x00,
- },
- expectErr: ErrInvalidPsbtFormat,
- },
- {
- name: "invalid path length not multiple of 4",
- path: []byte{
- 0x01, 0x00, 0x00, 0x00, 0x02,
- },
- expectErr: ErrInvalidPsbtFormat,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- fp, path, err := ReadBip32Derivation(tt.path)
- if tt.expectErr != nil {
- require.ErrorIs(t, err, tt.expectErr)
-
- return
- }
-
- require.NoError(t, err)
- require.Equal(t, tt.expectFingerprint, fp)
- require.Equal(t, tt.expectPath, path)
- })
- }
-}
diff --git a/btcutil/psbt/creator.go b/btcutil/psbt/creator.go
deleted file mode 100644
index 60185ad..0000000
--- a/btcutil/psbt/creator.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2018 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package psbt
-
-import (
- "github.com/btcsuite/btcd/wire/v2"
-)
-
-// MinTxVersion is the lowest transaction version that we'll permit.
-const MinTxVersion = 1
-
-// New on provision of an input and output 'skeleton' for the transaction, a
-// new partially populated PBST packet. The populated packet will include the
-// unsigned transaction, and the set of known inputs and outputs contained
-// within the unsigned transaction. The values of nLockTime, nSequence (per
-// input) and transaction version (must be 1 of 2) must be specified here. Note
-// that the default nSequence value is wire.MaxTxInSequenceNum. Referencing
-// the PSBT BIP, this function serves the roles of the Creator.
-func New(inputs []*wire.OutPoint,
- outputs []*wire.TxOut, version int32, nLockTime uint32,
- nSequences []uint32) (*Packet, error) {
-
- // Create the new struct; the input and output lists will be empty, the
- // unsignedTx object must be constructed and serialized, and that
- // serialization should be entered as the only entry for the
- // globalKVPairs list.
- //
- // Ensure that the version of the transaction is greater then our
- // minimum allowed transaction version. There must be one sequence
- // number per input.
- if version < MinTxVersion || len(nSequences) != len(inputs) {
- return nil, ErrInvalidPsbtFormat
- }
-
- unsignedTx := wire.NewMsgTx(version)
- unsignedTx.LockTime = nLockTime
- for i, in := range inputs {
- unsignedTx.AddTxIn(&wire.TxIn{
- PreviousOutPoint: *in,
- Sequence: nSequences[i],
- })
- }
- for _, out := range outputs {
- unsignedTx.AddTxOut(out)
- }
-
- // The input and output lists are empty, but there is a list of those
- // two lists, and each one must be of length matching the unsigned
- // transaction; the unknown list can be nil.
- pInputs := make([]PInput, len(unsignedTx.TxIn))
- pOutputs := make([]POutput, len(unsignedTx.TxOut))
-
- // This new Psbt is "raw" and contains no key-value fields, so sanity
- // checking with c.Cpsbt.SanityCheck() is not required.
- return &Packet{
- UnsignedTx: unsignedTx,
- Inputs: pInputs,
- Outputs: pOutputs,
- Unknowns: nil,
- }, nil
-}
diff --git a/btcutil/psbt/extractor.go b/btcutil/psbt/extractor.go
deleted file mode 100644
index cf7e7b6..0000000
--- a/btcutil/psbt/extractor.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) 2018 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package psbt
-
-// The Extractor requires provision of a single PSBT
-// in which all necessary signatures are encoded, and
-// uses it to construct a fully valid network serialized
-// transaction.
-
-import (
- "bytes"
-
- "github.com/btcsuite/btcd/txscript/v2"
- "github.com/btcsuite/btcd/wire/v2"
-)
-
-// Extract takes a finalized psbt.Packet and outputs a finalized transaction
-// instance. Note that if the PSBT is in-complete, then an error
-// ErrIncompletePSBT will be returned. As the extracted transaction has been
-// fully finalized, it will be ready for network broadcast once returned.
-func Extract(p *Packet) (*wire.MsgTx, error) {
- // If the packet isn't complete, then we'll return an error as it
- // doesn't have all the required witness data.
- if !p.IsComplete() {
- return nil, ErrIncompletePSBT
- }
-
- // First, we'll make a copy of the underlying unsigned transaction (the
- // initial template) so we don't mutate it during our activates below.
- finalTx := p.UnsignedTx.Copy()
-
- // For each input, we'll now populate any relevant witness and
- // sigScript data.
- for i, tin := range finalTx.TxIn {
- // We'll grab the corresponding internal packet input which
- // matches this materialized transaction input and emplace that
- // final sigScript (if present).
- pInput := p.Inputs[i]
- if pInput.FinalScriptSig != nil {
- tin.SignatureScript = pInput.FinalScriptSig
- }
-
- // Similarly, if there's a final witness, then we'll also need
- // to extract that as well, parsing the lower-level transaction
- // encoding.
- if pInput.FinalScriptWitness != nil {
- // In order to set the witness, need to re-deserialize
- // the field as encoded within the PSBT packet. For
- // each input, the witness is encoded as a stack with
- // one or more items.
- witnessReader := bytes.NewReader(
- pInput.FinalScriptWitness,
- )
-
- // First we extract the number of witness elements
- // encoded in the above witnessReader.
- witCount, err := wire.ReadVarInt(witnessReader, 0)
- if err != nil {
- return nil, err
- }
-
- // Now that we know how many inputs we'll need, we'll
- // construct a packing slice, then read out each input
- // (with a varint prefix) from the witnessReader.
- tin.Witness = make(wire.TxWitness, witCount)
- for j := uint64(0); j < witCount; j++ {
- wit, err := wire.ReadVarBytes(
- witnessReader, 0,
- txscript.MaxScriptSize, "witness",
- )
- if err != nil {
- return nil, err
- }
- tin.Witness[j] = wit
- }
- }
- }
-
- return finalTx, nil
-}
diff --git a/btcutil/psbt/finalizer.go b/btcutil/psbt/finalizer.go
deleted file mode 100644
index fa1d8f2..0000000
--- a/btcutil/psbt/finalizer.go
+++ /dev/null
@@ -1,597 +0,0 @@
-// Copyright (c) 2018 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package psbt
-
-// The Finalizer requires provision of a single PSBT input
-// in which all necessary signatures are encoded, and
-// uses it to construct valid final sigScript and scriptWitness
-// fields.
-// NOTE that p2sh (legacy) and p2wsh currently support only
-// multisig and no other custom script.
-
-import (
- "bytes"
- "fmt"
-
- "github.com/btcsuite/btcd/btcec/v2/schnorr"
- "github.com/btcsuite/btcd/txscript/v2"
- "github.com/btcsuite/btcd/wire/v2"
-)
-
-// isFinalized considers this input finalized if it contains at least one of
-// the FinalScriptSig or FinalScriptWitness are filled (which only occurs in a
-// successful call to Finalize*).
-func isFinalized(p *Packet, inIndex int) bool {
- input := p.Inputs[inIndex]
- return input.FinalScriptSig != nil || input.FinalScriptWitness != nil
-}
-
-// isFinalizableWitnessInput returns true if the target input is a witness UTXO
-// that can be finalized.
-func isFinalizableWitnessInput(pInput *PInput) bool {
- pkScript := pInput.WitnessUtxo.PkScript
-
- switch {
- // If this is a native witness output, then we require both
- // the witness script, but not a redeem script.
- case txscript.IsWitnessProgram(pkScript):
- switch {
- case txscript.IsPayToWitnessScriptHash(pkScript):
- if pInput.WitnessScript == nil ||
- pInput.RedeemScript != nil {
-
- return false
- }
-
- case txscript.IsPayToTaproot(pkScript):
- if pInput.TaprootKeySpendSig == nil &&
- pInput.TaprootScriptSpendSig == nil {
-
- return false
- }
-
- // For each of the script spend signatures we need a
- // corresponding tap script leaf with the control block.
- for _, sig := range pInput.TaprootScriptSpendSig {
- _, err := FindLeafScript(pInput, sig.LeafHash)
- if err != nil {
- return false
- }
- }
-
- default:
- // A P2WKH output on the other hand doesn't need
- // neither a witnessScript or redeemScript.
- if pInput.WitnessScript != nil ||
- pInput.RedeemScript != nil {
-
- return false
- }
- }
-
- // For nested P2SH inputs, we verify that a witness script is known.
- case txscript.IsPayToScriptHash(pkScript):
- if pInput.RedeemScript == nil {
- return false
- }
-
- // If this is a nested P2SH input, then it must also have a
- // witness script, while we don't need one for P2WKH.
- if txscript.IsPayToWitnessScriptHash(pInput.RedeemScript) {
- if pInput.WitnessScript == nil {
- return false
- }
- } else if txscript.IsPayToWitnessPubKeyHash(pInput.RedeemScript) {
- if pInput.WitnessScript != nil {
- return false
- }
- } else {
- // unrecognized type
- return false
- }
-
- // If this isn't a nested P2SH output or a native witness output, then
- // we can't finalize this input as we don't understand it.
- default:
- return false
- }
-
- return true
-}
-
-// isFinalizableLegacyInput returns true of the passed input a legacy input
-// (non-witness) that can be finalized.
-func isFinalizableLegacyInput(p *Packet, pInput *PInput, inIndex int) bool {
- // If the input has a witness, then it's invalid.
- if pInput.WitnessScript != nil {
- return false
- }
-
- // Otherwise, we'll verify that we only have a RedeemScript if the prev
- // output script is P2SH.
- outIndex := p.UnsignedTx.TxIn[inIndex].PreviousOutPoint.Index
- if txscript.IsPayToScriptHash(pInput.NonWitnessUtxo.TxOut[outIndex].PkScript) {
- if pInput.RedeemScript == nil {
- return false
- }
- } else {
- if pInput.RedeemScript != nil {
- return false
- }
- }
-
- return true
-}
-
-// isFinalizable checks whether the structure of the entry for the input of the
-// psbt.Packet at index inIndex contains sufficient information to finalize
-// this input.
-func isFinalizable(p *Packet, inIndex int) bool {
- pInput := p.Inputs[inIndex]
-
- // The input cannot be finalized without any signatures.
- if pInput.PartialSigs == nil && pInput.TaprootKeySpendSig == nil &&
- pInput.TaprootScriptSpendSig == nil {
-
- return false
- }
-
- // For an input to be finalized, we'll one of two possible top-level
- // UTXOs present. Each UTXO type has a distinct set of requirements to
- // be considered finalized.
- switch {
-
- // A witness input must be either native P2WSH or nested P2SH with all
- // relevant sigScript or witness data populated.
- case pInput.WitnessUtxo != nil:
- if !isFinalizableWitnessInput(&pInput) {
- return false
- }
-
- case pInput.NonWitnessUtxo != nil:
- if !isFinalizableLegacyInput(p, &pInput, inIndex) {
- return false
- }
-
- // If neither a known UTXO type isn't present at all, then we'll
- // return false as we need one of them.
- default:
- return false
- }
-
- return true
-}
-
-// MaybeFinalize attempts to finalize the input at index inIndex in the PSBT p,
-// returning true with no error if it succeeds, OR if the input has already
-// been finalized.
-func MaybeFinalize(p *Packet, inIndex int) (bool, error) {
- if isFinalized(p, inIndex) {
- return true, nil
- }
-
- if !isFinalizable(p, inIndex) {
- return false, ErrNotFinalizable
- }
-
- if err := Finalize(p, inIndex); err != nil {
- return false, err
- }
-
- return true, nil
-}
-
-// MaybeFinalizeAll attempts to finalize all inputs of the psbt.Packet that are
-// not already finalized, and returns an error if it fails to do so.
-func MaybeFinalizeAll(p *Packet) error {
- for i := range p.UnsignedTx.TxIn {
- success, err := MaybeFinalize(p, i)
- if err != nil || !success {
- return err
- }
- }
-
- return nil
-}
-
-// Finalize assumes that the provided psbt.Packet struct has all partial
-// signatures and redeem scripts/witness scripts already prepared for the
-// specified input, and so removes all temporary data and replaces them with
-// completed sigScript and witness fields, which are stored in key-types 07 and
-// 08. The witness/non-witness utxo fields in the inputs (key-types 00 and 01)
-// are left intact as they may be needed for validation (?). If there is any
-// invalid or incomplete data, an error is returned.
-func Finalize(p *Packet, inIndex int) error {
- pInput := p.Inputs[inIndex]
-
- // Depending on the UTXO type, we either attempt to finalize it as a
- // witness or legacy UTXO.
- switch {
- case pInput.WitnessUtxo != nil:
- pkScript := pInput.WitnessUtxo.PkScript
-
- switch {
- case txscript.IsPayToTaproot(pkScript):
- if err := finalizeTaprootInput(p, inIndex); err != nil {
- return err
- }
-
- default:
- if err := finalizeWitnessInput(p, inIndex); err != nil {
- return err
- }
- }
-
- case pInput.NonWitnessUtxo != nil:
- if err := finalizeNonWitnessInput(p, inIndex); err != nil {
- return err
- }
-
- default:
- return ErrInvalidPsbtFormat
- }
-
- // Before returning we sanity check the PSBT to ensure we don't extract
- // an invalid transaction or produce an invalid intermediate state.
- if err := p.SanityCheck(); err != nil {
- return err
- }
-
- return nil
-}
-
-// checkFinalScriptSigWitness checks whether a given input in the psbt.Packet
-// struct already has the fields 07 (FinalInScriptSig) or 08 (FinalInWitness).
-// If so, it returns true. It does not modify the Psbt.
-func checkFinalScriptSigWitness(p *Packet, inIndex int) bool {
- pInput := p.Inputs[inIndex]
-
- if pInput.FinalScriptSig != nil {
- return true
- }
-
- if pInput.FinalScriptWitness != nil {
- return true
- }
-
- return false
-}
-
-// finalizeNonWitnessInput attempts to create a PsbtInFinalScriptSig field for
-// the input at index inIndex, and removes all other fields except for the UTXO
-// field, for an input of type non-witness, or returns an error.
-func finalizeNonWitnessInput(p *Packet, inIndex int) error {
- // If this input has already been finalized, then we'll return an error
- // as we can't proceed.
- if checkFinalScriptSigWitness(p, inIndex) {
- return ErrInputAlreadyFinalized
- }
-
- // Our goal here is to construct a sigScript given the pubkey,
- // signature (keytype 02), of which there might be multiple, and the
- // redeem script field (keytype 04) if present (note, it is not present
- // for p2pkh type inputs).
- var sigScript []byte
-
- pInput := p.Inputs[inIndex]
- containsRedeemScript := pInput.RedeemScript != nil
-
- var (
- pubKeys [][]byte
- sigs [][]byte
- )
- for _, ps := range pInput.PartialSigs {
- pubKeys = append(pubKeys, ps.PubKey)
-
- sigOK := checkSigHashFlags(ps.Signature, &pInput)
- if !sigOK {
- return ErrInvalidSigHashFlags
- }
-
- sigs = append(sigs, ps.Signature)
- }
-
- // We have failed to identify at least 1 (sig, pub) pair in the PSBT,
- // which indicates it was not ready to be finalized. As a result, we
- // can't proceed.
- if len(sigs) < 1 || len(pubKeys) < 1 {
- return ErrNotFinalizable
- }
-
- // If this input doesn't need a redeem script (P2PKH), then we'll
- // construct a simple sigScript that's just the signature then the
- // pubkey (OP_CHECKSIG).
- var err error
- if !containsRedeemScript {
- // At this point, we should only have a single signature and
- // pubkey.
- if len(sigs) != 1 || len(pubKeys) != 1 {
- return ErrNotFinalizable
- }
-
- // In this case, our sigScript is just: <sig> <pubkey>.
- builder := txscript.NewScriptBuilder()
- builder.AddData(sigs[0]).AddData(pubKeys[0])
- sigScript, err = builder.Script()
- if err != nil {
- return err
- }
- } else {
- // This is assumed p2sh multisig Given redeemScript and pubKeys
- // we can decide in what order signatures must be appended.
- orderedSigs, err := extractKeyOrderFromScript(
- pInput.RedeemScript, pubKeys, sigs,
- )
- if err != nil {
- return err
- }
-
- // At this point, we assume that this is a mult-sig input, so
- // we construct our sigScript which looks something like this
- // (mind the extra element for the extra multi-sig pop):
- // * <nil> <sigs...> <redeemScript>
- //
- // TODO(waxwing): the below is specific to the multisig case.
- builder := txscript.NewScriptBuilder()
- builder.AddOp(txscript.OP_FALSE)
- for _, os := range orderedSigs {
- builder.AddData(os)
- }
- builder.AddData(pInput.RedeemScript)
- sigScript, err = builder.Script()
- if err != nil {
- return err
- }
- }
-
- // At this point, a sigScript has been constructed. Remove all fields
- // other than non-witness utxo (00) and finaliscriptsig (07)
- newInput := NewPsbtInput(pInput.NonWitnessUtxo, nil)
- newInput.FinalScriptSig = sigScript
-
- // Overwrite the entry in the input list at the correct index. Note
- // that this removes all the other entries in the list for this input
- // index.
- p.Inputs[inIndex] = *newInput
-
- return nil
-}
-
-// finalizeWitnessInput attempts to create PsbtInFinalScriptSig field and
-// PsbtInFinalScriptWitness field for input at index inIndex, and removes all
-// other fields except for the utxo field, for an input of type witness, or
-// returns an error.
-func finalizeWitnessInput(p *Packet, inIndex int) error {
- // If this input has already been finalized, then we'll return an error
- // as we can't proceed.
- if checkFinalScriptSigWitness(p, inIndex) {
- return ErrInputAlreadyFinalized
- }
-
- // Depending on the actual output type, we'll either populate a
- // serializedWitness or a witness as well asa sigScript.
- var (
- sigScript []byte
- serializedWitness []byte
- )
-
- pInput := p.Inputs[inIndex]
-
- // First we'll validate and collect the pubkey+sig pairs from the set
- // of partial signatures.
- var (
- pubKeys [][]byte
- sigs [][]byte
- )
- for _, ps := range pInput.PartialSigs {
- pubKeys = append(pubKeys, ps.PubKey)
-
- sigOK := checkSigHashFlags(ps.Signature, &pInput)
- if !sigOK {
- return ErrInvalidSigHashFlags
-
- }
-
- sigs = append(sigs, ps.Signature)
- }
-
- // If at this point, we don't have any pubkey+sig pairs, then we bail
- // as we can't proceed.
- if len(sigs) == 0 || len(pubKeys) == 0 {
- return ErrNotFinalizable
- }
-
- containsRedeemScript := pInput.RedeemScript != nil
- containsWitnessScript := pInput.WitnessScript != nil
-
- // If there's no redeem script, then we assume that this is native
- // segwit input.
- var err error
- if !containsRedeemScript {
- // If we have only a sigley pubkey+sig pair, and no witness
- // script, then we assume this is a P2WKH input.
- if len(pubKeys) == 1 && len(sigs) == 1 &&
- !containsWitnessScript {
-
- serializedWitness, err = writePKHWitness(
- sigs[0], pubKeys[0],
- )
- if err != nil {
- return err
- }
- } else {
- // Otherwise, we must have a witnessScript field, so
- // we'll generate a valid multi-sig witness.
- //
- // NOTE: We tacitly assume multisig.
- //
- // TODO(roasbeef): need to add custom finalize for
- // non-multisig P2WSH outputs (HTLCs, delay outputs,
- // etc).
- if !containsWitnessScript {
- return ErrNotFinalizable
- }
-
- serializedWitness, err = getMultisigScriptWitness(
- pInput.WitnessScript, pubKeys, sigs,
- )
- if err != nil {
- return err
- }
- }
- } else {
- // Otherwise, we assume that this is a p2wsh multi-sig output,
- // which is nested in a p2sh, or a p2wkh nested in a p2sh.
- //
- // In this case, we'll take the redeem script (the witness
- // program in this case), and push it on the stack within the
- // sigScript.
- builder := txscript.NewScriptBuilder()
- builder.AddData(pInput.RedeemScript)
- sigScript, err = builder.Script()
- if err != nil {
- return err
- }
-
- // If don't have a witness script, then we assume this is a
- // nested p2wkh output.
- if !containsWitnessScript {
- // Assumed p2sh-p2wkh Here the witness is just (sig,
- // pub) as for p2pkh case
- if len(sigs) != 1 || len(pubKeys) != 1 {
- return ErrNotFinalizable
- }
-
- serializedWitness, err = writePKHWitness(
- sigs[0], pubKeys[0],
- )
- if err != nil {
- return err
- }
-
- } else {
- // Otherwise, we assume that this is a p2wsh multi-sig,
- // so we generate the proper witness.
- serializedWitness, err = getMultisigScriptWitness(
- pInput.WitnessScript, pubKeys, sigs,
- )
- if err != nil {
- return err
- }
- }
- }
-
- // At this point, a witness has been constructed, and a sigScript (if
- // nested; else it's []). Remove all fields other than witness utxo
- // (01) and finalscriptsig (07), finalscriptwitness (08).
- newInput := NewPsbtInput(nil, pInput.WitnessUtxo)
- if len(sigScript) > 0 {
- newInput.FinalScriptSig = sigScript
- }
-
- newInput.FinalScriptWitness = serializedWitness
-
- // Finally, we overwrite the entry in the input list at the correct
- // index.
- p.Inputs[inIndex] = *newInput
- return nil
-}
-
-// finalizeTaprootInput attempts to create PsbtInFinalScriptWitness field for
-// input at index inIndex, and removes all other fields except for the utxo
-// field, for an input of type p2tr, or returns an error.
-func finalizeTaprootInput(p *Packet, inIndex int) error {
- // If this input has already been finalized, then we'll return an error
- // as we can't proceed.
- if checkFinalScriptSigWitness(p, inIndex) {
- return ErrInputAlreadyFinalized
- }
-
- // Any p2tr input will only have a witness script, no sig script.
- var (
- serializedWitness []byte
- err error
- pInput = &p.Inputs[inIndex]
- )
-
- // What spend path did we take?
- switch {
- // Key spend path.
- case len(pInput.TaprootKeySpendSig) > 0:
- sig := pInput.TaprootKeySpendSig
-
- // Make sure TaprootKeySpendSig is equal to size of signature,
- // if not, we assume that sighash flag was appended to the
- // signature.
- if len(pInput.TaprootKeySpendSig) == schnorr.SignatureSize {
- // Append to the signature if flag is not equal to the
- // default sighash (that can be omitted).
- if pInput.SighashType != txscript.SigHashDefault {
- sigHashType := byte(pInput.SighashType)
- sig = append(sig, sigHashType)
- }
- }
- serializedWitness, err = writeWitness(sig)
-
- // Script spend path.
- case len(pInput.TaprootScriptSpendSig) > 0:
- var witnessStack wire.TxWitness
-
- // If there are multiple script spend signatures, we assume they
- // are from multiple signing participants for the same leaf
- // script that uses OP_CHECKSIGADD for multi-sig. Signing
- // multiple possible execution paths at the same time is
- // currently not supported by this library.
- targetLeafHash := pInput.TaprootScriptSpendSig[0].LeafHash
- leafScript, err := FindLeafScript(pInput, targetLeafHash)
- if err != nil {
- return fmt.Errorf("control block for script spend " +
- "signature not found")
- }
-
- // The witness stack will contain all signatures, followed by
- // the script itself and then the control block.
- for idx, scriptSpendSig := range pInput.TaprootScriptSpendSig {
- // Make sure that if there are indeed multiple
- // signatures, they all reference the same leaf hash.
- if !bytes.Equal(scriptSpendSig.LeafHash, targetLeafHash) {
- return fmt.Errorf("script spend signature %d "+
- "references different target leaf "+
- "hash than first signature; only one "+
- "script path is supported", idx)
- }
-
- sig := append([]byte{}, scriptSpendSig.Signature...)
- if scriptSpendSig.SigHash != txscript.SigHashDefault {
- sig = append(sig, byte(scriptSpendSig.SigHash))
- }
- witnessStack = append(witnessStack, sig)
- }
-
- // Complete the witness stack with the executed script and the
- // serialized control block.
- witnessStack = append(witnessStack, leafScript.Script)
- witnessStack = append(witnessStack, leafScript.ControlBlock)
-
- serializedWitness, err = writeWitness(witnessStack...)
-
- default:
- return ErrInvalidPsbtFormat
- }
- if err != nil {
- return err
- }
-
- // At this point, a witness has been constructed. Remove all fields
- // other than witness utxo (01) and finalscriptsig (07),
- // finalscriptwitness (08).
- newInput := NewPsbtInput(nil, pInput.WitnessUtxo)
- newInput.FinalScriptWitness = serializedWitness
-
- // Finally, we overwrite the entry in the input list at the correct
- // index.
- p.Inputs[inIndex] = *newInput
- return nil
-}
diff --git a/btcutil/psbt/go.mod b/btcutil/psbt/go.mod
deleted file mode 100644
index 26a6057..0000000
--- a/btcutil/psbt/go.mod
+++ /dev/null
@@ -1,23 +0,0 @@
-module github.com/btcsuite/btcd/btcutil/psbt
-
-go 1.25
-
-require (
- github.com/btcsuite/btcd v0.24.2
- github.com/btcsuite/btcd/btcec/v2 v2.4.0
- github.com/btcsuite/btcd/btcutil v1.2.0
- github.com/btcsuite/btcd/chaincfg/chainhash v1.2.0
- github.com/davecgh/go-spew v1.1.1
- github.com/stretchr/testify v1.8.4
-)
-
-require (
- github.com/btcsuite/btclog v1.0.0 // indirect
- github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect
- github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
- github.com/kcalvinalvin/anet v0.0.0-20251112173137-d8ddc1f6dbee // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- golang.org/x/crypto v0.33.0 // indirect
- golang.org/x/sys v0.30.0 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
-)
diff --git a/btcutil/psbt/go.sum b/btcutil/psbt/go.sum
deleted file mode 100644
index d344aae..0000000
--- a/btcutil/psbt/go.sum
+++ /dev/null
@@ -1,30 +0,0 @@
-github.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY=
-github.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg=
-github.com/btcsuite/btcd/btcec/v2 v2.4.0 h1:9JgnRkOL8J1UKuGlpJs7oL5tFRgrBgyM/uhwfS+cUiI=
-github.com/btcsuite/btcd/btcec/v2 v2.4.0/go.mod h1:64BXFSNzV1koQHPqljB4LaD6lZPQEQNZ38zMImajCRo=
-github.com/btcsuite/btcd/btcutil v1.2.0 h1:p3+S2g3Q+7G5NOh4Ji+2UrBOrg5Z0Q4ykzShWG1Dhgs=
-github.com/btcsuite/btcd/btcutil v1.2.0/go.mod h1:/Taflm113pYjUpbWKKQEfa6XOtI/+WS8awxeMZpY75k=
-github.com/btcsuite/btcd/chaincfg/chainhash v1.2.0 h1:yMIg99+4aBvqfl/HzJRKfxTX9rGfikoI9uvFzterhc8=
-github.com/btcsuite/btcd/chaincfg/chainhash v1.2.0/go.mod h1:Y72Ren9gfhlEvnwnT78BGcSNO2UMphTKLn9AorF+5rg=
-github.com/btcsuite/btclog v1.0.0 h1:sEkpKJMmfGiyZjADwEIgB1NSwMyfdD1FB8v6+w1T0Ns=
-github.com/btcsuite/btclog v1.0.0/go.mod h1:w7xnGOhwT3lmrS4H3b/D1XAXxvh+tbhUm8xeHN2y3TQ=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
-github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
-github.com/kcalvinalvin/anet v0.0.0-20251112173137-d8ddc1f6dbee h1:FPP9HDkBbPyniu+u7FHZg+kKFX1WW0gxOGteJ0h3AJk=
-github.com/kcalvinalvin/anet v0.0.0-20251112173137-d8ddc1f6dbee/go.mod h1:N6sz6HwJAenJ6d+/xmSl0ikfV05ZrVGmjt1ryy/WOtE=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
-golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
-golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
-golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/btcutil/psbt/partial_input.go b/btcutil/psbt/partial_input.go
deleted file mode 100644
index 2e784be..0000000
--- a/btcutil/psbt/partial_input.go
+++ /dev/null
@@ -1,605 +0,0 @@
-package psbt
-
-import (
- "bytes"
- "encoding/binary"
- "io"
- "sort"
-
- "github.com/btcsuite/btcd/txscript/v2"
- "github.com/btcsuite/btcd/wire/v2"
-)
-
-// PInput is a struct encapsulating all the data that can be attached to any
-// specific input of the PSBT.
-type PInput struct {
- NonWitnessUtxo *wire.MsgTx
- WitnessUtxo *wire.TxOut
- PartialSigs []*PartialSig
- SighashType txscript.SigHashType
- RedeemScript []byte
- WitnessScript []byte
- Bip32Derivation []*Bip32Derivation
- FinalScriptSig []byte
- FinalScriptWitness []byte
- TaprootKeySpendSig []byte
- TaprootScriptSpendSig []*TaprootScriptSpendSig
- TaprootLeafScript []*TaprootTapLeafScript
- TaprootBip32Derivation []*TaprootBip32Derivation
- TaprootInternalKey []byte
- TaprootMerkleRoot []byte
- Unknowns []*Unknown
-}
-
-// NewPsbtInput creates an instance of PsbtInput given either a nonWitnessUtxo
-// or a witnessUtxo.
-//
-// NOTE: Only one of the two arguments should be specified, with the other
-// being `nil`; otherwise the created PsbtInput object will fail IsSane()
-// checks and will not be usable.
-func NewPsbtInput(nonWitnessUtxo *wire.MsgTx, witnessUtxo *wire.TxOut) *PInput {
- return &PInput{
- NonWitnessUtxo: nonWitnessUtxo,
- WitnessUtxo: witnessUtxo,
- PartialSigs: []*PartialSig{},
- SighashType: 0,
- RedeemScript: nil,
- WitnessScript: nil,
- Bip32Derivation: []*Bip32Derivation{},
- FinalScriptSig: nil,
- FinalScriptWitness: nil,
- Unknowns: nil,
- }
-}
-
-// IsSane returns true only if there are no conflicting values in the Psbt
-// PInput. For segwit v0 no checks are currently implemented.
-func (pi *PInput) IsSane() bool {
- // TODO(guggero): Implement sanity checks for segwit v1. For segwit v0
- // it is unsafe to only rely on the witness UTXO so we don't check that
- // only one is set anymore.
- // See https://github.com/bitcoin/bitcoin/pull/19215.
-
- return true
-}
-
-// deserialize attempts to deserialize a new PInput from the passed io.Reader.
-func (pi *PInput) deserialize(r io.Reader) error {
- for {
- keyCode, keyData, err := getKey(r)
- if err != nil {
- return err
- }
- if keyCode == -1 {
- // Reached separator byte, this section is done.
- break
- }
- value, err := wire.ReadVarBytes(
- r, 0, MaxPsbtValueLength, "PSBT value",
- )
- if err != nil {
- return err
- }
-
- switch InputType(keyCode) {
-
- case NonWitnessUtxoType:
- if pi.NonWitnessUtxo != nil {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
- tx := wire.NewMsgTx(2)
-
- err := tx.Deserialize(bytes.NewReader(value))
- if err != nil {
- return err
- }
- pi.NonWitnessUtxo = tx
-
- case WitnessUtxoType:
- if pi.WitnessUtxo != nil {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
- txout, err := readTxOut(value)
- if err != nil {
- return err
- }
- pi.WitnessUtxo = txout
-
- case PartialSigType:
- newPartialSig := PartialSig{
- PubKey: keyData,
- Signature: value,
- }
-
- if !newPartialSig.checkValid() {
- return ErrInvalidPsbtFormat
- }
-
- // Duplicate keys are not allowed.
- for _, x := range pi.PartialSigs {
- if bytes.Equal(x.PubKey, newPartialSig.PubKey) {
- return ErrDuplicateKey
- }
- }
-
- pi.PartialSigs = append(pi.PartialSigs, &newPartialSig)
-
- case SighashType:
- if pi.SighashType != 0 {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
-
- // Bounds check on value here since the sighash type
- // must be a 32-bit unsigned integer.
- if len(value) != 4 {
- return ErrInvalidKeyData
- }
-
- sighashType := txscript.SigHashType(
- binary.LittleEndian.Uint32(value),
- )
- pi.SighashType = sighashType
-
- case RedeemScriptInputType:
- if pi.RedeemScript != nil {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
- pi.RedeemScript = value
-
- case WitnessScriptInputType:
- if pi.WitnessScript != nil {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
- pi.WitnessScript = value
-
- case Bip32DerivationInputType:
- if !validatePubkey(keyData) {
- return ErrInvalidPsbtFormat
- }
- master, derivationPath, err := ReadBip32Derivation(
- value,
- )
- if err != nil {
- return err
- }
-
- // Duplicate keys are not allowed
- for _, x := range pi.Bip32Derivation {
- if bytes.Equal(x.PubKey, keyData) {
- return ErrDuplicateKey
- }
- }
-
- pi.Bip32Derivation = append(
- pi.Bip32Derivation,
- &Bip32Derivation{
- PubKey: keyData,
- MasterKeyFingerprint: master,
- Bip32Path: derivationPath,
- },
- )
-
- case FinalScriptSigType:
- if pi.FinalScriptSig != nil {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
-
- pi.FinalScriptSig = value
-
- case FinalScriptWitnessType:
- if pi.FinalScriptWitness != nil {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
-
- pi.FinalScriptWitness = value
-
- case TaprootKeySpendSignatureType:
- if pi.TaprootKeySpendSig != nil {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
-
- // The signature can either be 64 or 65 bytes.
- switch {
- case len(value) == schnorrSigMinLength:
- if !validateSchnorrSignature(value) {
- return ErrInvalidKeyData
- }
-
- case len(value) == schnorrSigMaxLength:
- if !validateSchnorrSignature(
- value[0:schnorrSigMinLength],
- ) {
- return ErrInvalidKeyData
- }
-
- default:
- return ErrInvalidKeyData
- }
-
- pi.TaprootKeySpendSig = value
-
- case TaprootScriptSpendSignatureType:
- // The key data for the script spend signature is:
- // <xonlypubkey> <leafhash>
- if len(keyData) != 32*2 {
- return ErrInvalidKeyData
- }
-
- newPartialSig := TaprootScriptSpendSig{
- XOnlyPubKey: keyData[:32],
- LeafHash: keyData[32:],
- }
-
- // The signature can either be 64 or 65 bytes.
- switch {
- case len(value) == schnorrSigMinLength:
- newPartialSig.Signature = value
- newPartialSig.SigHash = txscript.SigHashDefault
-
- case len(value) == schnorrSigMaxLength:
- newPartialSig.Signature = value[0:schnorrSigMinLength]
- newPartialSig.SigHash = txscript.SigHashType(
- value[schnorrSigMinLength],
- )
-
- default:
- return ErrInvalidKeyData
- }
-
- if !newPartialSig.checkValid() {
- return ErrInvalidKeyData
- }
-
- // Duplicate keys are not allowed.
- for _, x := range pi.TaprootScriptSpendSig {
- if x.EqualKey(&newPartialSig) {
- return ErrDuplicateKey
- }
- }
-
- pi.TaprootScriptSpendSig = append(
- pi.TaprootScriptSpendSig, &newPartialSig,
- )
-
- case TaprootLeafScriptType:
- if len(value) < 1 {
- return ErrInvalidKeyData
- }
-
- newLeafScript := TaprootTapLeafScript{
- ControlBlock: keyData,
- Script: value[:len(value)-1],
- LeafVersion: txscript.TapscriptLeafVersion(
- value[len(value)-1],
- ),
- }
-
- if !newLeafScript.checkValid() {
- return ErrInvalidKeyData
- }
-
- // Duplicate keys are not allowed.
- for _, x := range pi.TaprootLeafScript {
- if bytes.Equal(
- x.ControlBlock,
- newLeafScript.ControlBlock,
- ) {
- return ErrDuplicateKey
- }
- }
-
- pi.TaprootLeafScript = append(
- pi.TaprootLeafScript, &newLeafScript,
- )
-
- case TaprootBip32DerivationInputType:
- if !validateXOnlyPubkey(keyData) {
- return ErrInvalidKeyData
- }
-
- taprootDerivation, err := ReadTaprootBip32Derivation(
- keyData, value,
- )
- if err != nil {
- return err
- }
-
- // Duplicate keys are not allowed.
- for _, x := range pi.TaprootBip32Derivation {
- if bytes.Equal(x.XOnlyPubKey, keyData) {
- return ErrDuplicateKey
- }
- }
-
- pi.TaprootBip32Derivation = append(
- pi.TaprootBip32Derivation, taprootDerivation,
- )
-
- case TaprootInternalKeyInputType:
- if pi.TaprootInternalKey != nil {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
-
- if !validateXOnlyPubkey(value) {
- return ErrInvalidKeyData
- }
-
- pi.TaprootInternalKey = value
-
- case TaprootMerkleRootType:
- if pi.TaprootMerkleRoot != nil {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
-
- pi.TaprootMerkleRoot = value
-
- default:
- // A fall through case for any proprietary types.
- keyCodeAndData := append(
- []byte{byte(keyCode)}, keyData...,
- )
- newUnknown := &Unknown{
- Key: keyCodeAndData,
- Value: value,
- }
-
- // Duplicate key+keyData are not allowed.
- for _, x := range pi.Unknowns {
- if bytes.Equal(x.Key, newUnknown.Key) &&
- bytes.Equal(x.Value, newUnknown.Value) {
-
- return ErrDuplicateKey
- }
- }
-
- pi.Unknowns = append(pi.Unknowns, newUnknown)
- }
- }
-
- return nil
-}
-
-// serialize attempts to serialize the target PInput into the passed io.Writer.
-func (pi *PInput) serialize(w io.Writer) error {
- if !pi.IsSane() {
- return ErrInvalidPsbtFormat
- }
-
- if pi.NonWitnessUtxo != nil {
- var buf bytes.Buffer
- err := pi.NonWitnessUtxo.Serialize(&buf)
- if err != nil {
- return err
- }
-
- err = serializeKVPairWithType(
- w, uint8(NonWitnessUtxoType), nil, buf.Bytes(),
- )
- if err != nil {
- return err
- }
- }
- if pi.WitnessUtxo != nil {
- var buf bytes.Buffer
- err := wire.WriteTxOut(&buf, 0, 0, pi.WitnessUtxo)
- if err != nil {
- return err
- }
-
- err = serializeKVPairWithType(
- w, uint8(WitnessUtxoType), nil, buf.Bytes(),
- )
- if err != nil {
- return err
- }
- }
-
- if pi.FinalScriptSig == nil && pi.FinalScriptWitness == nil {
- sort.Sort(PartialSigSorter(pi.PartialSigs))
- for _, ps := range pi.PartialSigs {
- err := serializeKVPairWithType(
- w, uint8(PartialSigType), ps.PubKey,
- ps.Signature,
- )
- if err != nil {
- return err
- }
- }
-
- if pi.SighashType != 0 {
- var shtBytes [4]byte
- binary.LittleEndian.PutUint32(
- shtBytes[:], uint32(pi.SighashType),
- )
-
- err := serializeKVPairWithType(
- w, uint8(SighashType), nil, shtBytes[:],
- )
- if err != nil {
- return err
- }
- }
-
- if pi.RedeemScript != nil {
- err := serializeKVPairWithType(
- w, uint8(RedeemScriptInputType), nil,
- pi.RedeemScript,
- )
- if err != nil {
- return err
- }
- }
-
- if pi.WitnessScript != nil {
- err := serializeKVPairWithType(
- w, uint8(WitnessScriptInputType), nil,
- pi.WitnessScript,
- )
- if err != nil {
- return err
- }
- }
-
- sort.Sort(Bip32Sorter(pi.Bip32Derivation))
- for _, kd := range pi.Bip32Derivation {
- err := serializeKVPairWithType(
- w,
- uint8(Bip32DerivationInputType), kd.PubKey,
- SerializeBIP32Derivation(
- kd.MasterKeyFingerprint, kd.Bip32Path,
- ),
- )
- if err != nil {
- return err
- }
- }
-
- if pi.TaprootKeySpendSig != nil {
- err := serializeKVPairWithType(
- w, uint8(TaprootKeySpendSignatureType), nil,
- pi.TaprootKeySpendSig,
- )
- if err != nil {
- return err
- }
- }
-
- sort.Slice(pi.TaprootScriptSpendSig, func(i, j int) bool {
- return pi.TaprootScriptSpendSig[i].SortBefore(
- pi.TaprootScriptSpendSig[j],
- )
- })
- for _, scriptSpend := range pi.TaprootScriptSpendSig {
- keyData := append([]byte{}, scriptSpend.XOnlyPubKey...)
- keyData = append(keyData, scriptSpend.LeafHash...)
- value := append([]byte{}, scriptSpend.Signature...)
- if scriptSpend.SigHash != txscript.SigHashDefault {
- value = append(value, byte(scriptSpend.SigHash))
- }
- err := serializeKVPairWithType(
- w, uint8(TaprootScriptSpendSignatureType),
- keyData, value,
- )
- if err != nil {
- return err
- }
- }
-
- sort.Slice(pi.TaprootLeafScript, func(i, j int) bool {
- return pi.TaprootLeafScript[i].SortBefore(
- pi.TaprootLeafScript[j],
- )
- })
- for _, leafScript := range pi.TaprootLeafScript {
- value := append([]byte{}, leafScript.Script...)
- value = append(value, byte(leafScript.LeafVersion))
- err := serializeKVPairWithType(
- w, uint8(TaprootLeafScriptType),
- leafScript.ControlBlock, value,
- )
- if err != nil {
- return err
- }
- }
-
- sort.Slice(pi.TaprootBip32Derivation, func(i, j int) bool {
- return pi.TaprootBip32Derivation[i].SortBefore(
- pi.TaprootBip32Derivation[j],
- )
- })
- for _, derivation := range pi.TaprootBip32Derivation {
- value, err := SerializeTaprootBip32Derivation(
- derivation,
- )
- if err != nil {
- return err
- }
- err = serializeKVPairWithType(
- w, uint8(TaprootBip32DerivationInputType),
- derivation.XOnlyPubKey, value,
- )
- if err != nil {
- return err
- }
- }
-
- if pi.TaprootInternalKey != nil {
- err := serializeKVPairWithType(
- w, uint8(TaprootInternalKeyInputType), nil,
- pi.TaprootInternalKey,
- )
- if err != nil {
- return err
- }
- }
-
- if pi.TaprootMerkleRoot != nil {
- err := serializeKVPairWithType(
- w, uint8(TaprootMerkleRootType), nil,
- pi.TaprootMerkleRoot,
- )
- if err != nil {
- return err
- }
- }
- }
-
- if pi.FinalScriptSig != nil {
- err := serializeKVPairWithType(
- w, uint8(FinalScriptSigType), nil, pi.FinalScriptSig,
- )
- if err != nil {
- return err
- }
- }
-
- if pi.FinalScriptWitness != nil {
- err := serializeKVPairWithType(
- w, uint8(FinalScriptWitnessType), nil, pi.FinalScriptWitness,
- )
- if err != nil {
- return err
- }
- }
-
- // Unknown is a special case; we don't have a key type, only a key and
- // a value field.
- for _, kv := range pi.Unknowns {
- err := serializeKVpair(w, kv.Key, kv.Value)
- if err != nil {
- return err
- }
- }
-
- return nil
-}
diff --git a/btcutil/psbt/partial_output.go b/btcutil/psbt/partial_output.go
deleted file mode 100644
index 94b5d33..0000000
--- a/btcutil/psbt/partial_output.go
+++ /dev/null
@@ -1,259 +0,0 @@
-package psbt
-
-import (
- "bytes"
- "io"
- "sort"
-
- "github.com/btcsuite/btcd/wire/v2"
-)
-
-// POutput is a struct encapsulating all the data that can be attached
-// to any specific output of the PSBT.
-type POutput struct {
- RedeemScript []byte
- WitnessScript []byte
- Bip32Derivation []*Bip32Derivation
- TaprootInternalKey []byte
- TaprootTapTree []byte
- TaprootBip32Derivation []*TaprootBip32Derivation
- Unknowns []*Unknown
-}
-
-// NewPsbtOutput creates an instance of PsbtOutput; the three parameters
-// redeemScript, witnessScript and Bip32Derivation are all allowed to be
-// `nil`.
-func NewPsbtOutput(redeemScript []byte, witnessScript []byte,
- bip32Derivation []*Bip32Derivation) *POutput {
- return &POutput{
- RedeemScript: redeemScript,
- WitnessScript: witnessScript,
- Bip32Derivation: bip32Derivation,
- }
-}
-
-// deserialize attempts to recode a new POutput from the passed io.Reader.
-func (po *POutput) deserialize(r io.Reader) error {
- for {
- keyCode, keyData, err := getKey(r)
- if err != nil {
- return err
- }
- if keyCode == -1 {
- // Reached separator byte, this section is done.
- break
- }
-
- value, err := wire.ReadVarBytes(
- r, 0, MaxPsbtValueLength, "PSBT value",
- )
- if err != nil {
- return err
- }
-
- switch OutputType(keyCode) {
-
- case RedeemScriptOutputType:
- if po.RedeemScript != nil {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
- po.RedeemScript = value
-
- case WitnessScriptOutputType:
- if po.WitnessScript != nil {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
- po.WitnessScript = value
-
- case Bip32DerivationOutputType:
- if !validatePubkey(keyData) {
- return ErrInvalidKeyData
- }
- master, derivationPath, err := ReadBip32Derivation(
- value,
- )
- if err != nil {
- return err
- }
-
- // Duplicate keys are not allowed.
- for _, x := range po.Bip32Derivation {
- if bytes.Equal(x.PubKey, keyData) {
- return ErrDuplicateKey
- }
- }
-
- po.Bip32Derivation = append(po.Bip32Derivation,
- &Bip32Derivation{
- PubKey: keyData,
- MasterKeyFingerprint: master,
- Bip32Path: derivationPath,
- },
- )
-
- case TaprootInternalKeyOutputType:
- if po.TaprootInternalKey != nil {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
-
- if !validateXOnlyPubkey(value) {
- return ErrInvalidKeyData
- }
-
- po.TaprootInternalKey = value
-
- case TaprootTapTreeType:
- if po.TaprootTapTree != nil {
- return ErrDuplicateKey
- }
- if keyData != nil {
- return ErrInvalidKeyData
- }
-
- po.TaprootTapTree = value
-
- case TaprootBip32DerivationOutputType:
- if !validateXOnlyPubkey(keyData) {
- return ErrInvalidKeyData
- }
-
- taprootDerivation, err := ReadTaprootBip32Derivation(
- keyData, value,
- )
- if err != nil {
- return err
- }
-
- // Duplicate keys are not allowed.
- for _, x := range po.TaprootBip32Derivation {
- if bytes.Equal(x.XOnlyPubKey, keyData) {
- return ErrDuplicateKey
- }
- }
-
- po.TaprootBip32Derivation = append(
- po.TaprootBip32Derivation, taprootDerivation,
- )
-
- default:
- // A fall through case for any proprietary types.
- keyCodeAndData := append(
- []byte{byte(keyCode)}, keyData...,
- )
- newUnknown := &Unknown{
- Key: keyCodeAndData,
- Value: value,
- }
-
- // Duplicate key+keyData are not allowed.
- for _, x := range po.Unknowns {
- if bytes.Equal(x.Key, newUnknown.Key) &&
- bytes.Equal(x.Value, newUnknown.Value) {
-
- return ErrDuplicateKey
- }
- }
-
- po.Unknowns = append(po.Unknowns, newUnknown)
- }
- }
-
- return nil
-}
-
-// serialize attempts to write out the target POutput into the passed
-// io.Writer.
-func (po *POutput) serialize(w io.Writer) error {
- if po.RedeemScript != nil {
- err := serializeKVPairWithType(
- w, uint8(RedeemScriptOutputType), nil, po.RedeemScript,
- )
- if err != nil {
- return err
- }
- }
- if po.WitnessScript != nil {
- err := serializeKVPairWithType(
- w, uint8(WitnessScriptOutputType), nil, po.WitnessScript,
- )
- if err != nil {
- return err
- }
- }
-
- sort.Sort(Bip32Sorter(po.Bip32Derivation))
- for _, kd := range po.Bip32Derivation {
- err := serializeKVPairWithType(w,
- uint8(Bip32DerivationOutputType),
- kd.PubKey,
- SerializeBIP32Derivation(
- kd.MasterKeyFingerprint,
- kd.Bip32Path,
- ),
- )
- if err != nil {
- return err
- }
- }
-
- if po.TaprootInternalKey != nil {
- err := serializeKVPairWithType(
- w, uint8(TaprootInternalKeyOutputType), nil,
- po.TaprootInternalKey,
- )
- if err != nil {
- return err
- }
- }
-
- if po.TaprootTapTree != nil {
- err := serializeKVPairWithType(
- w, uint8(TaprootTapTreeType), nil,
- po.TaprootTapTree,
- )
- if err != nil {
- return err
- }
- }
-
- sort.Slice(po.TaprootBip32Derivation, func(i, j int) bool {
- return po.TaprootBip32Derivation[i].SortBefore(
- po.TaprootBip32Derivation[j],
- )
- })
- for _, derivation := range po.TaprootBip32Derivation {
- value, err := SerializeTaprootBip32Derivation(
- derivation,
- )
- if err != nil {
- return err
- }
- err = serializeKVPairWithType(
- w, uint8(TaprootBip32DerivationOutputType),
- derivation.XOnlyPubKey, value,
- )
- if err != nil {
- return err
- }
- }
-
- // Unknown is a special case; we don't have a key type, only a key and
- // a value field
- for _, kv := range po.Unknowns {
- err := serializeKVpair(w, kv.Key, kv.Value)
- if err != nil {
- return err
- }
- }
-
- return nil
-}
diff --git a/btcutil/psbt/partialsig.go b/btcutil/psbt/partialsig.go
deleted file mode 100644
index 9d24c49..0000000
--- a/btcutil/psbt/partialsig.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package psbt
-
-import (
- "bytes"
-
- "github.com/btcsuite/btcd/btcec/v2"
- "github.com/btcsuite/btcd/btcec/v2/ecdsa"
-)
-
-// PartialSig encapsulate a (BTC public key, ECDSA signature)
-// pair, note that the fields are stored as byte slices, not
-// btcec.PublicKey or btcec.Signature (because manipulations will
-// be with the former not the latter, here); compliance with consensus
-// serialization is enforced with .checkValid()
-type PartialSig struct {
- PubKey []byte
- Signature []byte
-}
-
-// PartialSigSorter implements sort.Interface for PartialSig.
-type PartialSigSorter []*PartialSig
-
-func (s PartialSigSorter) Len() int { return len(s) }
-
-func (s PartialSigSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
-func (s PartialSigSorter) Less(i, j int) bool {
- return bytes.Compare(s[i].PubKey, s[j].PubKey) < 0
-}
-
-// validatePubkey checks if pubKey is *any* valid pubKey serialization in a
-// Bitcoin context (compressed/uncomp. OK).
-func validatePubkey(pubKey []byte) bool {
- _, err := btcec.ParsePubKey(pubKey)
- return err == nil
-}
-
-// validateSignature checks that the passed byte slice is a valid DER-encoded
-// ECDSA signature, including the sighash flag. It does *not* of course
-// validate the signature against any message or public key.
-func validateSignature(sig []byte) bool {
- _, err := ecdsa.ParseDERSignature(sig)
- return err == nil
-}
-
-// checkValid checks that both the pubkey and sig are valid. See the methods
-// (PartialSig, validatePubkey, validateSignature) for more details.
-func (ps *PartialSig) checkValid() bool {
- return validatePubkey(ps.PubKey) && validateSignature(ps.Signature)
-}
diff --git a/btcutil/psbt/psbt.go b/btcutil/psbt/psbt.go
deleted file mode 100644
index 264f671..0000000
--- a/btcutil/psbt/psbt.go
+++ /dev/null
@@ -1,468 +0,0 @@
-// Copyright (c) 2018 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-// Package psbt is an implementation of Partially Signed Bitcoin
-// Transactions (PSBT). The format is defined in BIP 174:
-// https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
-package psbt
-
-import (
- "bytes"
- "encoding/base64"
- "errors"
- "io"
-
- "github.com/btcsuite/btcd/btcutil/v2"
- "github.com/btcsuite/btcd/wire/v2"
-)
-
-// psbtMagicLength is the length of the magic bytes used to signal the start of
-// a serialized PSBT packet.
-const psbtMagicLength = 5
-
-var (
- // psbtMagic is the separator.
- psbtMagic = [psbtMagicLength]byte{0x70,
- 0x73, 0x62, 0x74, 0xff, // = "psbt" + 0xff sep
- }
-)
-
-// MaxPsbtValueLength is the size of the largest transaction serialization
-// that could be passed in a NonWitnessUtxo field. This is definitely
-// less than 4M.
-const MaxPsbtValueLength = 4000000
-
-// MaxPsbtKeyLength is the length of the largest key that we'll successfully
-// deserialize from the wire. Anything more will return ErrInvalidKeyData.
-const MaxPsbtKeyLength = 10000
-
-// MaxPsbtKeyValue is the maximum value of a key type in a PSBT. This maximum
-// isn't specified by the BIP but used by bitcoind in various places to limit
-// the number of items processed. So we use it to validate the key type in order
-// to have a consistent behavior.
-const MaxPsbtKeyValue = 0x02000000
-
-var (
-
- // ErrInvalidPsbtFormat is a generic error for any situation in which a
- // provided Psbt serialization does not conform to the rules of BIP174.
- ErrInvalidPsbtFormat = errors.New("Invalid PSBT serialization format")
-
- // ErrDuplicateKey indicates that a passed Psbt serialization is invalid
- // due to having the same key repeated in the same key-value pair.
- ErrDuplicateKey = errors.New("Invalid Psbt due to duplicate key")
-
- // ErrInvalidKeyData indicates that a key-value pair in the PSBT
- // serialization contains data in the key which is not valid.
- ErrInvalidKeyData = errors.New("Invalid key data")
-
- // ErrInvalidMagicBytes indicates that a passed Psbt serialization is
- // invalid due to having incorrect magic bytes.
- ErrInvalidMagicBytes = errors.New("Invalid Psbt due to incorrect " +
- "magic bytes")
-
- // ErrInvalidRawTxSigned indicates that the raw serialized transaction
- // in the global section of the passed Psbt serialization is invalid
- // because it contains scriptSigs/witnesses (i.e. is fully or partially
- // signed), which is not allowed by BIP174.
- ErrInvalidRawTxSigned = errors.New("Invalid Psbt, raw transaction " +
- "must be unsigned.")
-
- // ErrInvalidPrevOutNonWitnessTransaction indicates that the transaction
- // hash (i.e. SHA256^2) of the fully serialized previous transaction
- // provided in the NonWitnessUtxo key-value field doesn't match the
- // prevout hash in the UnsignedTx field in the PSBT itself.
- ErrInvalidPrevOutNonWitnessTransaction = errors.New("Prevout hash " +
- "does not match the provided non-witness utxo serialization")
-
- // ErrInvalidSignatureForInput indicates that the signature the user is
- // trying to append to the PSBT is invalid, either because it does
- // not correspond to the previous transaction hash, or redeem script,
- // or witness script.
- // NOTE this does not include ECDSA signature checking.
- ErrInvalidSignatureForInput = errors.New("Signature does not " +
- "correspond to this input")
-
- // ErrInputAlreadyFinalized indicates that the PSBT passed to a
- // Finalizer already contains the finalized scriptSig or witness.
- ErrInputAlreadyFinalized = errors.New("Cannot finalize PSBT, " +
- "finalized scriptSig or scriptWitnes already exists")
-
- // ErrIncompletePSBT indicates that the Extractor object
- // was unable to successfully extract the passed Psbt struct because
- // it is not complete
- ErrIncompletePSBT = errors.New("PSBT cannot be extracted as it is " +
- "incomplete")
-
- // ErrNotFinalizable indicates that the PSBT struct does not have
- // sufficient data (e.g. signatures) for finalization
- ErrNotFinalizable = errors.New("PSBT is not finalizable")
-
- // ErrInvalidSigHashFlags indicates that a signature added to the PSBT
- // uses Sighash flags that are not in accordance with the requirement
- // according to the entry in PsbtInSighashType, or otherwise not the
- // default value (SIGHASH_ALL)
- ErrInvalidSigHashFlags = errors.New("Invalid Sighash Flags")
-
- // ErrUnsupportedScriptType indicates that the redeem script or
- // script witness given is not supported by this codebase, or is
- // otherwise not valid.
- ErrUnsupportedScriptType = errors.New("Unsupported script type")
-)
-
-// Unknown is a struct encapsulating a key-value pair for which the key type is
-// unknown by this package; these fields are allowed in both the 'Global' and
-// the 'Input' section of a PSBT.
-type Unknown struct {
- Key []byte
- Value []byte
-}
-
-// Packet is the actual psbt representation. It is a set of 1 + N + M
-// key-value pair lists, 1 global, defining the unsigned transaction structure
-// with N inputs and M outputs. These key-value pairs can contain scripts,
-// signatures, key derivations and other transaction-defining data.
-type Packet struct {
- // UnsignedTx is the decoded unsigned transaction for this PSBT.
- UnsignedTx *wire.MsgTx // Deserialization of unsigned tx
-
- // Inputs contains all the information needed to properly sign this
- // target input within the above transaction.
- Inputs []PInput
-
- // Outputs contains all information required to spend any outputs
- // produced by this PSBT.
- Outputs []POutput
-
- // XPubs is a list of extended public keys that can be used to derive
- // public keys used in the inputs and outputs of this transaction. It
- // should be the public key at the highest hardened derivation index so
- // that the unhardened child keys used in the transaction can be
- // derived.
- XPubs []XPub
-
- // Unknowns are the set of custom types (global only) within this PSBT.
- Unknowns []*Unknown
-}
-
-// validateUnsignedTx returns true if the transaction is unsigned. Note that
-// more basic sanity requirements, such as the presence of inputs and outputs,
-// is implicitly checked in the call to MsgTx.Deserialize().
-func validateUnsignedTX(tx *wire.MsgTx) bool {
- for _, tin := range tx.TxIn {
- if len(tin.SignatureScript) != 0 || len(tin.Witness) != 0 {
- return false
- }
- }
-
- return true
-}
-
-// NewFromUnsignedTx creates a new Psbt struct, without any signatures (i.e.
-// only the global section is non-empty) using the passed unsigned transaction.
-func NewFromUnsignedTx(tx *wire.MsgTx) (*Packet, error) {
- if !validateUnsignedTX(tx) {
- return nil, ErrInvalidRawTxSigned
- }
-
- inSlice := make([]PInput, len(tx.TxIn))
- outSlice := make([]POutput, len(tx.TxOut))
- xPubSlice := make([]XPub, 0)
- unknownSlice := make([]*Unknown, 0)
-
- return &Packet{
- UnsignedTx: tx,
- Inputs: inSlice,
- Outputs: outSlice,
- XPubs: xPubSlice,
- Unknowns: unknownSlice,
- }, nil
-}
-
-// NewFromRawBytes returns a new instance of a Packet struct created by reading
-// from a byte slice. If the format is invalid, an error is returned. If the
-// argument b64 is true, the passed byte slice is decoded from base64 encoding
-// before processing.
-//
-// NOTE: To create a Packet from one's own data, rather than reading in a
-// serialization from a counterparty, one should use a psbt.New.
-func NewFromRawBytes(r io.Reader, b64 bool) (*Packet, error) {
- // If the PSBT is encoded in bas64, then we'll create a new wrapper
- // reader that'll allow us to incrementally decode the contents of the
- // io.Reader.
- if b64 {
- based64EncodedReader := r
- r = base64.NewDecoder(base64.StdEncoding, based64EncodedReader)
- }
-
- // The Packet struct does not store the fixed magic bytes, but they
- // must be present or the serialization must be explicitly rejected.
- var magic [5]byte
- if _, err := io.ReadFull(r, magic[:]); err != nil {
- return nil, err
- }
- if magic != psbtMagic {
- return nil, ErrInvalidMagicBytes
- }
-
- // Next we parse the GLOBAL section. There is currently only 1 known
- // key type, UnsignedTx. We insist this exists first; unknowns are
- // allowed, but only after.
- keyCode, keyData, err := getKey(r)
- if err != nil {
- return nil, err
- }
- if GlobalType(keyCode) != UnsignedTxType || keyData != nil {
- return nil, ErrInvalidPsbtFormat
- }
-
- // Now that we've verified the global type is present, we'll decode it
- // into a proper unsigned transaction, and validate it.
- value, err := wire.ReadVarBytes(
- r, 0, MaxPsbtValueLength, "PSBT value",
- )
- if err != nil {
- return nil, err
- }
- msgTx := wire.NewMsgTx(2)
-
- // BIP-0174 states: "The transaction must be in the old serialization
- // format (without witnesses)."
- err = msgTx.DeserializeNoWitness(bytes.NewReader(value))
- if err != nil {
- return nil, err
- }
- if !validateUnsignedTX(msgTx) {
- return nil, ErrInvalidRawTxSigned
- }
-
- // Next we parse any unknowns that may be present, making sure that we
- // break at the separator.
- var (
- xPubSlice []XPub
- unknownSlice []*Unknown
- )
- for {
- keyint, keydata, err := getKey(r)
- if err != nil {
- return nil, ErrInvalidPsbtFormat
- }
- if keyint == -1 {
- break
- }
-
- value, err := wire.ReadVarBytes(
- r, 0, MaxPsbtValueLength, "PSBT value",
- )
- if err != nil {
- return nil, err
- }
-
- switch GlobalType(keyint) {
- case XPubType:
- xPub, err := ReadXPub(keydata, value)
- if err != nil {
- return nil, err
- }
-
- // Duplicate keys are not allowed
- for _, x := range xPubSlice {
- if bytes.Equal(x.ExtendedKey, keyData) {
- return nil, ErrDuplicateKey
- }
- }
-
- xPubSlice = append(xPubSlice, *xPub)
-
- default:
- keyintanddata := []byte{byte(keyint)}
- keyintanddata = append(keyintanddata, keydata...)
-
- newUnknown := &Unknown{
- Key: keyintanddata,
- Value: value,
- }
- unknownSlice = append(unknownSlice, newUnknown)
- }
- }
-
- // Next we parse the INPUT section.
- inSlice := make([]PInput, len(msgTx.TxIn))
- for i := range msgTx.TxIn {
- input := PInput{}
- err = input.deserialize(r)
- if err != nil {
- return nil, err
- }
-
- inSlice[i] = input
- }
-
- // Next we parse the OUTPUT section.
- outSlice := make([]POutput, len(msgTx.TxOut))
- for i := range msgTx.TxOut {
- output := POutput{}
- err = output.deserialize(r)
- if err != nil {
- return nil, err
- }
-
- outSlice[i] = output
- }
-
- // Populate the new Packet object.
- newPsbt := Packet{
- UnsignedTx: msgTx,
- Inputs: inSlice,
- Outputs: outSlice,
- XPubs: xPubSlice,
- Unknowns: unknownSlice,
- }
-
- // Extended sanity checking is applied here to make sure the
- // externally-passed Packet follows all the rules.
- if err = newPsbt.SanityCheck(); err != nil {
- return nil, err
- }
-
- return &newPsbt, nil
-}
-
-// Serialize creates a binary serialization of the referenced Packet struct
-// with lexicographical ordering (by key) of the subsections.
-func (p *Packet) Serialize(w io.Writer) error {
- // First we write out the precise set of magic bytes that identify a
- // valid PSBT transaction.
- if _, err := w.Write(psbtMagic[:]); err != nil {
- return err
- }
-
- // Next we prep to write out the unsigned transaction by first
- // serializing it into an intermediate buffer.
- serializedTx := bytes.NewBuffer(
- make([]byte, 0, p.UnsignedTx.SerializeSize()),
- )
- if err := p.UnsignedTx.SerializeNoWitness(serializedTx); err != nil {
- return err
- }
-
- // Now that we have the serialized transaction, we'll write it out to
- // the proper global type.
- err := serializeKVPairWithType(
- w, uint8(UnsignedTxType), nil, serializedTx.Bytes(),
- )
- if err != nil {
- return err
- }
-
- // Serialize the global xPubs.
- for _, xPub := range p.XPubs {
- pathBytes := SerializeBIP32Derivation(
- xPub.MasterKeyFingerprint, xPub.Bip32Path,
- )
- err := serializeKVPairWithType(
- w, uint8(XPubType), xPub.ExtendedKey, pathBytes,
- )
- if err != nil {
- return err
- }
- }
-
- // Unknown is a special case; we don't have a key type, only a key and
- // a value field
- for _, kv := range p.Unknowns {
- err := serializeKVpair(w, kv.Key, kv.Value)
- if err != nil {
- return err
- }
- }
-
- // With that our global section is done, so we'll write out the
- // separator.
- separator := []byte{0x00}
- if _, err := w.Write(separator); err != nil {
- return err
- }
-
- for _, pInput := range p.Inputs {
- err := pInput.serialize(w)
- if err != nil {
- return err
- }
-
- if _, err := w.Write(separator); err != nil {
- return err
- }
- }
-
- for _, pOutput := range p.Outputs {
- err := pOutput.serialize(w)
- if err != nil {
- return err
- }
-
- if _, err := w.Write(separator); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-// B64Encode returns the base64 encoding of the serialization of
-// the current PSBT, or an error if the encoding fails.
-func (p *Packet) B64Encode() (string, error) {
- var b bytes.Buffer
- if err := p.Serialize(&b); err != nil {
- return "", err
- }
-
- return base64.StdEncoding.EncodeToString(b.Bytes()), nil
-}
-
-// IsComplete returns true only if all of the inputs are
-// finalized; this is particularly important in that it decides
-// whether the final extraction to a network serialized signed
-// transaction will be possible.
-func (p *Packet) IsComplete() bool {
- for i := 0; i < len(p.UnsignedTx.TxIn); i++ {
- if !isFinalized(p, i) {
- return false
- }
- }
- return true
-}
-
-// SanityCheck checks conditions on a PSBT to ensure that it obeys the
-// rules of BIP174, and returns true if so, false if not.
-func (p *Packet) SanityCheck() error {
- if !validateUnsignedTX(p.UnsignedTx) {
- return ErrInvalidRawTxSigned
- }
-
- for _, tin := range p.Inputs {
- if !tin.IsSane() {
- return ErrInvalidPsbtFormat
- }
- }
-
- return nil
-}
-
-// GetTxFee returns the transaction fee. An error is returned if a transaction
-// input does not contain any UTXO information.
-func (p *Packet) GetTxFee() (btcutil.Amount, error) {
- sumInputs, err := SumUtxoInputValues(p)
- if err != nil {
- return 0, err
- }
-
- var sumOutputs int64
- for _, txOut := range p.UnsignedTx.TxOut {
- sumOutputs += txOut.Value
- }
-
- fee := sumInputs - sumOutputs
- return btcutil.Amount(fee), nil
-}
diff --git a/btcutil/psbt/psbt_test.go b/btcutil/psbt/psbt_test.go
deleted file mode 100644
index 1e0f4fe..0000000
--- a/btcutil/psbt/psbt_test.go
+++ /dev/null
@@ -1,1692 +0,0 @@
-// Copyright (c) 2018 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package psbt
-
-import (
- "bytes"
- "encoding/base64"
- "encoding/binary"
- "encoding/hex"
- "math"
- "strings"
- "testing"
-
- "github.com/btcsuite/btcd/btcutil/v2"
- "github.com/btcsuite/btcd/chainhash/v2"
- "github.com/btcsuite/btcd/txscript/v2"
- "github.com/btcsuite/btcd/wire/v2"
- "github.com/davecgh/go-spew/spew"
- "github.com/stretchr/testify/require"
-)
-
-// Test vectors from:
-// // https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#test-vectors
-
-// createPsbtFromSignedTx is a utility function to create a PSBT from an
-// already-signed transaction, so we can test reconstructing, signing and
-// extracting it. Returned are: an unsigned transaction serialization, a list
-// of scriptSigs, one per input, and a list of witnesses, one per input.
-func createPsbtFromSignedTx(serializedSignedTx []byte) (
- *Packet, [][]byte, []wire.TxWitness, error) {
-
- tx := wire.NewMsgTx(2)
- err := tx.Deserialize(bytes.NewReader(serializedSignedTx))
- if err != nil {
- return nil, nil, nil, err
- }
- scriptSigs := make([][]byte, 0, len(tx.TxIn))
- witnesses := make([]wire.TxWitness, 0, len(tx.TxIn))
- tx2 := tx.Copy()
-
- // Blank out signature info in inputs
- for i, tin := range tx2.TxIn {
- tin.SignatureScript = nil
- scriptSigs = append(scriptSigs, tx.TxIn[i].SignatureScript)
- tin.Witness = nil
- witnesses = append(witnesses, tx.TxIn[i].Witness)
-
- }
-
- // Outputs always contain: (value, scriptPubkey) so don't need
- // amending. Now tx2 is tx with all signing data stripped out
- unsignedPsbt, err := NewFromUnsignedTx(tx2)
- if err != nil {
- return nil, nil, nil, err
- }
- return unsignedPsbt, scriptSigs, witnesses, nil
-}
-
-// These are all valid PSBTs encoded as hex. The items with a comment are taken
-// from the BIP174 test vectors:
-// https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#test-vectors
-var validPsbtHex = map[int]string{
- // Case: PSBT with one P2PKH input. Outputs are empty.
- 0: "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab300000000000000",
- // Case: PSBT with one P2PKH input and one P2SH-P2WPKH input. First
- // input is signed and finalized. Outputs are empty.
- 1: "70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac000000000001076a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa882920001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000",
- // Case: PSBT with one P2PKH input which has a non-final scriptSig and
- // has a sighash type specified. Outputs are empty.
- 2: "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000001030401000000000000",
- // Case: PSBT with one P2PKH input and one P2SH-P2WPKH input both with
- // non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available.
- // Outputs filled.
- 3: "70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac00000000000100df0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf6000000006a473044022070b2245123e6bf474d60c5b50c043d4c691a5d2435f09a34a7662a9dc251790a022001329ca9dacf280bdf30740ec0390422422c81cb45839457aeb76fc12edd95b3012102657d118d3357b8e0f4c2cd46db7b39f6d9c38d9a70abcb9b2de5dc8dbfe4ce31feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e13000001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb8230800220202ead596687ca806043edc3de116cdf29d5e9257c196cd055cf698c8d02bf24e9910b4a6ba670000008000000080020000800022020394f62be9df19952c5587768aeb7698061ad2c4a25c894f47d8c162b4d7213d0510b4a6ba6700000080010000800200008000",
- // Case: PSBT with one P2SH-P2WSH input of a 2-of-2 multisig,
- // redeemScript, witnessScript, and keypaths are available. Contains one
- // signature.
- 4: "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000",
- 5: "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a010000000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0000",
- 6: "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a010000000000002206030d097466b7f59162ac4d90bf65f2a31a8bad82fcd22e98138dcf279401939bd104ffffffff0a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0000",
- 7: "70736274ff01002001000000000100000000000000000d6a0b68656c6c6f20776f726c64000000000000",
- // Case: PSBT with one P2WSH input of a 2-of-2 multisig. witnessScript,
- // keypaths, and global xpubs are available. Contains no signatures.
- // Outputs filled.
- 8: "70736274ff01005202000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef133579000000004f01043587cf02da3fd0088000000097048b1ad0445b1ec8275517727c87b4e4ebc18a203ffa0f94c01566bd38e9000351b743887ee1d40dc32a6043724f2d6459b3b5a4d73daec8fbae0472f3bc43e20cd90c6a4fae000080000000804f01043587cf02da3fd00880000001b90452427139cd78c2cff2444be353cd58605e3e513285e528b407fae3f6173503d30a5e97c8adbc557dac2ad9a7e39c1722ebac69e668b6f2667cc1d671c83cab0cd90c6a4fae000080010000800001012b0065cd1d000000002200202c5486126c4978079a814e13715d65f36459e4d6ccaded266d0508645bafa6320105475221029da12cdb5b235692b91536afefe5c91c3ab9473d8e43b533836ab456299c88712103372b34234ed7cf9c1fea5d05d441557927be9542b162eb02e1ab2ce80224c00b52ae2206029da12cdb5b235692b91536afefe5c91c3ab9473d8e43b533836ab456299c887110d90c6a4fae0000800000008000000000220603372b34234ed7cf9c1fea5d05d441557927be9542b162eb02e1ab2ce80224c00b10d90c6a4fae0000800100008000000000002202039eff1f547a1d5f92dfa2ba7af6ac971a4bd03ba4a734b03156a256b8ad3a1ef910ede45cc500000080000000800100008000",
- // Case: PSBT with `PSBT_GLOBAL_XPUB`.
- 9: "70736274ff01009d0100000002710ea76ab45c5cb6438e607e59cc037626981805ae9e0dfd9089012abb0be5350100000000ffffffff190994d6a8b3c8c82ccbcfb2fba4106aa06639b872a8d447465c0d42588d6d670000000000ffffffff0200e1f505000000001976a914b6bc2c0ee5655a843d79afedd0ccc3f7dd64340988ac605af405000000001600141188ef8e4ce0449eaac8fb141cbf5a1176e6a088000000004f010488b21e039e530cac800000003dbc8a5c9769f031b17e77fea1518603221a18fd18f2b9a54c6c8c1ac75cbc3502f230584b155d1c7f1cd45120a653c48d650b431b67c5b2c13f27d7142037c1691027569c503100008000000080000000800001011f00e1f5050000000016001433b982f91b28f160c920b4ab95e58ce50dda3a4a220203309680f33c7de38ea6a47cd4ecd66f1f5a49747c6ffb8808ed09039243e3ad5c47304402202d704ced830c56a909344bd742b6852dccd103e963bae92d38e75254d2bb424502202d86c437195df46c0ceda084f2a291c3da2d64070f76bf9b90b195e7ef28f77201220603309680f33c7de38ea6a47cd4ecd66f1f5a49747c6ffb8808ed09039243e3ad5c1827569c5031000080000000800000008000000000010000000001011f00e1f50500000000160014388fb944307eb77ef45197d0b0b245e079f011de220202c777161f73d0b7c72b9ee7bde650293d13f095bc7656ad1f525da5fd2e10b11047304402204cb1fb5f869c942e0e26100576125439179ae88dca8a9dc3ba08f7953988faa60220521f49ca791c27d70e273c9b14616985909361e25be274ea200d7e08827e514d01220602c777161f73d0b7c72b9ee7bde650293d13f095bc7656ad1f525da5fd2e10b1101827569c5031000080000000800000008000000000000000000000220202d20ca502ee289686d21815bd43a80637b0698e1fbcdbe4caed445f6c1a0a90ef1827569c50310000800000008000000080000000000400000000",
-}
-
-// These are additional valid PSBTs encoded as base64. The items with a comment
-// are taken from the BIP174 test vectors:
-// https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#test-vectors
-var validPsbtBase64 = map[int]string{
- // PSBT with one P2PKH input. Outputs are empty.
- 0: "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAIQ12pWrO2RXSUT3NhMLDeLLoqlzWMrW3HKLyrFsOOmSb2wIBAiENnBLP3ATHRYTXh6w9I3chMsGFJLx6so3sQhm4/FtCX3ABAQAAAA==",
- 1: "cHNidP8BAFICAAAAASd0Srq/MCf+DWzyOpbu4u+xiO9SMBlUWFiD5ptmJLJCAAAAAAD/////AUjmBSoBAAAAFgAUdo4e60z0IIZgM/gKzv8PlyB0SWkAAAAAAAEBKwDyBSoBAAAAIlEgWiws9bUs8x+DrS6Npj/wMYPs2PYJx1EK6KSOA5EKB1chFv40kGTJjW4qhT+jybEr2LMEoZwZXGDvp+4jkwRtP6IyGQB3Ky2nVgAAgAEAAIAAAACAAQAAAAAAAAABFyD+NJBkyY1uKoU/o8mxK9izBKGcGVxg76fuI5MEbT+iMgAiAgNrdyptt02HU8mKgnlY3mx4qzMSEJ830+AwRIQkLs5z2Bh3Ky2nVAAAgAEAAIAAAACAAAAAAAAAAAAA",
- 2: "cHNidP8BAFICAAAAASd0Srq/MCf+DWzyOpbu4u+xiO9SMBlUWFiD5ptmJLJCAAAAAAD/////AUjmBSoBAAAAFgAUdo4e60z0IIZgM/gKzv8PlyB0SWkAAAAAAAEBKwDyBSoBAAAAIlEgWiws9bUs8x+DrS6Npj/wMYPs2PYJx1EK6KSOA5EKB1cBE0C7U+yRe62dkGrxuocYHEi4as5aritTYFpyXKdGJWMUdvxvW67a9PLuD0d/NvWPOXDVuCc7fkl7l68uPxJcl680IRb+NJBkyY1uKoU/o8mxK9izBKGcGVxg76fuI5MEbT+iMhkAdystp1YAAIABAACAAAAAgAEAAAAAAAAAARcg/jSQZMmNbiqFP6PJsSvYswShnBlcYO+n7iOTBG0/ojIAIgIDa3cqbbdNh1PJioJ5WN5seKszEhCfN9PgMESEJC7Oc9gYdystp1QAAIABAACAAAAAgAAAAAAAAAAAAA==",
- 3: "cHNidP8BAF4CAAAAASd0Srq/MCf+DWzyOpbu4u+xiO9SMBlUWFiD5ptmJLJCAAAAAAD/////AUjmBSoBAAAAIlEgg2mORYxmZOFZXXXaJZfeHiLul9eY5wbEwKS1qYI810MAAAAAAAEBKwDyBSoBAAAAIlEgWiws9bUs8x+DrS6Npj/wMYPs2PYJx1EK6KSOA5EKB1chFv40kGTJjW4qhT+jybEr2LMEoZwZXGDvp+4jkwRtP6IyGQB3Ky2nVgAAgAEAAIAAAACAAQAAAAAAAAABFyD+NJBkyY1uKoU/o8mxK9izBKGcGVxg76fuI5MEbT+iMgABBSARJNp67JLM0GyVRWJkf0N7E4uVchqEvivyJ2u92rPmcSEHESTaeuySzNBslUViZH9DexOLlXIahL4r8idrvdqz5nEZAHcrLadWAACAAQAAgAAAAIAAAAAABQAAAAA=",
- 4: "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgg2mORYxmZOFZXXXaJZfeHiLul9eY5wbEwKS1qYI810MAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJiFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wG99YgWelJehpKJnVp2YdtpgEBr/OONSm5uTnOf5GulwEV8uSQr3zEXE94UR82BXzlxaXFYyWin7RN/CA/NW4fgjICyxOsaCSN6AaqajZZzzwD62gh0JyBFKToaP696GW7bSrMBCFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wJfG5v6l/3FP9XJEmZkIEOQG6YqhD1v35fZ4S8HQqabOIyBDILC/FvARtT6nvmFZJKp/J+XSmtIOoRVdhIZ2w7rRsqzAYhXBUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsDNlw4V9T/AyC+VD9Vg/6kZt2FyvgFzaKiZE68HT0ALCRFfLkkK98xFxPeFEfNgV85cWlxWMlop+0TfwgPzVuH4IyD6D3o87zsdDAps59JuF62gsuXJLRnvrUi0GFnLikUcqazAIRYssTrGgkjegGqmo2Wc88A+toIdCcgRSk6Gj+vehlu20jkBzZcOFfU/wMgvlQ/VYP+pGbdhcr4Bc2iomROvB09ACwl3Ky2nVgAAgAEAAIACAACAAAAAAAAAAAAhFkMgsL8W8BG1Pqe+YVkkqn8n5dKa0g6hFV2EhnbDutGyOQERXy5JCvfMRcT3hRHzYFfOXFpcVjJaKftE38ID81bh+HcrLadWAACAAQAAgAEAAIAAAAAAAAAAACEWUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsAFAHxGHl0hFvoPejzvOx0MCmzn0m4XraCy5cktGe+tSLQYWcuKRRypOQFvfWIFnpSXoaSiZ1admHbaYBAa/zjjUpubk5zn+RrpcHcrLadWAACAAQAAgAMAAIAAAAAAAAAAAAEXIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrAARgg8DYuL3Wm9CClvePrIh2WrmcgzyX4GJDJWx13WstRXmUAAQUgESTaeuySzNBslUViZH9DexOLlXIahL4r8idrvdqz5nEhBxEk2nrskszQbJVFYmR/Q3sTi5VyGoS+K/Ina73as+ZxGQB3Ky2nVgAAgAEAAIAAAACAAAAAAAUAAAAA",
- 5: "cHNidP8BAF4CAAAAASd0Srq/MCf+DWzyOpbu4u+xiO9SMBlUWFiD5ptmJLJCAAAAAAD/////AUjmBSoBAAAAIlEgCoy9yG3hzhwPnK6yLW33ztNoP+Qj4F0eQCqHk0HW9vUAAAAAAAEBKwDyBSoBAAAAIlEgWiws9bUs8x+DrS6Npj/wMYPs2PYJx1EK6KSOA5EKB1chFv40kGTJjW4qhT+jybEr2LMEoZwZXGDvp+4jkwRtP6IyGQB3Ky2nVgAAgAEAAIAAAACAAQAAAAAAAAABFyD+NJBkyY1uKoU/o8mxK9izBKGcGVxg76fuI5MEbT+iMgABBSBQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wAEGbwLAIiBzblcpAP4SUliaIUPI88efcaBBLSNTr3VelwHHgmlKAqwCwCIgYxxfO1gyuPvev7GXBM7rMjwh9A96JPQ9aO8MwmsSWWmsAcAiIET6pJoDON5IjI3//s37bzKfOAvVZu8gyN9tgT6rHEJzrCEHRPqkmgM43kiMjf/+zftvMp84C9Vm7yDI322BPqscQnM5AfBreYuSoQ7ZqdC7/Trxc6U7FhfaOkFZygCCFs2Fay4Odystp1YAAIABAACAAQAAgAAAAAADAAAAIQdQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wAUAfEYeXSEHYxxfO1gyuPvev7GXBM7rMjwh9A96JPQ9aO8MwmsSWWk5ARis5AmIl4Xg6nDO67jhyokqenjq7eDy4pbPQ1lhqPTKdystp1YAAIABAACAAgAAgAAAAAADAAAAIQdzblcpAP4SUliaIUPI88efcaBBLSNTr3VelwHHgmlKAjkBKaW0kVCQFi11mv0/4Pk/ozJgVtC0CIy5M8rngmy42Cx3Ky2nVgAAgAEAAIADAACAAAAAAAMAAAAA",
- 6: "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgg2mORYxmZOFZXXXaJZfeHiLul9eY5wbEwKS1qYI810MAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJBFCyxOsaCSN6AaqajZZzzwD62gh0JyBFKToaP696GW7bSzZcOFfU/wMgvlQ/VYP+pGbdhcr4Bc2iomROvB09ACwlAv4GNl1fW/+tTi6BX+0wfxOD17xhudlvrVkeR4Cr1/T1eJVHU404z2G8na4LJnHmu0/A5Wgge/NLMLGXdfmk9eUEUQyCwvxbwEbU+p75hWSSqfyfl0prSDqEVXYSGdsO60bIRXy5JCvfMRcT3hRHzYFfOXFpcVjJaKftE38ID81bh+EDh8atvq/omsjbyGDNxncHUKKt2jYD5H5mI2KvvR7+4Y7sfKlKfdowV8AzjTsKDzcB+iPhCi+KPbvZAQ8MpEYEaQRT6D3o87zsdDAps59JuF62gsuXJLRnvrUi0GFnLikUcqW99YgWelJehpKJnVp2YdtpgEBr/OONSm5uTnOf5GulwQOwfA3kgZGHIM0IoVCMyZwirAx8NpKJT7kWq+luMkgNNi2BUkPjNE+APmJmJuX4hX6o28S3uNpPS2szzeBwXV/ZiFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wG99YgWelJehpKJnVp2YdtpgEBr/OONSm5uTnOf5GulwEV8uSQr3zEXE94UR82BXzlxaXFYyWin7RN/CA/NW4fgjICyxOsaCSN6AaqajZZzzwD62gh0JyBFKToaP696GW7bSrMBCFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wJfG5v6l/3FP9XJEmZkIEOQG6YqhD1v35fZ4S8HQqabOIyBDILC/FvARtT6nvmFZJKp/J+XSmtIOoRVdhIZ2w7rRsqzAYhXBUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsDNlw4V9T/AyC+VD9Vg/6kZt2FyvgFzaKiZE68HT0ALCRFfLkkK98xFxPeFEfNgV85cWlxWMlop+0TfwgPzVuH4IyD6D3o87zsdDAps59JuF62gsuXJLRnvrUi0GFnLikUcqazAIRYssTrGgkjegGqmo2Wc88A+toIdCcgRSk6Gj+vehlu20jkBzZcOFfU/wMgvlQ/VYP+pGbdhcr4Bc2iomROvB09ACwl3Ky2nVgAAgAEAAIACAACAAAAAAAAAAAAhFkMgsL8W8BG1Pqe+YVkkqn8n5dKa0g6hFV2EhnbDutGyOQERXy5JCvfMRcT3hRHzYFfOXFpcVjJaKftE38ID81bh+HcrLadWAACAAQAAgAEAAIAAAAAAAAAAACEWUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsAFAHxGHl0hFvoPejzvOx0MCmzn0m4XraCy5cktGe+tSLQYWcuKRRypOQFvfWIFnpSXoaSiZ1admHbaYBAa/zjjUpubk5zn+RrpcHcrLadWAACAAQAAgAMAAIAAAAAAAAAAAAEXIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrAARgg8DYuL3Wm9CClvePrIh2WrmcgzyX4GJDJWx13WstRXmUAAQUgESTaeuySzNBslUViZH9DexOLlXIahL4r8idrvdqz5nEhBxEk2nrskszQbJVFYmR/Q3sTi5VyGoS+K/Ina73as+ZxGQB3Ky2nVgAAgAEAAIAAAACAAAAAAAUAAAAA",
- // Case: PSBT with one P2WSH input of a 2-of-2 multisig. witnessScript,
- // keypaths, and global xpubs are available. Contains no signatures.
- // Outputs filled.
- 7: "cHNidP8BAFICAAAAAZ38ZijCbFiZ/hvT3DOGZb/VXXraEPYiCXPfLTht7BJ2AQAAAAD/////AfA9zR0AAAAAFgAUezoAv9wU0neVwrdJAdCdpu8TNXkAAAAATwEENYfPAto/0AiAAAAAlwSLGtBEWx7IJ1UXcnyHtOTrwYogP/oPlMAVZr046QADUbdDiH7h1A3DKmBDck8tZFmztaTXPa7I+64EcvO8Q+IM2QxqT64AAIAAAACATwEENYfPAto/0AiAAAABuQRSQnE5zXjCz/JES+NTzVhgXj5RMoXlKLQH+uP2FzUD0wpel8itvFV9rCrZp+OcFyLrrGnmaLbyZnzB1nHIPKsM2QxqT64AAIABAACAAAEBKwBlzR0AAAAAIgAgLFSGEmxJeAeagU4TcV1l82RZ5NbMre0mbQUIZFuvpjIBBUdSIQKdoSzbWyNWkrkVNq/v5ckcOrlHPY5DtTODarRWKZyIcSEDNys0I07Xz5wf6l0F1EFVeSe+lUKxYusC4ass6AIkwAtSriIGAp2hLNtbI1aSuRU2r+/lyRw6uUc9jkO1M4NqtFYpnIhxENkMak+uAACAAAAAgAAAAAAiBgM3KzQjTtfPnB/qXQXUQVV5J76VQrFi6wLhqyzoAiTACxDZDGpPrgAAgAEAAIAAAAAAACICA57/H1R6HV+S36K6evaslxpL0DukpzSwMVaiVritOh75EO3kXMUAAACAAAAAgAEAAIAA",
- // Case: PSBT with `PSBT_GLOBAL_XPUB`.
- 8: "cHNidP8BAJ0BAAAAAnEOp2q0XFy2Q45gflnMA3YmmBgFrp4N/ZCJASq7C+U1AQAAAAD/////GQmU1qizyMgsy8+y+6QQaqBmObhyqNRHRlwNQliNbWcAAAAAAP////8CAOH1BQAAAAAZdqkUtrwsDuVlWoQ9ea/t0MzD991kNAmIrGBa9AUAAAAAFgAUEYjvjkzgRJ6qyPsUHL9aEXbmoIgAAAAATwEEiLIeA55TDKyAAAAAPbyKXJdp8DGxfnf+oVGGAyIaGP0Y8rmlTGyMGsdcvDUC8jBYSxVdHH8c1FEgplPEjWULQxtnxbLBPyfXFCA3wWkQJ1acUDEAAIAAAACAAAAAgAABAR8A4fUFAAAAABYAFDO5gvkbKPFgySC0q5XljOUN2jpKIgIDMJaA8zx9446mpHzU7NZvH1pJdHxv+4gI7QkDkkPjrVxHMEQCIC1wTO2DDFapCTRL10K2hS3M0QPpY7rpLTjnUlTSu0JFAiAthsQ3GV30bAztoITyopHD2i1kBw92v5uQsZXn7yj3cgEiBgMwloDzPH3jjqakfNTs1m8fWkl0fG/7iAjtCQOSQ+OtXBgnVpxQMQAAgAAAAIAAAACAAAAAAAEAAAAAAQEfAOH1BQAAAAAWABQ4j7lEMH63fvRRl9CwskXgefAR3iICAsd3Fh9z0LfHK57nveZQKT0T8JW8dlatH1Jdpf0uELEQRzBEAiBMsftfhpyULg4mEAV2ElQ5F5rojcqKncO6CPeVOYj6pgIgUh9JynkcJ9cOJzybFGFphZCTYeJb4nTqIA1+CIJ+UU0BIgYCx3cWH3PQt8crnue95lApPRPwlbx2Vq0fUl2l/S4QsRAYJ1acUDEAAIAAAACAAAAAgAAAAAAAAAAAAAAiAgLSDKUC7iiWhtIYFb1DqAY3sGmOH7zb5MrtRF9sGgqQ7xgnVpxQMQAAgAAAAIAAAACAAAAAAAQAAAAA",
-}
-
-// These are all invalid PSBTs for the indicated reasons.
-var invalidPsbtHex = map[int]string{
- // wire format, not PSBT format
- 0: "0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf6000000006a473044022070b2245123e6bf474d60c5b50c043d4c691a5d2435f09a34a7662a9dc251790a022001329ca9dacf280bdf30740ec0390422422c81cb45839457aeb76fc12edd95b3012102657d118d3357b8e0f4c2cd46db7b39f6d9c38d9a70abcb9b2de5dc8dbfe4ce31feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300",
- // missing outputs
- 1: "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000000",
- // Filled in scriptSig in unsigned tx
- 2: "70736274ff0100fd0a010200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be4000000006a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa88292feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac00000000000001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000",
- // No unsigned tx
- 3: "70736274ff000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000000",
- // Duplicate keys in an input
- 4: "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000001003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a010000000000000000",
- // Invalid global transaction typed key
- 5: "70736274ff020001550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000",
- // Invalid input witness utxo typed key
- 6: "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac000000000002010020955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000",
- // Invalid pubkey length for input partial signature typed key
- 7: "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87210203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd46304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000",
- // Invalid redeemscript typed key
- 8: "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a01020400220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000",
- // Invalid witness script typed key
- 9: "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d568102050047522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000",
- // Invalid bip32 typed key
- 10: "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae210603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd10b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000",
- // Invalid non-witness utxo typed key
- 11: "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f0000000000020000bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000",
- // Invalid final scriptsig typed key
- 12: "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000020700da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000",
- // Invalid final script witness typed key
- 13: "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903020800da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000",
- // Invalid pubkey in output BIP32 derivation paths typed key
- 14: "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00210203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca58710d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000",
- // Invalid input sighash type typed key
- 15: "70736274ff0100730200000001301ae986e516a1ec8ac5b4bc6573d32f83b465e23ad76167d68b38e730b4dbdb0000000000ffffffff02747b01000000000017a91403aa17ae882b5d0d54b25d63104e4ffece7b9ea2876043993b0000000017a914b921b1ba6f722e4bfa83b6557a3139986a42ec8387000000000001011f00ca9a3b00000000160014d2d94b64ae08587eefc8eeb187c601e939f9037c0203000100000000010016001462e9e982fff34dd8239610316b090cd2a3b747cb000100220020876bad832f1d168015ed41232a9ea65a1815d9ef13c0ef8759f64b5b2b278a65010125512103b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d2bd57f8a8751ae00",
- // Invalid output redeemscript typed key
- 16: "70736274ff0100730200000001301ae986e516a1ec8ac5b4bc6573d32f83b465e23ad76167d68b38e730b4dbdb0000000000ffffffff02747b01000000000017a91403aa17ae882b5d0d54b25d63104e4ffece7b9ea2876043993b0000000017a914b921b1ba6f722e4bfa83b6557a3139986a42ec8387000000000001011f00ca9a3b00000000160014d2d94b64ae08587eefc8eeb187c601e939f9037c0002000016001462e9e982fff34dd8239610316b090cd2a3b747cb000100220020876bad832f1d168015ed41232a9ea65a1815d9ef13c0ef8759f64b5b2b278a65010125512103b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d2bd57f8a8751ae00",
- // Invalid output witnessScript typed key
- 17: "70736274ff0100730200000001301ae986e516a1ec8ac5b4bc6573d32f83b465e23ad76167d68b38e730b4dbdb0000000000ffffffff02747b01000000000017a91403aa17ae882b5d0d54b25d63104e4ffece7b9ea2876043993b0000000017a914b921b1ba6f722e4bfa83b6557a3139986a42ec8387000000000001011f00ca9a3b00000000160014d2d94b64ae08587eefc8eeb187c601e939f9037c00010016001462e9e982fff34dd8239610316b090cd2a3b747cb000100220020876bad832f1d168015ed41232a9ea65a1815d9ef13c0ef8759f64b5b2b278a6521010025512103b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d2bd57f8a8751ae00",
- // Additional cases outside the existing test vectors.
- // Invalid duplicate PartialSig
- 18: "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a01220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000",
- // Invalid duplicate BIP32 derivation (different derivs, same key)
- 19: "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba670000008000000080050000800000",
- // Invalid var int for key type
- 20: "70736274ff01001c000000000002000000000000000000000000736210ff01000001010010ff70ff01001c00000000000000000000000000000000000000000000",
-}
-
-// All following PSBTs are Taproot specific invalid packets taken from
-// https://github.com/bitcoin/bitcoin/pull/22558.
-var invalidPsbtBase64 = map[int]string{
- // Invalid input internal key length.
- 0: "cHNidP8BAHECAAAAASd0Srq/MCf+DWzyOpbu4u+xiO9SMBlUWFiD5ptmJLJCAAAAAAD/////Anh8AQAAAAAAFgAUg6fjS9mf8DpJYu+KGhAbspVGHs5gawQqAQAAABYAFHrDad8bIOAz1hFmI5V7CsSfPFLoAAAAAAABASsA8gUqAQAAACJRIFosLPW1LPMfg60ujaY/8DGD7Nj2CcdRCuikjgORCgdXARchAv40kGTJjW4qhT+jybEr2LMEoZwZXGDvp+4jkwRtP6IyAAAA",
- // Invalid input key spend schnorr signature.
- 1: "cHNidP8BAHECAAAAASd0Srq/MCf+DWzyOpbu4u+xiO9SMBlUWFiD5ptmJLJCAAAAAAD/////Anh8AQAAAAAAFgAUg6fjS9mf8DpJYu+KGhAbspVGHs5gawQqAQAAABYAFHrDad8bIOAz1hFmI5V7CsSfPFLoAAAAAAABASsA8gUqAQAAACJRIFosLPW1LPMfg60ujaY/8DGD7Nj2CcdRCuikjgORCgdXARM/Fzuz02wHSvtxb+xjB6BpouRQuZXzyCeFlFq43w4kJg3NcDsMvzTeOZGEqUgawrNYbbZgHwJqd/fkk4SBvDR1AAAA",
- // Invalid input key spend signature length.
- 2: "cHNidP8BAHECAAAAASd0Srq/MCf+DWzyOpbu4u+xiO9SMBlUWFiD5ptmJLJCAAAAAAD/////Anh8AQAAAAAAFgAUg6fjS9mf8DpJYu+KGhAbspVGHs5gawQqAQAAABYAFHrDad8bIOAz1hFmI5V7CsSfPFLoAAAAAAABASsA8gUqAQAAACJRIFosLPW1LPMfg60ujaY/8DGD7Nj2CcdRCuikjgORCgdXARNCFzuz02wHSvtxb+xjB6BpouRQuZXzyCeFlFq43w4kJg3NcDsMvzTeOZGEqUgawrNYbbZgHwJqd/fkk4SBvDR1FwGqAAAA",
- // Invalid input x-only pubkey in key.
- 3: "cHNidP8BAHECAAAAASd0Srq/MCf+DWzyOpbu4u+xiO9SMBlUWFiD5ptmJLJCAAAAAAD/////Anh8AQAAAAAAFgAUg6fjS9mf8DpJYu+KGhAbspVGHs5gawQqAQAAABYAFHrDad8bIOAz1hFmI5V7CsSfPFLoAAAAAAABASsA8gUqAQAAACJRIFosLPW1LPMfg60ujaY/8DGD7Nj2CcdRCuikjgORCgdXIhYC/jSQZMmNbiqFP6PJsSvYswShnBlcYO+n7iOTBG0/ojIZAHcrLadWAACAAQAAgAAAAIABAAAAAAAAAAAAAA==",
- // Invalid output internal key length.
- 4: "cHNidP8BAH0CAAAAASd0Srq/MCf+DWzyOpbu4u+xiO9SMBlUWFiD5ptmJLJCAAAAAAD/////Aoh7AQAAAAAAFgAUI4KHHH6EIaAAk/dU2RKB5nWHS59gawQqAQAAACJRIFosLPW1LPMfg60ujaY/8DGD7Nj2CcdRCuikjgORCgdXAAAAAAABASsA8gUqAQAAACJRIFosLPW1LPMfg60ujaY/8DGD7Nj2CcdRCuikjgORCgdXAAABBSEC/jSQZMmNbiqFP6PJsSvYswShnBlcYO+n7iOTBG0/ojIA",
- // Invalid output BIP32 derivation x-only pubkey in key.
- 5: "cHNidP8BAH0CAAAAASd0Srq/MCf+DWzyOpbu4u+xiO9SMBlUWFiD5ptmJLJCAAAAAAD/////Aoh7AQAAAAAAFgAUI4KHHH6EIaAAk/dU2RKB5nWHS59gawQqAQAAACJRIFosLPW1LPMfg60ujaY/8DGD7Nj2CcdRCuikjgORCgdXAAAAAAABASsA8gUqAQAAACJRIFosLPW1LPMfg60ujaY/8DGD7Nj2CcdRCuikjgORCgdXAAAiBwL+NJBkyY1uKoU/o8mxK9izBKGcGVxg76fuI5MEbT+iMhkAdystp1YAAIABAACAAAAAgAEAAAAAAAAAAA==",
- // Invalid input script spend signature key length.
- 6: "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgAw2k/OT32yjCyylRYx4ANxOFZZf+ljiCy1AOaBEsymMAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJCFAIssTrGgkjegGqmo2Wc88A+toIdCcgRSk6Gj+vehlu20s2XDhX1P8DIL5UP1WD/qRm3YXK+AXNoqJkTrwdPQAsJQIl1aqNznMxonsD886NgvjLMC1mxbpOh6LtGBXJrLKej/3BsQXZkljKyzGjh+RK4pXjjcZzncQiFx6lm9JvNQ8sAAA==",
- // Invalid input script spend signature length.
- 7: "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgAw2k/OT32yjCyylRYx4ANxOFZZf+ljiCy1AOaBEsymMAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJBFCyxOsaCSN6AaqajZZzzwD62gh0JyBFKToaP696GW7bSzZcOFfU/wMgvlQ/VYP+pGbdhcr4Bc2iomROvB09ACwlCiXVqo3OczGiewPzzo2C+MswLWbFuk6Hou0YFcmssp6P/cGxBdmSWMrLMaOH5ErileONxnOdxCIXHqWb0m81DywEBAAA=",
- // Invalid encoding of base64 stream.
- 8: "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgAw2k/OT32yjCyylRYx4ANxOFZZf+ljiCy1AOaBEsymMAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJBFCyxOsaCSN6AaqajZZzzwD62gh0JyBFKToaP696GW7bSzZcOFfU/wMgvlQ/VYP+pGbdhcr4Bc2iomROvB09ACwk5iXVqo3OczGiewPzzo2C+MswLWbFuk6Hou0YFcmssp6P/cGxBdmSWMrLMaOH5ErileONxnOdxCIXHqWb0m81DywAA",
- // Invalid input leaf script type control block.
- 9: "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgAw2k/OT32yjCyylRYx4ANxOFZZf+ljiCy1AOaBEsymMAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJjFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wG99YgWelJehpKJnVp2YdtpgEBr/OONSm5uTnOf5GulwEV8uSQr3zEXE94UR82BXzlxaXFYyWin7RN/CA/NW4fgAIyAssTrGgkjegGqmo2Wc88A+toIdCcgRSk6Gj+vehlu20qzAAAA=",
- // Invalid input leaf script type control block.
- 10: "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgAw2k/OT32yjCyylRYx4ANxOFZZf+ljiCy1AOaBEsymMAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJhFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wG99YgWelJehpKJnVp2YdtpgEBr/OONSm5uTnOf5GulwEV8uSQr3zEXE94UR82BXzlxaXFYyWin7RN/CA/NW4SMgLLE6xoJI3oBqpqNlnPPAPraCHQnIEUpOho/r3oZbttKswAAA",
-}
-
-// This tests that valid PSBT serializations can be parsed
-// into Psbt structs.
-func TestReadValidPsbtAndReserialize(t *testing.T) {
- for key, v := range validPsbtHex {
- psbtBytes, err := hex.DecodeString(v)
- require.NoErrorf(t, err, "%d: hex decode", key)
-
- testPsbt, err := NewFromRawBytes(
- bytes.NewReader(psbtBytes), false,
- )
- require.NoErrorf(t, err, "%d: parse", key)
-
- t.Logf("Successfully parsed test %d, got transaction: %v",
- key, spew.Sdump(testPsbt.UnsignedTx))
-
- var b bytes.Buffer
- err = testPsbt.Serialize(&b)
- require.NoErrorf(t, err, "%d: serialize", key)
- if err != nil {
- t.Fatalf("Unable to serialize created Psbt: %v", err)
- }
-
- require.Equal(t, psbtBytes, b.Bytes(), "%d: serialized", key)
- }
-
- for key, v := range validPsbtBase64 {
- testPsbt, err := NewFromRawBytes(
- strings.NewReader(v), true,
- )
- require.NoErrorf(t, err, "%d: parse", key)
-
- t.Logf("Successfully parsed test %d, got transaction: %v",
- key, spew.Sdump(testPsbt.UnsignedTx))
-
- var b bytes.Buffer
- err = testPsbt.Serialize(&b)
- require.NoErrorf(t, err, "%d: serialize", key)
- if err != nil {
- t.Fatalf("Unable to serialize created Psbt: %v", err)
- }
-
- base64Packet := base64.StdEncoding.EncodeToString(b.Bytes())
- require.Equal(t, v, base64Packet, "%d: serialized", key)
- }
-}
-
-func TestReadInvalidPsbt(t *testing.T) {
- for key, v := range invalidPsbtHex {
- psbtBytes, err := hex.DecodeString(v)
- require.NoErrorf(t, err, "%d: hex decode", key)
-
- _, err = NewFromRawBytes(bytes.NewReader(psbtBytes), false)
- require.Errorf(t, err, "%d: new from raw bytes", key)
-
- t.Logf("Correctly got error: %v", err)
- }
-
- for key, v := range invalidPsbtBase64 {
- _, err := NewFromRawBytes(strings.NewReader(v), true)
- require.Errorf(t, err, "%d: new from raw bytes", key)
-
- t.Logf("Correctly got error: %v", err)
- }
-}
-
-func TestSanityCheck(t *testing.T) {
- // TODO(guggero): Remove when checks for segwit v1 are implemented.
- t.Skip("Skipping PSBT sanity checks for segwit v0.")
-
- // Test strategy:
- // 1. Create an invalid PSBT from a serialization
- // Then ensure that the sanity check fails.
- // 2. Create a valid PSBT from a serialization
- // Then create an updater, add a witness utxo to a non-witness
- // utxo.
- // Then ensure that the sanity check fails.
- // Then add a witnessScript field to a non-witness utxo.
- // Then ensure that the sanity check fails.
-
- // index 1 contains a psbt with two inputs, first non-witness,
- // second witness.
- psbtraw1, err := hex.DecodeString(validPsbtHex[1])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- psbt1, err := NewFromRawBytes(bytes.NewReader(psbtraw1), false)
- if err != nil {
- t.Fatalf("Unable to create Psbt struct: %v", err)
- }
-
- // Add a non-witness utxo field to input2 using raw insertion function,
- // so that it becomes invalid, then NewUpdater should fail.
- nonWitnessUtxoRaw, err := hex.DecodeString(
- CUTestHexData["NonWitnessUtxo"],
- )
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- nonWitnessUtxo := wire.NewMsgTx(2)
- err = nonWitnessUtxo.Deserialize(bytes.NewReader(nonWitnessUtxoRaw))
- if err != nil {
- t.Fatalf("Unable to deserialize: %v", err)
- }
- inputs1 := &psbt1.Inputs[1]
- inputs1.NonWitnessUtxo = nonWitnessUtxo
-
- // The PSBT is now in an inconsistent state; Updater creation should
- // fail.
- updater, err := NewUpdater(psbt1)
- if err == nil {
- t.Fatalf("Failed to identify invalid PSBT state ( " +
- "witness, non-witness fields)")
- }
-
- // Overwrite back with the correct psbt
- psbtraw1, err = hex.DecodeString(validPsbtHex[1])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- psbt1, err = NewFromRawBytes(bytes.NewReader(psbtraw1), false)
- updater, err = NewUpdater(psbt1)
- if err != nil {
- t.Fatalf("Unable to create Updater: %v", err)
- }
-
- // Create a fake non-witness utxo field to overlap with
- // the existing witness input at index 1.
- tx := wire.NewMsgTx(2)
- err = tx.Deserialize(bytes.NewReader(nonWitnessUtxoRaw))
- if err != nil {
- t.Fatalf("Error deserializing transaction: %v", err)
- }
- err = updater.AddInNonWitnessUtxo(tx, 1)
- if err == nil {
- t.Fatalf("Incorrectly accepted Psbt with conflicting witness " +
- "and non-witness utxo entries in the same input.")
- }
-
- // Now we try again; this time we try to add a witnessScript
- // key-value pair to an input which is non-witness, which should
- // also be rejected.
- psbt2, err := NewFromRawBytes(
- bytes.NewReader(psbtraw1), false,
- )
- if err != nil {
- t.Fatalf("Unable to create Psbt struct: %v", err)
- }
- updater2, err := NewUpdater(psbt2)
- if err != nil {
- t.Fatalf("Got error creating updater2: %v", err)
- }
- witnessScript, err := hex.DecodeString(
- CUTestHexData["Input2WitnessScript"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- err = updater2.AddInWitnessScript(witnessScript, 0)
- if err == nil {
- t.Fatalf("Incorrectly accepted adding witness script field " +
- "to non-witness utxo")
- }
-}
-
-// Data for creation and updating tests
-// ===============================================================================
-var CUTestHexData = map[string]string{
- "scriptPubkey1": "0014d85c2b71d0060b09c9886aeb815e50991dda124d",
- "scriptPubkey2": "001400aea9a2e5f0f876a588df5546e8742d1d87008f",
- "txid1": "75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858",
- "txid2": "1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83",
- "COPsbtHex": "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000",
- "NonWitnessUtxo": "0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000",
- "WitnessUtxo": "00c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887",
- // After adding witnessutxo and nonwitness utxo to inputs:
- "UOPsbtHex": "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887000000",
- "Input1RedeemScript": "5221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae",
- "Input2RedeemScript": "00208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903",
- "Input2WitnessScript": "522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae",
- // After adding redeemscripts and witness scripts to inputs:
- "UOPsbtHex2": "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88701042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae000000",
- // After adding bip32 derivations to inputs and outputs:
- "UOPsbtHex3": "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88701042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000",
- //After adding sighash types to inputs
- "UOPsbtHex4": "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000",
-}
-
-// Just one example sanity check of B64 construction; after sighash appending above
-var CUTestB64Data = map[string]string{
- "UOPsbtB644": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
-}
-
-var CUTestAmountData = map[string]int64{
- "amount1": 149990000,
- "amount2": 100000000,
- "amount3": 200000000,
-}
-
-var CUTestIndexData = map[string]uint32{
- "index1": 0,
- "index2": 1,
-}
-
-var CUMasterKeyFingerPrint = "d90c6a4f"
-
-var CUTestPathData = map[string][]uint32{
- "dpath1": {0 + 0x80000000, 0 + 0x80000000, 0 + 0x80000000},
- "dpath2": {0 + 0x80000000, 0 + 0x80000000, 1 + 0x80000000},
- "dpath3": {0 + 0x80000000, 0 + 0x80000000, 2 + 0x80000000},
- "dpath4": {0 + 0x80000000, 0 + 0x80000000, 3 + 0x80000000},
- "dpath5": {0 + 0x80000000, 0 + 0x80000000, 4 + 0x80000000},
- "dpath6": {0 + 0x80000000, 0 + 0x80000000, 5 + 0x80000000},
-}
-
-var CUTestPubkeyData = map[string]string{
- "pub1": "029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f",
- "pub2": "02dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7",
- "pub3": "03089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc",
- "pub4": "023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73",
- "pub5": "03a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca58771",
- "pub6": "027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b50051096",
-}
-
-// ===============================================================================
-
-func TestPsbtCreator(t *testing.T) {
- spkOut1, err := hex.DecodeString(CUTestHexData["scriptPubkey1"])
- if err != nil {
- t.Fatalf("Error: %v", err)
- }
- spkOut2, err := hex.DecodeString(CUTestHexData["scriptPubkey2"])
- if err != nil {
- t.Fatalf("Error: %v", err)
- }
- out1 := wire.NewTxOut(CUTestAmountData["amount1"], spkOut1)
- out2 := wire.NewTxOut(CUTestAmountData["amount2"], spkOut2)
- outputs := []*wire.TxOut{out1, out2}
- hash1, err := chainhash.NewHashFromStr(CUTestHexData["txid1"])
- if err != nil {
- t.Fatalf("Error: %v", err)
- }
- prevOut1 := wire.NewOutPoint(hash1, uint32(0))
- hash2, err := chainhash.NewHashFromStr(CUTestHexData["txid2"])
- if err != nil {
- t.Fatalf("Error: %v", err)
- }
- prevOut2 := wire.NewOutPoint(hash2, uint32(1))
- inputs := []*wire.OutPoint{prevOut1, prevOut2}
-
- // Check creation fails with invalid sequences:
- nSequences := []uint32{wire.MaxTxInSequenceNum}
- _, err = New(inputs, outputs, int32(3), uint32(0), nSequences)
- if err == nil {
- t.Fatalf("Did not error when creating transaction with " +
- "invalid nSequences")
- }
- nSequences = append(nSequences, wire.MaxTxInSequenceNum)
-
- // Check creation fails with invalid version
- _, err = New(inputs, outputs, int32(0), uint32(0), nSequences)
- if err == nil {
- t.Fatalf("Did not error when creating transaction with " +
- "invalid version (3)")
- }
-
- // Use valid data to create:
- cPsbt, err := New(inputs, outputs, int32(2), uint32(0), nSequences)
- var b bytes.Buffer
- err = cPsbt.Serialize(&b)
- if err != nil {
- t.Fatalf("Unable to serialize created Psbt: %v", err)
- }
- if CUTestHexData["COPsbtHex"] != hex.EncodeToString(b.Bytes()) {
- t.Fatalf("Failed to create expected psbt, instead got: %v",
- hex.EncodeToString(b.Bytes()))
- }
-
- // Now simulate passing the created PSBT to an Updater
- updater, err := NewUpdater(cPsbt)
- if err != nil {
- t.Fatalf("Unable to create Updater object")
- }
- tx := wire.NewMsgTx(2)
- nonWitnessUtxoHex, err := hex.DecodeString(
- CUTestHexData["NonWitnessUtxo"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- err = tx.Deserialize(bytes.NewReader(nonWitnessUtxoHex))
- if err != nil {
- t.Fatalf("Error deserializing transaction: %v", err)
- }
- witnessUtxoHex, err := hex.DecodeString(
- CUTestHexData["WitnessUtxo"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- txout := wire.TxOut{Value: CUTestAmountData["amount3"],
- PkScript: witnessUtxoHex[9:]}
- err = updater.AddInNonWitnessUtxo(tx, 0)
- if err != nil {
- t.Fatalf("Unable to add NonWitness Utxo to inputs: %v", err)
- }
- err = updater.AddInWitnessUtxo(&txout, 1)
- if err != nil {
- t.Fatalf("Unable to add Witness Utxo to inputs: %v", err)
- }
-
- b.Reset()
-
- err = updater.Upsbt.Serialize(&b)
- if err != nil {
- t.Fatalf("Unable to serialize updated Psbt: %v", err)
- }
- if CUTestHexData["UOPsbtHex"] != hex.EncodeToString(b.Bytes()) {
- t.Fatal("Failed to create valid updated PSBT after utxos")
- }
- input1RedeemScript, err := hex.DecodeString(CUTestHexData["Input1RedeemScript"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- err = updater.AddInRedeemScript(input1RedeemScript, 0)
- if err != nil {
- t.Fatalf("Unable to add redeem script: %v", err)
- }
- input2RedeemScript, err := hex.DecodeString(CUTestHexData["Input2RedeemScript"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- err = updater.AddInRedeemScript(input2RedeemScript, 1)
- if err != nil {
- t.Fatalf("Unable to add redeem script: %v", err)
- }
- input2WitnessScript, err := hex.DecodeString(CUTestHexData["Input2WitnessScript"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- err = updater.AddInWitnessScript(input2WitnessScript, 1)
- if err != nil {
- t.Fatalf("Unable to add witness script: %v", err)
- }
-
- b.Reset()
- err = updater.Upsbt.Serialize(&b)
- if err != nil {
- t.Fatalf("Unable to serialize updated Psbt: %v", err)
- }
- if CUTestHexData["UOPsbtHex2"] != hex.EncodeToString(b.Bytes()) {
- t.Fatal("Failed to create valid updated PSBT after redeem scripts")
- }
- masterKey, err := hex.DecodeString(CUMasterKeyFingerPrint)
- masterKeyInt := binary.LittleEndian.Uint32(masterKey)
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- input1Path1 := CUTestPathData["dpath1"]
- input1Path2 := CUTestPathData["dpath2"]
- input1Key1, err := hex.DecodeString(CUTestPubkeyData["pub1"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- input1Key2, err := hex.DecodeString(CUTestPubkeyData["pub2"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- err = updater.AddInBip32Derivation(masterKeyInt, input1Path1, input1Key1, 0)
- if err != nil {
- t.Fatal("Failed to add first key derivation for input 1")
- }
- err = updater.AddInBip32Derivation(masterKeyInt, input1Path2, input1Key2, 0)
- if err != nil {
- t.Fatal("Failed to add second key derivation for input 1")
- }
- input2Path1 := CUTestPathData["dpath3"]
- input2Path2 := CUTestPathData["dpath4"]
- input2Key1, err := hex.DecodeString(CUTestPubkeyData["pub3"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- input2Key2, err := hex.DecodeString(CUTestPubkeyData["pub4"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
-
- // check invalid pubkeys are not accepted
- borkedInput2Key1 := append([]byte{0xff}, input2Key1...)
- err = updater.AddInBip32Derivation(masterKeyInt, input2Path1,
- borkedInput2Key1, 1)
- if err == nil {
- t.Fatalf("Expected invalid pubkey, got: %v", err)
- }
-
- err = updater.AddInBip32Derivation(masterKeyInt, input2Path1, input2Key1, 1)
- if err != nil {
- t.Fatal("Failed to add first key derivation for input 2")
- }
- err = updater.AddInBip32Derivation(masterKeyInt, input2Path2, input2Key2, 1)
- if err != nil {
- t.Fatal("Failed to add second key derivation for input 2")
- }
- output1Key1, err := hex.DecodeString(CUTestPubkeyData["pub5"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- output1Path := CUTestPathData["dpath5"]
-
- // check invalid pubkeys are not accepted
- borkedOutput1Key1 := append([]byte{0xab}, output1Key1[:13]...)
- err = updater.AddOutBip32Derivation(masterKeyInt, output1Path,
- borkedOutput1Key1, 0)
- if err == nil {
- t.Fatalf("Expected invalid pubkey, got: %v", err)
- }
-
- err = updater.AddOutBip32Derivation(masterKeyInt, output1Path, output1Key1, 0)
- if err != nil {
- t.Fatal("Failed to add key to first output")
- }
- output2Key1, err := hex.DecodeString(CUTestPubkeyData["pub6"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- output2Path := CUTestPathData["dpath6"]
- err = updater.AddOutBip32Derivation(masterKeyInt, output2Path, output2Key1, 1)
- if err != nil {
- t.Fatal("Failed to add key to second output")
- }
-
- b.Reset()
- err = updater.Upsbt.Serialize(&b)
- if err != nil {
- t.Fatalf("Unable to serialize updated Psbt: %v", err)
- }
- if CUTestHexData["UOPsbtHex3"] != hex.EncodeToString(b.Bytes()) {
- t.Fatal("Failed to create valid updated PSBT after BIP32 derivations")
- }
- err = updater.AddInSighashType(txscript.SigHashType(1), 0)
- if err != nil {
- t.Fatal("Failed to add sighash type to first input")
- }
- err = updater.AddInSighashType(txscript.SigHashType(1), 1)
- if err != nil {
- t.Fatal("Failed to add sighash type to second input")
- }
-
- b.Reset()
- err = updater.Upsbt.Serialize(&b)
- if err != nil {
- t.Fatalf("Unable to serialize updated Psbt: %v", err)
- }
- if CUTestHexData["UOPsbtHex4"] != hex.EncodeToString(b.Bytes()) {
- t.Fatal("Failed to create valid updated PSBT after sighash types")
- }
- b644, err := updater.Upsbt.B64Encode()
- if err != nil {
- t.Fatalf("Unable to B64Encode updated Psbt: %v", err)
- }
- if b644 != CUTestB64Data["UOPsbtB644"] {
- t.Fatalf("Failed to base64 encode updated PSBT after sighash "+
- "types: %v", b644)
- }
-}
-
-// Signing test data taken from
-// https://github.com/achow101/bitcoin/blob/020628e3a4e88e36647eaf92bac4b3552796ac6a/test/functional/data/rpc_psbt.json
-var signerPsbtData = map[string]string{
- "signer1Privkey1": "cP53pDbR5WtAD8dYAW9hhTjuvvTVaEiQBdrz9XPrgLBeRFiyCbQr",
- "signer1Privkey2": "cR6SXDoyfQrcp4piaiHE97Rsgta9mNhGTen9XeonVgwsh4iSgw6d",
- "signer1PsbtB64": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAQMEAQAAAAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAAQMEAQAAAAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
- "signer1Result": "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000",
- "signer2Privkey1": "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
- "signer2Privkey2": "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE",
- "signer2Psbt": "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080010304010000000001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88701042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f0000008000000080020000800103040100000000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000",
- "signer2Result": "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8872202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d2010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000",
-}
-
-func TestPsbtSigner(t *testing.T) {
- psbt1, err := NewFromRawBytes(
- bytes.NewReader([]byte(signerPsbtData["signer1PsbtB64"])),
- true,
- )
- if err != nil {
- t.Fatalf("Failed to parse PSBT: %v", err)
- }
- psbtUpdater1 := Updater{
- Upsbt: psbt1,
- }
- sig1, err := hex.DecodeString("3044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01")
- pub1, err := hex.DecodeString("029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f")
- res, err := psbtUpdater1.Sign(0, sig1, pub1, nil, nil)
- if err != nil || res != 0 {
- t.Fatalf("Error from adding signatures: %v %v", err, res)
- }
- sig2, err := hex.DecodeString("3044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01")
- pub2, err := hex.DecodeString("03089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc")
- res, err = psbtUpdater1.Sign(1, sig2, pub2, nil, nil)
- if err != nil || res != 0 {
- t.Fatalf("Error from adding signatures: %v %v", err, res)
- }
- signer1Result, err := hex.DecodeString(signerPsbtData["signer1Result"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
-
- var b bytes.Buffer
- err = psbtUpdater1.Upsbt.Serialize(&b)
- if err != nil {
- t.Fatalf("Unable to serialize updated Psbt: %v", err)
- }
- if !bytes.Equal(b.Bytes(), signer1Result) {
- t.Fatalf("Failed to add signatures correctly")
- }
-}
-
-// Finalizer-extractor test
-
-var finalizerPsbtData = map[string]string{
- "finalizeb64": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEiAgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc0cwRAIgZfRbpZmLWaJ//hp77QFq8fH5DVSzqo90UKpfVqJRA70CIH9yRwOtHtuWaAsoS1bU/8uI9/t1nqu+CKow8puFE4PSAQEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
- "finalize": "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f012202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d2010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000",
- "resultb64": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==",
- "result": "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000",
- "network": "0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000",
- "twoOfThree": "70736274ff01005e01000000019a5fdb3c36f2168ea34a031857863c63bb776fd8a8a9149efd7341dfaf81c9970000000000ffffffff01e013a8040000000022002001c3a65ccfa5b39e31e6bafa504446200b9c88c58b4f21eb7e18412aff154e3f000000000001012bc817a80400000000220020114c9ab91ea00eb3e81a7aa4d0d8f1bc6bd8761f8f00dbccb38060dc2b9fdd5522020242ecd19afda551d58f496c17e3f51df4488089df4caafac3285ed3b9c590f6a847304402207c6ab50f421c59621323460aaf0f731a1b90ca76eddc635aed40e4d2fc86f97e02201b3f8fe931f1f94fde249e2b5b4dbfaff2f9df66dd97c6b518ffa746a4390bd1012202039f0acfe5a292aafc5331f18f6360a3cc53d645ebf0cc7f0509630b22b5d9f547473044022075329343e01033ebe5a22ea6eecf6361feca58752716bdc2260d7f449360a0810220299740ed32f694acc5f99d80c988bb270a030f63947f775382daf4669b272da0010103040100000001056952210242ecd19afda551d58f496c17e3f51df4488089df4caafac3285ed3b9c590f6a821035a654524d301dd0265c2370225a6837298b8ca2099085568cc61a8491287b63921039f0acfe5a292aafc5331f18f6360a3cc53d645ebf0cc7f0509630b22b5d9f54753ae22060242ecd19afda551d58f496c17e3f51df4488089df4caafac3285ed3b9c590f6a818d5f7375b2c000080000000800000008000000000010000002206035a654524d301dd0265c2370225a6837298b8ca2099085568cc61a8491287b63918e2314cf32c000080000000800000008000000000010000002206039f0acfe5a292aafc5331f18f6360a3cc53d645ebf0cc7f0509630b22b5d9f54718e524a1ce2c000080000000800000008000000000010000000000",
-}
-
-func TestFinalize2of3(t *testing.T) {
- b, err := hex.DecodeString(finalizerPsbtData["twoOfThree"])
- if err != nil {
- t.Fatalf("Error decoding hex: %v", err)
- }
- p, err := NewFromRawBytes(bytes.NewReader(b), false)
- if err != nil {
- t.Fatalf("Error parsing PSBT: %v", err)
- }
- if p.IsComplete() {
- t.Fatalf("Psbt is complete")
- }
- err = MaybeFinalizeAll(p)
- if err != nil {
- t.Fatalf("Error in MaybeFinalizeAll: %v", err)
- }
- if !p.IsComplete() {
- t.Fatalf("Psbt is not complete")
- }
-}
-
-func TestPsbtExtractor(t *testing.T) {
- rawToFinalize, err := base64.StdEncoding.DecodeString(
- finalizerPsbtData["finalizeb64"],
- )
- if err != nil {
- t.Fatalf("Error decoding b64: %v", err)
- }
-
- psbt1, err := NewFromRawBytes(
- bytes.NewReader(rawToFinalize), false,
- )
- if err != nil {
- t.Fatalf("Failed to parse PSBT: %v", err)
- }
-
- for i := range psbt1.Inputs {
- err = Finalize(psbt1, i)
- if err != nil {
- t.Fatalf("Error from finalizing PSBT: %v", err)
- }
- }
-
- finalizer1Result, err := base64.StdEncoding.DecodeString(
- finalizerPsbtData["resultb64"],
- )
- if err != nil {
- t.Fatalf("Unable to decode b64: %v", err)
- }
- finalToNetworkExpected, err := hex.DecodeString(finalizerPsbtData["network"])
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- tx, err := Extract(psbt1)
- if err != nil {
- t.Fatalf("Failed to extract: %v", err)
- }
- var resultToNetwork bytes.Buffer
- if err := tx.Serialize(&resultToNetwork); err != nil {
- t.Fatalf("unable to serialize: %v", err)
- }
-
- var b bytes.Buffer
- err = psbt1.Serialize(&b)
- if err != nil {
- t.Fatalf("Unable to serialize updated Psbt: %v", err)
- }
- if !bytes.Equal(b.Bytes(), finalizer1Result) {
- t.Fatalf("Failed to finalize transaction: expected %x, "+
- "got %x", finalizer1Result, b.Bytes())
- }
- if !bytes.Equal(finalToNetworkExpected, resultToNetwork.Bytes()) {
- t.Fatalf("Failed to network serialize transaction: %x", b.Bytes())
- }
-}
-
-func TestFinalizerAddSigHashFlags(t *testing.T) {
- var signedPsbtData = map[string]string{
- "Default": "70736274ff01005e0200000001f1aabce974f1b242b36913f4f8a9f138a8042914dddc4117a578813a4dc32ee10000000000ffffffff017b0a0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad1000000000001012b430b0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad1011340e80246ac1955def419572514e50e4be47f56ccd51beae41ec80ad30cb77ed59ebca3c38dd8506e1b7c28fafa4bdf7d821464be1ee152416bdaf2c056fb4fb3290117206b1a4876464d6bfc6a7c106dd4c5a0f08af94b45a8200e47e02a7dc6148fd7b00000",
- "All": "70736274ff01005e020000000193e988e9eebfe51c0f362741aaab1e0699175c83cfd8087c4a06e24e3b80bc220000000000ffffffff019b0d0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad1000000000001012b630e0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad101030401000000011340ee0a03b010e515e38553d4d96c65a9d6092d06756c47c16c5674c3bde6ad0c151f6d4074601f3c2967f12c3b624b4013591e65458a8b5f80b96a613132cee3bb0117206b1a4876464d6bfc6a7c106dd4c5a0f08af94b45a8200e47e02a7dc6148fd7b00000",
- "None": "70736274ff01005e02000000013cfe0f5fd1b9a73230b003d336b5e4d7abf3452f6a5c4f266c434648a161eb170000000000ffffffff01d30c0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad1000000000001012b9b0d0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad10103040200000001134032573ce8ee8a9afac2008bcb45ce7f96ac95ee7ffad26d10388c97fb87f76f77dc414224ca98b01cbec361488ac29d11e018be412d2725be85dfe5c3fd3b6b4c0117206b1a4876464d6bfc6a7c106dd4c5a0f08af94b45a8200e47e02a7dc6148fd7b00000",
- "Single": "70736274ff01005e02000000013173659bb6be7474b8d00efd3b38f2a225f5591bd4edd873170a1e0ff0ef15990000000000ffffffff01630e0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad1000000000001012b2b0f0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad101030403000000011340251ce90a8b36cd90bf430f9522772b09bd3ef90039e53cddc5bda6abb61f1c11db6505683d0b7778d4444549ae71df5012edb859251abca13bd819fa6ac9d6ac0117206b1a4876464d6bfc6a7c106dd4c5a0f08af94b45a8200e47e02a7dc6148fd7b00000",
- "AllAnyOneCanPay": "70736274ff01005e020000000130ac25ec34af987b9e0518ff05cd491bd2d339660a4bfeea49a580c9233fbd9d0000000000ffffffff010b0c0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad1000000000001012bd30c0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad101030481000000011340e86b7ea8d6fc2cbd99b1091c25a2a37b333b5d82ea559579553cf7ba08c0fe3bead26c458f4917a6e069a3712c15f0999adb243603c783133676c1a09cc574b20117206b1a4876464d6bfc6a7c106dd4c5a0f08af94b45a8200e47e02a7dc6148fd7b00000",
- "NoneAnyOneCanPay": "70736274ff01005e02000000015499da1d93851a8add52fcab05acab60eaaf16571e0015f678b68775937d11200000000000ffffffff01430b0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad1000000000001012b0b0c0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad1010304820000000113402d42b46429b739786020e52b69b969468aa69ca40af390ba13441c8e6dc9e53f679c2bd2ff0ef912f48922cd64f4a7bfe7e492e5ecc8603b63e0ea772385faab0117206b1a4876464d6bfc6a7c106dd4c5a0f08af94b45a8200e47e02a7dc6148fd7b00000",
- "SingleAnyOneCanPay": "70736274ff01005e02000000011bbe693ee5b3d75a5c8ad190e151c81e5b1ff1090982ea712c375e7d4a6069ce0100000000ffffffff012b0f0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad1000000000001012bf30f0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad1010304830000000113408e018d0ae9cd730f7eae428a456e920b4ded67c9a7500a82ba25dd23f98418c1f060680daa4352b262fdffab691a4a67fc603352c1d21ace7cc6d83490facde70117206b1a4876464d6bfc6a7c106dd4c5a0f08af94b45a8200e47e02a7dc6148fd7b00000",
- }
-
- var expectedTx = map[string]string{
- "Default": "02000000000101f1aabce974f1b242b36913f4f8a9f138a8042914dddc4117a578813a4dc32ee10000000000ffffffff017b0a0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad10140e80246ac1955def419572514e50e4be47f56ccd51beae41ec80ad30cb77ed59ebca3c38dd8506e1b7c28fafa4bdf7d821464be1ee152416bdaf2c056fb4fb32900000000",
- "All": "0200000000010193e988e9eebfe51c0f362741aaab1e0699175c83cfd8087c4a06e24e3b80bc220000000000ffffffff019b0d0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad10141ee0a03b010e515e38553d4d96c65a9d6092d06756c47c16c5674c3bde6ad0c151f6d4074601f3c2967f12c3b624b4013591e65458a8b5f80b96a613132cee3bb0100000000",
- "None": "020000000001013cfe0f5fd1b9a73230b003d336b5e4d7abf3452f6a5c4f266c434648a161eb170000000000ffffffff01d30c0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad1014132573ce8ee8a9afac2008bcb45ce7f96ac95ee7ffad26d10388c97fb87f76f77dc414224ca98b01cbec361488ac29d11e018be412d2725be85dfe5c3fd3b6b4c0200000000",
- "Single": "020000000001013173659bb6be7474b8d00efd3b38f2a225f5591bd4edd873170a1e0ff0ef15990000000000ffffffff01630e0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad10141251ce90a8b36cd90bf430f9522772b09bd3ef90039e53cddc5bda6abb61f1c11db6505683d0b7778d4444549ae71df5012edb859251abca13bd819fa6ac9d6ac0300000000",
- "AllAnyOneCanPay": "0200000000010130ac25ec34af987b9e0518ff05cd491bd2d339660a4bfeea49a580c9233fbd9d0000000000ffffffff010b0c0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad10141e86b7ea8d6fc2cbd99b1091c25a2a37b333b5d82ea559579553cf7ba08c0fe3bead26c458f4917a6e069a3712c15f0999adb243603c783133676c1a09cc574b28100000000",
- "NoneAnyOneCanPay": "020000000001015499da1d93851a8add52fcab05acab60eaaf16571e0015f678b68775937d11200000000000ffffffff01430b0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad101412d42b46429b739786020e52b69b969468aa69ca40af390ba13441c8e6dc9e53f679c2bd2ff0ef912f48922cd64f4a7bfe7e492e5ecc8603b63e0ea772385faab8200000000",
- "SingleAnyOneCanPay": "020000000001011bbe693ee5b3d75a5c8ad190e151c81e5b1ff1090982ea712c375e7d4a6069ce0100000000ffffffff012b0f0000000000002251209c1f4b7970d790c99b7265b53adec03551708fd7d67db78359f9c472fe642ad101418e018d0ae9cd730f7eae428a456e920b4ded67c9a7500a82ba25dd23f98418c1f060680daa4352b262fdffab691a4a67fc603352c1d21ace7cc6d83490facde78300000000",
- }
-
- for key, signedPsbtStr := range signedPsbtData {
- signedPsbtBytes, err := hex.DecodeString(signedPsbtStr)
- require.NoErrorf(t, err, "Failed to decode signed psbt string")
-
- signedPsbt, err := NewFromRawBytes(bytes.NewReader(signedPsbtBytes), false)
- require.NoErrorf(t, err, "Failed to parse psbt")
-
- // There is only one input in each psbt.
- err = Finalize(signedPsbt, 0)
- require.NoErrorf(t, err, "Failed to finalize")
-
- tx, err := Extract(signedPsbt)
- require.NoErrorf(t, err, "Failed to extract")
-
- var b bytes.Buffer
- err = tx.Serialize(&b)
- require.NoErrorf(t, err, "Failed to serialize tx into buffer")
-
- expectedTxBytes, err := hex.DecodeString(expectedTx[key])
- require.NoErrorf(t, err, "Unable to decode expected tx")
- require.Equal(t, expectedTxBytes, b.Bytes())
- }
-
-}
-
-func TestImportFromCore1(t *testing.T) {
- // This example #1 was created manually using Bitcoin Core 0.17 regtest.
- // It contains two inputs, one p2wkh and one p2pkh (non-witness).
- // We take the created PSBT as input, then add the fields for each input
- // separately, then finalize and extract, and compare with the network
- // serialized tx output from Core.
- imported := "cHNidP8BAJwCAAAAAjaoF6eKeGsPiDQxxqqhFDfHWjBtZzRqmaZmvyCVWZ5JAQAAAAD/////RhypNiFfnQSMNpo0SGsgIvDOyMQFAYEHZXD5jp4kCrUAAAAAAP////8CgCcSjAAAAAAXqRQFWy8ScSkkhlGMwfOnx15YwRzApofwX5MDAAAAABepFAt4TyLfGnL9QY6GLYHbpSQj+QclhwAAAAAAAAAAAA=="
- psbt1, err := NewFromRawBytes(bytes.NewReader([]byte(imported)), true)
- if err != nil {
- t.Fatalf("Failed to parse PSBT: %v", err)
- }
-
- // update with the first input's utxo (witness) and the second input's utxo
- // (non-witness)
- fundingTxInput1Hex := "02000000014f2cbac7d7691fafca30313097d79be9e78aa6670752fcb1fc15508e77586efb000000004847304402201b5568d7cab977ae0892840b779d84e36d62e42fd93b95e648aaebeacd2577d602201d2ebda2b0cddfa0c1a71d3cbcb602e7c9c860a41ed8b4d18d40c92ccbe92aed01feffffff028c636f91000000001600147447b6d7e6193499565779c8eb5184fcfdfee6ef00879303000000001600149e88f2828a074ebf64af23c2168d1816258311d72d010000"
- fundingTxInput2Hex := "020000000001012f03f70c673d83d65da0e8d0db3867b3e7d7bfbd34fd6be65892042e57576eb00000000000feffffff028027128c000000001976a91485780899b61a5506f342bd67a2f635181f50c8b788acb8032c040000000017a914e2e3d32d42d6f043cab39708a6073301df5039db8702473044022047ae396fd8aba8f67482ad16e315fe680db585c1ac6422ffb18dacd9cf5bac350220321176fd6157ef51d9eae9230b0b5bd7dd29bb6247a879189e6aaa8091f3020201210368081f7ff37dfadbed407eba17b232f959e41e6ac78741192c805ebf80d487852f010000"
- fundingTxInput1Bytes, err := hex.DecodeString(fundingTxInput1Hex)
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- txFund1 := wire.NewMsgTx(2)
- err = txFund1.Deserialize(bytes.NewReader(fundingTxInput1Bytes))
- if err != nil {
- t.Fatalf("Error deserializing transaction: %v", err)
- }
- // First input is witness, take correct output:
- txFund1Out := txFund1.TxOut[1]
-
- fundingTxInput2Bytes, err := hex.DecodeString(fundingTxInput2Hex)
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- txFund2 := wire.NewMsgTx(2)
- err = txFund2.Deserialize(bytes.NewReader(fundingTxInput2Bytes))
- if err != nil {
- t.Fatalf("Error deserializing transaction: %v", err)
- }
- psbtupdater1 := Updater{Upsbt: psbt1}
- psbtupdater1.AddInWitnessUtxo(txFund1Out, 0)
- err = psbtupdater1.AddInNonWitnessUtxo(txFund2, 1)
- if err != nil {
- t.Fatalf("Error inserting non-witness utxo: %v", err)
- }
-
- // Signing was done with Core; we manually insert the relevant input
- // entries here.
- sig1Hex := "304402200da03ac9890f5d724c42c83c2a62844c08425a274f1a5bca50dcde4126eb20dd02205278897b65cb8e390a0868c9582133c7157b2ad3e81c1c70d8fbd65f51a5658b01"
- sig1, err := hex.DecodeString(sig1Hex)
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- pub1Hex := "024d6b24f372dd4551277c8df4ecc0655101e11c22894c8e05a3468409c865a72c"
- pub1, err := hex.DecodeString(pub1Hex)
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
-
- // Check that invalid pubkeys are not accepted.
- pubInvalid := append(pub1, 0x00)
-
- res, err := psbtupdater1.Sign(0, sig1, pubInvalid, nil, nil)
- if err == nil {
- t.Fatalf("Incorrectly accepted invalid pubkey: %v",
- pubInvalid)
- }
-
- res, err = psbtupdater1.Sign(0, sig1, pub1, nil, nil)
- if err != nil || res != 0 {
- t.Fatalf("Error from adding signatures: %v %v", err, res)
- }
-
- sig2Hex := "3044022014eb9c4858f71c9f280bc68402aa742a5187f54c56c8eb07c902eb1eb5804e5502203d66656de8386b9b044346d5605f5ae2b200328fb30476f6ac993fc0dbb0455901"
- sig2, err := hex.DecodeString(sig2Hex)
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- pub2Hex := "03b4c79acdf4e7d978bef4019c421e4c6c67044ed49d27322dc90e808d8080e862"
- pub2, err := hex.DecodeString(pub2Hex)
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
-
- // ===============================================================
- // Before adding the signature, we'll make a new PSBT with
- // modifications to the input data and check it fails sanity checks.
-
- // First an invalid tx:
- psbtBorkedInput2, _ := NewFromRawBytes(bytes.NewReader([]byte(imported)), true)
- borkedUpdater, err := NewUpdater(psbtBorkedInput2)
- if err != nil {
- t.Fatalf("NewUpdater failed while trying to create borked "+
- "version: %v", err)
- }
- borkedUpdater.AddInWitnessUtxo(txFund1Out, 0)
-
- res, err = borkedUpdater.Sign(0, sig2, pub2, nil, nil)
- if err != ErrInvalidSignatureForInput {
- t.Fatalf("AddPartialSig succeeded, but should have failed "+
- "due to mismatch between pubkey and prevOut; err was: %v", err)
- }
-
- // Next, a valid tx serialization, but not the right one
- wrongTxBytes, err := hex.DecodeString("020000000001012d1d7b17356d0ad8232a5817d2d2fa5cd97d803c0ed03e013e97b65f4f1e5e7501000000171600147848cfb25bb163c7c63732615980a25eddbadc7bfeffffff022a8227630000000017a91472128ae6b6a1b74e499bedb5efb1cb09c9a6713287107240000000000017a91485f81cb970d854e2513ebf5c5b5d09e4509f4af3870247304402201c09aa8bcd18753ef01d8712a55eea5a0f69b6c4cc2944ac942264ff0662c91402201fc1390bf8b0023dd12ae78d7ec181124e106de57bc8f00812ae92bd024d3045012103ba077fc011aa59393bfe17cf491b3a02a9c4d39df122b2148322da0ec23508f459430800")
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- wrongTx := wire.NewMsgTx(2)
- err = wrongTx.Deserialize(bytes.NewReader(wrongTxBytes))
- if err != nil {
- t.Fatalf("Error deserializing transaction: %v", err)
- }
- psbtBorkedInput2.Inputs[1] = *NewPsbtInput(wrongTx, nil)
- res, err = borkedUpdater.Sign(1, sig2, pub2, nil, nil)
- if err != ErrInvalidSignatureForInput {
- t.Fatalf("Error should have been invalid sig for input, was: %v", err)
- }
- // ======================================================
-
- res, err = psbtupdater1.Sign(1, sig2, pub2, nil, nil)
- if err != nil || res != 0 {
- t.Fatalf("Failed to add signature to second input: %v %v", err, res)
- }
-
- // Neither input (p2pkh and p2wkh) require redeem script nor witness script,
- // so there are no more fields to add; we are ready to finalize.
- err = Finalize(psbt1, 0)
- if err != nil {
- t.Fatalf("Failed to finalize the first input, %v", err)
- }
- if psbt1.IsComplete() {
- t.Fatalf("PSBT was complete but has not been fully finalized")
- }
- err = Finalize(psbt1, 1)
- if err != nil {
- t.Fatalf("Failed to finalize second input, %v", err)
- }
-
- tx, err := Extract(psbt1)
- if err != nil {
- t.Fatalf("unable to extract tx: %v", err)
- }
- var networkSerializedTx bytes.Buffer
- if err := tx.Serialize(&networkSerializedTx); err != nil {
- t.Fatalf("unable to encode tx: %v", err)
- }
-
- expectedTx := "0200000000010236a817a78a786b0f883431c6aaa11437c75a306d67346a99a666bf2095599e490100000000ffffffff461ca936215f9d048c369a34486b2022f0cec8c4050181076570f98e9e240ab5000000006a473044022014eb9c4858f71c9f280bc68402aa742a5187f54c56c8eb07c902eb1eb5804e5502203d66656de8386b9b044346d5605f5ae2b200328fb30476f6ac993fc0dbb04559012103b4c79acdf4e7d978bef4019c421e4c6c67044ed49d27322dc90e808d8080e862ffffffff028027128c0000000017a914055b2f1271292486518cc1f3a7c75e58c11cc0a687f05f93030000000017a9140b784f22df1a72fd418e862d81dba52423f90725870247304402200da03ac9890f5d724c42c83c2a62844c08425a274f1a5bca50dcde4126eb20dd02205278897b65cb8e390a0868c9582133c7157b2ad3e81c1c70d8fbd65f51a5658b0121024d6b24f372dd4551277c8df4ecc0655101e11c22894c8e05a3468409c865a72c0000000000"
- expectedTxBytes, err := hex.DecodeString(expectedTx)
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- if !bytes.Equal(expectedTxBytes, networkSerializedTx.Bytes()) {
- t.Fatalf("The produced network transaction did not match the expected: %x \n %x \n",
- networkSerializedTx.Bytes(), expectedTxBytes)
- }
-
-}
-
-func TestImportFromCore2(t *testing.T) {
- // This example #2 was created manually using Bitcoin Core 0.17 regtest.
- // It contains two inputs, one p2sh-p2wkh and one fake utxo.
- // The PSBT has been created with walletcreatepsbt and then partial-signed
- // on the real input with walletprocessbst in Core.
- // We first check that the updating here, using the Core created signature,
- // redeem script and signature for the p2sh-p2wkh input, creates the
- // same partial-signed intermediate transaction as Core did after
- // walletprocesspsbt.
- // We then attach a fake
- // input of type p2sh-p2wsh, attach its witnessUtxo, redeemscript and
- // witnessscript fields, and then finalize the whole transaction. Unlike
- // the previous example, we cannot here compare with a Core produced
- // network serialized final transaction, because of the fake input.
- imported := "cHNidP8BAJsCAAAAAkxTQ+rig5QNnUS5nMc+Pccow4IcOJeQRcNNw+7p5ZA5AQAAAAD/////qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqoNAAAAAP////8CAIYOcAAAAAAWABQ1l7nn13RubTwqRQU2BnVV5WlXBWAxMbUAAAAAF6kUkiuXUjfWFgTp6nl/gf9+8zIWR6KHAAAAAAAAAAAA"
- psbt1, err := NewFromRawBytes(bytes.NewReader([]byte(imported)), true)
- if err != nil {
- t.Fatalf("Failed to parse PSBT: %v", err)
- }
-
- // update with the first input's utxo, taken from its funding
- // transaction
- fundingTxInput1Hex := "02000000017b260536a3c17aee49c41a9b36fdf01a418e0c04df06fbabcb0d4f590b95d175000000006a473044022074a5a13159b6c12d77881c9501aa5c18616fb76c1809fc4d55f18a2e63159a6702200d1aa72be6056a41808898d24da93c0c0192cad65b7c2cc86e00b3e0fbbd57f601210212cc429d61fde565d0c2271a3e4fdb063cb49ae2257fa71460be753ceb56d175feffffff02bc060d8f0000000017a9140b56c31b5dc5a5a22c45a7850e707ad602d94a3087008352840000000017a9149f3679d67a9a486238764f618a93b82a7d999103879a000000"
- fundingTxInput1Bytes, err := hex.DecodeString(fundingTxInput1Hex)
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- txFund1 := wire.NewMsgTx(2)
- err = txFund1.Deserialize(bytes.NewReader(fundingTxInput1Bytes))
- if err != nil {
- t.Fatalf("Error deserializing transaction: %v", err)
- }
- // First input is witness, take correct output:
- txFund1Out := txFund1.TxOut[1]
-
- psbtupdater1 := Updater{Upsbt: psbt1}
- psbtupdater1.AddInWitnessUtxo(txFund1Out, 0)
-
- // This input is p2sh-p2wkh, so it requires a redeemscript but not
- // a witness script. The redeemscript is the witness program.
- redeemScript, err := hex.DecodeString("00147aed39420a8b7ab98a83791327ccb70819d1fbe2")
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- psbtupdater1.AddInRedeemScript(redeemScript, 0)
-
- // Signing for the first input was done with Core; we manually insert the
- // relevant input entries here.
- sig1Hex := "30440220546d182d00e45ef659c329dce6197dc19e0abc795e2c9279873f5a887998b273022044143113fc3475d04fc8d5113e0bbcb42d80514a9f1a2247e9b2a7878e20d44901"
- sig1, err := hex.DecodeString(sig1Hex)
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- pub1Hex := "02bb3ce35af26f4c826eab3e5fc263ef56871b26686a8a995599b7ee6576613104"
- pub1, err := hex.DecodeString(pub1Hex)
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
-
- res, err := psbtupdater1.Sign(0, sig1, pub1, nil, nil)
- if err != nil || res != 0 {
- t.Fatalf("Unable to add partial signature: %v %v", err, res)
- }
-
- // Since this input is now finalizable, we do so:
- err = Finalize(psbt1, 0)
- if err != nil {
- t.Fatalf("Failed to finalize the first input: %v", err)
- }
- if psbt1.IsComplete() {
- t.Fatalf("PSBT was complete but has not been fully finalized")
- }
-
- // Core also adds the OutRedeemScript field for the output it knows about.
- // Note that usually we would not of course re-create, but rather start
- // from the half-signed version; so this is needed only for a sanity check
- // that we can recreate the half-signed.
- output2RedeemScript, err := hex.DecodeString("0014e0846bd17848ab40ca1f56b655c6fa31667880cc")
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- psbtupdater1.AddOutRedeemScript(output2RedeemScript, 1)
- // The main function of the test is to compare the thus-generated
- // partially (not completely) signed transaction with that generated and
- // encoded by Core.
- expectedPsbtPartialB64 := "cHNidP8BAJsCAAAAAkxTQ+rig5QNnUS5nMc+Pccow4IcOJeQRcNNw+7p5ZA5AQAAAAD/////qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqoNAAAAAP////8CAIYOcAAAAAAWABQ1l7nn13RubTwqRQU2BnVV5WlXBWAxMbUAAAAAF6kUkiuXUjfWFgTp6nl/gf9+8zIWR6KHAAAAAAABASAAg1KEAAAAABepFJ82edZ6mkhiOHZPYYqTuCp9mZEDhwEHFxYAFHrtOUIKi3q5ioN5EyfMtwgZ0fviAQhrAkcwRAIgVG0YLQDkXvZZwync5hl9wZ4KvHleLJJ5hz9aiHmYsnMCIEQUMRP8NHXQT8jVET4LvLQtgFFKnxoiR+myp4eOINRJASECuzzjWvJvTIJuqz5fwmPvVocbJmhqiplVmbfuZXZhMQQAAAABABYAFOCEa9F4SKtAyh9WtlXG+jFmeIDMAA=="
- generatedPsbtPartialB64, err := psbt1.B64Encode()
- if err != nil {
- t.Fatalf("Unable to B64Encode Psbt: %v", err)
- }
- if expectedPsbtPartialB64 != generatedPsbtPartialB64 {
- t.Fatalf("Partial did not match expected: %v", generatedPsbtPartialB64)
- }
-
- // We now simulate adding the signing data for the second (fake) input,
- // and check that we can finalize and extract. This input is p2sh-p2wsh.
- // the second input is fake, we're going to make it witness type,
- // so create a TxOut struct that fits
- fakeTxOutSerialized, err := hex.DecodeString("00c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887")
- if err != nil {
- t.Fatalf("Failed to decode hex: %v", err)
- }
- fakevalSerialized := binary.LittleEndian.Uint64(fakeTxOutSerialized[:8])
- fakeScriptPubKey := fakeTxOutSerialized[9:]
- txFund2Out := wire.NewTxOut(int64(fakevalSerialized), fakeScriptPubKey)
- psbt2, err := NewFromRawBytes(bytes.NewReader([]byte(expectedPsbtPartialB64)), true)
- if err != nil {
- t.Fatalf("Failed to load partial PSBT: %v", err)
- }
- psbtupdater2, err := NewUpdater(psbt2)
- if err != nil {
- t.Fatalf("Failed to create updater: %v", err)
- }
- psbtupdater2.AddInWitnessUtxo(txFund2Out, 1)
- // Add redeemScript, which is the witnessscript/program:
- redeemScript, err = hex.DecodeString("00208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903")
- if err != nil {
- t.Fatalf("Failed to decode hex: %v", err)
- }
- err = psbtupdater2.AddInRedeemScript(redeemScript, 1)
- if err != nil {
- t.Fatalf("Failed to add redeemscript to second input: %v", err)
- }
- // Add witnessScript, which here is multisig:
- witnessScript, err := hex.DecodeString("522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae")
- if err != nil {
- t.Fatalf("Failed to decode hex: %v", err)
- }
- // To test multisig checks, add a nonsense version of the multisig script
- witnessScriptNonsense, err := hex.DecodeString("52ffff")
- if err != nil {
- t.Fatalf("Failed to decode hex: %v", err)
- }
- err = psbtupdater2.AddInWitnessScript(witnessScript, 1)
- if err != nil {
- t.Fatalf("Failed to add witnessscript to second input: %v", err)
- }
- // Construct the two partial signatures to be added
- sig21, err := hex.DecodeString("3044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01")
- if err != nil {
- t.Fatalf("Failed to decode hex: %v", err)
- }
- pub21, err := hex.DecodeString("03089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc")
- if err != nil {
- t.Fatalf("Failed to decode hex: %v", err)
- }
- sig22, err := hex.DecodeString("3044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d201")
- if err != nil {
- t.Fatalf("Failed to decode hex: %v", err)
- }
- pub22, err := hex.DecodeString("023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73")
- if err != nil {
- t.Fatalf("Failed to decode hex: %v", err)
- }
- res, err = psbtupdater2.Sign(1, sig21, pub21, nil, nil)
-
- // Check that the finalization procedure fails here due to not
- // meeting the multisig policy
- success, err := MaybeFinalize(psbt2, 1)
- if success {
- t.Fatalf("Incorrectly succeeded in finalizing without sigs")
- }
- if err != ErrUnsupportedScriptType {
- t.Fatalf("Got unexpected error type: %v", err)
- }
-
- res, err = psbtupdater2.Sign(1, sig22, pub22, nil, nil)
-
- // Check that the finalization procedure also fails with a nonsense
- // script
- err = psbtupdater2.AddInWitnessScript(witnessScriptNonsense, 1)
- if err != nil {
- t.Fatalf("Failed to add witnessscript to second input: %v", err)
- }
- success, err = MaybeFinalize(psbt2, 1)
- if success {
- t.Fatalf("Incorrectly succeeded in finalizing with invalid msigscript")
- }
- if err != ErrUnsupportedScriptType {
- t.Fatalf("Got unexpected error type: %v", err)
- }
-
- // Restore the correct witnessScript to complete correctly
- err = psbtupdater2.AddInWitnessScript(witnessScript, 1)
- if err != nil {
- t.Fatalf("Failed to add witnessscript to second input: %v", err)
- }
-
- success, err = MaybeFinalize(psbt2, 1)
- if !success {
- if err != nil {
- t.Fatalf("Failed to finalize second input: %v", err)
- } else {
- t.Fatalf("Input was not finalizable")
- }
- }
-
- // Add a (fake) witnessOut descriptor field to one of the outputs,
- // for coverage purposes (we aren't currently using this field)
- psbtupdater2.AddOutWitnessScript([]byte{0xff, 0xff, 0xff}, 0)
-
- // Sanity check; we should not have lost the additional output entry
- // provided by Core initially
- uoutput1 := psbtupdater2.Upsbt.Outputs[1]
- if uoutput1.RedeemScript == nil {
- t.Fatalf("PSBT should contain outredeemscript entry, but it does not.")
- }
- // Nor should we have lost our fake witnessscript output entry
- uoutput2 := psbtupdater2.Upsbt.Outputs[0]
- if uoutput2.WitnessScript == nil {
- t.Fatalf("PSBT should contain outwitnessscript but it does not.")
- }
- var tx bytes.Buffer
- networkSerializedTx, err := Extract(psbt2)
- if err != nil {
- t.Fatalf("unable to extract tx: %v", err)
- }
- if err := networkSerializedTx.Serialize(&tx); err != nil {
- t.Fatalf("unable to encode tx: %v", err)
- }
- expectedSerializedTx, err := hex.DecodeString("020000000001024c5343eae283940d9d44b99cc73e3dc728c3821c38979045c34dc3eee9e5903901000000171600147aed39420a8b7ab98a83791327ccb70819d1fbe2ffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0d000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0200860e70000000001600143597b9e7d7746e6d3c2a450536067555e5695705603131b50000000017a914922b975237d61604e9ea797f81ff7ef3321647a287024730440220546d182d00e45ef659c329dce6197dc19e0abc795e2c9279873f5a887998b273022044143113fc3475d04fc8d5113e0bbcb42d80514a9f1a2247e9b2a7878e20d449012102bb3ce35af26f4c826eab3e5fc263ef56871b26686a8a995599b7ee65766131040400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000")
- if err != nil {
- t.Fatalf("Failed to decode hex: %v", err)
- }
- if !bytes.Equal(expectedSerializedTx, tx.Bytes()) {
- t.Fatalf("Failed to create correct network serialized "+
- "transaction: expected %x, got %x",
- expectedSerializedTx, tx.Bytes())
- }
-}
-
-func TestMaybeFinalizeAll(t *testing.T) {
- // The following data is from a 3rd transaction from Core,
- // using 3 inputs, all p2wkh.
- imported := "cHNidP8BAKQCAAAAAzJyXH13IqBFvvZ7y1VSgUgkMvMoPgP5CfFNqsjQexKQAQAAAAD/////fMdLydu5bsoiHN9cFSaBL0Qnq2KLSKx0RA4b938CAgQAAAAAAP/////yKNgfsDAHr/zFz8R9k8EFI26allfg9DdE8Gzj6tGlegEAAAAA/////wHw9E0OAAAAABYAFDnPCRduiEWmmSc1j30SJ8k9u7PHAAAAAAAAAAAA"
- psbt1, err := NewFromRawBytes(bytes.NewReader([]byte(imported)), true)
- if err != nil {
- t.Fatalf("Failed to parse PSBT: %v", err)
- }
-
- // update with the first input's utxo, taken from its funding
- // transaction
- fundingTxInput1, err := hex.DecodeString("020000000001017b260536a3c17aee49c41a9b36fdf01a418e0c04df06fbabcb0d4f590b95d1750100000017160014af82cd4409241b1de892726324bd780e3b5cd8aafeffffff02a85f9800000000001600149d21f8b306ddfd4dd035080689e88b4c3471e3cc801d2c0400000000160014d97ccd3dfb60820d7d33d862371ca5a73039bd560247304402201a1d2fdb5a7190b7fa59907769f0fc9c91fd3b34f6424acf5868a8ac21ec287102200a59b9d076ecf98c88f2196ed2be0aafff4966ead754041182fff5f92115a783012103604ffd31dc71db2e32c20f09eafe6353cd7515d3648aff829bb4879b553e30629a000000")
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- fundingTxInput2, err := hex.DecodeString("020000000001019c27b886e420fcadb077706b0933efa8bb53e3a250c3ec45cfdba5e05e233f360100000000feffffff0200b4c404000000001600140853f50c7d2d5d2af326a75efdbc83b62551e89afce31c0d000000001600142d6936c082c35607ec3bdb334a932d928150b75802473044022000d962f5e5e6425f9de21da7ac65b4fd8af8f6bfbd33c7ba022827c73866b477022034c59935c1ea10b5ba335d93f55a200c2588ec6058b8c7aedd10d5cbc4654f99012102c30e9f0cd98f6a805464d6b8a326b5679b6c3262934341855ee0436eaedfd2869a000000")
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
- fundingTxInput3, err := hex.DecodeString("02000000012bf4331bb95df4eadb14f7a28db3fecdc5e87f08c29c2332b66338dd606699f60000000048473044022075ed43f508528da47673550a785702e9a93eca84a11faea91c4e9c66fcab3c9e022054a37610bd40b12263a5933188f062b718e007f290cecde2b6e41da3e1ebbddf01feffffff020c99a8240100000016001483bd916985726094d6d1c5b969722da580b5966a804a5d05000000001600140a2ee13a6696d75006af5e8a026ea49316087dae9a000000")
- if err != nil {
- t.Fatalf("Unable to decode hex: %v", err)
- }
-
- psbtupdater1 := Updater{Upsbt: psbt1}
- tx := wire.NewMsgTx(2)
- err = tx.Deserialize(bytes.NewReader(fundingTxInput1))
- if err != nil {
- t.Fatalf("Error deserializing transaction: %v", err)
- }
- txFund1Out := tx.TxOut[1]
- psbtupdater1.AddInWitnessUtxo(txFund1Out, 0)
-
- tx = wire.NewMsgTx(2)
- err = tx.Deserialize(bytes.NewReader(fundingTxInput2))
- if err != nil {
- t.Fatalf("Error deserializing transaction: %v", err)
- }
- txFund2Out := tx.TxOut[0]
- psbtupdater1.AddInWitnessUtxo(txFund2Out, 1)
-
- tx = wire.NewMsgTx(2)
- err = tx.Deserialize(bytes.NewReader(fundingTxInput3))
- if err != nil {
- t.Fatalf("Error deserializing transaction: %v", err)
- }
- txFund3Out := tx.TxOut[1]
- psbtupdater1.AddInWitnessUtxo(txFund3Out, 2)
-
- // To be ready for finalization, we need to have partial signature
- // fields for each input
- sig1, _ := hex.DecodeString("30440220027605ee8015970baf02a72652967a543e1b29a6882d799738ed1baee508822702203818a2f1b9770c46a473f47ad7ae90bcc129a5d047f00fae354c80197a7cf50601")
- pub1, _ := hex.DecodeString("03235fc1f9dc8bbf6fa3df35dfeb0dd486f2d488f139579885eb684510f004f6c1")
- sig2, _ := hex.DecodeString("304402206f5aea4621696610de48736b95a89b1d3a434a4e536d9aae65e039c477cf4c7202203b27a18b0f63be7d3bbf5be1bc2306a7ec8c2da12c2820ff07b73c7f3f1d4d7301")
- pub2, _ := hex.DecodeString("022011b496f0603a268b55a781c7be0c3849f605f09cb2e917ed44288b8144a752")
- sig3, _ := hex.DecodeString("3044022036dbc6f8f85a856e7803cbbcf0a97b7a74806fc592e92d7c06826f911610b98e0220111d43c4b20f756581791334d9c5cbb1a9c07558f28404cabf01c782897ad50501")
- pub3, _ := hex.DecodeString("0381772a80c69e275e20d7f014555b13031e9cacf1c54a44a67ab2bc7eba64f227")
- res, err := psbtupdater1.Sign(0, sig1, pub1, nil, nil)
- if err != nil || res != 0 {
- t.Fatalf("Failed to add partial signature for input 0: %v %v", err, res)
- }
- res, err = psbtupdater1.Sign(1, sig2, pub2, nil, nil)
- if err != nil || res != 0 {
- t.Fatalf("Failed to add partial signature for input 1: %v %v", err, res)
- }
-
- // Not ready for finalize all, check it fails:
- err = MaybeFinalizeAll(psbt1)
- if err != ErrNotFinalizable {
- t.Fatalf("Expected finalization failure, got: %v", err)
- }
-
- res, err = psbtupdater1.Sign(2, sig3, pub3, nil, nil)
-
- // Since this input is now finalizable and is p2wkh only, we can do
- // all at once:
- err = MaybeFinalizeAll(psbt1)
- if err != nil {
- t.Fatalf("Failed to finalize PSBT: %v", err)
- }
- if !psbt1.IsComplete() {
- t.Fatalf("PSBT was finalized but not marked complete")
- }
-
-}
-
-func TestFromUnsigned(t *testing.T) {
- serTx, err := hex.DecodeString("0000000001e165f072311e71825b47a4797221d7ae56d4b40b7707c540049aee43302448a40000000000feffffff0212f1126a0000000017a9143e836801b2b15aa193449d815c62d6c4b6227c898780778e060000000017a914ba4bdb0b07d67bc60f59c1f4fe541705652549748700000000")
- if err != nil {
- t.Fatalf("Error: %v", err)
- }
- tx := wire.NewMsgTx(2)
- err = tx.Deserialize(bytes.NewReader(serTx))
- if err != nil {
- t.Fatalf("Error: %v", err)
- }
- psbt1, err := NewFromUnsignedTx(tx)
- if err != nil {
- t.Fatalf("Error: %v", err)
- }
- encoded, err := psbt1.B64Encode()
- if err != nil {
- t.Fatalf("Unable to B64Encode Psbt: %v", err)
- }
-
- // Compare with output of Core:
- fromCoreB64 := "cHNidP8BAHMAAAAAAeFl8HIxHnGCW0ekeXIh165W1LQLdwfFQASa7kMwJEikAAAAAAD+////AhLxEmoAAAAAF6kUPoNoAbKxWqGTRJ2BXGLWxLYifImHgHeOBgAAAAAXqRS6S9sLB9Z7xg9ZwfT+VBcFZSVJdIcAAAAAAAAAAA=="
- if encoded != fromCoreB64 {
- t.Fatalf("Got incorrect b64: %v", encoded)
- }
- _, err = NewFromRawBytes(bytes.NewReader([]byte(fromCoreB64)), true)
- if err != nil {
- t.Fatalf("Error: %v", err)
- }
-}
-
-func TestNonWitnessToWitness(t *testing.T) {
- // We'll start with a PSBT produced by Core for which
- // the first input is signed and we'll provided the signatures for
- // the other three inputs; they are p2sh-p2wkh, p2wkh and legacy
- // respectively.
- // In each case we'll *first* attach the NonWitnessUtxo field,
- // and then call sign; in the first two but not the third case, the
- // NonWitnessUtxo will automatically be replaced with the WitnessUtxo.
- // Finally we'll check that the fully finalized PSBT produced matches
- // the one produced by Core for the same keys.
-
- psbt1B64 := "cHNidP8BAM4CAAAABHtBMXY+SX95xidmWJP67CTQ02FPUpbNhIxNplAdlvk+AQAAAAD/////G2mt4bX7+sVi1jdbuBa5Q/xsJdgzFCgdHHSZq3ewK6YAAAAAAP/////NrbZb7GzfAg4kOqFWAIbXabq4cAvtVGv+eecIIv1KggEAAAAA/////73s9ifprgErlaONH1rgpNs3l6+t+mz2XGTHsTVWCem/AQAAAAD/////AfAmclMAAAAAF6kUQwsEC5nzbdY5meON2ZQ2thmeFgOHAAAAAAABASAAZc0dAAAAABepFPAv3VTMu5+4WN+/HIji6kG9RpzKhwEHFxYAFLN3PqXSyIHWKqm4ah5m9erc/3OoAQhrAkcwRAIgH7kzGO2iskfCvX0dgkDuzfqJ7tAu7KUZOeykTkJ1SYkCIBv4QRZK1hLz45D0gs+Lz93OE4s37lkPVE+SlXZtazWEASEC3jaf19MMferBn0Bn5lxXJGOqoqmfSvnHclQvB5gJ3nEAAAAAAQAWABTB+Qcq6iqdSvvc6959kd7XHrhYFgA="
- nwutxo1ser, _ := hex.DecodeString("02000000017f7baa6b7377541c4aca372d2dce8e1098ba44aa8379b7ea87644ef27e08ec240000000048473044022072e3b94c33cb5128518cd3903cc0ca19e8c234ac6d462e01ae2bb1da7768ed7d0220167d7ad89f6e1bbb3b866ae6fc2f67b5e7d51eb4f33f7bfe3f4b2673856b815001feffffff0200c2eb0b0000000017a9142dd25c78db2e2e09376eab9cb342e1b03005abe487e4ab953e0000000017a914120b8ca3fb4c7f852e30d4e3714fb64027a0b4c38721020000")
- nwutxo2ser, _ := hex.DecodeString("0200000001f51b0bb5d945dd5532448a4d3fb88134d0bd90493813515f9c2ddb1fa15b9ba60000000048473044022047d83caf88d398245c006374bfa9f27ae968f5f51d640cacd5a214ed2cba397a02204519b26035496855f574a72b73bdcfa46d53995faf64c8f0ab394b628cc5383901feffffff020ccb9f3800000000160014e13544a3c718faa6c5ad7089a6660383c12b072700a3e11100000000160014a5439b477c116b79bd4c7c5131f3e58d54f27bb721020000")
- nwutxo3ser, _ := hex.DecodeString("0200000001eb452f0fc9a8c39edb79f7174763f3cb25dc56db455926e411719a115ef16509000000004847304402205aa80cc615eb4b3f6e89696db4eadd192581a6c46f5c09807d3d98ece1d77355022025007e58c1992a1e5d877ee324bfe0a65db26d29f80941cfa277ac3efbcad2a701feffffff02bce9a9320000000017a9141590e852ac66eb8798afeb2a5ed67c568a2d6561870084d717000000001976a914a57ea05eacf94900d5fb92bccd273cfdb90af36f88ac21020000")
-
- nwutxo1 := wire.NewMsgTx(2)
- err := nwutxo1.Deserialize(bytes.NewReader(nwutxo1ser))
- if err != nil {
- t.Fatalf("Error deserializing transaction: %v", err)
- }
- nwutxo2 := wire.NewMsgTx(2)
- err = nwutxo2.Deserialize(bytes.NewReader(nwutxo2ser))
- if err != nil {
- t.Fatalf("Error deserializing transaction: %v", err)
- }
- nwutxo3 := wire.NewMsgTx(2)
- err = nwutxo3.Deserialize(bytes.NewReader(nwutxo3ser))
- if err != nil {
- t.Fatalf("Error deserializing transaction: %v", err)
- }
-
- // import the PSBT
- psbt1, err := NewFromRawBytes(bytes.NewReader([]byte(psbt1B64)), true)
- if err != nil {
- t.Fatalf("Failed to create PSBT: %v", err)
- }
-
- // check that we recognize the finality of the first input
- if !isFinalized(psbt1, 0) {
- t.Fatalf("First input incorrectly read as not finalized.")
- }
-
- // Add NonWitnessUtxo fields for each of the other three inputs
- u := Updater{Upsbt: psbt1}
- u.AddInNonWitnessUtxo(nwutxo1, 1)
- u.AddInNonWitnessUtxo(nwutxo2, 2)
- u.AddInNonWitnessUtxo(nwutxo3, 3)
-
- // Signatures for each of those inputs were created with Core:
- sig1, _ := hex.DecodeString("304402205676877e6162ce40a49ee5a74443cdc1e7915637c42da7b872c2ec2298fd371b02203c1d4a05b1e2a7a588d9ec9b8d4892d2cd59bebe0e777483477a0ec692ebbe6d01")
- pub1, _ := hex.DecodeString("02534f23cb88a048b649672967263bd7570312d5d31d066fa7b303970010a77b2b")
- redeemScript1, _ := hex.DecodeString("00142412be29368c0260cb841eecd9b59d7e01174aa1")
-
- sig2, _ := hex.DecodeString("3044022065d0a349709b8d8043cfd644cf6c196c1f601a22e1b3fdfbf8c0cc2a80fe2f1702207c87d36b666a8862e81ec5df288707f517d2f35ea1548feb82019de2c8de90f701")
- pub2, _ := hex.DecodeString("0257d88eaf1e79b72ea0a33ae89b57dae95ea68499bdc6770257e010ab899f0abb")
-
- sig3, _ := hex.DecodeString("30440220290abcaacbd759c4f989762a9ee3468a9231788aab8f50bf65955d8597d8dd3602204d7e394f4419dc5392c6edba6945837458dd750a030ac67a746231903a8eb7db01")
- pub3, _ := hex.DecodeString("0388025f50bb51c0469421ed13381f22f9d46a070ec2837e055c49c5876f0d0968")
-
- // Add the signatures and any scripts needed to the inputs
- res, err := u.Sign(1, sig1, pub1, redeemScript1, nil)
- if res != 0 || err != nil {
- t.Fatalf("Failed to sign at index %v res %v err %v", 1, res, err)
- }
- res, err = u.Sign(2, sig2, pub2, nil, nil)
- if res != 0 || err != nil {
- t.Fatalf("Failed to sign at index %v res %v err %v", 2, res, err)
- }
- res, err = u.Sign(3, sig3, pub3, nil, nil)
- if res != 0 || err != nil {
- t.Fatalf("Failed to sign at index %v res %v err %v", 3, res, err)
- }
-
- // Attempt to finalize the rest of the transaction
- _, err = MaybeFinalize(psbt1, 1)
- if err != nil {
- t.Fatalf("Failed to finalize input 1 %v", err)
- }
- _, err = MaybeFinalize(psbt1, 2)
- if err != nil {
- t.Fatalf("Failed to finalize input 2 %v", err)
- }
- _, err = MaybeFinalize(psbt1, 3)
- if err != nil {
- t.Fatalf("Failed to finalize input 3 %v", err)
- }
-
- // Finally we can check whether both the B64 encoding of the PSBT,
- // and the final network serialized signed transaction, that we generated
- // with Core using the 2 wallets, matches what this code produces:
- expectedFinalizedPsbt := "cHNidP8BAM4CAAAABHtBMXY+SX95xidmWJP67CTQ02FPUpbNhIxNplAdlvk+AQAAAAD/////G2mt4bX7+sVi1jdbuBa5Q/xsJdgzFCgdHHSZq3ewK6YAAAAAAP/////NrbZb7GzfAg4kOqFWAIbXabq4cAvtVGv+eecIIv1KggEAAAAA/////73s9ifprgErlaONH1rgpNs3l6+t+mz2XGTHsTVWCem/AQAAAAD/////AfAmclMAAAAAF6kUQwsEC5nzbdY5meON2ZQ2thmeFgOHAAAAAAABASAAZc0dAAAAABepFPAv3VTMu5+4WN+/HIji6kG9RpzKhwEHFxYAFLN3PqXSyIHWKqm4ah5m9erc/3OoAQhrAkcwRAIgH7kzGO2iskfCvX0dgkDuzfqJ7tAu7KUZOeykTkJ1SYkCIBv4QRZK1hLz45D0gs+Lz93OE4s37lkPVE+SlXZtazWEASEC3jaf19MMferBn0Bn5lxXJGOqoqmfSvnHclQvB5gJ3nEAAQEgAMLrCwAAAAAXqRQt0lx42y4uCTduq5yzQuGwMAWr5IcBBxcWABQkEr4pNowCYMuEHuzZtZ1+ARdKoQEIawJHMEQCIFZ2h35hYs5ApJ7lp0RDzcHnkVY3xC2nuHLC7CKY/TcbAiA8HUoFseKnpYjZ7JuNSJLSzVm+vg53dINHeg7Gkuu+bQEhAlNPI8uIoEi2SWcpZyY711cDEtXTHQZvp7MDlwAQp3srAAEBHwCj4REAAAAAFgAUpUObR3wRa3m9THxRMfPljVTye7cBCGsCRzBEAiBl0KNJcJuNgEPP1kTPbBlsH2AaIuGz/fv4wMwqgP4vFwIgfIfTa2ZqiGLoHsXfKIcH9RfS816hVI/rggGd4sjekPcBIQJX2I6vHnm3LqCjOuibV9rpXqaEmb3GdwJX4BCriZ8KuwABAL0CAAAAAetFLw/JqMOe23n3F0dj88sl3FbbRVkm5BFxmhFe8WUJAAAAAEhHMEQCIFqoDMYV60s/bolpbbTq3RklgabEb1wJgH09mOzh13NVAiAlAH5YwZkqHl2HfuMkv+CmXbJtKfgJQc+id6w++8rSpwH+////ArzpqTIAAAAAF6kUFZDoUqxm64eYr+sqXtZ8VootZWGHAITXFwAAAAAZdqkUpX6gXqz5SQDV+5K8zSc8/bkK82+IrCECAAABB2pHMEQCICkKvKrL11nE+Yl2Kp7jRoqSMXiKq49Qv2WVXYWX2N02AiBNfjlPRBncU5LG7bppRYN0WN11CgMKxnp0YjGQOo632wEhA4gCX1C7UcBGlCHtEzgfIvnUagcOwoN+BVxJxYdvDQloAAEAFgAUwfkHKuoqnUr73OvefZHe1x64WBYA"
- calculatedPsbt, err := u.Upsbt.B64Encode()
- if err != nil {
- t.Fatalf("Failed to base64 encode")
- }
- if expectedFinalizedPsbt != calculatedPsbt {
- t.Fatalf("Failed to generate correct PSBT")
- }
-
- expectedNetworkSer, _ := hex.DecodeString("020000000001047b4131763e497f79c627665893faec24d0d3614f5296cd848c4da6501d96f93e0100000017160014b3773ea5d2c881d62aa9b86a1e66f5eadcff73a8ffffffff1b69ade1b5fbfac562d6375bb816b943fc6c25d83314281d1c7499ab77b02ba600000000171600142412be29368c0260cb841eecd9b59d7e01174aa1ffffffffcdadb65bec6cdf020e243aa1560086d769bab8700bed546bfe79e70822fd4a820100000000ffffffffbdecf627e9ae012b95a38d1f5ae0a4db3797afadfa6cf65c64c7b1355609e9bf010000006a4730440220290abcaacbd759c4f989762a9ee3468a9231788aab8f50bf65955d8597d8dd3602204d7e394f4419dc5392c6edba6945837458dd750a030ac67a746231903a8eb7db01210388025f50bb51c0469421ed13381f22f9d46a070ec2837e055c49c5876f0d0968ffffffff01f02672530000000017a914430b040b99f36dd63999e38dd99436b6199e1603870247304402201fb93318eda2b247c2bd7d1d8240eecdfa89eed02eeca51939eca44e4275498902201bf841164ad612f3e390f482cf8bcfddce138b37ee590f544f9295766d6b3584012102de369fd7d30c7deac19f4067e65c572463aaa2a99f4af9c772542f079809de710247304402205676877e6162ce40a49ee5a74443cdc1e7915637c42da7b872c2ec2298fd371b02203c1d4a05b1e2a7a588d9ec9b8d4892d2cd59bebe0e777483477a0ec692ebbe6d012102534f23cb88a048b649672967263bd7570312d5d31d066fa7b303970010a77b2b02473044022065d0a349709b8d8043cfd644cf6c196c1f601a22e1b3fdfbf8c0cc2a80fe2f1702207c87d36b666a8862e81ec5df288707f517d2f35ea1548feb82019de2c8de90f701210257d88eaf1e79b72ea0a33ae89b57dae95ea68499bdc6770257e010ab899f0abb0000000000")
- tx, err := Extract(psbt1)
- if err != nil {
- t.Fatalf("Failed to extract: %v", err)
- }
- var b bytes.Buffer
- if err := tx.Serialize(&b); err != nil {
- t.Fatalf("unable to encode tx: %v", err)
- }
- if !bytes.Equal(expectedNetworkSer, b.Bytes()) {
- t.Fatalf("Expected serialized transaction was not produced: %x", b.Bytes())
- }
-}
-
-// TestPSBTNumberOfHashesOverflow tests the case where the number of hashes
-// in the PSBT exceeds the maximum allowed value. This is a regression test
-// for a bug that was fixed in the PSBT library.
-func TestPSBTNumberOfHashesOverflow(t *testing.T) {
- // This hex string represents a PSBT with an invalid number of hashes. The
- // PSBT library should return an error when trying to parse this PSBT.
- //
- // TODO(ffranr): Is there a more minimal PSBT example?
- hexString := "70736274ff01007374ff01030100000000002f0000002e2873007374" +
- "ff01070100000000000000000000000000000000000000060680050000736274f" +
- "f01000a0000000060c70006060000736274ff01000a0000010000010024070100" +
- "00000000000000000000000000000000000006060000736274ff01000a0000000" +
- "000010024c760002a707362c760000b0500000000000000060605000073626274" +
- "ff01000a000000000001002421212121212121212121212121212121212121212" +
- "12121212121212121212121212121212107010000000000000000000000000000" +
- "000000000006060000736274ff01000a000eff000001000a0a040404040404040" +
- "400"
-
- // Convert hex string to byte slice
- buffer, err := hex.DecodeString(hexString)
- require.NoError(t, err)
-
- // Attempt to parse the PSBT.
- psbt, err := NewFromRawBytes(bytes.NewBuffer(buffer), false)
- require.Nil(t, psbt)
- require.ErrorIs(t, err, ErrInvalidPsbtFormat)
-}
-
-// TestMinTaprootBip32DerivationByteSize tests the
-// minTaprootBip32DerivationByteSize function to ensure it correctly calculates
-// the minimum byte size of the Taproot BIP32 derivation path.
-func TestMinTaprootBip32DerivationByteSize(t *testing.T) {
- tests := []struct {
- label string
- numHashes uint64
- expectedSize uint64
- expectErr bool
- }{
- {
- label: "only compact size + fingerprint",
- numHashes: 0,
- expectedSize: 5,
- expectErr: false,
- },
- {
- label: "numHashes == 1, therefore: 1 * 32 + 5",
- numHashes: 1,
- expectedSize: 37,
- expectErr: false,
- },
- {
- label: "numHashes == 2, therefore: 2 * 32 + 5",
- numHashes: 2,
- expectedSize: 69,
- expectErr: false,
- },
- {
- label: "overflow expected",
- numHashes: math.MaxUint64,
- expectedSize: 0,
- expectErr: true,
- },
- }
-
- for _, tt := range tests {
- actualSize, err := minTaprootBip32DerivationByteSize(tt.numHashes)
-
- if (err != nil) != tt.expectErr {
- t.Errorf(
- "%s (numHashes=%d, unexpected_error=%v)", tt.label,
- tt.numHashes, err,
- )
- continue
- }
-
- if err == nil && actualSize != tt.expectedSize {
- t.Errorf("%s (numHashes=%d, actualSize=%d, expectedSize=%d)",
- tt.label, tt.numHashes, actualSize, tt.expectedSize,
- )
- }
- }
-}
-
-// 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")
- }
-}
-
-// TestWitnessForNonWitnessUtxo makes sure that a packet that only has a non-
-// witness UTXO set can still be signed correctly by adding witness data. This
-// is to make sure that PSBTs following the CVE-2020-14199 bugfix are not
-// rejected. See https://github.com/bitcoin/bitcoin/pull/19215.
-func TestWitnessForNonWitnessUtxo(t *testing.T) {
- // Our witness UTXO is index 1 of this raw transaction from the test
- // vectors.
- prevTxRaw, _ := hex.DecodeString("0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000")
- prevTx := wire.NewMsgTx(2)
- err := prevTx.Deserialize(bytes.NewReader(prevTxRaw))
- if err != nil {
- t.Fatalf("failed to deserialize previous TX: %v", err)
- }
-
- // First create a packet that contains one input and one output.
- outPkScript, _ := hex.DecodeString(CUTestHexData["scriptPubkey1"])
- packet := &Packet{
- UnsignedTx: &wire.MsgTx{
- Version: 2,
- LockTime: 0,
- TxIn: []*wire.TxIn{{
- PreviousOutPoint: wire.OutPoint{
- Hash: prevTx.TxHash(),
- Index: 1,
- },
- }},
- TxOut: []*wire.TxOut{{
- PkScript: outPkScript,
- Value: 1.9 * btcutil.SatoshiPerBitcoin,
- }},
- },
- Inputs: []PInput{{}},
- Outputs: []POutput{{}},
- }
-
- // Create an updater for the packet. This also performs a sanity check.
- updater, err := NewUpdater(packet)
- if err != nil {
- t.Fatalf("failed to sanity check raw packet: %v", err)
- }
-
- // Now add our witness UTXO to the input. But because hardware wallets
- // that are patched against CVE-2020-14199 require the full non-witness
- // UTXO to be set for all inputs, we do what Core does and add the full
- // transaction in the NonWitnessUtxo instead of just the outpoint in
- // WitnessUtxo.
- err = updater.AddInNonWitnessUtxo(prevTx, 0)
- if err != nil {
- t.Fatalf("failed to update non-witness UTXO: %v", err)
- }
-
- // Then add the redeem scripts and witness scripts.
- redeemScript, _ := hex.DecodeString(CUTestHexData["Input2RedeemScript"])
- err = updater.AddInRedeemScript(redeemScript, 0)
- if err != nil {
- t.Fatalf("failed to update redeem script: %v", err)
- }
- witnessScript, _ := hex.DecodeString(CUTestHexData["Input2WitnessScript"])
- err = updater.AddInWitnessScript(witnessScript, 0)
- if err != nil {
- t.Fatalf("failed to update redeem script: %v", err)
- }
-
- // Add the first of the two partial signatures.
- sig1, _ := hex.DecodeString("3044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01")
- pub1, _ := hex.DecodeString("03089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc")
- res, err := updater.Sign(0, sig1, pub1, nil, nil)
- if err != nil {
- t.Fatalf("failed to sign with pubkey 1: %v", err)
- }
- if res != SignSuccesful {
- t.Fatalf("signing was not successful, got result %v", res)
- }
-
- // Check that the finalization procedure fails here due to not
- // meeting the multisig policy
- success, err := MaybeFinalize(packet, 0)
- if success {
- t.Fatalf("Incorrectly succeeded in finalizing without sigs")
- }
- if err != ErrUnsupportedScriptType {
- t.Fatalf("Got unexpected error type: %v", err)
- }
-
- // Add the second partial signature.
- sig2, _ := hex.DecodeString("3044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d201")
- pub2, _ := hex.DecodeString("023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73")
- res, err = updater.Sign(0, sig2, pub2, nil, nil)
- if err != nil {
- t.Fatalf("failed to sign with pubkey 2: %v", err)
- }
- if res != SignSuccesful {
- t.Fatalf("signing was not successful, got result %v", res)
- }
-
- // Finally make sure we can finalize the packet and extract the raw TX.
- err = MaybeFinalizeAll(packet)
- if err != nil {
- t.Fatalf("error finalizing PSBT: %v", err)
- }
- _, err = Extract(packet)
- if err != nil {
- t.Fatalf("unable to extract funding TX: %v", err)
- }
-}
-
-// TestUnknowns tests that we can parse and serialize unknown fields on all
-// three levels (global, input, output).
-func TestUnknowns(t *testing.T) {
- packetWithUnknowns := "cHNidP8BAIkCAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgUAAAAAAAAAIlEg5i9uUYF8DDqT/1fKz8jKT2g/Gj68P6EjLW6dHbImdM0FAAAAAAAAACJRIHS02KqR/607mTrLCABOVF3rLxVDtOLvAw3JLcL5JIgwAAAAAAFwAQEBcQZ0YXJvcnQAIgYCkGaT9mOyWvyoiwSCb1xgFhRie+Y3nTSmO0QQrAe0q7AYAAAAAPkDAIABAACA2wAAgAAAAAAAAAAAIRaQZpP2Y7Ja/KiLBIJvXGAWFGJ75jedNKY7RBCsB7SrsBkAAAAAAPkDAIABAACA2wAAgAAAAAAAAAAAARcgkGaT9mOyWvyoiwSCb1xgFhRie+Y3nTSmO0QQrAe0q7ABGCBlB87S1Bq/Niu8SdW9U1se7WsumF+1gYZ/00f/WkWGAgFwZX/rKpmW4Iz1ScSX2U2SIv8LN5kLvMWGeI7scXdPH/1uAAAAATanCvuEYVDT4vBfORd+71iC7GijIfGKofjwnXI56U3TAhYyvDW2pIk+islXsY45l27xfgJwWWK+CmkFs+cUptDlAXEIAAAAAAAAA+gBciJRIIBtIlu09Y4lcMgdHz3QhfSVV69iKin6cPxH2JFLTO1jAXMIAAAAAAAAAAABdCECtg44XjZucowo0SQp2YJa0esIwS9Bc1N8CpcddTkDdrQBdSB+nQzzBbHVbtIB0AoMIZvFEQpGG1hdp3D+8eYIu37oUgF2GAAAAAD5AwCAAQAAgNsAAIAAAAAAAQAAAAF3GQAAAAAA+QMAgAEAAIDbAACAAAAAAAEAAAABef2sAgABAAFWQzv2kOxwflKCXy51yDJbmfD7pZRVI1+f2k4j5aRkVX0AAAAACWl0ZXN0YnV4eCJzb21lIG1ldGFkYXRhIGZvciB0aGUgaXRlc3QgYXNzZXRzAAAAAAACAQADAQoG/QIgAf0CHABlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/QGxSgAB5CgfrndtXUxNHYy61v8ZFC7EVnez4uBSIuSsEug67DIAAAAAAAATfv////////////////////////////////////////+//QFjAAEAAVZDO/aQ7HB+UoJfLnXIMluZ8PullFUjX5/aTiPlpGRVfQAAAAAJaXRlc3RidXh4InNvbWUgbWV0YWRhdGEgZm9yIHRoZSBpdGVzdCBhc3NldHMAAAAAAAIBAAMD/RN+Bq0BqwBldkseYyHTOjpT8WRNj+s5WMuADtDMKW09wG38rhEwM2oAAAAANqcK+4RhUNPi8F85F37vWILsaKMh8Yqh+PCdcjnpTdMCTr1IzgTZHOvZY2+EhzZF1w+HDMMZ2VZ5jDtyuViKWXIBQgFA0KHA0Di7lgqweVLU71eNWoOE759Ec6yFtcw6zVD45yUl8z58/GNb2+xbh/Ou5jfpDAkd4I4wXlafTu3dplTsqAcoHxlrrWtdUR74IMEFKrV3ECvdKAQfH98pZoSlmT1/jQUAAAAAAAATiAgCAAAJIQJhfW7AFTIwW95KKmZWOlJPDjl6ZUyk8uTE4AVS21a0wAgCAAAJIQIWMrw1tqSJPorJV7GOOZdu8X4CcFlivgppBbPnFKbQ5QF6AQEAIgICJzY1cX8foM/D3nXJDsULt45A8PTSWG42lK0rBOqOJrYYAAAAAPkDAIABAACA2wAAgAAAAAACAAAAAQUgJzY1cX8foM/D3nXJDsULt45A8PTSWG42lK0rBOqOJrYhByc2NXF/H6DPw951yQ7FC7eOQPD00lhuNpStKwTqjia2GQAAAAAA+QMAgAEAAIDbAACAAAAAAAIAAAABcAEBAXEBAAFyCAAAAAAAAAAAAXMhAy38VNCuGaPv8LhP6aLaKPFgZC+c5VBOwjrnKR2ReQRCAXQYAAAAAPkDAIABAACA2wAAgAAAAAADAAAAAXUZAAAAAAD5AwCAAQAAgNsAAIAAAAAAAwAAAAF2/WEBAAEAAVZDO/aQ7HB+UoJfLnXIMluZ8PullFUjX5/aTiPlpGRVfQAAAAAJaXRlc3RidXh4InNvbWUgbWV0YWRhdGEgZm9yIHRoZSBpdGVzdCBhc3NldHMAAAAAAAIBAAMBBQatAasAZX/rKpmW4Iz1ScSX2U2SIv8LN5kLvMWGeI7scXdPH/1uAAAAATanCvuEYVDT4vBfORd+71iC7GijIfGKofjwnXI56U3TAhYyvDW2pIk+islXsY45l27xfgJwWWK+CmkFs+cUptDlAUIBQIcR8GQWP8a+XpOIE2KfA844YQQoKuLX18B/Q47cO1MQYzA6SJdDQ3InMTjRxR9STCe5CxnPW9ufpX50GBaV9YIHKHkuFWwwWI5ZxJiPIInqUjmAvRpa9Gi8E4NAW0EtPMAnAAAAAAAAAAoIAgAACSEC5i9uUYF8DDqT/1fKz8jKT2g/Gj68P6EjLW6dHbImdM0AAXABAAFxAQABcggAAAAAAAAAAQFzIQIQiynNQqsCXWFOpFav8EY3PtUvCL3HdwPj0w4MMI1PowF2/aoCAAEAAVZDO/aQ7HB+UoJfLnXIMluZ8PullFUjX5/aTiPlpGRVfQAAAAAJaXRlc3RidXh4InNvbWUgbWV0YWRhdGEgZm9yIHRoZSBpdGVzdCBhc3NldHMAAAAAAAIBAAMBBQb9Ah4B/QIaAGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL9Aa9KAAEhQAiYnrNk28uUgoU7xUnxAxecle1lVSSbHyT0Xdo8FgAAAAAAAAAF/////////////////////////////////////////3/9AWEAAQABVkM79pDscH5Sgl8udcgyW5nw+6WUVSNfn9pOI+WkZFV9AAAAAAlpdGVzdGJ1eHgic29tZSBtZXRhZGF0YSBmb3IgdGhlIGl0ZXN0IGFzc2V0cwAAAAAAAgEAAwEFBq0BqwBlf+sqmZbgjPVJxJfZTZIi/ws3mQu8xYZ4juxxd08f/W4AAAABNqcK+4RhUNPi8F85F37vWILsaKMh8Yqh+PCdcjnpTdMCFjK8NbakiT6KyVexjjmXbvF+AnBZYr4KaQWz5xSm0OUBQgFAhxHwZBY/xr5ek4gTYp8DzjhhBCgq4tfXwH9Djtw7UxBjMDpIl0NDcicxONHFH1JMJ7kLGc9b25+lfnQYFpX1ggcoeS4VbDBYjlnEmI8giepSOYC9Glr0aLwTg0BbQS08wCcAAAAAAAAACggCAAAJIQLmL25RgXwMOpP/V8rPyMpPaD8aPrw/oSMtbp0dsiZ0zQgCAAAJIQJ0tNiqkf+tO5k6ywgATlRd6y8VQ7Ti7wMNyS3C+SSIMAA="
-
- packet, err := NewFromRawBytes(
- strings.NewReader(packetWithUnknowns), true,
- )
- require.NoError(t, err)
-
- require.Len(t, packet.Unknowns, 2)
-
- require.Len(t, packet.Inputs, 1)
- require.Len(t, packet.Inputs[0].Unknowns, 10)
-
- require.Len(t, packet.Outputs, 2)
- require.Len(t, packet.Outputs[0].Unknowns, 7)
-
- // Convert it to base64 again to make sure the fields are also
- // serialized.
- encoded, err := packet.B64Encode()
- require.NoError(t, err)
- require.Equal(t, packetWithUnknowns, encoded)
-}
diff --git a/btcutil/psbt/signer.go b/btcutil/psbt/signer.go
deleted file mode 100644
index ad5e7fd..0000000
--- a/btcutil/psbt/signer.go
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright (c) 2018 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package psbt
-
-// signer encapsulates the role 'Signer' as specified in BIP174; it controls
-// the insertion of signatures; the Sign() function will attempt to insert
-// signatures using Updater.addPartialSignature, after first ensuring the Psbt
-// is in the correct state.
-
-import (
- "github.com/btcsuite/btcd/txscript/v2"
-)
-
-// SignOutcome is a enum-like value that expresses the outcome of a call to the
-// Sign method.
-type SignOutcome int
-
-const (
- // SignSuccesful indicates that the partial signature was successfully
- // attached.
- SignSuccesful = 0
-
- // SignFinalized indicates that this input is already finalized, so the
- // provided signature was *not* attached
- SignFinalized = 1
-
- // SignInvalid indicates that the provided signature data was not valid.
- // In this case an error will also be returned.
- SignInvalid = -1
-)
-
-// Sign allows the caller to sign a PSBT at a particular input; they
-// must provide a signature and a pubkey, both as byte slices; they can also
-// optionally provide both witnessScript and/or redeemScript, otherwise these
-// arguments must be set as nil (and in that case, they must already be present
-// in the PSBT if required for signing to succeed).
-//
-// This serves as a wrapper around Updater.addPartialSignature; it ensures that
-// the redeemScript and witnessScript are updated as needed (note that the
-// Updater is allowed to add redeemScripts and witnessScripts independently,
-// before signing), and ensures that the right form of utxo field
-// (NonWitnessUtxo or WitnessUtxo) is included in the input so that signature
-// insertion (and then finalization) can take place.
-func (u *Updater) Sign(inIndex int, sig []byte, pubKey []byte,
- redeemScript []byte, witnessScript []byte) (SignOutcome, error) {
-
- if isFinalized(u.Upsbt, inIndex) {
- return SignFinalized, nil
- }
-
- // Add the witnessScript to the PSBT in preparation. If it already
- // exists, it will be overwritten.
- if witnessScript != nil {
- err := u.AddInWitnessScript(witnessScript, inIndex)
- if err != nil {
- return SignInvalid, err
- }
- }
-
- // Add the redeemScript to the PSBT in preparation. If it already
- // exists, it will be overwritten.
- if redeemScript != nil {
- err := u.AddInRedeemScript(redeemScript, inIndex)
- if err != nil {
- return SignInvalid, err
- }
- }
-
- // At this point, the PSBT must have the requisite witnessScript or
- // redeemScript fields for signing to succeed.
- //
- // Case 1: if witnessScript is present, it must be of type witness;
- // if not, signature insertion will of course fail.
- pInput := u.Upsbt.Inputs[inIndex]
- switch {
- case pInput.WitnessScript != nil:
- if pInput.WitnessUtxo == nil {
- err := nonWitnessToWitness(u.Upsbt, inIndex)
- if err != nil {
- return SignInvalid, err
- }
- }
-
- err := u.addPartialSignature(inIndex, sig, pubKey)
- if err != nil {
- return SignInvalid, err
- }
-
- // Case 2: no witness script, only redeem script; can be legacy p2sh or
- // p2sh-wrapped p2wkh.
- case pInput.RedeemScript != nil:
- // We only need to decide if the input is witness, and we don't
- // rely on the witnessutxo/nonwitnessutxo in the PSBT, instead
- // we check the redeemScript content.
- if txscript.IsWitnessProgram(redeemScript) {
- if pInput.WitnessUtxo == nil {
- err := nonWitnessToWitness(u.Upsbt, inIndex)
- if err != nil {
- return SignInvalid, err
- }
- }
- }
-
- // If it is not a valid witness program, we here assume that
- // the provided WitnessUtxo/NonWitnessUtxo field was correct.
- err := u.addPartialSignature(inIndex, sig, pubKey)
- if err != nil {
- return SignInvalid, err
- }
-
- // Case 3: Neither provided only works for native p2wkh, or non-segwit
- // non-p2sh. To check if it's segwit, check the scriptPubKey of the
- // output.
- default:
- if pInput.WitnessUtxo == nil {
- txIn := u.Upsbt.UnsignedTx.TxIn[inIndex]
- outIndex := txIn.PreviousOutPoint.Index
- script := pInput.NonWitnessUtxo.TxOut[outIndex].PkScript
-
- if txscript.IsWitnessProgram(script) {
- err := nonWitnessToWitness(u.Upsbt, inIndex)
- if err != nil {
- return SignInvalid, err
- }
- }
- }
-
- err := u.addPartialSignature(inIndex, sig, pubKey)
- if err != nil {
- return SignInvalid, err
- }
- }
-
- return SignSuccesful, nil
-}
-
-// nonWitnessToWitness extracts the TxOut from the existing NonWitnessUtxo
-// field in the given PSBT input and sets it as type witness by replacing the
-// NonWitnessUtxo field with a WitnessUtxo field. See
-// https://github.com/bitcoin/bitcoin/pull/14197.
-func nonWitnessToWitness(p *Packet, inIndex int) error {
- outIndex := p.UnsignedTx.TxIn[inIndex].PreviousOutPoint.Index
- txout := p.Inputs[inIndex].NonWitnessUtxo.TxOut[outIndex]
-
- // TODO(guggero): For segwit v1, we'll want to remove the NonWitnessUtxo
- // from the packet. For segwit v0 it is unsafe to only rely on the
- // witness UTXO. See https://github.com/bitcoin/bitcoin/pull/19215.
- // p.Inputs[inIndex].NonWitnessUtxo = nil
-
- u := Updater{
- Upsbt: p,
- }
-
- return u.AddInWitnessUtxo(txout, inIndex)
-}
diff --git a/btcutil/psbt/sort.go b/btcutil/psbt/sort.go
deleted file mode 100644
index 11454ba..0000000
--- a/btcutil/psbt/sort.go
+++ /dev/null
@@ -1,102 +0,0 @@
-package psbt
-
-import (
- "bytes"
- "sort"
-
- "github.com/btcsuite/btcd/chainhash/v2"
-)
-
-// InPlaceSort modifies the passed packet's wire TX inputs and outputs to be
-// sorted based on BIP 69. The sorting happens in a way that the packet's
-// partial inputs and outputs are also modified to match the sorted TxIn and
-// TxOuts of the wire transaction.
-//
-// WARNING: This function must NOT be called with packages that already contain
-// (partial) witness data since it will mutate the transaction if it's not
-// already sorted. This can cause issues if you mutate a tx in a block, for
-// example, which would invalidate the block. It could also cause cached hashes,
-// such as in a btcutil.Tx to become invalidated.
-//
-// The function should only be used if the caller is creating the transaction or
-// is otherwise 100% positive mutating will not cause adverse affects due to
-// other dependencies.
-func InPlaceSort(packet *Packet) error {
- // To make sure we don't run into any nil pointers or array index
- // violations during sorting, do a very basic sanity check first.
- err := VerifyInputOutputLen(packet, false, false)
- if err != nil {
- return err
- }
-
- sort.Sort(&sortableInputs{p: packet})
- sort.Sort(&sortableOutputs{p: packet})
-
- return nil
-}
-
-// sortableInputs is a simple wrapper around a packet that implements the
-// sort.Interface for sorting the wire and partial inputs of a packet.
-type sortableInputs struct {
- p *Packet
-}
-
-// sortableOutputs is a simple wrapper around a packet that implements the
-// sort.Interface for sorting the wire and partial outputs of a packet.
-type sortableOutputs struct {
- p *Packet
-}
-
-// For sortableInputs and sortableOutputs, three functions are needed to make
-// them sortable with sort.Sort() -- Len, Less, and Swap.
-// Len and Swap are trivial. Less is BIP 69 specific.
-func (s *sortableInputs) Len() int { return len(s.p.UnsignedTx.TxIn) }
-func (s sortableOutputs) Len() int { return len(s.p.UnsignedTx.TxOut) }
-
-// Swap swaps two inputs.
-func (s *sortableInputs) Swap(i, j int) {
- tx := s.p.UnsignedTx
- tx.TxIn[i], tx.TxIn[j] = tx.TxIn[j], tx.TxIn[i]
- s.p.Inputs[i], s.p.Inputs[j] = s.p.Inputs[j], s.p.Inputs[i]
-}
-
-// Swap swaps two outputs.
-func (s *sortableOutputs) Swap(i, j int) {
- tx := s.p.UnsignedTx
- tx.TxOut[i], tx.TxOut[j] = tx.TxOut[j], tx.TxOut[i]
- s.p.Outputs[i], s.p.Outputs[j] = s.p.Outputs[j], s.p.Outputs[i]
-}
-
-// Less is the input comparison function. First sort based on input hash
-// (reversed / rpc-style), then index.
-func (s *sortableInputs) Less(i, j int) bool {
- ins := s.p.UnsignedTx.TxIn
-
- // Input hashes are the same, so compare the index.
- ihash := ins[i].PreviousOutPoint.Hash
- jhash := ins[j].PreviousOutPoint.Hash
- if ihash == jhash {
- return ins[i].PreviousOutPoint.Index <
- ins[j].PreviousOutPoint.Index
- }
-
- // At this point, the hashes are not equal, so reverse them to
- // big-endian and return the result of the comparison.
- const hashSize = chainhash.HashSize
- for b := 0; b < hashSize/2; b++ {
- ihash[b], ihash[hashSize-1-b] = ihash[hashSize-1-b], ihash[b]
- jhash[b], jhash[hashSize-1-b] = jhash[hashSize-1-b], jhash[b]
- }
- return bytes.Compare(ihash[:], jhash[:]) == -1
-}
-
-// Less is the output comparison function. First sort based on amount (smallest
-// first), then PkScript.
-func (s *sortableOutputs) Less(i, j int) bool {
- outs := s.p.UnsignedTx.TxOut
-
- if outs[i].Value == outs[j].Value {
- return bytes.Compare(outs[i].PkScript, outs[j].PkScript) < 0
- }
- return outs[i].Value < outs[j].Value
-}
diff --git a/btcutil/psbt/sort_test.go b/btcutil/psbt/sort_test.go
deleted file mode 100644
index 4423d8b..0000000
--- a/btcutil/psbt/sort_test.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package psbt
-
-import (
- "reflect"
- "testing"
-
- "github.com/btcsuite/btcd/chainhash/v2"
- "github.com/btcsuite/btcd/wire/v2"
-)
-
-func TestInPlaceSort(t *testing.T) {
- testCases := []struct {
- name string
- packet *Packet
- expectedTxIn []*wire.TxIn
- expectedTxOut []*wire.TxOut
- expectedPIn []PInput
- expectedPOut []POutput
- expectErr bool
- }{{
- name: "packet nil",
- packet: nil,
- expectErr: true,
- }, {
- name: "no inputs or outputs",
- packet: &Packet{UnsignedTx: &wire.MsgTx{}},
- expectErr: false,
- }, {
- name: "inputs only",
- packet: &Packet{
- UnsignedTx: &wire.MsgTx{
- TxIn: []*wire.TxIn{{
- PreviousOutPoint: wire.OutPoint{
- Hash: chainhash.Hash{99, 88},
- Index: 7,
- },
- }, {
- PreviousOutPoint: wire.OutPoint{
- Hash: chainhash.Hash{77, 88},
- Index: 12,
- },
- }, {
- PreviousOutPoint: wire.OutPoint{
- Hash: chainhash.Hash{77, 88},
- Index: 7,
- },
- }},
- },
- // Abuse the SighashType as an index to make sure the
- // partial inputs are also sorted together with the wire
- // inputs.
- Inputs: []PInput{{
- SighashType: 0,
- }, {
- SighashType: 1,
- }, {
- SighashType: 2,
- }},
- },
- expectedTxIn: []*wire.TxIn{{
- PreviousOutPoint: wire.OutPoint{
- Hash: chainhash.Hash{77, 88},
- Index: 7,
- },
- }, {
- PreviousOutPoint: wire.OutPoint{
- Hash: chainhash.Hash{77, 88},
- Index: 12,
- },
- }, {
- PreviousOutPoint: wire.OutPoint{
- Hash: chainhash.Hash{99, 88},
- Index: 7,
- },
- }},
- expectedPIn: []PInput{{
- SighashType: 2,
- }, {
- SighashType: 1,
- }, {
- SighashType: 0,
- }},
- expectErr: false,
- }, {
- name: "outputs only",
- packet: &Packet{
- UnsignedTx: &wire.MsgTx{
- TxOut: []*wire.TxOut{{
- PkScript: []byte{99, 88},
- Value: 7,
- }, {
- PkScript: []byte{77, 88},
- Value: 12,
- }, {
- PkScript: []byte{77, 88},
- Value: 7,
- }},
- },
- // Abuse the RedeemScript as an index to make sure the
- // partial inputs are also sorted together with the wire
- // inputs.
- Outputs: []POutput{{
- RedeemScript: []byte{0},
- }, {
- RedeemScript: []byte{1},
- }, {
- RedeemScript: []byte{2},
- }},
- },
- expectedTxOut: []*wire.TxOut{{
- PkScript: []byte{77, 88},
- Value: 7,
- }, {
- PkScript: []byte{99, 88},
- Value: 7,
- }, {
- PkScript: []byte{77, 88},
- Value: 12,
- }},
- expectedPOut: []POutput{{
- RedeemScript: []byte{2},
- }, {
- RedeemScript: []byte{0},
- }, {
- RedeemScript: []byte{1},
- }},
- expectErr: false,
- }}
-
- for _, tc := range testCases {
- tc := tc
- t.Run(tc.name, func(t *testing.T) {
- p := tc.packet
- err := InPlaceSort(p)
- if (tc.expectErr && err == nil) ||
- (!tc.expectErr && err != nil) {
-
- t.Fatalf("got error '%v' but wanted it to be "+
- "nil: %v", err, tc.expectErr)
- }
-
- // Don't continue on this special test case.
- if p == nil {
- return
- }
-
- tx := p.UnsignedTx
- if !reflect.DeepEqual(tx.TxIn, tc.expectedTxIn) {
- t.Fatalf("unexpected txin, got %#v wanted %#v",
- tx.TxIn, tc.expectedTxIn)
- }
- if !reflect.DeepEqual(tx.TxOut, tc.expectedTxOut) {
- t.Fatalf("unexpected txout, got %#v wanted %#v",
- tx.TxOut, tc.expectedTxOut)
- }
-
- if !reflect.DeepEqual(p.Inputs, tc.expectedPIn) {
- t.Fatalf("unexpected pin, got %#v wanted %#v",
- p.Inputs, tc.expectedPIn)
- }
- if !reflect.DeepEqual(p.Outputs, tc.expectedPOut) {
- t.Fatalf("unexpected pout, got %#v wanted %#v",
- p.Inputs, tc.expectedPOut)
- }
- })
- }
-}
diff --git a/btcutil/psbt/taproot.go b/btcutil/psbt/taproot.go
deleted file mode 100644
index 117a1bf..0000000
--- a/btcutil/psbt/taproot.go
+++ /dev/null
@@ -1,271 +0,0 @@
-package psbt
-
-import (
- "bytes"
- "math"
- "math/bits"
-
- "github.com/btcsuite/btcd/btcec/v2/schnorr"
- "github.com/btcsuite/btcd/txscript/v2"
- "github.com/btcsuite/btcd/wire/v2"
-)
-
-const (
- // schnorrSigMinLength is the minimum length of a Schnorr signature
- // which is 64 bytes.
- schnorrSigMinLength = schnorr.SignatureSize
-
- // schnorrSigMaxLength is the maximum length of a Schnorr signature
- // which is 64 bytes plus one byte for the appended sighash flag.
- schnorrSigMaxLength = schnorrSigMinLength + 1
-)
-
-// TaprootScriptSpendSig encapsulates an individual Schnorr signature for a
-// given public key and leaf hash.
-type TaprootScriptSpendSig struct {
- XOnlyPubKey []byte
- LeafHash []byte
- Signature []byte
- SigHash txscript.SigHashType
-}
-
-// checkValid checks that both the pubkey and the signature are valid.
-func (s *TaprootScriptSpendSig) checkValid() bool {
- return validateXOnlyPubkey(s.XOnlyPubKey) &&
- validateSchnorrSignature(s.Signature)
-}
-
-// EqualKey returns true if this script spend signature's key data is the same
-// as the given script spend signature.
-func (s *TaprootScriptSpendSig) EqualKey(other *TaprootScriptSpendSig) bool {
- return bytes.Equal(s.XOnlyPubKey, other.XOnlyPubKey) &&
- bytes.Equal(s.LeafHash, other.LeafHash)
-}
-
-// SortBefore returns true if this script spend signature's key is
-// lexicographically smaller than the given other script spend signature's key
-// and should come first when being sorted.
-func (s *TaprootScriptSpendSig) SortBefore(other *TaprootScriptSpendSig) bool {
- return bytes.Compare(s.XOnlyPubKey, other.XOnlyPubKey) < 0 &&
- bytes.Compare(s.LeafHash, other.LeafHash) < 0
-}
-
-// TaprootTapLeafScript represents a single taproot leaf script that is
-// identified by its control block.
-type TaprootTapLeafScript struct {
- ControlBlock []byte
- Script []byte
- LeafVersion txscript.TapscriptLeafVersion
-}
-
-// checkValid checks that the control block is valid.
-func (s *TaprootTapLeafScript) checkValid() bool {
- return validateControlBlock(s.ControlBlock)
-}
-
-// SortBefore returns true if this leaf script's key is lexicographically
-// smaller than the given other leaf script's key and should come first when
-// being sorted.
-func (s *TaprootTapLeafScript) SortBefore(other *TaprootTapLeafScript) bool {
- return bytes.Compare(s.ControlBlock, other.ControlBlock) < 0
-}
-
-// TaprootBip32Derivation encapsulates the data for the input and output
-// taproot specific BIP-32 derivation key-value fields.
-type TaprootBip32Derivation struct {
- // XOnlyPubKey is the raw public key serialized in the x-only BIP-340
- // format.
- XOnlyPubKey []byte
-
- // LeafHashes is a list of leaf hashes that the given public key is
- // involved in.
- LeafHashes [][]byte
-
- // MasterKeyFingerprint is the fingerprint of the master pubkey.
- MasterKeyFingerprint uint32
-
- // Bip32Path is the BIP 32 path with child index as a distinct integer.
- Bip32Path []uint32
-}
-
-// SortBefore returns true if this derivation info's key is lexicographically
-// smaller than the given other derivation info's key and should come first when
-// being sorted.
-func (s *TaprootBip32Derivation) SortBefore(other *TaprootBip32Derivation) bool {
- return bytes.Compare(s.XOnlyPubKey, other.XOnlyPubKey) < 0
-}
-
-// minTaprootBip32DerivationByteSize returns the minimum number of bytes
-// required to encode a Taproot BIP32 derivation field, given the number of
-// leaf hashes.
-//
-// NOTE: This function does not account for the size of the BIP32 child indexes,
-// as we are only computing the minimum size (which occurs when the path is
-// empty). The bits package is used to safely detect and handle overflows.
-func minTaprootBip32DerivationByteSize(numHashes uint64) (uint64, error) {
- // The Taproot BIP32 derivation field is encoded as:
- // [compact size uint: number of leaf hashes]
- // [N × 32 bytes: leaf hashes]
- // [4 bytes: master key fingerprint]
- // [M × 4 bytes: BIP32 child indexes]
- //
- // To compute the minimum size given the number of hashes only, we assume:
- // - N = numHashes (provided)
- // - M = 0 (no child indexes)
- //
- // So the base byte size is:
- // 1 (leaf hash count) + (N × 32) + 4 (fingerprint)
- //
- // First, we calculate the total number of bytes for the leaf hashes.
- mulCarry, totalHashesBytes := bits.Mul64(numHashes, 32)
- if mulCarry != 0 {
- return 0, ErrInvalidPsbtFormat
- }
-
- // Since we're computing the minimum possible size, we add a constant that
- // accounts for the fixed size fields:
- // * 1 byte for the compact size leaf hash count (assumes numHashes < 0xfd)
- // * 4 bytes for the master key fingerprint
- // Total: 5 bytes.
- // All other fields (e.g., BIP32 path) are assumed absent for minimum size
- // calculation.
- result, addCarry := bits.Add64(5, totalHashesBytes, 0)
- if addCarry != 0 {
- return 0, ErrInvalidPsbtFormat
- }
-
- return result, nil
-}
-
-// ReadTaprootBip32Derivation deserializes a byte slice containing the Taproot
-// BIP32 derivation info that consists of a list of leaf hashes as well as the
-// normal BIP32 derivation info.
-func ReadTaprootBip32Derivation(xOnlyPubKey,
- value []byte) (*TaprootBip32Derivation, error) {
-
- // This function allocates additional memory while parsing the serialized
- // data. To prevent potential out-of-memory (OOM) issues, we must validate
- // the length of the value slice before proceeding.
- if len(value) > MaxPsbtValueLength {
- return nil, ErrInvalidPsbtFormat
- }
-
- // The taproot key BIP 32 derivation path is defined as:
- // <hashes len> <leaf hash>* <4 byte fingerprint> <32-bit uint>*
- // So we get at least 5 bytes for the length and the 4 byte fingerprint.
- if len(value) < 5 {
- return nil, ErrInvalidPsbtFormat
- }
-
- // The first element is the number of hashes that will follow.
- reader := bytes.NewReader(value)
- numHashes, err := wire.ReadVarInt(reader, 0)
- if err != nil {
- return nil, ErrInvalidPsbtFormat
- }
-
- // As a safety/sanity check, verify that the hash count fits in a `uint32`.
- // This isn’t mandated by BIP‑371, but it prevents overflow and limits
- // derivations to about 137 GiB of data.
- if numHashes > math.MaxUint32 {
- return nil, ErrInvalidPsbtFormat
- }
-
- // Given the number of hashes, we can calculate the minimum byte size
- // of the taproot BIP32 derivation.
- minByteSize, err := minTaprootBip32DerivationByteSize(numHashes)
- if err != nil {
- return nil, err
- }
-
- // Ensure that value is at least the minimum size.
- if uint64(len(value)) < minByteSize {
- return nil, ErrInvalidPsbtFormat
- }
-
- derivation := TaprootBip32Derivation{
- XOnlyPubKey: xOnlyPubKey,
- LeafHashes: make([][]byte, int(numHashes)),
- }
-
- for i := 0; i < int(numHashes); i++ {
- derivation.LeafHashes[i] = make([]byte, 32)
- n, err := reader.Read(derivation.LeafHashes[i])
- if err != nil || n != 32 {
- return nil, ErrInvalidPsbtFormat
- }
- }
-
- // Extract the remaining bytes from the reader (we don't actually know
- // how many bytes we read due to the compact size integer at the
- // beginning).
- var leftoverBuf bytes.Buffer
- _, err = reader.WriteTo(&leftoverBuf)
- if err != nil {
- return nil, err
- }
-
- // Read the BIP32 derivation info.
- fingerprint, path, err := ReadBip32Derivation(leftoverBuf.Bytes())
- if err != nil {
- return nil, err
- }
-
- derivation.MasterKeyFingerprint = fingerprint
- derivation.Bip32Path = path
-
- return &derivation, nil
-}
-
-// SerializeTaprootBip32Derivation serializes a TaprootBip32Derivation to its
-// raw byte representation.
-func SerializeTaprootBip32Derivation(d *TaprootBip32Derivation) ([]byte,
- error) {
-
- var buf bytes.Buffer
-
- // The taproot key BIP 32 derivation path is defined as:
- // <hashes len> <leaf hash>* <4 byte fingerprint> <32-bit uint>*
- err := wire.WriteVarInt(&buf, 0, uint64(len(d.LeafHashes)))
- if err != nil {
- return nil, ErrInvalidPsbtFormat
- }
-
- for _, hash := range d.LeafHashes {
- n, err := buf.Write(hash)
- if err != nil || n != 32 {
- return nil, ErrInvalidPsbtFormat
- }
- }
-
- _, err = buf.Write(SerializeBIP32Derivation(
- d.MasterKeyFingerprint, d.Bip32Path,
- ))
- if err != nil {
- return nil, ErrInvalidPsbtFormat
- }
-
- return buf.Bytes(), nil
-}
-
-// validateXOnlyPubkey checks if pubKey is *any* valid pubKey serialization in a
-// BIP-340 context (x-only serialization).
-func validateXOnlyPubkey(pubKey []byte) bool {
- _, err := schnorr.ParsePubKey(pubKey)
- return err == nil
-}
-
-// validateSchnorrSignature checks that the passed byte slice is a valid Schnorr
-// signature, _NOT_ including the sighash flag. It does *not* of course
-// validate the signature against any message or public key.
-func validateSchnorrSignature(sig []byte) bool {
- _, err := schnorr.ParseSignature(sig)
- return err == nil
-}
-
-// validateControlBlock checks that the passed byte slice is a valid control
-// block as it would appear in a BIP-341 witness stack as the last element.
-func validateControlBlock(controlBlock []byte) bool {
- _, err := txscript.ParseControlBlock(controlBlock)
- return err == nil
-}
diff --git a/btcutil/psbt/types.go b/btcutil/psbt/types.go
deleted file mode 100644
index ca55510..0000000
--- a/btcutil/psbt/types.go
+++ /dev/null
@@ -1,203 +0,0 @@
-package psbt
-
-// GlobalType is the set of types that are used at the global scope level
-// within the PSBT.
-type GlobalType uint8
-
-const (
- // UnsignedTxType is the global scope key that houses the unsigned
- // transaction of the PSBT. The value is a transaction in network
- // serialization. The scriptSigs and witnesses for each input must be
- // empty. The transaction must be in the old serialization format
- // (without witnesses). A PSBT must have a transaction, otherwise it is
- // invalid.
- UnsignedTxType GlobalType = 0
-
- // XPubType houses a global xPub for the entire PSBT packet.
- //
- // The key ({0x01}|{xpub}) is the 78 byte serialized extended public key
- // as defined by BIP-0032. Extended public keys are those that can be
- // used to derive public keys used in the inputs and outputs of this
- // transaction. It should be the public key at the highest hardened
- // derivation index so that the unhardened child keys used in the
- // transaction can be derived.
- //
- // The value is the master key fingerprint as defined by BIP-0032
- // concatenated with the derivation path of the public key. The
- // derivation path is represented as 32-bit little endian unsigned
- // integer indexes concatenated with each other. The number of 32-bit
- // unsigned integer indexes must match the depth provided in the
- // extended public key.
- XPubType GlobalType = 1
-
- // VersionType houses the global version number of this PSBT. There is
- // no key (only contains the byte type), then the value if omitted, is
- // assumed to be zero.
- VersionType GlobalType = 0xFB
-
- // ProprietaryGlobalType is used to house any proper chary global-scope
- // keys within the PSBT.
- //
- // The key is ({0xFC}|<prefix>|{subtype}|{key data}) a variable length
- // identifier prefix, followed by a subtype, followed by the key data
- // itself.
- //
- // The value is any data as defined by the proprietary type user.
- ProprietaryGlobalType = 0xFC
-)
-
-// InputType is the set of types that are defined for each input included
-// within the PSBT.
-type InputType uint32
-
-const (
- // NonWitnessUtxoType has no key ({0x00}) and houses the transaction in
- // network serialization format the current input spends from. This
- // should only be present for inputs which spend non-segwit outputs.
- // However, if it is unknown whether an input spends a segwit output,
- // this type should be used. The entire input transaction is needed in
- // order to be able to verify the values of the input (pre-segwit they
- // aren't in the signature digest).
- NonWitnessUtxoType InputType = 0
-
- // WitnessUtxoType has no key ({0x01}), and houses the entire
- // transaction output in network serialization which the current input
- // spends from. This should only be present for inputs which spend
- // segwit outputs, including P2SH embedded ones (value || script).
- WitnessUtxoType InputType = 1
-
- // PartialSigType is used to include a partial signature with key
- // ({0x02}|{public key}).
- //
- // The value is the signature as would be pushed to the stack from a
- // scriptSig or witness..
- PartialSigType InputType = 2
-
- // SighashType is an empty key ({0x03}).
- //
- // The value contains the 32-bit unsigned integer specifying the
- // sighash type to be used for this input. Signatures for this input
- // must use the sighash type, finalizers must fail to finalize inputs
- // which have signatures that do not match the specified sighash type.
- // Signers who cannot produce signatures with the sighash type must not
- // provide a signature.
- SighashType InputType = 3
-
- // RedeemScriptInputType is an empty key ({0x40}).
- //
- // The value is the redeem script of the input if present.
- RedeemScriptInputType InputType = 4
-
- // WitnessScriptInputType is an empty key ({0x05}).
- //
- // The value is the witness script of this input, if it has one.
- WitnessScriptInputType InputType = 5
-
- // Bip32DerivationInputType is a type that carries the pubkey along
- // with the key ({0x06}|{public key}).
- //
- // The value is master key fingerprint as defined by BIP 32
- // concatenated with the derivation path of the public key. The
- // derivation path is represented as 32 bit unsigned integer indexes
- // concatenated with each other. Public keys are those that will be
- // needed to sign this input.
- Bip32DerivationInputType InputType = 6
-
- // FinalScriptSigType is an empty key ({0x07}).
- //
- // The value contains a fully constructed scriptSig with signatures and
- // any other scripts necessary for the input to pass validation.
- FinalScriptSigType InputType = 7
-
- // FinalScriptWitnessType is an empty key ({0x08}). The value is a
- // fully constructed scriptWitness with signatures and any other
- // scripts necessary for the input to pass validation.
- FinalScriptWitnessType InputType = 8
-
- // TaprootKeySpendSignatureType is an empty key ({0x13}). The value is
- // a 64-byte Schnorr signature or a 65-byte Schnorr signature with the
- // one byte sighash type appended to it.
- TaprootKeySpendSignatureType InputType = 0x13
-
- // TaprootScriptSpendSignatureType is a type that carries the
- // x-only pubkey and leaf hash along with the key
- // ({0x14}|{xonlypubkey}|{leafhash}).
- //
- // The value is a 64-byte Schnorr signature or a 65-byte Schnorr
- // signature with the one byte sighash type appended to it.
- TaprootScriptSpendSignatureType InputType = 0x14
-
- // TaprootLeafScriptType is a type that carries the control block along
- // with the key ({0x15}|{control block}).
- //
- // The value is a script followed by a one byte unsigned integer that
- // represents the leaf version.
- TaprootLeafScriptType InputType = 0x15
-
- // TaprootBip32DerivationInputType is a type that carries the x-only
- // pubkey along with the key ({0x16}|{xonlypubkey}).
- //
- // The value is a compact integer denoting the number of hashes,
- // followed by said number of 32-byte leaf hashes. The rest of the value
- // is then identical to the Bip32DerivationInputType value.
- TaprootBip32DerivationInputType InputType = 0x16
-
- // TaprootInternalKeyInputType is an empty key ({0x17}). The value is
- // an x-only pubkey denoting the internal public key used for
- // constructing a taproot key.
- TaprootInternalKeyInputType InputType = 0x17
-
- // TaprootMerkleRootType is an empty key ({0x18}). The value is a
- // 32-byte hash denoting the root hash of a merkle tree of scripts.
- TaprootMerkleRootType InputType = 0x18
-
- // ProprietaryInputType is a custom type for use by devs.
- //
- // The key ({0xFC}|<prefix>|{subtype}|{key data}), is a Variable length
- // identifier prefix, followed by a subtype, followed by the key data
- // itself.
- //
- // The value is any value data as defined by the proprietary type user.
- ProprietaryInputType InputType = 0xFC
-)
-
-// OutputType is the set of types defined per output within the PSBT.
-type OutputType uint32
-
-const (
- // RedeemScriptOutputType is an empty key ({0x00}>
- //
- // The value is the redeemScript for this output if it has one.
- RedeemScriptOutputType OutputType = 0
-
- // WitnessScriptOutputType is an empty key ({0x01}).
- //
- // The value is the witness script of this input, if it has one.
- WitnessScriptOutputType OutputType = 1
-
- // Bip32DerivationOutputType is used to communicate derivation information
- // needed to spend this output. The key is ({0x02}|{public key}).
- //
- // The value is master key fingerprint concatenated with the derivation
- // path of the public key. The derivation path is represented as 32-bit
- // little endian unsigned integer indexes concatenated with each other.
- // Public keys are those needed to spend this output.
- Bip32DerivationOutputType OutputType = 2
-
- // TaprootInternalKeyOutputType is an empty key ({0x05}). The value is
- // an x-only pubkey denoting the internal public key used for
- // constructing a taproot key.
- TaprootInternalKeyOutputType OutputType = 5
-
- // TaprootTapTreeType is an empty key ({0x06}). The value is a
- // serialized taproot tree.
- TaprootTapTreeType OutputType = 6
-
- // TaprootBip32DerivationOutputType is a type that carries the x-only
- // pubkey along with the key ({0x07}|{xonlypubkey}).
- //
- // The value is a compact integer denoting the number of hashes,
- // followed by said number of 32-byte leaf hashes. The rest of the value
- // is then identical to the Bip32DerivationInputType value.
- TaprootBip32DerivationOutputType OutputType = 7
-)
diff --git a/btcutil/psbt/updater.go b/btcutil/psbt/updater.go
deleted file mode 100644
index 26329f8..0000000
--- a/btcutil/psbt/updater.go
+++ /dev/null
@@ -1,377 +0,0 @@
-// Copyright (c) 2018 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package psbt
-
-// The Updater requires provision of a single PSBT and is able to add data to
-// both input and output sections. It can be called repeatedly to add more
-// data. It also allows addition of signatures via the addPartialSignature
-// function; this is called internally to the package in the Sign() function of
-// Updater, located in signer.go
-
-import (
- "bytes"
- "crypto/sha256"
-
- "github.com/btcsuite/btcd/txscript/v2"
- "github.com/btcsuite/btcd/wire/v2"
- "github.com/btcsuite/btcutil/v2"
-)
-
-// Updater encapsulatWhy this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.