I want to create a PSBT transaction.
But get the error when to call sendrawtransaction method.
I used Golang package: github.com/btcsuite/btcd
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
}