Golang实现比特币交易广播失败,Script验证错误求助
比特币测试网交易广播脚本验证失败问题
在比特币测试网广播交易时遭遇脚本验证失败,错误信息如下:
Error validating transaction: Error running script for input 0 referencing 78b6df775e4132f747d8d15909cfe61834e6ff1d3b1e42219ace64aae7151e18 at 0: Script was NOT verified successfully..
已尝试在TxIn中使用解码后的Asm PkScript替代PubKey,也查阅过Stack Overflow上的同类问题解决方案,但均未解决问题。本地虚拟机未检测到交易存在异常,现寻求帮助排查该交易的问题所在。
交易十六进制数据
0100000001181e15e7aa64ce9a21421e3b1dffe63418e6cf0959d1d847f732415e77dfb678000000008a47304402200aa339f80c705a22180c8edd4acc4baa5bc76c9e8f64852eb3cb507f027aee9c02206da34700e76df568ef018fe346bb5b9c4484506ee84740916d6c3b454c2e1d3f0141042a1b4d9533ff37cd290b95016056cacbdbbf99b5975345dc5837a95f698f8a26d74f726e2a1e62552107953595502c8078a84311690c61ace3f22644ae33a0abffffffff02d0070000000000001976a91437383464376cccaf2ae4c8a121805f45bf544e4488acc8320000000000001976a914a404271e971d58240add530813e514b0ffe45f3588ac00000000
解码后的交易信息
{ "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 }
相关Golang代码
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 } 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 }
补充信息
- 钱包地址:
mvUC64ETwYLbTjH38ZVigDwMBtCS9TbuT1 - 关联UTXO交易哈希:
78b6df775e4132f747d8d15909cfe61834e6ff1d3b1e42219ace64aae7151e18
内容的提问来源于stack exchange,提问作者JkLondon
相关产品推荐
相关产品推荐

