From 60d3374a126b80994cc0c36934f183b48d44bc22 Mon Sep 17 00:00:00 2001 From: Harsha Goli Date: Mon, 21 Mar 2022 12:20:28 -0400 Subject: [PATCH] throwaway: refactor of htlc.go complete. we use slices across the board now --- loopdb/loop.go | 4 +- loopin.go | 9 ++- swap/htlc.go | 43 +++++----- swap/htlc_test.go | 196 ++++++++++------------------------------------ sweep/sweeper.go | 4 +- 5 files changed, 76 insertions(+), 180 deletions(-) diff --git a/loopdb/loop.go b/loopdb/loop.go index 07d9d4b..10d4e6b 100644 --- a/loopdb/loop.go +++ b/loopdb/loop.go @@ -20,11 +20,11 @@ type SwapContract struct { // SenderKey is the key of the sender that will be used in the on-chain // HTLC. - SenderKey [33]byte + SenderKey []byte // ReceiverKey is the of the receiver that will be used in the on-chain // HTLC. - ReceiverKey [33]byte + ReceiverKey []byte // CltvExpiry is the total absolute CLTV expiry of the swap. CltvExpiry int32 diff --git a/loopin.go b/loopin.go index 3863444..06328a9 100644 --- a/loopin.go +++ b/loopin.go @@ -151,8 +151,11 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig, if err != nil { return nil, err } + + senderKeySlice := keyDesc.PubKey.SerializeCompressed() + var senderKey [33]byte - copy(senderKey[:], keyDesc.PubKey.SerializeCompressed()) + copy(senderKey[:], senderKeySlice) // Create the swap invoice in lnd. _, swapInvoice, err := cfg.lnd.Client.AddInvoice( @@ -236,8 +239,8 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig, SwapContract: loopdb.SwapContract{ InitiationHeight: currentHeight, InitiationTime: initiationTime, - ReceiverKey: swapResp.receiverKey, - SenderKey: senderKey, + ReceiverKey: swapResp.receiverKey[:], + SenderKey: senderKeySlice, Preimage: swapPreimage, AmountRequested: request.Amount, CltvExpiry: swapResp.expiry, diff --git a/swap/htlc.go b/swap/htlc.go index 041d6fd..18abf07 100644 --- a/swap/htlc.go +++ b/swap/htlc.go @@ -89,7 +89,7 @@ type Htlc struct { } var ( - quoteKey [33]byte + quoteKey []byte quoteHash lntypes.Hash @@ -136,7 +136,7 @@ func (h HtlcOutputType) String() string { // NewHtlc returns a new instance. func NewHtlc(version ScriptVersion, cltvExpiry int32, - senderKey, receiverKey [33]byte, + senderKey, receiverKey []byte, hash lntypes.Hash, outputType HtlcOutputType, chainParams *chaincfg.Params) (*Htlc, error) { @@ -226,7 +226,7 @@ func NewHtlc(version ScriptVersion, cltvExpiry int32, } // Generate a tapscript address from our tree - address, err := btcutil.NewAddressTaproot( + address, err = btcutil.NewAddressTaproot( schnorr.SerializePubKey(trHtlc.taprootKey), &chaincfg.RegressionNetParams, ) if err != nil { @@ -323,7 +323,7 @@ type HtlcScriptV1 struct { // OP_ENDIF // OP_CHECKSIG func newHTLCScriptV1(cltvExpiry int32, senderHtlcKey, - receiverHtlcKey [33]byte, swapHash lntypes.Hash) (*HtlcScriptV1, error) { + receiverHtlcKey []byte, swapHash lntypes.Hash) (*HtlcScriptV1, error) { builder := txscript.NewScriptBuilder() @@ -337,7 +337,7 @@ func newHTLCScriptV1(cltvExpiry int32, senderHtlcKey, builder.AddData(input.Ripemd160H(swapHash[:])) builder.AddOp(txscript.OP_EQUALVERIFY) - builder.AddData(receiverHtlcKey[:]) + builder.AddData(receiverHtlcKey) builder.AddOp(txscript.OP_ELSE) @@ -347,7 +347,7 @@ func newHTLCScriptV1(cltvExpiry int32, senderHtlcKey, builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY) builder.AddOp(txscript.OP_DROP) - builder.AddData(senderHtlcKey[:]) + builder.AddData(senderHtlcKey) builder.AddOp(txscript.OP_ENDIF) @@ -440,7 +440,7 @@ func (h *HtlcScriptV1) SuccessSequence() uint32 { // HtlcScriptV2 encapsulates the htlc v2 script. type HtlcScriptV2 struct { script []byte - senderKey [33]byte + senderKey []byte } // newHTLCScriptV2 construct an HtlcScipt with the HTLC V2 witness script. @@ -453,17 +453,17 @@ type HtlcScriptV2 struct { // OP_CHECKSEQUENCEVERIFY // OP_ENDIF func newHTLCScriptV2(cltvExpiry int32, senderHtlcKey, - receiverHtlcKey [33]byte, swapHash lntypes.Hash) (*HtlcScriptV2, error) { + receiverHtlcKey []byte, swapHash lntypes.Hash) (*HtlcScriptV2, error) { builder := txscript.NewScriptBuilder() - builder.AddData(receiverHtlcKey[:]) + builder.AddData(receiverHtlcKey) builder.AddOp(txscript.OP_CHECKSIG) builder.AddOp(txscript.OP_NOTIF) builder.AddOp(txscript.OP_DUP) builder.AddOp(txscript.OP_HASH160) - senderHtlcKeyHash := sha256.Sum256(senderHtlcKey[:]) + senderHtlcKeyHash := sha256.Sum256(senderHtlcKey) builder.AddData(input.Ripemd160H(senderHtlcKeyHash[:])) builder.AddOp(txscript.OP_EQUALVERIFY) @@ -576,11 +576,11 @@ type HtlcScriptV3 struct { claimScript []byte taprootKey *secp.PublicKey internalPubKey *secp.PublicKey - senderKey [33]byte + senderKey []byte } func newHTLCScriptV3( - cltvExpiry int32, senderHtlcKey, receiverHtlcKey [33]byte, swapHash lntypes.Hash) (*HtlcScriptV3, error) { + cltvExpiry int32, receiverHtlcKey, senderHtlcKey []byte, swapHash lntypes.Hash) (*HtlcScriptV3, error) { /* CLAIM PATH @@ -589,7 +589,7 @@ func newHTLCScriptV3( */ builder := txscript.NewScriptBuilder() - builder.AddData(receiverHtlcKey[:]) + builder.AddData(receiverHtlcKey) builder.AddOp(txscript.OP_CHECKSIGVERIFY) builder.AddOp(txscript.OP_SIZE) builder.AddInt64(32) @@ -611,7 +611,7 @@ func newHTLCScriptV3( OP_CHECKSIGVERIFY OP_CHECKLOCKTIMEVERIFY */ builder = txscript.NewScriptBuilder() - builder.AddData(senderHtlcKey[:]) + builder.AddData(senderHtlcKey) builder.AddOp(txscript.OP_CHECKSIGVERIFY) builder.AddInt64(int64(cltvExpiry)) builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY) @@ -627,9 +627,12 @@ func newHTLCScriptV3( ) internalPubKey, err := btcec.ParsePubKey(randomPub) + if err != nil { + return nil, err + } tree := txscript.AssembleTaprootScriptTree( - txscript.NewBaseTapLeaf(timeoutPathScript), + txscript.NewBaseTapLeaf(claimPathScript), txscript.NewBaseTapLeaf(timeoutPathScript), ) @@ -671,13 +674,13 @@ func (h *HtlcScriptV3) genControlBlock(leafScript []byte) ([]byte, error) { return controlBlockBytes, nil } -func (h *HtlcScriptV3) genSuccessWitness(receiverSig []byte, preimage lntypes.Preimage) wire.TxWitness { +func (h *HtlcScriptV3) genSuccessWitness(signature []byte, preimage lntypes.Preimage) wire.TxWitness { // TODO: Unsilence errors - controlBlockBytes, _ := h.genControlBlock(h.claimScript) + controlBlockBytes, _ := h.genControlBlock(h.timeoutScript) return wire.TxWitness{ preimage[:], - receiverSig, + signature, h.claimScript, controlBlockBytes, } @@ -686,7 +689,7 @@ func (h *HtlcScriptV3) genSuccessWitness(receiverSig []byte, preimage lntypes.Pr func (h *HtlcScriptV3) GenTimeoutWitness(senderSig []byte) wire.TxWitness { // TODO: Unsilence errors - controlBlockBytes, _ := h.genControlBlock(h.timeoutScript) + controlBlockBytes, _ := h.genControlBlock(h.claimScript) return wire.TxWitness{ senderSig, h.timeoutScript, @@ -711,5 +714,5 @@ func (h *HtlcScriptV3) MaxTimeoutWitnessSize() int { } func (h *HtlcScriptV3) SuccessSequence() uint32 { - return 0 + return 10 } diff --git a/swap/htlc_test.go b/swap/htlc_test.go index 669c5cd..f7a9525 100644 --- a/swap/htlc_test.go +++ b/swap/htlc_test.go @@ -3,7 +3,6 @@ package swap import ( "bytes" "crypto/sha256" - "encoding/hex" "fmt" "testing" @@ -128,19 +127,11 @@ func TestHtlcV2(t *testing.T) { senderPrivKey, senderPubKey := test.CreateKey(1) receiverPrivKey, receiverPubKey := test.CreateKey(2) - var ( - senderKey [33]byte - receiverKey [33]byte - ) - copy(senderKey[:], senderPubKey.SerializeCompressed()) - copy(receiverKey[:], receiverPubKey.SerializeCompressed()) - hash := sha256.Sum256(testPreimage[:]) // Create the htlc. htlc, err := NewHtlc( - HtlcV2, testCltvExpiry, - senderKey, receiverKey, hash, + HtlcV2, testCltvExpiry, senderPubKey.SerializeCompressed(), receiverPubKey.SerializeCompressed(), hash, HtlcP2WSH, &chaincfg.MainNetParams, ) require.NoError(t, err) @@ -276,12 +267,12 @@ func TestHtlcV2(t *testing.T) { // key. "timeout case cannot spend with wrong key", func(t *testing.T) wire.TxWitness { - bogusKey := [33]byte{0xb, 0xa, 0xd} + bogusKey := []byte{0xb, 0xa, 0xd} // Create the htlc with the bogus key. htlc, err = NewHtlc( HtlcV2, testCltvExpiry, - bogusKey, receiverKey, hash, + bogusKey, receiverPubKey.SerializeCompressed(), hash, HtlcP2WSH, &chaincfg.MainNetParams, ) require.NoError(t, err) @@ -323,50 +314,6 @@ func TestHtlcV2(t *testing.T) { } } -/* - CLAIM PATH - - OP_CHECKSIGVERIFY OP_SIZE 20 OP_EQUALVERIFY OP_RIPEMD160 OP_EQUALVERIFY 1 OP_CHECKSEQUENCEVERIFY -*/ -func createClaimPathLeaf(t *testing.T, recieverHtlcKey [32]byte, swapHash lntypes.Hash) (txscript.TapLeaf, []byte) { - builder := txscript.NewScriptBuilder() - - builder.AddData(recieverHtlcKey[:]) - builder.AddOp(txscript.OP_CHECKSIGVERIFY) - builder.AddOp(txscript.OP_SIZE) - builder.AddInt64(32) - builder.AddOp(txscript.OP_EQUALVERIFY) - builder.AddOp(txscript.OP_HASH160) - builder.AddData(input.Ripemd160H(swapHash[:])) - builder.AddOp(txscript.OP_EQUALVERIFY) - builder.AddInt64(1) - builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY) - script, err := builder.Script() - require.NoError(t, err) - - return txscript.NewBaseTapLeaf(script), script -} - -/* - TIMEOUT PATH - - OP_CHECKSIGVERIFY OP_CHECKLOCKTIMEVERIFY -*/ -func createTimeoutPathLeaf( - t *testing.T, senderHtlcKey [32]byte, timeoutHeight int64) (txscript.TapLeaf, []byte) { - - // Let's add a second script output as well to test the partial reveal. - builder := txscript.NewScriptBuilder() - builder.AddData(senderHtlcKey[:]) - builder.AddOp(txscript.OP_CHECKSIGVERIFY) - builder.AddInt64(timeoutHeight) - builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY) - - script, err := builder.Script() - require.NoError(t, err) - return txscript.NewBaseTapLeaf(script), script -} - func CreateKey(index int32) (*btcec.PrivateKey, *btcec.PublicKey) { // Avoid all zeros, because it results in an invalid key. privKey, pubKey := btcec.PrivKeyFromBytes( @@ -378,72 +325,33 @@ func CreateKey(index int32) (*btcec.PrivateKey, *btcec.PublicKey) { } func TestHtlcV3(t *testing.T) { - - // const ( - // htlcValue = btcutil.Amount(1 * 10e8) - // cltvExpiry = 24 - // ) - - // var ( - // preimage = [32]byte{1, 2, 3} - // senderKey [32]byte - // receiverKey [32]byte - // ) - - // For the next step, we need a public key. Let's use a special family - // for this. - randomPub, _ := hex.DecodeString( - "03fcb7d1b502bd59f4dbc6cf503e5c280189e0e6dd2d10c4c14d97ed8611" + - "a99178", - ) - - internalPubKey, err := btcec.ParsePubKey(randomPub) - require.NoError(t, err) - preimage := [32]byte{1, 2, 3} p := lntypes.Preimage(preimage) hashedPreimage := sha256.Sum256(p[:]) + value := int64(800_000 - 500) // TODO(guggero): Calculate actual fee. senderPrivKey, senderPubKey := CreateKey(1) receiverPrivKey, receiverPubKey := CreateKey(2) - locktime := 10 + cltvExpiry := int32(10) - var ( - senderKey [32]byte - receiverKey [32]byte - ) - copy(senderKey[:], schnorr.SerializePubKey(senderPubKey)) - copy(receiverKey[:], schnorr.SerializePubKey(receiverPubKey)) - - claimPathLeaf, claimPathScript := createClaimPathLeaf( - t, senderKey, hashedPreimage, - ) - timeoutPathLeaf, timeoutPathScript := createTimeoutPathLeaf( - t, receiverKey, int64(locktime), - ) + shnorrSenderKey := schnorr.SerializePubKey(senderPubKey) + schnorrReceiverKey := schnorr.SerializePubKey(receiverPubKey) - tree := txscript.AssembleTaprootScriptTree( - claimPathLeaf, timeoutPathLeaf, + htlc, err := NewHtlc( + HtlcV3, cltvExpiry, shnorrSenderKey, schnorrReceiverKey, hashedPreimage, HtlcP2TR, &chaincfg.MainNetParams, ) + require.NoError(t, err) - rootHash := tree.RootNode.TapHash() - taprootKey := txscript.ComputeTaprootOutputKey( - internalPubKey, rootHash[:], - ) + var trAddress *btcutil.AddressTaproot + trAddress, ok := htlc.Address.(*btcutil.AddressTaproot) + require.True(t, ok) - // Generate a tapscript address from our tree - tapScriptAddr, err := btcutil.NewAddressTaproot( - schnorr.SerializePubKey(taprootKey), &chaincfg.RegressionNetParams, - ) - require.NoError(t, err) - p2trPkScript, err := txscript.PayToAddrScript(tapScriptAddr) + p2trPkScript, err := txscript.PayToAddrScript(trAddress) require.NoError(t, err) - value := int64(800_000 - 500) // TODO(guggero): Calculate actual fee. - tx := wire.NewMsgTx(2) - tx.LockTime = uint32(locktime) + tx.LockTime = uint32(cltvExpiry) tx.TxIn = []*wire.TxIn{{ PreviousOutPoint: wire.OutPoint{ Hash: chainhash.Hash(sha256.Sum256([]byte{1, 2, 3})), @@ -456,13 +364,6 @@ func TestHtlcV3(t *testing.T) { Value: value, }} - // With the commitment computed we can obtain the bit that denotes if - // the resulting key has an odd y coordinate or not. - var outputKeyYIsOdd bool - if taprootKey.SerializeCompressed()[0] == secp.PubKeyFormatCompressedOdd { - outputKeyYIsOdd = true - } - prevOutFetcher := txscript.NewCannedPrevOutputFetcher( p2trPkScript, 800_000, ) @@ -470,6 +371,18 @@ func TestHtlcV3(t *testing.T) { tx, prevOutFetcher, ) + signTx := func( + tx *wire.MsgTx, privateKey *secp.PrivateKey, leaf txscript.TapLeaf) []byte { + + sig, err := txscript.RawTxInTapscriptSignature( + tx, hashCache, 0, int64(value), p2trPkScript, leaf, + txscript.SigHashDefault, privateKey, + ) + require.NoError(t, err) + + return sig + } + testCases := []struct { name string witness func(*testing.T) wire.TxWitness @@ -478,56 +391,33 @@ func TestHtlcV3(t *testing.T) { { "claim path spend", func(t *testing.T) wire.TxWitness { - proof := timeoutPathLeaf.TapHash() - controlBlock := txscript.ControlBlock{ - InternalKey: internalPubKey, - OutputKeyYIsOdd: outputKeyYIsOdd, - LeafVersion: txscript.BaseLeafVersion, - InclusionProof: proof[:], - } - controlBlockBytes, err := controlBlock.ToBytes() - require.NoError(t, err) + tx.TxIn[0].Sequence = htlc.SuccessSequence() - senderSig, err := txscript.RawTxInTapscriptSignature( - tx, hashCache, 0, int64(value), p2trPkScript, claimPathLeaf, - txscript.SigHashDefault, senderPrivKey, - ) + var trHtlc *HtlcScriptV3 + trHtlc, ok := htlc.HtlcScript.(*HtlcScriptV3) + require.True(t, ok) - require.NoError(t, err) + sig := signTx( + tx, senderPrivKey, txscript.NewBaseTapLeaf(trHtlc.claimScript), + ) - return wire.TxWitness{ - preimage[:], - senderSig, - claimPathScript, - controlBlockBytes, - } + return htlc.genSuccessWitness(sig, preimage) }, true, }, { "timeout path spend", func(t *testing.T) wire.TxWitness { - proof := claimPathLeaf.TapHash() - controlBlock := txscript.ControlBlock{ - InternalKey: internalPubKey, - OutputKeyYIsOdd: outputKeyYIsOdd, - LeafVersion: txscript.BaseLeafVersion, - InclusionProof: proof[:], - } - controlBlockBytes, err := controlBlock.ToBytes() - require.NoError(t, err) + tx.TxIn[0].Sequence = htlc.SuccessSequence() - recipientSig, err := txscript.RawTxInTapscriptSignature( - tx, hashCache, 0, int64(value), p2trPkScript, timeoutPathLeaf, - txscript.SigHashDefault, receiverPrivKey, - ) + var trHtlc *HtlcScriptV3 + trHtlc, ok := htlc.HtlcScript.(*HtlcScriptV3) + require.True(t, ok) - require.NoError(t, err) + sig := signTx( + tx, receiverPrivKey, txscript.NewBaseTapLeaf(trHtlc.timeoutScript), + ) - return wire.TxWitness{ - recipientSig, - timeoutPathScript, - controlBlockBytes, - } + return htlc.GenTimeoutWitness(sig) }, true, }, } diff --git a/sweep/sweeper.go b/sweep/sweeper.go index 39b16d9..71f21f3 100644 --- a/sweep/sweeper.go +++ b/sweep/sweeper.go @@ -23,7 +23,7 @@ type Sweeper struct { func (s *Sweeper) CreateSweepTx( globalCtx context.Context, height int32, sequence uint32, htlc *swap.Htlc, htlcOutpoint wire.OutPoint, - keyBytes [33]byte, + keyBytes []byte, witnessFunc func(sig []byte) (wire.TxWitness, error), amount, fee btcutil.Amount, destAddr btcutil.Address) (*wire.MsgTx, error) { @@ -53,7 +53,7 @@ func (s *Sweeper) CreateSweepTx( // Generate a signature for the swap htlc transaction. - key, err := btcec.ParsePubKey(keyBytes[:]) + key, err := btcec.ParsePubKey(keyBytes) if err != nil { return nil, err }