From 916b83a6ee0f63e97d138349775bf4f50eaf46fa Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Mon, 25 Sep 2017 21:47:39 -0700 Subject: [PATCH] lnwallet: Implement test vectors from BOLT 03, Appendix C. Appendix C of BOLT 03 contains a series of test vectors asserting that commitment, HTLC success, and HTLC timeout transactions are created correctly. Here the test cases are transcribed to Go structs and verified. We also break out some logic need to tests that bypass the constructor and remove some redundant fields. --- lnwallet/channel.go | 146 +++--- lnwallet/common_test.go | 58 +++ lnwallet/script_utils_test.go | 30 -- lnwallet/transactions_test.go | 885 ++++++++++++++++++++++++++++++++++ 4 files changed, 1022 insertions(+), 97 deletions(-) create mode 100644 lnwallet/transactions_test.go diff --git a/lnwallet/channel.go b/lnwallet/channel.go index d2a76850..23f383b8 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -1173,13 +1173,6 @@ type LightningChannel struct { // initiated. pendingAckFeeUpdate *btcutil.Amount - // FundingWitnessScript is the witness script for the 2-of-2 multi-sig - // that opened the channel. - FundingWitnessScript []byte - - fundingTxIn wire.TxIn - fundingP2WSH []byte - // LocalFundingKey is the public key under control by the wallet that // was used for the 2-of-2 funding output which created this channel. LocalFundingKey *btcec.PublicKey @@ -1206,26 +1199,6 @@ type LightningChannel struct { func NewLightningChannel(signer Signer, pCache PreimageCache, state *channeldb.OpenChannel) (*LightningChannel, error) { - localKey := state.LocalChanCfg.MultiSigKey.SerializeCompressed() - remoteKey := state.RemoteChanCfg.MultiSigKey.SerializeCompressed() - multiSigScript, err := genMultiSigScript(localKey, remoteKey) - if err != nil { - return nil, err - } - - var stateHint [StateHintSize]byte - if state.IsInitiator { - stateHint = DeriveStateHintObfuscator( - state.LocalChanCfg.PaymentBasePoint, - state.RemoteChanCfg.PaymentBasePoint, - ) - } else { - stateHint = DeriveStateHintObfuscator( - state.RemoteChanCfg.PaymentBasePoint, - state.LocalChanCfg.PaymentBasePoint, - ) - } - localCommit := state.LocalCommitment remoteCommit := state.RemoteCommitment @@ -1240,29 +1213,27 @@ func NewLightningChannel(signer Signer, pCache PreimageCache, lc := &LightningChannel{ // TODO(roasbeef): tune num sig workers? - sigPool: newSigPool(runtime.NumCPU(), signer), - signer: signer, - pCache: pCache, - stateHintObfuscator: stateHint, - currentHeight: localCommit.CommitHeight, - remoteCommitChain: newCommitmentChain(remoteCommit.CommitHeight), - localCommitChain: newCommitmentChain(localCommit.CommitHeight), - channelState: state, - localChanCfg: &state.LocalChanCfg, - remoteChanCfg: &state.RemoteChanCfg, - localUpdateLog: localUpdateLog, - remoteUpdateLog: remoteUpdateLog, - ChanPoint: &state.FundingOutpoint, - Capacity: state.Capacity, - FundingWitnessScript: multiSigScript, - LocalFundingKey: state.LocalChanCfg.MultiSigKey, - RemoteFundingKey: state.RemoteChanCfg.MultiSigKey, - quit: make(chan struct{}), + sigPool: newSigPool(runtime.NumCPU(), signer), + signer: signer, + pCache: pCache, + currentHeight: localCommit.CommitHeight, + remoteCommitChain: newCommitmentChain(remoteCommit.CommitHeight), + localCommitChain: newCommitmentChain(localCommit.CommitHeight), + channelState: state, + localChanCfg: &state.LocalChanCfg, + remoteChanCfg: &state.RemoteChanCfg, + localUpdateLog: localUpdateLog, + remoteUpdateLog: remoteUpdateLog, + ChanPoint: &state.FundingOutpoint, + Capacity: state.Capacity, + LocalFundingKey: state.LocalChanCfg.MultiSigKey, + RemoteFundingKey: state.RemoteChanCfg.MultiSigKey, + quit: make(chan struct{}), } // With the main channel struct reconstructed, we'll now restore the // commitment state in memory and also the update logs themselves. - err = lc.restoreCommitState( + err := lc.restoreCommitState( &localCommit, &remoteCommit, localUpdateLog, remoteUpdateLog, ) if err != nil { @@ -1272,22 +1243,12 @@ func NewLightningChannel(signer Signer, pCache PreimageCache, // Create the sign descriptor which we'll be using very frequently to // request a signature for the 2-of-2 multi-sig from the signer in // order to complete channel state transitions. - fundingPkScript, err := witnessScriptHash(multiSigScript) + err = lc.createSignDesc() if err != nil { return nil, err } - lc.fundingTxIn = *wire.NewTxIn(&state.FundingOutpoint, nil, nil) - lc.fundingP2WSH = fundingPkScript - lc.signDesc = &SignDescriptor{ - PubKey: lc.localChanCfg.MultiSigKey, - WitnessScript: multiSigScript, - Output: &wire.TxOut{ - PkScript: lc.fundingP2WSH, - Value: int64(lc.channelState.Capacity), - }, - HashType: txscript.SigHashAll, - InputIndex: 0, - } + + lc.createStateHintObfuscator() // Finally, we'll kick of the signature job pool to handle any upcoming // commitment state generation and validation. @@ -1298,6 +1259,53 @@ func NewLightningChannel(signer Signer, pCache PreimageCache, return lc, nil } +// createSignDesc derives the SignDescriptor for commitment transactions from +// other fields on the LightningChannel. +func (lc *LightningChannel) createSignDesc() error { + localKey := lc.localChanCfg.MultiSigKey.SerializeCompressed() + remoteKey := lc.remoteChanCfg.MultiSigKey.SerializeCompressed() + + multiSigScript, err := genMultiSigScript(localKey, remoteKey) + if err != nil { + return err + } + + fundingPkScript, err := witnessScriptHash(multiSigScript) + if err != nil { + return err + } + lc.signDesc = &SignDescriptor{ + PubKey: lc.localChanCfg.MultiSigKey, + WitnessScript: multiSigScript, + Output: &wire.TxOut{ + PkScript: fundingPkScript, + Value: int64(lc.channelState.Capacity), + }, + HashType: txscript.SigHashAll, + InputIndex: 0, + } + + return nil +} + +// createStateHintObfuscator derives and assigns the state hint obfuscator for +// the channel, which is used to encode the commitment height in the sequence +// number of commitment transaction inputs. +func (lc *LightningChannel) createStateHintObfuscator() { + state := lc.channelState + if state.IsInitiator { + lc.stateHintObfuscator = DeriveStateHintObfuscator( + state.LocalChanCfg.PaymentBasePoint, + state.RemoteChanCfg.PaymentBasePoint, + ) + } else { + lc.stateHintObfuscator = DeriveStateHintObfuscator( + state.RemoteChanCfg.PaymentBasePoint, + state.LocalChanCfg.PaymentBasePoint, + ) + } +} + // Stop gracefully shuts down any active goroutines spawned by the // LightningChannel during regular duties. func (lc *LightningChannel) Stop() { @@ -2120,6 +2128,10 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool, return c, nil } +func (lc *LightningChannel) fundingTxIn() wire.TxIn { + return *wire.NewTxIn(&lc.channelState.FundingOutpoint, nil, nil) +} + // createCommitmentTx generates the unsigned commitment transaction for a // commitment view and assigns to txn field. func (lc *LightningChannel) createCommitmentTx(c *commitment, @@ -2183,7 +2195,7 @@ func (lc *LightningChannel) createCommitmentTx(c *commitment, // Generate a new commitment transaction with all the latest // unsettled/un-timed out HTLCs. - commitTx, err := CreateCommitTx(lc.fundingTxIn, keyRing, delay, + commitTx, err := CreateCommitTx(lc.fundingTxIn(), keyRing, delay, delayBalance, p2wkhBalance, c.dustLimit) if err != nil { return err @@ -3340,7 +3352,7 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig *btcec.Signature, // Construct the sighash of the commitment transaction corresponding to // this newly proposed state update. localCommitTx := localCommitmentView.txn - multiSigScript := lc.FundingWitnessScript + multiSigScript := lc.signDesc.WitnessScript hashCache := txscript.NewTxSigHashes(localCommitTx) sigHash, err := txscript.CalcWitnessSigHash(multiSigScript, hashCache, txscript.SigHashAll, localCommitTx, 0, @@ -4010,7 +4022,7 @@ func (lc *LightningChannel) getSignedCommitTx() (*wire.MsgTx, error) { theirKey := lc.remoteChanCfg.MultiSigKey.SerializeCompressed() commitTx.TxIn[0].Witness = SpendMultiSig( - lc.FundingWitnessScript, ourKey, + lc.signDesc.WitnessScript, ourKey, ourSig, theirKey, theirSig, ) @@ -4787,7 +4799,7 @@ func (lc *LightningChannel) CreateCloseProposal(proposedFee btcutil.Amount, theirBalance = theirBalance - proposedFee + commitFee } - closeTx := CreateCooperativeCloseTx(lc.fundingTxIn, + closeTx := CreateCooperativeCloseTx(lc.fundingTxIn(), lc.localChanCfg.DustLimit, lc.remoteChanCfg.DustLimit, ourBalance, theirBalance, localDeliveryScript, remoteDeliveryScript, lc.channelState.IsInitiator) @@ -4857,7 +4869,7 @@ func (lc *LightningChannel) CompleteCooperativeClose(localSig, remoteSig []byte, // Create the transaction used to return the current settled balance // on this active channel back to both parties. In this current model, // the initiator pays full fees for the cooperative close transaction. - closeTx := CreateCooperativeCloseTx(lc.fundingTxIn, + closeTx := CreateCooperativeCloseTx(lc.fundingTxIn(), lc.localChanCfg.DustLimit, lc.remoteChanCfg.DustLimit, ourBalance, theirBalance, localDeliveryScript, remoteDeliveryScript, lc.channelState.IsInitiator) @@ -4881,9 +4893,9 @@ func (lc *LightningChannel) CompleteCooperativeClose(localSig, remoteSig []byte, // Validate the finalized transaction to ensure the output script is // properly met, and that the remote peer supplied a valid signature. - vm, err := txscript.NewEngine(lc.fundingP2WSH, closeTx, 0, - txscript.StandardVerifyFlags, nil, hashCache, - int64(lc.channelState.Capacity)) + prevOut := lc.signDesc.Output + vm, err := txscript.NewEngine(prevOut.PkScript, closeTx, 0, + txscript.StandardVerifyFlags, nil, hashCache, prevOut.Value) if err != nil { return nil, 0, err } diff --git a/lnwallet/common_test.go b/lnwallet/common_test.go index 78e7d1f0..e21d89ef 100644 --- a/lnwallet/common_test.go +++ b/lnwallet/common_test.go @@ -3,6 +3,7 @@ package lnwallet import ( "bytes" "crypto/sha256" + "encoding/hex" "fmt" "sync" @@ -147,3 +148,60 @@ func (m *mockPreimageCache) AddPreimage(preimage []byte) error { return nil } + +// pubkeyFromHex parses a Bitcoin public key from a hex encoded string. +func pubkeyFromHex(keyHex string) (*btcec.PublicKey, error) { + bytes, err := hex.DecodeString(keyHex) + if err != nil { + return nil, err + } + return btcec.ParsePubKey(bytes, btcec.S256()) +} + +// privkeyFromHex parses a Bitcoin private key from a hex encoded string. +func privkeyFromHex(keyHex string) (*btcec.PrivateKey, error) { + bytes, err := hex.DecodeString(keyHex) + if err != nil { + return nil, err + } + key, _ := btcec.PrivKeyFromBytes(btcec.S256(), bytes) + return key, nil + +} + +// pubkeyToHex serializes a Bitcoin public key to a hex encoded string. +func pubkeyToHex(key *btcec.PublicKey) string { + return hex.EncodeToString(key.SerializeCompressed()) +} + +// privkeyFromHex serializes a Bitcoin private key to a hex encoded string. +func privkeyToHex(key *btcec.PrivateKey) string { + return hex.EncodeToString(key.Serialize()) +} + +// signatureFromHex parses a Bitcoin signature from a hex encoded string. +func signatureFromHex(sigHex string) (*btcec.Signature, error) { + bytes, err := hex.DecodeString(sigHex) + if err != nil { + return nil, err + } + return btcec.ParseSignature(bytes, btcec.S256()) +} + +// blockFromHex parses a full Bitcoin block from a hex encoded string. +func blockFromHex(blockHex string) (*btcutil.Block, error) { + bytes, err := hex.DecodeString(blockHex) + if err != nil { + return nil, err + } + return btcutil.NewBlockFromBytes(bytes) +} + +// txFromHex parses a full Bitcoin transaction from a hex encoded string. +func txFromHex(txHex string) (*btcutil.Tx, error) { + bytes, err := hex.DecodeString(txHex) + if err != nil { + return nil, err + } + return btcutil.NewTxFromBytes(bytes) +} diff --git a/lnwallet/script_utils_test.go b/lnwallet/script_utils_test.go index d3ee619e..da5da534 100644 --- a/lnwallet/script_utils_test.go +++ b/lnwallet/script_utils_test.go @@ -1170,33 +1170,3 @@ func TestSpecificationKeyDerivation(t *testing.T) { actualRevocationPrivKeyHex) } } - -// pubkeyFromHex parses a Bitcoin public key from a hex encoded string. -func pubkeyFromHex(keyHex string) (*btcec.PublicKey, error) { - bytes, err := hex.DecodeString(keyHex) - if err != nil { - return nil, err - } - return btcec.ParsePubKey(bytes, btcec.S256()) -} - -// privkeyFromHex parses a Bitcoin private key from a hex encoded string. -func privkeyFromHex(keyHex string) (*btcec.PrivateKey, error) { - bytes, err := hex.DecodeString(keyHex) - if err != nil { - return nil, err - } - key, _ := btcec.PrivKeyFromBytes(btcec.S256(), bytes) - return key, nil - -} - -// pubkeyToHex serializes a Bitcoin public key to a hex encoded string. -func pubkeyToHex(key *btcec.PublicKey) string { - return hex.EncodeToString(key.SerializeCompressed()) -} - -// privkeyFromHex serializes a Bitcoin private key to a hex encoded string. -func privkeyToHex(key *btcec.PrivateKey) string { - return hex.EncodeToString(key.Serialize()) -} diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go new file mode 100644 index 00000000..4b87b66f --- /dev/null +++ b/lnwallet/transactions_test.go @@ -0,0 +1,885 @@ +package lnwallet + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "testing" + + "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/shachain" + "github.com/roasbeef/btcd/btcec" + "github.com/roasbeef/btcd/chaincfg" + "github.com/roasbeef/btcd/chaincfg/chainhash" + "github.com/roasbeef/btcd/wire" + "github.com/roasbeef/btcutil" +) + +/** +* This file implements that different types of transactions used in the +* lightning protocol are created correctly. To do so, the tests use the test +* vectors defined in Appendix B & C of BOLT 03. + */ + +// testContext contains the test parameters defined in Appendix B & C of the +// BOLT 03 spec. +type testContext struct { + netParams *chaincfg.Params + block1 *btcutil.Block + + fundingInputPrivKey *btcec.PrivateKey + localFundingPrivKey *btcec.PrivateKey + localPaymentPrivKey *btcec.PrivateKey + + remoteFundingPubKey *btcec.PublicKey + localFundingPubKey *btcec.PublicKey + localRevocationPubKey *btcec.PublicKey + localPaymentPubKey *btcec.PublicKey + remotePaymentPubKey *btcec.PublicKey + localDelayPubKey *btcec.PublicKey + commitmentPoint *btcec.PublicKey + localPaymentBasePoint *btcec.PublicKey + remotePaymentBasePoint *btcec.PublicKey + + fundingChangeAddress btcutil.Address + fundingInputUtxo *Utxo + fundingInputTxOut *wire.TxOut + fundingTx *btcutil.Tx + fundingOutpoint wire.OutPoint + shortChanID lnwire.ShortChannelID + + htlcs []channeldb.HTLC + + localCsvDelay uint16 + fundingAmount btcutil.Amount + dustLimit btcutil.Amount + feePerKW btcutil.Amount +} + +// htlcDesc is a description used to construct each HTLC in each test case. +type htlcDesc struct { + index int + remoteSigHex string + resolutionTxHex string +} + +// getHTLC constructs an HTLC based on a configured HTLC with auxiliary data +// such as the remote signature from the htlcDesc. The partially defined HTLCs +// originate from the BOLT 03 spec and are contained in the test context. +func (tc *testContext) getHTLC(index int, desc *htlcDesc) (channeldb.HTLC, error) { + signature, err := hex.DecodeString(desc.remoteSigHex) + if err != nil { + return channeldb.HTLC{}, fmt.Errorf( + "Failed to parse serialized signature: %v", err) + } + + htlc := tc.htlcs[desc.index] + return channeldb.HTLC{ + Signature: signature, + RHash: htlc.RHash, + RefundTimeout: htlc.RefundTimeout, + Amt: htlc.Amt, + OutputIndex: int32(index), + Incoming: htlc.Incoming, + }, nil +} + +// newTestContext populates a new testContext struct with the constant +// parameters defined in the BOLT 03 spec. This may return an error if any of +// the serialized parameters cannot be parsed. +func newTestContext() (tc *testContext, err error) { + tc = new(testContext) + + const genesisHash = "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206" + if tc.netParams, err = tc.createNetParams(genesisHash); err != nil { + return + } + + const block1Hex = "0000002006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910fadbb20ea41a8423ea937e76e8151636bf6093b70eaff942930d20576600521fdc30f9858ffff7f20000000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0100f2052a010000001976a9143ca33c2e4446f4a305f23c80df8ad1afdcf652f988ac00000000" + if tc.block1, err = blockFromHex(block1Hex); err != nil { + err = fmt.Errorf("Failed to parse serialized block: %v", err) + return + } + + const fundingInputPrivKeyHex = "6bd078650fcee8444e4e09825227b801a1ca928debb750eb36e6d56124bb20e8" + tc.fundingInputPrivKey, err = privkeyFromHex(fundingInputPrivKeyHex) + if err != nil { + err = fmt.Errorf("Failed to parse serialized privkey: %v", err) + return + } + + const localFundingPrivKeyHex = "30ff4956bbdd3222d44cc5e8a1261dab1e07957bdac5ae88fe3261ef321f3749" + tc.localFundingPrivKey, err = privkeyFromHex(localFundingPrivKeyHex) + if err != nil { + err = fmt.Errorf("Failed to parse serialized privkey: %v", err) + return + } + + const localPaymentPrivKeyHex = "bb13b121cdc357cd2e608b0aea294afca36e2b34cf958e2e6451a2f274694491" + tc.localPaymentPrivKey, err = privkeyFromHex(localPaymentPrivKeyHex) + if err != nil { + err = fmt.Errorf("Failed to parse serialized privkey: %v", err) + return + } + + const localFundingPubKeyHex = "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb" + tc.localFundingPubKey, err = pubkeyFromHex(localFundingPubKeyHex) + if err != nil { + err = fmt.Errorf("Failed to parse serialized pubkey: %v", err) + return + } + + const remoteFundingPubKeyHex = "030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1" + tc.remoteFundingPubKey, err = pubkeyFromHex(remoteFundingPubKeyHex) + if err != nil { + err = fmt.Errorf("Failed to parse serialized pubkey: %v", err) + return + } + + const localRevocationPubKeyHex = "0212a140cd0c6539d07cd08dfe09984dec3251ea808b892efeac3ede9402bf2b19" + tc.localRevocationPubKey, err = pubkeyFromHex(localRevocationPubKeyHex) + if err != nil { + err = fmt.Errorf("Failed to parse serialized pubkey: %v", err) + return + } + + const localPaymentPubKeyHex = "030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e7" + tc.localPaymentPubKey, err = pubkeyFromHex(localPaymentPubKeyHex) + if err != nil { + err = fmt.Errorf("Failed to parse serialized pubkey: %v", err) + return + } + + const remotePaymentPubKeyHex = "0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b" + tc.remotePaymentPubKey, err = pubkeyFromHex(remotePaymentPubKeyHex) + if err != nil { + err = fmt.Errorf("Failed to parse serialized pubkey: %v", err) + return + } + + const localDelayPubKeyHex = "03fd5960528dc152014952efdb702a88f71e3c1653b2314431701ec77e57fde83c" + tc.localDelayPubKey, err = pubkeyFromHex(localDelayPubKeyHex) + if err != nil { + err = fmt.Errorf("Failed to parse serialized pubkey: %v", err) + return + } + + const commitmentPointHex = "025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486" + tc.commitmentPoint, err = pubkeyFromHex(commitmentPointHex) + if err != nil { + err = fmt.Errorf("Failed to parse serialized pubkey: %v", err) + return + } + + const localPaymentBasePointHex = "034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa" + tc.localPaymentBasePoint, err = pubkeyFromHex(localPaymentBasePointHex) + if err != nil { + err = fmt.Errorf("Failed to parse serialized pubkey: %v", err) + return + } + + const remotePaymentBasePointHex = "032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991" + tc.remotePaymentBasePoint, err = pubkeyFromHex(remotePaymentBasePointHex) + if err != nil { + err = fmt.Errorf("Failed to parse serialized pubkey: %v", err) + return + } + + const fundingChangeAddressStr = "tb1q8j3nctjygm62xp0j8jqdlzk34lw0v5hes3jhvy" + tc.fundingChangeAddress, err = btcutil.DecodeAddress( + fundingChangeAddressStr, tc.netParams) + if err != nil { + err = fmt.Errorf("Failed to parse address: %v", err) + return + } + + tc.fundingInputUtxo, tc.fundingInputTxOut, err = tc.extractFundingInput() + if err != nil { + return + } + + const fundingTxHex = "0200000001adbb20ea41a8423ea937e76e8151636bf6093b70eaff942930d20576600521fd000000006b48304502210090587b6201e166ad6af0227d3036a9454223d49a1f11839c1a362184340ef0240220577f7cd5cca78719405cbf1de7414ac027f0239ef6e214c90fcaab0454d84b3b012103535b32d5eb0a6ed0982a0479bbadc9868d9836f6ba94dd5a63be16d875069184ffffffff028096980000000000220020c015c4a6be010e21657068fc2e6a9d02b27ebe4d490a25846f7237f104d1a3cd20256d29010000001600143ca33c2e4446f4a305f23c80df8ad1afdcf652f900000000" + if tc.fundingTx, err = txFromHex(fundingTxHex); err != nil { + err = fmt.Errorf("Failed to parse serialized tx: %v", err) + return + } + + tc.fundingOutpoint = wire.OutPoint{ + Hash: *tc.fundingTx.Hash(), + Index: 0, + } + + tc.shortChanID = lnwire.ShortChannelID{ + BlockHeight: 1, + TxIndex: 0, + TxPosition: 0, + } + + htlcData := []struct { + incoming bool + amount lnwire.MilliSatoshi + expiry uint32 + preimage string + paymentHash PaymentHash + }{ + { + incoming: true, + amount: 1000000, + expiry: 500, + preimage: "0000000000000000000000000000000000000000000000000000000000000000", + }, + { + incoming: true, + amount: 2000000, + expiry: 501, + preimage: "0101010101010101010101010101010101010101010101010101010101010101", + }, + { + incoming: false, + amount: 2000000, + expiry: 502, + preimage: "0202020202020202020202020202020202020202020202020202020202020202", + }, + { + incoming: false, + amount: 3000000, + expiry: 503, + preimage: "0303030303030303030303030303030303030303030303030303030303030303", + }, + { + incoming: true, + amount: 4000000, + expiry: 504, + preimage: "0404040404040404040404040404040404040404040404040404040404040404", + }, + } + + tc.htlcs = make([]channeldb.HTLC, len(htlcData)) + for i, htlc := range htlcData { + preimage, decodeErr := hex.DecodeString(htlc.preimage) + if decodeErr != nil { + err = fmt.Errorf("Failed to decode HTLC preimage: %v", decodeErr) + return + } + + tc.htlcs[i].RHash = sha256.Sum256(preimage) + tc.htlcs[i].Amt = htlc.amount + tc.htlcs[i].RefundTimeout = htlc.expiry + tc.htlcs[i].Incoming = htlc.incoming + } + + tc.localCsvDelay = 144 + tc.fundingAmount = 10000000 + tc.dustLimit = 546 + tc.feePerKW = 15000 + + return +} + +// createNetParams is used by newTestContext to construct new chain parameters +// as required by the BOLT 03 spec. +func (tc *testContext) createNetParams(genesisHashStr string) (*chaincfg.Params, error) { + params := chaincfg.RegressionNetParams + + // Ensure regression net genesis block matches the one listed in BOLT spec. + expectedGenesisHash, err := chainhash.NewHashFromStr(genesisHashStr) + if err != nil { + return nil, err + } + if !params.GenesisHash.IsEqual(expectedGenesisHash) { + err = fmt.Errorf("Expected regression net genesis hash to be %s, "+ + "got %s", expectedGenesisHash, params.GenesisHash) + return nil, err + } + + return ¶ms, nil +} + +// extractFundingInput returns references to the transaction output of the +// coinbase transaction which is used to fund the channel in the test vectors. +func (tc *testContext) extractFundingInput() (*Utxo, *wire.TxOut, error) { + expectedTxHashHex := "fd2105607605d2302994ffea703b09f66b6351816ee737a93e42a841ea20bbad" + expectedTxHash, err := chainhash.NewHashFromStr(expectedTxHashHex) + if err != nil { + return nil, nil, fmt.Errorf("Failed to parse transaction hash: %v", err) + } + + tx, err := tc.block1.Tx(0) + if err != nil { + return nil, nil, fmt.Errorf("Failed to get coinbase transaction from "+ + "block 1: %v", err) + } + txout := tx.MsgTx().TxOut[0] + + var expectedAmount int64 = 5000000000 + if txout.Value != expectedAmount { + return nil, nil, fmt.Errorf("Coinbase transaction output amount from "+ + "block 1 does not match expected output amount: "+ + "expected %v, got %v", expectedAmount, txout.Value) + } + if !tx.Hash().IsEqual(expectedTxHash) { + return nil, nil, fmt.Errorf("Coinbase transaction hash from block 1 "+ + "does not match expected hash: expected %v, got %v", expectedTxHash, + tx.Hash()) + } + + block1Utxo := Utxo{ + AddressType: PubKeyHash, + Value: btcutil.Amount(txout.Value), + OutPoint: wire.OutPoint{ + Hash: *tx.Hash(), + Index: 0, + }, + PkScript: txout.PkScript, + } + return &block1Utxo, txout, nil +} + +// TestCommitmentAndHTLCTransactions checks the test vectors specified in +// BOLT 03, Appendix C. This deterministically generates commitment and second +// level HTLC transactions and checks that they match the expected values. +func TestCommitmentAndHTLCTransactions(t *testing.T) { + t.Parallel() + + tc, err := newTestContext() + if err != nil { + t.Fatal(err) + } + + // Generate random some keys that don't actually matter but need to be set. + var ( + identityKey *btcec.PublicKey + localDelayBasePoint *btcec.PublicKey + ) + generateKeys := []**btcec.PublicKey{ + &identityKey, + &localDelayBasePoint, + } + for _, keyRef := range generateKeys { + privkey, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Fatalf("Failed to generate new key: %v", err) + } + *keyRef = privkey.PubKey() + } + + // Manually construct a new LightningChannel. + channelState := channeldb.OpenChannel{ + ChanType: channeldb.SingleFunder, + ChainHash: *tc.netParams.GenesisHash, + FundingOutpoint: tc.fundingOutpoint, + ShortChanID: tc.shortChanID, + IsInitiator: true, + IdentityPub: identityKey, + LocalChanCfg: channeldb.ChannelConfig{ + ChannelConstraints: channeldb.ChannelConstraints{ + DustLimit: tc.dustLimit, + MaxPendingAmount: lnwire.NewMSatFromSatoshis(tc.fundingAmount), + MaxAcceptedHtlcs: MaxHTLCNumber, + }, + CsvDelay: tc.localCsvDelay, + MultiSigKey: tc.localFundingPubKey, + PaymentBasePoint: tc.localPaymentBasePoint, + HtlcBasePoint: tc.localPaymentBasePoint, + DelayBasePoint: localDelayBasePoint, + }, + RemoteChanCfg: channeldb.ChannelConfig{ + MultiSigKey: tc.remoteFundingPubKey, + PaymentBasePoint: tc.remotePaymentBasePoint, + HtlcBasePoint: tc.remotePaymentBasePoint, + }, + Capacity: tc.fundingAmount, + RevocationProducer: shachain.NewRevocationProducer(zeroHash), + } + signer := &mockSigner{ + privkeys: []*btcec.PrivateKey{ + tc.localFundingPrivKey, tc.localPaymentPrivKey, + }, + netParams: tc.netParams, + } + + // Construct a LightningChannel manually because we don't have nor need all + // of the dependencies. + channel := LightningChannel{ + channelState: &channelState, + signer: signer, + localChanCfg: &channelState.LocalChanCfg, + remoteChanCfg: &channelState.RemoteChanCfg, + } + err = channel.createSignDesc() + if err != nil { + t.Fatalf("Failed to generate channel sign descriptor: %v", err) + } + channel.createStateHintObfuscator() + + // The commitmentPoint is technically hidden in the spec, but we need it to + // generate the correct tweak. + tweak := SingleTweakBytes(tc.commitmentPoint, tc.localPaymentBasePoint) + keys := &commitmentKeyRing{ + commitPoint: tc.commitmentPoint, + localCommitKeyTweak: tweak, + localHtlcKeyTweak: tweak, + localHtlcKey: tc.localPaymentPubKey, + remoteHtlcKey: tc.remotePaymentPubKey, + delayKey: tc.localDelayPubKey, + noDelayKey: tc.remotePaymentPubKey, + revocationKey: tc.localRevocationPubKey, + } + + // testCases encode the raw test vectors specified in Appendix C of BOLT 03. + testCases := []struct { + commitment channeldb.ChannelCommitment + htlcDescs []htlcDesc + expectedCommitmentTxHex string + remoteSigHex string + }{ + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 7000000000, + RemoteBalance: 3000000000, + FeePerKw: 15000, + }, + htlcDescs: []htlcDesc{}, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8002c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311054a56a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022051b75c73198c6deee1a875871c3961832909acd297c6b908d59e3319e5185a46022055c419379c5051a78d00dbbce11b5b664a0c22815fbcc6fcef6b1937c383693901483045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "3045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c0", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 0, + }, + htlcDescs: []htlcDesc{ + { + index: 0, + remoteSigHex: "304402206a6e59f18764a5bf8d4fa45eebc591566689441229c918b480fb2af8cc6a4aeb02205248f273be447684b33e3c8d1d85a8e0ca9fa0bae9ae33f0527ada9c162919a6", + resolutionTxHex: "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219700000000000000000001e8030000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206a6e59f18764a5bf8d4fa45eebc591566689441229c918b480fb2af8cc6a4aeb02205248f273be447684b33e3c8d1d85a8e0ca9fa0bae9ae33f0527ada9c162919a60147304402207cb324fa0de88f452ffa9389678127ebcf4cabe1dd848b8e076c1a1962bf34720220116ed922b12311bd602d67e60d2529917f21c5b82f25ff6506c0f87886b4dfd5012000000000000000000000000000000000000000000000000000000000000000008a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac686800000000", + }, + { + index: 2, + remoteSigHex: "3045022100d5275b3619953cb0c3b5aa577f04bc512380e60fa551762ce3d7a1bb7401cff9022037237ab0dac3fe100cde094e82e2bed9ba0ed1bb40154b48e56aa70f259e608b", + resolutionTxHex: "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219701000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d5275b3619953cb0c3b5aa577f04bc512380e60fa551762ce3d7a1bb7401cff9022037237ab0dac3fe100cde094e82e2bed9ba0ed1bb40154b48e56aa70f259e608b01483045022100c89172099507ff50f4c925e6c5150e871fb6e83dd73ff9fbb72f6ce829a9633f02203a63821d9162e99f9be712a68f9e589483994feae2661e4546cd5b6cec007be501008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000", + }, + { + index: 1, + remoteSigHex: "304402201b63ec807771baf4fdff523c644080de17f1da478989308ad13a58b51db91d360220568939d38c9ce295adba15665fa68f51d967e8ed14a007b751540a80b325f202", + resolutionTxHex: "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219702000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402201b63ec807771baf4fdff523c644080de17f1da478989308ad13a58b51db91d360220568939d38c9ce295adba15665fa68f51d967e8ed14a007b751540a80b325f20201483045022100def389deab09cee69eaa1ec14d9428770e45bcbe9feb46468ecf481371165c2f022015d2e3c46600b2ebba8dcc899768874cc6851fd1ecb3fffd15db1cc3de7e10da012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000", + }, + { + index: 3, + remoteSigHex: "3045022100daee1808f9861b6c3ecd14f7b707eca02dd6bdfc714ba2f33bc8cdba507bb182022026654bf8863af77d74f51f4e0b62d461a019561bb12acb120d3f7195d148a554", + resolutionTxHex: "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219703000000000000000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100daee1808f9861b6c3ecd14f7b707eca02dd6bdfc714ba2f33bc8cdba507bb182022026654bf8863af77d74f51f4e0b62d461a019561bb12acb120d3f7195d148a554014730440220643aacb19bbb72bd2b635bc3f7375481f5981bace78cdd8319b2988ffcc6704202203d27784ec8ad51ed3bd517a05525a5139bb0b755dd719e0054332d186ac0872701008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", + }, + { + index: 4, + remoteSigHex: "304402207e0410e45454b0978a623f36a10626ef17b27d9ad44e2760f98cfa3efb37924f0220220bd8acd43ecaa916a80bd4f919c495a2c58982ce7c8625153f8596692a801d", + resolutionTxHex: "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219704000000000000000001a00f0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207e0410e45454b0978a623f36a10626ef17b27d9ad44e2760f98cfa3efb37924f0220220bd8acd43ecaa916a80bd4f919c495a2c58982ce7c8625153f8596692a801d014730440220549e80b4496803cbc4a1d09d46df50109f546d43fbbf86cd90b174b1484acd5402205f12a4f995cb9bded597eabfee195a285986aa6d93ae5bb72507ebc6a4e2349e012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", + }, + }, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8007e80300000000000022002052bfef0479d7b293c27e0f1eb294bea154c63a3294ef092c19af51409bce0e2ad007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110e0a06a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004730440220275b0c325a5e9355650dc30c0eccfbc7efb23987c24b556b9dfdd40effca18d202206caceb2c067836c51f296740c7ae807ffcbfbf1dd3a0d56b6de9a5b247985f060147304402204fd4928835db1ccdfc40f5c78ce9bd65249b16348df81f0c44328dcdefc97d630220194d3869c38bc732dd87d13d2958015e2fc16829e74cd4377f84d215c0b7060601475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "304402204fd4928835db1ccdfc40f5c78ce9bd65249b16348df81f0c44328dcdefc97d630220194d3869c38bc732dd87d13d2958015e2fc16829e74cd4377f84d215c0b70606", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 647, + }, + htlcDescs: []htlcDesc{ + { + index: 0, + remoteSigHex: "30440220385a5afe75632f50128cbb029ee95c80156b5b4744beddc729ad339c9ca432c802202ba5f48550cad3379ac75b9b4fedb86a35baa6947f16ba5037fb8b11ab343740", + resolutionTxHex: "020000000001018323148ce2419f21ca3d6780053747715832e18ac780931a514b187768882bb60000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220385a5afe75632f50128cbb029ee95c80156b5b4744beddc729ad339c9ca432c802202ba5f48550cad3379ac75b9b4fedb86a35baa6947f16ba5037fb8b11ab3437400147304402205999590b8a79fa346e003a68fd40366397119b2b0cdf37b149968d6bc6fbcc4702202b1e1fb5ab7864931caed4e732c359e0fe3d86a548b557be2246efb1708d579a012000000000000000000000000000000000000000000000000000000000000000008a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac686800000000", + }, + { + index: 2, + remoteSigHex: "304402207ceb6678d4db33d2401fdc409959e57c16a6cb97a30261d9c61f29b8c58d34b90220084b4a17b4ca0e86f2d798b3698ca52de5621f2ce86f80bed79afa66874511b0", + resolutionTxHex: "020000000001018323148ce2419f21ca3d6780053747715832e18ac780931a514b187768882bb60100000000000000000124060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207ceb6678d4db33d2401fdc409959e57c16a6cb97a30261d9c61f29b8c58d34b90220084b4a17b4ca0e86f2d798b3698ca52de5621f2ce86f80bed79afa66874511b00147304402207ff03eb0127fc7c6cae49cc29e2a586b98d1e8969cf4a17dfa50b9c2647720b902205e2ecfda2252956c0ca32f175080e75e4e390e433feb1f8ce9f2ba55648a1dac01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000", + }, + { + index: 1, + remoteSigHex: "304402206a401b29a0dff0d18ec903502c13d83e7ec019450113f4a7655a4ce40d1f65ba0220217723a084e727b6ca0cc8b6c69c014a7e4a01fcdcba3e3993f462a3c574d833", + resolutionTxHex: "020000000001018323148ce2419f21ca3d6780053747715832e18ac780931a514b187768882bb6020000000000000000010a060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206a401b29a0dff0d18ec903502c13d83e7ec019450113f4a7655a4ce40d1f65ba0220217723a084e727b6ca0cc8b6c69c014a7e4a01fcdcba3e3993f462a3c574d83301483045022100d50d067ca625d54e62df533a8f9291736678d0b86c28a61bb2a80cf42e702d6e02202373dde7e00218eacdafb9415fe0e1071beec1857d1af3c6a201a44cbc47c877012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000", + }, + { + index: 3, + remoteSigHex: "30450221009b1c987ba599ee3bde1dbca776b85481d70a78b681a8d84206723e2795c7cac002207aac84ad910f8598c4d1c0ea2e3399cf6627a4e3e90131315bc9f038451ce39d", + resolutionTxHex: "020000000001018323148ce2419f21ca3d6780053747715832e18ac780931a514b187768882bb6030000000000000000010c0a0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221009b1c987ba599ee3bde1dbca776b85481d70a78b681a8d84206723e2795c7cac002207aac84ad910f8598c4d1c0ea2e3399cf6627a4e3e90131315bc9f038451ce39d01483045022100db9dc65291077a52728c622987e9895b7241d4394d6dcb916d7600a3e8728c22022036ee3ee717ba0bb5c45ee84bc7bbf85c0f90f26ae4e4a25a6b4241afa8a3f1cb01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", + }, + { + index: 4, + remoteSigHex: "3045022100cc28030b59f0914f45b84caa983b6f8effa900c952310708c2b5b00781117022022027ba2ccdf94d03c6d48b327f183f6e28c8a214d089b9227f94ac4f85315274f0", + resolutionTxHex: "020000000001018323148ce2419f21ca3d6780053747715832e18ac780931a514b187768882bb604000000000000000001da0d0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100cc28030b59f0914f45b84caa983b6f8effa900c952310708c2b5b00781117022022027ba2ccdf94d03c6d48b327f183f6e28c8a214d089b9227f94ac4f85315274f00147304402202d1a3c0d31200265d2a2def2753ead4959ae20b4083e19553acfffa5dfab60bf022020ede134149504e15b88ab261a066de49848411e15e70f9e6a5462aec2949f8f012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", + }, + }, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8007e80300000000000022002052bfef0479d7b293c27e0f1eb294bea154c63a3294ef092c19af51409bce0e2ad007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110e09c6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040048304502210094bfd8f5572ac0157ec76a9551b6c5216a4538c07cd13a51af4a54cb26fa14320220768efce8ce6f4a5efac875142ff19237c011343670adf9c7ac69704a120d116301483045022100a5c01383d3ec646d97e40f44318d49def817fcd61a0ef18008a665b3e151785502203e648efddd5838981ef55ec954be69c4a652d021e6081a100d034de366815e9b01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "3045022100a5c01383d3ec646d97e40f44318d49def817fcd61a0ef18008a665b3e151785502203e648efddd5838981ef55ec954be69c4a652d021e6081a100d034de366815e9b", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 648, + }, + htlcDescs: []htlcDesc{ + { + index: 2, + remoteSigHex: "3044022062ef2e77591409d60d7817d9bb1e71d3c4a2931d1a6c7c8307422c84f001a251022022dad9726b0ae3fe92bda745a06f2c00f92342a186d84518588cf65f4dfaada8", + resolutionTxHex: "02000000000101579c183eca9e8236a5d7f5dcd79cfec32c497fdc0ec61533cde99ecd436cadd10000000000000000000123060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022062ef2e77591409d60d7817d9bb1e71d3c4a2931d1a6c7c8307422c84f001a251022022dad9726b0ae3fe92bda745a06f2c00f92342a186d84518588cf65f4dfaada801483045022100a4c574f00411dd2f978ca5cdc1b848c311cd7849c087ad2f21a5bce5e8cc5ae90220090ae39a9bce2fb8bc879d7e9f9022df249f41e25e51f1a9bf6447a9eeffc09801008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000", + }, + { + index: 1, + remoteSigHex: "3045022100e968cbbb5f402ed389fdc7f6cd2a80ed650bb42c79aeb2a5678444af94f6c78502204b47a1cb24ab5b0b6fe69fe9cfc7dba07b9dd0d8b95f372c1d9435146a88f8d4", + resolutionTxHex: "02000000000101579c183eca9e8236a5d7f5dcd79cfec32c497fdc0ec61533cde99ecd436cadd10100000000000000000109060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e968cbbb5f402ed389fdc7f6cd2a80ed650bb42c79aeb2a5678444af94f6c78502204b47a1cb24ab5b0b6fe69fe9cfc7dba07b9dd0d8b95f372c1d9435146a88f8d40147304402207679cf19790bea76a733d2fa0672bd43ab455687a068f815a3d237581f57139a0220683a1a799e102071c206b207735ca80f627ab83d6616b4bcd017c5d79ef3e7d0012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000", + }, + { + index: 3, + remoteSigHex: "3045022100aa91932e305292cf9969cc23502bbf6cef83a5df39c95ad04a707c4f4fed5c7702207099fc0f3a9bfe1e7683c0e9aa5e76c5432eb20693bf4cb182f04d383dc9c8c2", + resolutionTxHex: "02000000000101579c183eca9e8236a5d7f5dcd79cfec32c497fdc0ec61533cde99ecd436cadd1020000000000000000010b0a0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100aa91932e305292cf9969cc23502bbf6cef83a5df39c95ad04a707c4f4fed5c7702207099fc0f3a9bfe1e7683c0e9aa5e76c5432eb20693bf4cb182f04d383dc9c8c20147304402200df76fea718745f3c529bac7fd37923e7309ce38b25c0781e4cf514dd9ef8dc802204172295739dbae9fe0474dcee3608e3433b4b2af3a2e6787108b02f894dcdda301008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", + }, + { + index: 4, + remoteSigHex: "3044022035cac88040a5bba420b1c4257235d5015309113460bc33f2853cd81ca36e632402202fc94fd3e81e9d34a9d01782a0284f3044370d03d60f3fc041e2da088d2de58f", + resolutionTxHex: "02000000000101579c183eca9e8236a5d7f5dcd79cfec32c497fdc0ec61533cde99ecd436cadd103000000000000000001d90d0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022035cac88040a5bba420b1c4257235d5015309113460bc33f2853cd81ca36e632402202fc94fd3e81e9d34a9d01782a0284f3044370d03d60f3fc041e2da088d2de58f0147304402200daf2eb7afd355b4caf6fb08387b5f031940ea29d1a9f35071288a839c9039e4022067201b562456e7948616c13acb876b386b511599b58ac1d94d127f91c50463a6012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", + }, + }, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8006d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de8431104e9d6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100a2270d5950c89ae0841233f6efea9c951898b301b2e89e0adbd2c687b9f32efa02207943d90f95b9610458e7c65a576e149750ff3accaacad004cd85e70b235e27de01473044022072714e2fbb93cdd1c42eb0828b4f2eff143f717d8f26e79d6ada4f0dcb681bbe02200911be4e5161dd6ebe59ff1c58e1997c4aea804f81db6b698821db6093d7b05701475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "3044022072714e2fbb93cdd1c42eb0828b4f2eff143f717d8f26e79d6ada4f0dcb681bbe02200911be4e5161dd6ebe59ff1c58e1997c4aea804f81db6b698821db6093d7b057", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 2069, + }, + htlcDescs: []htlcDesc{ + { + index: 2, + remoteSigHex: "3045022100d1cf354de41c1369336cf85b225ed033f1f8982a01be503668df756a7e668b66022001254144fb4d0eecc61908fccc3388891ba17c5d7a1a8c62bdd307e5a513f992", + resolutionTxHex: "02000000000101ca94a9ad516ebc0c4bdd7b6254871babfa978d5accafb554214137d398bfcf6a0000000000000000000175020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d1cf354de41c1369336cf85b225ed033f1f8982a01be503668df756a7e668b66022001254144fb4d0eecc61908fccc3388891ba17c5d7a1a8c62bdd307e5a513f99201473044022056eb1af429660e45a1b0b66568cb8c4a3aa7e4c9c292d5d6c47f86ebf2c8838f022065c3ac4ebe980ca7a41148569be4ad8751b0a724a41405697ec55035dae6640201008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000", + }, + { + index: 1, + remoteSigHex: "3045022100d065569dcb94f090345402736385efeb8ea265131804beac06dd84d15dd2d6880220664feb0b4b2eb985fadb6ec7dc58c9334ea88ce599a9be760554a2d4b3b5d9f4", + resolutionTxHex: "02000000000101ca94a9ad516ebc0c4bdd7b6254871babfa978d5accafb554214137d398bfcf6a0100000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d065569dcb94f090345402736385efeb8ea265131804beac06dd84d15dd2d6880220664feb0b4b2eb985fadb6ec7dc58c9334ea88ce599a9be760554a2d4b3b5d9f401483045022100914bb232cd4b2690ee3d6cb8c3713c4ac9c4fb925323068d8b07f67c8541f8d9022057152f5f1615b793d2d45aac7518989ae4fe970f28b9b5c77504799d25433f7f012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000", + }, + { + index: 3, + remoteSigHex: "3045022100d4e69d363de993684eae7b37853c40722a4c1b4a7b588ad7b5d8a9b5006137a102207a069c628170ee34be5612747051bdcc087466dbaa68d5756ea81c10155aef18", + resolutionTxHex: "02000000000101ca94a9ad516ebc0c4bdd7b6254871babfa978d5accafb554214137d398bfcf6a020000000000000000015d060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d4e69d363de993684eae7b37853c40722a4c1b4a7b588ad7b5d8a9b5006137a102207a069c628170ee34be5612747051bdcc087466dbaa68d5756ea81c10155aef180147304402200e362443f7af830b419771e8e1614fc391db3a4eb799989abfc5ab26d6fcd032022039ab0cad1c14dfbe9446bf847965e56fe016e0cbcf719fd18c1bfbf53ecbd9f901008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", + }, + { + index: 4, + remoteSigHex: "30450221008ec888e36e4a4b3dc2ed6b823319855b2ae03006ca6ae0d9aa7e24bfc1d6f07102203b0f78885472a67ff4fe5916c0bb669487d659527509516fc3a08e87a2cc0a7c", + resolutionTxHex: "02000000000101ca94a9ad516ebc0c4bdd7b6254871babfa978d5accafb554214137d398bfcf6a03000000000000000001f2090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221008ec888e36e4a4b3dc2ed6b823319855b2ae03006ca6ae0d9aa7e24bfc1d6f07102203b0f78885472a67ff4fe5916c0bb669487d659527509516fc3a08e87a2cc0a7c0147304402202c3e14282b84b02705dfd00a6da396c9fe8a8bcb1d3fdb4b20a4feba09440e8b02202b058b39aa9b0c865b22095edcd9ff1f71bbfe20aa4993755e54d042755ed0d5012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", + }, + }, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8006d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311077956a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402203ca8f31c6a47519f83255dc69f1894d9a6d7476a19f498d31eaf0cd3a85eeb63022026fd92dc752b33905c4c838c528b692a8ad4ced959990b5d5ee2ff940fa90eea01473044022001d55e488b8b035b2dd29d50b65b530923a416d47f377284145bc8767b1b6a75022019bb53ddfe1cefaf156f924777eaaf8fdca1810695a7d0a247ad2afba8232eb401475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "3044022001d55e488b8b035b2dd29d50b65b530923a416d47f377284145bc8767b1b6a75022019bb53ddfe1cefaf156f924777eaaf8fdca1810695a7d0a247ad2afba8232eb4", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 2070, + }, + htlcDescs: []htlcDesc{ + { + index: 2, + remoteSigHex: "3045022100eed143b1ee4bed5dc3cde40afa5db3e7354cbf9c44054b5f713f729356f08cf7022077161d171c2bbd9badf3c9934de65a4918de03bbac1450f715275f75b103f891", + resolutionTxHex: "0200000000010140a83ce364747ff277f4d7595d8d15f708418798922c40bc2b056aca5485a2180000000000000000000174020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100eed143b1ee4bed5dc3cde40afa5db3e7354cbf9c44054b5f713f729356f08cf7022077161d171c2bbd9badf3c9934de65a4918de03bbac1450f715275f75b103f89101483045022100a0d043ed533e7fb1911e0553d31a8e2f3e6de19dbc035257f29d747c5e02f1f5022030cd38d8e84282175d49c1ebe0470db3ebd59768cf40780a784e248a43904fb801008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000", + }, + { + index: 3, + remoteSigHex: "3044022071e9357619fd8d29a411dc053b326a5224c5d11268070e88ecb981b174747c7a02202b763ae29a9d0732fa8836dd8597439460b50472183f420021b768981b4f7cf6", + resolutionTxHex: "0200000000010140a83ce364747ff277f4d7595d8d15f708418798922c40bc2b056aca5485a218010000000000000000015c060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022071e9357619fd8d29a411dc053b326a5224c5d11268070e88ecb981b174747c7a02202b763ae29a9d0732fa8836dd8597439460b50472183f420021b768981b4f7cf601483045022100adb1d679f65f96178b59f23ed37d3b70443118f345224a07ecb043eee2acc157022034d24524fe857144a3bcfff3065a9994d0a6ec5f11c681e49431d573e242612d01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", + }, + { + index: 4, + remoteSigHex: "3045022100c9458a4d2cbb741705577deb0a890e5cb90ee141be0400d3162e533727c9cb2102206edcf765c5dc5e5f9b976ea8149bf8607b5a0efb30691138e1231302b640d2a4", + resolutionTxHex: "0200000000010140a83ce364747ff277f4d7595d8d15f708418798922c40bc2b056aca5485a21802000000000000000001f1090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100c9458a4d2cbb741705577deb0a890e5cb90ee141be0400d3162e533727c9cb2102206edcf765c5dc5e5f9b976ea8149bf8607b5a0efb30691138e1231302b640d2a40147304402200831422aa4e1ee6d55e0b894201770a8f8817a189356f2d70be76633ffa6a6f602200dd1b84a4855dc6727dd46c98daae43dfc70889d1ba7ef0087529a57c06e5e04012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", + }, + }, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8005d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110da966a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004730440220443cb07f650aebbba14b8bc8d81e096712590f524c5991ac0ed3bbc8fd3bd0c7022028a635f548e3ca64b19b69b1ea00f05b22752f91daf0b6dab78e62ba52eb7fd001483045022100f2377f7a67b7fc7f4e2c0c9e3a7de935c32417f5668eda31ea1db401b7dc53030220415fdbc8e91d0f735e70c21952342742e25249b0d062d43efbfc564499f3752601475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "3045022100f2377f7a67b7fc7f4e2c0c9e3a7de935c32417f5668eda31ea1db401b7dc53030220415fdbc8e91d0f735e70c21952342742e25249b0d062d43efbfc564499f37526", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 2194, + }, + htlcDescs: []htlcDesc{ + { + index: 2, + remoteSigHex: "30450221009ed2f0a67f99e29c3c8cf45c08207b765980697781bb727fe0b1416de0e7622902206052684229bc171419ed290f4b615c943f819c0262414e43c5b91dcf72ddcf44", + resolutionTxHex: "02000000000101fb824d4e4dafc0f567789dee3a6bce8d411fe80f5563d8cdfdcc7d7e4447d43a0000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221009ed2f0a67f99e29c3c8cf45c08207b765980697781bb727fe0b1416de0e7622902206052684229bc171419ed290f4b615c943f819c0262414e43c5b91dcf72ddcf4401473044022004ad5f04ae69c71b3b141d4db9d0d4c38d84009fb3cfeeae6efdad414487a9a0022042d3fe1388c1ff517d1da7fb4025663d372c14728ed52dc88608363450ff6a2f01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000", + }, + { + index: 3, + remoteSigHex: "30440220155d3b90c67c33a8321996a9be5b82431b0c126613be751d400669da9d5c696702204318448bcd48824439d2c6a70be6e5747446be47ff45977cf41672bdc9b6b12d", + resolutionTxHex: "02000000000101fb824d4e4dafc0f567789dee3a6bce8d411fe80f5563d8cdfdcc7d7e4447d43a010000000000000000010a060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220155d3b90c67c33a8321996a9be5b82431b0c126613be751d400669da9d5c696702204318448bcd48824439d2c6a70be6e5747446be47ff45977cf41672bdc9b6b12d0147304402201707050c870c1f77cc3ed58d6d71bf281de239e9eabd8ef0955bad0d7fe38dcc02204d36d80d0019b3a71e646a08fa4a5607761d341ae8be371946ebe437c289c91501008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", + }, + { + index: 4, + remoteSigHex: "3045022100a12a9a473ece548584aabdd051779025a5ed4077c4b7aa376ec7a0b1645e5a48022039490b333f53b5b3e2ddde1d809e492cba2b3e5fc3a436cd3ffb4cd3d500fa5a", + resolutionTxHex: "02000000000101fb824d4e4dafc0f567789dee3a6bce8d411fe80f5563d8cdfdcc7d7e4447d43a020000000000000000019a090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100a12a9a473ece548584aabdd051779025a5ed4077c4b7aa376ec7a0b1645e5a48022039490b333f53b5b3e2ddde1d809e492cba2b3e5fc3a436cd3ffb4cd3d500fa5a01483045022100ff200bc934ab26ce9a559e998ceb0aee53bc40368e114ab9d3054d9960546e2802202496856ca163ac12c143110b6b3ac9d598df7254f2e17b3b94c3ab5301f4c3b0012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", + }, + }, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8005d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311040966a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402203b1b010c109c2ecbe7feb2d259b9c4126bd5dc99ee693c422ec0a5781fe161ba0220571fe4e2c649dea9c7aaf7e49b382962f6a3494963c97d80fef9a430ca3f706101483045022100d33c4e541aa1d255d41ea9a3b443b3b822ad8f7f86862638aac1f69f8f760577022007e2a18e6931ce3d3a804b1c78eda1de17dbe1fb7a95488c9a4ec8620395334801475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "3045022100d33c4e541aa1d255d41ea9a3b443b3b822ad8f7f86862638aac1f69f8f760577022007e2a18e6931ce3d3a804b1c78eda1de17dbe1fb7a95488c9a4ec86203953348", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 2195, + }, + htlcDescs: []htlcDesc{ + { + index: 3, + remoteSigHex: "3045022100a8a78fa1016a5c5c3704f2e8908715a3cef66723fb95f3132ec4d2d05cd84fb4022025ac49287b0861ec21932405f5600cbce94313dbde0e6c5d5af1b3366d8afbfc", + resolutionTxHex: "020000000001014e16c488fa158431c1a82e8f661240ec0a71ba0ce92f2721a6538c510226ad5c0000000000000000000109060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100a8a78fa1016a5c5c3704f2e8908715a3cef66723fb95f3132ec4d2d05cd84fb4022025ac49287b0861ec21932405f5600cbce94313dbde0e6c5d5af1b3366d8afbfc01483045022100be6ae1977fd7b630a53623f3f25c542317ccfc2b971782802a4f1ef538eb22b402207edc4d0408f8f38fd3c7365d1cfc26511b7cd2d4fecd8b005fba3cd5bc70439001008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", + }, + { + index: 4, + remoteSigHex: "3045022100e769cb156aa2f7515d126cef7a69968629620ce82afcaa9e210969de6850df4602200b16b3f3486a229a48aadde520dbee31ae340dbadaffae74fbb56681fef27b92", + resolutionTxHex: "020000000001014e16c488fa158431c1a82e8f661240ec0a71ba0ce92f2721a6538c510226ad5c0100000000000000000199090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e769cb156aa2f7515d126cef7a69968629620ce82afcaa9e210969de6850df4602200b16b3f3486a229a48aadde520dbee31ae340dbadaffae74fbb56681fef27b92014730440220665b9cb4a978c09d1ca8977a534999bc8a49da624d0c5439451dd69cde1a003d022070eae0620f01f3c1bd029cc1488da13fb40fdab76f396ccd335479a11c5276d8012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", + }, + }, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8004b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110b8976a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402203b12d44254244b8ff3bb4129b0920fd45120ab42f553d9976394b099d500c99e02205e95bb7a3164852ef0c48f9e0eaf145218f8e2c41251b231f03cbdc4f29a54290147304402205e2f76d4657fb732c0dfc820a18a7301e368f5799e06b7828007633741bda6df0220458009ae59d0c6246065c419359e05eb2a4b4ef4a1b310cc912db44eb792429801475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "304402205e2f76d4657fb732c0dfc820a18a7301e368f5799e06b7828007633741bda6df0220458009ae59d0c6246065c419359e05eb2a4b4ef4a1b310cc912db44eb7924298", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 3702, + }, + htlcDescs: []htlcDesc{ + { + index: 3, + remoteSigHex: "3045022100dfb73b4fe961b31a859b2bb1f4f15cabab9265016dd0272323dc6a9e85885c54022059a7b87c02861ee70662907f25ce11597d7b68d3399443a831ae40e777b76bdb", + resolutionTxHex: "02000000000101b8de11eb51c22498fe39722c7227b6e55ff1a94146cf638458cb9bc6a060d3a30000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100dfb73b4fe961b31a859b2bb1f4f15cabab9265016dd0272323dc6a9e85885c54022059a7b87c02861ee70662907f25ce11597d7b68d3399443a831ae40e777b76bdb0147304402202765b9c9ece4f127fa5407faf66da4c5ce2719cdbe47cd3175fc7d48b482e43d02205605125925e07bad1e41c618a4b434d72c88a164981c4b8af5eaf4ee9142ec3a01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", + }, + { + index: 4, + remoteSigHex: "3045022100ea9dc2a7c3c3640334dab733bb4e036e32a3106dc707b24227874fa4f7da746802204d672f7ac0fe765931a8df10b81e53a3242dd32bd9dc9331eb4a596da87954e9", + resolutionTxHex: "02000000000101b8de11eb51c22498fe39722c7227b6e55ff1a94146cf638458cb9bc6a060d3a30100000000000000000176050000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100ea9dc2a7c3c3640334dab733bb4e036e32a3106dc707b24227874fa4f7da746802204d672f7ac0fe765931a8df10b81e53a3242dd32bd9dc9331eb4a596da87954e9014730440220048a41c660c4841693de037d00a407810389f4574b3286afb7bc392a438fa3f802200401d71fa87c64fe621b49ac07e3bf85157ac680acb977124da28652cc7f1a5c012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", + }, + }, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8004b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de8431106f916a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402200e930a43c7951162dc15a2b7344f48091c74c70f7024e7116e900d8bcfba861c022066fa6cbda3929e21daa2e7e16a4b948db7e8919ef978402360d1095ffdaff7b001483045022100c1a3b0b60ca092ed5080121f26a74a20cec6bdee3f8e47bae973fcdceb3eda5502207d467a9873c939bf3aa758014ae67295fedbca52412633f7e5b2670fc7c381c101475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "3045022100c1a3b0b60ca092ed5080121f26a74a20cec6bdee3f8e47bae973fcdceb3eda5502207d467a9873c939bf3aa758014ae67295fedbca52412633f7e5b2670fc7c381c1", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 3703, + }, + htlcDescs: []htlcDesc{ + { + index: 4, + remoteSigHex: "3044022044f65cf833afdcb9d18795ca93f7230005777662539815b8a601eeb3e57129a902206a4bf3e53392affbba52640627defa8dc8af61c958c9e827b2798ab45828abdd", + resolutionTxHex: "020000000001011c076aa7fb3d7460d10df69432c904227ea84bbf3134d4ceee5fb0f135ef206d0000000000000000000175050000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022044f65cf833afdcb9d18795ca93f7230005777662539815b8a601eeb3e57129a902206a4bf3e53392affbba52640627defa8dc8af61c958c9e827b2798ab45828abdd01483045022100b94d931a811b32eeb885c28ddcf999ae1981893b21dd1329929543fe87ce793002206370107fdd151c5f2384f9ceb71b3107c69c74c8ed5a28a94a4ab2d27d3b0724012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", + }, + }, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110eb936a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022047305531dd44391dce03ae20f8735005c615eb077a974edb0059ea1a311857d602202e0ed6972fbdd1e8cb542b06e0929bc41b2ddf236e04cb75edd56151f4197506014830450221008b7c191dd46893b67b628e618d2dc8e81169d38bade310181ab77d7c94c6675e02203b4dd131fd7c9deb299560983dcdc485545c98f989f7ae8180c28289f9e6bdb001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "30450221008b7c191dd46893b67b628e618d2dc8e81169d38bade310181ab77d7c94c6675e02203b4dd131fd7c9deb299560983dcdc485545c98f989f7ae8180c28289f9e6bdb0", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 4914, + }, + htlcDescs: []htlcDesc{ + { + index: 4, + remoteSigHex: "3045022100fcb38506bfa11c02874092a843d0cc0a8613c23b639832564a5f69020cb0f6ba02206508b9e91eaa001425c190c68ee5f887e1ad5b1b314002e74db9dbd9e42dbecf", + resolutionTxHex: "0200000000010110a3fdcbcd5db477cd3ad465e7f501ffa8c437e8301f00a6061138590add757f0000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100fcb38506bfa11c02874092a843d0cc0a8613c23b639832564a5f69020cb0f6ba02206508b9e91eaa001425c190c68ee5f887e1ad5b1b314002e74db9dbd9e42dbecf0148304502210086e76b460ddd3cea10525fba298405d3fe11383e56966a5091811368362f689a02200f72ee75657915e0ede89c28709acd113ede9e1b7be520e3bc5cda425ecd6e68012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", + }, + }, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206a2679efa3c7aaffd2a447fd0df7aba8792858b589750f6a1203f9259173198a022008d52a0e77a99ab533c36206cb15ad7aeb2aa72b93d4b571e728cb5ec2f6fe260147304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 4915, + }, + htlcDescs: []htlcDesc{}, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8002c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110fa926a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100a012691ba6cea2f73fa8bac37750477e66363c6d28813b0bb6da77c8eb3fb0270220365e99c51304b0b1a6ab9ea1c8500db186693e39ec1ad5743ee231b0138384b90147304402200769ba89c7330dfa4feba447b6e322305f12ac7dac70ec6ba997ed7c1b598d0802204fe8d337e7fee781f9b7b1a06e580b22f4f79d740059560191d7db53f876555201475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "304402200769ba89c7330dfa4feba447b6e322305f12ac7dac70ec6ba997ed7c1b598d0802204fe8d337e7fee781f9b7b1a06e580b22f4f79d740059560191d7db53f8765552", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 9651180, + }, + htlcDescs: []htlcDesc{}, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b800222020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80ec0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311004004730440220514f977bf7edc442de8ce43ace9686e5ebdc0f893033f13e40fb46c8b8c6e1f90220188006227d175f5c35da0b092c57bea82537aed89f7778204dc5bacf4f29f2b901473044022037f83ff00c8e5fb18ae1f918ffc24e54581775a20ff1ae719297ef066c71caa9022039c529cccd89ff6c5ed1db799614533844bd6d101da503761c45c713996e3bbd01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "3044022037f83ff00c8e5fb18ae1f918ffc24e54581775a20ff1ae719297ef066c71caa9022039c529cccd89ff6c5ed1db799614533844bd6d101da503761c45c713996e3bbd", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 9651181, + }, + htlcDescs: []htlcDesc{}, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de8431100400473044022031a82b51bd014915fe68928d1abf4b9885353fb896cac10c3fdd88d7f9c7f2e00220716bda819641d2c63e65d3549b6120112e1aeaf1742eed94a471488e79e206b101473044022064901950be922e62cbe3f2ab93de2b99f37cff9fc473e73e394b27f88ef0731d02206d1dfa227527b4df44a07599289e207d6fd9cca60c0365682dcd3deaf739567e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "3044022064901950be922e62cbe3f2ab93de2b99f37cff9fc473e73e394b27f88ef0731d02206d1dfa227527b4df44a07599289e207d6fd9cca60c0365682dcd3deaf739567e", + }, + { + commitment: channeldb.ChannelCommitment{ + CommitHeight: 42, + LocalBalance: 6988000000, + RemoteBalance: 3000000000, + FeePerKw: 9651936, + }, + htlcDescs: []htlcDesc{}, + expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de8431100400473044022031a82b51bd014915fe68928d1abf4b9885353fb896cac10c3fdd88d7f9c7f2e00220716bda819641d2c63e65d3549b6120112e1aeaf1742eed94a471488e79e206b101473044022064901950be922e62cbe3f2ab93de2b99f37cff9fc473e73e394b27f88ef0731d02206d1dfa227527b4df44a07599289e207d6fd9cca60c0365682dcd3deaf739567e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", + remoteSigHex: "3044022064901950be922e62cbe3f2ab93de2b99f37cff9fc473e73e394b27f88ef0731d02206d1dfa227527b4df44a07599289e207d6fd9cca60c0365682dcd3deaf739567e", + }, + } + + for i, test := range testCases { + expectedCommitmentTx, err := txFromHex(test.expectedCommitmentTxHex) + if err != nil { + t.Fatalf("Case %d: Failed to parse serialized tx: %v", i, err) + } + + // Build required HTLC structs from raw test vector data. + htlcs := make([]channeldb.HTLC, len(test.htlcDescs), len(test.htlcDescs)) + for i, htlcDesc := range test.htlcDescs { + htlcs[i], err = tc.getHTLC(i, &htlcDesc) + if err != nil { + t.Fatal(err) + } + } + theHTLCView := htlcViewFromHTLCs(htlcs) + + // Create unsigned commitment transaction. + commitmentView := &commitment{ + height: test.commitment.CommitHeight, + ourBalance: test.commitment.LocalBalance, + theirBalance: test.commitment.RemoteBalance, + feePerKw: test.commitment.FeePerKw, + dustLimit: tc.dustLimit, + isOurs: true, + } + err = channel.createCommitmentTx(commitmentView, theHTLCView, + keys) + if err != nil { + t.Errorf("Case %d: Failed to create new commitment tx: %v", i, err) + continue + } + + // Initialize LocalCommit, which is used in getSignedCommitTx. + channelState.LocalCommitment = test.commitment + channelState.LocalCommitment.Htlcs = htlcs + channelState.LocalCommitment.CommitTx = commitmentView.txn + + // This is the remote party's signature over the commitment transaction + // which is included in the commitment tx's witness data. + channelState.LocalCommitment.CommitSig, err = hex.DecodeString(test.remoteSigHex) + if err != nil { + t.Fatalf("Case %d: Failed to parse serialized signature: %v", + i, err) + } + + commitTx, err := channel.getSignedCommitTx() + if err != nil { + t.Errorf("Case %d: Failed to sign commitment tx: %v", i, err) + continue + } + + // Check that commitment transaction was created correctly. + if commitTx.WitnessHash() != *expectedCommitmentTx.WitnessHash() { + t.Errorf("Case %d: Generated unexpected commitment tx: "+ + "expected %s, got %s", i, expectedCommitmentTx.WitnessHash(), + commitTx.WitnessHash()) + continue + } + + // Generate second-level HTLC transactions for HTLCs in commitment tx. + htlcResolutions, err := extractHtlcResolutions( + test.commitment.FeePerKw, true, signer, htlcs, keys, + channel.localChanCfg, channel.remoteChanCfg, commitTx.TxHash()) + if err != nil { + t.Errorf("Case %d: Failed to extract HTLC resolutions: %v", i, err) + continue + } + + resolutionIdx := 0 + for j, htlcDesc := range test.htlcDescs { + // TODO: Check HTLC success transactions; currently not implemented. + // resolutionIdx can be replaced by j when this is handled. + if htlcs[j].Incoming { + continue + } + + expectedTx, err := txFromHex(htlcDesc.resolutionTxHex) + if err != nil { + t.Fatalf("Failed to parse serialized tx: %v", err) + } + + htlcResolution := htlcResolutions[resolutionIdx] + resolutionIdx++ + + actualTx := htlcResolution.SignedTimeoutTx + if actualTx == nil { + t.Errorf("Case %d: Failed to generate second level tx: "+ + "output %d, %v", i, j, htlcResolutions[j]) + continue + } + + // Check that second-level HTLC transaction was created correctly. + if actualTx.WitnessHash() != *expectedTx.WitnessHash() { + t.Errorf("Case %d: Generated unexpected second level tx: "+ + "output %d, expected %s, got %s", i, j, + expectedTx.WitnessHash(), actualTx.WitnessHash()) + continue + } + } + } +} + +// htlcViewFromHTLCs constructs an htlcView of PaymentDescriptors from a slice +// of channeldb.HTLC structs. +func htlcViewFromHTLCs(htlcs []channeldb.HTLC) *htlcView { + var theHTLCView htlcView + for _, htlc := range htlcs { + paymentDesc := &PaymentDescriptor{ + RHash: htlc.RHash, + Timeout: htlc.RefundTimeout, + Amount: htlc.Amt, + } + if htlc.Incoming { + theHTLCView.theirUpdates = + append(theHTLCView.theirUpdates, paymentDesc) + } else { + theHTLCView.ourUpdates = + append(theHTLCView.ourUpdates, paymentDesc) + } + } + return &theHTLCView +}