Closed lenhatquang97 closed 1 year ago
// instead of
tweakedPubKey, err := schnorr.ParsePubKey(wif.PrivKey.PubKey().X().Bytes())
// can just use
tweakedPubKey, err := schnorr.ParsePubKey(schnorr.SerializePubKey(wif.PrivKey.PubKey()))
// this is for a key-only spend. so p2pktrAddr will give you the wrong address if you're attempting to include a script.
tapKey := txscript.ComputeTaprootKeyNoScript(wif.PrivKey.PubKey())
// this looks wrong...
ctrlBlock := tapScriptTree.LeafMerkleProofs[0].ToControlBlock(wif.PrivKey.PubKey())
See https://github.com/lightningnetwork/lnd/blob/db73e640d935060e98803f2cbbbf748e41a75826/input/taproot.go#L61 for an example of a correct control block.
// It looks like you want to sign for the script spend path, in which case you need to use txscript.RawTxInTapscriptSignature instead
sig, err := txscript.RawTxInTaprootSignature(
So I want to do this following:
Thank you very much for your help!
Also, I don't know how to use RawTxInTapscriptSignature and NewCannedPrevOutputFetcher. How do I use this?
You can skip step 1, you can send directly from the p2wpkh to the commitment transaction. And then the reveal transaction spends from the commitment transaction, and the output can be a p2wpkh address again. So p2wpkh -> p2tr -> p2wpkh (just to keep things simple to understand). Let's call the first TX (p2wpkh -> p2tr) COMMIT and the second TX (p2tr -> p2wpkh) REVEAL.
I think what you're struggling with is that the output script in the COMMIT must already be the script you want to reveal. So the taproot output key of COMMIT must be constructed the same way as the input witness script and control block in the REVEAL transaction.
So what kind of B script I want to include? maybe scriptPubKey OP_CHECKSIG?
I don't know, what kind of script do you want to reveal?
Also, I don't know how to use RawTxInTapscriptSignature and NewCannedPrevOutputFetcher. How do I use this?
Here's an example: https://github.com/lightningnetwork/lnd/blob/4da26fb65a669fbee68fa36e60259a8da8ef6d3b/lnwallet/btcwallet/psbt.go#L410
Ah, sorry. A is P2PKH because it uses SignatureScript in simnet with address SeZdpbs8WBuPHMZETPWajMeXZt1xzCJNAJ
In fact, I am struggling in verifying the witness in the commit transaction. I think that I am wrong in signing part but I don't know how to fix this problem.
func StartTapTree(client *rpcclient.Client, keyPair *btcutil.WIF, data []byte, hash *chainhash.Hash, index uint32, commitOutput *wire.TxOut) error {
hashLockKeypair, err := MakeRandomKeyPair()
if err != nil {
return err
}
builder := txscript.NewScriptBuilder()
builder.AddData(hashLockKeypair.PrivKey.PubKey().X().Bytes())
builder.AddOp(txscript.OP_CHECKSIG)
hashLockScript, err := builder.Script()
if err != nil {
return err
}
var allTreeLeaves []txscript.TapLeaf
tapLeaf := txscript.NewBaseTapLeaf(hashLockScript)
allTreeLeaves = append(allTreeLeaves, tapLeaf)
tapTree := TapscriptFullTree(keyPair.PrivKey.PubKey(), allTreeLeaves...)
taprootKey, err := tapTree.TaprootKey()
if err != nil {
return err
}
scriptAddr, err := btcutil.NewAddressTaproot(schnorr.SerializePubKey(taprootKey), &chaincfg.SimNetParams)
if err != nil {
return err
}
//Commit transaction
commitTx, err := NewTx()
if err != nil {
return err
}
commitTx.AddTxIn(&wire.TxIn{
PreviousOutPoint: *wire.NewOutPoint(hash, index),
})
scriptAddrScript, _ := txscript.PayToAddrScript(scriptAddr)
commitTx.AddTxOut(&wire.TxOut{
Value: commitOutput.Value * 80 / 100,
PkScript: scriptAddrScript,
})
inputFetcher := txscript.NewCannedPrevOutputFetcher(scriptAddrScript, commitOutput.Value*80/100)
sigHashes := txscript.NewTxSigHashes(commitTx, inputFetcher)
sig, err := txscript.RawTxInTapscriptSignature(commitTx, sigHashes, 0, commitOutput.Value*80/100, scriptAddrScript, tapLeaf, txscript.SigHashDefault, keyPair.PrivKey)
if err != nil {
return err
}
controlBlock, err := tapTree.ControlBlock.ToBytes()
if err != nil {
return err
}
commitTx.TxIn[0].Witness = wire.TxWitness{sig, hashLockScript, controlBlock}
finalHash, err := client.SendRawTransaction(commitTx, false)
if err != nil {
return err
}
fmt.Println(finalHash)
return nil
}
func MakeRandomKeyPair() (*btcutil.WIF, error) {
randPriv, err := btcec.NewPrivateKey()
if err != nil {
return nil, err
}
wif, err := btcutil.NewWIF(randPriv, &chaincfg.SimNetParams, true)
if err != nil {
return nil, err
}
return wif, nil
}
How are you calling StartTapTree
? And what does the pkScript of the output look like that you're spending here? Meaning: How do you create the output that you are referencing here with the PreviousOutPoint
? You need to send to the same address as you're creating here (scriptAddr
).
So I have the solution there, thank you for your help. A (any address) -> B -> C (any address). So B must be the taproot address. In A -> B, I create script so that I have B address with script OP_1 schnorrPubKey. In B -> C, I create the script to unlock with schnorrPubKey OP_CHECKSIG. The key to this solution is that B in two phases must be the same address, only different from the script. Details of the source are available here: https://github.com/lenhatquang97/bitcoin_nft_v2
Situation
Hello everyone, I am doing thesis related to putting data into the transaction and I do not understand the mechanics of P2TR. Can everyone give me a sample code about simple P2TR transaction?
Why I stuck?
I do not understand how it works in P2TR transaction. Maybe I sign in a wrong way!....
Source code