throwaway: loop out works! (mostly)

pull/471/head
Harsha Goli 2 years ago
parent e5e51b065e
commit 2de6c18ede
No known key found for this signature in database
GPG Key ID: 90E00CCB1C74C611

@ -216,12 +216,10 @@ func testResume(t *testing.T, confs uint32, expired, preimageRevealed,
} }
_, senderPubKey := test.CreateKey(1) _, senderPubKey := test.CreateKey(1)
var senderKey [33]byte senderKey := senderPubKey.SerializeCompressed()
copy(senderKey[:], senderPubKey.SerializeCompressed())
_, receiverPubKey := test.CreateKey(2) _, receiverPubKey := test.CreateKey(2)
var receiverKey [33]byte receiverKey := receiverPubKey.SerializeCompressed()
copy(receiverKey[:], receiverPubKey.SerializeCompressed())
update := loopdb.LoopEvent{ update := loopdb.LoopEvent{
SwapStateData: loopdb.SwapStateData{ SwapStateData: loopdb.SwapStateData{

@ -211,26 +211,54 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) (
if failureReason != clientrpc.FailureReason_FAILURE_REASON_NONE { if failureReason != clientrpc.FailureReason_FAILURE_REASON_NONE {
state = clientrpc.SwapState_FAILED state = clientrpc.SwapState_FAILED
} }
scriptVer := loop.GetHtlcScriptVersion(loopSwap.ProtocolVersion)
var swapType clientrpc.SwapType var swapType clientrpc.SwapType
var htlcAddress, htlcAddressP2WSH, htlcAddressNP2WSH string var htlcAddress, htlcAddressP2WSH, htlcAddressP2TR, htlcAddressNP2WSH string
switch loopSwap.SwapType { switch loopSwap.SwapType {
case swap.TypeIn: case swap.TypeIn:
swapType = clientrpc.SwapType_LOOP_IN swapType = clientrpc.SwapType_LOOP_IN
htlcAddressP2WSH = loopSwap.HtlcAddressP2WSH.EncodeAddress() htlcAddressP2WSH = loopSwap.HtlcAddressP2WSH.EncodeAddress()
// Determine which address to set depending on script version.
// If the loop in is external, we'll default to v1
if loopSwap.ExternalHtlc { if loopSwap.ExternalHtlc {
htlcAddressNP2WSH = loopSwap.HtlcAddressNP2WSH.EncodeAddress() htlcAddressNP2WSH = loopSwap.HtlcAddressNP2WSH.EncodeAddress()
htlcAddress = htlcAddressNP2WSH htlcAddress = htlcAddressNP2WSH
} else { }
switch scriptVer {
case swap.HtlcV1:
htlcAddressNP2WSH = loopSwap.HtlcAddressNP2WSH.EncodeAddress()
htlcAddress = htlcAddressNP2WSH
case swap.HtlcV2:
htlcAddressP2WSH = loopSwap.HtlcAddressP2WSH.EncodeAddress()
htlcAddress = htlcAddressP2WSH htlcAddress = htlcAddressP2WSH
case swap.HtlcV3:
htlcAddressP2TR = loopSwap.HtlcAddressP2TR.EncodeAddress()
htlcAddress = htlcAddressP2TR
default:
return nil, errors.New("unknown script version")
} }
case swap.TypeOut: case swap.TypeOut:
swapType = clientrpc.SwapType_LOOP_OUT swapType = clientrpc.SwapType_LOOP_OUT
htlcAddressP2WSH = loopSwap.HtlcAddressP2WSH.EncodeAddress()
htlcAddress = htlcAddressP2WSH switch scriptVer {
case swap.HtlcV2:
htlcAddressP2WSH = loopSwap.HtlcAddressP2WSH.EncodeAddress()
htlcAddress = htlcAddressP2WSH
case swap.HtlcV3:
htlcAddressP2TR = loopSwap.HtlcAddressP2TR.EncodeAddress()
htlcAddress = htlcAddressP2TR
default:
return nil, errors.New("unknown script version")
}
default: default:
return nil, errors.New("unknown swap type") return nil, errors.New("unknown swap type")
@ -245,6 +273,7 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) (
InitiationTime: loopSwap.InitiationTime.UnixNano(), InitiationTime: loopSwap.InitiationTime.UnixNano(),
LastUpdateTime: loopSwap.LastUpdate.UnixNano(), LastUpdateTime: loopSwap.LastUpdate.UnixNano(),
HtlcAddress: htlcAddress, HtlcAddress: htlcAddress,
HtlcAddressP2Tr: htlcAddressP2TR,
HtlcAddressP2Wsh: htlcAddressP2WSH, HtlcAddressP2Wsh: htlcAddressP2WSH,
HtlcAddressNp2Wsh: htlcAddressNP2WSH, HtlcAddressNp2Wsh: htlcAddressNP2WSH,
Type: swapType, Type: swapType,

@ -24,6 +24,7 @@ func TestProtocolVersionSanity(t *testing.T) {
ProtocolVersionLoopOutCancel, ProtocolVersionLoopOutCancel,
ProtocolVersionProbe, ProtocolVersionProbe,
ProtocolVersionRoutingPlugin, ProtocolVersionRoutingPlugin,
ProtocolVersionTaproot,
} }
rpcVersions := [...]looprpc.ProtocolVersion{ rpcVersions := [...]looprpc.ProtocolVersion{
@ -37,6 +38,7 @@ func TestProtocolVersionSanity(t *testing.T) {
looprpc.ProtocolVersion_LOOP_OUT_CANCEL, looprpc.ProtocolVersion_LOOP_OUT_CANCEL,
looprpc.ProtocolVersion_PROBE, looprpc.ProtocolVersion_PROBE,
looprpc.ProtocolVersion_ROUTING_PLUGIN, looprpc.ProtocolVersion_ROUTING_PLUGIN,
looprpc.ProtocolVersion_TAPROOT,
} }
require.Equal(t, len(versions), len(rpcVersions)) require.Equal(t, len(versions), len(rpcVersions))

@ -58,6 +58,8 @@ type loopInSwap struct {
htlc *swap.Htlc htlc *swap.Htlc
htlcP2TR *swap.Htlc
htlcP2WSH *swap.Htlc htlcP2WSH *swap.Htlc
htlcNP2WSH *swap.Htlc htlcNP2WSH *swap.Htlc
@ -405,6 +407,11 @@ func validateLoopInContract(lnd *lndclient.LndServices,
// initHtlcs creates and updates the native and nested segwit htlcs // initHtlcs creates and updates the native and nested segwit htlcs
// of the loopInSwap. // of the loopInSwap.
func (s *loopInSwap) initHtlcs() error { func (s *loopInSwap) initHtlcs() error {
htlcP2TR, err := s.swapKit.getHtlc(swap.HtlcP2TR)
if err != nil {
return err
}
htlcP2WSH, err := s.swapKit.getHtlc(swap.HtlcP2WSH) htlcP2WSH, err := s.swapKit.getHtlc(swap.HtlcP2WSH)
if err != nil { if err != nil {
return err return err
@ -418,7 +425,9 @@ func (s *loopInSwap) initHtlcs() error {
// Log htlc addresses for debugging. // Log htlc addresses for debugging.
s.swapKit.log.Infof("Htlc address (P2WSH): %v", htlcP2WSH.Address) s.swapKit.log.Infof("Htlc address (P2WSH): %v", htlcP2WSH.Address)
s.swapKit.log.Infof("Htlc address (NP2WSH): %v", htlcNP2WSH.Address) s.swapKit.log.Infof("Htlc address (NP2WSH): %v", htlcNP2WSH.Address)
s.swapKit.log.Infof("P2TR address (NP2WSH): %v", htlcP2TR.Address)
s.htlcP2TR = htlcP2TR
s.htlcP2WSH = htlcP2WSH s.htlcP2WSH = htlcP2WSH
s.htlcNP2WSH = htlcNP2WSH s.htlcNP2WSH = htlcNP2WSH
@ -432,6 +441,7 @@ func (s *loopInSwap) sendUpdate(ctx context.Context) error {
info.HtlcAddressP2WSH = s.htlcP2WSH.Address info.HtlcAddressP2WSH = s.htlcP2WSH.Address
info.HtlcAddressNP2WSH = s.htlcNP2WSH.Address info.HtlcAddressNP2WSH = s.htlcNP2WSH.Address
info.HtlcAddressP2TR = s.htlcP2TR.Address
info.ExternalHtlc = s.ExternalHtlc info.ExternalHtlc = s.ExternalHtlc
select { select {
@ -600,15 +610,8 @@ func (s *loopInSwap) waitForHtlcConf(globalCtx context.Context) (
notifier := s.lnd.ChainNotifier notifier := s.lnd.ChainNotifier
confChanP2WSH, confErrP2WSH, err := notifier.RegisterConfirmationsNtfn( confChanP2TR, confErrP2TR, err := notifier.RegisterConfirmationsNtfn(
ctx, s.htlcTxHash, s.htlcP2WSH.PkScript, 1, s.InitiationHeight, ctx, s.htlcTxHash, s.htlcP2TR.PkScript, 1, s.InitiationHeight,
)
if err != nil {
return nil, err
}
confChanNP2WSH, confErrNP2WSH, err := notifier.RegisterConfirmationsNtfn(
ctx, s.htlcTxHash, s.htlcNP2WSH.PkScript, 1, s.InitiationHeight,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -618,22 +621,13 @@ func (s *loopInSwap) waitForHtlcConf(globalCtx context.Context) (
for conf == nil { for conf == nil {
select { select {
// P2WSH htlc confirmed. // P2TR htlc confirmed.
case conf = <-confChanP2WSH: case conf = <-confChanP2TR:
s.htlc = s.htlcP2WSH s.htlc = s.htlcP2TR
s.log.Infof("P2WSH htlc confirmed") s.log.Infof("P2TR htlc confirmed")
// NP2WSH htlc confirmed.
case conf = <-confChanNP2WSH:
s.htlc = s.htlcNP2WSH
s.log.Infof("NP2WSH htlc confirmed")
// Conf ntfn error.
case err := <-confErrP2WSH:
return nil, err
// Conf ntfn error. // Conf ntfn error.
case err := <-confErrNP2WSH: case err = <-confErrP2TR:
return nil, err return nil, err
// Keep up with block height. // Keep up with block height.
@ -692,10 +686,10 @@ func (s *loopInSwap) publishOnChainHtlc(ctx context.Context) (bool, error) {
s.log.Infof("Publishing on chain HTLC with fee rate %v", feeRate) s.log.Infof("Publishing on chain HTLC with fee rate %v", feeRate)
// Internal loop-in is always P2WSH. // Internal loop-in is always P2TR.
tx, err := s.lnd.WalletKit.SendOutputs( tx, err := s.lnd.WalletKit.SendOutputs(
ctx, []*wire.TxOut{{ ctx, []*wire.TxOut{{
PkScript: s.htlcP2WSH.PkScript, PkScript: s.htlcP2TR.PkScript,
Value: int64(s.LoopInContract.AmountRequested), Value: int64(s.LoopInContract.AmountRequested),
}}, feeRate, labels.LoopInHtlcLabel(swap.ShortHash(&s.hash)), }}, feeRate, labels.LoopInHtlcLabel(swap.ShortHash(&s.hash)),
) )
@ -944,10 +938,20 @@ func (s *loopInSwap) publishTimeoutTx(ctx context.Context,
return s.htlc.GenTimeoutWitness(sig), nil return s.htlc.GenTimeoutWitness(sig), nil
} }
// TODO(arshbot): replace with a more holistic Script func
var witnessScript []byte
var trHtlc *swap.HtlcScriptV3
trHtlc, ok := s.htlc.HtlcScript.(*swap.HtlcScriptV3)
if !ok {
witnessScript = s.htlc.Script()
} else {
witnessScript = trHtlc.TimeoutScript
}
sequence := uint32(0) sequence := uint32(0)
timeoutTx, err := s.sweeper.CreateSweepTx( timeoutTx, err := s.sweeper.CreateSweepTx(
ctx, s.height, sequence, s.htlc, *htlcOutpoint, s.SenderKey, ctx, s.height, sequence, s.htlc, *htlcOutpoint, s.SenderKey,
witnessFunc, htlcValue, fee, s.timeoutAddr, witnessScript, witnessFunc, htlcValue, fee, s.timeoutAddr,
) )
if err != nil { if err != nil {
return 0, err return 0, err

@ -345,8 +345,8 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool,
ctx := newLoopInTestContext(t) ctx := newLoopInTestContext(t)
cfg := newSwapConfig(&ctx.lnd.LndServices, ctx.store, ctx.server) cfg := newSwapConfig(&ctx.lnd.LndServices, ctx.store, ctx.server)
senderKey := [33]byte{4} senderKey := []byte{4}
receiverKey := [33]byte{5} receiverKey := []byte{5}
contract := &loopdb.LoopInContract{ contract := &loopdb.LoopInContract{
HtlcConfTarget: 2, HtlcConfTarget: 2,

@ -304,7 +304,7 @@ func (s *loopOutSwap) sendUpdate(ctx context.Context) error {
info := s.swapInfo() info := s.swapInfo()
s.log.Infof("Loop out swap state: %v", info.State) s.log.Infof("Loop out swap state: %v", info.State)
info.HtlcAddressP2WSH = s.htlc.Address info.HtlcAddressP2TR = s.htlc.Address
select { select {
case s.statusChan <- *info: case s.statusChan <- *info:
@ -488,6 +488,7 @@ func (s *loopOutSwap) executeSwap(globalCtx context.Context) error {
htlcOutpoint, htlcValue, err := swap.GetScriptOutput( htlcOutpoint, htlcValue, err := swap.GetScriptOutput(
txConf.Tx, s.htlc.PkScript, txConf.Tx, s.htlc.PkScript,
) )
if err != nil { if err != nil {
return err return err
} }
@ -857,6 +858,7 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
ctx, cancel := context.WithCancel(globalCtx) ctx, cancel := context.WithCancel(globalCtx)
defer cancel() defer cancel()
htlcConfChan, htlcErrChan, err := htlcConfChan, htlcErrChan, err :=
s.lnd.ChainNotifier.RegisterConfirmationsNtfn( s.lnd.ChainNotifier.RegisterConfirmationsNtfn(
ctx, s.htlcTxHash, s.htlc.PkScript, ctx, s.htlcTxHash, s.htlc.PkScript,
@ -950,6 +952,7 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
// Unexpected error on the confirm channel happened, // Unexpected error on the confirm channel happened,
// abandon the swap. // abandon the swap.
case err := <-htlcErrChan: case err := <-htlcErrChan:
s.log.Infof(err.Error())
return nil, err return nil, err
// Htlc got confirmed, continue to sweeping. // Htlc got confirmed, continue to sweeping.
@ -1284,10 +1287,20 @@ func (s *loopOutSwap) sweep(ctx context.Context,
} }
} }
// TODO(arshbot): replace with a more holistic Script func
var witnessScript []byte
var trHtlc *swap.HtlcScriptV3
trHtlc, ok := s.htlc.HtlcScript.(*swap.HtlcScriptV3)
if !ok {
witnessScript = s.htlc.Script()
} else {
witnessScript = trHtlc.ClaimScript
}
// Create sweep tx. // Create sweep tx.
sweepTx, err := s.sweeper.CreateSweepTx( sweepTx, err := s.sweeper.CreateSweepTx(
ctx, s.height, s.htlc.SuccessSequence(), s.htlc, htlcOutpoint, ctx, s.height, s.htlc.SuccessSequence(), s.htlc, htlcOutpoint,
s.ReceiverKey, witnessFunc, htlcValue, fee, s.DestAddr, s.ReceiverKey, witnessScript, witnessFunc, htlcValue, fee, s.DestAddr,
) )
if err != nil { if err != nil {
return err return err

@ -71,7 +71,7 @@ func newServerMock(lnd *test.LndMockServices) *serverMock {
} }
func (s *serverMock) NewLoopOutSwap(_ context.Context, swapHash lntypes.Hash, func (s *serverMock) NewLoopOutSwap(_ context.Context, swapHash lntypes.Hash,
amount btcutil.Amount, _ int32, _ [33]byte, _ time.Time, amount btcutil.Amount, _ int32, _ []byte, _ time.Time,
_ string) (*newLoopOutResponse, error) { _ string) (*newLoopOutResponse, error) {
_, senderKey := test.CreateKey(100) _, senderKey := test.CreateKey(100)
@ -92,11 +92,8 @@ func (s *serverMock) NewLoopOutSwap(_ context.Context, swapHash lntypes.Hash,
return nil, err return nil, err
} }
var senderKeyArray [33]byte
copy(senderKeyArray[:], senderKey.SerializeCompressed())
return &newLoopOutResponse{ return &newLoopOutResponse{
senderKey: senderKeyArray, senderKey: senderKey.SerializeCompressed(),
swapInvoice: swapPayReqString, swapInvoice: swapPayReqString,
prepayInvoice: prePayReqString, prepayInvoice: prePayReqString,
}, nil }, nil

@ -215,7 +215,7 @@ func NewHtlc(version ScriptVersion, cltvExpiry int32,
// Generate a tapscript address from our tree // Generate a tapscript address from our tree
address, err = btcutil.NewAddressTaproot( address, err = btcutil.NewAddressTaproot(
schnorr.SerializePubKey(trHtlc.taprootKey), chainParams, schnorr.SerializePubKey(trHtlc.TaprootKey), chainParams,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -239,24 +239,6 @@ func NewHtlc(version ScriptVersion, cltvExpiry int32,
Address: address, Address: address,
SigScript: sigScript, SigScript: sigScript,
}, nil }, nil
/*
{
HtlcScript:
timeoutScript []byte
claimScript []byte
internalPubKey *secp.PublicKey
senderKey [33]byte
},
Hash: preimage,
Version: HtlcV3,
PkScript: p2trPkScript or nil
OutputType: HtlcP2WSH,
ChainParams: chainParams,
Address: tapScriptAddr,
SigScript: nil,
}
*/
} }
// GenSuccessWitness returns the success script to spend this htlc with // GenSuccessWitness returns the success script to spend this htlc with
@ -564,11 +546,11 @@ func (h *HtlcScriptV2) SuccessSequence() uint32 {
// HtlcScriptV2 encapsulates the htlc v2 script. // HtlcScriptV2 encapsulates the htlc v2 script.
type HtlcScriptV3 struct { type HtlcScriptV3 struct {
timeoutScript []byte TimeoutScript []byte
claimScript []byte ClaimScript []byte
taprootKey *secp.PublicKey TaprootKey *secp.PublicKey
internalPubKey *secp.PublicKey InternalPubKey *secp.PublicKey
senderKey []byte SenderKey []byte
} }
func newHTLCScriptV3( func newHTLCScriptV3(
@ -634,18 +616,18 @@ func newHTLCScriptV3(
) )
return &HtlcScriptV3{ return &HtlcScriptV3{
timeoutScript: timeoutPathScript, TimeoutScript: timeoutPathScript,
claimScript: claimPathScript, ClaimScript: claimPathScript,
taprootKey: taprootKey, TaprootKey: taprootKey,
internalPubKey: internalPubKey, InternalPubKey: internalPubKey,
senderKey: senderHtlcKey, SenderKey: senderHtlcKey,
}, nil }, nil
} }
func (h *HtlcScriptV3) genControlBlock(leafScript []byte) ([]byte, error) { func (h *HtlcScriptV3) genControlBlock(leafScript []byte) ([]byte, error) {
var outputKeyYIsOdd bool var outputKeyYIsOdd bool
if h.taprootKey.SerializeCompressed()[0] == secp.PubKeyFormatCompressedOdd { if h.TaprootKey.SerializeCompressed()[0] == secp.PubKeyFormatCompressedOdd {
outputKeyYIsOdd = true outputKeyYIsOdd = true
} }
@ -653,7 +635,7 @@ func (h *HtlcScriptV3) genControlBlock(leafScript []byte) ([]byte, error) {
proof := leaf.TapHash() proof := leaf.TapHash()
controlBlock := txscript.ControlBlock{ controlBlock := txscript.ControlBlock{
InternalKey: h.internalPubKey, InternalKey: h.InternalPubKey,
OutputKeyYIsOdd: outputKeyYIsOdd, OutputKeyYIsOdd: outputKeyYIsOdd,
LeafVersion: txscript.BaseLeafVersion, LeafVersion: txscript.BaseLeafVersion,
InclusionProof: proof[:], InclusionProof: proof[:],
@ -668,23 +650,23 @@ func (h *HtlcScriptV3) genControlBlock(leafScript []byte) ([]byte, error) {
func (h *HtlcScriptV3) genSuccessWitness(signature []byte, preimage lntypes.Preimage) wire.TxWitness { func (h *HtlcScriptV3) genSuccessWitness(signature []byte, preimage lntypes.Preimage) wire.TxWitness {
// TODO: Unsilence errors // TODO(arshbot): Unsilence errors
controlBlockBytes, _ := h.genControlBlock(h.timeoutScript) controlBlockBytes, _ := h.genControlBlock(h.TimeoutScript)
return wire.TxWitness{ return wire.TxWitness{
preimage[:], preimage[:],
signature, signature,
h.claimScript, h.ClaimScript,
controlBlockBytes, controlBlockBytes,
} }
} }
func (h *HtlcScriptV3) GenTimeoutWitness(senderSig []byte) wire.TxWitness { func (h *HtlcScriptV3) GenTimeoutWitness(senderSig []byte) wire.TxWitness {
// TODO: Unsilence errors // TODO(arshbot): Unsilence errors
controlBlockBytes, _ := h.genControlBlock(h.claimScript) controlBlockBytes, _ := h.genControlBlock(h.ClaimScript)
return wire.TxWitness{ return wire.TxWitness{
senderSig, senderSig,
h.timeoutScript, h.TimeoutScript,
controlBlockBytes, controlBlockBytes,
} }
} }
@ -706,5 +688,5 @@ func (h *HtlcScriptV3) MaxTimeoutWitnessSize() int {
} }
func (h *HtlcScriptV3) SuccessSequence() uint32 { func (h *HtlcScriptV3) SuccessSequence() uint32 {
return 10 return 1
} }

@ -398,7 +398,7 @@ func TestHtlcV3(t *testing.T) {
require.True(t, ok) require.True(t, ok)
sig := signTx( sig := signTx(
tx, senderPrivKey, txscript.NewBaseTapLeaf(trHtlc.claimScript), tx, senderPrivKey, txscript.NewBaseTapLeaf(trHtlc.ClaimScript),
) )
return htlc.genSuccessWitness(sig, preimage) return htlc.genSuccessWitness(sig, preimage)
@ -414,7 +414,7 @@ func TestHtlcV3(t *testing.T) {
require.True(t, ok) require.True(t, ok)
sig := signTx( sig := signTx(
tx, receiverPrivKey, txscript.NewBaseTapLeaf(trHtlc.timeoutScript), tx, receiverPrivKey, txscript.NewBaseTapLeaf(trHtlc.TimeoutScript),
) )
return htlc.GenTimeoutWitness(sig) return htlc.GenTimeoutWitness(sig)

@ -23,7 +23,7 @@ type Sweeper struct {
func (s *Sweeper) CreateSweepTx( func (s *Sweeper) CreateSweepTx(
globalCtx context.Context, height int32, sequence uint32, globalCtx context.Context, height int32, sequence uint32,
htlc *swap.Htlc, htlcOutpoint wire.OutPoint, htlc *swap.Htlc, htlcOutpoint wire.OutPoint,
keyBytes []byte, keyBytes, witnessScript []byte,
witnessFunc func(sig []byte) (wire.TxWitness, error), witnessFunc func(sig []byte) (wire.TxWitness, error),
amount, fee btcutil.Amount, amount, fee btcutil.Amount,
destAddr btcutil.Address) (*wire.MsgTx, error) { destAddr btcutil.Address) (*wire.MsgTx, error) {
@ -52,18 +52,17 @@ func (s *Sweeper) CreateSweepTx(
}) })
// Generate a signature for the swap htlc transaction. // Generate a signature for the swap htlc transaction.
key, err := btcec.ParsePubKey(keyBytes) key, err := btcec.ParsePubKey(keyBytes)
if err != nil { if err != nil {
return nil, err return nil, err
} }
signDesc := lndclient.SignDescriptor{ signDesc := lndclient.SignDescriptor{
WitnessScript: htlc.Script(), WitnessScript: witnessScript,
Output: &wire.TxOut{ Output: &wire.TxOut{
Value: int64(amount), Value: int64(amount),
}, },
HashType: txscript.SigHashAll, HashType: txscript.SigHashDefault,
InputIndex: 0, InputIndex: 0,
KeyDesc: keychain.KeyDescriptor{ KeyDesc: keychain.KeyDescriptor{
PubKey: key, PubKey: key,

Loading…
Cancel
Save