Closed phanquocky closed 1 year ago
witness, err := txscript.WitnessSignature(rawTx, sigHashes, 0, rawTx.TxOut[0].Value, []byte(unspents[0].ScriptPubKey), txscript.SigHashAll, privKey.PrivKey, true)
The rawTx.TxOut[0].Value
is wrong. This needs to be the input value (so unspents[0].Value
).
I have changed the code to:
witness, err := txscript.WitnessSignature(rawTx, sigHashes, 0, int64(unspents[0].Amount), []byte(unspents[0].ScriptPubKey), txscript.SigHashAll, privKey.PrivKey, true)
but I also get same error:
2023/05/31 14:41:07 intputs [{81ca4185a877ff4aefa11b52a3b8865524ad044a8e3422580f2ecbd4cfd402a1 1}]
2023/05/31 14:41:07 amounts map[mhzsEj6fpWmkyi2xwBnb1CeKzEWxLrLU6g:0.004 BTC]
2023/05/31 14:41:07 tx {1 [0xc0002a64e0] [0xc00002cf40] 0}
2023/05/31 14:41:07 Private Key: &{0525753a322636e0be1435d59b2a74b9ce746cb62c03327517136288a1f9f568}
2023/05/31 14:41:07 witness: [[48 69 2 33 0 174 192 136 224 161 227 210 73 250 200 186 136 103 243 33 57 182 93 170 236 138 74 162 41 126 65 5 100 240 181 100 169 2 32 41 99 4 243 148 45 49 56 62 49 177 102 149 112 179 7 9 47 172 118 79 210 10 22 194 60 161 212 43 61 142 233 1] [3 184 138 186 135 21 69 153 124 186 25 37 5 225 65 86 255 143 222 187 163 102 34 77 202 196 123 184 113 155 220 119 130]]
2023/05/31 14:41:07 -25: TX rejected: failed to validate input 1b3be042f83763b778a4813ce82ec99c01280ab49c2b2af23cc121bf4a184cb7:0 which references output 81ca4185a877ff4aefa11b52a3b8865524ad044a8e3422580f2ecbd4cfd402a1:1 - signature not empty on failed checksig (input witness [3045022100aec088e0a1e3d249fac8ba8867f32139b65daaec8a4aa2297e410564f0b564a90220296304f3942d31383e31b1669570b307092fac764fd20a16c23ca1d42b3d8ee901 03b88aba871545997cba192505e14156ff8fdebba366224dcac47bb8719bdc7782], input script bytes , prev output script bytes 0014cccedddcb93a4dedbcdf2a051f7aaead5312bb18)
2023/05/31 14:41:07 hashtx
What's the value of []byte(unspents[0].ScriptPubKey)
? I think that might need to be hex decoded instead of just cast to a byte slice (everywhere it's used).
the value of unspents[0].ScriptPubKey is string: 0014cccedddcb93a4dedbcdf2a051f7aaead5312bb18 the value of []byte(unspents[0].ScriptPubKey) is : [48 48 49 52 99 99 99 101 100 100 100 99 98 57 51 97 52 100 101 100 98 99 100 102 50 97 48 53 49 102 55 97 97 101 97 100 53 51 49 50 98 98 49 56]
I have replaced all of the []byte(unspents[0].ScriptPubKey) to scriptPubkeyUnspent, _ := hex.DecodeString(unspents[0].ScriptPubKey). But I also got the same error
Can you post the full code as it looks now? Please use triple back ticks to format (or the UI elements of GitHub).
Oh sorry about the format of the code:
package main
import (
"encoding/hex"
"fmt"
"io/ioutil"
"log"
"math"
"path/filepath"
"time"
"github.com/btcsuite/btcd/btcjson"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/txscript"
)
func main() {
ntfnHandlers := rpcclient.NotificationHandlers{
OnAccountBalance: func(account string, balance btcutil.Amount, confirmed bool) {
log.Printf("New balance for account %s: %v", account,
balance)
},
}
// Connect to local btcwallet RPC server using websockets.
certHomeDir := btcutil.AppDataDir("btcwallet", false)
certs, err := ioutil.ReadFile(filepath.Join(certHomeDir, "rpc.cert"))
if err != nil {
log.Fatal(err)
}
connCfg := &rpcclient.ConnConfig{
Host: "localhost:18332",
Endpoint: "ws",
User: "eeyHzXbqKIxOrZquE5c9POR/8mI=",
Pass: "q7pfGKtXrHE95qpS3oFGdAiAAXM=",
Certificates: certs,
Params: "testnet3",
}
client, err := rpcclient.New(connCfg, &ntfnHandlers)
if err != nil {
log.Fatal(err)
}
// want spend 0.004 btc
btcAmount := btcutil.Amount(400000)
unspents, err := client.ListUnspent()
if err != nil {
log.Println("Cannot listUnspent")
}
inputs := make([]btcjson.TransactionInput, 0)
inputs = append(inputs, btcjson.TransactionInput{Txid: unspents[0].TxID, Vout: unspents[0].Vout})
// send coin to this address
destinationAddress, err := btcutil.DecodeAddress("mhzsEj6fpWmkyi2xwBnb1CeKzEWxLrLU6g", &chaincfg.TestNet3Params)
if err != nil {
log.Println("Your address is not valid")
}
amounts := make(map[btcutil.Address]btcutil.Amount)
amounts[destinationAddress] = btcAmount
var locktime int64 = 0
log.Println("intputs", inputs)
log.Println("amounts", amounts)
rawTx, err := client.CreateRawTransaction(inputs, amounts, &locktime)
if err != nil {
log.Println("Can't create raw transaction")
}
log.Println("tx", *rawTx)
err = client.WalletPassphrase("161002", 100)
if err != nil {
log.Println("Cannot unlock wallet with passphrase")
}
scriptPubkeyUnspent, _ := hex.DecodeString(unspents[0].ScriptPubKey)
fetcher := txscript.NewCannedPrevOutputFetcher(scriptPubkeyUnspent, int64(unspents[0].Amount))
sigHashes := txscript.NewTxSigHashes(rawTx, fetcher)
address, err := btcutil.DecodeAddress(unspents[0].Address, &chaincfg.TestNet3Params)
if err != nil {
log.Println("Cannot address")
}
privKey, err := client.DumpPrivKey(address)
if err != nil {
log.Println("Cannot Privkey")
}
log.Println("Private Key:", privKey.PrivKey)
log.Println("unspents[0].ScriptPubKey", unspents[0].ScriptPubKey)
witness, err := txscript.WitnessSignature(rawTx, sigHashes, 0, int64(unspents[0].Amount), scriptPubkeyUnspent, txscript.SigHashAll, privKey.PrivKey, true)
if err != nil {
log.Println("Cannot witness")
log.Println(err)
}
log.Println("witness: ", witness)
rawTx.TxIn[0].Witness = witness
hashTx, err := client.SendRawTransaction(rawTx, true)
if err != nil {
log.Println(err)
}
log.Println("hashtx", hashTx)
time.AfterFunc(time.Second*10, func() {
log.Println("Client shutting down...")
client.Shutdown()
log.Println("Client shutdown complete.")
})
// Wait until the client either shuts down gracefully (or the user
// terminates the process with Ctrl+C).
client.WaitForShutdown()
}
The content in the console:
2023/05/31 15:47:11 intputs [{81ca4185a877ff4aefa11b52a3b8865524ad044a8e3422580f2ecbd4cfd402a1 1}]
2023/05/31 15:47:11 amounts map[mhzsEj6fpWmkyi2xwBnb1CeKzEWxLrLU6g:0.004 BTC]
2023/05/31 15:47:11 tx {1 [0xc0000d2060] [0xc000098120] 0}
2023/05/31 15:47:12 Private Key: &{0525753a322636e0be1435d59b2a74b9ce746cb62c03327517136288a1f9f568}
2023/05/31 15:47:12 unspents[0].ScriptPubKey 0014cccedddcb93a4dedbcdf2a051f7aaead5312bb18
2023/05/31 15:47:12 witness: [[48 68 2 32 94 147 219 202 124 167 136 33 12 228 172 255 164 63 59 96 210 250 137 77 13 8 109 9 50 128 86 43 170 214 106 196 2 32 16 120 26 84 172 188 74 56 253 93 121 93 91 251 183 48 88 133 9 205 213 202 188 164 131 139 93 96 66 229 14 87 1] [3 184 138 186 135 21 69 153 124 186 25 37 5 225 65 86 255 143 222 187 163 102 34 77 202 196 123 184 113 155 220 119 130]]
2023/05/31 15:47:12 -25: TX rejected: failed to validate input 1b3be042f83763b778a4813ce82ec99c01280ab49c2b2af23cc121bf4a184cb7:0 which references output 81ca4185a877ff4aefa11b52a3b8865524ad044a8e3422580f2ecbd4cfd402a1:1 - signature not empty on failed checksig (input witness [304402205e93dbca7ca788210ce4acffa43f3b60d2fa894d0d086d093280562baad66ac4022010781a54acbc4a38fd5d795d5bfbb730588509cdd5cabca4838b5d6042e50e5701 03b88aba871545997cba192505e14156ff8fdebba366224dcac47bb8719bdc7782], input script bytes , prev output script bytes 0014cccedddcb93a4dedbcdf2a051f7aaead5312bb18)
2023/05/31 15:47:12 hashtx <nil>
2023/05/31 15:47:22 Client shutting down...
2023/05/31 15:47:22 Client shutdown complete.
And the list of the unspent I have is:
[
{
"txid": "81ca4185a877ff4aefa11b52a3b8865524ad044a8e3422580f2ecbd4cfd402a1",
"vout": 1,
"address": "tb1qen8dmh9e8fx7m0xl9gz3774w44f39wccq86xm6",
"account": "default",
"scriptPubKey": "0014cccedddcb93a4dedbcdf2a051f7aaead5312bb18",
"amount": 0.005,
"confirmations": 1903,
"spendable": true
},
{
"txid": "81ca4185a877ff4aefa11b52a3b8865524ad044a8e3422580f2ecbd4cfd402a1",
"vout": 0,
"address": "mgzwyoP3wwurRGKruLnVTRxkzNMJh53J1Y",
"account": "default",
"scriptPubKey": "76a9141043828f7c914a26a5bcb8a1a36fafcae41a550a88ac",
"amount": 0.00575776,
"confirmations": 1903,
"spendable": true
},
{
"txid": "62bc5ee6179a45445adc01f09ade947955fb31bbeda6583b722f5d4641efe85f",
"vout": 1,
"address": "moioPjJgk4JYnB83UivqxfVMjgrZK6dsAk",
"account": "default",
"scriptPubKey": "76a91459fe9112328ff6fdde80fb03fb5e1a0d2963b3d688ac",
"amount": 0.00000229,
"confirmations": 1994,
"spendable": true
}
]
Hmm, it looks correct. So might be something small now.
Can you add this before client.SendRawTransaction(rawTx, true)
and paste the output here?
var buf bytes.Buffer
_ = rawTx.Serialize(&buf)
fmt.Printf("Raw tx: %x\n", buf.Bytes())
Untested code written from memory, might need slight adjustments, but you get the idea I hope.
sorry for the late reply. I just insert your code to my code i got the hex of the transaction
01000000000101a102d4cfd4cb2e0f5822348e4a04ad245586b8a3521ba1ef4aff77a88541ca810100000000ffffffff01801a0600000000001976a9141b37ad4401250185aeb05249ccd90f84caccab0888ac0247304402205e93dbca7ca788210ce4acffa43f3b60d2fa894d0d086d093280562baad66ac4022010781a54acbc4a38fd5d795d5bfbb730588509cdd5cabca4838b5d6042e50e57012103b88aba871545997cba192505e14156ff8fdebba366224dcac47bb8719bdc778200000000
And I use the command decoderawtransaction
{
"txid": "1b3be042f83763b778a4813ce82ec99c01280ab49c2b2af23cc121bf4a184cb7",
"version": 1,
"locktime": 0,
"vin": [
{
"txid": "81ca4185a877ff4aefa11b52a3b8865524ad044a8e3422580f2ecbd4cfd402a1",
"vout": 1,
"scriptSig": {
"asm": "",
"hex": ""
},
"txinwitness": [
"304402205e93dbca7ca788210ce4acffa43f3b60d2fa894d0d086d093280562baad66ac4022010781a54acbc4a38fd5d795d5bfbb730588509cdd5cabca4838b5d6042e50e5701",
"03b88aba871545997cba192505e14156ff8fdebba366224dcac47bb8719bdc7782"
],
"sequence": 4294967295
}
],
"vout": [
{
"value": 0.004,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 1b37ad4401250185aeb05249ccd90f84caccab08 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9141b37ad4401250185aeb05249ccd90f84caccab0888ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"mhzsEj6fpWmkyi2xwBnb1CeKzEWxLrLU6g"
]
}
}
]
}
I think you might need to set the version of the rawTx
to 2 (before signing), as version 1 is deprecated (and therefore probably not allowed for witness spends).
I have set the version of the rawTx
to 2 but it doesn't work.
But I found the code show error:
in txscript/opcode.go: in function opcodeCheckSig
case !valid && vm.hasFlag(ScriptVerifyNullFail) && len(fullSigBytes) > 0:
str := "signature not empty on failed checksig"
return scriptError(ErrNullFail, str)
}
full function of opcodeChecksig
func opcodeCheckSig(op *opcode, data []byte, vm *Engine) error {
pkBytes, err := vm.dstack.PopByteArray()
if err != nil {
return err
}
fullSigBytes, err := vm.dstack.PopByteArray()
if err != nil {
return err
}
// The signature actually needs needs to be longer than this, but at
// least 1 byte is needed for the hash type below. The full length is
// checked depending on the script flags and upon parsing the signature.
//
// This only applies if tapscript verification isn't active, as this
// check is done within the sighash itself.
if vm.taprootCtx == nil && len(fullSigBytes) < 1 {
vm.dstack.PushBool(false)
return nil
}
var sigVerifier signatureVerifier
switch {
// If no witness program is active, then we're verifying under the
// base consensus rules.
case vm.witnessProgram == nil:
sigVerifier, err = newBaseSigVerifier(
pkBytes, fullSigBytes, vm,
)
if err != nil {
var scriptErr Error
if errors.As(err, &scriptErr) {
return err
}
vm.dstack.PushBool(false)
return nil
}
// If the base segwit version is active, then we'll create the verifier
// that factors in those new consensus rules.
case vm.isWitnessVersionActive(BaseSegwitWitnessVersion):
sigVerifier, err = newBaseSegwitSigVerifier(
pkBytes, fullSigBytes, vm,
)
if err != nil {
var scriptErr Error
if errors.As(err, &scriptErr) {
return err
}
vm.dstack.PushBool(false)
return nil
}
// Otherwise, this is routine tapscript execution.
case vm.taprootCtx != nil:
// Account for changes in the sig ops budget after this
// execution, but only for non-empty signatures.
if len(fullSigBytes) > 0 {
if err := vm.taprootCtx.tallysigOp(); err != nil {
return err
}
}
// Empty public keys immediately cause execution to fail.
if len(pkBytes) == 0 {
return scriptError(ErrTaprootPubkeyIsEmpty, "")
}
// If this is tapscript execution, and the signature was
// actually an empty vector, then we push on an empty vector
// and continue execution from there, but only if the pubkey
// isn't empty.
if len(fullSigBytes) == 0 {
vm.dstack.PushByteArray([]byte{})
return nil
}
// If the constructor fails immediately, then it's because
// the public key size is zero, so we'll fail all script
// execution.
sigVerifier, err = newBaseTapscriptSigVerifier(
pkBytes, fullSigBytes, vm,
)
if err != nil {
return err
}
default:
// We skip segwit v1 in isolation here, as the v1 rules aren't
// used in script execution (for sig verification) and are only
// part of the top-level key-spend verification which we
// already skipped.
//
// In other words, this path shouldn't ever be reached
//
// TODO(roasbeef): return an error?
}
valid := sigVerifier.Verify()
switch {
// For tapscript, and prior execution with null fail active, if the
// signature is invalid, then this MUST be an empty signature.
case !valid && vm.taprootCtx != nil && len(fullSigBytes) != 0:
fallthrough
case !valid && vm.hasFlag(ScriptVerifyNullFail) && len(fullSigBytes) > 0:
str := "signature not empty on failed checksig"
return scriptError(ErrNullFail, str)
}
vm.dstack.PushBool(valid)
return nil
}
I'm not sure what's wrong... I got it working locally with this (not sure what client.CreateRawTransaction()
actually does):
txid, err := chainhash.NewHashFromStr(unspents[0].TxID)
if err != nil {
log.Printf("error parsing hash")
}
utxo := &wire.TxOut{
Value: int64(unspents[0].Amount),
PkScript: scriptPubkeyUnspent,
}
rawTx := &wire.MsgTx{
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: wire.OutPoint{
Hash: *txid,
Index: unspents[0].Vout,
},
}},
TxOut: []*wire.TxOut{{
Value: int64(btcAmount),
PkScript: destinationAddress.ScriptAddress(),
}},
LockTime: 0,
}
fetcher := txscript.NewCannedPrevOutputFetcher(utxo.PkScript, utxo.Value)
sigHashes := txscript.NewTxSigHashes(rawTx, fetcher)
I have a unspents transaction:
I want to spend my first unspent transaction:
But i got error but I don't find any information for this error. If you don't mind, you can help point out what error in this code