mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
use np2wsh for loop in htlc
This commit is contained in:
parent
e765baa1f9
commit
30c7d71c57
10 changed files with 219 additions and 113 deletions
18
client.go
18
client.go
|
|
@ -276,15 +276,9 @@ func (s *Client) LoopOut(globalCtx context.Context,
|
|||
// Post swap to the main loop.
|
||||
s.executor.initiateSwap(globalCtx, swap)
|
||||
|
||||
// Retrieve htlc address.
|
||||
htlcAddress, err := swap.htlc.Address(s.lndServices.ChainParams)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Return hash so that the caller can identify this swap in the updates
|
||||
// stream.
|
||||
return &swap.hash, htlcAddress, nil
|
||||
return &swap.hash, swap.htlc.Address, nil
|
||||
}
|
||||
|
||||
// LoopOutQuote takes a LoopOut amount and returns a break down of estimated
|
||||
|
|
@ -313,7 +307,7 @@ func (s *Client) LoopOutQuote(ctx context.Context,
|
|||
)
|
||||
|
||||
minerFee, err := s.sweeper.GetSweepFee(
|
||||
ctx, swap.QuoteHtlc.MaxSuccessWitnessSize,
|
||||
ctx, swap.QuoteHtlc.AddSuccessToEstimator,
|
||||
request.SweepConfTarget,
|
||||
)
|
||||
if err != nil {
|
||||
|
|
@ -381,15 +375,9 @@ func (s *Client) LoopIn(globalCtx context.Context,
|
|||
// Post swap to the main loop.
|
||||
s.executor.initiateSwap(globalCtx, swap)
|
||||
|
||||
// Retrieve htlc address.
|
||||
htlcAddress, err := swap.htlc.Address(s.lndServices.ChainParams)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Return hash so that the caller can identify this swap in the updates
|
||||
// stream.
|
||||
return &swap.hash, htlcAddress, nil
|
||||
return &swap.hash, swap.htlc.Address, nil
|
||||
}
|
||||
|
||||
// LoopInQuote takes an amount and returns a break down of estimated
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/lightninglabs/loop"
|
||||
"github.com/lightninglabs/loop/lndclient"
|
||||
"github.com/lightninglabs/loop/loopdb"
|
||||
"github.com/lightninglabs/loop/swap"
|
||||
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lightninglabs/loop/looprpc"
|
||||
|
|
@ -104,19 +103,6 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) (
|
|||
state = looprpc.SwapState_FAILED
|
||||
}
|
||||
|
||||
htlc, err := swap.NewHtlc(
|
||||
loopSwap.CltvExpiry, loopSwap.SenderKey, loopSwap.ReceiverKey,
|
||||
loopSwap.SwapHash,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
address, err := htlc.Address(s.lnd.ChainParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var swapType looprpc.SwapType
|
||||
switch loopSwap.SwapType {
|
||||
case loop.TypeIn:
|
||||
|
|
@ -133,7 +119,7 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) (
|
|||
State: state,
|
||||
InitiationTime: loopSwap.InitiationTime.UnixNano(),
|
||||
LastUpdateTime: loopSwap.LastUpdate.UnixNano(),
|
||||
HtlcAddress: address.EncodeAddress(),
|
||||
HtlcAddress: loopSwap.HtlcAddress.EncodeAddress(),
|
||||
Type: swapType,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import (
|
|||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/lightninglabs/loop"
|
||||
"github.com/lightninglabs/loop/swap"
|
||||
)
|
||||
|
||||
|
|
@ -28,13 +30,21 @@ func view(config *config) error {
|
|||
}
|
||||
defer cleanup()
|
||||
|
||||
swaps, err := swapClient.FetchLoopOutSwaps()
|
||||
if err != nil {
|
||||
if err := viewOut(swapClient, chainParams); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(swaps) == 0 {
|
||||
fmt.Printf("No swaps\n")
|
||||
if err := viewIn(swapClient, chainParams); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func viewOut(swapClient *loop.Client, chainParams *chaincfg.Params) error {
|
||||
swaps, err := swapClient.FetchLoopOutSwaps()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, s := range swaps {
|
||||
|
|
@ -42,23 +52,18 @@ func view(config *config) error {
|
|||
s.Contract.CltvExpiry,
|
||||
s.Contract.SenderKey,
|
||||
s.Contract.ReceiverKey,
|
||||
s.Hash,
|
||||
s.Hash, swap.HtlcP2WSH, chainParams,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
htlcAddress, err := htlc.Address(chainParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("%v\n", s.Hash)
|
||||
fmt.Printf("OUT %v\n", s.Hash)
|
||||
fmt.Printf(" Created: %v (height %v)\n",
|
||||
s.Contract.InitiationTime, s.Contract.InitiationHeight,
|
||||
)
|
||||
fmt.Printf(" Preimage: %v\n", s.Contract.Preimage)
|
||||
fmt.Printf(" Htlc address: %v\n", htlcAddress)
|
||||
fmt.Printf(" Htlc address: %v\n", htlc.Address)
|
||||
|
||||
unchargeChannel := "any"
|
||||
if s.Contract.UnchargeChannel != nil {
|
||||
|
|
@ -81,3 +86,40 @@ func view(config *config) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func viewIn(swapClient *loop.Client, chainParams *chaincfg.Params) error {
|
||||
swaps, err := swapClient.FetchLoopInSwaps()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, s := range swaps {
|
||||
htlc, err := swap.NewHtlc(
|
||||
s.Contract.CltvExpiry,
|
||||
s.Contract.SenderKey,
|
||||
s.Contract.ReceiverKey,
|
||||
s.Hash, swap.HtlcNP2WSH, chainParams,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("IN %v\n", s.Hash)
|
||||
fmt.Printf(" Created: %v (height %v)\n",
|
||||
s.Contract.InitiationTime, s.Contract.InitiationHeight,
|
||||
)
|
||||
fmt.Printf(" Preimage: %v\n", s.Contract.Preimage)
|
||||
fmt.Printf(" Htlc address: %v\n", htlc.Address)
|
||||
fmt.Printf(" Amt: %v, Expiry: %v\n",
|
||||
s.Contract.AmountRequested, s.Contract.CltvExpiry,
|
||||
)
|
||||
for i, e := range s.Events {
|
||||
fmt.Printf(" Update %v, Time %v, State: %v\n",
|
||||
i, e.Time, e.State,
|
||||
)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -289,6 +289,8 @@ type SwapInfo struct {
|
|||
SwapType Type
|
||||
|
||||
loopdb.SwapContract
|
||||
|
||||
HtlcAddress btcutil.Address
|
||||
}
|
||||
|
||||
// LastUpdate returns the last update time of the swap
|
||||
|
|
|
|||
14
loopin.go
14
loopin.go
|
|
@ -151,7 +151,7 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
|
|||
}
|
||||
|
||||
swapKit, err := newSwapKit(
|
||||
swapHash, TypeIn, cfg, &contract.SwapContract,
|
||||
swapHash, TypeIn, cfg, &contract.SwapContract, swap.HtlcNP2WSH,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -184,7 +184,7 @@ func resumeLoopInSwap(reqContext context.Context, cfg *swapConfig,
|
|||
logger.Infof("Resuming loop in swap %v", hash)
|
||||
|
||||
swapKit, err := newSwapKit(
|
||||
hash, TypeIn, cfg, &pend.Contract.SwapContract,
|
||||
hash, TypeIn, cfg, &pend.Contract.SwapContract, swap.HtlcNP2WSH,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -307,7 +307,7 @@ func (s *loopInSwap) executeSwap(globalCtx context.Context) error {
|
|||
|
||||
// Determine the htlc outpoint by inspecting the htlc tx.
|
||||
htlcOutpoint, htlcValue, err := swap.GetScriptOutput(
|
||||
conf.Tx, s.htlc.ScriptHash,
|
||||
conf.Tx, s.htlc.PkScript,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -340,7 +340,7 @@ func (s *loopInSwap) waitForHtlcConf(globalCtx context.Context) (
|
|||
ctx, cancel := context.WithCancel(globalCtx)
|
||||
defer cancel()
|
||||
confChan, confErr, err := s.lnd.ChainNotifier.RegisterConfirmationsNtfn(
|
||||
ctx, nil, s.htlc.ScriptHash, 1, s.InitiationHeight,
|
||||
ctx, nil, s.htlc.PkScript, 1, s.InitiationHeight,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -400,7 +400,7 @@ func (s *loopInSwap) publishOnChainHtlc(ctx context.Context) (bool, error) {
|
|||
s.log.Infof("Publishing on chain HTLC with fee rate %v", feeRate)
|
||||
tx, err := s.lnd.WalletKit.SendOutputs(ctx,
|
||||
[]*wire.TxOut{{
|
||||
PkScript: s.htlc.ScriptHash,
|
||||
PkScript: s.htlc.PkScript,
|
||||
Value: int64(s.LoopInContract.AmountRequested),
|
||||
}},
|
||||
feeRate,
|
||||
|
|
@ -424,7 +424,7 @@ func (s *loopInSwap) waitForSwapComplete(ctx context.Context,
|
|||
rpcCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
spendChan, spendErr, err := s.lnd.ChainNotifier.RegisterSpendNtfn(
|
||||
rpcCtx, nil, s.htlc.ScriptHash, s.InitiationHeight,
|
||||
rpcCtx, nil, s.htlc.PkScript, s.InitiationHeight,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("register spend ntfn: %v", err)
|
||||
|
|
@ -583,7 +583,7 @@ func (s *loopInSwap) publishTimeoutTx(ctx context.Context,
|
|||
|
||||
// Calculate sweep tx fee
|
||||
fee, err := s.sweeper.GetSweepFee(
|
||||
ctx, s.htlc.MaxTimeoutWitnessSize, TimeoutTxConfTarget,
|
||||
ctx, s.htlc.AddTimeoutToEstimator, TimeoutTxConfTarget,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool) {
|
|||
|
||||
htlc, err := swap.NewHtlc(
|
||||
contract.CltvExpiry, contract.SenderKey, contract.ReceiverKey,
|
||||
testPreimage.Hash(),
|
||||
testPreimage.Hash(), swap.HtlcNP2WSH, cfg.lnd.ChainParams,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -329,7 +329,7 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool) {
|
|||
ctx.assertState(loopdb.StateHtlcPublished)
|
||||
|
||||
htlcTx.AddTxOut(&wire.TxOut{
|
||||
PkScript: htlc.ScriptHash,
|
||||
PkScript: htlc.PkScript,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
14
loopout.go
14
loopout.go
|
|
@ -105,7 +105,7 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig,
|
|||
}
|
||||
|
||||
swapKit, err := newSwapKit(
|
||||
swapHash, TypeOut, cfg, &contract.SwapContract,
|
||||
swapHash, TypeOut, cfg, &contract.SwapContract, swap.HtlcP2WSH,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -138,7 +138,7 @@ func resumeLoopOutSwap(reqContext context.Context, cfg *swapConfig,
|
|||
logger.Infof("Resuming loop out swap %v", hash)
|
||||
|
||||
swapKit, err := newSwapKit(
|
||||
hash, TypeOut, cfg, &pend.Contract.SwapContract,
|
||||
hash, TypeOut, cfg, &pend.Contract.SwapContract, swap.HtlcP2WSH,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -168,6 +168,7 @@ func (s *loopOutSwap) execute(mainCtx context.Context,
|
|||
s.executeConfig = *cfg
|
||||
s.height = height
|
||||
|
||||
// Execute swap.
|
||||
err := s.executeAndFinalize(mainCtx)
|
||||
|
||||
// If an unexpected error happened, report a temporary failure.
|
||||
|
|
@ -189,6 +190,7 @@ func (s *loopOutSwap) execute(mainCtx context.Context,
|
|||
// executeAndFinalize executes a swap and awaits the definitive outcome of the
|
||||
// offchain payments. When this method returns, the swap outcome is final.
|
||||
func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error {
|
||||
|
||||
// Announce swap by sending out an initial update.
|
||||
err := s.sendUpdate(globalCtx)
|
||||
if err != nil {
|
||||
|
|
@ -281,7 +283,7 @@ func (s *loopOutSwap) executeSwap(globalCtx context.Context) error {
|
|||
|
||||
// Retrieve outpoint for sweep.
|
||||
htlcOutpoint, htlcValue, err := swap.GetScriptOutput(
|
||||
txConf.Tx, s.htlc.ScriptHash,
|
||||
txConf.Tx, s.htlc.PkScript,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -383,7 +385,7 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
|
|||
defer cancel()
|
||||
htlcConfChan, htlcErrChan, err :=
|
||||
s.lnd.ChainNotifier.RegisterConfirmationsNtfn(
|
||||
ctx, nil, s.htlc.ScriptHash, 1,
|
||||
ctx, nil, s.htlc.PkScript, 1,
|
||||
s.InitiationHeight,
|
||||
)
|
||||
if err != nil {
|
||||
|
|
@ -514,7 +516,7 @@ func (s *loopOutSwap) waitForHtlcSpendConfirmed(globalCtx context.Context,
|
|||
ctx, cancel := context.WithCancel(globalCtx)
|
||||
defer cancel()
|
||||
spendChan, spendErr, err := s.lnd.ChainNotifier.RegisterSpendNtfn(
|
||||
ctx, nil, s.htlc.ScriptHash, s.InitiationHeight,
|
||||
ctx, nil, s.htlc.PkScript, s.InitiationHeight,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("register spend ntfn: %v", err)
|
||||
|
|
@ -571,7 +573,7 @@ func (s *loopOutSwap) sweep(ctx context.Context,
|
|||
|
||||
// Calculate sweep tx fee
|
||||
fee, err := s.sweeper.GetSweepFee(
|
||||
ctx, s.htlc.MaxSuccessWitnessSize,
|
||||
ctx, s.htlc.AddSuccessToEstimator,
|
||||
s.SweepConfTarget,
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
|||
16
swap.go
16
swap.go
|
|
@ -29,29 +29,26 @@ type swapKit struct {
|
|||
}
|
||||
|
||||
func newSwapKit(hash lntypes.Hash, swapType Type, cfg *swapConfig,
|
||||
contract *loopdb.SwapContract) (*swapKit, error) {
|
||||
contract *loopdb.SwapContract, outputType swap.HtlcOutputType) (
|
||||
*swapKit, error) {
|
||||
|
||||
// Compose expected on-chain swap script
|
||||
htlc, err := swap.NewHtlc(
|
||||
contract.CltvExpiry, contract.SenderKey,
|
||||
contract.ReceiverKey, hash,
|
||||
contract.ReceiverKey, hash, outputType,
|
||||
cfg.lnd.ChainParams,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Log htlc address for debugging.
|
||||
htlcAddress, err := htlc.Address(cfg.lnd.ChainParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log := &SwapLog{
|
||||
Hash: hash,
|
||||
Logger: logger,
|
||||
}
|
||||
|
||||
log.Infof("Htlc address: %v", htlcAddress)
|
||||
// Log htlc address for debugging.
|
||||
log.Infof("Htlc address: %v", htlc.Address)
|
||||
|
||||
return &swapKit{
|
||||
swapConfig: *cfg,
|
||||
|
|
@ -72,6 +69,7 @@ func (s *swapKit) sendUpdate(ctx context.Context) error {
|
|||
SwapType: s.swapType,
|
||||
LastUpdate: s.lastUpdateTime,
|
||||
State: s.state,
|
||||
HtlcAddress: s.htlc.Address,
|
||||
}
|
||||
|
||||
s.log.Infof("state %v", info.State)
|
||||
|
|
|
|||
172
swap/htlc.go
172
swap/htlc.go
|
|
@ -2,6 +2,7 @@ package swap
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
|
|
@ -12,13 +13,27 @@ import (
|
|||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
)
|
||||
|
||||
// HtlcOutputType defines the output type of the htlc that is published.
|
||||
type HtlcOutputType uint8
|
||||
|
||||
const (
|
||||
// HtlcP2WSH is a pay-to-witness-script-hash output (segwit only)
|
||||
HtlcP2WSH HtlcOutputType = iota
|
||||
|
||||
// HtlcNP2WSH is a nested pay-to-witness-script-hash output that can be
|
||||
// paid to be legacy wallets.
|
||||
HtlcNP2WSH
|
||||
)
|
||||
|
||||
// Htlc contains relevant htlc information from the receiver perspective.
|
||||
type Htlc struct {
|
||||
Script []byte
|
||||
ScriptHash []byte
|
||||
Hash lntypes.Hash
|
||||
MaxSuccessWitnessSize int
|
||||
MaxTimeoutWitnessSize int
|
||||
Script []byte
|
||||
PkScript []byte
|
||||
Hash lntypes.Hash
|
||||
OutputType HtlcOutputType
|
||||
ChainParams *chaincfg.Params
|
||||
Address btcutil.Address
|
||||
SigScript []byte
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
@ -30,13 +45,15 @@ var (
|
|||
// the maximum value for cltv expiry to get the maximum (worst case)
|
||||
// script size.
|
||||
QuoteHtlc, _ = NewHtlc(
|
||||
^int32(0), quoteKey, quoteKey, quoteHash,
|
||||
^int32(0), quoteKey, quoteKey, quoteHash, HtlcP2WSH,
|
||||
&chaincfg.MainNetParams,
|
||||
)
|
||||
)
|
||||
|
||||
// NewHtlc returns a new instance.
|
||||
func NewHtlc(cltvExpiry int32, senderKey, receiverKey [33]byte,
|
||||
hash lntypes.Hash) (*Htlc, error) {
|
||||
hash lntypes.Hash, outputType HtlcOutputType,
|
||||
chainParams *chaincfg.Params) (*Htlc, error) {
|
||||
|
||||
script, err := swapHTLCScript(
|
||||
cltvExpiry, senderKey, receiverKey, hash,
|
||||
|
|
@ -45,39 +62,73 @@ func NewHtlc(cltvExpiry int32, senderKey, receiverKey [33]byte,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
scriptHash, err := input.WitnessScriptHash(script)
|
||||
p2wshPkScript, err := input.WitnessScriptHash(script)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Calculate maximum success witness size
|
||||
//
|
||||
// - number_of_witness_elements: 1 byte
|
||||
// - receiver_sig_length: 1 byte
|
||||
// - receiver_sig: 73 bytes
|
||||
// - preimage_length: 1 byte
|
||||
// - preimage: 33 bytes
|
||||
// - witness_script_length: 1 byte
|
||||
// - witness_script: len(script) bytes
|
||||
maxSuccessWitnessSize := 1 + 1 + 73 + 1 + 33 + 1 + len(script)
|
||||
p2wshPkScriptHash := sha256.Sum256(p2wshPkScript)
|
||||
|
||||
// Calculate maximum timeout witness size
|
||||
//
|
||||
// - number_of_witness_elements: 1 byte
|
||||
// - sender_sig_length: 1 byte
|
||||
// - sender_sig: 73 bytes
|
||||
// - zero_length: 1 byte
|
||||
// - zero: 1 byte
|
||||
// - witness_script_length: 1 byte
|
||||
// - witness_script: len(script) bytes
|
||||
maxTimeoutWitnessSize := 1 + 1 + 73 + 1 + 1 + 1 + len(script)
|
||||
var pkScript, sigScript []byte
|
||||
var address btcutil.Address
|
||||
|
||||
switch outputType {
|
||||
case HtlcNP2WSH:
|
||||
// Generate p2sh script for p2wsh (nested).
|
||||
|
||||
hash160 := input.Ripemd160H(p2wshPkScriptHash[:])
|
||||
|
||||
builder := txscript.NewScriptBuilder()
|
||||
|
||||
builder.AddOp(txscript.OP_HASH160)
|
||||
builder.AddData(hash160)
|
||||
builder.AddOp(txscript.OP_EQUAL)
|
||||
|
||||
pkScript, err = builder.Script()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Generate a valid sigScript that will allow us to spend the
|
||||
// p2sh output. The sigScript will contain only a single push of
|
||||
// the p2wsh witness program corresponding to the matching
|
||||
// public key of this address.
|
||||
sigScript, err = txscript.NewScriptBuilder().
|
||||
AddData(p2wshPkScript).
|
||||
Script()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
address, err = btcutil.NewAddressScriptHash(
|
||||
p2wshPkScript, chainParams,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case HtlcP2WSH:
|
||||
pkScript = p2wshPkScript
|
||||
|
||||
address, err = btcutil.NewAddressWitnessScriptHash(
|
||||
p2wshPkScriptHash[:],
|
||||
chainParams,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("unknown output type")
|
||||
}
|
||||
|
||||
return &Htlc{
|
||||
Hash: hash,
|
||||
Script: script,
|
||||
ScriptHash: scriptHash,
|
||||
MaxSuccessWitnessSize: maxSuccessWitnessSize,
|
||||
MaxTimeoutWitnessSize: maxTimeoutWitnessSize,
|
||||
Hash: hash,
|
||||
Script: script,
|
||||
PkScript: pkScript,
|
||||
OutputType: outputType,
|
||||
ChainParams: chainParams,
|
||||
Address: address,
|
||||
SigScript: sigScript,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -127,17 +178,6 @@ func swapHTLCScript(cltvExpiry int32, senderHtlcKey,
|
|||
return builder.Script()
|
||||
}
|
||||
|
||||
// Address returns the p2wsh address of the htlc.
|
||||
func (h *Htlc) Address(chainParams *chaincfg.Params) (
|
||||
btcutil.Address, error) {
|
||||
|
||||
// Skip OP_0 and data length.
|
||||
return btcutil.NewAddressWitnessScriptHash(
|
||||
h.ScriptHash[2:],
|
||||
chainParams,
|
||||
)
|
||||
}
|
||||
|
||||
// GenSuccessWitness returns the success script to spend this htlc with the
|
||||
// preimage.
|
||||
func (h *Htlc) GenSuccessWitness(receiverSig []byte,
|
||||
|
|
@ -178,3 +218,47 @@ func (h *Htlc) GenTimeoutWitness(senderSig []byte) (wire.TxWitness, error) {
|
|||
|
||||
return witnessStack, nil
|
||||
}
|
||||
|
||||
// AddSuccessToEstimator adds a successful spend to a weight estimator.
|
||||
func (h *Htlc) AddSuccessToEstimator(estimator *input.TxWeightEstimator) {
|
||||
// Calculate maximum success witness size
|
||||
//
|
||||
// - number_of_witness_elements: 1 byte
|
||||
// - receiver_sig_length: 1 byte
|
||||
// - receiver_sig: 73 bytes
|
||||
// - preimage_length: 1 byte
|
||||
// - preimage: 33 bytes
|
||||
// - witness_script_length: 1 byte
|
||||
// - witness_script: len(script) bytes
|
||||
maxSuccessWitnessSize := 1 + 1 + 73 + 1 + 33 + 1 + len(h.Script)
|
||||
|
||||
switch h.OutputType {
|
||||
case HtlcP2WSH:
|
||||
estimator.AddWitnessInput(maxSuccessWitnessSize)
|
||||
|
||||
case HtlcNP2WSH:
|
||||
estimator.AddNestedP2WSHInput(maxSuccessWitnessSize)
|
||||
}
|
||||
}
|
||||
|
||||
// AddTimeoutToEstimator adds a timeout spend to a weight estimator.
|
||||
func (h *Htlc) AddTimeoutToEstimator(estimator *input.TxWeightEstimator) {
|
||||
// Calculate maximum timeout witness size
|
||||
//
|
||||
// - number_of_witness_elements: 1 byte
|
||||
// - sender_sig_length: 1 byte
|
||||
// - sender_sig: 73 bytes
|
||||
// - zero_length: 1 byte
|
||||
// - zero: 1 byte
|
||||
// - witness_script_length: 1 byte
|
||||
// - witness_script: len(script) bytes
|
||||
maxTimeoutWitnessSize := 1 + 1 + 73 + 1 + 1 + 1 + len(h.Script)
|
||||
|
||||
switch h.OutputType {
|
||||
case HtlcP2WSH:
|
||||
estimator.AddWitnessInput(maxTimeoutWitnessSize)
|
||||
|
||||
case HtlcNP2WSH:
|
||||
estimator.AddNestedP2WSHInput(maxTimeoutWitnessSize)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ func (s *Sweeper) CreateSweepTx(
|
|||
// Add HTLC input.
|
||||
sweepTx.AddTxIn(&wire.TxIn{
|
||||
PreviousOutPoint: htlcOutpoint,
|
||||
SignatureScript: htlc.SigScript,
|
||||
})
|
||||
|
||||
// Add output for the destination address.
|
||||
|
|
@ -85,9 +86,12 @@ func (s *Sweeper) CreateSweepTx(
|
|||
return sweepTx, nil
|
||||
}
|
||||
|
||||
// GetSweepFee calculates the required tx fee.
|
||||
// GetSweepFee calculates the required tx fee to spend to P2WKH. It takes a
|
||||
// function that is expected to add the weight of the input to the weight
|
||||
// estimator.
|
||||
func (s *Sweeper) GetSweepFee(ctx context.Context,
|
||||
htlcSuccessWitnessSize int, sweepConfTarget int32) (
|
||||
addInputEstimate func(*input.TxWeightEstimator),
|
||||
sweepConfTarget int32) (
|
||||
btcutil.Amount, error) {
|
||||
|
||||
// Get fee estimate from lnd.
|
||||
|
|
@ -99,7 +103,7 @@ func (s *Sweeper) GetSweepFee(ctx context.Context,
|
|||
// Calculate weight for this tx.
|
||||
var weightEstimate input.TxWeightEstimator
|
||||
weightEstimate.AddP2WKHOutput()
|
||||
weightEstimate.AddWitnessInput(htlcSuccessWitnessSize)
|
||||
addInputEstimate(&weightEstimate)
|
||||
weight := weightEstimate.Weight()
|
||||
|
||||
return feeRate.FeeForWeight(int64(weight)), nil
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue