Closed yplong closed 10 months ago
How do I sign when I enter multiple input signatures? I made the following attempts:
- When I tried to adjust the number of signatures, an error {"code":-26,"message":" non-mandatory-script-verification-flag (Invalid Schnorr signature)"} was reported,
- If I only sign once, {"code":-22,"message":"TX decode failed. Make sure the tx has at least one input."} This error is reported.
- I adjusted the sighash GetTransactionTaprootDigest method the value of the parameter, SignTaprootTransaction sighash parameters value, or will be signed at the wrong mistake
// Private key of the UTXO owner privateKey, _ := keypair.NewECPrivateFromWIF("91qdf1RH6UMZwZTnHUJ3RSiGSZ5EAxvW2FgYFV2HeaLnqZQh4zx") // privateKey, _ := keypair.NewECPrivateFromWIF("cUUUyKDSNuDFtAt8deeSHxjHY5p7M9mvBfp32EFxz62H91WFiX9J") // Address we want to spend from fromAddr := privateKey.GetPublic().ToTaprootAddress() // Create an input // Insert transaction ID and index of UTXO sigTxin1 := scripts.NewTxInput("0924c8ad1b635f7edfb77321f43ba868ae4d71b9976d639fa6a582b4a7bc4714", 0) //500 sigTxin2 := scripts.NewTxInput("ab03d8f71103ffe1e346ca65635cdad84dcd658e58c3b3ddd529f777c57ec848", 1) //1000 // Address we want to send funds to // addr, _ := btcAddress.P2PKHAddressFromAddress("n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR") addr, _ := btcAddress.P2TRAddressFromAddress("tb1pnztcay5kzpyxcfhfmpth4f32re964zupd3k2f8g53rmcnp9kyz9qjukvm2") // Create an output: Send 3000 to `n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR` txout := scripts.NewTxOutput( big.NewInt(500), addr.ToScriptPubKey(), ) changeOut := scripts.NewTxOutput( big.NewInt(100), fromAddr.ToScriptPubKey(), ) // Create a transaction tx := scripts.NewBtcTransaction( []*scripts.TxInput{sigTxin1, sigTxin2}, []*scripts.TxOutput{txout, changeOut}, // []*scripts.TxOutput{txout}, true, // The transaction contains one or more segwit UTXOs ) // Get the transaction digest for signing input at index 0 // Arguments: // - Index 0 // - The scriptPubkeys that correspond to all the inputs/UTXOs // - The amounts that correspond to all the inputs/UTXOs // - Ext_flag: Extension mechanism, default is 0; 1 is for script spending (BIP342) // - Script: The script that we are spending when ext_flag is 1 digest := tx.GetTransactionTaprootDigest(0, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(1500)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL) digest2 := tx.GetTransactionTaprootDigest(1, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(1500)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL) // digest := tx.GetTransactionTaprootDigest(0, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(3000)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL) // Sign the transaction // Arguments: // - Transaction digest related to the index // - Signature Hash Type (TAPROOT_SIGHASH_ALL) // - Script path (tapleafs) // - Tweak: Note that we don't use tapleafs script in this transaction, so the tweak should be set to False sig := privateKey.SignTaprootTransaction(digest, constant.TAPROOT_SIGHASH_ALL, []interface{}{}, true) sig2 := privateKey.SignTaprootTransaction(digest2, constant.TAPROOT_SIGHASH_ALL, []interface{}{}, true) // sig := privateKey.SignTaprootTransaction(digest, constant.TAPROOT_SIGHASH_ALL, []interface{}{}, true) // set to tue // Create a witness signature and set it to the transaction at the current index witness := scripts.NewTxWitnessInput(sig) // witnessOut := scripts.NewTxWitness(sig) tx.Witnesses = append(tx.Witnesses, witness) witness2 := scripts.NewTxWitnessInput(sig2) tx.Witnesses = append(tx.Witnesses, witness2) // Transaction ID tx.TxId() // In this case, the transaction is segwit, and we must use GetVSize for transaction size tx.GetVSize() // Transaction digest ready for broadcast digestHex := tx.Serialize() api := provider.SelectApi(provider.MempoolApi, &address.TestnetNetwork) trId, err := api.SendRawTransaction(digestHex) if err != nil { fmt.Println("err:", err) } fmt.Println("trid:", trId)
There are 2 problems in this transaction
1 - This sigTxin1 := scripts.NewTxInput("0924c8ad1b635f7edfb77321f43ba868ae4d71b9976d639fa6a582b4a7bc4714", 0)
has already been spent in transaction 5e2bf9e87ec42cfaf1b3b732e5983bdfaa8c95151b8189b6a773d1c0d304145c
2- If your UTX is P2TR, you must enter all the transaction UTXO,s amounts (not the sum of them), and script pub keys.
in this case, if your selected UTXO's is pt2r
digest := tx.GetTransactionTaprootDigest(0, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(1500)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL)
digest2 := tx.GetTransactionTaprootDigest(1, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(1500)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL)
You need to add all UTXO, pubkey script and amounts to generate transaction summary, like
digest := tx.GetTransactionTaprootDigest(0, []*scripts.Script{fromAddr.ToScriptPubKey(),fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(500),big.NewInt(1000)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL)
digest2 := tx.GetTransactionTaprootDigest(1, []*scripts.Script{fromAddr.ToScriptPubKey(),fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(500),big.NewInt(1000)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL)
I suggest you use the transaction builder, or see its code to understand how it works.
How do I sign when I enter multiple input signatures? I made the following attempts:
- When I tried to adjust the number of signatures, an error {"code":-26,"message":" non-mandatory-script-verification-flag (Invalid Schnorr signature)"} was reported,
- If I only sign once, {"code":-22,"message":"TX decode failed. Make sure the tx has at least one input."} This error is reported.
- I adjusted the sighash GetTransactionTaprootDigest method the value of the parameter, SignTaprootTransaction sighash parameters value, or will be signed at the wrong mistake
// Private key of the UTXO owner privateKey, _ := keypair.NewECPrivateFromWIF("91qdf1RH6UMZwZTnHUJ3RSiGSZ5EAxvW2FgYFV2HeaLnqZQh4zx") // privateKey, _ := keypair.NewECPrivateFromWIF("cUUUyKDSNuDFtAt8deeSHxjHY5p7M9mvBfp32EFxz62H91WFiX9J") // Address we want to spend from fromAddr := privateKey.GetPublic().ToTaprootAddress() // Create an input // Insert transaction ID and index of UTXO sigTxin1 := scripts.NewTxInput("0924c8ad1b635f7edfb77321f43ba868ae4d71b9976d639fa6a582b4a7bc4714", 0) //500 sigTxin2 := scripts.NewTxInput("ab03d8f71103ffe1e346ca65635cdad84dcd658e58c3b3ddd529f777c57ec848", 1) //1000 // Address we want to send funds to // addr, _ := btcAddress.P2PKHAddressFromAddress("n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR") addr, _ := btcAddress.P2TRAddressFromAddress("tb1pnztcay5kzpyxcfhfmpth4f32re964zupd3k2f8g53rmcnp9kyz9qjukvm2") // Create an output: Send 3000 to `n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR` txout := scripts.NewTxOutput( big.NewInt(500), addr.ToScriptPubKey(), ) changeOut := scripts.NewTxOutput( big.NewInt(100), fromAddr.ToScriptPubKey(), ) // Create a transaction tx := scripts.NewBtcTransaction( []*scripts.TxInput{sigTxin1, sigTxin2}, []*scripts.TxOutput{txout, changeOut}, // []*scripts.TxOutput{txout}, true, // The transaction contains one or more segwit UTXOs ) // Get the transaction digest for signing input at index 0 // Arguments: // - Index 0 // - The scriptPubkeys that correspond to all the inputs/UTXOs // - The amounts that correspond to all the inputs/UTXOs // - Ext_flag: Extension mechanism, default is 0; 1 is for script spending (BIP342) // - Script: The script that we are spending when ext_flag is 1 digest := tx.GetTransactionTaprootDigest(0, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(1500)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL) digest2 := tx.GetTransactionTaprootDigest(1, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(1500)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL) // digest := tx.GetTransactionTaprootDigest(0, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(3000)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL) // Sign the transaction // Arguments: // - Transaction digest related to the index // - Signature Hash Type (TAPROOT_SIGHASH_ALL) // - Script path (tapleafs) // - Tweak: Note that we don't use tapleafs script in this transaction, so the tweak should be set to False sig := privateKey.SignTaprootTransaction(digest, constant.TAPROOT_SIGHASH_ALL, []interface{}{}, true) sig2 := privateKey.SignTaprootTransaction(digest2, constant.TAPROOT_SIGHASH_ALL, []interface{}{}, true) // sig := privateKey.SignTaprootTransaction(digest, constant.TAPROOT_SIGHASH_ALL, []interface{}{}, true) // set to tue // Create a witness signature and set it to the transaction at the current index witness := scripts.NewTxWitnessInput(sig) // witnessOut := scripts.NewTxWitness(sig) tx.Witnesses = append(tx.Witnesses, witness) witness2 := scripts.NewTxWitnessInput(sig2) tx.Witnesses = append(tx.Witnesses, witness2) // Transaction ID tx.TxId() // In this case, the transaction is segwit, and we must use GetVSize for transaction size tx.GetVSize() // Transaction digest ready for broadcast digestHex := tx.Serialize() api := provider.SelectApi(provider.MempoolApi, &address.TestnetNetwork) trId, err := api.SendRawTransaction(digestHex) if err != nil { fmt.Println("err:", err) } fmt.Println("trid:", trId)
There are 2 problems in this transaction 1 - This
sigTxin1 := scripts.NewTxInput("0924c8ad1b635f7edfb77321f43ba868ae4d71b9976d639fa6a582b4a7bc4714", 0)
has already been spent in transaction5e2bf9e87ec42cfaf1b3b732e5983bdfaa8c95151b8189b6a773d1c0d304145c
2- If your UTX is P2TR, you must enter all the transaction UTXO,s amounts (not the sum of them), and script pub keys. in this case, if your selected UTXO's is pt2rdigest := tx.GetTransactionTaprootDigest(0, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(1500)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL) digest2 := tx.GetTransactionTaprootDigest(1, []*scripts.Script{fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(1500)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL)
You need to add all UTXO, pubkey script and amounts to generate transaction summary, like
digest := tx.GetTransactionTaprootDigest(0, []*scripts.Script{fromAddr.ToScriptPubKey(),fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(500),big.NewInt(1000)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL) digest2 := tx.GetTransactionTaprootDigest(1, []*scripts.Script{fromAddr.ToScriptPubKey(),fromAddr.ToScriptPubKey()}, []*big.Int{big.NewInt(500),big.NewInt(1000)}, 0, scripts.NewScript(), constant.TAPROOT_SIGHASH_ALL)
I suggest you use the transaction builder, or see its code to understand how it works.
That's it. Thank you very much
How do I sign when I enter multiple input signatures? I made the following attempts: