package lnwallet import ( "bytes" "crypto/rand" "encoding/binary" "encoding/hex" "fmt" "io" "io/ioutil" "net" "os" "sort" "testing" "time" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/shachain" "github.com/stretchr/testify/require" ) /** * 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 { localFundingPrivkey *btcec.PrivateKey localPaymentBasepointSecret *btcec.PrivateKey localDelayedPaymentBasepointSecret *btcec.PrivateKey remoteFundingPrivkey *btcec.PrivateKey remoteRevocationBasepointSecret *btcec.PrivateKey remotePaymentBasepointSecret *btcec.PrivateKey localPerCommitSecret lntypes.Hash fundingTx *btcutil.Tx localCsvDelay uint16 fundingAmount btcutil.Amount dustLimit btcutil.Amount commitHeight uint64 t *testing.T } // newTestContext populates a new testContext struct with the constant // parameters defined in the BOLT 03 spec. func newTestContext(t *testing.T) (tc *testContext) { tc = new(testContext) priv := func(v string) *btcec.PrivateKey { k, err := privkeyFromHex(v) require.NoError(t, err) return k } tc.remoteFundingPrivkey = priv("1552dfba4f6cf29a62a0af13c8d6981d36d0ef8d61ba10fb0fe90da7634d7e13") tc.remoteRevocationBasepointSecret = priv("2222222222222222222222222222222222222222222222222222222222222222") tc.remotePaymentBasepointSecret = priv("4444444444444444444444444444444444444444444444444444444444444444") tc.localPaymentBasepointSecret = priv("1111111111111111111111111111111111111111111111111111111111111111") tc.localDelayedPaymentBasepointSecret = priv("3333333333333333333333333333333333333333333333333333333333333333") tc.localFundingPrivkey = priv("30ff4956bbdd3222d44cc5e8a1261dab1e07957bdac5ae88fe3261ef321f3749") var err error tc.localPerCommitSecret, err = lntypes.MakeHashFromStr("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100") require.NoError(t, err) const fundingTxHex = "0200000001adbb20ea41a8423ea937e76e8151636bf6093b70eaff942930d20576600521fd000000006b48304502210090587b6201e166ad6af0227d3036a9454223d49a1f11839c1a362184340ef0240220577f7cd5cca78719405cbf1de7414ac027f0239ef6e214c90fcaab0454d84b3b012103535b32d5eb0a6ed0982a0479bbadc9868d9836f6ba94dd5a63be16d875069184ffffffff028096980000000000220020c015c4a6be010e21657068fc2e6a9d02b27ebe4d490a25846f7237f104d1a3cd20256d29010000001600143ca33c2e4446f4a305f23c80df8ad1afdcf652f900000000" tc.fundingTx, err = txFromHex(fundingTxHex) require.NoError(t, err) tc.localCsvDelay = 144 tc.fundingAmount = 10000000 tc.dustLimit = 546 tc.commitHeight = 42 tc.t = t return tc } var testHtlcs = []struct { incoming bool amount lnwire.MilliSatoshi expiry uint32 preimage string }{ { 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", }, } // htlcDesc is a description used to construct each HTLC in each test case. type htlcDesc struct { remoteSigHex string resolutionTxHex string } type testCase struct { name string commitment channeldb.ChannelCommitment htlcDescs []htlcDesc expectedCommitmentTxHex string remoteSigHex string } // testCases encode the raw test vectors specified in Appendix C1 of BOLT 03. var testCases = []testCase{ { name: "simple commitment tx with no HTLCs", commitment: channeldb.ChannelCommitment{ CommitHeight: 42, LocalBalance: 7000000000, RemoteBalance: 3000000000, FeePerKw: 15000, }, htlcDescs: nil, expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8002c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311054a56a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022051b75c73198c6deee1a875871c3961832909acd297c6b908d59e3319e5185a46022055c419379c5051a78d00dbbce11b5b664a0c22815fbcc6fcef6b1937c383693901483045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", remoteSigHex: "3045022100f51d2e566a70ba740fc5d8c0f07b9b93d2ed741c3c0860c613173de7d39e7968022041376d520e9c0e1ad52248ddf4b22e12be8763007df977253ef45a4ca3bdb7c0", }, { name: "commitment tx with seven outputs untrimmed (maximum feerate)", commitment: channeldb.ChannelCommitment{ CommitHeight: 42, LocalBalance: 6988000000, RemoteBalance: 3000000000, FeePerKw: 647, }, htlcDescs: []htlcDesc{ { remoteSigHex: "30440220385a5afe75632f50128cbb029ee95c80156b5b4744beddc729ad339c9ca432c802202ba5f48550cad3379ac75b9b4fedb86a35baa6947f16ba5037fb8b11ab343740", resolutionTxHex: "020000000001018323148ce2419f21ca3d6780053747715832e18ac780931a514b187768882bb60000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220385a5afe75632f50128cbb029ee95c80156b5b4744beddc729ad339c9ca432c802202ba5f48550cad3379ac75b9b4fedb86a35baa6947f16ba5037fb8b11ab3437400147304402205999590b8a79fa346e003a68fd40366397119b2b0cdf37b149968d6bc6fbcc4702202b1e1fb5ab7864931caed4e732c359e0fe3d86a548b557be2246efb1708d579a012000000000000000000000000000000000000000000000000000000000000000008a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac686800000000", }, { remoteSigHex: "304402207ceb6678d4db33d2401fdc409959e57c16a6cb97a30261d9c61f29b8c58d34b90220084b4a17b4ca0e86f2d798b3698ca52de5621f2ce86f80bed79afa66874511b0", resolutionTxHex: "020000000001018323148ce2419f21ca3d6780053747715832e18ac780931a514b187768882bb60100000000000000000124060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402207ceb6678d4db33d2401fdc409959e57c16a6cb97a30261d9c61f29b8c58d34b90220084b4a17b4ca0e86f2d798b3698ca52de5621f2ce86f80bed79afa66874511b00147304402207ff03eb0127fc7c6cae49cc29e2a586b98d1e8969cf4a17dfa50b9c2647720b902205e2ecfda2252956c0ca32f175080e75e4e390e433feb1f8ce9f2ba55648a1dac01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000", }, { remoteSigHex: "304402206a401b29a0dff0d18ec903502c13d83e7ec019450113f4a7655a4ce40d1f65ba0220217723a084e727b6ca0cc8b6c69c014a7e4a01fcdcba3e3993f462a3c574d833", resolutionTxHex: "020000000001018323148ce2419f21ca3d6780053747715832e18ac780931a514b187768882bb6020000000000000000010a060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206a401b29a0dff0d18ec903502c13d83e7ec019450113f4a7655a4ce40d1f65ba0220217723a084e727b6ca0cc8b6c69c014a7e4a01fcdcba3e3993f462a3c574d83301483045022100d50d067ca625d54e62df533a8f9291736678d0b86c28a61bb2a80cf42e702d6e02202373dde7e00218eacdafb9415fe0e1071beec1857d1af3c6a201a44cbc47c877012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000", }, { remoteSigHex: "30450221009b1c987ba599ee3bde1dbca776b85481d70a78b681a8d84206723e2795c7cac002207aac84ad910f8598c4d1c0ea2e3399cf6627a4e3e90131315bc9f038451ce39d", resolutionTxHex: "020000000001018323148ce2419f21ca3d6780053747715832e18ac780931a514b187768882bb6030000000000000000010c0a0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221009b1c987ba599ee3bde1dbca776b85481d70a78b681a8d84206723e2795c7cac002207aac84ad910f8598c4d1c0ea2e3399cf6627a4e3e90131315bc9f038451ce39d01483045022100db9dc65291077a52728c622987e9895b7241d4394d6dcb916d7600a3e8728c22022036ee3ee717ba0bb5c45ee84bc7bbf85c0f90f26ae4e4a25a6b4241afa8a3f1cb01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", }, { remoteSigHex: "3045022100cc28030b59f0914f45b84caa983b6f8effa900c952310708c2b5b00781117022022027ba2ccdf94d03c6d48b327f183f6e28c8a214d089b9227f94ac4f85315274f0", resolutionTxHex: "020000000001018323148ce2419f21ca3d6780053747715832e18ac780931a514b187768882bb604000000000000000001da0d0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100cc28030b59f0914f45b84caa983b6f8effa900c952310708c2b5b00781117022022027ba2ccdf94d03c6d48b327f183f6e28c8a214d089b9227f94ac4f85315274f00147304402202d1a3c0d31200265d2a2def2753ead4959ae20b4083e19553acfffa5dfab60bf022020ede134149504e15b88ab261a066de49848411e15e70f9e6a5462aec2949f8f012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", }, }, expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8007e80300000000000022002052bfef0479d7b293c27e0f1eb294bea154c63a3294ef092c19af51409bce0e2ad007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110e09c6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040048304502210094bfd8f5572ac0157ec76a9551b6c5216a4538c07cd13a51af4a54cb26fa14320220768efce8ce6f4a5efac875142ff19237c011343670adf9c7ac69704a120d116301483045022100a5c01383d3ec646d97e40f44318d49def817fcd61a0ef18008a665b3e151785502203e648efddd5838981ef55ec954be69c4a652d021e6081a100d034de366815e9b01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", remoteSigHex: "3045022100a5c01383d3ec646d97e40f44318d49def817fcd61a0ef18008a665b3e151785502203e648efddd5838981ef55ec954be69c4a652d021e6081a100d034de366815e9b", }, { name: "commitment tx with six outputs untrimmed (minimum feerate)", commitment: channeldb.ChannelCommitment{ CommitHeight: 42, LocalBalance: 6988000000, RemoteBalance: 3000000000, FeePerKw: 648, }, htlcDescs: []htlcDesc{ { remoteSigHex: "3044022062ef2e77591409d60d7817d9bb1e71d3c4a2931d1a6c7c8307422c84f001a251022022dad9726b0ae3fe92bda745a06f2c00f92342a186d84518588cf65f4dfaada8", resolutionTxHex: "02000000000101579c183eca9e8236a5d7f5dcd79cfec32c497fdc0ec61533cde99ecd436cadd10000000000000000000123060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022062ef2e77591409d60d7817d9bb1e71d3c4a2931d1a6c7c8307422c84f001a251022022dad9726b0ae3fe92bda745a06f2c00f92342a186d84518588cf65f4dfaada801483045022100a4c574f00411dd2f978ca5cdc1b848c311cd7849c087ad2f21a5bce5e8cc5ae90220090ae39a9bce2fb8bc879d7e9f9022df249f41e25e51f1a9bf6447a9eeffc09801008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000", }, { remoteSigHex: "3045022100e968cbbb5f402ed389fdc7f6cd2a80ed650bb42c79aeb2a5678444af94f6c78502204b47a1cb24ab5b0b6fe69fe9cfc7dba07b9dd0d8b95f372c1d9435146a88f8d4", resolutionTxHex: "02000000000101579c183eca9e8236a5d7f5dcd79cfec32c497fdc0ec61533cde99ecd436cadd10100000000000000000109060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e968cbbb5f402ed389fdc7f6cd2a80ed650bb42c79aeb2a5678444af94f6c78502204b47a1cb24ab5b0b6fe69fe9cfc7dba07b9dd0d8b95f372c1d9435146a88f8d40147304402207679cf19790bea76a733d2fa0672bd43ab455687a068f815a3d237581f57139a0220683a1a799e102071c206b207735ca80f627ab83d6616b4bcd017c5d79ef3e7d0012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000", }, { remoteSigHex: "3045022100aa91932e305292cf9969cc23502bbf6cef83a5df39c95ad04a707c4f4fed5c7702207099fc0f3a9bfe1e7683c0e9aa5e76c5432eb20693bf4cb182f04d383dc9c8c2", resolutionTxHex: "02000000000101579c183eca9e8236a5d7f5dcd79cfec32c497fdc0ec61533cde99ecd436cadd1020000000000000000010b0a0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100aa91932e305292cf9969cc23502bbf6cef83a5df39c95ad04a707c4f4fed5c7702207099fc0f3a9bfe1e7683c0e9aa5e76c5432eb20693bf4cb182f04d383dc9c8c20147304402200df76fea718745f3c529bac7fd37923e7309ce38b25c0781e4cf514dd9ef8dc802204172295739dbae9fe0474dcee3608e3433b4b2af3a2e6787108b02f894dcdda301008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", }, { remoteSigHex: "3044022035cac88040a5bba420b1c4257235d5015309113460bc33f2853cd81ca36e632402202fc94fd3e81e9d34a9d01782a0284f3044370d03d60f3fc041e2da088d2de58f", resolutionTxHex: "02000000000101579c183eca9e8236a5d7f5dcd79cfec32c497fdc0ec61533cde99ecd436cadd103000000000000000001d90d0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022035cac88040a5bba420b1c4257235d5015309113460bc33f2853cd81ca36e632402202fc94fd3e81e9d34a9d01782a0284f3044370d03d60f3fc041e2da088d2de58f0147304402200daf2eb7afd355b4caf6fb08387b5f031940ea29d1a9f35071288a839c9039e4022067201b562456e7948616c13acb876b386b511599b58ac1d94d127f91c50463a6012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", }, }, expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8006d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de8431104e9d6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100a2270d5950c89ae0841233f6efea9c951898b301b2e89e0adbd2c687b9f32efa02207943d90f95b9610458e7c65a576e149750ff3accaacad004cd85e70b235e27de01473044022072714e2fbb93cdd1c42eb0828b4f2eff143f717d8f26e79d6ada4f0dcb681bbe02200911be4e5161dd6ebe59ff1c58e1997c4aea804f81db6b698821db6093d7b05701475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", remoteSigHex: "3044022072714e2fbb93cdd1c42eb0828b4f2eff143f717d8f26e79d6ada4f0dcb681bbe02200911be4e5161dd6ebe59ff1c58e1997c4aea804f81db6b698821db6093d7b057", }, { name: "commitment tx with six outputs untrimmed (maximum feerate)", commitment: channeldb.ChannelCommitment{ CommitHeight: 42, LocalBalance: 6988000000, RemoteBalance: 3000000000, FeePerKw: 2069, }, htlcDescs: []htlcDesc{ { remoteSigHex: "3045022100d1cf354de41c1369336cf85b225ed033f1f8982a01be503668df756a7e668b66022001254144fb4d0eecc61908fccc3388891ba17c5d7a1a8c62bdd307e5a513f992", resolutionTxHex: "02000000000101ca94a9ad516ebc0c4bdd7b6254871babfa978d5accafb554214137d398bfcf6a0000000000000000000175020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d1cf354de41c1369336cf85b225ed033f1f8982a01be503668df756a7e668b66022001254144fb4d0eecc61908fccc3388891ba17c5d7a1a8c62bdd307e5a513f99201473044022056eb1af429660e45a1b0b66568cb8c4a3aa7e4c9c292d5d6c47f86ebf2c8838f022065c3ac4ebe980ca7a41148569be4ad8751b0a724a41405697ec55035dae6640201008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000", }, { remoteSigHex: "3045022100d065569dcb94f090345402736385efeb8ea265131804beac06dd84d15dd2d6880220664feb0b4b2eb985fadb6ec7dc58c9334ea88ce599a9be760554a2d4b3b5d9f4", resolutionTxHex: "02000000000101ca94a9ad516ebc0c4bdd7b6254871babfa978d5accafb554214137d398bfcf6a0100000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d065569dcb94f090345402736385efeb8ea265131804beac06dd84d15dd2d6880220664feb0b4b2eb985fadb6ec7dc58c9334ea88ce599a9be760554a2d4b3b5d9f401483045022100914bb232cd4b2690ee3d6cb8c3713c4ac9c4fb925323068d8b07f67c8541f8d9022057152f5f1615b793d2d45aac7518989ae4fe970f28b9b5c77504799d25433f7f012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000", }, { remoteSigHex: "3045022100d4e69d363de993684eae7b37853c40722a4c1b4a7b588ad7b5d8a9b5006137a102207a069c628170ee34be5612747051bdcc087466dbaa68d5756ea81c10155aef18", resolutionTxHex: "02000000000101ca94a9ad516ebc0c4bdd7b6254871babfa978d5accafb554214137d398bfcf6a020000000000000000015d060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d4e69d363de993684eae7b37853c40722a4c1b4a7b588ad7b5d8a9b5006137a102207a069c628170ee34be5612747051bdcc087466dbaa68d5756ea81c10155aef180147304402200e362443f7af830b419771e8e1614fc391db3a4eb799989abfc5ab26d6fcd032022039ab0cad1c14dfbe9446bf847965e56fe016e0cbcf719fd18c1bfbf53ecbd9f901008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", }, { remoteSigHex: "30450221008ec888e36e4a4b3dc2ed6b823319855b2ae03006ca6ae0d9aa7e24bfc1d6f07102203b0f78885472a67ff4fe5916c0bb669487d659527509516fc3a08e87a2cc0a7c", resolutionTxHex: "02000000000101ca94a9ad516ebc0c4bdd7b6254871babfa978d5accafb554214137d398bfcf6a03000000000000000001f2090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221008ec888e36e4a4b3dc2ed6b823319855b2ae03006ca6ae0d9aa7e24bfc1d6f07102203b0f78885472a67ff4fe5916c0bb669487d659527509516fc3a08e87a2cc0a7c0147304402202c3e14282b84b02705dfd00a6da396c9fe8a8bcb1d3fdb4b20a4feba09440e8b02202b058b39aa9b0c865b22095edcd9ff1f71bbfe20aa4993755e54d042755ed0d5012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", }, }, expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8006d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5d007000000000000220020748eba944fedc8827f6b06bc44678f93c0f9e6078b35c6331ed31e75f8ce0c2db80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311077956a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402203ca8f31c6a47519f83255dc69f1894d9a6d7476a19f498d31eaf0cd3a85eeb63022026fd92dc752b33905c4c838c528b692a8ad4ced959990b5d5ee2ff940fa90eea01473044022001d55e488b8b035b2dd29d50b65b530923a416d47f377284145bc8767b1b6a75022019bb53ddfe1cefaf156f924777eaaf8fdca1810695a7d0a247ad2afba8232eb401475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", remoteSigHex: "3044022001d55e488b8b035b2dd29d50b65b530923a416d47f377284145bc8767b1b6a75022019bb53ddfe1cefaf156f924777eaaf8fdca1810695a7d0a247ad2afba8232eb4", }, { name: "commitment tx with five outputs untrimmed (minimum feerate)", commitment: channeldb.ChannelCommitment{ CommitHeight: 42, LocalBalance: 6988000000, RemoteBalance: 3000000000, FeePerKw: 2070, }, htlcDescs: []htlcDesc{ { remoteSigHex: "3045022100eed143b1ee4bed5dc3cde40afa5db3e7354cbf9c44054b5f713f729356f08cf7022077161d171c2bbd9badf3c9934de65a4918de03bbac1450f715275f75b103f891", resolutionTxHex: "0200000000010140a83ce364747ff277f4d7595d8d15f708418798922c40bc2b056aca5485a2180000000000000000000174020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100eed143b1ee4bed5dc3cde40afa5db3e7354cbf9c44054b5f713f729356f08cf7022077161d171c2bbd9badf3c9934de65a4918de03bbac1450f715275f75b103f89101483045022100a0d043ed533e7fb1911e0553d31a8e2f3e6de19dbc035257f29d747c5e02f1f5022030cd38d8e84282175d49c1ebe0470db3ebd59768cf40780a784e248a43904fb801008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000", }, { remoteSigHex: "3044022071e9357619fd8d29a411dc053b326a5224c5d11268070e88ecb981b174747c7a02202b763ae29a9d0732fa8836dd8597439460b50472183f420021b768981b4f7cf6", resolutionTxHex: "0200000000010140a83ce364747ff277f4d7595d8d15f708418798922c40bc2b056aca5485a218010000000000000000015c060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022071e9357619fd8d29a411dc053b326a5224c5d11268070e88ecb981b174747c7a02202b763ae29a9d0732fa8836dd8597439460b50472183f420021b768981b4f7cf601483045022100adb1d679f65f96178b59f23ed37d3b70443118f345224a07ecb043eee2acc157022034d24524fe857144a3bcfff3065a9994d0a6ec5f11c681e49431d573e242612d01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", }, { remoteSigHex: "3045022100c9458a4d2cbb741705577deb0a890e5cb90ee141be0400d3162e533727c9cb2102206edcf765c5dc5e5f9b976ea8149bf8607b5a0efb30691138e1231302b640d2a4", resolutionTxHex: "0200000000010140a83ce364747ff277f4d7595d8d15f708418798922c40bc2b056aca5485a21802000000000000000001f1090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100c9458a4d2cbb741705577deb0a890e5cb90ee141be0400d3162e533727c9cb2102206edcf765c5dc5e5f9b976ea8149bf8607b5a0efb30691138e1231302b640d2a40147304402200831422aa4e1ee6d55e0b894201770a8f8817a189356f2d70be76633ffa6a6f602200dd1b84a4855dc6727dd46c98daae43dfc70889d1ba7ef0087529a57c06e5e04012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", }, }, expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8005d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110da966a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e04004730440220443cb07f650aebbba14b8bc8d81e096712590f524c5991ac0ed3bbc8fd3bd0c7022028a635f548e3ca64b19b69b1ea00f05b22752f91daf0b6dab78e62ba52eb7fd001483045022100f2377f7a67b7fc7f4e2c0c9e3a7de935c32417f5668eda31ea1db401b7dc53030220415fdbc8e91d0f735e70c21952342742e25249b0d062d43efbfc564499f3752601475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", remoteSigHex: "3045022100f2377f7a67b7fc7f4e2c0c9e3a7de935c32417f5668eda31ea1db401b7dc53030220415fdbc8e91d0f735e70c21952342742e25249b0d062d43efbfc564499f37526", }, { name: "commitment tx with five outputs untrimmed (maximum feerate)", commitment: channeldb.ChannelCommitment{ CommitHeight: 42, LocalBalance: 6988000000, RemoteBalance: 3000000000, FeePerKw: 2194, }, htlcDescs: []htlcDesc{ { remoteSigHex: "30450221009ed2f0a67f99e29c3c8cf45c08207b765980697781bb727fe0b1416de0e7622902206052684229bc171419ed290f4b615c943f819c0262414e43c5b91dcf72ddcf44", resolutionTxHex: "02000000000101fb824d4e4dafc0f567789dee3a6bce8d411fe80f5563d8cdfdcc7d7e4447d43a0000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004830450221009ed2f0a67f99e29c3c8cf45c08207b765980697781bb727fe0b1416de0e7622902206052684229bc171419ed290f4b615c943f819c0262414e43c5b91dcf72ddcf4401473044022004ad5f04ae69c71b3b141d4db9d0d4c38d84009fb3cfeeae6efdad414487a9a0022042d3fe1388c1ff517d1da7fb4025663d372c14728ed52dc88608363450ff6a2f01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000", }, { remoteSigHex: "30440220155d3b90c67c33a8321996a9be5b82431b0c126613be751d400669da9d5c696702204318448bcd48824439d2c6a70be6e5747446be47ff45977cf41672bdc9b6b12d", resolutionTxHex: "02000000000101fb824d4e4dafc0f567789dee3a6bce8d411fe80f5563d8cdfdcc7d7e4447d43a010000000000000000010a060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e05004730440220155d3b90c67c33a8321996a9be5b82431b0c126613be751d400669da9d5c696702204318448bcd48824439d2c6a70be6e5747446be47ff45977cf41672bdc9b6b12d0147304402201707050c870c1f77cc3ed58d6d71bf281de239e9eabd8ef0955bad0d7fe38dcc02204d36d80d0019b3a71e646a08fa4a5607761d341ae8be371946ebe437c289c91501008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", }, { remoteSigHex: "3045022100a12a9a473ece548584aabdd051779025a5ed4077c4b7aa376ec7a0b1645e5a48022039490b333f53b5b3e2ddde1d809e492cba2b3e5fc3a436cd3ffb4cd3d500fa5a", resolutionTxHex: "02000000000101fb824d4e4dafc0f567789dee3a6bce8d411fe80f5563d8cdfdcc7d7e4447d43a020000000000000000019a090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100a12a9a473ece548584aabdd051779025a5ed4077c4b7aa376ec7a0b1645e5a48022039490b333f53b5b3e2ddde1d809e492cba2b3e5fc3a436cd3ffb4cd3d500fa5a01483045022100ff200bc934ab26ce9a559e998ceb0aee53bc40368e114ab9d3054d9960546e2802202496856ca163ac12c143110b6b3ac9d598df7254f2e17b3b94c3ab5301f4c3b0012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", }, }, expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8005d007000000000000220020403d394747cae42e98ff01734ad5c08f82ba123d3d9a620abda88989651e2ab5b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311040966a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402203b1b010c109c2ecbe7feb2d259b9c4126bd5dc99ee693c422ec0a5781fe161ba0220571fe4e2c649dea9c7aaf7e49b382962f6a3494963c97d80fef9a430ca3f706101483045022100d33c4e541aa1d255d41ea9a3b443b3b822ad8f7f86862638aac1f69f8f760577022007e2a18e6931ce3d3a804b1c78eda1de17dbe1fb7a95488c9a4ec8620395334801475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", remoteSigHex: "3045022100d33c4e541aa1d255d41ea9a3b443b3b822ad8f7f86862638aac1f69f8f760577022007e2a18e6931ce3d3a804b1c78eda1de17dbe1fb7a95488c9a4ec86203953348", }, { name: "commitment tx with four outputs untrimmed (minimum feerate)", commitment: channeldb.ChannelCommitment{ CommitHeight: 42, LocalBalance: 6988000000, RemoteBalance: 3000000000, FeePerKw: 2195, }, htlcDescs: []htlcDesc{ { remoteSigHex: "3045022100a8a78fa1016a5c5c3704f2e8908715a3cef66723fb95f3132ec4d2d05cd84fb4022025ac49287b0861ec21932405f5600cbce94313dbde0e6c5d5af1b3366d8afbfc", resolutionTxHex: "020000000001014e16c488fa158431c1a82e8f661240ec0a71ba0ce92f2721a6538c510226ad5c0000000000000000000109060000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100a8a78fa1016a5c5c3704f2e8908715a3cef66723fb95f3132ec4d2d05cd84fb4022025ac49287b0861ec21932405f5600cbce94313dbde0e6c5d5af1b3366d8afbfc01483045022100be6ae1977fd7b630a53623f3f25c542317ccfc2b971782802a4f1ef538eb22b402207edc4d0408f8f38fd3c7365d1cfc26511b7cd2d4fecd8b005fba3cd5bc70439001008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", }, { remoteSigHex: "3045022100e769cb156aa2f7515d126cef7a69968629620ce82afcaa9e210969de6850df4602200b16b3f3486a229a48aadde520dbee31ae340dbadaffae74fbb56681fef27b92", resolutionTxHex: "020000000001014e16c488fa158431c1a82e8f661240ec0a71ba0ce92f2721a6538c510226ad5c0100000000000000000199090000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100e769cb156aa2f7515d126cef7a69968629620ce82afcaa9e210969de6850df4602200b16b3f3486a229a48aadde520dbee31ae340dbadaffae74fbb56681fef27b92014730440220665b9cb4a978c09d1ca8977a534999bc8a49da624d0c5439451dd69cde1a003d022070eae0620f01f3c1bd029cc1488da13fb40fdab76f396ccd335479a11c5276d8012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", }, }, expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8004b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110b8976a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402203b12d44254244b8ff3bb4129b0920fd45120ab42f553d9976394b099d500c99e02205e95bb7a3164852ef0c48f9e0eaf145218f8e2c41251b231f03cbdc4f29a54290147304402205e2f76d4657fb732c0dfc820a18a7301e368f5799e06b7828007633741bda6df0220458009ae59d0c6246065c419359e05eb2a4b4ef4a1b310cc912db44eb792429801475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", remoteSigHex: "304402205e2f76d4657fb732c0dfc820a18a7301e368f5799e06b7828007633741bda6df0220458009ae59d0c6246065c419359e05eb2a4b4ef4a1b310cc912db44eb7924298", }, { name: "commitment tx with four outputs untrimmed (maximum feerate)", commitment: channeldb.ChannelCommitment{ CommitHeight: 42, LocalBalance: 6988000000, RemoteBalance: 3000000000, FeePerKw: 3702, }, htlcDescs: []htlcDesc{ { remoteSigHex: "3045022100dfb73b4fe961b31a859b2bb1f4f15cabab9265016dd0272323dc6a9e85885c54022059a7b87c02861ee70662907f25ce11597d7b68d3399443a831ae40e777b76bdb", resolutionTxHex: "02000000000101b8de11eb51c22498fe39722c7227b6e55ff1a94146cf638458cb9bc6a060d3a30000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100dfb73b4fe961b31a859b2bb1f4f15cabab9265016dd0272323dc6a9e85885c54022059a7b87c02861ee70662907f25ce11597d7b68d3399443a831ae40e777b76bdb0147304402202765b9c9ece4f127fa5407faf66da4c5ce2719cdbe47cd3175fc7d48b482e43d02205605125925e07bad1e41c618a4b434d72c88a164981c4b8af5eaf4ee9142ec3a01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000", }, { remoteSigHex: "3045022100ea9dc2a7c3c3640334dab733bb4e036e32a3106dc707b24227874fa4f7da746802204d672f7ac0fe765931a8df10b81e53a3242dd32bd9dc9331eb4a596da87954e9", resolutionTxHex: "02000000000101b8de11eb51c22498fe39722c7227b6e55ff1a94146cf638458cb9bc6a060d3a30100000000000000000176050000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100ea9dc2a7c3c3640334dab733bb4e036e32a3106dc707b24227874fa4f7da746802204d672f7ac0fe765931a8df10b81e53a3242dd32bd9dc9331eb4a596da87954e9014730440220048a41c660c4841693de037d00a407810389f4574b3286afb7bc392a438fa3f802200401d71fa87c64fe621b49ac07e3bf85157ac680acb977124da28652cc7f1a5c012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", }, }, expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8004b80b000000000000220020c20b5d1f8584fd90443e7b7b720136174fa4b9333c261d04dbbd012635c0f419a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de8431106f916a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402200e930a43c7951162dc15a2b7344f48091c74c70f7024e7116e900d8bcfba861c022066fa6cbda3929e21daa2e7e16a4b948db7e8919ef978402360d1095ffdaff7b001483045022100c1a3b0b60ca092ed5080121f26a74a20cec6bdee3f8e47bae973fcdceb3eda5502207d467a9873c939bf3aa758014ae67295fedbca52412633f7e5b2670fc7c381c101475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", remoteSigHex: "3045022100c1a3b0b60ca092ed5080121f26a74a20cec6bdee3f8e47bae973fcdceb3eda5502207d467a9873c939bf3aa758014ae67295fedbca52412633f7e5b2670fc7c381c1", }, { name: "commitment tx with three outputs untrimmed (minimum feerate)", commitment: channeldb.ChannelCommitment{ CommitHeight: 42, LocalBalance: 6988000000, RemoteBalance: 3000000000, FeePerKw: 3703, }, htlcDescs: []htlcDesc{ { remoteSigHex: "3044022044f65cf833afdcb9d18795ca93f7230005777662539815b8a601eeb3e57129a902206a4bf3e53392affbba52640627defa8dc8af61c958c9e827b2798ab45828abdd", resolutionTxHex: "020000000001011c076aa7fb3d7460d10df69432c904227ea84bbf3134d4ceee5fb0f135ef206d0000000000000000000175050000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500473044022044f65cf833afdcb9d18795ca93f7230005777662539815b8a601eeb3e57129a902206a4bf3e53392affbba52640627defa8dc8af61c958c9e827b2798ab45828abdd01483045022100b94d931a811b32eeb885c28ddcf999ae1981893b21dd1329929543fe87ce793002206370107fdd151c5f2384f9ceb71b3107c69c74c8ed5a28a94a4ab2d27d3b0724012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", }, }, expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110eb936a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400473044022047305531dd44391dce03ae20f8735005c615eb077a974edb0059ea1a311857d602202e0ed6972fbdd1e8cb542b06e0929bc41b2ddf236e04cb75edd56151f4197506014830450221008b7c191dd46893b67b628e618d2dc8e81169d38bade310181ab77d7c94c6675e02203b4dd131fd7c9deb299560983dcdc485545c98f989f7ae8180c28289f9e6bdb001475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", remoteSigHex: "30450221008b7c191dd46893b67b628e618d2dc8e81169d38bade310181ab77d7c94c6675e02203b4dd131fd7c9deb299560983dcdc485545c98f989f7ae8180c28289f9e6bdb0", }, { name: "commitment tx with three outputs untrimmed (maximum feerate)", commitment: channeldb.ChannelCommitment{ CommitHeight: 42, LocalBalance: 6988000000, RemoteBalance: 3000000000, FeePerKw: 4914, }, htlcDescs: []htlcDesc{ { remoteSigHex: "3045022100fcb38506bfa11c02874092a843d0cc0a8613c23b639832564a5f69020cb0f6ba02206508b9e91eaa001425c190c68ee5f887e1ad5b1b314002e74db9dbd9e42dbecf", resolutionTxHex: "0200000000010110a3fdcbcd5db477cd3ad465e7f501ffa8c437e8301f00a6061138590add757f0000000000000000000122020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100fcb38506bfa11c02874092a843d0cc0a8613c23b639832564a5f69020cb0f6ba02206508b9e91eaa001425c190c68ee5f887e1ad5b1b314002e74db9dbd9e42dbecf0148304502210086e76b460ddd3cea10525fba298405d3fe11383e56966a5091811368362f689a02200f72ee75657915e0ede89c28709acd113ede9e1b7be520e3bc5cda425ecd6e68012004040404040404040404040404040404040404040404040404040404040404048a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a91418bc1a114ccf9c052d3d23e28d3b0a9d1227434288527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f801b175ac686800000000", }, }, expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206a2679efa3c7aaffd2a447fd0df7aba8792858b589750f6a1203f9259173198a022008d52a0e77a99ab533c36206cb15ad7aeb2aa72b93d4b571e728cb5ec2f6fe260147304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", remoteSigHex: "304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e", }, { name: "commitment tx with two outputs untrimmed (minimum feerate)", commitment: channeldb.ChannelCommitment{ CommitHeight: 42, LocalBalance: 6988000000, RemoteBalance: 3000000000, FeePerKw: 4915, }, htlcDescs: []htlcDesc{}, expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8002c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110fa926a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0400483045022100a012691ba6cea2f73fa8bac37750477e66363c6d28813b0bb6da77c8eb3fb0270220365e99c51304b0b1a6ab9ea1c8500db186693e39ec1ad5743ee231b0138384b90147304402200769ba89c7330dfa4feba447b6e322305f12ac7dac70ec6ba997ed7c1b598d0802204fe8d337e7fee781f9b7b1a06e580b22f4f79d740059560191d7db53f876555201475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", remoteSigHex: "304402200769ba89c7330dfa4feba447b6e322305f12ac7dac70ec6ba997ed7c1b598d0802204fe8d337e7fee781f9b7b1a06e580b22f4f79d740059560191d7db53f8765552", }, { name: "commitment tx with two outputs untrimmed (maximum feerate)", commitment: channeldb.ChannelCommitment{ CommitHeight: 42, LocalBalance: 6988000000, RemoteBalance: 3000000000, FeePerKw: 9651180, }, htlcDescs: []htlcDesc{}, expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b800222020000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80ec0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de84311004004730440220514f977bf7edc442de8ce43ace9686e5ebdc0f893033f13e40fb46c8b8c6e1f90220188006227d175f5c35da0b092c57bea82537aed89f7778204dc5bacf4f29f2b901473044022037f83ff00c8e5fb18ae1f918ffc24e54581775a20ff1ae719297ef066c71caa9022039c529cccd89ff6c5ed1db799614533844bd6d101da503761c45c713996e3bbd01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", remoteSigHex: "3044022037f83ff00c8e5fb18ae1f918ffc24e54581775a20ff1ae719297ef066c71caa9022039c529cccd89ff6c5ed1db799614533844bd6d101da503761c45c713996e3bbd", }, { name: "commitment tx with one output untrimmed (minimum feerate)", commitment: channeldb.ChannelCommitment{ CommitHeight: 42, LocalBalance: 6988000000, RemoteBalance: 3000000000, FeePerKw: 9651181, }, htlcDescs: []htlcDesc{}, expectedCommitmentTxHex: "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de8431100400473044022031a82b51bd014915fe68928d1abf4b9885353fb896cac10c3fdd88d7f9c7f2e00220716bda819641d2c63e65d3549b6120112e1aeaf1742eed94a471488e79e206b101473044022064901950be922e62cbe3f2ab93de2b99f37cff9fc473e73e394b27f88ef0731d02206d1dfa227527b4df44a07599289e207d6fd9cca60c0365682dcd3deaf739567e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", remoteSigHex: "3044022064901950be922e62cbe3f2ab93de2b99f37cff9fc473e73e394b27f88ef0731d02206d1dfa227527b4df44a07599289e207d6fd9cca60c0365682dcd3deaf739567e", }, } // 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() for _, test := range testCases { test := test t.Run(test.name, func(t *testing.T) { testVectors(t, test) }) } } // addTestHtlcs adds the test vector htlcs to the update logs of the local and // remote node. func addTestHtlcs(t *testing.T, remote, local *LightningChannel) map[[20]byte]lntypes.Preimage { hash160map := make(map[[20]byte]lntypes.Preimage) for _, htlc := range testHtlcs { preimage, err := lntypes.MakePreimageFromStr(htlc.preimage) require.NoError(t, err) hash := preimage.Hash() // Store ripemd160 hash of the payment hash to later identify // resolutions. var hash160 [20]byte copy(hash160[:], input.Ripemd160H(hash[:])) hash160map[hash160] = preimage // Add htlc to the channel. chanID := lnwire.NewChanIDFromOutPoint(remote.ChanPoint) msg := &lnwire.UpdateAddHTLC{ Amount: htlc.amount, ChanID: chanID, Expiry: htlc.expiry, PaymentHash: hash, } if htlc.incoming { htlcID, err := remote.AddHTLC(msg, nil) require.NoError(t, err, "unable to add htlc") msg.ID = htlcID _, err = local.ReceiveHTLC(msg) require.NoError(t, err, "unable to recv htlc") } else { htlcID, err := local.AddHTLC(msg, nil) require.NoError(t, err, "unable to add htlc") msg.ID = htlcID _, err = remote.ReceiveHTLC(msg) require.NoError(t, err, "unable to recv htlc") } } return hash160map } // testVectors executes a commit dance to end up with the commitment transaction // that is described in the test vectors and then asserts that all values are // correct. func testVectors(t *testing.T, test testCase) { tc := newTestContext(t) // Balances in the test vectors are before subtraction of in-flight // htlcs. Convert to spendable balances. remoteBalance := test.commitment.RemoteBalance localBalance := test.commitment.LocalBalance if test.htlcDescs != nil { for _, htlc := range testHtlcs { if htlc.incoming { remoteBalance += htlc.amount } else { localBalance += htlc.amount } } } // This should actually be tweakless. Update once // https://github.com/lightningnetwork/lightning-rfc/pull/758 is merged. chanType := channeldb.SingleFunderBit // Set up a test channel on which the test commitment transaction is // going to be produced. remoteChannel, localChannel, cleanUp := createTestChannelsForVectors( tc, chanType, test.commitment.FeePerKw, remoteBalance.ToSatoshis(), localBalance.ToSatoshis(), ) defer cleanUp() // Add htlcs (if any) to the update logs of both sides and save a hash // map that allows us to identify the htlcs in the scripts later on and // retrieve the corresponding preimage. var hash160map map[[20]byte]lntypes.Preimage if test.htlcDescs != nil { hash160map = addTestHtlcs(t, remoteChannel, localChannel) } // Execute commit dance to arrive at the point where the local node has // received the test commitment and the remote signature. localSig, localHtlcSigs, _, err := localChannel.SignNextCommitment() require.NoError(t, err, "local unable to sign commitment") err = remoteChannel.ReceiveNewCommitment(localSig, localHtlcSigs) require.NoError(t, err) revMsg, _, err := remoteChannel.RevokeCurrentCommitment() require.NoError(t, err) _, _, _, _, err = localChannel.ReceiveRevocation(revMsg) require.NoError(t, err) remoteSig, remoteHtlcSigs, _, err := remoteChannel.SignNextCommitment() require.NoError(t, err) require.Equal(t, test.remoteSigHex, hex.EncodeToString(remoteSig.ToSignatureBytes())) for i, sig := range remoteHtlcSigs { require.Equal(t, test.htlcDescs[i].remoteSigHex, hex.EncodeToString(sig.ToSignatureBytes())) } err = localChannel.ReceiveNewCommitment(remoteSig, remoteHtlcSigs) require.NoError(t, err) _, _, err = localChannel.RevokeCurrentCommitment() require.NoError(t, err) // Now the local node force closes the channel so that we can inspect // its state. forceCloseSum, err := localChannel.ForceClose() require.NoError(t, err) // Assert that the commitment transaction itself is as expected. var txBytes bytes.Buffer require.NoError(t, forceCloseSum.CloseTx.Serialize(&txBytes)) require.Equal(t, test.expectedCommitmentTxHex, hex.EncodeToString(txBytes.Bytes())) // Obtain the second level transactions that the local node's channel // state machine has produced. Store them in a map indexed by commit tx // output index. Also complete the second level transaction with the // preimage. This is normally done later in the contract resolver. secondLevelTxes := map[uint32]*wire.MsgTx{} storeTx := func(index uint32, tx *wire.MsgTx) { // Prevent overwrites. _, exists := secondLevelTxes[index] require.False(t, exists) secondLevelTxes[index] = tx } for _, r := range forceCloseSum.HtlcResolutions.IncomingHTLCs { successTx := r.SignedSuccessTx witnessScript := successTx.TxIn[0].Witness[4] var hash160 [20]byte copy(hash160[:], witnessScript[69:69+20]) preimage := hash160map[hash160] successTx.TxIn[0].Witness[3] = preimage[:] storeTx(r.HtlcPoint().Index, successTx) } for _, r := range forceCloseSum.HtlcResolutions.OutgoingHTLCs { storeTx(r.HtlcPoint().Index, r.SignedTimeoutTx) } // Create a list of second level transactions ordered by commit tx // output index. var keys []uint32 for k := range secondLevelTxes { keys = append(keys, k) } sort.Slice(keys, func(a, b int) bool { return keys[a] < keys[b] }) // Assert that this list matches the test vectors. for i, idx := range keys { tx := secondLevelTxes[idx] var b bytes.Buffer err := tx.Serialize(&b) require.NoError(t, err) require.Equal( t, test.htlcDescs[i].resolutionTxHex, hex.EncodeToString(b.Bytes()), ) } } // 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 } func TestCommitTxStateHint(t *testing.T) { t.Parallel() stateHintTests := []struct { name string from uint64 to uint64 inputs int shouldFail bool }{ { name: "states 0 to 1000", from: 0, to: 1000, inputs: 1, shouldFail: false, }, { name: "states 'maxStateHint-1000' to 'maxStateHint'", from: maxStateHint - 1000, to: maxStateHint, inputs: 1, shouldFail: false, }, { name: "state 'maxStateHint+1'", from: maxStateHint + 1, to: maxStateHint + 10, inputs: 1, shouldFail: true, }, { name: "commit transaction with two inputs", inputs: 2, shouldFail: true, }, } var obfuscator [StateHintSize]byte copy(obfuscator[:], testHdSeed[:StateHintSize]) timeYesterday := uint32(time.Now().Unix() - 24*60*60) for _, test := range stateHintTests { commitTx := wire.NewMsgTx(2) // Add supplied number of inputs to the commitment transaction. for i := 0; i < test.inputs; i++ { commitTx.AddTxIn(&wire.TxIn{}) } for i := test.from; i <= test.to; i++ { stateNum := uint64(i) err := SetStateNumHint(commitTx, stateNum, obfuscator) if err != nil && !test.shouldFail { t.Fatalf("unable to set state num %v: %v", i, err) } else if err == nil && test.shouldFail { t.Fatalf("Failed(%v): test should fail but did not", test.name) } locktime := commitTx.LockTime sequence := commitTx.TxIn[0].Sequence // Locktime should not be less than 500,000,000 and not larger // than the time 24 hours ago. One day should provide a good // enough buffer for the tests. if locktime < 5e8 || locktime > timeYesterday { if !test.shouldFail { t.Fatalf("The value of locktime (%v) may cause the commitment "+ "transaction to be unspendable", locktime) } } if sequence&wire.SequenceLockTimeDisabled == 0 { if !test.shouldFail { t.Fatalf("Sequence locktime is NOT disabled when it should be") } } extractedStateNum := GetStateNumHint(commitTx, obfuscator) if extractedStateNum != stateNum && !test.shouldFail { t.Fatalf("state number mismatched, expected %v, got %v", stateNum, extractedStateNum) } else if extractedStateNum == stateNum && test.shouldFail { t.Fatalf("Failed(%v): test should fail but did not", test.name) } } t.Logf("Passed: %v", test.name) } } // testSpendValidation ensures that we're able to spend all outputs in the // commitment transaction that we create. func testSpendValidation(t *testing.T, tweakless bool) { // We generate a fake output, and the corresponding txin. This output // doesn't need to exist, as we'll only be validating spending from the // transaction that references this. txid, err := chainhash.NewHash(testHdSeed.CloneBytes()) if err != nil { t.Fatalf("unable to create txid: %v", err) } fundingOut := &wire.OutPoint{ Hash: *txid, Index: 50, } fakeFundingTxIn := wire.NewTxIn(fundingOut, nil, nil) const channelBalance = btcutil.Amount(1 * 10e8) const csvTimeout = 5 // We also set up set some resources for the commitment transaction. // Each side currently has 1 BTC within the channel, with a total // channel capacity of 2BTC. aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes( btcec.S256(), testWalletPrivKey, ) bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes( btcec.S256(), bobsPrivKey, ) revocationPreimage := testHdSeed.CloneBytes() commitSecret, commitPoint := btcec.PrivKeyFromBytes( btcec.S256(), revocationPreimage, ) revokePubKey := input.DeriveRevocationPubkey(bobKeyPub, commitPoint) aliceDelayKey := input.TweakPubKey(aliceKeyPub, commitPoint) // Bob will have the channel "force closed" on him, so for the sake of // our commitments, if it's tweakless, his key will just be his regular // pubkey. bobPayKey := input.TweakPubKey(bobKeyPub, commitPoint) channelType := channeldb.SingleFunderBit if tweakless { bobPayKey = bobKeyPub channelType = channeldb.SingleFunderTweaklessBit } remoteCommitTweak := input.SingleTweakBytes(commitPoint, aliceKeyPub) localCommitTweak := input.SingleTweakBytes(commitPoint, bobKeyPub) aliceSelfOutputSigner := &input.MockSigner{ Privkeys: []*btcec.PrivateKey{aliceKeyPriv}, } aliceChanCfg := &channeldb.ChannelConfig{ ChannelConstraints: channeldb.ChannelConstraints{ DustLimit: DefaultDustLimit(), CsvDelay: csvTimeout, }, } bobChanCfg := &channeldb.ChannelConfig{ ChannelConstraints: channeldb.ChannelConstraints{ DustLimit: DefaultDustLimit(), CsvDelay: csvTimeout, }, } // With all the test data set up, we create the commitment transaction. // We only focus on a single party's transactions, as the scripts are // identical with the roles reversed. // // This is Alice's commitment transaction, so she must wait a CSV delay // of 5 blocks before sweeping the output, while bob can spend // immediately with either the revocation key, or his regular key. keyRing := &CommitmentKeyRing{ ToLocalKey: aliceDelayKey, RevocationKey: revokePubKey, ToRemoteKey: bobPayKey, } commitmentTx, err := CreateCommitTx( channelType, *fakeFundingTxIn, keyRing, aliceChanCfg, bobChanCfg, channelBalance, channelBalance, 0, ) if err != nil { t.Fatalf("unable to create commitment transaction: %v", nil) } delayOutput := commitmentTx.TxOut[0] regularOutput := commitmentTx.TxOut[1] // We're testing an uncooperative close, output sweep, so construct a // transaction which sweeps the funds to a random address. targetOutput, err := input.CommitScriptUnencumbered(aliceKeyPub) if err != nil { t.Fatalf("unable to create target output: %v", err) } sweepTx := wire.NewMsgTx(2) sweepTx.AddTxIn(wire.NewTxIn(&wire.OutPoint{ Hash: commitmentTx.TxHash(), Index: 0, }, nil, nil)) sweepTx.AddTxOut(&wire.TxOut{ PkScript: targetOutput, Value: 0.5 * 10e8, }) // First, we'll test spending with Alice's key after the timeout. delayScript, err := input.CommitScriptToSelf( csvTimeout, aliceDelayKey, revokePubKey, ) if err != nil { t.Fatalf("unable to generate alice delay script: %v", err) } sweepTx.TxIn[0].Sequence = input.LockTimeToSequence(false, csvTimeout) signDesc := &input.SignDescriptor{ WitnessScript: delayScript, KeyDesc: keychain.KeyDescriptor{ PubKey: aliceKeyPub, }, SingleTweak: remoteCommitTweak, SigHashes: txscript.NewTxSigHashes(sweepTx), Output: &wire.TxOut{ Value: int64(channelBalance), }, HashType: txscript.SigHashAll, InputIndex: 0, } aliceWitnessSpend, err := input.CommitSpendTimeout( aliceSelfOutputSigner, signDesc, sweepTx, ) if err != nil { t.Fatalf("unable to generate delay commit spend witness: %v", err) } sweepTx.TxIn[0].Witness = aliceWitnessSpend vm, err := txscript.NewEngine(delayOutput.PkScript, sweepTx, 0, txscript.StandardVerifyFlags, nil, nil, int64(channelBalance)) if err != nil { t.Fatalf("unable to create engine: %v", err) } if err := vm.Execute(); err != nil { t.Fatalf("spend from delay output is invalid: %v", err) } localSigner := &input.MockSigner{Privkeys: []*btcec.PrivateKey{bobKeyPriv}} // Next, we'll test bob spending with the derived revocation key to // simulate the scenario when Alice broadcasts this commitment // transaction after it's been revoked. signDesc = &input.SignDescriptor{ KeyDesc: keychain.KeyDescriptor{ PubKey: bobKeyPub, }, DoubleTweak: commitSecret, WitnessScript: delayScript, SigHashes: txscript.NewTxSigHashes(sweepTx), Output: &wire.TxOut{ Value: int64(channelBalance), }, HashType: txscript.SigHashAll, InputIndex: 0, } bobWitnessSpend, err := input.CommitSpendRevoke(localSigner, signDesc, sweepTx) if err != nil { t.Fatalf("unable to generate revocation witness: %v", err) } sweepTx.TxIn[0].Witness = bobWitnessSpend vm, err = txscript.NewEngine(delayOutput.PkScript, sweepTx, 0, txscript.StandardVerifyFlags, nil, nil, int64(channelBalance)) if err != nil { t.Fatalf("unable to create engine: %v", err) } if err := vm.Execute(); err != nil { t.Fatalf("revocation spend is invalid: %v", err) } // In order to test the final scenario, we modify the TxIn of the sweep // transaction to instead point to the regular output (non delay) // within the commitment transaction. sweepTx.TxIn[0] = &wire.TxIn{ PreviousOutPoint: wire.OutPoint{ Hash: commitmentTx.TxHash(), Index: 1, }, } // Finally, we test bob sweeping his output as normal in the case that // Alice broadcasts this commitment transaction. bobScriptP2WKH, err := input.CommitScriptUnencumbered(bobPayKey) if err != nil { t.Fatalf("unable to create bob p2wkh script: %v", err) } signDesc = &input.SignDescriptor{ KeyDesc: keychain.KeyDescriptor{ PubKey: bobKeyPub, }, WitnessScript: bobScriptP2WKH, SigHashes: txscript.NewTxSigHashes(sweepTx), Output: &wire.TxOut{ Value: int64(channelBalance), PkScript: bobScriptP2WKH, }, HashType: txscript.SigHashAll, InputIndex: 0, } if !tweakless { signDesc.SingleTweak = localCommitTweak } bobRegularSpend, err := input.CommitSpendNoDelay( localSigner, signDesc, sweepTx, tweakless, ) if err != nil { t.Fatalf("unable to create bob regular spend: %v", err) } sweepTx.TxIn[0].Witness = bobRegularSpend vm, err = txscript.NewEngine( regularOutput.PkScript, sweepTx, 0, txscript.StandardVerifyFlags, nil, nil, int64(channelBalance), ) if err != nil { t.Fatalf("unable to create engine: %v", err) } if err := vm.Execute(); err != nil { t.Fatalf("bob p2wkh spend is invalid: %v", err) } } // TestCommitmentSpendValidation test the spendability of both outputs within // the commitment transaction. // // The following spending cases are covered by this test: // * Alice's spend from the delayed output on her commitment transaction. // * Bob's spend from Alice's delayed output when she broadcasts a revoked // commitment transaction. // * Bob's spend from his unencumbered output within Alice's commitment // transaction. func TestCommitmentSpendValidation(t *testing.T) { t.Parallel() // In the modern network, all channels use the new tweakless format, // but we also need to support older nodes that want to open channels // with the legacy format, so we'll test spending in both scenarios. for _, tweakless := range []bool{true, false} { tweakless := tweakless t.Run(fmt.Sprintf("tweak=%v", tweakless), func(t *testing.T) { testSpendValidation(t, tweakless) }) } } type mockProducer struct { secret chainhash.Hash } func (p *mockProducer) AtIndex(uint64) (*chainhash.Hash, error) { return &p.secret, nil } func (p *mockProducer) Encode(w io.Writer) error { _, err := w.Write(p.secret[:]) return err } // createTestChannelsForVectors creates two LightningChannel instances for the // test channel that is used to verify the test vectors. func createTestChannelsForVectors(tc *testContext, chanType channeldb.ChannelType, feeRate btcutil.Amount, remoteBalance, localBalance btcutil.Amount) ( *LightningChannel, *LightningChannel, func()) { t := tc.t prevOut := &wire.OutPoint{ Hash: *tc.fundingTx.Hash(), Index: 0, } fundingTxIn := wire.NewTxIn(prevOut, nil, nil) // Generate random some keys that don't actually matter but need to be // set. var ( remoteDummy1, remoteDummy2 *btcec.PrivateKey localDummy2, localDummy1 *btcec.PrivateKey ) generateKeys := []**btcec.PrivateKey{ &remoteDummy1, &remoteDummy2, &localDummy1, &localDummy2, } for _, keyRef := range generateKeys { privkey, err := btcec.NewPrivateKey(btcec.S256()) require.NoError(t, err) *keyRef = privkey } // Define channel configurations. remoteCfg := channeldb.ChannelConfig{ ChannelConstraints: channeldb.ChannelConstraints{ DustLimit: tc.dustLimit, MaxPendingAmount: lnwire.NewMSatFromSatoshis( tc.fundingAmount, ), ChanReserve: 0, MinHTLC: 0, MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, CsvDelay: tc.localCsvDelay, }, MultiSigKey: keychain.KeyDescriptor{ PubKey: tc.remoteFundingPrivkey.PubKey(), }, PaymentBasePoint: keychain.KeyDescriptor{ PubKey: tc.remotePaymentBasepointSecret.PubKey(), }, HtlcBasePoint: keychain.KeyDescriptor{ PubKey: tc.remotePaymentBasepointSecret.PubKey(), }, DelayBasePoint: keychain.KeyDescriptor{ PubKey: remoteDummy1.PubKey(), }, RevocationBasePoint: keychain.KeyDescriptor{ PubKey: tc.remoteRevocationBasepointSecret.PubKey(), }, } localCfg := channeldb.ChannelConfig{ ChannelConstraints: channeldb.ChannelConstraints{ DustLimit: tc.dustLimit, MaxPendingAmount: lnwire.NewMSatFromSatoshis( tc.fundingAmount, ), ChanReserve: 0, MinHTLC: 0, MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, CsvDelay: tc.localCsvDelay, }, MultiSigKey: keychain.KeyDescriptor{ PubKey: tc.localFundingPrivkey.PubKey(), }, PaymentBasePoint: keychain.KeyDescriptor{ PubKey: tc.localPaymentBasepointSecret.PubKey(), }, HtlcBasePoint: keychain.KeyDescriptor{ PubKey: tc.localPaymentBasepointSecret.PubKey(), }, DelayBasePoint: keychain.KeyDescriptor{ PubKey: tc.localDelayedPaymentBasepointSecret.PubKey(), }, RevocationBasePoint: keychain.KeyDescriptor{ PubKey: localDummy1.PubKey(), }, } // Create mock producers to force usage of the test vector commitment // point. remotePreimageProducer := &mockProducer{ secret: chainhash.Hash(tc.localPerCommitSecret), } remoteCommitPoint := input.ComputeCommitmentPoint( tc.localPerCommitSecret[:], ) localPreimageProducer := &mockProducer{ secret: chainhash.Hash(tc.localPerCommitSecret), } localCommitPoint := input.ComputeCommitmentPoint( tc.localPerCommitSecret[:], ) // Create temporary databases. remotePath, err := ioutil.TempDir("", "remotedb") require.NoError(t, err) dbRemote, err := channeldb.Open(remotePath) require.NoError(t, err) localPath, err := ioutil.TempDir("", "localdb") require.NoError(t, err) dbLocal, err := channeldb.Open(localPath) require.NoError(t, err) // Create the initial commitment transactions for the channel. feePerKw := chainfee.SatPerKWeight(feeRate) commitWeight := int64(input.CommitWeight) commitFee := feePerKw.FeeForWeight(commitWeight) remoteCommitTx, localCommitTx, err := CreateCommitmentTxns( remoteBalance, localBalance-commitFee, &remoteCfg, &localCfg, remoteCommitPoint, localCommitPoint, *fundingTxIn, chanType, ) require.NoError(t, err) // Set up the full channel state. // Subtract one because extra sig exchange will take place during setup // to get to the right test point. var commitHeight = tc.commitHeight - 1 remoteCommit := channeldb.ChannelCommitment{ CommitHeight: commitHeight, LocalBalance: lnwire.NewMSatFromSatoshis(remoteBalance), RemoteBalance: lnwire.NewMSatFromSatoshis(localBalance - commitFee), CommitFee: commitFee, FeePerKw: btcutil.Amount(feePerKw), CommitTx: remoteCommitTx, CommitSig: testSigBytes, } localCommit := channeldb.ChannelCommitment{ CommitHeight: commitHeight, LocalBalance: lnwire.NewMSatFromSatoshis(localBalance - commitFee), RemoteBalance: lnwire.NewMSatFromSatoshis(remoteBalance), CommitFee: commitFee, FeePerKw: btcutil.Amount(feePerKw), CommitTx: localCommitTx, CommitSig: testSigBytes, } var chanIDBytes [8]byte _, err = io.ReadFull(rand.Reader, chanIDBytes[:]) require.NoError(t, err) shortChanID := lnwire.NewShortChanIDFromInt( binary.BigEndian.Uint64(chanIDBytes[:]), ) remoteChannelState := &channeldb.OpenChannel{ LocalChanCfg: remoteCfg, RemoteChanCfg: localCfg, IdentityPub: remoteDummy2.PubKey(), FundingOutpoint: *prevOut, ShortChannelID: shortChanID, ChanType: chanType, IsInitiator: false, Capacity: tc.fundingAmount, RemoteCurrentRevocation: localCommitPoint, RevocationProducer: remotePreimageProducer, RevocationStore: shachain.NewRevocationStore(), LocalCommitment: remoteCommit, RemoteCommitment: remoteCommit, Db: dbRemote, Packager: channeldb.NewChannelPackager(shortChanID), FundingTxn: tc.fundingTx.MsgTx(), } localChannelState := &channeldb.OpenChannel{ LocalChanCfg: localCfg, RemoteChanCfg: remoteCfg, IdentityPub: localDummy2.PubKey(), FundingOutpoint: *prevOut, ShortChannelID: shortChanID, ChanType: chanType, IsInitiator: true, Capacity: tc.fundingAmount, RemoteCurrentRevocation: remoteCommitPoint, RevocationProducer: localPreimageProducer, RevocationStore: shachain.NewRevocationStore(), LocalCommitment: localCommit, RemoteCommitment: localCommit, Db: dbLocal, Packager: channeldb.NewChannelPackager(shortChanID), FundingTxn: tc.fundingTx.MsgTx(), } // Create mock signers that can sign for the keys that are used. localSigner := &input.MockSigner{Privkeys: []*btcec.PrivateKey{ tc.localPaymentBasepointSecret, tc.localDelayedPaymentBasepointSecret, tc.localFundingPrivkey, localDummy1, localDummy2, }} remoteSigner := &input.MockSigner{Privkeys: []*btcec.PrivateKey{ tc.remoteFundingPrivkey, tc.remoteRevocationBasepointSecret, tc.remotePaymentBasepointSecret, remoteDummy1, remoteDummy2, }} remotePool := NewSigPool(1, remoteSigner) channelRemote, err := NewLightningChannel( remoteSigner, remoteChannelState, remotePool, ) require.NoError(t, err) require.NoError(t, remotePool.Start()) localPool := NewSigPool(1, localSigner) channelLocal, err := NewLightningChannel( localSigner, localChannelState, localPool, ) require.NoError(t, err) require.NoError(t, localPool.Start()) // Create state hunt obfuscator for the commitment transaction. obfuscator := createStateHintObfuscator(remoteChannelState) err = SetStateNumHint( remoteCommitTx, commitHeight, obfuscator, ) require.NoError(t, err) err = SetStateNumHint( localCommitTx, commitHeight, obfuscator, ) require.NoError(t, err) // Initialize the database. addr := &net.TCPAddr{ IP: net.ParseIP("127.0.0.1"), Port: 18556, } require.NoError(t, channelRemote.channelState.SyncPending(addr, 101)) addr = &net.TCPAddr{ IP: net.ParseIP("127.0.0.1"), Port: 18555, } require.NoError(t, channelLocal.channelState.SyncPending(addr, 101)) // Now that the channel are open, simulate the start of a session by // having local and remote extend their revocation windows to each other. err = initRevocationWindows(channelRemote, channelLocal) require.NoError(t, err) // Return a clean up function that stops goroutines and removes the test // databases. cleanUpFunc := func() { os.RemoveAll(localPath) os.RemoveAll(remotePath) require.NoError(t, remotePool.Stop()) require.NoError(t, localPool.Stop()) } return channelRemote, channelLocal, cleanUpFunc }