sweepremoteclosed: add support for simple taproot channels

pull/106/head
Oliver Gugger 4 months ago
parent 0ebb732576
commit 801f881274
No known key found for this signature in database
GPG Key ID: 8E4256593F177720

@ -53,6 +53,7 @@ funds can be swept after the force-close transaction was confirmed.
Supported remote force-closed channel types are:
- STATIC_REMOTE_KEY (a.k.a. tweakless channels)
- ANCHOR (a.k.a. anchor output channels)
- SIMPLE_TAPROOT (a.k.a. simple taproot channels)
`,
Example: `chantools sweepremoteclosed \
--recoverywindow 300 \
@ -113,12 +114,13 @@ func (c *sweepRemoteClosedCommand) Execute(_ *cobra.Command, _ []string) error {
}
type targetAddr struct {
addr btcutil.Address
pubKey *btcec.PublicKey
path string
keyDesc *keychain.KeyDescriptor
vouts []*btc.Vout
script []byte
addr btcutil.Address
pubKey *btcec.PublicKey
path string
keyDesc *keychain.KeyDescriptor
vouts []*btc.Vout
script []byte
scriptTree *input.CommitScriptTree
}
func sweepRemoteClosed(extendedKey *hdkeychain.ExtendedKey, apiURL,
@ -196,18 +198,6 @@ func sweepRemoteClosed(extendedKey *hdkeychain.ExtendedKey, apiURL,
err)
}
sequence := wire.MaxTxInSequenceNum
switch target.addr.(type) {
case *btcutil.AddressWitnessPubKeyHash:
estimator.AddP2WKHInput()
case *btcutil.AddressWitnessScriptHash:
estimator.AddWitnessInput(
input.ToRemoteConfirmedWitnessSize,
)
sequence = 1
}
prevOutPoint := wire.OutPoint{
Hash: *txHash,
Index: uint32(vout.Outspend.Vin),
@ -217,18 +207,76 @@ func sweepRemoteClosed(extendedKey *hdkeychain.ExtendedKey, apiURL,
Value: int64(vout.Value),
}
prevOutFetcher.AddPrevOut(prevOutPoint, prevTxOut)
sweepTx.TxIn = append(sweepTx.TxIn, &wire.TxIn{
txIn := &wire.TxIn{
PreviousOutPoint: prevOutPoint,
Sequence: sequence,
})
Sequence: wire.MaxTxInSequenceNum,
}
sweepTx.TxIn = append(sweepTx.TxIn, txIn)
inputIndex := len(sweepTx.TxIn) - 1
signDescs = append(signDescs, &input.SignDescriptor{
KeyDesc: *target.keyDesc,
WitnessScript: target.script,
Output: prevTxOut,
HashType: txscript.SigHashAll,
PrevOutputFetcher: prevOutFetcher,
})
var signDesc *input.SignDescriptor
switch target.addr.(type) {
case *btcutil.AddressWitnessPubKeyHash:
estimator.AddP2WKHInput()
signDesc = &input.SignDescriptor{
KeyDesc: *target.keyDesc,
WitnessScript: target.script,
Output: prevTxOut,
HashType: txscript.SigHashAll,
PrevOutputFetcher: prevOutFetcher,
InputIndex: inputIndex,
}
case *btcutil.AddressWitnessScriptHash:
estimator.AddWitnessInput(
input.ToRemoteConfirmedWitnessSize,
)
txIn.Sequence = 1
signDesc = &input.SignDescriptor{
KeyDesc: *target.keyDesc,
WitnessScript: target.script,
Output: prevTxOut,
HashType: txscript.SigHashAll,
PrevOutputFetcher: prevOutFetcher,
InputIndex: inputIndex,
}
case *btcutil.AddressTaproot:
estimator.AddWitnessInput(
input.TaprootToRemoteWitnessSize,
)
txIn.Sequence = 1
tree := target.scriptTree
controlBlock, err := tree.CtrlBlockForPath(
input.ScriptPathSuccess,
)
if err != nil {
return err
}
controlBlockBytes, err := controlBlock.ToBytes()
if err != nil {
return err
}
script := tree.SettleLeaf.Script
signMethod := input.TaprootScriptSpendSignMethod
signDesc = &input.SignDescriptor{
KeyDesc: *target.keyDesc,
WitnessScript: script,
Output: prevTxOut,
HashType: txscript.SigHashDefault,
PrevOutputFetcher: prevOutFetcher,
ControlBlock: controlBlockBytes,
InputIndex: inputIndex,
SignMethod: signMethod,
TapTweak: tree.TapscriptRoot,
}
}
signDescs = append(signDescs, signDesc)
}
}
@ -270,7 +318,19 @@ func sweepRemoteClosed(extendedKey *hdkeychain.ExtendedKey, apiURL,
desc.SigHashes = sigHashes
desc.InputIndex = idx
if len(desc.WitnessScript) > 0 {
switch {
// Simple Taproot Channels.
case desc.SignMethod == input.TaprootScriptSpendSignMethod:
witness, err := input.TaprootCommitSpendSuccess(
signer, desc, sweepTx, nil,
)
if err != nil {
return err
}
sweepTx.TxIn[idx].Witness = witness
// Anchor Channels.
case len(desc.WitnessScript) > 0:
witness, err := input.CommitSpendToRemoteConfirmed(
signer, desc, sweepTx,
)
@ -278,7 +338,9 @@ func sweepRemoteClosed(extendedKey *hdkeychain.ExtendedKey, apiURL,
return err
}
sweepTx.TxIn[idx].Witness = witness
} else {
// Static Remote Key Channels.
default:
// The txscript library expects the witness script of a
// P2WKH descriptor to be set to the pkScript of the
// output...
@ -320,7 +382,9 @@ func queryAddressBalances(pubKey *btcec.PublicKey, path string,
error) {
var targets []*targetAddr
queryAddr := func(address btcutil.Address, script []byte) error {
queryAddr := func(address btcutil.Address, script []byte,
scriptTree *input.CommitScriptTree) error {
unspent, err := api.Unspent(address.EncodeAddress())
if err != nil {
return fmt.Errorf("could not query unspent: %w", err)
@ -330,12 +394,13 @@ func queryAddressBalances(pubKey *btcec.PublicKey, path string,
log.Infof("Found %d unspent outputs for address %v",
len(unspent), address.EncodeAddress())
targets = append(targets, &targetAddr{
addr: address,
pubKey: pubKey,
path: path,
keyDesc: keyDesc,
vouts: unspent,
script: script,
addr: address,
pubKey: pubKey,
path: path,
keyDesc: keyDesc,
vouts: unspent,
script: script,
scriptTree: scriptTree,
})
}
@ -346,7 +411,7 @@ func queryAddressBalances(pubKey *btcec.PublicKey, path string,
if err != nil {
return nil, err
}
if err := queryAddr(p2wkh, nil); err != nil {
if err := queryAddr(p2wkh, nil, nil); err != nil {
return nil, err
}
@ -354,7 +419,15 @@ func queryAddressBalances(pubKey *btcec.PublicKey, path string,
if err != nil {
return nil, err
}
if err := queryAddr(p2anchor, script); err != nil {
if err := queryAddr(p2anchor, script, nil); err != nil {
return nil, err
}
p2tr, scriptTree, err := lnd.P2TaprootStaticRemove(pubKey, chainParams)
if err != nil {
return nil, err
}
if err := queryAddr(p2tr, nil, scriptTree); err != nil {
return nil, err
}

@ -276,11 +276,7 @@ func GetWitnessAddrScript(addr btcutil.Address,
chainParams.Name)
}
builder := txscript.NewScriptBuilder()
builder.AddOp(txscript.OP_0)
builder.AddData(addr.ScriptAddress())
return builder.Script()
return txscript.PayToAddrScript(addr)
}
// GetP2WPKHScript creates a P2WKH output script from an address. If the address
@ -387,6 +383,21 @@ func P2AnchorStaticRemote(pubKey *btcec.PublicKey,
return p2wsh, commitScript, err
}
func P2TaprootStaticRemove(pubKey *btcec.PublicKey,
params *chaincfg.Params) (*btcutil.AddressTaproot,
*input.CommitScriptTree, error) {
scriptTree, err := input.NewRemoteCommitScriptTree(pubKey)
if err != nil {
return nil, nil, fmt.Errorf("could not create script: %w", err)
}
addr, err := btcutil.NewAddressTaproot(
schnorr.SerializePubKey(scriptTree.TaprootKey), params,
)
return addr, scriptTree, err
}
type HDKeyRing struct {
ExtendedKey *hdkeychain.ExtendedKey
ChainParams *chaincfg.Params

Loading…
Cancel
Save