I've encouraged an error broadcasting my bitcoin transaction here.
Error validating transaction: Error running script for input 0 referencing 78b6df775e4132f747d8d15909cfe61834e6ff1d3b1e42219ace64aae7151e18 at 0: Script was NOT verified successfully..
I've tried to put decoded Asm PkScript instead of PubKey in TxIn. I've tried to find similar error on sof but their steps didn't work for me. Can anyone find out what is wrong with this tx? because my vm didn't find any troubles.
Hex transaction:
0100000001181e15e7aa64ce9a21421e3b1dffe63418e6cf0959d1d847f732415e77dfb678000000008a47304402200aa339f80c705a22180c8edd4acc4baa5bc76c9e8f64852eb3cb507f027aee9c02206da34700e76df568ef018fe346bb5b9c4484506ee84740916d6c3b454c2e1d3f0141042a1b4d9533ff37cd290b95016056cacbdbbf99b5975345dc5837a95f698f8a26d74f726e2a1e62552107953595502c8078a84311690c61ace3f22644ae33a0abffffffff02d0070000000000001976a91437383464376cccaf2ae4c8a121805f45bf544e4488acc8320000000000001976a914a404271e971d58240add530813e514b0ffe45f3588ac00000000
Decoded transaction:
{
"addresses": [
"mvUC64ETwYLbTjH38ZVigDwMBtCS9TbuT1",
"mkYvnmm3KUBkvVqUAYsG6A6amt5Dva4jzX"
],
"block_height": -1,
"block_index": -1,
"confirmations": 0,
"double_spend": false,
"fees": 5000,
"hash": "410f8119e9c225fc197a21ede7f9e6902f85a36010a2776dd3fdc2663072a36c",
"inputs": [
{
"addresses": [
"mvUC64ETwYLbTjH38ZVigDwMBtCS9TbuT1"
],
"age": 2345496,
"output_index": 0,
"output_value": 20000,
"prev_hash": "78b6df775e4132f747d8d15909cfe61834e6ff1d3b1e42219ace64aae7151e18",
"script": "47304402200aa339f80c705a22180c8edd4acc4baa5bc76c9e8f64852eb3cb507f027aee9c02206da34700e76df568ef018fe346bb5b9c4484506ee84740916d6c3b454c2e1d3f0141042a1b4d9533ff37cd290b95016056cacbdbbf99b5975345dc5837a95f698f8a26d74f726e2a1e62552107953595502c8078a84311690c61ace3f22644ae33a0ab",
"script_type": "pay-to-pubkey-hash",
"sequence": 4294967295
}
],
"outputs": [
{
"addresses": [
"mkYvnmm3KUBkvVqUAYsG6A6amt5Dva4jzX"
],
"script": "76a91437383464376cccaf2ae4c8a121805f45bf544e4488ac",
"script_type": "pay-to-pubkey-hash",
"value": 2000
},
{
"addresses": [
"mvUC64ETwYLbTjH38ZVigDwMBtCS9TbuT1"
],
"script": "76a914a404271e971d58240add530813e514b0ffe45f3588ac",
"script_type": "pay-to-pubkey-hash",
"value": 13000
}
],
"preference": "low",
"received": "2022-09-06T14:10:50.749940874Z",
"relayed_by": "44.204.10.232",
"size": 257,
"total": 15000,
"ver": 1,
"vin_sz": 1,
"vout_sz": 2,
"vsize": 257
}
func main() {
connCfg := &rpcclient.ConnConfig{ //smth here
}
client, err := rpcclient.New(connCfg, nil)
if err != nil {
log.Fatal(err)
}
defer client.Shutdown()
utxoMap := make(map[string]string)
utxoMap["mvUC64ETwYLbTjH38ZVigDwMBtCS9TbuT1"] = "78b6df775e4132f747d8d15909cfe61834e6ff1d3b1e42219ace64aae7151e18"
rawTx, err := CreateRawTx("mvUC64ETwYLbTjH38ZVigDwMBtCS9TbuT1", "mkYvnmm3KUBkvVqUAYsG6A6amt5Dva4jzX", 2000, utxoMap, client)
if err != nil {
println(err.Error())
}
signedTx, err := Sign(rawTx, "private key here")
if err != nil {
println(err.Error())
}
fmt.Println(signedTx)
}
type UTXO struct {
previousTxID string
pubKeyScript string
Asm string
Amount decimal.Decimal
}
func GetUTXO(utxoMap map[string]string, address string, client *rpcclient.Client) (utxo UTXO, err error) {
// unmarshal it, and extract necessary data
hash, _ := chainhash.NewHashFromStr(utxoMap[address])
tx, err := client.GetRawTransactionVerbose(hash)
if err != nil {
return utxo, errors.Wrapf(err, "GetUTXO.GetRawTransactionVerbose")
}
pubKeyScript := tx.Vout[0].ScriptPubKey.Hex
previousTxID := utxoMap[address]
amount := decimal.NewFromFloat(tx.Vout[0].Value)
asm := tx.Vout[0].ScriptPubKey.Hex
return UTXO{
previousTxID: previousTxID,
pubKeyScript: pubKeyScript,
Asm: asm,
Amount: amount,
}, nil
}
func GetPayToAddrScript(address string) []byte {
rcvAddress, _ := btcutil.DecodeAddress(address, &chaincfg.TestNet3Params)
rcvScript, _ := txscript.PayToAddrScript(rcvAddress)
return rcvScript
}
type TXRef struct {
TXHash string
TXOutputN int
}
// get private key
func getKeyAddressFromPrivateKey(privateKey string, conf *chaincfg.Params) (*btcec.PrivateKey, string, error) {
newWif, err := btcutil.DecodeWIF(privateKey)
if err != nil {
return nil, "", err
}
publicKey := newWif.PrivKey.PubKey().SerializeUncompressed()
address, err := btcutil.NewAddressPubKeyHash(btcutil.Hash160(publicKey), conf)
if err != nil {
return nil, "", err
}
return newWif.PrivKey, address.EncodeAddress(), nil
}
// debug signing function
func Sign(rawTx, privateKey string) (string, error) {
var signTx wire.MsgTx
err := json.Unmarshal([]byte(rawTx), &signTx)
if err != nil {
return "", err
}
myPrivateKey, address, err := getKeyAddressFromPrivateKey(privateKey, &chaincfg.TestNet3Params)
fmt.Println("address ", address)
if err != nil {
return "", err
}
txScript := GetPayToAddrScript(address)
for i := 0; i < len(signTx.TxIn); i++ {
sig, err := txscript.SignatureScript(
&signTx, // The tx to be signed.
i, // The index of the txin the signature is for.
txScript, // The other half of the script from the PubKeyHash.
txscript.SigHashAll, // The signature flags that indicate what the sig covers.
myPrivateKey, // The key to generate the signature with.
false) // The compress sig flag. This saves space on the blockchain.
if err != nil {
return "", err
}
//refer from this link for sign multiple inputs https://bitcoin.stackexchange.com/questions/41209/how-to-sign-a-transaction-with-multiple-inputs
signTx.TxIn[i].SignatureScript = sig
//Validate signature
flags := txscript.StandardVerifyFlags
vm, err := txscript.NewEngine(txScript, &signTx, i, flags, nil, nil, signTx.TxOut[0].Value, nil)
if err != nil {
return "", err
}
if err := vm.Execute(); err != nil {
return "", err
}
}
// return signed tx
var signedTx bytes.Buffer
signTx.Serialize(&signedTx)
hexSignedTx := hex.EncodeToString(signedTx.Bytes())
return hexSignedTx, nil
}
// CreateBtcRawTx create raw tx for sending btc
func CreateRawTx(from string, to string, amount int64, utxoMap map[string]string, client *rpcclient.Client) (string, error) {
amountInt := amount
var feeBitcoin int64 = 5000
spendAmount := amountInt + feeBitcoin
utxo, err := GetUTXO(utxoMap, from, client)
changeAmount := utxo.Amount.Shift(8).IntPart() - spendAmount
// create new empty transaction
redemTx := wire.NewMsgTx(wire.TxVersion)
// create multiple txIns
hash, err := chainhash.NewHashFromStr(utxo.previousTxID)
if err != nil {
fmt.Printf("could not get hash from transaction ID: %v", err)
return "", err
}
outPoint := wire.NewOutPoint(hash, 0)
txIn := wire.NewTxIn(outPoint, nil, nil)
redemTx.AddTxIn(txIn)
// create TxOut
rcvScript := GetPayToAddrScript(to)
txOut := wire.NewTxOut(amountInt, rcvScript)
redemTx.AddTxOut(txOut)
// create TxOut for change address, in this case, change address is sender itself
if changeAmount > 0 {
// return change BTC to its own address
rcvChangeAddressScript := GetPayToAddrScript(from)
txOut := wire.NewTxOut(changeAmount, rcvChangeAddressScript)
redemTx.AddTxOut(txOut)
}
encodedTx, err := json.Marshal(redemTx)
if err != nil {
return "", err
}
// return raw tx in hex format
return string(encodedTx), nil
}
my bitcoin wallet: mvUC64ETwYLbTjH38ZVigDwMBtCS9TbuT1
last transaction on the wallet (hash): 78b6df775e4132f747d8d15909cfe61834e6ff1d3b1e42219ace64aae7151e18