From 093ea6fa903db1a9b457c7522a031543d158ab3c Mon Sep 17 00:00:00 2001 From: oxf71 <144757737+oxf71@users.noreply.github.com> Date: Sun, 7 Jan 2024 13:58:51 +0800 Subject: [PATCH] update --- README.md | 23 +++ .../main.go | 5 +- lib/go-ord-tx/pkg/ord/ord.go | 16 +- main.go | 163 ++++++++++++++++++ 4 files changed, 196 insertions(+), 11 deletions(-) rename example/{inscribewithoutnoderpc => taprootmusig}/main.go (96%) diff --git a/README.md b/README.md index aed401c..3a05872 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,29 @@ taproot_tweaked_x_only ``` +## taproot musig2 example + +```shell +➜ musig2-demo git:(main) ✗ go run example/taprootmusig/main.go +utxoTaprootAddress: tb1prggx0jcdqgag2kj9agxa7n6p888ffpzs4flps8ztwctrluz040hq6x9sz8 +musigAddress no script: tb1pegcl5gc8d9smtux47ezk7fa85jk3tu48e0920d3pqrffq8jfc3gs2l0fgy +unspentList: 73a20bf212b60e191ae6808ad921d1080eb28cfe5049b98c4ff9457e4e44fe57:1 +unspentList: 92851308a20a38944728baf496476a568d13131e622f7f34c80729ab2c17b750:0 +musig commitAddress: tb1pz5n2kes9edrgvhuety8n38q55nvxfmdew7e0e76dt93sdc2scunqj96wjz +taproot sign +2024/01/07 13:55:02 recoveryKeyWIF 0 cVPr3q8FLH5GxGUWtFxGspH8zM1ojLaXw3R4asWurXZVA41rn5oD +2024/01/07 13:55:02 commitTxHex 0100000000010257fe444e7e45f94f8cb94950fe8cb20e08d121d98a80e61a190eb612f20ba2730100000000f5ffffff50b7172cab2907c8347f2f621e13138d566a4796f4ba284794380aa2081385920000000000f5ffffff02a40c0000000000002251201526ab6605cb46865f99590f389c14a4d864edb977b2fcfb4d596306e150c72674700f00000000002251201a1067cb0d023a855a45ea0ddf4f4139ce948450aa7e181c4b76163ff04fabee01406b12417046297c390979167972a3dc107dc1dc932dd20d26774ed76cee6489c1a5eb7052c19c270db8baea10ed80b9979430231dded835a420e34dbfb264198f0140451786067ed3692fbdfe29eece6c97a8349fa9b0a3bd8956068fee160394b186535bf9c91a95921dc272c73bbcbd30ed9d19567a9708fc52b299fddc7fa7d37200000000 +2024/01/07 13:55:02 revealTxHex 0 0100000000010159ec22c8f36a62f3c7d3ecea32060d81d751d176e68ce0ef50a49acb870160c90000000000f5ffffff01f4010000000000002251201a1067cb0d023a855a45ea0ddf4f4139ce948450aa7e181c4b76163ff04fabee0340f0013735c53d4ae47698b961b872ab774440fb84faac348d6dad66fea222b0fd566a29dd533d4c55ec2fce910f6ce4398c5a478acf5266d0ef6f98dbb460f05c5f20c3b383df58f16de1f5317cbcff2232dd2e99f79d53cd5777faaf06314d375cb2ac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d38001943726561746520576974686f75742066756c6c204e6f6465206821c1c3b383df58f16de1f5317cbcff2232dd2e99f79d53cd5777faaf06314d375cb200000000 +commitTx json marshal: {"Version":1,"TxIn":[{"PreviousOutPoint":{"Hash":"73a20bf212b60e191ae6808ad921d1080eb28cfe5049b98c4ff9457e4e44fe57","Index":1},"SignatureScript":null,"Witness":["axJBcEYpfDkJeRZ5cqPcEH3B3JMt0g0md07XbO5kicGl63BSwZwnDbi66hDtgLmXlDAjHd7YNaQg402/smQZjw=="],"Sequence":4294967285},{"PreviousOutPoint":{"Hash":"92851308a20a38944728baf496476a568d13131e622f7f34c80729ab2c17b750","Index":0},"SignatureScript":null,"Witness":["RReGBn7TaS+9/inuzmyXqDSfqbCjvYlWBo/uFgOUsYZTW/nJGpWSHcJyxzu8vTDtnRlWepcI/FKymf3cf6fTcg=="],"Sequence":4294967285}],"TxOut":[{"Value":3236,"PkScript":"USAVJqtmBctGhl+ZWQ84nBSk2GTtuXey/PtNWWMG4VDHJg=="},{"Value":1011828,"PkScript":"USAaEGfLDQI6hVpF6g3fT0E5zpSEUKp+GBxLdhY/8E+r7g=="}],"LockTime":0} +revealTx json marshal: [{"Version":1,"TxIn":[{"PreviousOutPoint":{"Hash":"c9600187cb9aa450efe08ce676d151d7810d0632eaecd3c7f3626af3c822ec59","Index":0},"SignatureScript":null,"Witness":["8AE3NcU9SuR2mLlhuHKrd0RA+4T6rDSNba1m/qIisP1WaindUz1MVewvzpEPbOQ5jFpHis9SZtDvb5jbtGDwXA==","IMOzg99Y8W3h9TF8vP8iMt0umfedU81Xd/qvBjFNN1yyrABjA29yZAEBGHRleHQvcGxhaW47Y2hhcnNldD11dGYtOAAZQ3JlYXRlIFdpdGhvdXQgZnVsbCBOb2RlIGg=","wcOzg99Y8W3h9TF8vP8iMt0umfedU81Xd/qvBjFNN1yy"],"Sequence":4294967285}],"TxOut":[{"Value":500,"PkScript":"USAaEGfLDQI6hVpF6g3fT0E5zpSEUKp+GBxLdhY/8E+r7g=="}],"LockTime":0}] +2024/01/07 13:55:02 commitTxHash, c9600187cb9aa450efe08ce676d151d7810d0632eaecd3c7f3626af3c822ec59 +2024/01/07 13:55:02 revealTxHash, 12eee7681ce5e9af5db26a655aeb5849fbbb25a027ae251628c2946fab01214e +2024/01/07 13:55:02 inscription, 12eee7681ce5e9af5db26a655aeb5849fbbb25a027ae251628c2946fab01214ei0 +2024/01/07 13:55:02 fees: 5940 +➜ musig2-demo git:(main) ✗ +``` + + ## notice diff --git a/example/inscribewithoutnoderpc/main.go b/example/taprootmusig/main.go similarity index 96% rename from example/inscribewithoutnoderpc/main.go rename to example/taprootmusig/main.go index c58855b..e6465cf 100644 --- a/example/inscribewithoutnoderpc/main.go +++ b/example/taprootmusig/main.go @@ -34,8 +34,7 @@ func main() { musigPrivKey := musig2demo.TwoBtcTaprootAddress(privKey1, privKey2) musigPriv := make([]*btcec.PrivateKey, 0) - musigPriv = append(musigPriv, privKey1) - musigPriv = append(musigPriv, privKey2) + musigPriv = append(musigPriv, privKey1, privKey2) musigAddress, _ := btcutil.DecodeAddress(musigPrivKey, netParams) @@ -54,7 +53,7 @@ func main() { } fmt.Println("utxoTaprootAddress:", utxoTaprootAddress.EncodeAddress()) - fmt.Println("musigAddress:", musigAddress.EncodeAddress()) + fmt.Println("musigAddress no script:", musigAddress.EncodeAddress()) unspentList, err := btcApiClient.ListUnspent(utxoTaprootAddress) diff --git a/lib/go-ord-tx/pkg/ord/ord.go b/lib/go-ord-tx/pkg/ord/ord.go index e35bf3c..3d197db 100644 --- a/lib/go-ord-tx/pkg/ord/ord.go +++ b/lib/go-ord-tx/pkg/ord/ord.go @@ -92,7 +92,7 @@ func NewInscriptionTool(net *chaincfg.Params, rpcclient *rpcclient.Client, reque func NewInscriptionToolWithBtcApiClient(net *chaincfg.Params, btcApiClient btcapi.BTCAPIClient, request *InscriptionRequest, - utxoPrivKey []*btcec.PrivateKey, + musigPriv []*btcec.PrivateKey, ) (*InscriptionTool, error) { if len(request.CommitTxPrivateKeyList) != len(request.CommitTxOutPointList) { return nil, errors.New("the length of CommitTxPrivateKeyList and CommitTxOutPointList should be the same") @@ -106,12 +106,12 @@ func NewInscriptionToolWithBtcApiClient(net *chaincfg.Params, commitTxPrivateKeyList: request.CommitTxPrivateKeyList, revealTxPrevOutputFetcher: txscript.NewMultiPrevOutFetcher(nil), } - return tool, tool._initTool(net, request, utxoPrivKey) + return tool, tool._initTool(net, request, musigPriv) } func (tool *InscriptionTool) _initTool(net *chaincfg.Params, request *InscriptionRequest, - utxoPrivKey []*btcec.PrivateKey, + musigPriv []*btcec.PrivateKey, ) error { revealOutValue := defaultRevealOutValue if request.RevealOutValue > 0 { @@ -120,7 +120,7 @@ func (tool *InscriptionTool) _initTool(net *chaincfg.Params, tool.txCtxDataList = make([]*inscriptionTxCtxData, len(request.DataList)) destinations := make([]string, len(request.DataList)) for i := 0; i < len(request.DataList); i++ { - txCtxData, err := createInscriptionTxCtxData(net, request.DataList[i], utxoPrivKey) + txCtxData, err := createInscriptionTxCtxData(net, request.DataList[i], musigPriv) if err != nil { return err } @@ -148,7 +148,7 @@ func (tool *InscriptionTool) _initTool(net *chaincfg.Params, func createInscriptionTxCtxData(net *chaincfg.Params, data InscriptionData, - privateKey []*btcec.PrivateKey, + musigPriv []*btcec.PrivateKey, ) (*inscriptionTxCtxData, error) { // privateKey, err := btcec.NewPrivateKey() // if err != nil { @@ -156,7 +156,7 @@ func createInscriptionTxCtxData(net *chaincfg.Params, // } // - publicKey, _ := musig2.TwoCombinedKey(privateKey[0], privateKey[1]) + publicKey, _ := musig2.TwoCombinedKey(musigPriv[0], musigPriv[1]) inscriptionBuilder := txscript.NewScriptBuilder(). AddData(schnorr.SerializePubKey(publicKey)). @@ -211,13 +211,13 @@ func createInscriptionTxCtxData(net *chaincfg.Params, return nil, err } - recoveryPrivateKeyWIF, err := btcutil.NewWIF(txscript.TweakTaprootPrivKey(*privateKey[0], tapHash[:]), net, true) + recoveryPrivateKeyWIF, err := btcutil.NewWIF(txscript.TweakTaprootPrivKey(*musigPriv[0], tapHash[:]), net, true) if err != nil { return nil, err } return &inscriptionTxCtxData{ - privateKey: privateKey, + privateKey: musigPriv, inscriptionScript: inscriptionScript, commitTxAddressPkScript: commitTxAddressPkScript, controlBlockWitness: controlBlockWitness, diff --git a/main.go b/main.go index f0e1ed6..a25afd6 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "crypto/sha256" "encoding/hex" + "encoding/json" "errors" "fmt" "log" @@ -17,6 +18,8 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" + "github.com/oxf71/musig2-demo/lib/go-ord-tx/pkg/btcapi/mempool" + "github.com/oxf71/musig2-demo/lib/go-ord-tx/pkg/ord" musig2demo "github.com/oxf71/musig2-demo/musig2" ) @@ -518,6 +521,166 @@ func SignatureScript(tx *wire.MsgTx, idx int, subscript []byte, hashType txscrip return txscript.NewScriptBuilder().AddData(sig).AddData(pkData).Script() } +func sendTransaction() { + netParams := &chaincfg.SigNetParams + btcApiClient := mempool.NewClient(netParams) + + // privateKeyHex02 := "4ef5cb1fd5afd08ca9acbe5d077d89f1e095f67616a326d368851e57a92d1bab" + // privateKeyByte02, _ := hex.DecodeString(privateKeyHex02) + // privateKeyBytes02 := privateKeyByte02 // 用你自己的私钥替换这里的字节 + // privateKey02, publicKey02 := btcec.PrivKeyFromBytes(privateKeyBytes02) + // // 根据公钥生成比特币地址 + // addressPubKeyHash01 := btcutil.Hash160(publicKey02.SerializeCompressed()) + // address02, err := btcutil.NewAddressPubKeyHash(addressPubKeyHash01, &chaincfg.TestNet3Params) + // if err != nil { + // log.Fatal(err) + // } + // fmt.Println("address: ", address02) + + // 找零地址 + changeAddress, err := btcutil.DecodeAddress("tb1prggx0jcdqgag2kj9agxa7n6p888ffpzs4flps8ztwctrluz040hq6x9sz8", netParams) + if err != nil { + fmt.Println("DecodeAddress err:", err) + return + } + + privKey1, _ := btcec.PrivKeyFromBytes(decodeHex("440bb3ec56d213e90d006d344d74f6478db4f7fa4cdd388095d8f4edef0c5156")) + privKey2, _ := btcec.PrivKeyFromBytes(decodeHex(bip340TestVectors[1].secretKey)) + + musig2BtcTaprootAddress := musig2demo.TwoBtcTaprootAddress(privKey1, privKey2) + // fmt.Println("taprootAddress: ", taprootAddress) + // addressPubKeyHash01 := btcutil.Hash160(musig2BtcAddress.SerializeCompressed()) + // address02, err := btcutil.NewAddressPubKeyHash(addressPubKeyHash01, &chaincfg.TestNet3Params) + // if err != nil { + // log.Fatal(err) + // } + + // mulsigAddr, err := btcutil.DecodeAddress(musig2BtcAddress, &chaincfg.TestNet3Params) + // if err != nil { + // fmt.Println("DecodeAddress err:", err) + // return + // } + + // fmt.Println("taprootAddress: ", taprootAddress) + addressPubKey1 := btcutil.Hash160(privKey1.PubKey().SerializeCompressed()) + address01, err := btcutil.NewAddressPubKeyHash(addressPubKey1, netParams) + if err != nil { + log.Fatal(err) + } + + // mulsigAddr := musig2BtcTaprootAddress + + fmt.Println("mulsigAddr:", musig2BtcTaprootAddress) + fmt.Println("address 1", address01) + + musig2Address, err := btcutil.DecodeAddress("tb1prggx0jcdqgag2kj9agxa7n6p888ffpzs4flps8ztwctrluz040hq6x9sz8", netParams) + if err != nil { + fmt.Println("DecodeAddress err:", err) + return + } + + unspentList, err := btcApiClient.ListUnspent(musig2Address) + if err != nil { + fmt.Println("ListUnspent err:", err) + return + } + if len(unspentList) == 0 { + return + } + fmt.Println("000000:", len(unspentList)) + + // 创建比特币交易输入和输出 + totalSenderAmount := btcutil.Amount(0) + tx := wire.NewMsgTx(wire.TxVersion) + for i := range unspentList { + in := wire.NewTxIn(unspentList[i].Outpoint, nil, nil) + tx.AddTxIn(in) + totalSenderAmount += btcutil.Amount(unspentList[i].Output.Value) + } + + // 获取目标地址的比特币脚本 + destAddress, err := btcutil.DecodeAddress("tb1prggx0jcdqgag2kj9agxa7n6p888ffpzs4flps8ztwctrluz040hq6x9sz8", netParams) + if err != nil { + fmt.Println("DecodeAddress err:", err) + return + } + destinationScript, err := txscript.PayToAddrScript(destAddress) + if err != nil { + fmt.Println("PayToAddrScript err:", err) + return + } + + // 计算总金额和交易费用 + var fee int64 = 1000 + changeAmount := int64(totalSenderAmount) - 2000 - fee // 减去交易费用,转账2000 + + fmt.Println("0000: ", int64(totalSenderAmount)) + + // 添加目标地址作为交易输出 + tx.AddTxOut(wire.NewTxOut(2000, destinationScript)) + + var changeScript []byte + if changeAmount > 0 { + // 添加找零地址作为交易输出 + changeScript, err = txscript.PayToAddrScript(changeAddress) + if err != nil { + fmt.Println("PayToAddrScript err:", err) + return + } + + tx.AddTxOut(wire.NewTxOut(changeAmount, changeScript)) + } + + // 构建多签赎回脚本 + for i, v := range tx.TxIn { + // sigScriptB, err := SignatureScript(tx, i, changeScript, txscript.SigHashDefault, privKey1, privKey2, true) + // if err != nil { + // fmt.Println("SignatureScript:", err) + // return + // } + + // fmt.Println("sigScriptB:", sigScriptB) + + txOut := txscript.NewMultiPrevOutFetcher(nil).FetchPrevOutput(v.PreviousOutPoint) + witness, err := ord.TaprootWitnessSignature( + tx, + txscript.NewTxSigHashes(tx, txscript.NewMultiPrevOutFetcher(nil)), + i, + txOut.Value, + txOut.PkScript, + txscript.SigHashDefault, + privKey1, + nil, + // tool.txCtxDataList[0].controlBlockWitness, + ) + if err != nil { + log.Fatal(err) + } + v.Witness = witness + // witnessList[i] = witness + + // v.Witness = wire.TxWitness{sigScriptB.Serialize(), hash} + + // v.SignatureScript = sigScriptB + } + + txjsondata, err := json.Marshal(tx) + if err != nil { + fmt.Println("json.Marshal err:", err) + return + } + + fmt.Println("txjsondata:", string(txjsondata)) + + // 发送交易 + txHash, err := btcApiClient.BroadcastTx(tx) + if err != nil { + fmt.Println("BroadcastTx err:", err) + return + } + fmt.Printf("转账成功!交易哈希:%s\n", txHash.String()) + +} func main() {