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 +}