-1

I want to create a PSBT transaction. But get the error when to call sendrawtransaction method.

I used Golang package: github.com/btcsuite/btcd

This is my code: enter image description here PSBT inputs

enter image description here PSBT outputs

Then I passed them to the function.

func GenerateSignedOwnerTx(ins []*TxInput, outs []*TxOutput, network *chaincfg.Params) (string, error) {
var inputs []*wire.OutPoint
var nSequences []uint32
prevOuts := make(map[wire.OutPoint]*wire.TxOut)
for _, in := range ins {
    var prevOut *wire.OutPoint
    txHash, err := chainhash.NewHashFromStr(in.TxId)
    if err != nil {
        panic(err)
    }
    prevOut = wire.NewOutPoint(txHash, in.VOut)
    inputs = append(inputs, prevOut)

    prevPkScript, err := AddrToPkScript(in.Address, network)
    if err != nil {
        panic(err)
    }
    witnessUtxo := wire.NewTxOut(in.Amount, prevPkScript)
    prevOuts[*prevOut] = witnessUtxo

    nSequences = append(nSequences, wire.MaxTxInSequenceNum)
}

var outputs []*wire.TxOut
for _, out := range outs {
    pkScript, err := AddrToPkScript(out.Address, network)
    if err != nil {
        panic(err)
    }
    outputs = append(outputs, wire.NewTxOut(out.Amount, pkScript))
}

bp, err := psbt.New(inputs, outputs, int32(2), uint32(0), nSequences)
if err != nil {
    panic(err)
}

updater, err := psbt.NewUpdater(bp)
if err != nil {
    panic(err)
}

prevOutputFetcher := txscript.NewMultiPrevOutFetcher(prevOuts)

for i, in := range ins {

    if err = signInput(updater, i, in, prevOutputFetcher, txscript.SigHashAll, network); err != nil {
        panic(err)
    }

    if err = psbt.Finalize(bp, i); err != nil {
        panic(err)
    }
}

fmt.Println("signed bp base64 encode:")
fmt.Println(bp.B64Encode())
if err = psbt.MaybeFinalizeAll(bp); err != nil {
    return "", err
}

buyerSignedTx, err := psbt.Extract(bp)
if err != nil {
    return "", err
}

var buf bytes.Buffer
if err := buyerSignedTx.Serialize(&buf); err != nil {
    return "", err
}

return hex.EncodeToString(buf.Bytes()), nil}

This is sign function.

func signInput(updater *psbt.Updater, i int, in *TxInput, prevOutFetcher *txscript.MultiPrevOutFetcher, hashType txscript.SigHashType, network *chaincfg.Params) error {
wif, err := btcutil.DecodeWIF(in.PrivateKey)
if err != nil && i != 1 {
    panic(err)
}
privKey := wif.PrivKey

prevPkScript, err := AddrToPkScript(in.Address, network)
if err != nil {
    panic(err)
}
if txscript.IsPayToPubKeyHash(prevPkScript) {
    prevTx := wire.NewMsgTx(2)
    txBytes, err := hex.DecodeString(in.NonWitnessUtxo)
    if err != nil {
        panic(err)
    }
    if err = prevTx.Deserialize(bytes.NewReader(txBytes)); err != nil {
        panic(err)
    }
    if err = updater.AddInNonWitnessUtxo(prevTx, i); err != nil {
        panic(err)
    }
} else {
    witnessUtxo := wire.NewTxOut(in.Amount, prevPkScript)
    if err = updater.AddInWitnessUtxo(witnessUtxo, i); err != nil {
        panic(err)
    }
}

if err = updater.AddInSighashType(hashType, i); err != nil {
    panic(err)
}

if txscript.IsPayToTaproot(prevPkScript) {
    internalPubKey := schnorr.SerializePubKey(privKey.PubKey())
    updater.Upsbt.Inputs[i].TaprootInternalKey = internalPubKey

    sigHashes := txscript.NewTxSigHashes(updater.Upsbt.UnsignedTx, prevOutFetcher)
    if hashType == txscript.SigHashAll {
        hashType = txscript.SigHashDefault
    }
    witness, err := txscript.TaprootWitnessSignature(updater.Upsbt.UnsignedTx, sigHashes,
        i, in.Amount, prevPkScript, hashType, privKey)
    if err != nil {
        panic(err)
    }

    updater.Upsbt.Inputs[i].TaprootKeySpendSig = witness[0]
} else if txscript.IsPayToPubKeyHash(prevPkScript) {
    signature, err := txscript.RawTxInSignature(updater.Upsbt.UnsignedTx, i, prevPkScript, hashType, privKey)
    if err != nil {
        panic(err)
    }

    if _, err := updater.Sign(i, signature, privKey.PubKey().SerializeCompressed(), nil, nil); err != nil {
        panic(err)
    }
} else {
    pubKeyBytes := privKey.PubKey().SerializeCompressed()
    sigHashes := txscript.NewTxSigHashes(updater.Upsbt.UnsignedTx, prevOutFetcher)

    script, err := PayToPubKeyHashScript(btcutil.Hash160(pubKeyBytes))
    if err != nil {
        panic(err)
    }
    signature, err := txscript.RawTxInWitnessSignature(updater.Upsbt.UnsignedTx, sigHashes, i, in.Amount, script, hashType, privKey)
    if err != nil {
        panic(err)
    }

    if txscript.IsPayToScriptHash(prevPkScript) {
        redeemScript, err := PayToWitnessPubKeyHashScript(btcutil.Hash160(pubKeyBytes))
        if err != nil {
            panic(err)
        }
        err = updater.AddInRedeemScript(redeemScript, i)
        if err != nil {
            panic(err)
        }
    }

    if _, err := updater.Sign(i, signature, pubKeyBytes, nil, nil); err != nil {
        panic(err)
    }
}
return nil

}

3
  • Does the output you are trying to spend actually exist? I cannot find the txid on any block explorers for mainnet, testnet, or signet. The error you get is a generic error for any transaction where the node cannot find the output being spent, and is unrelated to PSBTs.
    – Ava Chow
    Feb 7 at 19:20
  • Yes, I found them at the following link: blockstream.info/testnet/tx/… blockstream.info/testnet/tx/… I think they should exist.
    – MarkTangCd
    Feb 8 at 1:17
  • The vout isn't correct. I have updated them and send the transaction again. but I get a new error. non-mandatory-script-verify-flag (Invalid Schnorr signature)
    – MarkTangCd
    Feb 8 at 14:49

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.