From e679fc9325e70ba3d9d3e596f3f13b02f2080169 Mon Sep 17 00:00:00 2001 From: quake Date: Wed, 13 Nov 2024 10:11:26 +0900 Subject: [PATCH 1/8] chore: rebase e2e watchtower --- Cargo.lock | 671 +++++++--- rust-toolchain.toml | 2 +- src/fiber/channel.rs | 822 +++++++----- src/fiber/config.rs | 9 + src/fiber/gen/fiber.rs | 1098 +++-------------- src/fiber/network.rs | 42 +- src/fiber/schema/fiber.mol | 33 +- src/fiber/tests/channel.rs | 58 +- src/fiber/types.rs | 30 +- src/main.rs | 66 +- src/rpc/README.md | 24 + src/rpc/channel.rs | 8 + src/rpc/config.rs | 12 + src/rpc/dev.rs | 105 ++ src/rpc/mod.rs | 94 +- src/store/store.rs | 20 +- src/store/tests/store.rs | 6 +- src/watchtower/actor.rs | 437 +++++-- src/watchtower/mod.rs | 4 +- src/watchtower/store.rs | 25 +- .../force-close/01-connect-peer.bru | 38 + .../force-close/02-open-channel.bru | 39 + .../03-get-auto-accepted-channel.bru | 40 + .../force-close/04-generate-a-few-blocks.bru | 33 + .../force-close/05-node2-gen-invoice.bru | 65 + .../06-node1-send-payment-with-invoice.bru | 45 + .../watchtower/force-close/07-force-close.bru | 40 + ...08-get-force-closed-commitment-tx-hash.bru | 39 + ...enerate-a-few-blocks-for-commitment-tx.bru | 34 + ...few-blocks-for-settlement-tx-generated.bru | 34 + ...few-blocks-for-settlement-tx-committed.bru | 33 + .../force-close/12-check-commitment-tx.bru | 39 + .../watchtower/revocation/01-connect-peer.bru | 38 + .../watchtower/revocation/02-open-channel.bru | 39 + .../03-get-auto-accepted-channel.bru | 40 + .../revocation/04-generate-a-few-blocks.bru | 33 + .../revocation/05-node3-gen-invoice.bru | 65 + .../06-node1-send-payment-with-invoice.bru | 45 + .../07-submit-old-version-commitment-tx.bru | 35 + ...enerate-a-few-blocks-for-commitment-tx.bru | 34 + ...enerate-a-few-blocks-for-revocation-tx.bru | 34 + .../revocation/10-check-commitment-tx.bru | 39 + tests/nodes/deployer/config.yml | 9 + 43 files changed, 2763 insertions(+), 1693 deletions(-) create mode 100644 src/rpc/dev.rs create mode 100644 tests/bruno/e2e/watchtower/force-close/01-connect-peer.bru create mode 100644 tests/bruno/e2e/watchtower/force-close/02-open-channel.bru create mode 100644 tests/bruno/e2e/watchtower/force-close/03-get-auto-accepted-channel.bru create mode 100644 tests/bruno/e2e/watchtower/force-close/04-generate-a-few-blocks.bru create mode 100644 tests/bruno/e2e/watchtower/force-close/05-node2-gen-invoice.bru create mode 100644 tests/bruno/e2e/watchtower/force-close/06-node1-send-payment-with-invoice.bru create mode 100644 tests/bruno/e2e/watchtower/force-close/07-force-close.bru create mode 100644 tests/bruno/e2e/watchtower/force-close/08-get-force-closed-commitment-tx-hash.bru create mode 100644 tests/bruno/e2e/watchtower/force-close/09-generate-a-few-blocks-for-commitment-tx.bru create mode 100644 tests/bruno/e2e/watchtower/force-close/10-generate-a-few-blocks-for-settlement-tx-generated.bru create mode 100644 tests/bruno/e2e/watchtower/force-close/11-generate-a-few-blocks-for-settlement-tx-committed.bru create mode 100644 tests/bruno/e2e/watchtower/force-close/12-check-commitment-tx.bru create mode 100644 tests/bruno/e2e/watchtower/revocation/01-connect-peer.bru create mode 100644 tests/bruno/e2e/watchtower/revocation/02-open-channel.bru create mode 100644 tests/bruno/e2e/watchtower/revocation/03-get-auto-accepted-channel.bru create mode 100644 tests/bruno/e2e/watchtower/revocation/04-generate-a-few-blocks.bru create mode 100644 tests/bruno/e2e/watchtower/revocation/05-node3-gen-invoice.bru create mode 100644 tests/bruno/e2e/watchtower/revocation/06-node1-send-payment-with-invoice.bru create mode 100644 tests/bruno/e2e/watchtower/revocation/07-submit-old-version-commitment-tx.bru create mode 100644 tests/bruno/e2e/watchtower/revocation/08-generate-a-few-blocks-for-commitment-tx.bru create mode 100644 tests/bruno/e2e/watchtower/revocation/09-generate-a-few-blocks-for-revocation-tx.bru create mode 100644 tests/bruno/e2e/watchtower/revocation/10-check-commitment-tx.bru diff --git a/Cargo.lock b/Cargo.lock index 6b27d8e4a..ff73a3151 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,9 +64,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -79,43 +79,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "arcode" @@ -127,6 +127,12 @@ dependencies = [ "fenwick", ] +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "async-stream" version = "0.3.6" @@ -146,7 +152,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -157,7 +163,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -344,7 +350,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.79", + "syn 2.0.90", "which", ] @@ -368,12 +374,18 @@ checksum = "1945a5048598e4189e239d3f809b19bdad4845c4b2ba400d304d2dcf26d2c462" dependencies = [ "bech32 0.9.1", "bitcoin-private", - "bitcoin_hashes", + "bitcoin_hashes 0.12.0", "hex_lit", "secp256k1 0.27.0", "serde", ] +[[package]] +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + [[package]] name = "bitcoin-private" version = "0.1.0" @@ -390,6 +402,16 @@ dependencies = [ "serde", ] +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative 0.2.1", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -462,9 +484,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -498,9 +520,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.30" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "jobserver", "libc", @@ -897,9 +919,9 @@ dependencies = [ [[package]] name = "ckb-sdk" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ffec62a524764661f5e64349fceccee1a677197fcef625a5fb93efd1a31100" +checksum = "75d816b57b37c49a99c715f07e120928d8139993523efec0b9e2faa94db7edce" dependencies = [ "anyhow", "bech32 0.8.1", @@ -1109,9 +1131,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -1141,9 +1163,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -1160,20 +1182,20 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "console" @@ -1232,9 +1254,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -1309,7 +1331,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -1333,7 +1355,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -1344,7 +1366,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -1391,7 +1413,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -1414,6 +1436,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "dlv-list" version = "0.5.2" @@ -1449,9 +1482,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if 1.0.0", ] @@ -1476,12 +1509,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1492,9 +1525,9 @@ checksum = "51e2ce894d53b295cf97b05685aa077950ff3e8541af83217fc720a6437169f8" [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fenwick" @@ -1529,9 +1562,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -1677,7 +1710,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -1767,7 +1800,7 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -1849,9 +1882,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heapsize" @@ -1874,12 +1907,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "hex" version = "0.4.3" @@ -1892,6 +1919,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + [[package]] name = "hex_lit" version = "0.1.1" @@ -2046,6 +2082,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -2054,12 +2208,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", ] [[package]] @@ -2101,7 +2266,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.2", "serde", ] @@ -2158,9 +2323,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jobserver" @@ -2173,9 +2338,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "fb15147158e79fd8b8afd0252522769c4f48725460b37338544d8379d94fc8f9" dependencies = [ "wasm-bindgen", ] @@ -2241,7 +2406,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -2304,15 +2469,15 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if 1.0.0", "windows-targets 0.52.6", @@ -2325,7 +2490,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b0c1f811ae288f86c6767055c55b5f7a721ca1e61bf1897a9ae2ec663e8aba1" dependencies = [ "bitcoin", - "hex-conservative", + "hex-conservative 0.1.2", ] [[package]] @@ -2362,6 +2527,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + [[package]] name = "lnd-grpc-tonic-client" version = "0.3.0" @@ -2470,7 +2641,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -2496,11 +2667,10 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi", "libc", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", @@ -2673,9 +2843,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.67" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8cefcf97f41316955f9294cd61f639bdcfa9f2f230faac6cb896aa8ab64704" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if 1.0.0", @@ -2694,7 +2864,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -2822,29 +2992,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -2892,12 +3062,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.22" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -2935,9 +3105,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -2979,7 +3149,7 @@ dependencies = [ "prost 0.12.6", "prost-types", "regex", - "syn 2.0.79", + "syn 2.0.90", "tempfile", ] @@ -3006,7 +3176,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -3134,9 +3304,9 @@ dependencies = [ [[package]] name = "reflink-copy" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc31414597d1cd7fdd2422798b7652a6329dda0fe0219e6335a13d5bcaa9aeb6" +checksum = "17400ed684c3a0615932f00c271ae3eea13e47056a1455821995122348ab6438" dependencies = [ "cfg-if 1.0.0", "rustix", @@ -3145,13 +3315,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -3166,9 +3336,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -3281,9 +3451,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags 2.6.0", "errno", @@ -3324,9 +3494,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -3377,7 +3547,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" dependencies = [ - "bitcoin_hashes", + "bitcoin_hashes 0.12.0", "rand 0.8.5", "secp256k1-sys 0.8.1", "serde", @@ -3403,6 +3573,17 @@ dependencies = [ "secp256k1-sys 0.10.1", ] +[[package]] +name = "secp256k1" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" +dependencies = [ + "bitcoin_hashes 0.14.0", + "rand 0.8.5", + "secp256k1-sys 0.10.1", +] + [[package]] name = "secp256k1-sys" version = "0.8.1" @@ -3445,9 +3626,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -3461,22 +3642,22 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -3492,9 +3673,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -3541,7 +3722,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -3670,9 +3851,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -3728,6 +3909,12 @@ dependencies = [ "xxhash-rust", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.11.1" @@ -3753,7 +3940,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -3775,9 +3962,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -3790,6 +3977,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -3813,9 +4011,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if 1.0.0", "fastrand", @@ -3826,9 +4024,9 @@ dependencies = [ [[package]] name = "tentacle" -version = "0.6.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d335523ec132a2bbefbaf403b52eba047fb50bc83bed2d0b1d22c119bae2fec1" +checksum = "6218c3269605008b5e88f4e91fa2e98e20491213c464dc6da8370858db89d92b" dependencies = [ "async-trait", "bytes", @@ -3838,7 +4036,6 @@ dependencies = [ "log", "molecule", "nohash-hasher", - "once_cell", "rand 0.8.5", "socket2", "tentacle-multiaddr", @@ -3867,9 +4064,9 @@ dependencies = [ [[package]] name = "tentacle-secio" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac8b23a7879426a4961acea6ae66287f7fe9a934d131a722cbb88f145e97fea" +checksum = "99df015b8649588f2958d4853eee221860f95d2721995857e9dde1462ceb3dc4" dependencies = [ "bs58", "bytes", @@ -3884,7 +4081,7 @@ dependencies = [ "rand 0.8.5", "rand_core 0.6.4", "ring", - "secp256k1 0.29.1", + "secp256k1 0.30.0", "sha2", "tokio", "tokio-util", @@ -3894,22 +4091,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -3962,6 +4159,16 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" version = "1.8.0" @@ -3979,9 +4186,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -4013,7 +4220,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -4067,9 +4274,9 @@ dependencies = [ [[package]] name = "tokio-yamux" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ed88a04bfbf9e70343a5748a423200ee0591c55e7e487d784a55ee8af17db9" +checksum = "208cecd45a38868bfc0a45aac52cb1aea4583c6b801bf57f351e9d531b23cb86" dependencies = [ "bytes", "futures", @@ -4077,6 +4284,7 @@ dependencies = [ "nohash-hasher", "tokio", "tokio-util", + "web-time", ] [[package]] @@ -4174,7 +4382,7 @@ dependencies = [ "proc-macro2", "prost-build", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -4244,9 +4452,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -4256,20 +4464,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -4298,9 +4506,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -4326,26 +4534,11 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-width" @@ -4383,15 +4576,27 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -4449,9 +4654,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "21d3b25c3ea1126a2ad5f4f9068483c2af1e64168f847abe863a526b8dbfe00b" dependencies = [ "cfg-if 1.0.0", "once_cell", @@ -4460,36 +4665,37 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "52857d4c32e496dc6537646b5b117081e71fd2ff06de792e3577a150627db283" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "951fe82312ed48443ac78b66fa43eded9999f738f6022e67aead7b708659e49a" dependencies = [ "cfg-if 1.0.0", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "920b0ffe069571ebbfc9ddc0b36ba305ef65577c94b06262ed793716a1afd981" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4497,28 +4703,38 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "bf59002391099644be3524e23b781fa43d2be0c5aa0719a18c0731b9d195cab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "e5047c5392700766601942795a436d7d2599af60dcc3cc1248c9120bfb0827b0" [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "476364ff87d0ae6bfb661053a9104ab312542658c3d8f963b7ace80b6f9b26b9" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -4607,7 +4823,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -4618,7 +4834,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -4807,6 +5023,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "x25519-dalek" version = "2.0.1" @@ -4825,6 +5053,30 @@ version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984" +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -4843,7 +5095,28 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", ] [[package]] @@ -4863,5 +5136,27 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] diff --git a/rust-toolchain.toml b/rust-toolchain.toml index d8e821e88..e2df5b625 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.76.0" +channel = "1.81.0" components = [ "rustfmt", "clippy" ] profile = "minimal" diff --git a/src/fiber/channel.rs b/src/fiber/channel.rs index f0aa15a67..8f6fee887 100644 --- a/src/fiber/channel.rs +++ b/src/fiber/channel.rs @@ -9,7 +9,7 @@ use crate::{ fiber::{ fee::calculate_tlc_forward_fee, network::{get_chain_hash, SendOnionPacketCommand}, - serde_utils::PubNonceAsBytes, + serde_utils::{CompactSignatureAsBytes, PubNonceAsBytes}, types::{ChannelUpdate, PeeledPaymentOnionPacket, TlcErr, TlcErrPacket, TlcErrorCode}, }, invoice::{CkbInvoice, CkbInvoiceStatus, InvoiceStore}, @@ -47,7 +47,7 @@ use tokio::sync::oneshot; use std::{ borrow::Borrow, - collections::BTreeMap, + collections::{BTreeMap, HashMap}, fmt::Debug, sync::Arc, time::{SystemTime, UNIX_EPOCH}, @@ -87,6 +87,13 @@ use super::{ // - `pubkey`: 32 bytes, x only aggregated public key // - `signature`: 64 bytes, aggregated signature pub const FUNDING_CELL_WITNESS_LEN: usize = 16 + 32 + 64; + +// - `empty_witness_args`: 16 bytes, fixed to 0x10000000100000001000000010000000, for compatibility with the xudt +// - `unlock_type`: 1 byte +// - `pubkey`: 32 bytes, x only aggregated public key +// - `signature`: 64 bytes, aggregated signature +pub const COMMITMENT_CELL_WITNESS_LEN: usize = 16 + 1 + 32 + 64; + // Some part of the code liberally gets previous commitment number, which is // the current commitment number minus 1. We deliberately set initial commitment number to 1, // so that we can get previous commitment point/number without checking if the channel @@ -1123,12 +1130,8 @@ where "Building and signing commitment tx for state {:?}", &state.state ); - let PartiallySignedCommitmentTransaction { - version, - commitment_tx, - funding_tx_partial_signature, - commitment_tx_partial_signature, - } = state.build_and_sign_commitment_tx()?; + let (funding_tx_partial_signature, commitment_tx_partial_signature) = + state.build_and_sign_commitment_tx()?; debug!( "Sending next local nonce {:?} (previous nonce {:?})", @@ -1153,17 +1156,6 @@ where )), )) .expect(ASSUME_NETWORK_ACTOR_ALIVE); - self.network - .send_message(NetworkActorMessage::new_notification( - NetworkServiceEvent::LocalCommitmentSigned( - state.get_remote_peer_id(), - state.get_id(), - version, - commitment_tx, - ), - )) - .expect("myself alive"); - state.save_remote_nonce_for_raa(); match flags { @@ -2119,7 +2111,7 @@ impl CommitmentNumbers { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Hash)] pub enum TLCId { Offered(u64), Received(u64), @@ -2726,6 +2718,35 @@ impl ChannelConstraints { } } +#[serde_as] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct RevocationData { + pub commitment_number: u64, + pub x_only_aggregated_pubkey: [u8; 32], + #[serde_as(as = "CompactSignatureAsBytes")] + pub aggregated_signature: CompactSignature, + #[serde_as(as = "EntityHex")] + pub output: CellOutput, + #[serde_as(as = "EntityHex")] + pub output_data: Bytes, +} + +#[serde_as] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct SettlementData { + pub x_only_aggregated_pubkey: [u8; 32], + #[serde_as(as = "CompactSignatureAsBytes")] + pub aggregated_signature: CompactSignature, + #[serde_as(as = "EntityHex")] + pub to_local_output: CellOutput, + #[serde_as(as = "EntityHex")] + pub to_local_output_data: Bytes, + #[serde_as(as = "EntityHex")] + pub to_remote_output: CellOutput, + #[serde_as(as = "EntityHex")] + pub to_remote_output_data: Bytes, +} + #[serde_as] #[derive(Clone, Serialize, Deserialize)] pub struct ChannelActorState { @@ -2822,7 +2843,8 @@ pub struct ChannelActorState { #[serde_as(as = "Vec<(U64Hex, PubNonceAsBytes)>")] pub remote_nonces: Vec<(u64, PubNonce)>, - // The latest commitment transaction we're holding + // The latest commitment transaction we're holding, + // it can be broadcasted to blockchain by us to force close the channel. #[serde_as(as = "Option")] pub latest_commitment_transaction: Option, @@ -3570,7 +3592,6 @@ impl ChannelActorState { remote_shutdown_info: None, local_reserved_ckb_amount, remote_reserved_ckb_amount, - latest_commitment_transaction: None, local_constraints: ChannelConstraints::new( local_max_tlc_value_in_flight, local_max_tlc_number_in_flight, @@ -3579,6 +3600,7 @@ impl ChannelActorState { remote_max_tlc_value_in_flight, remote_max_tlc_number_in_flight, ), + latest_commitment_transaction: None, reestablishing: false, created_at: SystemTime::now(), }; @@ -4010,64 +4032,112 @@ impl ChannelActorState { // Send RevokeAndAck message to the counterparty, and update the // channel state accordingly. fn send_revoke_and_ack_message(&mut self, network: &ActorRef) { - let commitment_tx_fee = - calculate_commitment_tx_fee(self.commitment_fee_rate, &self.funding_udt_type_script); - let lock_script = self.get_remote_shutdown_script(); - let (output, output_data) = if let Some(udt_type_script) = &self.funding_udt_type_script { - let capacity = self.get_total_reserved_ckb_amount() - commitment_tx_fee; - let output = CellOutput::new_builder() - .lock(lock_script) - .type_(Some(udt_type_script.clone()).pack()) - .capacity(capacity.pack()) - .build(); - - let output_data = self.get_total_udt_amount().to_le_bytes().pack(); - (output, output_data) - } else { - let capacity = self.get_total_ckb_amount() - commitment_tx_fee; - let output = CellOutput::new_builder() - .lock(lock_script) - .capacity(capacity.pack()) - .build(); - let output_data = Bytes::default(); - (output, output_data) + let key_agg_ctx = { + let local_pubkey = self.get_local_channel_public_keys().funding_pubkey; + let remote_pubkey = self.get_remote_channel_public_keys().funding_pubkey; + KeyAggContext::new([remote_pubkey, local_pubkey]).expect("Valid pubkeys") + }; + let x_only_aggregated_pubkey = key_agg_ctx.aggregated_pubkey::().serialize_xonly(); + let sign_ctx = { + let local_nonce = self.get_local_nonce(); + let remote_nonce = self.get_remote_nonce(); + let nonces = [local_nonce, remote_nonce]; + let agg_nonce = AggNonce::sum(nonces); + Musig2SignContext { + key_agg_ctx, + agg_nonce, + seckey: self.signer.funding_key.clone(), + secnonce: self.get_local_musig2_secnonce(), + } }; - let local_pubkey = self.get_local_channel_public_keys().funding_pubkey; - let remote_pubkey = self.get_remote_channel_public_keys().funding_pubkey; - let key_agg_ctx = KeyAggContext::new([remote_pubkey, local_pubkey]).expect("Valid pubkeys"); + let revocation_partial_signature = { + let commitment_tx_fee = calculate_commitment_tx_fee( + self.commitment_fee_rate, + &self.funding_udt_type_script, + ); + let lock_script = self.get_remote_shutdown_script(); + let (output, output_data) = if let Some(udt_type_script) = &self.funding_udt_type_script + { + let capacity = self.get_total_reserved_ckb_amount() - commitment_tx_fee; + let output = CellOutput::new_builder() + .lock(lock_script) + .type_(Some(udt_type_script.clone()).pack()) + .capacity(capacity.pack()) + .build(); + + let output_data = self.get_total_udt_amount().to_le_bytes().pack(); + (output, output_data) + } else { + let capacity = self.get_total_ckb_amount() - commitment_tx_fee; + let output = CellOutput::new_builder() + .lock(lock_script) + .capacity(capacity.pack()) + .build(); + let output_data = Bytes::default(); + (output, output_data) + }; - let x_only_aggregated_pubkey = key_agg_ctx.aggregated_pubkey::().serialize_xonly(); - let delay_epoch = self.commitment_delay_epoch; - let commitment_number = self.get_remote_commitment_number(); - let commitment_lock_script_args = [ - &blake2b_256(x_only_aggregated_pubkey)[0..20], - (Since::new(SinceType::EpochNumberWithFraction, delay_epoch, true).value()) + let commitment_number = self.get_remote_commitment_number() - 1; + let commitment_lock_script_args = [ + &blake2b_256(x_only_aggregated_pubkey)[0..20], + (Since::new( + SinceType::EpochNumberWithFraction, + self.commitment_delay_epoch, + true, + ) + .value()) .to_le_bytes() .as_slice(), - commitment_number.to_be_bytes().as_slice(), - ] - .concat(); + commitment_number.to_be_bytes().as_slice(), + ] + .concat(); + + let message = blake2b_256( + [ + output.as_slice(), + output_data.as_slice(), + commitment_lock_script_args.as_slice(), + ] + .concat(), + ); + sign_ctx + .clone() + .sign(message.as_slice()) + .expect("valid signature") + }; - let message = blake2b_256( - [ - output.as_slice(), - output_data.as_slice(), - commitment_lock_script_args.as_slice(), + let commitment_tx_partial_signature = { + let ( + [to_local_output, to_remote_output], + [to_local_output_data, to_remote_output_data], + ) = self.build_settlement_transaction_outputs(false); + let commitment_lock_script_args = [ + &blake2b_256(x_only_aggregated_pubkey)[0..20], + (Since::new( + SinceType::EpochNumberWithFraction, + self.commitment_delay_epoch, + true, + ) + .value()) + .to_le_bytes() + .as_slice(), + self.get_remote_commitment_number().to_be_bytes().as_slice(), ] - .concat(), - ); - let local_nonce = self.get_local_nonce(); - let remote_nonce = self.get_remote_nonce(); - let nonces = [local_nonce, remote_nonce]; - let agg_nonce = AggNonce::sum(nonces); - let sign_ctx = Musig2SignContext { - key_agg_ctx, - agg_nonce, - seckey: self.signer.funding_key.clone(), - secnonce: self.get_local_musig2_secnonce(), + .concat(); + let message = blake2b_256( + [ + to_local_output.as_slice(), + to_local_output_data.as_slice(), + to_remote_output.as_slice(), + to_remote_output_data.as_slice(), + commitment_lock_script_args.as_slice(), + ] + .concat(), + ); + + sign_ctx.sign(message.as_slice()).expect("valid signature") }; - let signature = sign_ctx.sign(message.as_slice()).expect("valid signature"); // Note that we must update channel state here to update commitment number, // so that next step will obtain the correct commitment point. @@ -4080,7 +4150,8 @@ impl ChannelActorState { self.get_remote_peer_id(), FiberMessage::revoke_and_ack(RevokeAndAck { channel_id: self.get_id(), - partial_signature: signature, + revocation_partial_signature, + commitment_tx_partial_signature, next_per_commitment_point: point, }), )), @@ -4503,10 +4574,7 @@ impl ChannelActorState { AggNonce::sum(nonces) } - pub fn get_active_received_tlcs( - &self, - local_commitment: bool, - ) -> impl Iterator { + fn get_active_received_tlcs(&self, local_commitment: bool) -> impl Iterator { self.tlc_state .get_tlcs_with(local_commitment) .into_iter() @@ -4516,10 +4584,7 @@ impl ChannelActorState { }) } - pub fn get_active_offered_tlcs( - &self, - local_commitment: bool, - ) -> impl Iterator { + fn get_active_offered_tlcs(&self, local_commitment: bool) -> impl Iterator { self.tlc_state .get_tlcs_with(local_commitment) .into_iter() @@ -4529,6 +4594,50 @@ impl ChannelActorState { }) } + // Get the total amount of pending tlcs that are fulfilled + fn get_pending_fulfilled_tlcs_amount(&self, for_remote: bool, offered: bool) -> u128 { + let (local_pending_tlcs, remote_pending_tlcs) = if for_remote { + ( + &self.tlc_state.local_pending_tlcs, + &self.tlc_state.remote_pending_tlcs, + ) + } else { + ( + &self.tlc_state.remote_pending_tlcs, + &self.tlc_state.local_pending_tlcs, + ) + }; + let mut pending = local_pending_tlcs + .get_committed_tlcs() + .into_iter() + .chain(remote_pending_tlcs.get_committed_tlcs().into_iter()) + .filter_map(|tlc| { + if matches!(tlc, TlcKind::AddTlc(info) if info.removed_at.is_none() && info.is_offered() == offered) { + Some((tlc.tlc_id(), tlc.amount())) + } else { + None + } + }).collect::>(); + let mut fulfilled = 0; + + for tlc in local_pending_tlcs.get_staging_tlcs() { + match tlc { + TlcKind::AddTlc(_info) => { + pending.insert(tlc.tlc_id(), tlc.amount()); + } + TlcKind::RemoveTlc(remove_tlc) => { + if let Some(amount) = pending.remove(&remove_tlc.tlc_id) { + if matches!(remove_tlc.reason, RemoveTlcReason::RemoveTlcFulfill(_)) { + fulfilled += amount; + } + } + } + } + } + + fulfilled + } + pub fn get_all_received_tlcs(&self) -> impl Iterator { self.tlc_state.all_tlcs().filter(|tlc| tlc.is_received()) } @@ -4569,7 +4678,7 @@ impl ChannelActorState { } } - pub fn get_active_received_tlc_with_pubkeys( + fn get_active_received_tlc_with_pubkeys( &self, local: bool, ) -> Vec<(AddTlcInfo, Pubkey, Pubkey)> { @@ -4581,7 +4690,7 @@ impl ChannelActorState { .collect() } - pub fn get_active_offered_tlc_with_pubkeys( + fn get_active_offered_tlc_with_pubkeys( &self, local: bool, ) -> Vec<(AddTlcInfo, Pubkey, Pubkey)> { @@ -4850,50 +4959,100 @@ impl ChannelActorState { Ok(tlc_info) } - pub fn create_witness_for_funding_cell( - &self, - signature: CompactSignature, - ) -> [u8; FUNDING_CELL_WITNESS_LEN] { - create_witness_for_funding_cell(self.get_funding_lock_script_xonly(), signature) - } - - pub fn aggregate_partial_signatures_to_consume_funding_cell( + fn aggregate_partial_signatures_to_consume_funding_cell( &self, partial_signatures: [PartialSignature; 2], tx: &TransactionView, ) -> Result { - let funding_out_point = self.must_get_funding_transaction_outpoint(); - debug_assert_eq!( - tx.input_pts_iter().next().as_ref(), - Some(&funding_out_point), - "The first input of the tx must be the funding cell outpoint" - ); - let verify_ctx = Musig2VerifyContext::from(self); - let signature = aggregate_partial_signatures_for_msg( - tx.hash().as_slice(), - verify_ctx, - partial_signatures, - )?; + let signature = verify_ctx + .aggregate_partial_signatures_for_msg(partial_signatures, tx.hash().as_slice())?; - let witness = self.create_witness_for_funding_cell(signature); + let witness = + create_witness_for_funding_cell(self.get_funding_lock_script_xonly(), signature); Ok(tx .as_advanced_builder() .set_witnesses(vec![witness.pack()]) .build()) } - pub fn sign_tx_to_consume_funding_cell( + fn complete_partially_signed_tx( &self, psct: &PartiallySignedCommitmentTransaction, - ) -> Result { - let sign_ctx = Musig2SignContext::from(self); - let signature2 = sign_ctx.sign(psct.commitment_tx.hash().as_slice())?; + ) -> Result<(TransactionView, SettlementData), ProcessingChannelError> { + let completed_commitment_tx = { + let sign_ctx = Musig2SignContext::from(self); + let our_funding_tx_partial_signature = + sign_ctx.sign(psct.commitment_tx.hash().as_slice())?; + self.aggregate_partial_signatures_to_consume_funding_cell( + [ + psct.funding_tx_partial_signature, + our_funding_tx_partial_signature, + ], + &psct.commitment_tx, + )? + }; - self.aggregate_partial_signatures_to_consume_funding_cell( - [psct.funding_tx_partial_signature, signature2], - &psct.commitment_tx, - ) + let settlement_data = { + let settlement_tx = &psct.settlement_tx; + let commitment_tx = &psct.commitment_tx; + let to_local_output = settlement_tx + .outputs() + .get(0) + .expect("get output 0 of settlement tx"); + let to_local_output_data = settlement_tx + .outputs_data() + .get(0) + .expect("get output 0 data of settlement tx"); + let to_remote_output = settlement_tx + .outputs() + .get(1) + .expect("get output 1 of settlement tx"); + let to_remote_output_data = settlement_tx + .outputs_data() + .get(1) + .expect("get output 1 data of settlement tx"); + let args = commitment_tx + .outputs() + .get(0) + .expect("get output 0 of commitment tx") + .lock() + .args() + .raw_data(); + let message = blake2b_256( + [ + to_local_output.as_slice(), + to_local_output_data.as_slice(), + to_remote_output.as_slice(), + to_remote_output_data.as_slice(), + &args[0..36], + ] + .concat(), + ); + let sign_ctx = Musig2SignContext::from((self, false)); + let our_commitment_tx_partial_signature = sign_ctx.sign(message.as_slice())?; + + let verify_ctx = Musig2VerifyContext::from((self, false)); + let aggregated_signature = verify_ctx.aggregate_partial_signatures_for_msg( + [ + our_commitment_tx_partial_signature, + psct.commitment_tx_partial_signature, + ], + message.as_slice(), + )?; + let x_only_aggregated_pubkey = self.get_commitment_lock_script_xonly(false); + + SettlementData { + x_only_aggregated_pubkey, + aggregated_signature, + to_local_output, + to_local_output_data, + to_remote_output, + to_remote_output_data, + } + }; + + Ok((completed_commitment_tx, settlement_data)) } pub fn maybe_transition_to_shutdown( @@ -5129,18 +5288,6 @@ impl ChannelActorState { self.check_tx_complete_preconditions()?; let flags = flags | CollaboratingFundingTxFlags::THEIR_TX_COMPLETE_SENT; self.update_state(ChannelState::CollaboratingFundingTx(flags)); - if flags.contains(CollaboratingFundingTxFlags::COLLABRATION_COMPLETED) { - // Notify outside observers. - network - .send_message(NetworkActorMessage::new_notification( - NetworkServiceEvent::CommitmentSignaturePending( - self.get_remote_peer_id(), - self.get_id(), - self.get_current_commitment_number(false), - ), - )) - .expect(ASSUME_NETWORK_ACTOR_ALIVE); - } } } Ok(()) @@ -5208,18 +5355,10 @@ impl ChannelActorState { } }; - let tx = self.verify_and_complete_tx( + let (commitment_tx, settlement_data) = self.verify_and_complete_tx( commitment_signed.funding_tx_partial_signature, commitment_signed.commitment_tx_partial_signature, )?; - // This is the commitment transaction that both parties signed, - // can be broadcasted to the network if necessary - let num = self.get_current_commitment_number(false); - - info!( - "Successfully handled commitment signed message: {:?}, tx: {:?}", - &commitment_signed, &tx - ); // Notify outside observers. network @@ -5227,8 +5366,8 @@ impl ChannelActorState { NetworkServiceEvent::RemoteCommitmentSigned( self.get_remote_peer_id(), self.get_id(), - num, - tx.clone(), + commitment_tx.clone(), + settlement_data, ), )) .expect(ASSUME_NETWORK_ACTOR_ALIVE); @@ -5239,7 +5378,7 @@ impl ChannelActorState { &commitment_signed.next_local_nonce ); self.save_remote_nonce(commitment_signed.next_local_nonce); - self.latest_commitment_transaction = Some(tx.data()); + self.latest_commitment_transaction = Some(commitment_tx.data()); match flags { CommitmentSignedFlags::SigningCommitment(flags) => { let flags = flags | SigningCommitmentFlags::THEIR_COMMITMENT_SIGNED_SENT; @@ -5264,23 +5403,6 @@ impl ChannelActorState { } } } - - if let ChannelState::SigningCommitment(flags) = self.state { - if !flags.contains(SigningCommitmentFlags::OUR_COMMITMENT_SIGNED_SENT) { - // TODO: maybe we should send our commitment_signed message here. - debug!("CommitmentSigned message received, but we haven't sent our commitment_signed message yet"); - // Notify outside observers. - network - .send_message(NetworkActorMessage::new_notification( - NetworkServiceEvent::CommitmentSignaturePending( - self.get_remote_peer_id(), - self.get_id(), - self.get_current_commitment_number(false), - ), - )) - .expect(ASSUME_NETWORK_ACTOR_ALIVE); - } - } Ok(()) } @@ -5479,88 +5601,147 @@ impl ChannelActorState { network: &ActorRef, revoke_and_ack: RevokeAndAck, ) -> ProcessingChannelResult { - let commitment_tx_fee = - calculate_commitment_tx_fee(self.commitment_fee_rate, &self.funding_udt_type_script); - let lock_script = self.get_local_shutdown_script(); - let (output, output_data) = if let Some(udt_type_script) = &self.funding_udt_type_script { - let capacity = self.get_total_reserved_ckb_amount() - commitment_tx_fee; - let output = CellOutput::new_builder() - .lock(lock_script) - .type_(Some(udt_type_script.clone()).pack()) - .capacity(capacity.pack()) - .build(); + let RevokeAndAck { + channel_id: _, + revocation_partial_signature, + commitment_tx_partial_signature, + next_per_commitment_point, + } = revoke_and_ack; - let output_data = self.get_total_udt_amount().to_le_bytes().pack(); - (output, output_data) - } else { - let capacity = self.get_total_ckb_amount() - commitment_tx_fee; - let output = CellOutput::new_builder() - .lock(lock_script) - .capacity(capacity.pack()) - .build(); - let output_data = Bytes::default(); - (output, output_data) + let key_agg_ctx = { + let local_pubkey = self.get_local_channel_public_keys().funding_pubkey; + let remote_pubkey = self.get_remote_channel_public_keys().funding_pubkey; + KeyAggContext::new([local_pubkey, remote_pubkey]).expect("Valid pubkeys") }; - - let local_pubkey = self.get_local_channel_public_keys().funding_pubkey; - let remote_pubkey = self.get_remote_channel_public_keys().funding_pubkey; - let key_agg_ctx = KeyAggContext::new([local_pubkey, remote_pubkey]).expect("Valid pubkeys"); - let x_only_aggregated_pubkey = key_agg_ctx.aggregated_pubkey::().serialize_xonly(); - let delay_epoch = self.commitment_delay_epoch; - let commitment_number = self.get_local_commitment_number(); - - let commitment_lock_script_args = [ - &blake2b_256(x_only_aggregated_pubkey)[0..20], - (Since::new(SinceType::EpochNumberWithFraction, delay_epoch, true).value()) - .to_le_bytes() - .as_slice(), - commitment_number.to_be_bytes().as_slice(), - ] - .concat(); - - let message = blake2b_256( - [ - output.as_slice(), - output_data.as_slice(), - commitment_lock_script_args.as_slice(), - ] - .concat(), - ); + let (verify_ctx, sign_ctx) = { + let local_nonce = self.get_local_nonce(); + let remote_nonce = self.take_remote_nonce_for_raa(); + let nonces = [remote_nonce.clone(), local_nonce]; + let agg_nonce = AggNonce::sum(nonces); - let local_nonce = self.get_local_nonce(); - let remote_nonce = self.take_remote_nonce_for_raa(); - let nonces = [remote_nonce.clone(), local_nonce]; - let agg_nonce = AggNonce::sum(nonces); - - let verify_ctx = Musig2VerifyContext { - key_agg_ctx: key_agg_ctx.clone(), - agg_nonce: agg_nonce.clone(), - pubkey: *self.get_remote_funding_pubkey(), - pubnonce: remote_nonce, + ( + Musig2VerifyContext { + key_agg_ctx: key_agg_ctx.clone(), + agg_nonce: agg_nonce.clone(), + pubkey: *self.get_remote_funding_pubkey(), + pubnonce: remote_nonce, + }, + Musig2SignContext { + key_agg_ctx, + agg_nonce, + seckey: self.signer.funding_key.clone(), + secnonce: self.get_local_musig2_secnonce(), + }, + ) }; - let RevokeAndAck { - channel_id: _, - partial_signature, - next_per_commitment_point, - } = revoke_and_ack; + let revocation_data = { + let commitment_tx_fee = calculate_commitment_tx_fee( + self.commitment_fee_rate, + &self.funding_udt_type_script, + ); + let lock_script = self.get_local_shutdown_script(); + let (output, output_data) = if let Some(udt_type_script) = &self.funding_udt_type_script + { + let capacity = self.get_total_reserved_ckb_amount() - commitment_tx_fee; + let output = CellOutput::new_builder() + .lock(lock_script) + .type_(Some(udt_type_script.clone()).pack()) + .capacity(capacity.pack()) + .build(); + + let output_data = self.get_total_udt_amount().to_le_bytes().pack(); + (output, output_data) + } else { + let capacity = self.get_total_ckb_amount() - commitment_tx_fee; + let output = CellOutput::new_builder() + .lock(lock_script) + .capacity(capacity.pack()) + .build(); + let output_data = Bytes::default(); + (output, output_data) + }; - verify_ctx.verify(partial_signature, message.as_slice())?; + let delay_epoch = self.commitment_delay_epoch; + let commitment_number = self.get_local_commitment_number() - 1; - let sign_ctx: Musig2SignContext = Musig2SignContext { - key_agg_ctx, - agg_nonce, - seckey: self.signer.funding_key.clone(), - secnonce: self.get_local_musig2_secnonce(), + let commitment_lock_script_args = [ + &blake2b_256(x_only_aggregated_pubkey)[0..20], + (Since::new(SinceType::EpochNumberWithFraction, delay_epoch, true).value()) + .to_le_bytes() + .as_slice(), + commitment_number.to_be_bytes().as_slice(), + ] + .concat(); + + let message = blake2b_256( + [ + output.as_slice(), + output_data.as_slice(), + commitment_lock_script_args.as_slice(), + ] + .concat(), + ); + verify_ctx.verify(revocation_partial_signature, message.as_slice())?; + let our_signature = sign_ctx.clone().sign(message.as_slice())?; + let aggregated_signature = verify_ctx.aggregate_partial_signatures_for_msg( + [revocation_partial_signature, our_signature], + message.as_slice(), + )?; + RevocationData { + commitment_number, + x_only_aggregated_pubkey, + aggregated_signature, + output, + output_data, + } }; - let signature2 = sign_ctx.sign(message.as_slice())?; - let aggregate_signature = aggregate_partial_signatures_for_msg( - message.as_slice(), - verify_ctx, - [partial_signature, signature2], - )?; + let settlement_data = { + let ( + [to_local_output, to_remote_output], + [to_local_output_data, to_remote_output_data], + ) = self.build_settlement_transaction_outputs(true); + let commitment_lock_script_args = [ + &blake2b_256(x_only_aggregated_pubkey)[0..20], + (Since::new( + SinceType::EpochNumberWithFraction, + self.commitment_delay_epoch, + true, + ) + .value()) + .to_le_bytes() + .as_slice(), + self.get_local_commitment_number().to_be_bytes().as_slice(), + ] + .concat(); + let message = blake2b_256( + [ + to_local_output.as_slice(), + to_local_output_data.as_slice(), + to_remote_output.as_slice(), + to_remote_output_data.as_slice(), + commitment_lock_script_args.as_slice(), + ] + .concat(), + ); + verify_ctx.verify(commitment_tx_partial_signature, message.as_slice())?; + let our_signature = sign_ctx.sign(message.as_slice())?; + let aggregated_signature = verify_ctx.aggregate_partial_signatures_for_msg( + [commitment_tx_partial_signature, our_signature], + message.as_slice(), + )?; + + SettlementData { + x_only_aggregated_pubkey, + aggregated_signature, + to_local_output, + to_local_output_data, + to_remote_output, + to_remote_output_data, + } + }; self.increment_local_commitment_number(); self.append_remote_commitment_point(next_per_commitment_point); @@ -5579,11 +5760,8 @@ impl ChannelActorState { NetworkServiceEvent::RevokeAndAckReceived( self.get_remote_peer_id(), self.get_id(), - commitment_number, - x_only_aggregated_pubkey, - aggregate_signature, - output, - output_data, + revocation_data, + settlement_data, ), )) .expect(ASSUME_NETWORK_ACTOR_ALIVE); @@ -5915,27 +6093,28 @@ impl ChannelActorState { "shutdown_tx local_capacity: {} - {} = {}", self.local_reserved_ckb_amount, local_shutdown_fee, local_capacity ); - let local_output = CellOutput::new_builder() + let to_local_output = CellOutput::new_builder() .lock(local_shutdown_script) .type_(Some(type_script.clone()).pack()) .capacity(local_capacity.pack()) .build(); - let local_output_data = self.to_local_amount.to_le_bytes().pack(); + let to_local_output_data = self.to_local_amount.to_le_bytes().pack(); let remote_capacity: u64 = self.remote_reserved_ckb_amount - remote_shutdown_fee; debug!( "shutdown_tx remote_capacity: {} - {} = {}", self.remote_reserved_ckb_amount, remote_shutdown_fee, remote_capacity ); - let remote_output = CellOutput::new_builder() + let to_remote_output = CellOutput::new_builder() .lock(remote_shutdown_script) .type_(Some(type_script.clone()).pack()) .capacity(remote_capacity.pack()) .build(); - let remote_output_data = self.to_remote_amount.to_le_bytes().pack(); + let to_remote_output_data = self.to_remote_amount.to_le_bytes().pack(); - let outputs = self.order_things_for_musig2(local_output, remote_output); - let outputs_data = self.order_things_for_musig2(local_output_data, remote_output_data); + let outputs = self.order_things_for_musig2(to_local_output, to_remote_output); + let outputs_data = + self.order_things_for_musig2(to_local_output_data, to_remote_output_data); let tx = tx_builder .set_outputs(outputs.to_vec()) .set_outputs_data(outputs_data.to_vec()) @@ -5955,15 +6134,15 @@ impl ChannelActorState { "Building shutdown transaction with values: local {}, remote {}", local_value, remote_value ); - let local_output = CellOutput::new_builder() + let to_local_output = CellOutput::new_builder() .capacity(local_value.pack()) .lock(local_shutdown_script) .build(); - let remote_output = CellOutput::new_builder() + let to_remote_output = CellOutput::new_builder() .capacity(remote_value.pack()) .lock(remote_shutdown_script) .build(); - let outputs = self.order_things_for_musig2(local_output, remote_output); + let outputs = self.order_things_for_musig2(to_local_output, to_remote_output); let tx = tx_builder .set_outputs(outputs.to_vec()) .set_outputs_data(vec![Default::default(), Default::default()]) @@ -5972,8 +6151,8 @@ impl ChannelActorState { } } - // The parameter `local` here specifies whether we are building the commitment transaction - // for the local party or the remote party. If `local` is true, then we are building a + // The parameter `for_remote` here specifies whether we are building the commitment transaction + // for the local party or the remote party. If `for_remote` is false, then we are building a // commitment transaction which can be broadcasted by ourself (with valid partial // signature from the other party), else we are building a commitment transaction // for the remote party (we build this commitment transaction @@ -5984,13 +6163,13 @@ impl ChannelActorState { // commitment transaction. fn build_commitment_and_settlement_tx( &self, - local: bool, + for_remote: bool, ) -> (TransactionView, TransactionView) { let commitment_tx = { let funding_out_point = self.must_get_funding_transaction_outpoint(); let cell_deps = get_cell_deps(vec![Contract::FundingLock], &self.funding_udt_type_script); - let (output, output_data) = self.build_commitment_transaction_output(local); + let (output, output_data) = self.build_commitment_transaction_output(for_remote); TransactionBuilder::default() .cell_deps(cell_deps) @@ -6010,7 +6189,7 @@ impl ChannelActorState { vec![Contract::CommitmentLock], &self.funding_udt_type_script, ); - let (outputs, outputs_data) = self.build_settlement_transaction_outputs(local); + let (outputs, outputs_data) = self.build_settlement_transaction_outputs(for_remote); TransactionBuilder::default() .cell_deps(cell_deps) @@ -6027,22 +6206,11 @@ impl ChannelActorState { (commitment_tx, settlement_tx) } - fn build_commitment_transaction_output(&self, local: bool) -> (CellOutput, Bytes) { - let local_pubkey = self.get_local_channel_public_keys().funding_pubkey; - let remote_pubkey = self.get_remote_channel_public_keys().funding_pubkey; - let pubkeys = if local { - [local_pubkey, remote_pubkey] - } else { - [remote_pubkey, local_pubkey] - }; - let x_only_aggregated_pubkey = KeyAggContext::new(pubkeys) - .expect("Valid pubkeys") - .aggregated_pubkey::() - .serialize_xonly(); - + fn build_commitment_transaction_output(&self, for_remote: bool) -> (CellOutput, Bytes) { + let x_only_aggregated_pubkey = self.get_commitment_lock_script_xonly(for_remote); let delay_epoch = self.commitment_delay_epoch; - let version = self.get_current_commitment_number(local); - let htlcs = self.get_active_htlcs(local); + let version = self.get_current_commitment_number(for_remote); + let htlcs = self.get_active_htlcs(for_remote); let mut commitment_lock_script_args = [ &blake2b_256(x_only_aggregated_pubkey)[0..20], @@ -6084,39 +6252,51 @@ impl ChannelActorState { } } - fn build_settlement_transaction_outputs(&self, local: bool) -> ([CellOutput; 2], [Bytes; 2]) { - let received_tlc_value = self - .get_active_received_tlcs(local) - .map(|tlc| tlc.amount) - .sum::(); - let offered_tlc_value = self - .get_active_offered_tlcs(local) - .map(|tlc| tlc.amount) - .sum::(); + fn get_commitment_lock_script_xonly(&self, for_remote: bool) -> [u8; 32] { + let local_pubkey = self.get_local_channel_public_keys().funding_pubkey; + let remote_pubkey = self.get_remote_channel_public_keys().funding_pubkey; + let pubkeys = if for_remote { + [local_pubkey, remote_pubkey] + } else { + [remote_pubkey, local_pubkey] + }; + KeyAggContext::new(pubkeys) + .expect("Valid pubkeys") + .aggregated_pubkey::() + .serialize_xonly() + } - let to_local_value = - self.to_local_amount + self.local_reserved_ckb_amount as u128 - offered_tlc_value; - let to_remote_value = - self.to_remote_amount + self.remote_reserved_ckb_amount as u128 - received_tlc_value; + fn build_settlement_transaction_outputs( + &self, + for_remote: bool, + ) -> ([CellOutput; 2], [Bytes; 2]) { + let offered_fulfilled = self.get_pending_fulfilled_tlcs_amount(for_remote, true); + let received_fulfilled = self.get_pending_fulfilled_tlcs_amount(for_remote, false); + + let to_local_value = self.to_local_amount - offered_fulfilled + received_fulfilled; + let to_remote_value = self.to_remote_amount - received_fulfilled + offered_fulfilled; + let commitment_tx_fee = + calculate_commitment_tx_fee(self.commitment_fee_rate, &self.funding_udt_type_script); let to_local_output_script = self.get_local_shutdown_script(); let to_remote_output_script = self.get_remote_shutdown_script(); + // to simplify the fee calculation, we assume that the fee is double paid by both parties if let Some(udt_type_script) = &self.funding_udt_type_script { let to_local_output = CellOutput::new_builder() .lock(to_local_output_script) .type_(Some(udt_type_script.clone()).pack()) - .capacity(self.local_reserved_ckb_amount.pack()) + .capacity((self.local_reserved_ckb_amount - commitment_tx_fee).pack()) .build(); let to_local_output_data = to_local_value.to_le_bytes().pack(); let to_remote_output = CellOutput::new_builder() .lock(to_remote_output_script) .type_(Some(udt_type_script.clone()).pack()) - .capacity(self.remote_reserved_ckb_amount.pack()) + .capacity((self.remote_reserved_ckb_amount - commitment_tx_fee).pack()) .build(); let to_remote_output_data = to_remote_value.to_le_bytes().pack(); - if local { + if for_remote { ( [to_local_output, to_remote_output], [to_local_output_data, to_remote_output_data], @@ -6130,16 +6310,22 @@ impl ChannelActorState { } else { let to_local_output = CellOutput::new_builder() .lock(to_local_output_script) - .capacity((to_local_value as u64).pack()) + .capacity( + (to_local_value as u64 + self.local_reserved_ckb_amount - commitment_tx_fee) + .pack(), + ) .build(); let to_local_output_data = Bytes::default(); let to_remote_output = CellOutput::new_builder() .lock(to_remote_output_script) - .capacity((to_remote_value as u64).pack()) + .capacity( + (to_remote_value as u64 + self.remote_reserved_ckb_amount - commitment_tx_fee) + .pack(), + ) .build(); let to_remote_output_data = Bytes::default(); - if local { + if for_remote { ( [to_local_output, to_remote_output], [to_local_output_data, to_remote_output_data], @@ -6205,6 +6391,7 @@ impl ChannelActorState { Ok(PartiallySignedCommitmentTransaction { version: self.get_current_commitment_number(false), commitment_tx, + settlement_tx, funding_tx_partial_signature, commitment_tx_partial_signature, }) @@ -6212,7 +6399,7 @@ impl ChannelActorState { fn build_and_sign_commitment_tx( &self, - ) -> Result { + ) -> Result<(PartialSignature, PartialSignature), ProcessingChannelError> { let (commitment_tx, settlement_tx) = self.build_commitment_and_settlement_tx(true); let sign_ctx = Musig2SignContext::from(self); @@ -6255,12 +6442,10 @@ impl ChannelActorState { let commitment_tx_partial_signature = sign_ctx.sign(message.as_slice())?; - Ok(PartiallySignedCommitmentTransaction { - version: self.get_current_commitment_number(true), - commitment_tx, + Ok(( funding_tx_partial_signature, commitment_tx_partial_signature, - }) + )) } /// Verify the partial signature from the peer and create a complete transaction @@ -6269,12 +6454,12 @@ impl ChannelActorState { &self, funding_tx_partial_signature: PartialSignature, commitment_tx_partial_signature: PartialSignature, - ) -> Result { + ) -> Result<(TransactionView, SettlementData), ProcessingChannelError> { let tx = self.build_and_verify_commitment_tx( funding_tx_partial_signature, commitment_tx_partial_signature, )?; - self.sign_tx_to_consume_funding_cell(&tx) + self.complete_partially_signed_tx(&tx) } } @@ -6311,6 +6496,8 @@ pub struct PartiallySignedCommitmentTransaction { pub version: u64, // The commitment transaction. pub commitment_tx: TransactionView, + // The settlement transaction. + pub settlement_tx: TransactionView, // The partial signature to unlock the funding transaction. pub funding_tx_partial_signature: PartialSignature, // The partial signature to unlock the commitment transaction. @@ -6329,12 +6516,23 @@ pub fn create_witness_for_funding_cell( witness.extend_from_slice(&empty_witness_args); witness.extend_from_slice(lock_key_xonly.as_slice()); witness.extend_from_slice(signature.serialize().as_slice()); + witness + .try_into() + .expect("Witness length should be correct") +} - debug!( - "Building witnesses for transaction to consume funding cell: {:?}", - hex::encode(&witness) - ); - +pub fn create_witness_for_commitment_cell( + lock_key_xonly: [u8; 32], + signature: CompactSignature, +) -> [u8; COMMITMENT_CELL_WITNESS_LEN] { + let mut witness = Vec::with_capacity(COMMITMENT_CELL_WITNESS_LEN); + // for xudt compatibility issue, + // refer to: https://github.com/nervosnetwork/fiber-scripts/pull/5 + let empty_witness_args = [16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0]; + witness.extend_from_slice(&empty_witness_args); + witness.extend_from_slice(&[0xFE]); + witness.extend_from_slice(lock_key_xonly.as_slice()); + witness.extend_from_slice(signature.serialize().as_slice()); witness .try_into() .expect("Witness length should be correct") @@ -6348,24 +6546,28 @@ pub struct Musig2VerifyContext { } impl Musig2VerifyContext { - pub fn verify(&self, signature: PartialSignature, message: &[u8]) -> ProcessingChannelResult { - let result = verify_partial( + pub fn verify(&self, signature: PartialSignature, message: &[u8]) -> Result<(), VerifyError> { + verify_partial( &self.key_agg_ctx, signature, &self.agg_nonce, self.pubkey, &self.pubnonce, message, - ); - debug!( - "Verifying partial signature {:?} with message {:?}, nonce {:?}, agg nonce {:?}, result {:?}", - &signature, - hex::encode(message), - &self.pubnonce, + ) + } + + pub fn aggregate_partial_signatures_for_msg( + &self, + partial_signatures: [PartialSignature; 2], + message: &[u8], + ) -> Result { + aggregate_partial_signatures( + &self.key_agg_ctx, &self.agg_nonce, - result - ); - Ok(result?) + partial_signatures, + message, + ) } } @@ -6398,24 +6600,6 @@ impl Musig2SignContext { } } -pub fn aggregate_partial_signatures_for_msg( - message: &[u8], - verify_ctx: Musig2VerifyContext, - partial_signatures: [PartialSignature; 2], -) -> Result { - debug!( - "Message to aggregate signatures: {:?}", - hex::encode(message) - ); - let signature: CompactSignature = aggregate_partial_signatures( - &verify_ctx.key_agg_ctx, - &verify_ctx.agg_nonce, - partial_signatures, - message, - )?; - Ok(signature) -} - /// One counterparty's public keys which do not change over the life of a channel. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct ChannelBasePublicKeys { diff --git a/src/fiber/config.rs b/src/fiber/config.rs index 57060c98b..894373086 100644 --- a/src/fiber/config.rs +++ b/src/fiber/config.rs @@ -189,6 +189,15 @@ pub struct FiberConfig { help = "Whether to sync the network graph from the network. [default: true]" )] pub(crate) sync_network_graph: Option, + + /// The interval to check watchtower, in seconds. 0 means never check. [default: 60 (1 minute)] + #[arg( + name = "FIBER_WATCHTOWER_CHECK_INTERVAL_SECONDS", + long = "fiber-watchtower-check-interval-seconds", + env, + help = "The interval to check watchtower, in seconds. 0 means never check. [default: 60 (1 minute)]" + )] + pub watchtower_check_interval_seconds: Option, } #[derive(PartialEq, Copy, Clone, Default)] diff --git a/src/fiber/gen/fiber.rs b/src/fiber/gen/fiber.rs index a6d93d9ef..e2a5d07e9 100644 --- a/src/fiber/gen/fiber.rs +++ b/src/fiber/gen/fiber.rs @@ -4393,19 +4393,6 @@ impl ::core::fmt::Display for OpenChannel { self.commitment_delay_epoch() )?; write!(f, ", {}: {}", "funding_pubkey", self.funding_pubkey())?; - write!( - f, - ", {}: {}", - "revocation_basepoint", - self.revocation_basepoint() - )?; - write!(f, ", {}: {}", "payment_basepoint", self.payment_basepoint())?; - write!( - f, - ", {}: {}", - "delayed_payment_basepoint", - self.delayed_payment_basepoint() - )?; write!(f, ", {}: {}", "tlc_basepoint", self.tlc_basepoint())?; write!( f, @@ -4441,16 +4428,13 @@ impl ::core::default::Default for OpenChannel { } } impl OpenChannel { - const DEFAULT_VALUE: [u8; 575] = [ - 63, 2, 0, 0, 88, 0, 0, 0, 120, 0, 0, 0, 152, 0, 0, 0, 152, 0, 0, 0, 168, 0, 0, 0, 221, 0, - 0, 0, 229, 0, 0, 0, 237, 0, 0, 0, 245, 0, 0, 0, 5, 1, 0, 0, 13, 1, 0, 0, 21, 1, 0, 0, 54, - 1, 0, 0, 87, 1, 0, 0, 120, 1, 0, 0, 153, 1, 0, 0, 186, 1, 0, 0, 219, 1, 0, 0, 252, 1, 0, 0, - 252, 1, 0, 0, 62, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, - 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + const DEFAULT_VALUE: [u8; 464] = [ + 208, 1, 0, 0, 76, 0, 0, 0, 108, 0, 0, 0, 140, 0, 0, 0, 140, 0, 0, 0, 156, 0, 0, 0, 209, 0, + 0, 0, 217, 0, 0, 0, 225, 0, 0, 0, 233, 0, 0, 0, 249, 0, 0, 0, 1, 1, 0, 0, 9, 1, 0, 0, 42, + 1, 0, 0, 75, 1, 0, 0, 108, 1, 0, 0, 141, 1, 0, 0, 141, 1, 0, 0, 207, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -4460,10 +4444,9 @@ impl OpenChannel { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; - pub const FIELD_COUNT: usize = 21; + pub const FIELD_COUNT: usize = 18; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -4552,59 +4535,41 @@ impl OpenChannel { let end = molecule::unpack_number(&slice[52..]) as usize; Pubkey::new_unchecked(self.0.slice(start..end)) } - pub fn revocation_basepoint(&self) -> Pubkey { + pub fn tlc_basepoint(&self) -> Pubkey { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[52..]) as usize; let end = molecule::unpack_number(&slice[56..]) as usize; Pubkey::new_unchecked(self.0.slice(start..end)) } - pub fn payment_basepoint(&self) -> Pubkey { + pub fn first_per_commitment_point(&self) -> Pubkey { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[56..]) as usize; let end = molecule::unpack_number(&slice[60..]) as usize; Pubkey::new_unchecked(self.0.slice(start..end)) } - pub fn delayed_payment_basepoint(&self) -> Pubkey { + pub fn second_per_commitment_point(&self) -> Pubkey { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[60..]) as usize; let end = molecule::unpack_number(&slice[64..]) as usize; Pubkey::new_unchecked(self.0.slice(start..end)) } - pub fn tlc_basepoint(&self) -> Pubkey { + pub fn channel_annoucement_nonce(&self) -> PubNonceOpt { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[64..]) as usize; let end = molecule::unpack_number(&slice[68..]) as usize; - Pubkey::new_unchecked(self.0.slice(start..end)) - } - pub fn first_per_commitment_point(&self) -> Pubkey { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[68..]) as usize; - let end = molecule::unpack_number(&slice[72..]) as usize; - Pubkey::new_unchecked(self.0.slice(start..end)) - } - pub fn second_per_commitment_point(&self) -> Pubkey { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[72..]) as usize; - let end = molecule::unpack_number(&slice[76..]) as usize; - Pubkey::new_unchecked(self.0.slice(start..end)) - } - pub fn channel_annoucement_nonce(&self) -> PubNonceOpt { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[76..]) as usize; - let end = molecule::unpack_number(&slice[80..]) as usize; PubNonceOpt::new_unchecked(self.0.slice(start..end)) } pub fn next_local_nonce(&self) -> PubNonce { let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[80..]) as usize; - let end = molecule::unpack_number(&slice[84..]) as usize; + let start = molecule::unpack_number(&slice[68..]) as usize; + let end = molecule::unpack_number(&slice[72..]) as usize; PubNonce::new_unchecked(self.0.slice(start..end)) } pub fn channel_flags(&self) -> Byte { let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[84..]) as usize; + let start = molecule::unpack_number(&slice[72..]) as usize; if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[88..]) as usize; + let end = molecule::unpack_number(&slice[76..]) as usize; Byte::new_unchecked(self.0.slice(start..end)) } else { Byte::new_unchecked(self.0.slice(start..)) @@ -4649,9 +4614,6 @@ impl molecule::prelude::Entity for OpenChannel { .max_tlc_number_in_flight(self.max_tlc_number_in_flight()) .commitment_delay_epoch(self.commitment_delay_epoch()) .funding_pubkey(self.funding_pubkey()) - .revocation_basepoint(self.revocation_basepoint()) - .payment_basepoint(self.payment_basepoint()) - .delayed_payment_basepoint(self.delayed_payment_basepoint()) .tlc_basepoint(self.tlc_basepoint()) .first_per_commitment_point(self.first_per_commitment_point()) .second_per_commitment_point(self.second_per_commitment_point()) @@ -4721,19 +4683,6 @@ impl<'r> ::core::fmt::Display for OpenChannelReader<'r> { self.commitment_delay_epoch() )?; write!(f, ", {}: {}", "funding_pubkey", self.funding_pubkey())?; - write!( - f, - ", {}: {}", - "revocation_basepoint", - self.revocation_basepoint() - )?; - write!(f, ", {}: {}", "payment_basepoint", self.payment_basepoint())?; - write!( - f, - ", {}: {}", - "delayed_payment_basepoint", - self.delayed_payment_basepoint() - )?; write!(f, ", {}: {}", "tlc_basepoint", self.tlc_basepoint())?; write!( f, @@ -4763,7 +4712,7 @@ impl<'r> ::core::fmt::Display for OpenChannelReader<'r> { } } impl<'r> OpenChannelReader<'r> { - pub const FIELD_COUNT: usize = 21; + pub const FIELD_COUNT: usize = 18; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -4852,59 +4801,41 @@ impl<'r> OpenChannelReader<'r> { let end = molecule::unpack_number(&slice[52..]) as usize; PubkeyReader::new_unchecked(&self.as_slice()[start..end]) } - pub fn revocation_basepoint(&self) -> PubkeyReader<'r> { + pub fn tlc_basepoint(&self) -> PubkeyReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[52..]) as usize; let end = molecule::unpack_number(&slice[56..]) as usize; PubkeyReader::new_unchecked(&self.as_slice()[start..end]) } - pub fn payment_basepoint(&self) -> PubkeyReader<'r> { + pub fn first_per_commitment_point(&self) -> PubkeyReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[56..]) as usize; let end = molecule::unpack_number(&slice[60..]) as usize; PubkeyReader::new_unchecked(&self.as_slice()[start..end]) } - pub fn delayed_payment_basepoint(&self) -> PubkeyReader<'r> { + pub fn second_per_commitment_point(&self) -> PubkeyReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[60..]) as usize; let end = molecule::unpack_number(&slice[64..]) as usize; PubkeyReader::new_unchecked(&self.as_slice()[start..end]) } - pub fn tlc_basepoint(&self) -> PubkeyReader<'r> { + pub fn channel_annoucement_nonce(&self) -> PubNonceOptReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[64..]) as usize; let end = molecule::unpack_number(&slice[68..]) as usize; - PubkeyReader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn first_per_commitment_point(&self) -> PubkeyReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[68..]) as usize; - let end = molecule::unpack_number(&slice[72..]) as usize; - PubkeyReader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn second_per_commitment_point(&self) -> PubkeyReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[72..]) as usize; - let end = molecule::unpack_number(&slice[76..]) as usize; - PubkeyReader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn channel_annoucement_nonce(&self) -> PubNonceOptReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[76..]) as usize; - let end = molecule::unpack_number(&slice[80..]) as usize; PubNonceOptReader::new_unchecked(&self.as_slice()[start..end]) } pub fn next_local_nonce(&self) -> PubNonceReader<'r> { let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[80..]) as usize; - let end = molecule::unpack_number(&slice[84..]) as usize; + let start = molecule::unpack_number(&slice[68..]) as usize; + let end = molecule::unpack_number(&slice[72..]) as usize; PubNonceReader::new_unchecked(&self.as_slice()[start..end]) } pub fn channel_flags(&self) -> ByteReader<'r> { let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[84..]) as usize; + let start = molecule::unpack_number(&slice[72..]) as usize; if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[88..]) as usize; + let end = molecule::unpack_number(&slice[76..]) as usize; ByteReader::new_unchecked(&self.as_slice()[start..end]) } else { ByteReader::new_unchecked(&self.as_slice()[start..]) @@ -4972,12 +4903,9 @@ impl<'r> molecule::prelude::Reader<'r> for OpenChannelReader<'r> { PubkeyReader::verify(&slice[offsets[12]..offsets[13]], compatible)?; PubkeyReader::verify(&slice[offsets[13]..offsets[14]], compatible)?; PubkeyReader::verify(&slice[offsets[14]..offsets[15]], compatible)?; - PubkeyReader::verify(&slice[offsets[15]..offsets[16]], compatible)?; - PubkeyReader::verify(&slice[offsets[16]..offsets[17]], compatible)?; - PubkeyReader::verify(&slice[offsets[17]..offsets[18]], compatible)?; - PubNonceOptReader::verify(&slice[offsets[18]..offsets[19]], compatible)?; - PubNonceReader::verify(&slice[offsets[19]..offsets[20]], compatible)?; - ByteReader::verify(&slice[offsets[20]..offsets[21]], compatible)?; + PubNonceOptReader::verify(&slice[offsets[15]..offsets[16]], compatible)?; + PubNonceReader::verify(&slice[offsets[16]..offsets[17]], compatible)?; + ByteReader::verify(&slice[offsets[17]..offsets[18]], compatible)?; Ok(()) } } @@ -4995,9 +4923,6 @@ pub struct OpenChannelBuilder { pub(crate) max_tlc_number_in_flight: Uint64, pub(crate) commitment_delay_epoch: Uint64, pub(crate) funding_pubkey: Pubkey, - pub(crate) revocation_basepoint: Pubkey, - pub(crate) payment_basepoint: Pubkey, - pub(crate) delayed_payment_basepoint: Pubkey, pub(crate) tlc_basepoint: Pubkey, pub(crate) first_per_commitment_point: Pubkey, pub(crate) second_per_commitment_point: Pubkey, @@ -5006,7 +4931,7 @@ pub struct OpenChannelBuilder { pub(crate) channel_flags: Byte, } impl OpenChannelBuilder { - pub const FIELD_COUNT: usize = 21; + pub const FIELD_COUNT: usize = 18; pub fn chain_hash(mut self, v: Byte32) -> Self { self.chain_hash = v; self @@ -5055,18 +4980,6 @@ impl OpenChannelBuilder { self.funding_pubkey = v; self } - pub fn revocation_basepoint(mut self, v: Pubkey) -> Self { - self.revocation_basepoint = v; - self - } - pub fn payment_basepoint(mut self, v: Pubkey) -> Self { - self.payment_basepoint = v; - self - } - pub fn delayed_payment_basepoint(mut self, v: Pubkey) -> Self { - self.delayed_payment_basepoint = v; - self - } pub fn tlc_basepoint(mut self, v: Pubkey) -> Self { self.tlc_basepoint = v; self @@ -5109,9 +5022,6 @@ impl molecule::prelude::Builder for OpenChannelBuilder { + self.max_tlc_number_in_flight.as_slice().len() + self.commitment_delay_epoch.as_slice().len() + self.funding_pubkey.as_slice().len() - + self.revocation_basepoint.as_slice().len() - + self.payment_basepoint.as_slice().len() - + self.delayed_payment_basepoint.as_slice().len() + self.tlc_basepoint.as_slice().len() + self.first_per_commitment_point.as_slice().len() + self.second_per_commitment_point.as_slice().len() @@ -5147,12 +5057,6 @@ impl molecule::prelude::Builder for OpenChannelBuilder { offsets.push(total_size); total_size += self.funding_pubkey.as_slice().len(); offsets.push(total_size); - total_size += self.revocation_basepoint.as_slice().len(); - offsets.push(total_size); - total_size += self.payment_basepoint.as_slice().len(); - offsets.push(total_size); - total_size += self.delayed_payment_basepoint.as_slice().len(); - offsets.push(total_size); total_size += self.tlc_basepoint.as_slice().len(); offsets.push(total_size); total_size += self.first_per_commitment_point.as_slice().len(); @@ -5180,9 +5084,6 @@ impl molecule::prelude::Builder for OpenChannelBuilder { writer.write_all(self.max_tlc_number_in_flight.as_slice())?; writer.write_all(self.commitment_delay_epoch.as_slice())?; writer.write_all(self.funding_pubkey.as_slice())?; - writer.write_all(self.revocation_basepoint.as_slice())?; - writer.write_all(self.payment_basepoint.as_slice())?; - writer.write_all(self.delayed_payment_basepoint.as_slice())?; writer.write_all(self.tlc_basepoint.as_slice())?; writer.write_all(self.first_per_commitment_point.as_slice())?; writer.write_all(self.second_per_commitment_point.as_slice())?; @@ -5238,26 +5139,7 @@ impl ::core::fmt::Display for AcceptChannel { "max_tlc_number_in_flight", self.max_tlc_number_in_flight() )?; - write!( - f, - ", {}: {}", - "commitment_delay_epoch", - self.commitment_delay_epoch() - )?; write!(f, ", {}: {}", "funding_pubkey", self.funding_pubkey())?; - write!( - f, - ", {}: {}", - "revocation_basepoint", - self.revocation_basepoint() - )?; - write!(f, ", {}: {}", "payment_basepoint", self.payment_basepoint())?; - write!( - f, - ", {}: {}", - "delayed_payment_basepoint", - self.delayed_payment_basepoint() - )?; write!(f, ", {}: {}", "tlc_basepoint", self.tlc_basepoint())?; write!( f, @@ -5292,16 +5174,12 @@ impl ::core::default::Default for AcceptChannel { } } impl AcceptChannel { - const DEFAULT_VALUE: [u8; 506] = [ - 250, 1, 0, 0, 68, 0, 0, 0, 100, 0, 0, 0, 116, 0, 0, 0, 169, 0, 0, 0, 177, 0, 0, 0, 193, 0, - 0, 0, 201, 0, 0, 0, 209, 0, 0, 0, 242, 0, 0, 0, 19, 1, 0, 0, 52, 1, 0, 0, 85, 1, 0, 0, 118, - 1, 0, 0, 151, 1, 0, 0, 184, 1, 0, 0, 184, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 53, 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + const DEFAULT_VALUE: [u8; 383] = [ + 127, 1, 0, 0, 52, 0, 0, 0, 84, 0, 0, 0, 100, 0, 0, 0, 153, 0, 0, 0, 161, 0, 0, 0, 177, 0, + 0, 0, 185, 0, 0, 0, 218, 0, 0, 0, 251, 0, 0, 0, 28, 1, 0, 0, 61, 1, 0, 0, 61, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, + 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -5310,9 +5188,9 @@ impl AcceptChannel { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, + 0, ]; - pub const FIELD_COUNT: usize = 16; + pub const FIELD_COUNT: usize = 12; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -5365,65 +5243,41 @@ impl AcceptChannel { let end = molecule::unpack_number(&slice[28..]) as usize; Uint64::new_unchecked(self.0.slice(start..end)) } - pub fn commitment_delay_epoch(&self) -> Uint64 { + pub fn funding_pubkey(&self) -> Pubkey { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[28..]) as usize; let end = molecule::unpack_number(&slice[32..]) as usize; - Uint64::new_unchecked(self.0.slice(start..end)) + Pubkey::new_unchecked(self.0.slice(start..end)) } - pub fn funding_pubkey(&self) -> Pubkey { + pub fn tlc_basepoint(&self) -> Pubkey { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[32..]) as usize; let end = molecule::unpack_number(&slice[36..]) as usize; Pubkey::new_unchecked(self.0.slice(start..end)) } - pub fn revocation_basepoint(&self) -> Pubkey { + pub fn first_per_commitment_point(&self) -> Pubkey { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[36..]) as usize; let end = molecule::unpack_number(&slice[40..]) as usize; Pubkey::new_unchecked(self.0.slice(start..end)) } - pub fn payment_basepoint(&self) -> Pubkey { + pub fn second_per_commitment_point(&self) -> Pubkey { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[40..]) as usize; let end = molecule::unpack_number(&slice[44..]) as usize; Pubkey::new_unchecked(self.0.slice(start..end)) } - pub fn delayed_payment_basepoint(&self) -> Pubkey { + pub fn channel_annoucement_nonce(&self) -> PubNonceOpt { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[44..]) as usize; let end = molecule::unpack_number(&slice[48..]) as usize; - Pubkey::new_unchecked(self.0.slice(start..end)) - } - pub fn tlc_basepoint(&self) -> Pubkey { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[48..]) as usize; - let end = molecule::unpack_number(&slice[52..]) as usize; - Pubkey::new_unchecked(self.0.slice(start..end)) - } - pub fn first_per_commitment_point(&self) -> Pubkey { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[52..]) as usize; - let end = molecule::unpack_number(&slice[56..]) as usize; - Pubkey::new_unchecked(self.0.slice(start..end)) - } - pub fn second_per_commitment_point(&self) -> Pubkey { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[56..]) as usize; - let end = molecule::unpack_number(&slice[60..]) as usize; - Pubkey::new_unchecked(self.0.slice(start..end)) - } - pub fn channel_annoucement_nonce(&self) -> PubNonceOpt { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[60..]) as usize; - let end = molecule::unpack_number(&slice[64..]) as usize; PubNonceOpt::new_unchecked(self.0.slice(start..end)) } pub fn next_local_nonce(&self) -> PubNonce { let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[64..]) as usize; + let start = molecule::unpack_number(&slice[48..]) as usize; if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[68..]) as usize; + let end = molecule::unpack_number(&slice[52..]) as usize; PubNonce::new_unchecked(self.0.slice(start..end)) } else { PubNonce::new_unchecked(self.0.slice(start..)) @@ -5462,11 +5316,7 @@ impl molecule::prelude::Entity for AcceptChannel { .reserved_ckb_amount(self.reserved_ckb_amount()) .max_tlc_value_in_flight(self.max_tlc_value_in_flight()) .max_tlc_number_in_flight(self.max_tlc_number_in_flight()) - .commitment_delay_epoch(self.commitment_delay_epoch()) .funding_pubkey(self.funding_pubkey()) - .revocation_basepoint(self.revocation_basepoint()) - .payment_basepoint(self.payment_basepoint()) - .delayed_payment_basepoint(self.delayed_payment_basepoint()) .tlc_basepoint(self.tlc_basepoint()) .first_per_commitment_point(self.first_per_commitment_point()) .second_per_commitment_point(self.second_per_commitment_point()) @@ -5514,26 +5364,7 @@ impl<'r> ::core::fmt::Display for AcceptChannelReader<'r> { "max_tlc_number_in_flight", self.max_tlc_number_in_flight() )?; - write!( - f, - ", {}: {}", - "commitment_delay_epoch", - self.commitment_delay_epoch() - )?; write!(f, ", {}: {}", "funding_pubkey", self.funding_pubkey())?; - write!( - f, - ", {}: {}", - "revocation_basepoint", - self.revocation_basepoint() - )?; - write!(f, ", {}: {}", "payment_basepoint", self.payment_basepoint())?; - write!( - f, - ", {}: {}", - "delayed_payment_basepoint", - self.delayed_payment_basepoint() - )?; write!(f, ", {}: {}", "tlc_basepoint", self.tlc_basepoint())?; write!( f, @@ -5562,7 +5393,7 @@ impl<'r> ::core::fmt::Display for AcceptChannelReader<'r> { } } impl<'r> AcceptChannelReader<'r> { - pub const FIELD_COUNT: usize = 16; + pub const FIELD_COUNT: usize = 12; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -5615,65 +5446,41 @@ impl<'r> AcceptChannelReader<'r> { let end = molecule::unpack_number(&slice[28..]) as usize; Uint64Reader::new_unchecked(&self.as_slice()[start..end]) } - pub fn commitment_delay_epoch(&self) -> Uint64Reader<'r> { + pub fn funding_pubkey(&self) -> PubkeyReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[28..]) as usize; let end = molecule::unpack_number(&slice[32..]) as usize; - Uint64Reader::new_unchecked(&self.as_slice()[start..end]) + PubkeyReader::new_unchecked(&self.as_slice()[start..end]) } - pub fn funding_pubkey(&self) -> PubkeyReader<'r> { + pub fn tlc_basepoint(&self) -> PubkeyReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[32..]) as usize; let end = molecule::unpack_number(&slice[36..]) as usize; PubkeyReader::new_unchecked(&self.as_slice()[start..end]) } - pub fn revocation_basepoint(&self) -> PubkeyReader<'r> { + pub fn first_per_commitment_point(&self) -> PubkeyReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[36..]) as usize; let end = molecule::unpack_number(&slice[40..]) as usize; PubkeyReader::new_unchecked(&self.as_slice()[start..end]) } - pub fn payment_basepoint(&self) -> PubkeyReader<'r> { + pub fn second_per_commitment_point(&self) -> PubkeyReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[40..]) as usize; let end = molecule::unpack_number(&slice[44..]) as usize; PubkeyReader::new_unchecked(&self.as_slice()[start..end]) } - pub fn delayed_payment_basepoint(&self) -> PubkeyReader<'r> { + pub fn channel_annoucement_nonce(&self) -> PubNonceOptReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[44..]) as usize; let end = molecule::unpack_number(&slice[48..]) as usize; - PubkeyReader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn tlc_basepoint(&self) -> PubkeyReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[48..]) as usize; - let end = molecule::unpack_number(&slice[52..]) as usize; - PubkeyReader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn first_per_commitment_point(&self) -> PubkeyReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[52..]) as usize; - let end = molecule::unpack_number(&slice[56..]) as usize; - PubkeyReader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn second_per_commitment_point(&self) -> PubkeyReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[56..]) as usize; - let end = molecule::unpack_number(&slice[60..]) as usize; - PubkeyReader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn channel_annoucement_nonce(&self) -> PubNonceOptReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[60..]) as usize; - let end = molecule::unpack_number(&slice[64..]) as usize; PubNonceOptReader::new_unchecked(&self.as_slice()[start..end]) } pub fn next_local_nonce(&self) -> PubNonceReader<'r> { let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[64..]) as usize; + let start = molecule::unpack_number(&slice[48..]) as usize; if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[68..]) as usize; + let end = molecule::unpack_number(&slice[52..]) as usize; PubNonceReader::new_unchecked(&self.as_slice()[start..end]) } else { PubNonceReader::new_unchecked(&self.as_slice()[start..]) @@ -5732,16 +5539,12 @@ impl<'r> molecule::prelude::Reader<'r> for AcceptChannelReader<'r> { Uint64Reader::verify(&slice[offsets[3]..offsets[4]], compatible)?; Uint128Reader::verify(&slice[offsets[4]..offsets[5]], compatible)?; Uint64Reader::verify(&slice[offsets[5]..offsets[6]], compatible)?; - Uint64Reader::verify(&slice[offsets[6]..offsets[7]], compatible)?; + PubkeyReader::verify(&slice[offsets[6]..offsets[7]], compatible)?; PubkeyReader::verify(&slice[offsets[7]..offsets[8]], compatible)?; PubkeyReader::verify(&slice[offsets[8]..offsets[9]], compatible)?; PubkeyReader::verify(&slice[offsets[9]..offsets[10]], compatible)?; - PubkeyReader::verify(&slice[offsets[10]..offsets[11]], compatible)?; - PubkeyReader::verify(&slice[offsets[11]..offsets[12]], compatible)?; - PubkeyReader::verify(&slice[offsets[12]..offsets[13]], compatible)?; - PubkeyReader::verify(&slice[offsets[13]..offsets[14]], compatible)?; - PubNonceOptReader::verify(&slice[offsets[14]..offsets[15]], compatible)?; - PubNonceReader::verify(&slice[offsets[15]..offsets[16]], compatible)?; + PubNonceOptReader::verify(&slice[offsets[10]..offsets[11]], compatible)?; + PubNonceReader::verify(&slice[offsets[11]..offsets[12]], compatible)?; Ok(()) } } @@ -5753,11 +5556,7 @@ pub struct AcceptChannelBuilder { pub(crate) reserved_ckb_amount: Uint64, pub(crate) max_tlc_value_in_flight: Uint128, pub(crate) max_tlc_number_in_flight: Uint64, - pub(crate) commitment_delay_epoch: Uint64, pub(crate) funding_pubkey: Pubkey, - pub(crate) revocation_basepoint: Pubkey, - pub(crate) payment_basepoint: Pubkey, - pub(crate) delayed_payment_basepoint: Pubkey, pub(crate) tlc_basepoint: Pubkey, pub(crate) first_per_commitment_point: Pubkey, pub(crate) second_per_commitment_point: Pubkey, @@ -5765,7 +5564,7 @@ pub struct AcceptChannelBuilder { pub(crate) next_local_nonce: PubNonce, } impl AcceptChannelBuilder { - pub const FIELD_COUNT: usize = 16; + pub const FIELD_COUNT: usize = 12; pub fn channel_id(mut self, v: Byte32) -> Self { self.channel_id = v; self @@ -5790,26 +5589,10 @@ impl AcceptChannelBuilder { self.max_tlc_number_in_flight = v; self } - pub fn commitment_delay_epoch(mut self, v: Uint64) -> Self { - self.commitment_delay_epoch = v; - self - } pub fn funding_pubkey(mut self, v: Pubkey) -> Self { self.funding_pubkey = v; self } - pub fn revocation_basepoint(mut self, v: Pubkey) -> Self { - self.revocation_basepoint = v; - self - } - pub fn payment_basepoint(mut self, v: Pubkey) -> Self { - self.payment_basepoint = v; - self - } - pub fn delayed_payment_basepoint(mut self, v: Pubkey) -> Self { - self.delayed_payment_basepoint = v; - self - } pub fn tlc_basepoint(mut self, v: Pubkey) -> Self { self.tlc_basepoint = v; self @@ -5842,11 +5625,7 @@ impl molecule::prelude::Builder for AcceptChannelBuilder { + self.reserved_ckb_amount.as_slice().len() + self.max_tlc_value_in_flight.as_slice().len() + self.max_tlc_number_in_flight.as_slice().len() - + self.commitment_delay_epoch.as_slice().len() + self.funding_pubkey.as_slice().len() - + self.revocation_basepoint.as_slice().len() - + self.payment_basepoint.as_slice().len() - + self.delayed_payment_basepoint.as_slice().len() + self.tlc_basepoint.as_slice().len() + self.first_per_commitment_point.as_slice().len() + self.second_per_commitment_point.as_slice().len() @@ -5869,16 +5648,8 @@ impl molecule::prelude::Builder for AcceptChannelBuilder { offsets.push(total_size); total_size += self.max_tlc_number_in_flight.as_slice().len(); offsets.push(total_size); - total_size += self.commitment_delay_epoch.as_slice().len(); - offsets.push(total_size); total_size += self.funding_pubkey.as_slice().len(); offsets.push(total_size); - total_size += self.revocation_basepoint.as_slice().len(); - offsets.push(total_size); - total_size += self.payment_basepoint.as_slice().len(); - offsets.push(total_size); - total_size += self.delayed_payment_basepoint.as_slice().len(); - offsets.push(total_size); total_size += self.tlc_basepoint.as_slice().len(); offsets.push(total_size); total_size += self.first_per_commitment_point.as_slice().len(); @@ -5898,11 +5669,7 @@ impl molecule::prelude::Builder for AcceptChannelBuilder { writer.write_all(self.reserved_ckb_amount.as_slice())?; writer.write_all(self.max_tlc_value_in_flight.as_slice())?; writer.write_all(self.max_tlc_number_in_flight.as_slice())?; - writer.write_all(self.commitment_delay_epoch.as_slice())?; writer.write_all(self.funding_pubkey.as_slice())?; - writer.write_all(self.revocation_basepoint.as_slice())?; - writer.write_all(self.payment_basepoint.as_slice())?; - writer.write_all(self.delayed_payment_basepoint.as_slice())?; writer.write_all(self.tlc_basepoint.as_slice())?; writer.write_all(self.first_per_commitment_point.as_slice())?; writer.write_all(self.second_per_commitment_point.as_slice())?; @@ -5950,10 +5717,6 @@ impl ::core::fmt::Display for CommitmentSigned { self.commitment_tx_partial_signature() )?; write!(f, ", {}: {}", "next_local_nonce", self.next_local_nonce())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } write!(f, " }}") } } @@ -5964,59 +5727,28 @@ impl ::core::default::Default for CommitmentSigned { } } impl CommitmentSigned { - const DEFAULT_VALUE: [u8; 182] = [ - 182, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, 0, 84, 0, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + const DEFAULT_VALUE: [u8; 162] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; + pub const TOTAL_SIZE: usize = 162; + pub const FIELD_SIZES: [usize; 4] = [32, 32, 32, 66]; pub const FIELD_COUNT: usize = 4; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() - } pub fn channel_id(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) + Byte32::new_unchecked(self.0.slice(0..32)) } pub fn funding_tx_partial_signature(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) + Byte32::new_unchecked(self.0.slice(32..64)) } pub fn commitment_tx_partial_signature(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; - let end = molecule::unpack_number(&slice[16..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) + Byte32::new_unchecked(self.0.slice(64..96)) } pub fn next_local_nonce(&self) -> PubNonce { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[16..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[20..]) as usize; - PubNonce::new_unchecked(self.0.slice(start..end)) - } else { - PubNonce::new_unchecked(self.0.slice(start..)) - } + PubNonce::new_unchecked(self.0.slice(96..162)) } pub fn as_reader<'r>(&'r self) -> CommitmentSignedReader<'r> { CommitmentSignedReader::new_unchecked(self.as_slice()) @@ -6084,58 +5816,24 @@ impl<'r> ::core::fmt::Display for CommitmentSignedReader<'r> { self.commitment_tx_partial_signature() )?; write!(f, ", {}: {}", "next_local_nonce", self.next_local_nonce())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } write!(f, " }}") } } impl<'r> CommitmentSignedReader<'r> { + pub const TOTAL_SIZE: usize = 162; + pub const FIELD_SIZES: [usize; 4] = [32, 32, 32, 66]; pub const FIELD_COUNT: usize = 4; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() - } pub fn channel_id(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + Byte32Reader::new_unchecked(&self.as_slice()[0..32]) } pub fn funding_tx_partial_signature(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + Byte32Reader::new_unchecked(&self.as_slice()[32..64]) } pub fn commitment_tx_partial_signature(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; - let end = molecule::unpack_number(&slice[16..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + Byte32Reader::new_unchecked(&self.as_slice()[64..96]) } pub fn next_local_nonce(&self) -> PubNonceReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[16..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[20..]) as usize; - PubNonceReader::new_unchecked(&self.as_slice()[start..end]) - } else { - PubNonceReader::new_unchecked(&self.as_slice()[start..]) - } + PubNonceReader::new_unchecked(&self.as_slice()[96..162]) } } impl<'r> molecule::prelude::Reader<'r> for CommitmentSignedReader<'r> { @@ -6150,44 +5848,12 @@ impl<'r> molecule::prelude::Reader<'r> for CommitmentSignedReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::verification_error as ve; let slice_len = slice.len(); - if slice_len < molecule::NUMBER_SIZE { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); - } - let total_size = molecule::unpack_number(slice) as usize; - if slice_len != total_size { - return ve!(Self, TotalSizeNotMatch, total_size, slice_len); - } - if slice_len < molecule::NUMBER_SIZE * 2 { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); - } - let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; - if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { - return ve!(Self, OffsetsNotMatch); - } - if slice_len < offset_first { - return ve!(Self, HeaderIsBroken, offset_first, slice_len); - } - let field_count = offset_first / molecule::NUMBER_SIZE - 1; - if field_count < Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - } else if !compatible && field_count > Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - }; - let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] - .chunks_exact(molecule::NUMBER_SIZE) - .map(|x| molecule::unpack_number(x) as usize) - .collect(); - offsets.push(total_size); - if offsets.windows(2).any(|i| i[0] > i[1]) { - return ve!(Self, OffsetsNotMatch); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); } - Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; - Byte32Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; - Byte32Reader::verify(&slice[offsets[2]..offsets[3]], compatible)?; - PubNonceReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; Ok(()) } } @@ -6199,6 +5865,8 @@ pub struct CommitmentSignedBuilder { pub(crate) next_local_nonce: PubNonce, } impl CommitmentSignedBuilder { + pub const TOTAL_SIZE: usize = 162; + pub const FIELD_SIZES: [usize; 4] = [32, 32, 32, 66]; pub const FIELD_COUNT: usize = 4; pub fn channel_id(mut self, v: Byte32) -> Self { self.channel_id = v; @@ -6221,27 +5889,9 @@ impl molecule::prelude::Builder for CommitmentSignedBuilder { type Entity = CommitmentSigned; const NAME: &'static str = "CommitmentSignedBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.channel_id.as_slice().len() - + self.funding_tx_partial_signature.as_slice().len() - + self.commitment_tx_partial_signature.as_slice().len() - + self.next_local_nonce.as_slice().len() + Self::TOTAL_SIZE } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); - let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); - offsets.push(total_size); - total_size += self.channel_id.as_slice().len(); - offsets.push(total_size); - total_size += self.funding_tx_partial_signature.as_slice().len(); - offsets.push(total_size); - total_size += self.commitment_tx_partial_signature.as_slice().len(); - offsets.push(total_size); - total_size += self.next_local_nonce.as_slice().len(); - writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; - for offset in offsets.into_iter() { - writer.write_all(&molecule::pack_number(offset as molecule::Number))?; - } writer.write_all(self.channel_id.as_slice())?; writer.write_all(self.funding_tx_partial_signature.as_slice())?; writer.write_all(self.commitment_tx_partial_signature.as_slice())?; @@ -6564,50 +6214,25 @@ impl ::core::fmt::Display for ChannelReady { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "channel_id", self.channel_id())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } write!(f, " }}") } } impl ::core::default::Default for ChannelReady { - fn default() -> Self { - let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); - ChannelReady::new_unchecked(v) - } -} -impl ChannelReady { - const DEFAULT_VALUE: [u8; 40] = [ - 40, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; - pub const FIELD_COUNT: usize = 1; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ChannelReady::new_unchecked(v) } +} +impl ChannelReady { + const DEFAULT_VALUE: [u8; 32] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; + pub const TOTAL_SIZE: usize = 32; + pub const FIELD_SIZES: [usize; 1] = [32]; + pub const FIELD_COUNT: usize = 1; pub fn channel_id(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) - } else { - Byte32::new_unchecked(self.0.slice(start..)) - } + Byte32::new_unchecked(self.0.slice(0..32)) } pub fn as_reader<'r>(&'r self) -> ChannelReadyReader<'r> { ChannelReadyReader::new_unchecked(self.as_slice()) @@ -6658,40 +6283,15 @@ impl<'r> ::core::fmt::Display for ChannelReadyReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "channel_id", self.channel_id())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } write!(f, " }}") } } impl<'r> ChannelReadyReader<'r> { + pub const TOTAL_SIZE: usize = 32; + pub const FIELD_SIZES: [usize; 1] = [32]; pub const FIELD_COUNT: usize = 1; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() - } pub fn channel_id(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) - } else { - Byte32Reader::new_unchecked(&self.as_slice()[start..]) - } + Byte32Reader::new_unchecked(&self.as_slice()[0..32]) } } impl<'r> molecule::prelude::Reader<'r> for ChannelReadyReader<'r> { @@ -6706,41 +6306,12 @@ impl<'r> molecule::prelude::Reader<'r> for ChannelReadyReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::verification_error as ve; let slice_len = slice.len(); - if slice_len < molecule::NUMBER_SIZE { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); - } - let total_size = molecule::unpack_number(slice) as usize; - if slice_len != total_size { - return ve!(Self, TotalSizeNotMatch, total_size, slice_len); - } - if slice_len < molecule::NUMBER_SIZE * 2 { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); - } - let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; - if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { - return ve!(Self, OffsetsNotMatch); - } - if slice_len < offset_first { - return ve!(Self, HeaderIsBroken, offset_first, slice_len); - } - let field_count = offset_first / molecule::NUMBER_SIZE - 1; - if field_count < Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - } else if !compatible && field_count > Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - }; - let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] - .chunks_exact(molecule::NUMBER_SIZE) - .map(|x| molecule::unpack_number(x) as usize) - .collect(); - offsets.push(total_size); - if offsets.windows(2).any(|i| i[0] > i[1]) { - return ve!(Self, OffsetsNotMatch); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); } - Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; Ok(()) } } @@ -6749,6 +6320,8 @@ pub struct ChannelReadyBuilder { pub(crate) channel_id: Byte32, } impl ChannelReadyBuilder { + pub const TOTAL_SIZE: usize = 32; + pub const FIELD_SIZES: [usize; 1] = [32]; pub const FIELD_COUNT: usize = 1; pub fn channel_id(mut self, v: Byte32) -> Self { self.channel_id = v; @@ -6759,17 +6332,9 @@ impl molecule::prelude::Builder for ChannelReadyBuilder { type Entity = ChannelReady; const NAME: &'static str = "ChannelReadyBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + self.channel_id.as_slice().len() + Self::TOTAL_SIZE } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); - let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); - offsets.push(total_size); - total_size += self.channel_id.as_slice().len(); - writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; - for offset in offsets.into_iter() { - writer.write_all(&molecule::pack_number(offset as molecule::Number))?; - } writer.write_all(self.channel_id.as_slice())?; Ok(()) } @@ -7065,10 +6630,6 @@ impl ::core::fmt::Display for TxComplete { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "channel_id", self.channel_id())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } write!(f, " }}") } } @@ -7079,36 +6640,15 @@ impl ::core::default::Default for TxComplete { } } impl TxComplete { - const DEFAULT_VALUE: [u8; 40] = [ - 40, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + const DEFAULT_VALUE: [u8; 32] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, ]; + pub const TOTAL_SIZE: usize = 32; + pub const FIELD_SIZES: [usize; 1] = [32]; pub const FIELD_COUNT: usize = 1; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() - } pub fn channel_id(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) - } else { - Byte32::new_unchecked(self.0.slice(start..)) - } + Byte32::new_unchecked(self.0.slice(0..32)) } pub fn as_reader<'r>(&'r self) -> TxCompleteReader<'r> { TxCompleteReader::new_unchecked(self.as_slice()) @@ -7159,40 +6699,15 @@ impl<'r> ::core::fmt::Display for TxCompleteReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "channel_id", self.channel_id())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } write!(f, " }}") } } impl<'r> TxCompleteReader<'r> { + pub const TOTAL_SIZE: usize = 32; + pub const FIELD_SIZES: [usize; 1] = [32]; pub const FIELD_COUNT: usize = 1; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() - } pub fn channel_id(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) - } else { - Byte32Reader::new_unchecked(&self.as_slice()[start..]) - } + Byte32Reader::new_unchecked(&self.as_slice()[0..32]) } } impl<'r> molecule::prelude::Reader<'r> for TxCompleteReader<'r> { @@ -7207,41 +6722,12 @@ impl<'r> molecule::prelude::Reader<'r> for TxCompleteReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::verification_error as ve; let slice_len = slice.len(); - if slice_len < molecule::NUMBER_SIZE { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); - } - let total_size = molecule::unpack_number(slice) as usize; - if slice_len != total_size { - return ve!(Self, TotalSizeNotMatch, total_size, slice_len); - } - if slice_len < molecule::NUMBER_SIZE * 2 { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); - } - let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; - if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { - return ve!(Self, OffsetsNotMatch); - } - if slice_len < offset_first { - return ve!(Self, HeaderIsBroken, offset_first, slice_len); - } - let field_count = offset_first / molecule::NUMBER_SIZE - 1; - if field_count < Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - } else if !compatible && field_count > Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - }; - let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] - .chunks_exact(molecule::NUMBER_SIZE) - .map(|x| molecule::unpack_number(x) as usize) - .collect(); - offsets.push(total_size); - if offsets.windows(2).any(|i| i[0] > i[1]) { - return ve!(Self, OffsetsNotMatch); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); } - Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; Ok(()) } } @@ -7250,6 +6736,8 @@ pub struct TxCompleteBuilder { pub(crate) channel_id: Byte32, } impl TxCompleteBuilder { + pub const TOTAL_SIZE: usize = 32; + pub const FIELD_SIZES: [usize; 1] = [32]; pub const FIELD_COUNT: usize = 1; pub fn channel_id(mut self, v: Byte32) -> Self { self.channel_id = v; @@ -7260,17 +6748,9 @@ impl molecule::prelude::Builder for TxCompleteBuilder { type Entity = TxComplete; const NAME: &'static str = "TxCompleteBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + self.channel_id.as_slice().len() + Self::TOTAL_SIZE } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); - let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); - offsets.push(total_size); - total_size += self.channel_id.as_slice().len(); - writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; - for offset in offsets.into_iter() { - writer.write_all(&molecule::pack_number(offset as molecule::Number))?; - } writer.write_all(self.channel_id.as_slice())?; Ok(()) } @@ -8354,10 +7834,6 @@ impl ::core::fmt::Display for ClosingSigned { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "channel_id", self.channel_id())?; write!(f, ", {}: {}", "partial_signature", self.partial_signature())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } write!(f, " }}") } } @@ -8368,43 +7844,19 @@ impl ::core::default::Default for ClosingSigned { } } impl ClosingSigned { - const DEFAULT_VALUE: [u8; 76] = [ - 76, 0, 0, 0, 12, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + const DEFAULT_VALUE: [u8; 64] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, ]; + pub const TOTAL_SIZE: usize = 64; + pub const FIELD_SIZES: [usize; 2] = [32, 32]; pub const FIELD_COUNT: usize = 2; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() - } pub fn channel_id(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) + Byte32::new_unchecked(self.0.slice(0..32)) } pub fn partial_signature(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[12..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) - } else { - Byte32::new_unchecked(self.0.slice(start..)) - } + Byte32::new_unchecked(self.0.slice(32..64)) } pub fn as_reader<'r>(&'r self) -> ClosingSignedReader<'r> { ClosingSignedReader::new_unchecked(self.as_slice()) @@ -8458,46 +7910,18 @@ impl<'r> ::core::fmt::Display for ClosingSignedReader<'r> { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "channel_id", self.channel_id())?; write!(f, ", {}: {}", "partial_signature", self.partial_signature())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } write!(f, " }}") } } impl<'r> ClosingSignedReader<'r> { + pub const TOTAL_SIZE: usize = 64; + pub const FIELD_SIZES: [usize; 2] = [32, 32]; pub const FIELD_COUNT: usize = 2; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() - } pub fn channel_id(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + Byte32Reader::new_unchecked(&self.as_slice()[0..32]) } pub fn partial_signature(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[12..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) - } else { - Byte32Reader::new_unchecked(&self.as_slice()[start..]) - } + Byte32Reader::new_unchecked(&self.as_slice()[32..64]) } } impl<'r> molecule::prelude::Reader<'r> for ClosingSignedReader<'r> { @@ -8512,42 +7936,12 @@ impl<'r> molecule::prelude::Reader<'r> for ClosingSignedReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::verification_error as ve; let slice_len = slice.len(); - if slice_len < molecule::NUMBER_SIZE { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); - } - let total_size = molecule::unpack_number(slice) as usize; - if slice_len != total_size { - return ve!(Self, TotalSizeNotMatch, total_size, slice_len); - } - if slice_len < molecule::NUMBER_SIZE * 2 { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); - } - let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; - if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { - return ve!(Self, OffsetsNotMatch); - } - if slice_len < offset_first { - return ve!(Self, HeaderIsBroken, offset_first, slice_len); - } - let field_count = offset_first / molecule::NUMBER_SIZE - 1; - if field_count < Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - } else if !compatible && field_count > Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - }; - let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] - .chunks_exact(molecule::NUMBER_SIZE) - .map(|x| molecule::unpack_number(x) as usize) - .collect(); - offsets.push(total_size); - if offsets.windows(2).any(|i| i[0] > i[1]) { - return ve!(Self, OffsetsNotMatch); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); } - Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; - Byte32Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; Ok(()) } } @@ -8557,6 +7951,8 @@ pub struct ClosingSignedBuilder { pub(crate) partial_signature: Byte32, } impl ClosingSignedBuilder { + pub const TOTAL_SIZE: usize = 64; + pub const FIELD_SIZES: [usize; 2] = [32, 32]; pub const FIELD_COUNT: usize = 2; pub fn channel_id(mut self, v: Byte32) -> Self { self.channel_id = v; @@ -8571,21 +7967,9 @@ impl molecule::prelude::Builder for ClosingSignedBuilder { type Entity = ClosingSigned; const NAME: &'static str = "ClosingSignedBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.channel_id.as_slice().len() - + self.partial_signature.as_slice().len() + Self::TOTAL_SIZE } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); - let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); - offsets.push(total_size); - total_size += self.channel_id.as_slice().len(); - offsets.push(total_size); - total_size += self.partial_signature.as_slice().len(); - writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; - for offset in offsets.into_iter() { - writer.write_all(&molecule::pack_number(offset as molecule::Number))?; - } writer.write_all(self.channel_id.as_slice())?; writer.write_all(self.partial_signature.as_slice())?; Ok(()) @@ -9008,17 +8392,24 @@ impl ::core::fmt::Display for RevokeAndAck { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "channel_id", self.channel_id())?; - write!(f, ", {}: {}", "partial_signature", self.partial_signature())?; + write!( + f, + ", {}: {}", + "revocation_partial_signature", + self.revocation_partial_signature() + )?; + write!( + f, + ", {}: {}", + "commitment_tx_partial_signature", + self.commitment_tx_partial_signature() + )?; write!( f, ", {}: {}", "next_per_commitment_point", self.next_per_commitment_point() )?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } write!(f, " }}") } } @@ -9029,50 +8420,27 @@ impl ::core::default::Default for RevokeAndAck { } } impl RevokeAndAck { - const DEFAULT_VALUE: [u8; 113] = [ - 113, 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + const DEFAULT_VALUE: [u8; 129] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; - pub const FIELD_COUNT: usize = 3; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() - } + pub const TOTAL_SIZE: usize = 129; + pub const FIELD_SIZES: [usize; 4] = [32, 32, 32, 33]; + pub const FIELD_COUNT: usize = 4; pub fn channel_id(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) + Byte32::new_unchecked(self.0.slice(0..32)) } - pub fn partial_signature(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) + pub fn revocation_partial_signature(&self) -> Byte32 { + Byte32::new_unchecked(self.0.slice(32..64)) + } + pub fn commitment_tx_partial_signature(&self) -> Byte32 { + Byte32::new_unchecked(self.0.slice(64..96)) } pub fn next_per_commitment_point(&self) -> Pubkey { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[16..]) as usize; - Pubkey::new_unchecked(self.0.slice(start..end)) - } else { - Pubkey::new_unchecked(self.0.slice(start..)) - } + Pubkey::new_unchecked(self.0.slice(96..129)) } pub fn as_reader<'r>(&'r self) -> RevokeAndAckReader<'r> { RevokeAndAckReader::new_unchecked(self.as_slice()) @@ -9102,7 +8470,8 @@ impl molecule::prelude::Entity for RevokeAndAck { fn as_builder(self) -> Self::Builder { Self::new_builder() .channel_id(self.channel_id()) - .partial_signature(self.partial_signature()) + .revocation_partial_signature(self.revocation_partial_signature()) + .commitment_tx_partial_signature(self.commitment_tx_partial_signature()) .next_per_commitment_point(self.next_per_commitment_point()) } } @@ -9126,59 +8495,42 @@ impl<'r> ::core::fmt::Display for RevokeAndAckReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "channel_id", self.channel_id())?; - write!(f, ", {}: {}", "partial_signature", self.partial_signature())?; + write!( + f, + ", {}: {}", + "revocation_partial_signature", + self.revocation_partial_signature() + )?; + write!( + f, + ", {}: {}", + "commitment_tx_partial_signature", + self.commitment_tx_partial_signature() + )?; write!( f, ", {}: {}", "next_per_commitment_point", self.next_per_commitment_point() )?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } write!(f, " }}") } } impl<'r> RevokeAndAckReader<'r> { - pub const FIELD_COUNT: usize = 3; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() - } + pub const TOTAL_SIZE: usize = 129; + pub const FIELD_SIZES: [usize; 4] = [32, 32, 32, 33]; + pub const FIELD_COUNT: usize = 4; pub fn channel_id(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + Byte32Reader::new_unchecked(&self.as_slice()[0..32]) } - pub fn partial_signature(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + pub fn revocation_partial_signature(&self) -> Byte32Reader<'r> { + Byte32Reader::new_unchecked(&self.as_slice()[32..64]) + } + pub fn commitment_tx_partial_signature(&self) -> Byte32Reader<'r> { + Byte32Reader::new_unchecked(&self.as_slice()[64..96]) } pub fn next_per_commitment_point(&self) -> PubkeyReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[16..]) as usize; - PubkeyReader::new_unchecked(&self.as_slice()[start..end]) - } else { - PubkeyReader::new_unchecked(&self.as_slice()[start..]) - } + PubkeyReader::new_unchecked(&self.as_slice()[96..129]) } } impl<'r> molecule::prelude::Reader<'r> for RevokeAndAckReader<'r> { @@ -9193,60 +8545,36 @@ impl<'r> molecule::prelude::Reader<'r> for RevokeAndAckReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::verification_error as ve; let slice_len = slice.len(); - if slice_len < molecule::NUMBER_SIZE { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); - } - let total_size = molecule::unpack_number(slice) as usize; - if slice_len != total_size { - return ve!(Self, TotalSizeNotMatch, total_size, slice_len); - } - if slice_len < molecule::NUMBER_SIZE * 2 { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); - } - let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; - if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { - return ve!(Self, OffsetsNotMatch); - } - if slice_len < offset_first { - return ve!(Self, HeaderIsBroken, offset_first, slice_len); - } - let field_count = offset_first / molecule::NUMBER_SIZE - 1; - if field_count < Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - } else if !compatible && field_count > Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - }; - let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] - .chunks_exact(molecule::NUMBER_SIZE) - .map(|x| molecule::unpack_number(x) as usize) - .collect(); - offsets.push(total_size); - if offsets.windows(2).any(|i| i[0] > i[1]) { - return ve!(Self, OffsetsNotMatch); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); } - Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; - Byte32Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; - PubkeyReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; Ok(()) } } #[derive(Clone, Debug, Default)] pub struct RevokeAndAckBuilder { pub(crate) channel_id: Byte32, - pub(crate) partial_signature: Byte32, + pub(crate) revocation_partial_signature: Byte32, + pub(crate) commitment_tx_partial_signature: Byte32, pub(crate) next_per_commitment_point: Pubkey, } impl RevokeAndAckBuilder { - pub const FIELD_COUNT: usize = 3; + pub const TOTAL_SIZE: usize = 129; + pub const FIELD_SIZES: [usize; 4] = [32, 32, 32, 33]; + pub const FIELD_COUNT: usize = 4; pub fn channel_id(mut self, v: Byte32) -> Self { self.channel_id = v; self } - pub fn partial_signature(mut self, v: Byte32) -> Self { - self.partial_signature = v; + pub fn revocation_partial_signature(mut self, v: Byte32) -> Self { + self.revocation_partial_signature = v; + self + } + pub fn commitment_tx_partial_signature(mut self, v: Byte32) -> Self { + self.commitment_tx_partial_signature = v; self } pub fn next_per_commitment_point(mut self, v: Pubkey) -> Self { @@ -9258,26 +8586,12 @@ impl molecule::prelude::Builder for RevokeAndAckBuilder { type Entity = RevokeAndAck; const NAME: &'static str = "RevokeAndAckBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.channel_id.as_slice().len() - + self.partial_signature.as_slice().len() - + self.next_per_commitment_point.as_slice().len() + Self::TOTAL_SIZE } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); - let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); - offsets.push(total_size); - total_size += self.channel_id.as_slice().len(); - offsets.push(total_size); - total_size += self.partial_signature.as_slice().len(); - offsets.push(total_size); - total_size += self.next_per_commitment_point.as_slice().len(); - writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; - for offset in offsets.into_iter() { - writer.write_all(&molecule::pack_number(offset as molecule::Number))?; - } writer.write_all(self.channel_id.as_slice())?; - writer.write_all(self.partial_signature.as_slice())?; + writer.write_all(self.revocation_partial_signature.as_slice())?; + writer.write_all(self.commitment_tx_partial_signature.as_slice())?; writer.write_all(self.next_per_commitment_point.as_slice())?; Ok(()) } @@ -18274,15 +17588,14 @@ impl ::core::default::Default for FiberMessage { } } impl FiberMessage { - const DEFAULT_VALUE: [u8; 579] = [ - 0, 0, 0, 0, 63, 2, 0, 0, 88, 0, 0, 0, 120, 0, 0, 0, 152, 0, 0, 0, 152, 0, 0, 0, 168, 0, 0, - 0, 221, 0, 0, 0, 229, 0, 0, 0, 237, 0, 0, 0, 245, 0, 0, 0, 5, 1, 0, 0, 13, 1, 0, 0, 21, 1, - 0, 0, 54, 1, 0, 0, 87, 1, 0, 0, 120, 1, 0, 0, 153, 1, 0, 0, 186, 1, 0, 0, 219, 1, 0, 0, - 252, 1, 0, 0, 252, 1, 0, 0, 62, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + const DEFAULT_VALUE: [u8; 468] = [ + 0, 0, 0, 0, 208, 1, 0, 0, 76, 0, 0, 0, 108, 0, 0, 0, 140, 0, 0, 0, 140, 0, 0, 0, 156, 0, 0, + 0, 209, 0, 0, 0, 217, 0, 0, 0, 225, 0, 0, 0, 233, 0, 0, 0, 249, 0, 0, 0, 1, 1, 0, 0, 9, 1, + 0, 0, 42, 1, 0, 0, 75, 1, 0, 0, 108, 1, 0, 0, 141, 1, 0, 0, 141, 1, 0, 0, 207, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 53, 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 16, 0, 0, 0, 48, 0, + 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -18291,10 +17604,7 @@ impl FiberMessage { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; pub const ITEMS_COUNT: usize = 26; pub fn item_id(&self) -> molecule::Number { diff --git a/src/fiber/network.rs b/src/fiber/network.rs index d9b41577d..cfc341637 100644 --- a/src/fiber/network.rs +++ b/src/fiber/network.rs @@ -1,9 +1,8 @@ use ckb_hash::blake2b_256; use ckb_jsonrpc_types::{BlockNumber, Status, TxStatus}; use ckb_types::core::{EpochNumberWithFraction, TransactionView}; -use ckb_types::packed::{self, Byte32, CellOutput, OutPoint, Script, Transaction}; +use ckb_types::packed::{Byte32, OutPoint, Script, Transaction}; use ckb_types::prelude::{IntoTransactionView, Pack, Unpack}; -use musig2::CompactSignature; use once_cell::sync::OnceCell; use ractor::concurrency::Duration; use ractor::{ @@ -507,7 +506,7 @@ impl NetworkActorMessage { } } -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum NetworkServiceEvent { NetworkStarted(PeerId, MultiAddr, Vec), NetworkStopped(PeerId), @@ -523,30 +522,18 @@ pub enum NetworkServiceEvent { // and both parties sent ChannelReady messages). ChannelReady(PeerId, Hash256, OutPoint), ChannelClosed(PeerId, Hash256, Byte32), - // We should sign a commitment transaction and send it to the other party. - CommitmentSignaturePending(PeerId, Hash256, u64), - // We have signed a commitment transaction and sent it to the other party. - LocalCommitmentSigned( - PeerId, /* Peer Id */ - Hash256, /* Channel Id */ - u64, /* Commitment number */ - TransactionView, /* Commitment transaction, not valid per se (requires other party's signature) */ - ), // A RevokeAndAck is received from the peer. Other data relevant to this // RevokeAndAck message are also assembled here. The watch tower may use this. RevokeAndAckReceived( - PeerId, /* Peer Id */ - Hash256, /* Channel Id */ - u64, /* Commitment number */ - [u8; 32], /* Aggregated public key x-only */ - CompactSignature, /* Aggregated signature */ - CellOutput, - packed::Bytes, + PeerId, /* Peer Id */ + Hash256, /* Channel Id */ + RevocationData, + SettlementData, ), // The other party has signed a valid commitment transaction, // and we successfully assemble the partial signature from other party - // to create a complete commitment transaction. - RemoteCommitmentSigned(PeerId, Hash256, u64, TransactionView), + // to create a complete commitment transaction and a settlement transaction. + RemoteCommitmentSigned(PeerId, Hash256, TransactionView, SettlementData), // The syncing of network information has completed. SyncingCompleted, } @@ -593,9 +580,6 @@ pub enum NetworkActorEvent { /// A funding transaction has failed. FundingTransactionFailed(OutPoint), - /// A commitment transaction is signed by us and has sent to the other party. - LocalCommitmentSigned(PeerId, Hash256, u64, TransactionView), - /// Channel is going to be closed forcely, and the closing transaction is ready to be broadcasted. CommitmentTransactionPending(Transaction, Hash256), @@ -1250,16 +1234,6 @@ where &channel_id, &tx_hash, &peer_id ); } - NetworkActorEvent::LocalCommitmentSigned(peer_id, channel_id, version, tx) => { - // Notify outside observers. - myself - .send_message(NetworkActorMessage::new_notification( - NetworkServiceEvent::LocalCommitmentSigned( - peer_id, channel_id, version, tx, - ), - )) - .expect("myself alive"); - } NetworkActorEvent::GraphSyncerExited(peer_id, reason) => { debug!( "Graph syncer to peer {:?} has exited with reason {:?}", diff --git a/src/fiber/schema/fiber.mol b/src/fiber/schema/fiber.mol index bb24bb51d..fd63673fc 100644 --- a/src/fiber/schema/fiber.mol +++ b/src/fiber/schema/fiber.mol @@ -22,12 +22,6 @@ table OpenChannel { max_tlc_number_in_flight: Uint64, commitment_delay_epoch: Uint64, funding_pubkey: Pubkey, - // deprecated - revocation_basepoint: Pubkey, - // deprecated - payment_basepoint: Pubkey, - // deprecated - delayed_payment_basepoint: Pubkey, tlc_basepoint: Pubkey, first_per_commitment_point: Pubkey, second_per_commitment_point: Pubkey, @@ -43,15 +37,7 @@ table AcceptChannel { reserved_ckb_amount: Uint64, max_tlc_value_in_flight: Uint128, max_tlc_number_in_flight: Uint64, - // deprecated - commitment_delay_epoch: Uint64, funding_pubkey: Pubkey, - // deprecated - revocation_basepoint: Pubkey, - // deprecated - payment_basepoint: Pubkey, - // deprecated - delayed_payment_basepoint: Pubkey, tlc_basepoint: Pubkey, first_per_commitment_point: Pubkey, second_per_commitment_point: Pubkey, @@ -59,7 +45,7 @@ table AcceptChannel { next_local_nonce: PubNonce, } -table CommitmentSigned { +struct CommitmentSigned { channel_id: Byte32, funding_tx_partial_signature: Byte32, commitment_tx_partial_signature: Byte32, @@ -72,7 +58,7 @@ table TxSignatures { witnesses: BytesVec, } -table ChannelReady { +struct ChannelReady { channel_id: Byte32, } @@ -81,7 +67,7 @@ table TxUpdate { tx: Transaction, } -table TxComplete { +struct TxComplete { channel_id: Byte32, } @@ -105,8 +91,8 @@ table Shutdown { close_script: Script, } -table ClosingSigned { - channel_id: Byte32, +struct ClosingSigned { + channel_id: Byte32, partial_signature: Byte32, } @@ -122,10 +108,11 @@ table AddTlc { onion_packet: Bytes, } -table RevokeAndAck { - channel_id: Byte32, - partial_signature: Byte32, - next_per_commitment_point: Pubkey, +struct RevokeAndAck { + channel_id: Byte32, + revocation_partial_signature: Byte32, + commitment_tx_partial_signature: Byte32, + next_per_commitment_point: Pubkey, } struct RemoveTlcFulfill { diff --git a/src/fiber/tests/channel.rs b/src/fiber/tests/channel.rs index ddc0f8b8d..2d3ec1aa5 100644 --- a/src/fiber/tests/channel.rs +++ b/src/fiber/tests/channel.rs @@ -2011,10 +2011,10 @@ async fn do_test_channel_commitment_tx_after_add_tlc(algorithm: HashAlgorithm) { // to be received by node b. let node_b_commitment_tx = node_b .expect_to_process_event(|event| match event { - NetworkServiceEvent::RemoteCommitmentSigned(peer_id, channel_id, num, tx) => { + NetworkServiceEvent::RemoteCommitmentSigned(peer_id, channel_id, tx, _) => { println!( - "Commitment tx (#{}) {:?} from {:?} for channel {:?} received", - num, &tx, peer_id, channel_id + "Commitment tx {:?} from {:?} for channel {:?} received", + &tx, peer_id, channel_id ); assert_eq!(peer_id, &node_a.peer_id); assert_eq!(channel_id, &new_channel_id); @@ -2048,10 +2048,10 @@ async fn do_test_channel_commitment_tx_after_add_tlc(algorithm: HashAlgorithm) { // to be received by node a. let node_a_commitment_tx = node_a .expect_to_process_event(|event| match event { - NetworkServiceEvent::RemoteCommitmentSigned(peer_id, channel_id, num, tx) => { + NetworkServiceEvent::RemoteCommitmentSigned(peer_id, channel_id, tx, _) => { println!( - "Commitment tx (#{}) {:?} from {:?} for channel {:?} received", - num, &tx, peer_id, channel_id + "Commitment tx {:?} from {:?} for channel {:?} received", + &tx, peer_id, channel_id ); assert_eq!(peer_id, &node_b.peer_id); assert_eq!(channel_id, &new_channel_id); @@ -3473,10 +3473,10 @@ async fn test_revoke_old_commitment_transaction() { let commitment_tx = node_b .expect_to_process_event(|event| match event { - NetworkServiceEvent::RemoteCommitmentSigned(peer_id, channel_id, num, tx) => { + NetworkServiceEvent::RemoteCommitmentSigned(peer_id, channel_id, tx, _) => { println!( - "Commitment tx (#{}) {:?} from {:?} for channel {:?} received", - num, &tx, peer_id, channel_id + "Commitment tx {:?} from {:?} for channel {:?} received", + &tx, peer_id, channel_id ); assert_eq!(peer_id, &node_a.peer_id); assert_eq!(channel_id, &new_channel_id); @@ -3526,26 +3526,18 @@ async fn test_revoke_old_commitment_transaction() { )) .expect("node_a alive"); - let (x_only_aggregated_pubkey, signature, output, output_data) = node_a + let revocation_data = node_a .expect_to_process_event(|event| match event { NetworkServiceEvent::RevokeAndAckReceived( peer_id, channel_id, - commitment_number, - x_only_aggregated_pubkey, - signature, - output, - output_data, + revocation_data, + _settlement_data, ) => { assert_eq!(peer_id, &node_b.peer_id); assert_eq!(channel_id, &new_channel_id); - assert_eq!(*commitment_number, 1u64); - Some(( - x_only_aggregated_pubkey.clone(), - signature.clone(), - output.clone(), - output_data.clone(), - )) + assert_eq!(revocation_data.commitment_number, 0u64); + Some(revocation_data.clone()) } _ => None, }) @@ -3566,17 +3558,17 @@ async fn test_revoke_old_commitment_transaction() { .previous_output(commitment_tx.output_pts().get(0).unwrap().clone()) .build(), ) - .output(output) - .output_data(output_data) + .output(revocation_data.output) + .output_data(revocation_data.output_data) .build(); let empty_witness_args = [16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0]; let witness = [ empty_witness_args.to_vec(), vec![0xFF], - 1u64.to_be_bytes().to_vec(), - x_only_aggregated_pubkey.to_vec(), - signature.serialize().to_vec(), + 0u64.to_be_bytes().to_vec(), + revocation_data.x_only_aggregated_pubkey.to_vec(), + revocation_data.aggregated_signature.serialize().to_vec(), ] .concat(); @@ -3655,10 +3647,10 @@ async fn test_create_channel() { let node_a_commitment_tx = node_a .expect_to_process_event(|event| match event { - NetworkServiceEvent::RemoteCommitmentSigned(peer_id, channel_id, num, tx) => { + NetworkServiceEvent::RemoteCommitmentSigned(peer_id, channel_id, tx, _) => { println!( - "Commitment tx (#{}) {:?} from {:?} for channel {:?} received", - num, &tx, peer_id, channel_id + "Commitment tx {:?} from {:?} for channel {:?} received", + &tx, peer_id, channel_id ); assert_eq!(peer_id, &node_b.peer_id); assert_eq!(channel_id, &new_channel_id); @@ -3670,10 +3662,10 @@ async fn test_create_channel() { let node_b_commitment_tx = node_b .expect_to_process_event(|event| match event { - NetworkServiceEvent::RemoteCommitmentSigned(peer_id, channel_id, num, tx) => { + NetworkServiceEvent::RemoteCommitmentSigned(peer_id, channel_id, tx, _) => { println!( - "Commitment tx (#{}) {:?} from {:?} for channel {:?} received", - num, &tx, peer_id, channel_id + "Commitment tx {:?} from {:?} for channel {:?} received", + &tx, peer_id, channel_id ); assert_eq!(peer_id, &node_a.peer_id); assert_eq!(channel_id, &new_channel_id); diff --git a/src/fiber/types.rs b/src/fiber/types.rs index 74cdd0f9a..1e0f15836 100644 --- a/src/fiber/types.rs +++ b/src/fiber/types.rs @@ -716,17 +716,7 @@ pub struct CommitmentSigned { } fn partial_signature_to_molecule(partial_signature: PartialSignature) -> MByte32 { - MByte32::new_builder() - .set( - partial_signature - .serialize() - .into_iter() - .map(Byte::new) - .collect::>() - .try_into() - .expect("[Byte; 32] from [u8; 32]"), - ) - .build() + MByte32::from_slice(partial_signature.serialize().as_ref()).expect("[Byte; 32] from [u8; 32]") } impl From for molecule_fiber::CommitmentSigned { @@ -1080,7 +1070,8 @@ impl TryFrom for AddTlc { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RevokeAndAck { pub channel_id: Hash256, - pub partial_signature: PartialSignature, + pub revocation_partial_signature: PartialSignature, + pub commitment_tx_partial_signature: PartialSignature, pub next_per_commitment_point: Pubkey, } @@ -1088,8 +1079,11 @@ impl From for molecule_fiber::RevokeAndAck { fn from(revoke_and_ack: RevokeAndAck) -> Self { molecule_fiber::RevokeAndAck::new_builder() .channel_id(revoke_and_ack.channel_id.into()) - .partial_signature(partial_signature_to_molecule( - revoke_and_ack.partial_signature, + .revocation_partial_signature(partial_signature_to_molecule( + revoke_and_ack.revocation_partial_signature, + )) + .commitment_tx_partial_signature(partial_signature_to_molecule( + revoke_and_ack.commitment_tx_partial_signature, )) .next_per_commitment_point(revoke_and_ack.next_per_commitment_point.into()) .build() @@ -1102,8 +1096,12 @@ impl TryFrom for RevokeAndAck { fn try_from(revoke_and_ack: molecule_fiber::RevokeAndAck) -> Result { Ok(RevokeAndAck { channel_id: revoke_and_ack.channel_id().into(), - partial_signature: PartialSignature::from_slice( - revoke_and_ack.partial_signature().as_slice(), + revocation_partial_signature: PartialSignature::from_slice( + revoke_and_ack.revocation_partial_signature().as_slice(), + ) + .map_err(|e| anyhow!(e))?, + commitment_tx_partial_signature: PartialSignature::from_slice( + revoke_and_ack.commitment_tx_partial_signature().as_slice(), ) .map_err(|e| anyhow!(e))?, next_per_commitment_point: revoke_and_ack.next_per_commitment_point().try_into()?, diff --git a/src/main.rs b/src/main.rs index fb96dbdce..d7be66dc1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,10 +13,16 @@ use fnn::store::Store; use fnn::tasks::{ cancel_tasks_and_wait_for_completion, new_tokio_cancellation_token, new_tokio_task_tracker, }; -use fnn::watchtower::{WatchtowerActor, WatchtowerMessage}; +use fnn::watchtower::{ + WatchtowerActor, WatchtowerMessage, DEFAULT_WATCHTOWER_CHECK_INTERVAL_SECONDS, +}; +#[cfg(debug_assertions)] +use fnn::NetworkServiceEvent; use fnn::{start_cch, start_network, start_rpc, Config}; use ractor::Actor; use secp256k1::Secp256k1; +#[cfg(debug_assertions)] +use std::collections::HashMap; use std::fmt::Debug; use std::path::Path; use std::sync::Arc; @@ -76,7 +82,16 @@ pub async fn main() -> Result<(), ExitMessage> { let root_actor = RootActor::start(tracker, token).await; let subscribers = ChannelSubscribers::default(); - let (fiber_command_sender, network_graph) = match config.fiber.clone() { + #[cfg(debug_assertions)] + let rpc_dev_module_commitment_txs = config.rpc.as_ref().and_then(|rpc_config| { + if rpc_config.is_module_enabled("dev") { + Some(Arc::new(RwLock::new(HashMap::new()))) + } else { + None + } + }); + + let (network_actor, ckb_chain_actor, network_graph) = match config.fiber.clone() { Some(fiber_config) => { // TODO: this is not a super user friendly error message which has actionable information // for the user to fix the error and start the node. @@ -107,7 +122,7 @@ pub async fn main() -> Result<(), ExitMessage> { ) .map_err(|err| ExitMessage(format!("failed to init contracts context: {}", err)))?; - let ckb_actor = Actor::spawn_linked( + let ckb_chain_actor = Actor::spawn_linked( Some("ckb".to_string()), CkbChainActor {}, ckb_config.clone(), @@ -138,8 +153,8 @@ pub async fn main() -> Result<(), ExitMessage> { info!("Starting fiber"); let network_actor = start_network( - fiber_config, - ckb_actor, + fiber_config.clone(), + ckb_chain_actor.clone(), event_sender, new_tokio_task_tracker(), root_actor.get_cell(), @@ -160,11 +175,17 @@ pub async fn main() -> Result<(), ExitMessage> { .map_err(|err| ExitMessage(format!("failed to start watchtower actor: {}", err)))? .0; - // every 60 seconds, check if there are any channels that submitted a commitment transaction - // TODO: move interval to config file - watchtower_actor - .send_interval(Duration::from_secs(60), || WatchtowerMessage::PeriodicCheck); + watchtower_actor.send_interval( + Duration::from_secs( + fiber_config + .watchtower_check_interval_seconds + .unwrap_or(DEFAULT_WATCHTOWER_CHECK_INTERVAL_SECONDS), + ), + || WatchtowerMessage::PeriodicCheck, + ); + #[cfg(debug_assertions)] + let rpc_dev_module_commitment_txs_clone = rpc_dev_module_commitment_txs.clone(); new_tokio_task_tracker().spawn(async move { let token = new_tokio_cancellation_token(); loop { @@ -176,6 +197,17 @@ pub async fn main() -> Result<(), ExitMessage> { break; } Some(event) => { + // we may forward more events to the rpc dev module in the future for integration testing + // for now, we only forward RemoteCommitmentSigned events, which are used for submitting outdated commitment transactions + #[cfg(debug_assertions)] + if let Some(rpc_dev_module_commitment_txs) = rpc_dev_module_commitment_txs_clone.as_ref() { + if let NetworkServiceEvent::RemoteCommitmentSigned(_, channel_id, commitment_tx, _) = event.clone() { + let lock_args = commitment_tx.outputs().get(0).unwrap().lock().args().raw_data(); + let version = u64::from_be_bytes(lock_args[28..36].try_into().unwrap()); + rpc_dev_module_commitment_txs.write().await.insert((channel_id, version), commitment_tx); + } + } + // forward the event to the watchtower actor let _ = watchtower_actor.send_message(WatchtowerMessage::NetworkServiceEvent(event)); } } @@ -189,9 +221,13 @@ pub async fn main() -> Result<(), ExitMessage> { debug!("Event processing service exited"); }); - (Some(network_actor), Some(network_graph)) + ( + Some(network_actor), + Some(ckb_chain_actor), + Some(network_graph), + ) } - None => (None, None), + None => (None, None, None), }; let cch_actor = match config.cch { @@ -203,7 +239,7 @@ pub async fn main() -> Result<(), ExitMessage> { new_tokio_task_tracker(), new_tokio_cancellation_token(), root_actor.get_cell(), - fiber_command_sender.clone(), + network_actor.clone(), ) .await { @@ -245,10 +281,12 @@ pub async fn main() -> Result<(), ExitMessage> { let handle = start_rpc( rpc_config, config.fiber, - fiber_command_sender, + network_actor, cch_actor, store, - network_graph + network_graph, + #[cfg(debug_assertions)] ckb_chain_actor, + #[cfg(debug_assertions)] rpc_dev_module_commitment_txs, ) .await; Some(handle) diff --git a/src/rpc/README.md b/src/rpc/README.md index 52b194a67..d31f46b8b 100644 --- a/src/rpc/README.md +++ b/src/rpc/README.md @@ -27,6 +27,8 @@ You may refer to the e2e test cases in the `tests/bruno/e2e` directory for examp * [Method `update_channel`](#channel-update_channel) * [Method `send_payment`](#channel-send_payment) * [Method `get_payment`](#channel-get_payment) + * [Module Dev](#module-dev) + * [Method `submit_commitment_transaction`](#dev-submit_commitment_transaction) * [Module Graph](#module-graph) * [Method `graph_nodes`](#graph-graph_nodes) * [Method `graph_channels`](#graph-graph_channels) @@ -353,6 +355,27 @@ Retrieves a payment. * `fee` - u128, fee paid for the payment + +### Module `Dev` +RPC module for development purposes, this module is not intended to be used in production. + This module will be disabled in release build. + + + +#### Method `submit_commitment_transaction` + +Submit a commitment transaction to the chain + +##### Params + +* `channel_id` - Hash256, Channel ID +* `commitment_number` - u64, Commitment number + +##### Returns + +* `tx_hash` - Hash256, Submitted commitment transaction hash + + ### Module `Graph` RPC module for graph management. @@ -576,6 +599,7 @@ The channel data structure * `offered_tlc_balance` - u128, The offered balance of the channel * `remote_balance` - u128, The remote balance of the channel * `received_tlc_balance` - u128, The received balance of the channel +* `latest_commitment_transaction_hash` - `Option`, The hash of the latest commitment transaction * `created_at` - u64, The time the channel was created at, in milliseconds from UNIX epoch diff --git a/src/rpc/channel.rs b/src/rpc/channel.rs index 54cadfc58..35e3bdef6 100644 --- a/src/rpc/channel.rs +++ b/src/rpc/channel.rs @@ -20,6 +20,8 @@ use ckb_jsonrpc_types::{EpochNumberWithFraction, Script}; use ckb_types::{ core::{EpochNumberWithFraction as EpochNumberWithFractionCore, FeeRate}, packed::OutPoint, + prelude::{IntoTransactionView, Unpack}, + H256, }; use jsonrpsee::{ core::async_trait, @@ -248,6 +250,8 @@ pub(crate) struct Channel { /// The received balance of the channel #[serde_as(as = "U128Hex")] received_tlc_balance: u128, + /// The hash of the latest commitment transaction + latest_commitment_transaction_hash: Option, /// The time the channel was created at, in milliseconds from UNIX epoch #[serde_as(as = "U64Hex")] created_at: u64, @@ -576,6 +580,10 @@ where remote_balance: state.get_remote_balance(), offered_tlc_balance: state.get_offered_tlc_balance(), received_tlc_balance: state.get_received_tlc_balance(), + latest_commitment_transaction_hash: state + .latest_commitment_transaction + .as_ref() + .map(|tx| tx.clone().into_view().hash().unpack()), created_at: state.get_created_at_in_millis(), }) }) diff --git a/src/rpc/config.rs b/src/rpc/config.rs index 81bf020b5..aea3391ec 100644 --- a/src/rpc/config.rs +++ b/src/rpc/config.rs @@ -1,9 +1,21 @@ use clap_serde_derive::ClapSerde; +const DEFAULT_ENABLED_MODULES: &str = "cch,channel,graph,info,invoice,peer"; + #[derive(ClapSerde, Debug, Clone)] pub struct RpcConfig { // Don't use default_value here. Otherwise the default value will override config from file /// listening port for rpc service #[arg(name = "RPC_LISTENING_ADDR", long = "rpc-listening-addr", env)] pub listening_addr: Option, + + #[default(DEFAULT_ENABLED_MODULES.split(',').map(ToString::to_string).collect())] + #[arg(name = "RPC_ENABLED_MODULES", long = "rpc-enabled-modules", env, value_parser, num_args = 0.., value_delimiter = ',')] + pub enabled_modules: Vec, +} + +impl RpcConfig { + pub fn is_module_enabled(&self, module: &str) -> bool { + self.enabled_modules.iter().any(|m| m == module) + } } diff --git a/src/rpc/dev.rs b/src/rpc/dev.rs new file mode 100644 index 000000000..be9133b5b --- /dev/null +++ b/src/rpc/dev.rs @@ -0,0 +1,105 @@ +use std::{collections::HashMap, sync::Arc}; + +use ckb_types::core::TransactionView; +use jsonrpsee::{ + core::async_trait, + proc_macros::rpc, + types::{error::CALL_EXECUTION_FAILED_CODE, ErrorObjectOwned}, +}; + +use ractor::{call_t, ActorRef}; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; +use tokio::sync::RwLock; + +use crate::{ + ckb::CkbChainMessage, + fiber::{network::DEFAULT_CHAIN_ACTOR_TIMEOUT, serde_utils::U64Hex, types::Hash256}, +}; + +#[serde_as] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub(crate) struct SubmitCommitmentTransactionParams { + /// Channel ID + channel_id: Hash256, + /// Commitment number + #[serde_as(as = "U64Hex")] + commitment_number: u64, +} + +#[serde_as] +#[derive(Serialize, Deserialize, Debug, Clone)] + +pub(crate) struct SubmitCommitmentTransactionResult { + /// Submitted commitment transaction hash + tx_hash: Hash256, +} + +/// RPC module for development purposes, this module is not intended to be used in production. +/// This module will be disabled in release build. +#[rpc(server)] +trait DevRpc { + /// Submit a commitment transaction to the chain + #[method(name = "submit_commitment_transaction")] + async fn submit_commitment_transaction( + &self, + params: SubmitCommitmentTransactionParams, + ) -> Result; +} + +pub(crate) struct DevRpcServerImpl { + ckb_chain_actor: ActorRef, + commitment_txs: Arc>>, +} + +impl DevRpcServerImpl { + pub(crate) fn new( + ckb_chain_actor: ActorRef, + commitment_txs: Arc>>, + ) -> Self { + Self { + ckb_chain_actor, + commitment_txs, + } + } +} + +#[async_trait] +impl DevRpcServer for DevRpcServerImpl { + async fn submit_commitment_transaction( + &self, + params: SubmitCommitmentTransactionParams, + ) -> Result { + if let Some(tx) = self + .commitment_txs + .read() + .await + .get(&(params.channel_id, params.commitment_number)) + { + if let Err(err) = call_t!( + &self.ckb_chain_actor, + CkbChainMessage::SendTx, + DEFAULT_CHAIN_ACTOR_TIMEOUT, + tx.clone() + ) + .unwrap() + { + Err(ErrorObjectOwned::owned( + CALL_EXECUTION_FAILED_CODE, + err.to_string(), + Some(params), + )) + } else { + Ok(SubmitCommitmentTransactionResult { + tx_hash: tx.hash().into(), + }) + } + } else { + Err(ErrorObjectOwned::owned( + CALL_EXECUTION_FAILED_CODE, + "Commitment transaction not found".to_string(), + Some(params), + )) + } + } +} diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index 99aff8fd3..aad9aa495 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -1,13 +1,13 @@ mod cch; mod channel; mod config; +#[cfg(debug_assertions)] +mod dev; mod graph; mod info; mod invoice; mod peer; mod utils; - -use crate::rpc::info::InfoRpcServer; use crate::{ cch::CchMessage, fiber::{ @@ -15,25 +15,33 @@ use crate::{ graph::{NetworkGraph, NetworkGraphStateStore}, NetworkActorMessage, }, - invoice::{InvoiceCommand, InvoiceStore}, + invoice::InvoiceStore, FiberConfig, }; +#[cfg(debug_assertions)] +use crate::{ckb::CkbChainMessage, fiber::types::Hash256}; use cch::{CchRpcServer, CchRpcServerImpl}; use channel::{ChannelRpcServer, ChannelRpcServerImpl}; +#[cfg(debug_assertions)] +use ckb_types::core::TransactionView; pub use config::RpcConfig; +#[cfg(debug_assertions)] +use dev::{DevRpcServer, DevRpcServerImpl}; use graph::{GraphRpcServer, GraphRpcServerImpl}; +use info::InfoRpcServer; use info::InfoRpcServerImpl; use invoice::{InvoiceRpcServer, InvoiceRpcServerImpl}; use jsonrpsee::server::{Server, ServerHandle}; +use jsonrpsee::RpcModule; use peer::{PeerRpcServer, PeerRpcServerImpl}; use ractor::ActorRef; +#[cfg(debug_assertions)] +use std::collections::HashMap; use std::sync::Arc; -use tokio::sync::{mpsc::Sender, RwLock}; - -pub type InvoiceCommandWithReply = (InvoiceCommand, Sender>); +use tokio::sync::RwLock; -fn build_server(addr: &str) -> Server { - #[cfg(not(release))] +async fn build_server(addr: &str) -> Server { + #[cfg(debug_assertions)] { // Use socket2 to set reuse address and reuse port, // so that we can restart the server without waiting for the port to be released. @@ -56,7 +64,7 @@ fn build_server(addr: &str) -> Server { .build_from_tcp(socket) .expect("JsonRPC server built from TCP") } - #[cfg(release)] + #[cfg(not(debug_assertions))] { Server::builder() .build(addr) @@ -74,25 +82,63 @@ pub async fn start_rpc< cch_actor: Option>, store: S, network_graph: Arc>>, + #[cfg(debug_assertions)] ckb_chain_actor: Option>, + #[cfg(debug_assertions)] rpc_dev_module_commitment_txs: Option< + Arc>>, + >, ) -> ServerHandle { let listening_addr = config.listening_addr.as_deref().unwrap_or("[::]:0"); - let server = build_server(listening_addr); - let mut methods = InvoiceRpcServerImpl::new(store.clone(), fiber_config).into_rpc(); + let server = build_server(listening_addr).await; + let mut modules = RpcModule::new(()); + if config.is_module_enabled("invoice") { + modules + .merge(InvoiceRpcServerImpl::new(store.clone(), fiber_config).into_rpc()) + .unwrap(); + } + if config.is_module_enabled("graph") { + modules + .merge(GraphRpcServerImpl::new(network_graph, store.clone()).into_rpc()) + .unwrap(); + } if let Some(network_actor) = network_actor { - let info = InfoRpcServerImpl::new(network_actor.clone(), store.clone()); - let peer = PeerRpcServerImpl::new(network_actor.clone()); - let channel = ChannelRpcServerImpl::new(network_actor, store.clone()); - let network_graph = GraphRpcServerImpl::new(network_graph, store.clone()); - methods.merge(info.into_rpc()).expect("add info RPC"); - methods.merge(peer.into_rpc()).expect("add peer RPC"); - methods.merge(channel.into_rpc()).expect("add channel RPC"); - methods - .merge(network_graph.into_rpc()) - .expect("add network graph RPC"); + if config.is_module_enabled("info") { + modules + .merge(InfoRpcServerImpl::new(network_actor.clone(), store.clone()).into_rpc()) + .unwrap(); + } + + if config.is_module_enabled("peer") { + modules + .merge(PeerRpcServerImpl::new(network_actor.clone()).into_rpc()) + .unwrap(); + } + + if config.is_module_enabled("channel") { + modules + .merge(ChannelRpcServerImpl::new(network_actor.clone(), store.clone()).into_rpc()) + .unwrap(); + } + + #[cfg(debug_assertions)] + if config.is_module_enabled("dev") { + modules + .merge( + DevRpcServerImpl::new( + ckb_chain_actor.expect("ckb_chain_actor should be set"), + rpc_dev_module_commitment_txs + .expect("rpc_dev_module_commitment_txs should be set"), + ) + .into_rpc(), + ) + .unwrap(); + } } if let Some(cch_actor) = cch_actor { - let cch = CchRpcServerImpl::new(cch_actor); - methods.merge(cch.into_rpc()).expect("add cch RPC"); + if config.is_module_enabled("cch") { + modules + .merge(CchRpcServerImpl::new(cch_actor).into_rpc()) + .unwrap(); + } } - server.start(methods) + server.start(modules) } diff --git a/src/store/store.rs b/src/store/store.rs index b0030f7cd..51563468d 100644 --- a/src/store/store.rs +++ b/src/store/store.rs @@ -2,14 +2,16 @@ use super::db_migrate::DbMigrate; use super::schema::*; use crate::{ fiber::{ - channel::{ChannelActorState, ChannelActorStateStore, ChannelState}, + channel::{ + ChannelActorState, ChannelActorStateStore, ChannelState, RevocationData, SettlementData, + }, graph::{ChannelInfo, NetworkGraphStateStore, NodeInfo, PaymentSession}, history::{Direction, TimedResult}, network::{NetworkActorStateStore, PersistentNetworkActorState}, types::{Hash256, Pubkey}, }, invoice::{CkbInvoice, CkbInvoiceStatus, InvoiceError, InvoiceStore}, - watchtower::{ChannelData, RevocationData, WatchtowerStore}, + watchtower::{ChannelData, WatchtowerStore}, }; use ckb_jsonrpc_types::JsonBytes; use ckb_types::packed::{OutPoint, Script}; @@ -624,6 +626,7 @@ impl WatchtowerStore for Store { channel_id, funding_tx_lock, revocation_data: None, + settlement_data: None, }, "ChannelData", ); @@ -649,4 +652,17 @@ impl WatchtowerStore for Store { batch.commit(); } } + + fn update_settlement(&self, channel_id: Hash256, settlement_data: SettlementData) { + let key = [&[WATCHTOWER_CHANNEL_PREFIX], channel_id.as_ref()].concat(); + if let Some(mut channel_data) = self + .get(key) + .map(|v| deserialize_from::(v.as_ref(), "ChannelData")) + { + channel_data.settlement_data = Some(settlement_data); + let mut batch = self.batch(); + batch.put_kv(KeyValue::WatchtowerChannel(channel_id, channel_data)); + batch.commit(); + } + } } diff --git a/src/store/tests/store.rs b/src/store/tests/store.rs index 6164fb7bd..4992f93fe 100644 --- a/src/store/tests/store.rs +++ b/src/store/tests/store.rs @@ -193,7 +193,8 @@ fn test_store_wacthtower() { vec![ChannelData { channel_id, funding_tx_lock: funding_tx_lock.clone(), - revocation_data: None + revocation_data: None, + settlement_data: None }] ); @@ -211,7 +212,8 @@ fn test_store_wacthtower() { vec![ChannelData { channel_id, funding_tx_lock, - revocation_data: Some(revocation_data) + revocation_data: Some(revocation_data), + settlement_data: None }] ); diff --git a/src/watchtower/actor.rs b/src/watchtower/actor.rs index 261ff9224..89ff0356d 100644 --- a/src/watchtower/actor.rs +++ b/src/watchtower/actor.rs @@ -24,10 +24,13 @@ use crate::{ contracts::{get_cell_deps, get_script_by_contract, Contract}, CkbConfig, }, + fiber::channel::{create_witness_for_commitment_cell, RevocationData, SettlementData}, NetworkServiceEvent, }; -use super::{store::RevocationData, WatchtowerStore}; +use super::WatchtowerStore; + +pub const DEFAULT_WATCHTOWER_CHECK_INTERVAL_SECONDS: u64 = 60; pub struct WatchtowerActor { store: S, @@ -125,153 +128,247 @@ where NetworkServiceEvent::RevokeAndAckReceived( _peer_id, channel_id, - commitment_number, - aggregated_pubkey, - signature, - output, - output_data, + revocation_data, + _settlement_data, ) => { - self.store.update_revocation( - channel_id, - RevocationData { - commitment_number, - x_only_aggregated_pubkey: aggregated_pubkey, - aggregated_signature: signature, - output, - output_data, - }, - ); + self.store.update_revocation(channel_id, revocation_data); + } + NetworkServiceEvent::RemoteCommitmentSigned( + _peer_id, + channel_id, + _commitment_tx, + settlement_data, + ) => { + self.store.update_settlement(channel_id, settlement_data); } _ => { // ignore } } } - WatchtowerMessage::PeriodicCheck => { - for channel_data in self.store.get_watch_channels() { - if channel_data.revocation_data.is_none() { - continue; - } - let revocation_data = channel_data - .revocation_data - .expect("get channel revocation data"); - let secret_key = state.secret_key; - let rpc_url = state.config.rpc_url.clone(); - tokio::task::block_in_place(move || { - let ckb_client = CkbRpcClient::new(&rpc_url); - let mut cell_collector = DefaultCellCollector::new(&rpc_url); - let search_key = SearchKey { - script: channel_data.funding_tx_lock.clone().into(), - script_type: ScriptType::Lock, - script_search_mode: Some(SearchMode::Exact), - with_data: None, - filter: None, - group_by_transaction: None, - }; - // we need two parties' signatures to unlock the funding tx, so we can check the last one transaction only to see if it's an old version commitment tx - match ckb_client.get_transactions( - search_key, - Order::Desc, - 1u32.into(), - None, - ) { - Ok(txs) => { - if let Some(Tx::Ungrouped(tx)) = txs.objects.first() { - if matches!(tx.io_type, CellType::Input) { - match ckb_client.get_transaction(tx.tx_hash.clone()) { - Ok(Some(tx_with_status)) => { - if tx_with_status.tx_status.status - != Status::Committed - { - error!("Cannot find the commitment tx: {:?}, status is {:?}, maybe ckb indexer bug?", tx_with_status.tx_status.status, tx.tx_hash); - } else if let Some(tx) = tx_with_status.transaction - { - match tx.inner { - Either::Left(tx) => { - let tx: Transaction = tx.inner.into(); - if tx.raw().outputs().len() == 1 { - let output = tx - .raw() - .outputs() - .get(0) - .expect("get output 0 of tx"); - let lock_args = - output.lock().args().raw_data(); - let commitment_number = - u64::from_le_bytes( - lock_args[28..36] - .try_into() - .expect( - "u64 from slice", - ), + WatchtowerMessage::PeriodicCheck => self.periodic_check(state), + } + Ok(()) + } +} + +impl WatchtowerActor +where + S: WatchtowerStore, +{ + fn periodic_check(&self, state: &WatchtowerState) { + for channel_data in self.store.get_watch_channels() { + if channel_data.revocation_data.is_none() { + continue; + } + let revocation_data = channel_data + .revocation_data + .expect("get channel revocation data"); + let secret_key = state.secret_key; + let rpc_url = state.config.rpc_url.clone(); + tokio::task::block_in_place(move || { + let ckb_client = CkbRpcClient::new(&rpc_url); + let mut cell_collector = DefaultCellCollector::new(&rpc_url); + let search_key = SearchKey { + script: channel_data.funding_tx_lock.clone().into(), + script_type: ScriptType::Lock, + script_search_mode: Some(SearchMode::Exact), + with_data: None, + filter: None, + group_by_transaction: None, + }; + // we need two parties' signatures to unlock the funding tx, so we can check the last one transaction only to see if it's an old version commitment tx + match ckb_client.get_transactions(search_key, Order::Desc, 1u32.into(), None) { + Ok(txs) => { + if let Some(Tx::Ungrouped(tx)) = txs.objects.first() { + if matches!(tx.io_type, CellType::Input) { + match ckb_client.get_transaction(tx.tx_hash.clone()) { + Ok(Some(tx_with_status)) => { + if tx_with_status.tx_status.status != Status::Committed { + error!("Cannot find the commitment tx: {:?}, status is {:?}, maybe ckb indexer bug?", tx_with_status.tx_status.status, tx.tx_hash); + } else if let Some(tx) = tx_with_status.transaction { + match tx.inner { + Either::Left(tx) => { + let tx: Transaction = tx.inner.into(); + if tx.raw().outputs().len() == 1 { + let output = tx + .raw() + .outputs() + .get(0) + .expect("get output 0 of tx"); + let commitment_lock = output.lock(); + let lock_args = + commitment_lock.args().raw_data(); + let pub_key_hash: [u8; 20] = lock_args + [0..20] + .try_into() + .expect("checked length"); + let commitment_number = u64::from_be_bytes( + lock_args[28..36] + .try_into() + .expect("u64 from slice"), + ); + + if blake160( + &revocation_data + .x_only_aggregated_pubkey, + ) + .0 == pub_key_hash + { + if revocation_data.commitment_number + >= commitment_number + { + warn!("Found an old version commitment tx submitted by remote: {:?}, revocation commitment number: {}, commitment number: {}", tx.calc_tx_hash(), revocation_data.commitment_number, commitment_number); + let commitment_tx_out_point = + OutPoint::new( + tx.calc_tx_hash(), + 0, ); - if revocation_data.commitment_number - >= commitment_number - { - warn!("Found an old version commitment tx: {:?}, revocation commitment number: {}, commitment number: {}", tx.calc_tx_hash(), revocation_data.commitment_number, commitment_number); - let commitment_tx_out_point = - OutPoint::new( - tx.calc_tx_hash(), - 0, - ); - match build_revocation_tx( - commitment_tx_out_point, - revocation_data, - secret_key, - &mut cell_collector, - ) { - Ok(tx) => { - match ckb_client - .send_transaction( - tx.data() - .into(), - None, - ) { - Ok(tx_hash) => { - info!("Revocation tx: {:?} sent, tx_hash: {:?}", tx, tx_hash); + match build_revocation_tx( + commitment_tx_out_point, + revocation_data, + secret_key, + &mut cell_collector, + ) { + Ok(tx) => { + match ckb_client + .send_transaction( + tx.data().into(), + None, + ) { + Ok(tx_hash) => { + info!("Revocation tx: {:?} sent, tx_hash: {:?}", tx, tx_hash); + } + Err(err) => { + error!("Failed to send revocation tx: {:?}, error: {:?}", tx, err); + } + } + } + Err(err) => { + error!("Failed to build revocation tx: {:?}", err); + } + } + } else { + info!("Found a force closed commitment tx submitted by remote: {:?}, revocation commitment number: {}, commitment number: {}", tx.calc_tx_hash(), revocation_data.commitment_number, commitment_number); + } + } else { + // it's a force closed commitment tx which is submitted by local + info!("Found a force closed commitment tx submitted by local: {:?}, revocation commitment number: {}, commitment number: {}", tx.calc_tx_hash(), revocation_data.commitment_number, commitment_number); + let script = commitment_lock + .as_builder() + .args( + lock_args[0..36] + .to_vec() + .pack(), + ) + .build(); + let search_key = SearchKey { + script: script.into(), + script_type: ScriptType::Lock, + script_search_mode: Some( + SearchMode::Prefix, + ), + with_data: None, + filter: None, + group_by_transaction: None, + }; + + // the live cells number should be 1 or 0 for normal case, however, an attacker may create a lot of cells to implement a tx pinning attack. + match ckb_client.get_cells( + search_key, + Order::Desc, + 100u32.into(), + None, + ) { + Ok(cells) => { + for cell in cells.objects { + let cell_output: CellOutput = cell.output.into(); + let commitment_tx_out_point = + OutPoint::new( + cell.out_point + .tx_hash + .pack(), + cell.out_point + .index + .value(), + ); + let lock_script_args = + cell_output + .lock() + .args() + .raw_data(); + if lock_script_args.len() + == 36 + { + let since = u64::from_le_bytes(cell_output.lock().args().raw_data()[20..28].try_into().expect("u64 from slice")); + // TODO check since + match build_settlement_tx( + commitment_tx_out_point, + since, + channel_data.settlement_data.clone().expect("settlement data should be some"), + secret_key, + &mut cell_collector, + ) { + Ok(tx) => { + match ckb_client + .send_transaction( + tx.data().into(), + None, + ) { + Ok(tx_hash) => { + info!("Settlement tx: {:?} sent, tx_hash: {:?}", tx, tx_hash); + } + Err(err) => { + error!("Failed to send settlement tx: {:?}, error: {:?}", tx, err); + } + } } Err(err) => { - error!("Failed to send revocation tx: {:?}, error: {:?}", tx, err); + error!("Failed to build settlement tx: {:?}", err); } } - } - Err(err) => { - error!("Failed to build revocation tx: {:?}", err); + } else { + // TODO use 0x00 ~ 0xFD to get back the funds } } } - } else { - // there may be a race condition that PeriodicCheck is triggered before the remove_channel fn is called - // it's a close channel tx, ignore + Err(err) => { + error!( + "Failed to get cells: {:?}", + err + ); + } } } - Either::Right(_tx) => { - // unreachable, ignore - } + } else { + // there may be a race condition that PeriodicCheck is triggered before the remove_channel fn is called + // it's a close channel tx, ignore } - } else { - error!("Cannot find the commitment tx: {:?}, transcation is none, maybe ckb indexer bug?", tx.tx_hash); + } + Either::Right(_tx) => { + // unreachable, ignore } } - Ok(None) => { - error!("Cannot find the commitment tx: {:?}, maybe ckb indexer bug?", tx.tx_hash); - } - Err(err) => { - error!("Failed to get funding tx: {:?}", err); - } + } else { + error!("Cannot find the commitment tx: {:?}, transcation is none, maybe ckb indexer bug?", tx.tx_hash); } } + Ok(None) => { + error!("Cannot find the commitment tx: {:?}, maybe ckb indexer bug?", tx.tx_hash); + } + Err(err) => { + error!("Failed to get funding tx: {:?}", err); + } } } - Err(err) => { - error!("Failed to get transactions: {:?}", err); - } } - }); + } + Err(err) => { + error!("Failed to get transactions: {:?}", err); + } } - } + }); } - Ok(()) } } @@ -353,7 +450,97 @@ fn build_revocation_tx( .set_outputs(vec![revocation_data.output, new_change_output]) .build(); - let tx = sign_revocation_tx(tx, secret_key)?; + let tx = sign_tx(tx, secret_key)?; + return Ok(tx); + } + } + + Err(Box::new(RpcError::Other(anyhow!("Not enough capacity")))) +} + +fn build_settlement_tx( + commitment_tx_out_point: OutPoint, + since: u64, + settlement_data: SettlementData, + secret_key: SecretKey, + cell_collector: &mut DefaultCellCollector, +) -> Result> { + let pubkey = PublicKey::from_secret_key(&Secp256k1::new(), &secret_key); + let args = blake160(pubkey.serialize().as_ref()); + let fee_provider_lock_script = get_script_by_contract(Contract::Secp256k1Lock, args.as_bytes()); + + let change_output = CellOutput::new_builder() + .lock(fee_provider_lock_script.clone()) + .build(); + let change_output_occupied_capacity = change_output + .occupied_capacity(Capacity::shannons(0)) + .expect("capacity does not overflow") + .as_u64(); + let placeholder_witness = WitnessArgs::new_builder() + .lock(Some(ckb_types::bytes::Bytes::from(vec![0u8; 65])).pack()) + .build(); + + let SettlementData { + x_only_aggregated_pubkey, + aggregated_signature, + to_local_output, + to_local_output_data, + to_remote_output, + to_remote_output_data, + } = settlement_data; + + let mut tx_builder = Transaction::default() + .as_advanced_builder() + .cell_deps(get_cell_deps( + vec![Contract::CommitmentLock, Contract::Secp256k1Lock], + &to_local_output.type_().to_opt(), + )) + .input( + CellInput::new_builder() + .previous_output(commitment_tx_out_point) + .since(since.pack()) + .build(), + ) + .output(to_local_output.clone()) + .output_data(to_local_output_data) + .output(to_remote_output.clone()) + .output_data(to_remote_output_data) + .output(change_output.clone()) + .output_data(Bytes::default()) + .witness( + create_witness_for_commitment_cell(x_only_aggregated_pubkey, aggregated_signature) + .pack(), + ) + .witness(placeholder_witness.as_bytes().pack()); + + // TODO: move it to config or use https://github.com/nervosnetwork/ckb/pull/4477 + let fee_calculator = FeeCalculator::new(1000); + + let mut query = CellQueryOptions::new_lock(fee_provider_lock_script); + query.script_search_mode = Some(SearchMode::Exact); + query.secondary_script_len_range = Some(ValueRangeOption::new_exact(0)); + query.data_len_range = Some(ValueRangeOption::new_exact(0)); + let (cells, _total_capacity) = cell_collector.collect_live_cells(&query, true)?; + + let mut inputs_capacity = 0u64; + for cell in cells { + let input_capacity: u64 = cell.output.capacity().unpack(); + inputs_capacity += input_capacity; + tx_builder = tx_builder.input( + CellInput::new_builder() + .previous_output(cell.out_point) + .build(), + ); + let fee = + fee_calculator.fee(tx_builder.clone().build().data().serialized_size_in_block() as u64); + if inputs_capacity >= change_output_occupied_capacity + fee { + let new_change_output = change_output + .as_builder() + .capacity((inputs_capacity - fee).pack()) + .build(); + let outputs = vec![to_local_output, to_remote_output, new_change_output]; + let tx = tx_builder.set_outputs(outputs).build(); + let tx = sign_tx(tx, secret_key)?; return Ok(tx); } } @@ -361,7 +548,7 @@ fn build_revocation_tx( Err(Box::new(RpcError::Other(anyhow!("Not enough capacity")))) } -fn sign_revocation_tx( +fn sign_tx( tx: TransactionView, secret_key: SecretKey, ) -> Result> { @@ -369,8 +556,8 @@ fn sign_revocation_tx( let witness = tx.witnesses().get(1).expect("get witness at index 1"); let mut blake2b = new_blake2b(); blake2b.update(tx.calc_tx_hash().as_slice()); - blake2b.update(&(witness.as_bytes().len() as u64).to_le_bytes()); - blake2b.update(&witness.as_bytes()); + blake2b.update(&(witness.item_count() as u64).to_le_bytes()); + blake2b.update(&witness.raw_data()); let mut message = vec![0u8; 32]; blake2b.finalize(&mut message); let secp256k1_message = Message::from_digest_slice(&message)?; diff --git a/src/watchtower/mod.rs b/src/watchtower/mod.rs index abfea71ac..0dcbc1049 100644 --- a/src/watchtower/mod.rs +++ b/src/watchtower/mod.rs @@ -1,5 +1,5 @@ mod actor; mod store; -pub use actor::{WatchtowerActor, WatchtowerMessage}; -pub use store::{ChannelData, RevocationData, WatchtowerStore}; +pub use actor::{WatchtowerActor, WatchtowerMessage, DEFAULT_WATCHTOWER_CHECK_INTERVAL_SECONDS}; +pub use store::{ChannelData, WatchtowerStore}; diff --git a/src/watchtower/store.rs b/src/watchtower/store.rs index 9f0fb2452..db0c8418d 100644 --- a/src/watchtower/store.rs +++ b/src/watchtower/store.rs @@ -1,9 +1,12 @@ -use ckb_types::packed::{Bytes, CellOutput, Script}; -use musig2::CompactSignature; +use ckb_types::packed::Script; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use crate::fiber::{serde_utils::CompactSignatureAsBytes, serde_utils::EntityHex, types::Hash256}; +use crate::fiber::{ + channel::{RevocationData, SettlementData}, + serde_utils::EntityHex, + types::Hash256, +}; pub trait WatchtowerStore { /// Get the channels that are currently being watched by the watchtower @@ -15,6 +18,8 @@ pub trait WatchtowerStore { fn remove_watch_channel(&self, channel_id: Hash256); /// Update the revocation data of a channel, the watchtower will use this data to revoke an old version commitment transaction fn update_revocation(&self, channel_id: Hash256, revocation_data: RevocationData); + /// Update the settlement data of a channel, the watchtower will use this data to settle the commitment transaction of a force closed channel + fn update_settlement(&self, channel_id: Hash256, settlement_data: SettlementData); } /// The data of a channel that the watchtower is monitoring @@ -25,17 +30,5 @@ pub struct ChannelData { #[serde_as(as = "EntityHex")] pub funding_tx_lock: Script, pub revocation_data: Option, -} - -#[serde_as] -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct RevocationData { - pub commitment_number: u64, - pub x_only_aggregated_pubkey: [u8; 32], - #[serde_as(as = "CompactSignatureAsBytes")] - pub aggregated_signature: CompactSignature, - #[serde_as(as = "EntityHex")] - pub output: CellOutput, - #[serde_as(as = "EntityHex")] - pub output_data: Bytes, + pub settlement_data: Option, } diff --git a/tests/bruno/e2e/watchtower/force-close/01-connect-peer.bru b/tests/bruno/e2e/watchtower/force-close/01-connect-peer.bru new file mode 100644 index 000000000..7029e544a --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close/01-connect-peer.bru @@ -0,0 +1,38 @@ +meta { + name: connect peer + type: http + seq: 1 +} + +post { + url: {{NODE2_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "connect_peer", + "params": [ + {"address": "{{NODE1_ADDR}}"} + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result: isNull +} + +script:post-response { + // Dialing a peer is async in tentacle. Sleep for some time to make sure + // we're connected to the peer. + await new Promise(r => setTimeout(r, 1000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close/02-open-channel.bru b/tests/bruno/e2e/watchtower/force-close/02-open-channel.bru new file mode 100644 index 000000000..f2f0f8ff9 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close/02-open-channel.bru @@ -0,0 +1,39 @@ +meta { + name: Node1 open a channel to Node2 + type: http + seq: 2 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "open_channel", + "params": [ + { + "peer_id": "{{NODE2_PEERID}}", + "funding_amount": "0xba43b7400" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result.temporary_channel_id: isDefined +} + +script:post-response { + await new Promise(r => setTimeout(r, 2000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close/03-get-auto-accepted-channel.bru b/tests/bruno/e2e/watchtower/force-close/03-get-auto-accepted-channel.bru new file mode 100644 index 000000000..f2834adc2 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close/03-get-auto-accepted-channel.bru @@ -0,0 +1,40 @@ +meta { + name: get auto accepted channel id from Node1 + type: http + seq: 3 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "list_channels", + "params": [ + { + "peer_id": "{{NODE2_PEERID}}" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result.channels: isDefined +} + +script:post-response { + await new Promise(r => setTimeout(r, 2000)); + console.log(res.body.result); + bru.setVar("CHANNEL_ID", res.body.result.channels.at(-1).channel_id); +} diff --git a/tests/bruno/e2e/watchtower/force-close/04-generate-a-few-blocks.bru b/tests/bruno/e2e/watchtower/force-close/04-generate-a-few-blocks.bru new file mode 100644 index 000000000..9da68c5c0 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close/04-generate-a-few-blocks.bru @@ -0,0 +1,33 @@ +meta { + name: generate a few blocks + type: http + seq: 4 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x1"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close/05-node2-gen-invoice.bru b/tests/bruno/e2e/watchtower/force-close/05-node2-gen-invoice.bru new file mode 100644 index 000000000..f17c31ba5 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close/05-node2-gen-invoice.bru @@ -0,0 +1,65 @@ +meta { + name: generate a invoice + type: http + seq: 5 +} + +post { + url: {{NODE2_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "new_invoice", + "params": [ + { + "amount": "0x2dc6c0", + "currency": "Fibd", + "description": "test invoice generated by node3", + "expiry": "0xe10", + "final_expiry_delta": "0xDFFA0", + "payment_preimage": "{{payment_preimage}}" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result: isDefined +} + +script:pre-request { + // generate random preimage + function generateRandomPreimage() { + let hash = '0x'; + for (let i = 0; i < 64; i++) { + hash += Math.floor(Math.random() * 16).toString(16); + } + return hash; + } + const payment_preimage = generateRandomPreimage(); + bru.setVar("payment_preimage", payment_preimage); + let hash_algorithm = bru.getEnvVar("HASH_ALGORITHM"); + if (hash_algorithm !== null) { + let body = req.getBody(); + body.params[0].hash_algorithm = hash_algorithm; + req.setBody(body); + } +} + +script:post-response { + console.log("generated result: ", res.body.result); + bru.setVar("encoded_invoice", res.body.result.invoice_address); + // Sleep for sometime to make sure current operation finishes before next request starts. + await new Promise(r => setTimeout(r, 1000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close/06-node1-send-payment-with-invoice.bru b/tests/bruno/e2e/watchtower/force-close/06-node1-send-payment-with-invoice.bru new file mode 100644 index 000000000..2fd533e03 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close/06-node1-send-payment-with-invoice.bru @@ -0,0 +1,45 @@ +meta { + name: Node1 send payment with invoice + type: http + seq: 6 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "send_payment", + "params": [ + { + "invoice": "{{encoded_invoice}}" + } + ] + } +} + +assert { + res.body.error: isUndefined +} + + +script:pre-request { + // sleep for a while + await new Promise(r => setTimeout(r, 1000)); +} + + +script:post-response { + // Sleep for sometime to make sure current operation finishes before next request starts. + await new Promise(r => setTimeout(r, 1000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close/07-force-close.bru b/tests/bruno/e2e/watchtower/force-close/07-force-close.bru new file mode 100644 index 000000000..0f61b52b5 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close/07-force-close.bru @@ -0,0 +1,40 @@ +meta { + name: Node1 force close channel + type: http + seq: 7 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "shutdown_channel", + "params": [ + { + "channel_id": "{{CHANNEL_ID}}", + "close_script": { + "code_hash": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a", + "hash_type": "data", + "args": "0x0101010101010101010101010101010101010101" + }, + "fee_rate": "0x3FC", + "force": true + } + ] + } +} + +script:post-response { + console.log(res.body); +} diff --git a/tests/bruno/e2e/watchtower/force-close/08-get-force-closed-commitment-tx-hash.bru b/tests/bruno/e2e/watchtower/force-close/08-get-force-closed-commitment-tx-hash.bru new file mode 100644 index 000000000..09df4692d --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close/08-get-force-closed-commitment-tx-hash.bru @@ -0,0 +1,39 @@ +meta { + name: get force closed commitment tx hash + type: http + seq: 8 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "list_channels", + "params": [ + { + "peer_id": "{{NODE2_PEERID}}" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result.channels: isDefined +} + +script:post-response { + console.log(res.body.result); + bru.setVar("TX_HASH", res.body.result.channels.at(-1).latest_commitment_transaction_hash); +} diff --git a/tests/bruno/e2e/watchtower/force-close/09-generate-a-few-blocks-for-commitment-tx.bru b/tests/bruno/e2e/watchtower/force-close/09-generate-a-few-blocks-for-commitment-tx.bru new file mode 100644 index 000000000..45597cbb6 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close/09-generate-a-few-blocks-for-commitment-tx.bru @@ -0,0 +1,34 @@ +meta { + name: generate a few blocks for commitment tx + type: http + seq: 9 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x1"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + // Wait for the commitment tx to be included in a block + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close/10-generate-a-few-blocks-for-settlement-tx-generated.bru b/tests/bruno/e2e/watchtower/force-close/10-generate-a-few-blocks-for-settlement-tx-generated.bru new file mode 100644 index 000000000..59465ed87 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close/10-generate-a-few-blocks-for-settlement-tx-generated.bru @@ -0,0 +1,34 @@ +meta { + name: generate a few blocks for watchtower to generate settlement tx, default delay epoch is 6 epochs + type: http + seq: 10 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x7"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + // Wait for the commitment tx to be revoked by the watchtower + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close/11-generate-a-few-blocks-for-settlement-tx-committed.bru b/tests/bruno/e2e/watchtower/force-close/11-generate-a-few-blocks-for-settlement-tx-committed.bru new file mode 100644 index 000000000..d6f95b15a --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close/11-generate-a-few-blocks-for-settlement-tx-committed.bru @@ -0,0 +1,33 @@ +meta { + name: generate a few blocks for settlement tx to be committed + type: http + seq: 11 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x1"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close/12-check-commitment-tx.bru b/tests/bruno/e2e/watchtower/force-close/12-check-commitment-tx.bru new file mode 100644 index 000000000..610d0d1a2 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close/12-check-commitment-tx.bru @@ -0,0 +1,39 @@ +meta { + name: check submitted commitment tx should be settled + type: http + seq: 12 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "get_live_cell", + "params": [ + { + "index": "0x0", + "tx_hash": "{{TX_HASH}}" + }, + false + ] + } +} + +assert { + res.body.result.status: eq "unknown" +} + +script:post-response { + console.log("generated result: ", res.body); +} diff --git a/tests/bruno/e2e/watchtower/revocation/01-connect-peer.bru b/tests/bruno/e2e/watchtower/revocation/01-connect-peer.bru new file mode 100644 index 000000000..196fd5483 --- /dev/null +++ b/tests/bruno/e2e/watchtower/revocation/01-connect-peer.bru @@ -0,0 +1,38 @@ +meta { + name: connect peer + type: http + seq: 1 +} + +post { + url: {{NODE3_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "connect_peer", + "params": [ + {"address": "{{NODE1_ADDR}}"} + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result: isNull +} + +script:post-response { + // Dialing a peer is async in tentacle. Sleep for some time to make sure + // we're connected to the peer. + await new Promise(r => setTimeout(r, 1000)); +} diff --git a/tests/bruno/e2e/watchtower/revocation/02-open-channel.bru b/tests/bruno/e2e/watchtower/revocation/02-open-channel.bru new file mode 100644 index 000000000..9cd67ab62 --- /dev/null +++ b/tests/bruno/e2e/watchtower/revocation/02-open-channel.bru @@ -0,0 +1,39 @@ +meta { + name: Node1 open a channel to Node3 + type: http + seq: 2 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "open_channel", + "params": [ + { + "peer_id": "{{NODE3_PEERID}}", + "funding_amount": "0xba43b7400" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result.temporary_channel_id: isDefined +} + +script:post-response { + await new Promise(r => setTimeout(r, 2000)); +} diff --git a/tests/bruno/e2e/watchtower/revocation/03-get-auto-accepted-channel.bru b/tests/bruno/e2e/watchtower/revocation/03-get-auto-accepted-channel.bru new file mode 100644 index 000000000..d30b20fa2 --- /dev/null +++ b/tests/bruno/e2e/watchtower/revocation/03-get-auto-accepted-channel.bru @@ -0,0 +1,40 @@ +meta { + name: get auto accepted channel id from Node1 + type: http + seq: 3 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "list_channels", + "params": [ + { + "peer_id": "{{NODE3_PEERID}}" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result.channels: isDefined +} + +script:post-response { + await new Promise(r => setTimeout(r, 2000)); + console.log(res.body.result); + bru.setVar("CHANNEL_ID", res.body.result.channels.at(-1).channel_id); +} diff --git a/tests/bruno/e2e/watchtower/revocation/04-generate-a-few-blocks.bru b/tests/bruno/e2e/watchtower/revocation/04-generate-a-few-blocks.bru new file mode 100644 index 000000000..9da68c5c0 --- /dev/null +++ b/tests/bruno/e2e/watchtower/revocation/04-generate-a-few-blocks.bru @@ -0,0 +1,33 @@ +meta { + name: generate a few blocks + type: http + seq: 4 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x1"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/revocation/05-node3-gen-invoice.bru b/tests/bruno/e2e/watchtower/revocation/05-node3-gen-invoice.bru new file mode 100644 index 000000000..026f64124 --- /dev/null +++ b/tests/bruno/e2e/watchtower/revocation/05-node3-gen-invoice.bru @@ -0,0 +1,65 @@ +meta { + name: generate a invoice + type: http + seq: 5 +} + +post { + url: {{NODE3_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "new_invoice", + "params": [ + { + "amount": "0x1", + "currency": "Fibd", + "description": "test invoice generated by node3", + "expiry": "0xe10", + "final_expiry_delta": "0xDFFA0", + "payment_preimage": "{{payment_preimage}}" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result: isDefined +} + +script:pre-request { + // generate random preimage + function generateRandomPreimage() { + let hash = '0x'; + for (let i = 0; i < 64; i++) { + hash += Math.floor(Math.random() * 16).toString(16); + } + return hash; + } + const payment_preimage = generateRandomPreimage(); + bru.setVar("payment_preimage", payment_preimage); + let hash_algorithm = bru.getEnvVar("HASH_ALGORITHM"); + if (hash_algorithm !== null) { + let body = req.getBody(); + body.params[0].hash_algorithm = hash_algorithm; + req.setBody(body); + } +} + +script:post-response { + console.log("generated result: ", res.body.result); + bru.setVar("encoded_invoice", res.body.result.invoice_address); + // Sleep for sometime to make sure current operation finishes before next request starts. + await new Promise(r => setTimeout(r, 1000)); +} diff --git a/tests/bruno/e2e/watchtower/revocation/06-node1-send-payment-with-invoice.bru b/tests/bruno/e2e/watchtower/revocation/06-node1-send-payment-with-invoice.bru new file mode 100644 index 000000000..2fd533e03 --- /dev/null +++ b/tests/bruno/e2e/watchtower/revocation/06-node1-send-payment-with-invoice.bru @@ -0,0 +1,45 @@ +meta { + name: Node1 send payment with invoice + type: http + seq: 6 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "send_payment", + "params": [ + { + "invoice": "{{encoded_invoice}}" + } + ] + } +} + +assert { + res.body.error: isUndefined +} + + +script:pre-request { + // sleep for a while + await new Promise(r => setTimeout(r, 1000)); +} + + +script:post-response { + // Sleep for sometime to make sure current operation finishes before next request starts. + await new Promise(r => setTimeout(r, 1000)); +} diff --git a/tests/bruno/e2e/watchtower/revocation/07-submit-old-version-commitment-tx.bru b/tests/bruno/e2e/watchtower/revocation/07-submit-old-version-commitment-tx.bru new file mode 100644 index 000000000..d56643b39 --- /dev/null +++ b/tests/bruno/e2e/watchtower/revocation/07-submit-old-version-commitment-tx.bru @@ -0,0 +1,35 @@ +meta { + name: Node1 submit an old version commitment tx + type: http + seq: 7 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "submit_commitment_transaction", + "params": [ + { + "channel_id": "{{CHANNEL_ID}}", + "commitment_number": "0x0" + } + ] + } +} + +script:post-response { + console.log(res.body); + bru.setVar("TX_HASH", res.body.result.tx_hash); +} diff --git a/tests/bruno/e2e/watchtower/revocation/08-generate-a-few-blocks-for-commitment-tx.bru b/tests/bruno/e2e/watchtower/revocation/08-generate-a-few-blocks-for-commitment-tx.bru new file mode 100644 index 000000000..3a9a9a577 --- /dev/null +++ b/tests/bruno/e2e/watchtower/revocation/08-generate-a-few-blocks-for-commitment-tx.bru @@ -0,0 +1,34 @@ +meta { + name: generate a few blocks for commitment tx + type: http + seq: 8 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x1"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + // Wait for the commitment tx to be included in a block + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/revocation/09-generate-a-few-blocks-for-revocation-tx.bru b/tests/bruno/e2e/watchtower/revocation/09-generate-a-few-blocks-for-revocation-tx.bru new file mode 100644 index 000000000..2c6da223e --- /dev/null +++ b/tests/bruno/e2e/watchtower/revocation/09-generate-a-few-blocks-for-revocation-tx.bru @@ -0,0 +1,34 @@ +meta { + name: generate a few blocks for revocation tx + type: http + seq: 9 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x1"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + // Wait for the commitment tx to be revoked by the watchtower + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/revocation/10-check-commitment-tx.bru b/tests/bruno/e2e/watchtower/revocation/10-check-commitment-tx.bru new file mode 100644 index 000000000..728de78db --- /dev/null +++ b/tests/bruno/e2e/watchtower/revocation/10-check-commitment-tx.bru @@ -0,0 +1,39 @@ +meta { + name: check submitted commitment tx should be revoked + type: http + seq: 10 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "get_live_cell", + "params": [ + { + "index": "0x0", + "tx_hash": "{{TX_HASH}}" + }, + false + ] + } +} + +assert { + res.body.result.status: eq "unknown" +} + +script:post-response { + console.log("generated result: ", res.body); +} diff --git a/tests/nodes/deployer/config.yml b/tests/nodes/deployer/config.yml index 9d595e022..a6d11e28e 100644 --- a/tests/nodes/deployer/config.yml +++ b/tests/nodes/deployer/config.yml @@ -5,9 +5,18 @@ fiber: chain: dev.toml auto_announce_node: true announce_private_addr: true + watchtower_check_interval_seconds: 1 rpc: listening_addr: 127.0.0.1:41716 + enabled_modules: + - cch + - channel + - graph + - info + - invoice + - peer + - dev cch: ignore_startup_failure: true From 785ea07dca171110016d10c2de6034e5545cfcf9 Mon Sep 17 00:00:00 2001 From: quake Date: Tue, 10 Dec 2024 10:24:26 +0900 Subject: [PATCH 2/8] chore: refactor --- src/store/store.rs | 15 +++- src/store/tests/store.rs | 17 +++- src/watchtower/actor.rs | 181 ++++++++++++++++++++------------------- src/watchtower/store.rs | 16 ++-- 4 files changed, 128 insertions(+), 101 deletions(-) diff --git a/src/store/store.rs b/src/store/store.rs index 51563468d..0dbd2e61d 100644 --- a/src/store/store.rs +++ b/src/store/store.rs @@ -626,7 +626,8 @@ impl WatchtowerStore for Store { channel_id, funding_tx_lock, revocation_data: None, - settlement_data: None, + local_settlement_data: None, + remote_settlement_data: None, }, "ChannelData", ); @@ -640,26 +641,32 @@ impl WatchtowerStore for Store { self.db.delete(key).expect("delete should be OK"); } - fn update_revocation(&self, channel_id: Hash256, revocation_data: RevocationData) { + fn update_revocation( + &self, + channel_id: Hash256, + revocation_data: RevocationData, + settlement_data: SettlementData, + ) { let key = [&[WATCHTOWER_CHANNEL_PREFIX], channel_id.as_ref()].concat(); if let Some(mut channel_data) = self .get(key) .map(|v| deserialize_from::(v.as_ref(), "ChannelData")) { channel_data.revocation_data = Some(revocation_data); + channel_data.local_settlement_data = Some(settlement_data); let mut batch = self.batch(); batch.put_kv(KeyValue::WatchtowerChannel(channel_id, channel_data)); batch.commit(); } } - fn update_settlement(&self, channel_id: Hash256, settlement_data: SettlementData) { + fn update_remote_settlement(&self, channel_id: Hash256, settlement_data: SettlementData) { let key = [&[WATCHTOWER_CHANNEL_PREFIX], channel_id.as_ref()].concat(); if let Some(mut channel_data) = self .get(key) .map(|v| deserialize_from::(v.as_ref(), "ChannelData")) { - channel_data.settlement_data = Some(settlement_data); + channel_data.remote_settlement_data = Some(settlement_data); let mut batch = self.batch(); batch.put_kv(KeyValue::WatchtowerChannel(channel_id, channel_data)); batch.commit(); diff --git a/src/store/tests/store.rs b/src/store/tests/store.rs index 4992f93fe..950c86490 100644 --- a/src/store/tests/store.rs +++ b/src/store/tests/store.rs @@ -194,7 +194,8 @@ fn test_store_wacthtower() { channel_id, funding_tx_lock: funding_tx_lock.clone(), revocation_data: None, - settlement_data: None + local_settlement_data: None, + remote_settlement_data: None, }] ); @@ -206,14 +207,24 @@ fn test_store_wacthtower() { output_data: Bytes::default(), }; - store.update_revocation(channel_id, revocation_data.clone()); + let settlement_data = SettlementData { + x_only_aggregated_pubkey: [0u8; 32], + aggregated_signature: CompactSignature::from_bytes(&[0u8; 64]).unwrap(), + to_local_output: CellOutput::default(), + to_local_output_data: Bytes::default(), + to_remote_output: CellOutput::default(), + to_remote_output_data: Bytes::default(), + }; + + store.update_revocation(channel_id, revocation_data.clone(), settlement_data.clone()); assert_eq!( store.get_watch_channels(), vec![ChannelData { channel_id, funding_tx_lock, revocation_data: Some(revocation_data), - settlement_data: None + local_settlement_data: Some(settlement_data), + remote_settlement_data: None, }] ); diff --git a/src/watchtower/actor.rs b/src/watchtower/actor.rs index 89ff0356d..eb3d1b66f 100644 --- a/src/watchtower/actor.rs +++ b/src/watchtower/actor.rs @@ -11,7 +11,7 @@ use ckb_sdk::{ use ckb_types::{ self, core::{Capacity, TransactionView}, - packed::{Bytes, CellInput, CellOutput, OutPoint, Transaction, WitnessArgs}, + packed::{Bytes, CellInput, CellOutput, OutPoint, Script, Transaction, WitnessArgs}, prelude::*, }; use molecule::prelude::Entity; @@ -129,9 +129,10 @@ where _peer_id, channel_id, revocation_data, - _settlement_data, + settlement_data, ) => { - self.store.update_revocation(channel_id, revocation_data); + self.store + .update_revocation(channel_id, revocation_data, settlement_data); } NetworkServiceEvent::RemoteCommitmentSigned( _peer_id, @@ -139,7 +140,8 @@ where _commitment_tx, settlement_data, ) => { - self.store.update_settlement(channel_id, settlement_data); + self.store + .update_remote_settlement(channel_id, settlement_data); } _ => { // ignore @@ -250,95 +252,30 @@ where } } else { info!("Found a force closed commitment tx submitted by remote: {:?}, revocation commitment number: {}, commitment number: {}", tx.calc_tx_hash(), revocation_data.commitment_number, commitment_number); + try_settle_commitment_tx( + commitment_lock, + ckb_client, + channel_data + .remote_settlement_data + .clone() + .expect("settlement data should be some"), + secret_key, + &mut cell_collector, + ); } } else { // it's a force closed commitment tx which is submitted by local info!("Found a force closed commitment tx submitted by local: {:?}, revocation commitment number: {}, commitment number: {}", tx.calc_tx_hash(), revocation_data.commitment_number, commitment_number); - let script = commitment_lock - .as_builder() - .args( - lock_args[0..36] - .to_vec() - .pack(), - ) - .build(); - let search_key = SearchKey { - script: script.into(), - script_type: ScriptType::Lock, - script_search_mode: Some( - SearchMode::Prefix, - ), - with_data: None, - filter: None, - group_by_transaction: None, - }; - - // the live cells number should be 1 or 0 for normal case, however, an attacker may create a lot of cells to implement a tx pinning attack. - match ckb_client.get_cells( - search_key, - Order::Desc, - 100u32.into(), - None, - ) { - Ok(cells) => { - for cell in cells.objects { - let cell_output: CellOutput = cell.output.into(); - let commitment_tx_out_point = - OutPoint::new( - cell.out_point - .tx_hash - .pack(), - cell.out_point - .index - .value(), - ); - let lock_script_args = - cell_output - .lock() - .args() - .raw_data(); - if lock_script_args.len() - == 36 - { - let since = u64::from_le_bytes(cell_output.lock().args().raw_data()[20..28].try_into().expect("u64 from slice")); - // TODO check since - match build_settlement_tx( - commitment_tx_out_point, - since, - channel_data.settlement_data.clone().expect("settlement data should be some"), - secret_key, - &mut cell_collector, - ) { - Ok(tx) => { - match ckb_client - .send_transaction( - tx.data().into(), - None, - ) { - Ok(tx_hash) => { - info!("Settlement tx: {:?} sent, tx_hash: {:?}", tx, tx_hash); - } - Err(err) => { - error!("Failed to send settlement tx: {:?}, error: {:?}", tx, err); - } - } - } - Err(err) => { - error!("Failed to build settlement tx: {:?}", err); - } - } - } else { - // TODO use 0x00 ~ 0xFD to get back the funds - } - } - } - Err(err) => { - error!( - "Failed to get cells: {:?}", - err - ); - } - } + try_settle_commitment_tx( + commitment_lock, + ckb_client, + channel_data + .local_settlement_data + .clone() + .expect("settlement data should be some"), + secret_key, + &mut cell_collector, + ); } } else { // there may be a race condition that PeriodicCheck is triggered before the remove_channel fn is called @@ -458,6 +395,72 @@ fn build_revocation_tx( Err(Box::new(RpcError::Other(anyhow!("Not enough capacity")))) } +fn try_settle_commitment_tx( + commitment_lock: Script, + ckb_client: CkbRpcClient, + settlement_data: SettlementData, + secret_key: SecretKey, + cell_collector: &mut DefaultCellCollector, +) { + let lock_args = commitment_lock.args().raw_data(); + let script = commitment_lock + .as_builder() + .args(lock_args[0..36].to_vec().pack()) + .build(); + let search_key = SearchKey { + script: script.into(), + script_type: ScriptType::Lock, + script_search_mode: Some(SearchMode::Prefix), + with_data: None, + filter: None, + group_by_transaction: None, + }; + + // the live cells number should be 1 or 0 for normal case, however, an attacker may create a lot of cells to implement a tx pinning attack. + match ckb_client.get_cells(search_key, Order::Desc, 100u32.into(), None) { + Ok(cells) => { + for cell in cells.objects { + let cell_output: CellOutput = cell.output.into(); + let commitment_tx_out_point = + OutPoint::new(cell.out_point.tx_hash.pack(), cell.out_point.index.value()); + let lock_script_args = cell_output.lock().args().raw_data(); + if lock_script_args.len() == 36 { + let since = u64::from_le_bytes( + cell_output.lock().args().raw_data()[20..28] + .try_into() + .expect("u64 from slice"), + ); + // TODO check since + match build_settlement_tx( + commitment_tx_out_point, + since, + settlement_data.clone(), + secret_key, + cell_collector, + ) { + Ok(tx) => match ckb_client.send_transaction(tx.data().into(), None) { + Ok(tx_hash) => { + info!("Settlement tx: {:?} sent, tx_hash: {:?}", tx, tx_hash); + } + Err(err) => { + error!("Failed to send settlement tx: {:?}, error: {:?}", tx, err); + } + }, + Err(err) => { + error!("Failed to build settlement tx: {:?}", err); + } + } + } else { + // TODO use 0x00 ~ 0xFD to get back the funds + } + } + } + Err(err) => { + error!("Failed to get cells: {:?}", err); + } + } +} + fn build_settlement_tx( commitment_tx_out_point: OutPoint, since: u64, diff --git a/src/watchtower/store.rs b/src/watchtower/store.rs index db0c8418d..b693ad395 100644 --- a/src/watchtower/store.rs +++ b/src/watchtower/store.rs @@ -16,10 +16,15 @@ pub trait WatchtowerStore { fn insert_watch_channel(&self, channel_id: Hash256, funding_tx_lock: Script); /// Remove a channel from the store, the watchtower will stop monitoring the channel fn remove_watch_channel(&self, channel_id: Hash256); - /// Update the revocation data of a channel, the watchtower will use this data to revoke an old version commitment transaction - fn update_revocation(&self, channel_id: Hash256, revocation_data: RevocationData); - /// Update the settlement data of a channel, the watchtower will use this data to settle the commitment transaction of a force closed channel - fn update_settlement(&self, channel_id: Hash256, settlement_data: SettlementData); + /// Update the revocation data of a channel, the watchtower will use this data to revoke an old version commitment transaction and settle the local commitment transaction of a force closed channel + fn update_revocation( + &self, + channel_id: Hash256, + revocation_data: RevocationData, + settlement_data: SettlementData, + ); + /// Update the settlement data of a channel, the watchtower will use this data to settle the remote commitment transaction of a force closed channel + fn update_remote_settlement(&self, channel_id: Hash256, settlement_data: SettlementData); } /// The data of a channel that the watchtower is monitoring @@ -30,5 +35,6 @@ pub struct ChannelData { #[serde_as(as = "EntityHex")] pub funding_tx_lock: Script, pub revocation_data: Option, - pub settlement_data: Option, + pub local_settlement_data: Option, + pub remote_settlement_data: Option, } From f2e9c73ba6f7abf9de86228cd03caa53e70d28aa Mon Sep 17 00:00:00 2001 From: quake Date: Tue, 10 Dec 2024 10:57:22 +0900 Subject: [PATCH 3/8] chore: remove unused tx_hash from TxSignatures --- src/fiber/gen/fiber.rs | 48 +++++++++----------------------------- src/fiber/network.rs | 2 -- src/fiber/schema/fiber.mol | 1 - src/fiber/types.rs | 3 --- 4 files changed, 11 insertions(+), 43 deletions(-) diff --git a/src/fiber/gen/fiber.rs b/src/fiber/gen/fiber.rs index e2a5d07e9..80bc6530b 100644 --- a/src/fiber/gen/fiber.rs +++ b/src/fiber/gen/fiber.rs @@ -5925,7 +5925,6 @@ impl ::core::fmt::Display for TxSignatures { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "channel_id", self.channel_id())?; - write!(f, ", {}: {}", "tx_hash", self.tx_hash())?; write!(f, ", {}: {}", "witnesses", self.witnesses())?; let extra_count = self.count_extra_fields(); if extra_count != 0 { @@ -5941,12 +5940,11 @@ impl ::core::default::Default for TxSignatures { } } impl TxSignatures { - const DEFAULT_VALUE: [u8; 84] = [ - 84, 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, + const DEFAULT_VALUE: [u8; 48] = [ + 48, 0, 0, 0, 12, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, ]; - pub const FIELD_COUNT: usize = 3; + pub const FIELD_COUNT: usize = 2; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -5969,17 +5967,11 @@ impl TxSignatures { let end = molecule::unpack_number(&slice[8..]) as usize; Byte32::new_unchecked(self.0.slice(start..end)) } - pub fn tx_hash(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) - } pub fn witnesses(&self) -> BytesVec { let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; + let start = molecule::unpack_number(&slice[8..]) as usize; if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; BytesVec::new_unchecked(self.0.slice(start..end)) } else { BytesVec::new_unchecked(self.0.slice(start..)) @@ -6013,7 +6005,6 @@ impl molecule::prelude::Entity for TxSignatures { fn as_builder(self) -> Self::Builder { Self::new_builder() .channel_id(self.channel_id()) - .tx_hash(self.tx_hash()) .witnesses(self.witnesses()) } } @@ -6037,7 +6028,6 @@ impl<'r> ::core::fmt::Display for TxSignaturesReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "channel_id", self.channel_id())?; - write!(f, ", {}: {}", "tx_hash", self.tx_hash())?; write!(f, ", {}: {}", "witnesses", self.witnesses())?; let extra_count = self.count_extra_fields(); if extra_count != 0 { @@ -6047,7 +6037,7 @@ impl<'r> ::core::fmt::Display for TxSignaturesReader<'r> { } } impl<'r> TxSignaturesReader<'r> { - pub const FIELD_COUNT: usize = 3; + pub const FIELD_COUNT: usize = 2; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -6070,17 +6060,11 @@ impl<'r> TxSignaturesReader<'r> { let end = molecule::unpack_number(&slice[8..]) as usize; Byte32Reader::new_unchecked(&self.as_slice()[start..end]) } - pub fn tx_hash(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) - } pub fn witnesses(&self) -> BytesVecReader<'r> { let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; + let start = molecule::unpack_number(&slice[8..]) as usize; if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; BytesVecReader::new_unchecked(&self.as_slice()[start..end]) } else { BytesVecReader::new_unchecked(&self.as_slice()[start..]) @@ -6134,27 +6118,21 @@ impl<'r> molecule::prelude::Reader<'r> for TxSignaturesReader<'r> { return ve!(Self, OffsetsNotMatch); } Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; - Byte32Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; - BytesVecReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + BytesVecReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; Ok(()) } } #[derive(Clone, Debug, Default)] pub struct TxSignaturesBuilder { pub(crate) channel_id: Byte32, - pub(crate) tx_hash: Byte32, pub(crate) witnesses: BytesVec, } impl TxSignaturesBuilder { - pub const FIELD_COUNT: usize = 3; + pub const FIELD_COUNT: usize = 2; pub fn channel_id(mut self, v: Byte32) -> Self { self.channel_id = v; self } - pub fn tx_hash(mut self, v: Byte32) -> Self { - self.tx_hash = v; - self - } pub fn witnesses(mut self, v: BytesVec) -> Self { self.witnesses = v; self @@ -6166,7 +6144,6 @@ impl molecule::prelude::Builder for TxSignaturesBuilder { fn expected_length(&self) -> usize { molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + self.channel_id.as_slice().len() - + self.tx_hash.as_slice().len() + self.witnesses.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { @@ -6175,15 +6152,12 @@ impl molecule::prelude::Builder for TxSignaturesBuilder { offsets.push(total_size); total_size += self.channel_id.as_slice().len(); offsets.push(total_size); - total_size += self.tx_hash.as_slice().len(); - offsets.push(total_size); total_size += self.witnesses.as_slice().len(); writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; for offset in offsets.into_iter() { writer.write_all(&molecule::pack_number(offset as molecule::Number))?; } writer.write_all(self.channel_id.as_slice())?; - writer.write_all(self.tx_hash.as_slice())?; writer.write_all(self.witnesses.as_slice())?; Ok(()) } diff --git a/src/fiber/network.rs b/src/fiber/network.rs index cfc341637..f78672dd1 100644 --- a/src/fiber/network.rs +++ b/src/fiber/network.rs @@ -1507,7 +1507,6 @@ where FiberChannelMessage::TxSignatures(TxSignatures { channel_id: *channel_id, witnesses: witnesses.into_iter().map(|x| x.unpack()).collect(), - tx_hash: funding_tx.hash().into(), }), ), } @@ -1535,7 +1534,6 @@ where FiberChannelMessage::TxSignatures(TxSignatures { channel_id: *channel_id, witnesses: witnesses.into_iter().map(|x| x.unpack()).collect(), - tx_hash: funding_tx.hash().into(), }), ), } diff --git a/src/fiber/schema/fiber.mol b/src/fiber/schema/fiber.mol index fd63673fc..dae1d94a7 100644 --- a/src/fiber/schema/fiber.mol +++ b/src/fiber/schema/fiber.mol @@ -54,7 +54,6 @@ struct CommitmentSigned { table TxSignatures { channel_id: Byte32, - tx_hash: Byte32, witnesses: BytesVec, } diff --git a/src/fiber/types.rs b/src/fiber/types.rs index 1e0f15836..6fdaea665 100644 --- a/src/fiber/types.rs +++ b/src/fiber/types.rs @@ -761,7 +761,6 @@ impl TryFrom for CommitmentSigned { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TxSignatures { pub channel_id: Hash256, - pub tx_hash: Hash256, pub witnesses: Vec>, } @@ -769,7 +768,6 @@ impl From for molecule_fiber::TxSignatures { fn from(tx_signatures: TxSignatures) -> Self { molecule_fiber::TxSignatures::new_builder() .channel_id(tx_signatures.channel_id.into()) - .tx_hash(tx_signatures.tx_hash.into()) .witnesses( BytesVec::new_builder() .set( @@ -791,7 +789,6 @@ impl TryFrom for TxSignatures { fn try_from(tx_signatures: molecule_fiber::TxSignatures) -> Result { Ok(TxSignatures { channel_id: tx_signatures.channel_id().into(), - tx_hash: tx_signatures.tx_hash().into(), witnesses: tx_signatures .witnesses() .into_iter() From f440a140532dd52dc287a37857993bba39e2f0cd Mon Sep 17 00:00:00 2001 From: quake Date: Thu, 12 Dec 2024 14:10:03 +0900 Subject: [PATCH 4/8] fix: resolve forse close after open bug --- src/fiber/channel.rs | 239 ++++++++++++++---- src/fiber/gen/fiber.rs | 51 +++- src/fiber/network.rs | 89 ++++--- src/fiber/schema/fiber.mol | 3 +- src/fiber/types.rs | 8 + src/store/store.rs | 21 +- src/store/tests/store.rs | 25 +- src/watchtower/actor.rs | 154 +++++------ src/watchtower/store.rs | 13 +- .../01-connect-peer.bru | 38 +++ .../02-open-channel.bru | 39 +++ .../03-get-auto-accepted-channel.bru | 40 +++ .../04-generate-a-few-blocks.bru | 33 +++ .../05-force-close.bru | 40 +++ ...06-get-force-closed-commitment-tx-hash.bru | 39 +++ ...enerate-a-few-blocks-for-commitment-tx.bru | 34 +++ ...few-blocks-for-settlement-tx-generated.bru | 34 +++ ...few-blocks-for-settlement-tx-committed.bru | 33 +++ .../10-check-commitment-tx.bru | 39 +++ 19 files changed, 756 insertions(+), 216 deletions(-) create mode 100644 tests/bruno/e2e/watchtower/force-close-after-open-channel/01-connect-peer.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-open-channel/02-open-channel.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-open-channel/03-get-auto-accepted-channel.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-open-channel/04-generate-a-few-blocks.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-open-channel/05-force-close.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-open-channel/06-get-force-closed-commitment-tx-hash.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-open-channel/07-generate-a-few-blocks-for-commitment-tx.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-open-channel/08-generate-a-few-blocks-for-settlement-tx-generated.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-open-channel/09-generate-a-few-blocks-for-settlement-tx-committed.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-open-channel/10-check-commitment-tx.bru diff --git a/src/fiber/channel.rs b/src/fiber/channel.rs index 8f6fee887..5aa55324c 100644 --- a/src/fiber/channel.rs +++ b/src/fiber/channel.rs @@ -1256,9 +1256,42 @@ where state: &mut ChannelActorState, command: ShutdownCommand, ) -> ProcessingChannelResult { - // The force shutdown command has been handled speically in the `NetworkActorState#send_command_to_channel` function. - // We only need to handle the normal shutdown command here. debug!("Handling shutdown command: {:?}", &command); + if command.force { + match state.state { + ChannelState::ChannelReady() => { + debug!("Handling force shutdown command in ChannelReady state"); + } + ChannelState::ShuttingDown(flags) => { + debug!( + "Handling force shutdown command in ShuttingDown state, flags: {:?}", + &flags + ); + } + _ => { + return Err(ProcessingChannelError::InvalidState(format!( + "Handling force shutdown command invalid state {:?}", + &state.state + ))); + } + }; + + let transaction = state + .latest_commitment_transaction + .clone() + .expect("latest_commitment_transaction should exist when channel is in ChannelReady of ShuttingDown state"); + self.network + .send_message(NetworkActorMessage::new_event( + NetworkActorEvent::CommitmentTransactionPending(transaction, state.get_id()), + )) + .expect(ASSUME_NETWORK_ACTOR_ALIVE); + + state.update_state(ChannelState::ShuttingDown( + ShuttingDownFlags::WAITING_COMMITMENT_CONFIRMATION, + )); + return Ok(()); + } + let flags = match state.state { ChannelState::ChannelReady() => { debug!("Handling shutdown command in ChannelReady state"); @@ -1542,8 +1575,10 @@ where } TxCollaborationCommand::TxComplete() => { state.check_tx_complete_preconditions()?; + let commitment_tx_partial_signature = state.build_init_commitment_tx_signature()?; let fiber_message = FiberMessage::tx_complete(TxComplete { channel_id: state.get_id(), + commitment_tx_partial_signature, }); self.network .send_message(NetworkActorMessage::new_command( @@ -4031,7 +4066,10 @@ impl ChannelActorState { // Send RevokeAndAck message to the counterparty, and update the // channel state accordingly. - fn send_revoke_and_ack_message(&mut self, network: &ActorRef) { + fn send_revoke_and_ack_message( + &mut self, + network: &ActorRef, + ) -> ProcessingChannelResult { let key_agg_ctx = { let local_pubkey = self.get_local_channel_public_keys().funding_pubkey; let remote_pubkey = self.get_remote_channel_public_keys().funding_pubkey; @@ -4081,14 +4119,7 @@ impl ChannelActorState { let commitment_number = self.get_remote_commitment_number() - 1; let commitment_lock_script_args = [ &blake2b_256(x_only_aggregated_pubkey)[0..20], - (Since::new( - SinceType::EpochNumberWithFraction, - self.commitment_delay_epoch, - true, - ) - .value()) - .to_le_bytes() - .as_slice(), + self.get_delay_epoch_as_lock_args_bytes().as_slice(), commitment_number.to_be_bytes().as_slice(), ] .concat(); @@ -4114,14 +4145,7 @@ impl ChannelActorState { ) = self.build_settlement_transaction_outputs(false); let commitment_lock_script_args = [ &blake2b_256(x_only_aggregated_pubkey)[0..20], - (Since::new( - SinceType::EpochNumberWithFraction, - self.commitment_delay_epoch, - true, - ) - .value()) - .to_le_bytes() - .as_slice(), + self.get_delay_epoch_as_lock_args_bytes().as_slice(), self.get_remote_commitment_number().to_be_bytes().as_slice(), ] .concat(); @@ -4136,7 +4160,7 @@ impl ChannelActorState { .concat(), ); - sign_ctx.sign(message.as_slice()).expect("valid signature") + sign_ctx.sign(message.as_slice())? }; // Note that we must update channel state here to update commitment number, @@ -4157,6 +4181,7 @@ impl ChannelActorState { )), )) .expect(ASSUME_NETWORK_ACTOR_ALIVE); + Ok(()) } pub fn get_id(&self) -> Hash256 { @@ -5284,8 +5309,21 @@ impl ChannelActorState { )); } } - TxCollaborationMsg::TxComplete(_msg) => { + TxCollaborationMsg::TxComplete(tx_complete) => { self.check_tx_complete_preconditions()?; + let settlement_data = self.check_init_commitment_tx_signature( + tx_complete.commitment_tx_partial_signature, + )?; + network + .send_message(NetworkActorMessage::new_notification( + NetworkServiceEvent::RemoteTxComplete( + self.get_remote_peer_id(), + self.get_id(), + self.get_funding_lock_script(), + settlement_data, + ), + )) + .expect(ASSUME_NETWORK_ACTOR_ALIVE); let flags = flags | CollaboratingFundingTxFlags::THEIR_TX_COMPLETE_SENT; self.update_state(ChannelState::CollaboratingFundingTx(flags)); } @@ -5386,7 +5424,7 @@ impl ChannelActorState { self.maybe_transition_to_tx_signatures(flags, network)?; } CommitmentSignedFlags::ChannelReady() | CommitmentSignedFlags::PendingShutdown(_) => { - self.send_revoke_and_ack_message(network); + self.send_revoke_and_ack_message(network)?; match flags { CommitmentSignedFlags::ChannelReady() => {} CommitmentSignedFlags::PendingShutdown(_) => { @@ -5663,14 +5701,11 @@ impl ChannelActorState { (output, output_data) }; - let delay_epoch = self.commitment_delay_epoch; let commitment_number = self.get_local_commitment_number() - 1; let commitment_lock_script_args = [ &blake2b_256(x_only_aggregated_pubkey)[0..20], - (Since::new(SinceType::EpochNumberWithFraction, delay_epoch, true).value()) - .to_le_bytes() - .as_slice(), + self.get_delay_epoch_as_lock_args_bytes().as_slice(), commitment_number.to_be_bytes().as_slice(), ] .concat(); @@ -5705,14 +5740,7 @@ impl ChannelActorState { ) = self.build_settlement_transaction_outputs(true); let commitment_lock_script_args = [ &blake2b_256(x_only_aggregated_pubkey)[0..20], - (Since::new( - SinceType::EpochNumberWithFraction, - self.commitment_delay_epoch, - true, - ) - .value()) - .to_le_bytes() - .as_slice(), + self.get_delay_epoch_as_lock_args_bytes().as_slice(), self.get_local_commitment_number().to_be_bytes().as_slice(), ] .concat(); @@ -5865,7 +5893,7 @@ impl ChannelActorState { // Resetting our remote commitment number to the actual remote commitment number // and resend the RevokeAndAck message. self.set_remote_commitment_number(acutal_remote_commitment_number); - self.send_revoke_and_ack_message(network); + self.send_revoke_and_ack_message(network)?; } else { // unreachable state, just log an error for potential bugs error!( @@ -5953,12 +5981,14 @@ impl ChannelActorState { // Otherwise, it is possible that when the network actor is processing ControlFiberChannel, // it receives another SendFiberMessage command, and that message (e.g. CommitmentSigned) // is processed first, thus breaking the order of messages. + let commitment_tx_partial_signature = self.build_init_commitment_tx_signature()?; network .send_message(NetworkActorMessage::new_command( NetworkActorCommand::SendFiberMessage(FiberMessageWithPeerId::new( self.get_remote_peer_id(), FiberMessage::tx_complete(TxComplete { channel_id: self.get_id(), + commitment_tx_partial_signature, }), )), )) @@ -5978,6 +6008,116 @@ impl ChannelActorState { Ok(()) } + fn build_init_commitment_tx_signature(&self) -> Result { + let key_agg_ctx = { + let local_pubkey = self.get_local_channel_public_keys().funding_pubkey; + let remote_pubkey = self.get_remote_channel_public_keys().funding_pubkey; + KeyAggContext::new([remote_pubkey, local_pubkey]).expect("Valid pubkeys") + }; + let x_only_aggregated_pubkey = key_agg_ctx.aggregated_pubkey::().serialize_xonly(); + let sign_ctx = { + let local_nonce = self.get_local_nonce(); + let remote_nonce = self.get_remote_nonce(); + let nonces = [local_nonce, remote_nonce]; + let agg_nonce = AggNonce::sum(nonces); + Musig2SignContext { + key_agg_ctx, + agg_nonce, + seckey: self.signer.funding_key.clone(), + secnonce: self.get_local_musig2_secnonce(), + } + }; + let ([to_local_output, to_remote_output], [to_local_output_data, to_remote_output_data]) = + self.build_settlement_transaction_outputs(false); + let version = 0u64; + let commitment_lock_script_args = [ + &blake2b_256(x_only_aggregated_pubkey)[0..20], + self.get_delay_epoch_as_lock_args_bytes().as_slice(), + version.to_be_bytes().as_slice(), + ] + .concat(); + let message = blake2b_256( + [ + to_local_output.as_slice(), + to_local_output_data.as_slice(), + to_remote_output.as_slice(), + to_remote_output_data.as_slice(), + commitment_lock_script_args.as_slice(), + ] + .concat(), + ); + + sign_ctx.sign(message.as_slice()) + } + + fn check_init_commitment_tx_signature( + &self, + signature: PartialSignature, + ) -> Result { + let key_agg_ctx = { + let local_pubkey = self.get_local_channel_public_keys().funding_pubkey; + let remote_pubkey = self.get_remote_channel_public_keys().funding_pubkey; + KeyAggContext::new([local_pubkey, remote_pubkey]).expect("Valid pubkeys") + }; + let x_only_aggregated_pubkey = key_agg_ctx.aggregated_pubkey::().serialize_xonly(); + let local_nonce = self.get_local_nonce(); + let remote_nonce = self.get_remote_nonce(); + let nonces = [remote_nonce.clone(), local_nonce]; + let agg_nonce = AggNonce::sum(nonces); + let verify_ctx = Musig2VerifyContext { + key_agg_ctx: key_agg_ctx.clone(), + agg_nonce: agg_nonce.clone(), + pubkey: *self.get_remote_funding_pubkey(), + pubnonce: remote_nonce, + }; + let ([to_local_output, to_remote_output], [to_local_output_data, to_remote_output_data]) = + self.build_settlement_transaction_outputs(true); + let version = 0u64; + let commitment_lock_script_args = [ + &blake2b_256(x_only_aggregated_pubkey)[0..20], + self.get_delay_epoch_as_lock_args_bytes().as_slice(), + version.to_be_bytes().as_slice(), + ] + .concat(); + let message = blake2b_256( + [ + to_local_output.as_slice(), + to_local_output_data.as_slice(), + to_remote_output.as_slice(), + to_remote_output_data.as_slice(), + commitment_lock_script_args.as_slice(), + ] + .concat(), + ); + + verify_ctx.verify(signature, message.as_slice())?; + + let settlement_data = { + let sign_ctx = Musig2SignContext { + key_agg_ctx, + agg_nonce, + seckey: self.signer.funding_key.clone(), + secnonce: self.get_local_musig2_secnonce(), + }; + + let our_signature = sign_ctx.sign(message.as_slice())?; + let aggregated_signature = verify_ctx.aggregate_partial_signatures_for_msg( + [signature, our_signature], + message.as_slice(), + )?; + + SettlementData { + x_only_aggregated_pubkey, + aggregated_signature, + to_local_output, + to_local_output_data, + to_remote_output, + to_remote_output_data, + } + }; + Ok(settlement_data) + } + // TODO: More checks to the funding tx. fn check_tx_complete_preconditions(&mut self) -> ProcessingChannelResult { match self.funding_tx.as_ref() { @@ -6208,15 +6348,12 @@ impl ChannelActorState { fn build_commitment_transaction_output(&self, for_remote: bool) -> (CellOutput, Bytes) { let x_only_aggregated_pubkey = self.get_commitment_lock_script_xonly(for_remote); - let delay_epoch = self.commitment_delay_epoch; let version = self.get_current_commitment_number(for_remote); let htlcs = self.get_active_htlcs(for_remote); let mut commitment_lock_script_args = [ &blake2b_256(x_only_aggregated_pubkey)[0..20], - (Since::new(SinceType::EpochNumberWithFraction, delay_epoch, true).value()) - .to_le_bytes() - .as_slice(), + self.get_delay_epoch_as_lock_args_bytes().as_slice(), version.to_be_bytes().as_slice(), ] .concat(); @@ -6461,6 +6598,15 @@ impl ChannelActorState { )?; self.complete_partially_signed_tx(&tx) } + + fn get_delay_epoch_as_lock_args_bytes(&self) -> [u8; 8] { + let since = Since::new( + SinceType::EpochNumberWithFraction, + self.commitment_delay_epoch, + true, + ); + since.value().to_le_bytes() + } } pub trait ChannelActorStateStore { @@ -6580,23 +6726,14 @@ pub struct Musig2SignContext { } impl Musig2SignContext { - pub fn sign(self, message: &[u8]) -> Result { - let result = sign_partial( + pub fn sign(self, message: &[u8]) -> Result { + sign_partial( &self.key_agg_ctx, self.seckey, self.secnonce.clone(), &self.agg_nonce, message, - ); - debug!( - "Musig2 signing partial message {:?} with nonce {:?} (public nonce: {:?}), agg nonce {:?}: result {:?}", - hex::encode(message), - self.secnonce, - self.secnonce.public_nonce(), - &self.agg_nonce, - &result - ); - Ok(result?) + ) } } diff --git a/src/fiber/gen/fiber.rs b/src/fiber/gen/fiber.rs index 80bc6530b..1ec17ae43 100644 --- a/src/fiber/gen/fiber.rs +++ b/src/fiber/gen/fiber.rs @@ -6604,6 +6604,12 @@ impl ::core::fmt::Display for TxComplete { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "channel_id", self.channel_id())?; + write!( + f, + ", {}: {}", + "commitment_tx_partial_signature", + self.commitment_tx_partial_signature() + )?; write!(f, " }}") } } @@ -6614,16 +6620,20 @@ impl ::core::default::Default for TxComplete { } } impl TxComplete { - const DEFAULT_VALUE: [u8; 32] = [ + const DEFAULT_VALUE: [u8; 64] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, ]; - pub const TOTAL_SIZE: usize = 32; - pub const FIELD_SIZES: [usize; 1] = [32]; - pub const FIELD_COUNT: usize = 1; + pub const TOTAL_SIZE: usize = 64; + pub const FIELD_SIZES: [usize; 2] = [32, 32]; + pub const FIELD_COUNT: usize = 2; pub fn channel_id(&self) -> Byte32 { Byte32::new_unchecked(self.0.slice(0..32)) } + pub fn commitment_tx_partial_signature(&self) -> Byte32 { + Byte32::new_unchecked(self.0.slice(32..64)) + } pub fn as_reader<'r>(&'r self) -> TxCompleteReader<'r> { TxCompleteReader::new_unchecked(self.as_slice()) } @@ -6650,7 +6660,9 @@ impl molecule::prelude::Entity for TxComplete { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder().channel_id(self.channel_id()) + Self::new_builder() + .channel_id(self.channel_id()) + .commitment_tx_partial_signature(self.commitment_tx_partial_signature()) } } #[derive(Clone, Copy)] @@ -6673,16 +6685,25 @@ impl<'r> ::core::fmt::Display for TxCompleteReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "channel_id", self.channel_id())?; + write!( + f, + ", {}: {}", + "commitment_tx_partial_signature", + self.commitment_tx_partial_signature() + )?; write!(f, " }}") } } impl<'r> TxCompleteReader<'r> { - pub const TOTAL_SIZE: usize = 32; - pub const FIELD_SIZES: [usize; 1] = [32]; - pub const FIELD_COUNT: usize = 1; + pub const TOTAL_SIZE: usize = 64; + pub const FIELD_SIZES: [usize; 2] = [32, 32]; + pub const FIELD_COUNT: usize = 2; pub fn channel_id(&self) -> Byte32Reader<'r> { Byte32Reader::new_unchecked(&self.as_slice()[0..32]) } + pub fn commitment_tx_partial_signature(&self) -> Byte32Reader<'r> { + Byte32Reader::new_unchecked(&self.as_slice()[32..64]) + } } impl<'r> molecule::prelude::Reader<'r> for TxCompleteReader<'r> { type Entity = TxComplete; @@ -6708,15 +6729,20 @@ impl<'r> molecule::prelude::Reader<'r> for TxCompleteReader<'r> { #[derive(Clone, Debug, Default)] pub struct TxCompleteBuilder { pub(crate) channel_id: Byte32, + pub(crate) commitment_tx_partial_signature: Byte32, } impl TxCompleteBuilder { - pub const TOTAL_SIZE: usize = 32; - pub const FIELD_SIZES: [usize; 1] = [32]; - pub const FIELD_COUNT: usize = 1; + pub const TOTAL_SIZE: usize = 64; + pub const FIELD_SIZES: [usize; 2] = [32, 32]; + pub const FIELD_COUNT: usize = 2; pub fn channel_id(mut self, v: Byte32) -> Self { self.channel_id = v; self } + pub fn commitment_tx_partial_signature(mut self, v: Byte32) -> Self { + self.commitment_tx_partial_signature = v; + self + } } impl molecule::prelude::Builder for TxCompleteBuilder { type Entity = TxComplete; @@ -6726,6 +6752,7 @@ impl molecule::prelude::Builder for TxCompleteBuilder { } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { writer.write_all(self.channel_id.as_slice())?; + writer.write_all(self.commitment_tx_partial_signature.as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { diff --git a/src/fiber/network.rs b/src/fiber/network.rs index f78672dd1..b5b77dcf4 100644 --- a/src/fiber/network.rs +++ b/src/fiber/network.rs @@ -516,6 +516,8 @@ pub enum NetworkServiceEvent { ChannelCreated(PeerId, Hash256), // A outgoing channel is pending to be accepted. ChannelPendingToBeAccepted(PeerId, Hash256), + // A funding tx is completed. The watch tower may use this to monitor the channel. + RemoteTxComplete(PeerId, Hash256, Script, SettlementData), // A AddTlc peer message processed with failure AddTlcFailed(PeerId, Hash256, TlcErr), // The channel is ready to use (with funding transaction confirmed @@ -3367,50 +3369,57 @@ where match command { // Need to handle the force shutdown command specially because the ChannelActor may not exist when remote peer is disconnected. ChannelCommand::Shutdown(shutdown, rpc_reply) if shutdown.force => { - match self.store.get_channel_actor_state(&channel_id) { - Some(mut state) => { - match state.state { - ChannelState::ChannelReady() => { - debug!("Handling force shutdown command in ChannelReady state"); - } - ChannelState::ShuttingDown(flags) => { - debug!("Handling force shutdown command in ShuttingDown state, flags: {:?}", &flags); - } - _ => { - let error = Error::ChannelError( - ProcessingChannelError::InvalidState(format!( - "Handling force shutdown command invalid state {:?}", - &state.state - )), - ); - - let _ = rpc_reply.send(Err(error.to_string())); - return Err(error); - } - }; + if let Some(actor) = self.channels.get(&channel_id) { + actor.send_message(ChannelActorMessage::Command(ChannelCommand::Shutdown( + shutdown, rpc_reply, + )))?; + Ok(()) + } else { + match self.store.get_channel_actor_state(&channel_id) { + Some(mut state) => { + match state.state { + ChannelState::ChannelReady() => { + debug!("Handling force shutdown command in ChannelReady state"); + } + ChannelState::ShuttingDown(flags) => { + debug!("Handling force shutdown command in ShuttingDown state, flags: {:?}", &flags); + } + _ => { + let error = Error::ChannelError( + ProcessingChannelError::InvalidState(format!( + "Handling force shutdown command invalid state {:?}", + &state.state + )), + ); + + let _ = rpc_reply.send(Err(error.to_string())); + return Err(error); + } + }; - let transaction = state - .latest_commitment_transaction - .clone() - .expect("latest_commitment_transaction should exist when channel is in ChannelReady of ShuttingDown state"); - self.network - .send_message(NetworkActorMessage::new_event( - NetworkActorEvent::CommitmentTransactionPending( - transaction, - channel_id, - ), - )) - .expect(ASSUME_NETWORK_ACTOR_ALIVE); + let transaction = state + .latest_commitment_transaction + .clone() + .expect("latest_commitment_transaction should exist when channel is in ChannelReady of ShuttingDown state"); + self.network + .send_message(NetworkActorMessage::new_event( + NetworkActorEvent::CommitmentTransactionPending( + transaction, + channel_id, + ), + )) + .expect(ASSUME_NETWORK_ACTOR_ALIVE); - state.update_state(ChannelState::ShuttingDown( - ShuttingDownFlags::WAITING_COMMITMENT_CONFIRMATION, - )); - self.store.insert_channel_actor_state(state); + state.update_state(ChannelState::ShuttingDown( + ShuttingDownFlags::WAITING_COMMITMENT_CONFIRMATION, + )); + self.store.insert_channel_actor_state(state); - let _ = rpc_reply.send(Ok(())); - Ok(()) + let _ = rpc_reply.send(Ok(())); + Ok(()) + } + None => Err(Error::ChannelNotFound(channel_id)), } - None => Err(Error::ChannelNotFound(channel_id)), } } _ => match self.channels.get(&channel_id) { diff --git a/src/fiber/schema/fiber.mol b/src/fiber/schema/fiber.mol index dae1d94a7..bbda3cc54 100644 --- a/src/fiber/schema/fiber.mol +++ b/src/fiber/schema/fiber.mol @@ -67,7 +67,8 @@ table TxUpdate { } struct TxComplete { - channel_id: Byte32, + channel_id: Byte32, + commitment_tx_partial_signature: Byte32, } table TxAbort { diff --git a/src/fiber/types.rs b/src/fiber/types.rs index 6fdaea665..0eda150ee 100644 --- a/src/fiber/types.rs +++ b/src/fiber/types.rs @@ -856,12 +856,16 @@ impl TryFrom for TxUpdate { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TxComplete { pub channel_id: Hash256, + pub commitment_tx_partial_signature: PartialSignature, } impl From for molecule_fiber::TxComplete { fn from(tx_complete: TxComplete) -> Self { molecule_fiber::TxComplete::new_builder() .channel_id(tx_complete.channel_id.into()) + .commitment_tx_partial_signature(partial_signature_to_molecule( + tx_complete.commitment_tx_partial_signature, + )) .build() } } @@ -872,6 +876,10 @@ impl TryFrom for TxComplete { fn try_from(tx_complete: molecule_fiber::TxComplete) -> Result { Ok(TxComplete { channel_id: tx_complete.channel_id().into(), + commitment_tx_partial_signature: PartialSignature::from_slice( + tx_complete.commitment_tx_partial_signature().as_slice(), + ) + .map_err(|e| anyhow!(e))?, }) } } diff --git a/src/store/store.rs b/src/store/store.rs index 0dbd2e61d..469dfd5ee 100644 --- a/src/store/store.rs +++ b/src/store/store.rs @@ -619,14 +619,19 @@ impl WatchtowerStore for Store { .collect() } - fn insert_watch_channel(&self, channel_id: Hash256, funding_tx_lock: Script) { + fn insert_watch_channel( + &self, + channel_id: Hash256, + funding_tx_lock: Script, + local_settlement_data: SettlementData, + ) { let key = [&[WATCHTOWER_CHANNEL_PREFIX], channel_id.as_ref()].concat(); let value = serialize_to_vec( &ChannelData { channel_id, funding_tx_lock, + local_settlement_data, revocation_data: None, - local_settlement_data: None, remote_settlement_data: None, }, "ChannelData", @@ -645,28 +650,32 @@ impl WatchtowerStore for Store { &self, channel_id: Hash256, revocation_data: RevocationData, - settlement_data: SettlementData, + local_settlement_data: SettlementData, ) { let key = [&[WATCHTOWER_CHANNEL_PREFIX], channel_id.as_ref()].concat(); if let Some(mut channel_data) = self .get(key) .map(|v| deserialize_from::(v.as_ref(), "ChannelData")) { + channel_data.local_settlement_data = local_settlement_data; channel_data.revocation_data = Some(revocation_data); - channel_data.local_settlement_data = Some(settlement_data); let mut batch = self.batch(); batch.put_kv(KeyValue::WatchtowerChannel(channel_id, channel_data)); batch.commit(); } } - fn update_remote_settlement(&self, channel_id: Hash256, settlement_data: SettlementData) { + fn update_remote_settlement( + &self, + channel_id: Hash256, + remote_settlement_data: SettlementData, + ) { let key = [&[WATCHTOWER_CHANNEL_PREFIX], channel_id.as_ref()].concat(); if let Some(mut channel_data) = self .get(key) .map(|v| deserialize_from::(v.as_ref(), "ChannelData")) { - channel_data.remote_settlement_data = Some(settlement_data); + channel_data.remote_settlement_data = Some(remote_settlement_data); let mut batch = self.batch(); batch.put_kv(KeyValue::WatchtowerChannel(channel_id, channel_data)); batch.commit(); diff --git a/src/store/tests/store.rs b/src/store/tests/store.rs index 950c86490..c31bad5b4 100644 --- a/src/store/tests/store.rs +++ b/src/store/tests/store.rs @@ -187,14 +187,24 @@ fn test_store_wacthtower() { let channel_id = gen_sha256_hash(); let funding_tx_lock = Script::default(); - store.insert_watch_channel(channel_id, funding_tx_lock.clone()); + + let settlement_data = SettlementData { + x_only_aggregated_pubkey: [0u8; 32], + aggregated_signature: CompactSignature::from_bytes(&[0u8; 64]).unwrap(), + to_local_output: CellOutput::default(), + to_local_output_data: Bytes::default(), + to_remote_output: CellOutput::default(), + to_remote_output_data: Bytes::default(), + }; + + store.insert_watch_channel(channel_id, funding_tx_lock.clone(), settlement_data.clone()); assert_eq!( store.get_watch_channels(), vec![ChannelData { channel_id, funding_tx_lock: funding_tx_lock.clone(), revocation_data: None, - local_settlement_data: None, + local_settlement_data: settlement_data.clone(), remote_settlement_data: None, }] ); @@ -207,23 +217,14 @@ fn test_store_wacthtower() { output_data: Bytes::default(), }; - let settlement_data = SettlementData { - x_only_aggregated_pubkey: [0u8; 32], - aggregated_signature: CompactSignature::from_bytes(&[0u8; 64]).unwrap(), - to_local_output: CellOutput::default(), - to_local_output_data: Bytes::default(), - to_remote_output: CellOutput::default(), - to_remote_output_data: Bytes::default(), - }; - store.update_revocation(channel_id, revocation_data.clone(), settlement_data.clone()); assert_eq!( store.get_watch_channels(), vec![ChannelData { channel_id, funding_tx_lock, + local_settlement_data: settlement_data, revocation_data: Some(revocation_data), - local_settlement_data: Some(settlement_data), remote_settlement_data: None, }] ); diff --git a/src/watchtower/actor.rs b/src/watchtower/actor.rs index eb3d1b66f..36c06bd51 100644 --- a/src/watchtower/actor.rs +++ b/src/watchtower/actor.rs @@ -80,47 +80,17 @@ where WatchtowerMessage::NetworkServiceEvent(event) => { trace!("Received NetworkServiceEvent: {:?}", event); match event { - NetworkServiceEvent::ChannelReady( - peer_id, + NetworkServiceEvent::RemoteTxComplete( + _peer_id, channel_id, - funding_tx_out_point, + funding_tx_lock, + settlement_data, ) => { - let rpc_url = state.config.rpc_url.clone(); - tokio::task::block_in_place(move || { - let ckb_client = CkbRpcClient::new(&rpc_url); - match ckb_client - .get_transaction(funding_tx_out_point.tx_hash().unpack()) - { - Ok(Some(tx_with_status)) => { - if tx_with_status.tx_status.status != Status::Committed { - error!("Funding tx: {:?} is not committed yet, maybe it's a bug in the fn on_channel_ready", funding_tx_out_point); - } else if let Some(tx) = tx_with_status.transaction { - match tx.inner { - Either::Left(tx) => { - let tx: Transaction = tx.inner.into(); - self.store.insert_watch_channel( - channel_id, - tx.raw() - .outputs() - .get(0) - .expect("get output 0 of tx") - .lock(), - ); - } - Either::Right(_tx) => { - // unreachable, ignore - } - } - } - } - Ok(None) => { - error!("Cannot find funding tx: {:?} for channel: {:?} from peer: {:?}", funding_tx_out_point, channel_id, peer_id); - } - Err(err) => { - error!("Failed to get funding tx: {:?}", err); - } - } - }); + self.store.insert_watch_channel( + channel_id, + funding_tx_lock, + settlement_data, + ); } NetworkServiceEvent::ChannelClosed(_peer_id, channel_id, _close_tx_hash) => { self.store.remove_watch_channel(channel_id); @@ -160,12 +130,6 @@ where { fn periodic_check(&self, state: &WatchtowerState) { for channel_data in self.store.get_watch_channels() { - if channel_data.revocation_data.is_none() { - continue; - } - let revocation_data = channel_data - .revocation_data - .expect("get channel revocation data"); let secret_key = state.secret_key; let rpc_url = state.config.rpc_url.clone(); tokio::task::block_in_place(move || { @@ -212,67 +176,77 @@ where ); if blake160( - &revocation_data + &channel_data + .local_settlement_data .x_only_aggregated_pubkey, ) .0 == pub_key_hash { - if revocation_data.commitment_number - >= commitment_number + match channel_data + .revocation_data + .clone() { - warn!("Found an old version commitment tx submitted by remote: {:?}, revocation commitment number: {}, commitment number: {}", tx.calc_tx_hash(), revocation_data.commitment_number, commitment_number); - let commitment_tx_out_point = - OutPoint::new( - tx.calc_tx_hash(), - 0, - ); - match build_revocation_tx( - commitment_tx_out_point, - revocation_data, - secret_key, - &mut cell_collector, - ) { - Ok(tx) => { - match ckb_client - .send_transaction( - tx.data().into(), - None, - ) { - Ok(tx_hash) => { - info!("Revocation tx: {:?} sent, tx_hash: {:?}", tx, tx_hash); - } - Err(err) => { - error!("Failed to send revocation tx: {:?}, error: {:?}", tx, err); + Some(revocation_data) + if revocation_data + .commitment_number + >= commitment_number => + { + warn!("Found an old version commitment tx submitted by remote: {:?}, revocation commitment number: {}, commitment number: {}", tx.calc_tx_hash(), revocation_data.commitment_number, commitment_number); + let commitment_tx_out_point = + OutPoint::new( + tx.calc_tx_hash(), + 0, + ); + match build_revocation_tx( + commitment_tx_out_point, + revocation_data, + secret_key, + &mut cell_collector, + ) { + Ok(tx) => { + match ckb_client + .send_transaction( + tx.data() + .into(), + None, + ) { + Ok(tx_hash) => { + info!("Revocation tx: {:?} sent, tx_hash: {:?}", tx, tx_hash); + } + Err(err) => { + error!("Failed to send revocation tx: {:?}, error: {:?}", tx, err); + } } } + Err(err) => { + error!("Failed to build revocation tx: {:?}", err); + } } - Err(err) => { - error!("Failed to build revocation tx: {:?}", err); - } } - } else { - info!("Found a force closed commitment tx submitted by remote: {:?}, revocation commitment number: {}, commitment number: {}", tx.calc_tx_hash(), revocation_data.commitment_number, commitment_number); - try_settle_commitment_tx( - commitment_lock, - ckb_client, - channel_data - .remote_settlement_data - .clone() - .expect("settlement data should be some"), - secret_key, - &mut cell_collector, - ); + _ => { + info!("Found a force closed commitment tx submitted by remote: {:?}, commitment number: {}", tx.calc_tx_hash(), commitment_number); + try_settle_commitment_tx( + commitment_lock, + ckb_client, + channel_data + .local_settlement_data + .clone(), + secret_key, + &mut cell_collector, + ); + } } } else { - // it's a force closed commitment tx which is submitted by local - info!("Found a force closed commitment tx submitted by local: {:?}, revocation commitment number: {}, commitment number: {}", tx.calc_tx_hash(), revocation_data.commitment_number, commitment_number); + info!("Found a force closed commitment tx submitted by local: {:?}, commitment number: {}", tx.calc_tx_hash(), commitment_number); try_settle_commitment_tx( commitment_lock, ckb_client, channel_data - .local_settlement_data + .remote_settlement_data .clone() - .expect("settlement data should be some"), + .expect( + "remote settlement data", + ), secret_key, &mut cell_collector, ); diff --git a/src/watchtower/store.rs b/src/watchtower/store.rs index b693ad395..fefb8babc 100644 --- a/src/watchtower/store.rs +++ b/src/watchtower/store.rs @@ -13,7 +13,12 @@ pub trait WatchtowerStore { fn get_watch_channels(&self) -> Vec; /// Insert a channel's funding tx lock script into the store, it will be used to monitor the channel, /// please note that the lock script should be globally unique, so that the watchtower can identify the channel. - fn insert_watch_channel(&self, channel_id: Hash256, funding_tx_lock: Script); + fn insert_watch_channel( + &self, + channel_id: Hash256, + funding_tx_lock: Script, + local_settlement_data: SettlementData, + ); /// Remove a channel from the store, the watchtower will stop monitoring the channel fn remove_watch_channel(&self, channel_id: Hash256); /// Update the revocation data of a channel, the watchtower will use this data to revoke an old version commitment transaction and settle the local commitment transaction of a force closed channel @@ -21,10 +26,10 @@ pub trait WatchtowerStore { &self, channel_id: Hash256, revocation_data: RevocationData, - settlement_data: SettlementData, + local_settlement_data: SettlementData, ); /// Update the settlement data of a channel, the watchtower will use this data to settle the remote commitment transaction of a force closed channel - fn update_remote_settlement(&self, channel_id: Hash256, settlement_data: SettlementData); + fn update_remote_settlement(&self, channel_id: Hash256, remote_settlement_data: SettlementData); } /// The data of a channel that the watchtower is monitoring @@ -34,7 +39,7 @@ pub struct ChannelData { pub channel_id: Hash256, #[serde_as(as = "EntityHex")] pub funding_tx_lock: Script, + pub local_settlement_data: SettlementData, pub revocation_data: Option, - pub local_settlement_data: Option, pub remote_settlement_data: Option, } diff --git a/tests/bruno/e2e/watchtower/force-close-after-open-channel/01-connect-peer.bru b/tests/bruno/e2e/watchtower/force-close-after-open-channel/01-connect-peer.bru new file mode 100644 index 000000000..7029e544a --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-open-channel/01-connect-peer.bru @@ -0,0 +1,38 @@ +meta { + name: connect peer + type: http + seq: 1 +} + +post { + url: {{NODE2_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "connect_peer", + "params": [ + {"address": "{{NODE1_ADDR}}"} + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result: isNull +} + +script:post-response { + // Dialing a peer is async in tentacle. Sleep for some time to make sure + // we're connected to the peer. + await new Promise(r => setTimeout(r, 1000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-open-channel/02-open-channel.bru b/tests/bruno/e2e/watchtower/force-close-after-open-channel/02-open-channel.bru new file mode 100644 index 000000000..f2f0f8ff9 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-open-channel/02-open-channel.bru @@ -0,0 +1,39 @@ +meta { + name: Node1 open a channel to Node2 + type: http + seq: 2 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "open_channel", + "params": [ + { + "peer_id": "{{NODE2_PEERID}}", + "funding_amount": "0xba43b7400" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result.temporary_channel_id: isDefined +} + +script:post-response { + await new Promise(r => setTimeout(r, 2000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-open-channel/03-get-auto-accepted-channel.bru b/tests/bruno/e2e/watchtower/force-close-after-open-channel/03-get-auto-accepted-channel.bru new file mode 100644 index 000000000..f2834adc2 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-open-channel/03-get-auto-accepted-channel.bru @@ -0,0 +1,40 @@ +meta { + name: get auto accepted channel id from Node1 + type: http + seq: 3 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "list_channels", + "params": [ + { + "peer_id": "{{NODE2_PEERID}}" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result.channels: isDefined +} + +script:post-response { + await new Promise(r => setTimeout(r, 2000)); + console.log(res.body.result); + bru.setVar("CHANNEL_ID", res.body.result.channels.at(-1).channel_id); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-open-channel/04-generate-a-few-blocks.bru b/tests/bruno/e2e/watchtower/force-close-after-open-channel/04-generate-a-few-blocks.bru new file mode 100644 index 000000000..9da68c5c0 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-open-channel/04-generate-a-few-blocks.bru @@ -0,0 +1,33 @@ +meta { + name: generate a few blocks + type: http + seq: 4 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x1"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-open-channel/05-force-close.bru b/tests/bruno/e2e/watchtower/force-close-after-open-channel/05-force-close.bru new file mode 100644 index 000000000..3e92cac4a --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-open-channel/05-force-close.bru @@ -0,0 +1,40 @@ +meta { + name: Node1 force close channel + type: http + seq: 5 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "shutdown_channel", + "params": [ + { + "channel_id": "{{CHANNEL_ID}}", + "close_script": { + "code_hash": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a", + "hash_type": "data", + "args": "0x0101010101010101010101010101010101010101" + }, + "fee_rate": "0x3FC", + "force": true + } + ] + } +} + +script:post-response { + console.log(res.body); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-open-channel/06-get-force-closed-commitment-tx-hash.bru b/tests/bruno/e2e/watchtower/force-close-after-open-channel/06-get-force-closed-commitment-tx-hash.bru new file mode 100644 index 000000000..0a66c753a --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-open-channel/06-get-force-closed-commitment-tx-hash.bru @@ -0,0 +1,39 @@ +meta { + name: get force closed commitment tx hash + type: http + seq: 6 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "list_channels", + "params": [ + { + "peer_id": "{{NODE2_PEERID}}" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result.channels: isDefined +} + +script:post-response { + console.log(res.body.result); + bru.setVar("TX_HASH", res.body.result.channels.at(-1).latest_commitment_transaction_hash); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-open-channel/07-generate-a-few-blocks-for-commitment-tx.bru b/tests/bruno/e2e/watchtower/force-close-after-open-channel/07-generate-a-few-blocks-for-commitment-tx.bru new file mode 100644 index 000000000..ddcbad26d --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-open-channel/07-generate-a-few-blocks-for-commitment-tx.bru @@ -0,0 +1,34 @@ +meta { + name: generate a few blocks for commitment tx + type: http + seq: 7 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x1"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + // Wait for the commitment tx to be included in a block + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-open-channel/08-generate-a-few-blocks-for-settlement-tx-generated.bru b/tests/bruno/e2e/watchtower/force-close-after-open-channel/08-generate-a-few-blocks-for-settlement-tx-generated.bru new file mode 100644 index 000000000..a74408d6d --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-open-channel/08-generate-a-few-blocks-for-settlement-tx-generated.bru @@ -0,0 +1,34 @@ +meta { + name: generate a few blocks for watchtower to generate settlement tx, default delay epoch is 6 epochs + type: http + seq: 8 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x7"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + // Wait for the commitment tx to be revoked by the watchtower + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-open-channel/09-generate-a-few-blocks-for-settlement-tx-committed.bru b/tests/bruno/e2e/watchtower/force-close-after-open-channel/09-generate-a-few-blocks-for-settlement-tx-committed.bru new file mode 100644 index 000000000..48de6ed48 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-open-channel/09-generate-a-few-blocks-for-settlement-tx-committed.bru @@ -0,0 +1,33 @@ +meta { + name: generate a few blocks for settlement tx to be committed + type: http + seq: 9 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x1"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-open-channel/10-check-commitment-tx.bru b/tests/bruno/e2e/watchtower/force-close-after-open-channel/10-check-commitment-tx.bru new file mode 100644 index 000000000..620e2284f --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-open-channel/10-check-commitment-tx.bru @@ -0,0 +1,39 @@ +meta { + name: check submitted commitment tx should be settled + type: http + seq: 10 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "get_live_cell", + "params": [ + { + "index": "0x0", + "tx_hash": "{{TX_HASH}}" + }, + false + ] + } +} + +assert { + res.body.result.status: eq "unknown" +} + +script:post-response { + console.log("generated result: ", res.body); +} From 85a7f433b44b49d36f0b83d53b6734e96f37a56b Mon Sep 17 00:00:00 2001 From: quake Date: Fri, 13 Dec 2024 09:26:25 +0900 Subject: [PATCH 5/8] fix: try to fix force close bug --- src/fiber/channel.rs | 8 +-- src/store/store.rs | 18 ++--- src/store/tests/store.rs | 8 +-- src/watchtower/actor.rs | 8 +-- src/watchtower/store.rs | 14 ++-- .../01-connect-peer.bru | 38 +++++++++++ .../02-open-channel.bru | 39 +++++++++++ .../03-get-auto-accepted-channel.bru | 40 ++++++++++++ .../04-generate-a-few-blocks.bru | 33 ++++++++++ .../05-node2-gen-invoice.bru | 65 +++++++++++++++++++ .../06-node1-send-payment-with-invoice.bru | 45 +++++++++++++ .../07-node1-gen-invoice.bru | 65 +++++++++++++++++++ .../08-node2-send-payment-with-invoice.bru | 45 +++++++++++++ .../09-force-close.bru | 40 ++++++++++++ ...enerate-a-few-blocks-for-commitment-tx.bru | 34 ++++++++++ ...few-blocks-for-settlement-tx-generated.bru | 34 ++++++++++ ...few-blocks-for-settlement-tx-committed.bru | 33 ++++++++++ ...13-get-force-closed-commitment-tx-hash.bru | 39 +++++++++++ .../14-check-commitment-tx.bru | 39 +++++++++++ .../force-close/05-node2-gen-invoice.bru | 2 +- 20 files changed, 616 insertions(+), 31 deletions(-) create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/01-connect-peer.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/02-open-channel.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/03-get-auto-accepted-channel.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/04-generate-a-few-blocks.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/05-node2-gen-invoice.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/06-node1-send-payment-with-invoice.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/07-node1-gen-invoice.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/08-node2-send-payment-with-invoice.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/09-force-close.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/10-generate-a-few-blocks-for-commitment-tx.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/11-generate-a-few-blocks-for-settlement-tx-generated.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/12-generate-a-few-blocks-for-settlement-tx-committed.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/13-get-force-closed-commitment-tx-hash.bru create mode 100644 tests/bruno/e2e/watchtower/force-close-after-multiple-payments/14-check-commitment-tx.bru diff --git a/src/fiber/channel.rs b/src/fiber/channel.rs index 5aa55324c..622ff6036 100644 --- a/src/fiber/channel.rs +++ b/src/fiber/channel.rs @@ -4298,16 +4298,16 @@ impl ChannelActorState { self.commitment_numbers.increment_remote(); } - pub fn get_current_commitment_number(&self, local: bool) -> u64 { - if local { + pub fn get_current_commitment_number(&self, for_remote: bool) -> u64 { + if for_remote { self.get_local_commitment_number() } else { self.get_remote_commitment_number() } } - pub fn get_next_commitment_number(&self, local: bool) -> u64 { - self.get_current_commitment_number(local) + 1 + pub fn get_next_commitment_number(&self, for_remote: bool) -> u64 { + self.get_current_commitment_number(for_remote) + 1 } pub fn get_next_offering_tlc_id(&self) -> u64 { diff --git a/src/store/store.rs b/src/store/store.rs index 469dfd5ee..fc1a187ed 100644 --- a/src/store/store.rs +++ b/src/store/store.rs @@ -623,16 +623,16 @@ impl WatchtowerStore for Store { &self, channel_id: Hash256, funding_tx_lock: Script, - local_settlement_data: SettlementData, + remote_settlement_data: SettlementData, ) { let key = [&[WATCHTOWER_CHANNEL_PREFIX], channel_id.as_ref()].concat(); let value = serialize_to_vec( &ChannelData { channel_id, funding_tx_lock, - local_settlement_data, + remote_settlement_data, + local_settlement_data: None, revocation_data: None, - remote_settlement_data: None, }, "ChannelData", ); @@ -650,14 +650,14 @@ impl WatchtowerStore for Store { &self, channel_id: Hash256, revocation_data: RevocationData, - local_settlement_data: SettlementData, + remote_settlement_data: SettlementData, ) { let key = [&[WATCHTOWER_CHANNEL_PREFIX], channel_id.as_ref()].concat(); if let Some(mut channel_data) = self .get(key) .map(|v| deserialize_from::(v.as_ref(), "ChannelData")) { - channel_data.local_settlement_data = local_settlement_data; + channel_data.remote_settlement_data = remote_settlement_data; channel_data.revocation_data = Some(revocation_data); let mut batch = self.batch(); batch.put_kv(KeyValue::WatchtowerChannel(channel_id, channel_data)); @@ -665,17 +665,13 @@ impl WatchtowerStore for Store { } } - fn update_remote_settlement( - &self, - channel_id: Hash256, - remote_settlement_data: SettlementData, - ) { + fn update_local_settlement(&self, channel_id: Hash256, local_settlement_data: SettlementData) { let key = [&[WATCHTOWER_CHANNEL_PREFIX], channel_id.as_ref()].concat(); if let Some(mut channel_data) = self .get(key) .map(|v| deserialize_from::(v.as_ref(), "ChannelData")) { - channel_data.remote_settlement_data = Some(remote_settlement_data); + channel_data.local_settlement_data = Some(local_settlement_data); let mut batch = self.batch(); batch.put_kv(KeyValue::WatchtowerChannel(channel_id, channel_data)); batch.commit(); diff --git a/src/store/tests/store.rs b/src/store/tests/store.rs index c31bad5b4..0a45140d6 100644 --- a/src/store/tests/store.rs +++ b/src/store/tests/store.rs @@ -204,8 +204,8 @@ fn test_store_wacthtower() { channel_id, funding_tx_lock: funding_tx_lock.clone(), revocation_data: None, - local_settlement_data: settlement_data.clone(), - remote_settlement_data: None, + local_settlement_data: None, + remote_settlement_data: settlement_data.clone(), }] ); @@ -223,9 +223,9 @@ fn test_store_wacthtower() { vec![ChannelData { channel_id, funding_tx_lock, - local_settlement_data: settlement_data, + local_settlement_data: None, revocation_data: Some(revocation_data), - remote_settlement_data: None, + remote_settlement_data: settlement_data, }] ); diff --git a/src/watchtower/actor.rs b/src/watchtower/actor.rs index 36c06bd51..28e714c82 100644 --- a/src/watchtower/actor.rs +++ b/src/watchtower/actor.rs @@ -111,7 +111,7 @@ where settlement_data, ) => { self.store - .update_remote_settlement(channel_id, settlement_data); + .update_local_settlement(channel_id, settlement_data); } _ => { // ignore @@ -177,7 +177,7 @@ where if blake160( &channel_data - .local_settlement_data + .remote_settlement_data .x_only_aggregated_pubkey, ) .0 == pub_key_hash @@ -229,7 +229,7 @@ where commitment_lock, ckb_client, channel_data - .local_settlement_data + .remote_settlement_data .clone(), secret_key, &mut cell_collector, @@ -242,7 +242,7 @@ where commitment_lock, ckb_client, channel_data - .remote_settlement_data + .local_settlement_data .clone() .expect( "remote settlement data", diff --git a/src/watchtower/store.rs b/src/watchtower/store.rs index fefb8babc..1113bb8f5 100644 --- a/src/watchtower/store.rs +++ b/src/watchtower/store.rs @@ -17,19 +17,19 @@ pub trait WatchtowerStore { &self, channel_id: Hash256, funding_tx_lock: Script, - local_settlement_data: SettlementData, + remote_settlement_data: SettlementData, ); /// Remove a channel from the store, the watchtower will stop monitoring the channel fn remove_watch_channel(&self, channel_id: Hash256); - /// Update the revocation data of a channel, the watchtower will use this data to revoke an old version commitment transaction and settle the local commitment transaction of a force closed channel + /// Update the revocation data of a channel, the watchtower will use this data to revoke an old version commitment transaction and settle the remote commitment transaction of a force closed channel fn update_revocation( &self, channel_id: Hash256, revocation_data: RevocationData, - local_settlement_data: SettlementData, + remote_settlement_data: SettlementData, ); - /// Update the settlement data of a channel, the watchtower will use this data to settle the remote commitment transaction of a force closed channel - fn update_remote_settlement(&self, channel_id: Hash256, remote_settlement_data: SettlementData); + /// Update the settlement data of a channel, the watchtower will use this data to settle the local commitment transaction of a force closed channel + fn update_local_settlement(&self, channel_id: Hash256, local_settlement_data: SettlementData); } /// The data of a channel that the watchtower is monitoring @@ -39,7 +39,7 @@ pub struct ChannelData { pub channel_id: Hash256, #[serde_as(as = "EntityHex")] pub funding_tx_lock: Script, - pub local_settlement_data: SettlementData, + pub remote_settlement_data: SettlementData, + pub local_settlement_data: Option, pub revocation_data: Option, - pub remote_settlement_data: Option, } diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/01-connect-peer.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/01-connect-peer.bru new file mode 100644 index 000000000..7029e544a --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/01-connect-peer.bru @@ -0,0 +1,38 @@ +meta { + name: connect peer + type: http + seq: 1 +} + +post { + url: {{NODE2_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "connect_peer", + "params": [ + {"address": "{{NODE1_ADDR}}"} + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result: isNull +} + +script:post-response { + // Dialing a peer is async in tentacle. Sleep for some time to make sure + // we're connected to the peer. + await new Promise(r => setTimeout(r, 1000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/02-open-channel.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/02-open-channel.bru new file mode 100644 index 000000000..f2f0f8ff9 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/02-open-channel.bru @@ -0,0 +1,39 @@ +meta { + name: Node1 open a channel to Node2 + type: http + seq: 2 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "open_channel", + "params": [ + { + "peer_id": "{{NODE2_PEERID}}", + "funding_amount": "0xba43b7400" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result.temporary_channel_id: isDefined +} + +script:post-response { + await new Promise(r => setTimeout(r, 2000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/03-get-auto-accepted-channel.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/03-get-auto-accepted-channel.bru new file mode 100644 index 000000000..f2834adc2 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/03-get-auto-accepted-channel.bru @@ -0,0 +1,40 @@ +meta { + name: get auto accepted channel id from Node1 + type: http + seq: 3 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "list_channels", + "params": [ + { + "peer_id": "{{NODE2_PEERID}}" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result.channels: isDefined +} + +script:post-response { + await new Promise(r => setTimeout(r, 2000)); + console.log(res.body.result); + bru.setVar("CHANNEL_ID", res.body.result.channels.at(-1).channel_id); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/04-generate-a-few-blocks.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/04-generate-a-few-blocks.bru new file mode 100644 index 000000000..9da68c5c0 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/04-generate-a-few-blocks.bru @@ -0,0 +1,33 @@ +meta { + name: generate a few blocks + type: http + seq: 4 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x1"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/05-node2-gen-invoice.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/05-node2-gen-invoice.bru new file mode 100644 index 000000000..c629c51e4 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/05-node2-gen-invoice.bru @@ -0,0 +1,65 @@ +meta { + name: generate a invoice + type: http + seq: 5 +} + +post { + url: {{NODE2_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "new_invoice", + "params": [ + { + "amount": "0x2dc6c0", + "currency": "Fibd", + "description": "test invoice generated by node2", + "expiry": "0xe10", + "final_expiry_delta": "0xDFFA0", + "payment_preimage": "{{payment_preimage}}" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result: isDefined +} + +script:pre-request { + // generate random preimage + function generateRandomPreimage() { + let hash = '0x'; + for (let i = 0; i < 64; i++) { + hash += Math.floor(Math.random() * 16).toString(16); + } + return hash; + } + const payment_preimage = generateRandomPreimage(); + bru.setVar("payment_preimage", payment_preimage); + let hash_algorithm = bru.getEnvVar("HASH_ALGORITHM"); + if (hash_algorithm !== null) { + let body = req.getBody(); + body.params[0].hash_algorithm = hash_algorithm; + req.setBody(body); + } +} + +script:post-response { + console.log("generated result: ", res.body.result); + bru.setVar("encoded_invoice", res.body.result.invoice_address); + // Sleep for sometime to make sure current operation finishes before next request starts. + await new Promise(r => setTimeout(r, 1000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/06-node1-send-payment-with-invoice.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/06-node1-send-payment-with-invoice.bru new file mode 100644 index 000000000..2fd533e03 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/06-node1-send-payment-with-invoice.bru @@ -0,0 +1,45 @@ +meta { + name: Node1 send payment with invoice + type: http + seq: 6 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "send_payment", + "params": [ + { + "invoice": "{{encoded_invoice}}" + } + ] + } +} + +assert { + res.body.error: isUndefined +} + + +script:pre-request { + // sleep for a while + await new Promise(r => setTimeout(r, 1000)); +} + + +script:post-response { + // Sleep for sometime to make sure current operation finishes before next request starts. + await new Promise(r => setTimeout(r, 1000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/07-node1-gen-invoice.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/07-node1-gen-invoice.bru new file mode 100644 index 000000000..7c777284d --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/07-node1-gen-invoice.bru @@ -0,0 +1,65 @@ +meta { + name: generate a invoice + type: http + seq: 7 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "new_invoice", + "params": [ + { + "amount": "0x2dc6c0", + "currency": "Fibd", + "description": "test invoice generated by node1", + "expiry": "0xe10", + "final_expiry_delta": "0xDFFA0", + "payment_preimage": "{{payment_preimage}}" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result: isDefined +} + +script:pre-request { + // generate random preimage + function generateRandomPreimage() { + let hash = '0x'; + for (let i = 0; i < 64; i++) { + hash += Math.floor(Math.random() * 16).toString(16); + } + return hash; + } + const payment_preimage = generateRandomPreimage(); + bru.setVar("payment_preimage", payment_preimage); + let hash_algorithm = bru.getEnvVar("HASH_ALGORITHM"); + if (hash_algorithm !== null) { + let body = req.getBody(); + body.params[0].hash_algorithm = hash_algorithm; + req.setBody(body); + } +} + +script:post-response { + console.log("generated result: ", res.body.result); + bru.setVar("encoded_invoice", res.body.result.invoice_address); + // Sleep for sometime to make sure current operation finishes before next request starts. + await new Promise(r => setTimeout(r, 1000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/08-node2-send-payment-with-invoice.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/08-node2-send-payment-with-invoice.bru new file mode 100644 index 000000000..b6863e5f6 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/08-node2-send-payment-with-invoice.bru @@ -0,0 +1,45 @@ +meta { + name: Node2 send payment with invoice + type: http + seq: 8 +} + +post { + url: {{NODE2_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "send_payment", + "params": [ + { + "invoice": "{{encoded_invoice}}" + } + ] + } +} + +assert { + res.body.error: isUndefined +} + + +script:pre-request { + // sleep for a while + await new Promise(r => setTimeout(r, 1000)); +} + + +script:post-response { + // Sleep for sometime to make sure current operation finishes before next request starts. + await new Promise(r => setTimeout(r, 1000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/09-force-close.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/09-force-close.bru new file mode 100644 index 000000000..309e8dfc6 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/09-force-close.bru @@ -0,0 +1,40 @@ +meta { + name: Node1 force close channel + type: http + seq: 9 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "shutdown_channel", + "params": [ + { + "channel_id": "{{CHANNEL_ID}}", + "close_script": { + "code_hash": "0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a", + "hash_type": "data", + "args": "0x0101010101010101010101010101010101010101" + }, + "fee_rate": "0x3FC", + "force": true + } + ] + } +} + +script:post-response { + console.log(res.body); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/10-generate-a-few-blocks-for-commitment-tx.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/10-generate-a-few-blocks-for-commitment-tx.bru new file mode 100644 index 000000000..a3392fc9b --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/10-generate-a-few-blocks-for-commitment-tx.bru @@ -0,0 +1,34 @@ +meta { + name: generate a few blocks for commitment tx + type: http + seq: 10 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x1"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + // Wait for the commitment tx to be included in a block + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/11-generate-a-few-blocks-for-settlement-tx-generated.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/11-generate-a-few-blocks-for-settlement-tx-generated.bru new file mode 100644 index 000000000..281a7f737 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/11-generate-a-few-blocks-for-settlement-tx-generated.bru @@ -0,0 +1,34 @@ +meta { + name: generate a few blocks for watchtower to generate settlement tx, default delay epoch is 6 epochs + type: http + seq: 11 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x7"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + // Wait for the commitment tx to be revoked by the watchtower + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/12-generate-a-few-blocks-for-settlement-tx-committed.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/12-generate-a-few-blocks-for-settlement-tx-committed.bru new file mode 100644 index 000000000..c1a62c044 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/12-generate-a-few-blocks-for-settlement-tx-committed.bru @@ -0,0 +1,33 @@ +meta { + name: generate a few blocks for settlement tx to be committed + type: http + seq: 12 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "generate_epochs", + "params": ["0x1"] + } +} + +assert { + res.status: eq 200 +} + +script:post-response { + await new Promise(r => setTimeout(r, 5000)); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/13-get-force-closed-commitment-tx-hash.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/13-get-force-closed-commitment-tx-hash.bru new file mode 100644 index 000000000..bfae2fec1 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/13-get-force-closed-commitment-tx-hash.bru @@ -0,0 +1,39 @@ +meta { + name: get force closed commitment tx hash + type: http + seq: 13 +} + +post { + url: {{NODE1_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": "42", + "jsonrpc": "2.0", + "method": "list_channels", + "params": [ + { + "peer_id": "{{NODE2_PEERID}}" + } + ] + } +} + +assert { + res.body.error: isUndefined + res.body.result.channels: isDefined +} + +script:post-response { + console.log(res.body.result); + bru.setVar("TX_HASH", res.body.result.channels.at(-1).latest_commitment_transaction_hash); +} diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/14-check-commitment-tx.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/14-check-commitment-tx.bru new file mode 100644 index 000000000..93093cc57 --- /dev/null +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/14-check-commitment-tx.bru @@ -0,0 +1,39 @@ +meta { + name: check submitted commitment tx should be settled + type: http + seq: 14 +} + +post { + url: {{CKB_RPC_URL}} + body: json + auth: none +} + +headers { + Content-Type: application/json + Accept: application/json +} + +body:json { + { + "id": 42, + "jsonrpc": "2.0", + "method": "get_live_cell", + "params": [ + { + "index": "0x0", + "tx_hash": "{{TX_HASH}}" + }, + false + ] + } +} + +assert { + res.body.result.status: eq "unknown" +} + +script:post-response { + console.log("generated result: ", res.body); +} diff --git a/tests/bruno/e2e/watchtower/force-close/05-node2-gen-invoice.bru b/tests/bruno/e2e/watchtower/force-close/05-node2-gen-invoice.bru index f17c31ba5..c629c51e4 100644 --- a/tests/bruno/e2e/watchtower/force-close/05-node2-gen-invoice.bru +++ b/tests/bruno/e2e/watchtower/force-close/05-node2-gen-invoice.bru @@ -24,7 +24,7 @@ body:json { { "amount": "0x2dc6c0", "currency": "Fibd", - "description": "test invoice generated by node3", + "description": "test invoice generated by node2", "expiry": "0xe10", "final_expiry_delta": "0xDFFA0", "payment_preimage": "{{payment_preimage}}" From 888f81b8c8d6ffc7beb8a76a88fccf9ee0288228 Mon Sep 17 00:00:00 2001 From: quake Date: Sat, 14 Dec 2024 20:54:08 +0900 Subject: [PATCH 6/8] chore: tweak log and add more e2e test --- src/fiber/channel.rs | 10 -- src/rpc/README.md | 1 + src/rpc/channel.rs | 11 +- src/watchtower/actor.rs | 134 ++++++++++++------ .../07-node1-gen-invoice.bru | 2 +- ...13-get-force-closed-commitment-tx-hash.bru | 5 +- ...06-get-force-closed-commitment-tx-hash.bru | 5 +- ...08-get-force-closed-commitment-tx-hash.bru | 5 +- 8 files changed, 106 insertions(+), 67 deletions(-) diff --git a/src/fiber/channel.rs b/src/fiber/channel.rs index 622ff6036..f0b654542 100644 --- a/src/fiber/channel.rs +++ b/src/fiber/channel.rs @@ -1184,7 +1184,6 @@ where state.tlc_state.add_local_tlc(tlc.clone()); state.increment_next_offered_tlc_id(); - debug!("Inserted tlc into channel state: {:?}", &tlc); let add_tlc = AddTlc { channel_id: state.get_id(), tlc_id: tlc.tlc_id().into(), @@ -1198,7 +1197,6 @@ where // Send tlc update message to peer. let msg = FiberMessageWithPeerId::new(state.get_remote_peer_id(), FiberMessage::add_tlc(add_tlc)); - debug!("Sending AddTlc message: {:?}", &msg); self.network .send_message(NetworkActorMessage::new_command( @@ -4377,14 +4375,6 @@ impl ChannelActorState { ))); } } - debug!( - "Adding new tlc {:?} to channel {:?} with local balance {} and remote balance {}", - &tlc, - &self.get_id(), - self.to_local_amount, - self.to_remote_amount - ); - Ok(()) } diff --git a/src/rpc/README.md b/src/rpc/README.md index d31f46b8b..5a0393987 100644 --- a/src/rpc/README.md +++ b/src/rpc/README.md @@ -212,6 +212,7 @@ Lists all channels. ##### Params * `peer_id` - `Option`, The peer ID to list channels for, an optional parameter, if not provided, all channels will be listed +* `include_closed` - `Option`, Whether to include closed channels in the list, an optional parameter, default value is false ##### Returns diff --git a/src/rpc/channel.rs b/src/rpc/channel.rs index 35e3bdef6..5f1e53c78 100644 --- a/src/rpc/channel.rs +++ b/src/rpc/channel.rs @@ -159,6 +159,8 @@ pub(crate) struct ListChannelsParams { /// The peer ID to list channels for, an optional parameter, if not provided, all channels will be listed #[serde_as(as = "Option")] peer_id: Option, + /// Whether to include closed channels in the list, an optional parameter, default value is false + include_closed: Option, } #[derive(Clone, Serialize)] @@ -559,9 +561,12 @@ where &self, params: ListChannelsParams, ) -> Result { - let mut channels: Vec<_> = self - .store - .get_active_channel_states(params.peer_id) + let channel_states = if params.include_closed.unwrap_or_default() { + self.store.get_channel_states(params.peer_id) + } else { + self.store.get_active_channel_states(params.peer_id) + }; + let mut channels: Vec<_> = channel_states .into_iter() .filter_map(|(peer_id, channel_id, _state)| { self.store diff --git a/src/watchtower/actor.rs b/src/watchtower/actor.rs index 28e714c82..7d06ebccd 100644 --- a/src/watchtower/actor.rs +++ b/src/watchtower/actor.rs @@ -10,7 +10,7 @@ use ckb_sdk::{ }; use ckb_types::{ self, - core::{Capacity, TransactionView}, + core::{Capacity, EpochNumberWithFraction, HeaderView, TransactionView}, packed::{Bytes, CellInput, CellOutput, OutPoint, Script, Transaction, WitnessArgs}, prelude::*, }; @@ -191,40 +191,56 @@ where .commitment_number >= commitment_number => { - warn!("Found an old version commitment tx submitted by remote: {:?}, revocation commitment number: {}, commitment number: {}", tx.calc_tx_hash(), revocation_data.commitment_number, commitment_number); let commitment_tx_out_point = OutPoint::new( tx.calc_tx_hash(), 0, ); - match build_revocation_tx( - commitment_tx_out_point, - revocation_data, - secret_key, - &mut cell_collector, + match ckb_client.get_live_cell( + commitment_tx_out_point + .clone() + .into(), + false, ) { - Ok(tx) => { - match ckb_client - .send_transaction( - tx.data() - .into(), - None, + Ok(cell_with_status) => { + if cell_with_status + .status + == "live" + { + warn!("Found an old version commitment tx submitted by remote: {:#x}", tx.calc_tx_hash()); + match build_revocation_tx( + commitment_tx_out_point, + revocation_data, + secret_key, + &mut cell_collector, ) { - Ok(tx_hash) => { - info!("Revocation tx: {:?} sent, tx_hash: {:?}", tx, tx_hash); - } - Err(err) => { - error!("Failed to send revocation tx: {:?}, error: {:?}", tx, err); + Ok(tx) => { + match ckb_client + .send_transaction( + tx.data() + .into(), + None, + ) { + Ok(tx_hash) => { + info!("Revocation tx: {:?} sent, tx_hash: {:?}", tx, tx_hash); + } + Err(err) => { + error!("Failed to send revocation tx: {:?}, error: {:?}", tx, err); + } + } + } + Err(err) => { + error!("Failed to build revocation tx: {:?}", err); + } } } } Err(err) => { - error!("Failed to build revocation tx: {:?}", err); + error!("Failed to get live cell: {:?}", err); } } } _ => { - info!("Found a force closed commitment tx submitted by remote: {:?}, commitment number: {}", tx.calc_tx_hash(), commitment_number); try_settle_commitment_tx( commitment_lock, ckb_client, @@ -237,7 +253,6 @@ where } } } else { - info!("Found a force closed commitment tx submitted by local: {:?}, commitment number: {}", tx.calc_tx_hash(), commitment_number); try_settle_commitment_tx( commitment_lock, ckb_client, @@ -376,6 +391,17 @@ fn try_settle_commitment_tx( secret_key: SecretKey, cell_collector: &mut DefaultCellCollector, ) { + let current_epoch = match ckb_client.get_tip_header() { + Ok(tip_header) => { + let tip_header: HeaderView = tip_header.into(); + tip_header.epoch() + } + Err(err) => { + error!("Failed to get tip header: {:?}", err); + return; + } + }; + let lock_args = commitment_lock.args().raw_data(); let script = commitment_lock .as_builder() @@ -389,7 +415,6 @@ fn try_settle_commitment_tx( filter: None, group_by_transaction: None, }; - // the live cells number should be 1 or 0 for normal case, however, an attacker may create a lot of cells to implement a tx pinning attack. match ckb_client.get_cells(search_key, Order::Desc, 100u32.into(), None) { Ok(cells) => { @@ -398,34 +423,48 @@ fn try_settle_commitment_tx( let commitment_tx_out_point = OutPoint::new(cell.out_point.tx_hash.pack(), cell.out_point.index.value()); let lock_script_args = cell_output.lock().args().raw_data(); - if lock_script_args.len() == 36 { - let since = u64::from_le_bytes( - cell_output.lock().args().raw_data()[20..28] - .try_into() - .expect("u64 from slice"), - ); - // TODO check since - match build_settlement_tx( - commitment_tx_out_point, - since, - settlement_data.clone(), - secret_key, - cell_collector, - ) { - Ok(tx) => match ckb_client.send_transaction(tx.data().into(), None) { - Ok(tx_hash) => { - info!("Settlement tx: {:?} sent, tx_hash: {:?}", tx, tx_hash); - } - Err(err) => { - error!("Failed to send settlement tx: {:?}, error: {:?}", tx, err); - } - }, + let since = u64::from_le_bytes( + lock_script_args[20..28].try_into().expect("u64 from slice"), + ); + let header: HeaderView = match ckb_client.get_header_by_number(cell.block_number) { + Ok(Some(header)) => header.into(), + Ok(None) => { + error!("Cannot find header: {}", cell.block_number); + continue; + } + Err(err) => { + error!("Failed to get header: {:?}", err); + continue; + } + }; + let since_epoch = EpochNumberWithFraction::from_full_value(since); + if header.epoch().to_rational() + since_epoch.to_rational() + > current_epoch.to_rational() + { + continue; + } + info!( + "Found a force closed commitment tx: {:#x}", + cell.out_point.tx_hash + ); + match build_settlement_tx( + commitment_tx_out_point, + since, + settlement_data.clone(), + secret_key, + cell_collector, + ) { + Ok(tx) => match ckb_client.send_transaction(tx.data().into(), None) { + Ok(tx_hash) => { + info!("Settlement tx: {:?} sent, tx_hash: {:#x}", tx, tx_hash); + } Err(err) => { - error!("Failed to build settlement tx: {:?}", err); + error!("Failed to send settlement tx: {:?}, error: {:?}", tx, err); } + }, + Err(err) => { + error!("Failed to build settlement tx: {:?}", err); } - } else { - // TODO use 0x00 ~ 0xFD to get back the funds } } } @@ -442,6 +481,7 @@ fn build_settlement_tx( secret_key: SecretKey, cell_collector: &mut DefaultCellCollector, ) -> Result> { + // TODO use 0x00 ~ 0xFD to get back the funds let pubkey = PublicKey::from_secret_key(&Secp256k1::new(), &secret_key); let args = blake160(pubkey.serialize().as_ref()); let fee_provider_lock_script = get_script_by_contract(Contract::Secp256k1Lock, args.as_bytes()); diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/07-node1-gen-invoice.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/07-node1-gen-invoice.bru index 7c777284d..cc7b57373 100644 --- a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/07-node1-gen-invoice.bru +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/07-node1-gen-invoice.bru @@ -22,7 +22,7 @@ body:json { "method": "new_invoice", "params": [ { - "amount": "0x2dc6c0", + "amount": "0x42", "currency": "Fibd", "description": "test invoice generated by node1", "expiry": "0xe10", diff --git a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/13-get-force-closed-commitment-tx-hash.bru b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/13-get-force-closed-commitment-tx-hash.bru index bfae2fec1..227a19c13 100644 --- a/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/13-get-force-closed-commitment-tx-hash.bru +++ b/tests/bruno/e2e/watchtower/force-close-after-multiple-payments/13-get-force-closed-commitment-tx-hash.bru @@ -22,7 +22,8 @@ body:json { "method": "list_channels", "params": [ { - "peer_id": "{{NODE2_PEERID}}" + "peer_id": "{{NODE2_PEERID}}", + "include_closed": true } ] } @@ -35,5 +36,5 @@ assert { script:post-response { console.log(res.body.result); - bru.setVar("TX_HASH", res.body.result.channels.at(-1).latest_commitment_transaction_hash); + bru.setVar("TX_HASH", res.body.result.channels[0].latest_commitment_transaction_hash); } diff --git a/tests/bruno/e2e/watchtower/force-close-after-open-channel/06-get-force-closed-commitment-tx-hash.bru b/tests/bruno/e2e/watchtower/force-close-after-open-channel/06-get-force-closed-commitment-tx-hash.bru index 0a66c753a..99fffafa4 100644 --- a/tests/bruno/e2e/watchtower/force-close-after-open-channel/06-get-force-closed-commitment-tx-hash.bru +++ b/tests/bruno/e2e/watchtower/force-close-after-open-channel/06-get-force-closed-commitment-tx-hash.bru @@ -22,7 +22,8 @@ body:json { "method": "list_channels", "params": [ { - "peer_id": "{{NODE2_PEERID}}" + "peer_id": "{{NODE2_PEERID}}", + "include_closed": true } ] } @@ -35,5 +36,5 @@ assert { script:post-response { console.log(res.body.result); - bru.setVar("TX_HASH", res.body.result.channels.at(-1).latest_commitment_transaction_hash); + bru.setVar("TX_HASH", res.body.result.channels[0].latest_commitment_transaction_hash); } diff --git a/tests/bruno/e2e/watchtower/force-close/08-get-force-closed-commitment-tx-hash.bru b/tests/bruno/e2e/watchtower/force-close/08-get-force-closed-commitment-tx-hash.bru index 09df4692d..d60115854 100644 --- a/tests/bruno/e2e/watchtower/force-close/08-get-force-closed-commitment-tx-hash.bru +++ b/tests/bruno/e2e/watchtower/force-close/08-get-force-closed-commitment-tx-hash.bru @@ -22,7 +22,8 @@ body:json { "method": "list_channels", "params": [ { - "peer_id": "{{NODE2_PEERID}}" + "peer_id": "{{NODE2_PEERID}}", + "include_closed": true } ] } @@ -35,5 +36,5 @@ assert { script:post-response { console.log(res.body.result); - bru.setVar("TX_HASH", res.body.result.channels.at(-1).latest_commitment_transaction_hash); + bru.setVar("TX_HASH", res.body.result.channels[0].latest_commitment_transaction_hash); } From 6089a861b43f21d01ed1555004ff9fe39d54b6a4 Mon Sep 17 00:00:00 2001 From: quake Date: Sat, 14 Dec 2024 21:06:45 +0900 Subject: [PATCH 7/8] chore: resolve rebase error --- src/fiber/network.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fiber/network.rs b/src/fiber/network.rs index b5b77dcf4..ef6533afa 100644 --- a/src/fiber/network.rs +++ b/src/fiber/network.rs @@ -49,9 +49,9 @@ use super::channel::{ ChannelActorMessage, ChannelActorStateStore, ChannelCommand, ChannelCommandWithId, ChannelEvent, ChannelInitializationParameter, ChannelState, ChannelSubscribers, OpenChannelParameter, ProcessingChannelError, ProcessingChannelResult, PublicChannelInfo, - ShuttingDownFlags, DEFAULT_COMMITMENT_FEE_RATE, DEFAULT_FEE_RATE, - DEFAULT_MAX_TLC_VALUE_IN_FLIGHT, MAX_COMMITMENT_DELAY_EPOCHS, MAX_TLC_NUMBER_IN_FLIGHT, - MIN_COMMITMENT_DELAY_EPOCHS, SYS_MAX_TLC_NUMBER_IN_FLIGHT, + RevocationData, SettlementData, ShuttingDownFlags, DEFAULT_COMMITMENT_FEE_RATE, + DEFAULT_FEE_RATE, DEFAULT_MAX_TLC_VALUE_IN_FLIGHT, MAX_COMMITMENT_DELAY_EPOCHS, + MAX_TLC_NUMBER_IN_FLIGHT, MIN_COMMITMENT_DELAY_EPOCHS, SYS_MAX_TLC_NUMBER_IN_FLIGHT, }; use super::config::{AnnouncedNodeName, MIN_TLC_EXPIRY_DELTA}; use super::fee::calculate_commitment_tx_fee; From a63dbaff84a9dadf1759399e1ed9377eb4abe6dc Mon Sep 17 00:00:00 2001 From: quake Date: Sun, 15 Dec 2024 12:19:30 +0900 Subject: [PATCH 8/8] chore: log cleanup --- .github/workflows/e2e.yml | 1 + src/ckb/funding/funding_tx.rs | 5 - src/fiber/channel.rs | 132 +----------------- src/fiber/fee.rs | 9 +- src/fiber/network.rs | 19 --- src/fiber/types.rs | 24 ---- .../03-get-auto-accepted-channel.bru | 2 +- .../03-get-auto-accepted-channel.bru | 2 +- .../03-get-auto-accepted-channel.bru | 2 +- .../03-get-auto-accepted-channel.bru | 2 +- 10 files changed, 8 insertions(+), 190 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 454f9f052..47f6043eb 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -16,6 +16,7 @@ jobs: - cross-chain-hub - router-pay - udt-router-pay + - watchtower release: - "0.116.1" test_env: diff --git a/src/ckb/funding/funding_tx.rs b/src/ckb/funding/funding_tx.rs index b9f92cf80..1671ba6f2 100644 --- a/src/ckb/funding/funding_tx.rs +++ b/src/ckb/funding/funding_tx.rs @@ -192,7 +192,6 @@ impl FundingTxBuilder { .capacity(Capacity::shannons(ckb_amount).pack()) .lock(self.context.funding_cell_lock_script.clone()) .build(); - debug!("build_funding_cell debug ckb_output: {:?}", ckb_output); Ok((ckb_output, packed::Bytes::default())) } } @@ -297,10 +296,6 @@ impl FundingTxBuilder { .lock(Some(molecule::bytes::Bytes::from(vec![0u8; 170])).pack()) .build(); - debug!( - "request.funding_fee_rate: {}", - self.request.funding_fee_rate - ); let balancer = CapacityBalancer::new_simple( sender.clone(), placeholder_witness, diff --git a/src/fiber/channel.rs b/src/fiber/channel.rs index f0b654542..e8804386f 100644 --- a/src/fiber/channel.rs +++ b/src/fiber/channel.rs @@ -698,7 +698,6 @@ where .apply_remove_tlc_operation(myself, state, remove_tlc) .await .map_err(|e| { - debug!("error happened in apply_remove_tlc_operation: {:?}", e); error!("Error handling apply_remove_tlc_operation: {:?}", e); }); } @@ -720,11 +719,6 @@ where assert!(previous_tlc.is_received()); assert!(previous_channel_id != state.get_id()); - debug!( - "begin to remove tlc from previous channel: {:?}", - &previous_tlc - ); - let remove_reason = remove_reason.clone().backward(&tlc_info.shared_secret); // TODO: encrypt the error to backward @@ -784,10 +778,6 @@ where } } - debug!( - "register remove reason: {:?} with reason: {:?}", - tlc.tlc_id, remove_reason - ); self.register_retryable_tlc_remove(myself, state, tlc.tlc_id, remove_reason) .await; } @@ -863,10 +853,6 @@ where let payment_hash = add_tlc.payment_hash; let received_amount = add_tlc.amount; let forward_amount = peeled_onion_packet.current.amount; - debug!( - "received_amount: {} forward_amount: {}", - add_tlc.amount, forward_amount - ); if peeled_onion_packet.is_last() { if forward_amount != add_tlc.amount { @@ -1082,10 +1068,6 @@ where ))); } ChannelState::CollaboratingFundingTx(_) => { - debug!( - "Processing commitment_signed command in from CollaboratingFundingTx state {:?}", - &state.state - ); CommitmentSignedFlags::SigningCommitment(SigningCommitmentFlags::empty()) } ChannelState::SigningCommitment(flags) @@ -1097,19 +1079,11 @@ where ))); } ChannelState::SigningCommitment(flags) => { - debug!( - "Processing commitment_signed command in from SigningCommitment state {:?}", - &state.state - ); CommitmentSignedFlags::SigningCommitment(flags) } ChannelState::ChannelReady() => CommitmentSignedFlags::ChannelReady(), ChannelState::ShuttingDown(flags) => { if flags.contains(ShuttingDownFlags::AWAITING_PENDING_TLCS) { - debug!( - "Signing commitment transactions while shutdown is pending, current state {:?}", - &state.state - ); CommitmentSignedFlags::PendingShutdown(flags) } else { return Err(ProcessingChannelError::InvalidState(format!( @@ -1125,29 +1099,14 @@ where ))); } }; - - debug!( - "Building and signing commitment tx for state {:?}", - &state.state - ); let (funding_tx_partial_signature, commitment_tx_partial_signature) = state.build_and_sign_commitment_tx()?; - - debug!( - "Sending next local nonce {:?} (previous nonce {:?})", - state.get_next_local_nonce(), - state.get_local_nonce().borrow() - ); let commitment_signed = CommitmentSigned { channel_id: state.get_id(), funding_tx_partial_signature, commitment_tx_partial_signature, next_local_nonce: state.get_next_local_nonce(), }; - debug!( - "Sending built commitment_signed message: {:?}", - &commitment_signed - ); self.network .send_message(NetworkActorMessage::new_command( NetworkActorCommand::SendFiberMessage(FiberMessageWithPeerId::new( @@ -1236,13 +1195,6 @@ where )) .expect(ASSUME_NETWORK_ACTOR_ALIVE); - debug!( - "Channel ({:?}) balance after removing tlc {:?}: local balance: {}, remote balance: {}", - state.get_id(), - tlc_kind, - state.to_local_amount, - state.to_remote_amount - ); state.maybe_transition_to_shutdown(&self.network)?; self.handle_commitment_signed_command(state)?; state.tlc_state.set_waiting_ack(true); @@ -3387,30 +3339,13 @@ impl ChannelActorState { capacity, self.funding_udt_type_script.clone(), ); - debug!( - "Created unsigned channel announcement for channel {:?}: {:?}", - &self.get_id(), - &channel_announcement, - ); channel_announcement } }; - debug!( - "Trying to complete channel announcement signatures for channel {:?}: {:?}", - &self.get_id(), - channel_announcement, - ); - let local_nonce = self .get_channel_announcement_musig2_secnonce() .public_nonce(); - debug!( - "Local nonce: {:?}, remote nonce: {:?}, remote signatures: {:?}", - &local_nonce, - self.get_remote_channel_announcement_nonce(), - self.get_remote_channel_announcement_signature() - ); let remote_nonce = self.get_remote_channel_announcement_nonce()?; let agg_nonce = AggNonce::sum(self.order_things_for_musig2(local_nonce, remote_nonce.clone())); @@ -3430,8 +3365,6 @@ impl ChannelActorState { let (remote_node_signature, remote_partial_signature) = self.get_remote_channel_announcement_signature()?; - debug!("Aggregating partial signatures for channel {:?}", &self.id); - if self.local_is_node1() { channel_announcement.node1_signature = Some(local_node_signature); channel_announcement.node2_signature = Some(remote_node_signature); @@ -3496,12 +3429,6 @@ impl ChannelActorState { network: &ActorRef, ) { let channel_update = self.generate_channel_update(network).await; - - debug!( - "Broadcasting channel update message to peers: {:?}", - &channel_update - ); - network .send_message(NetworkActorMessage::new_command( NetworkActorCommand::ProccessChannelUpdate( @@ -4214,10 +4141,6 @@ impl ChannelActorState { pub fn get_remote_nonce(&self) -> PubNonce { let comitment_number = self.get_remote_commitment_number(); - debug!( - "Getting remote nonce: commitment number {}, current nonces: {:?}", - comitment_number, &self.remote_nonces - ); assert!(self.remote_nonces.len() <= 2); self.remote_nonces .iter() @@ -4233,11 +4156,6 @@ impl ChannelActorState { } fn save_remote_nonce(&mut self, nonce: PubNonce) { - debug!( - "Saving remote nonce: new nonce {:?}, current nonces {:?}, commitment numbers {:?}", - &nonce, &self.remote_nonces, self.commitment_numbers - ); - let next_remote_number = if self.remote_nonces.is_empty() { 0 } else { @@ -4251,18 +4169,10 @@ impl ChannelActorState { fn save_remote_nonce_for_raa(&mut self) { let nonce = self.get_remote_nonce(); - debug!( - "Saving remote nonce used in commitment signed: {:?}", - &nonce - ); self.last_used_nonce_in_commitment_signed = Some(nonce); } fn take_remote_nonce_for_raa(&mut self) -> PubNonce { - debug!( - "Taking remote nonce used in commitment signed: {:?}", - &self.last_used_nonce_in_commitment_signed - ); self.last_used_nonce_in_commitment_signed .take() .expect("set last_used_nonce_in_commitment_signed in commitment signed") @@ -4281,10 +4191,6 @@ impl ChannelActorState { } fn set_remote_commitment_number(&mut self, number: u64) { - debug!( - "Setting remote commitment number from {} to {}", - self.commitment_numbers.remote, number - ); self.commitment_numbers.remote = number; } @@ -4352,7 +4258,6 @@ impl ChannelActorState { } if tlc.is_offered() { let sent_tlc_value = self.get_offered_tlc_balance(); - debug!("Value of local sent tlcs: {}", sent_tlc_value); debug_assert!(self.to_local_amount >= sent_tlc_value); if sent_tlc_value + tlc.amount > self.to_local_amount { return Err(ProcessingChannelError::InvalidParameter(format!( @@ -4364,7 +4269,6 @@ impl ChannelActorState { } } else { let received_tlc_value = self.get_received_tlc_balance(); - debug!("Value of remote received tlcs: {}", received_tlc_value); debug_assert!(self.to_remote_amount >= received_tlc_value); if received_tlc_value + tlc.amount > self.to_remote_amount { return Err(ProcessingChannelError::InvalidParameter(format!( @@ -4404,9 +4308,6 @@ impl ChannelActorState { tlc_id, current_removed_at, reason, removed_at, current_remove_reason))); } None => { - debug!("Inserting remove reason {:?} at commitment number {:?} for tlc {:?} hash_algorithm: {:?}", - reason, removed_at, current, current.hash_algorithm); - if let RemoveTlcReason::RemoveTlcFulfill(fulfill) = reason { let filled_payment_hash: Hash256 = current.hash_algorithm.hash(fulfill.payment_preimage).into(); @@ -4490,20 +4391,11 @@ impl ChannelActorState { } fn get_local_commitment_point(&self, commitment_number: u64) -> Pubkey { - let commitment_point = self.signer.get_commitment_point(commitment_number); - debug!( - "Obtained {}th local commitment point: {:?}", - commitment_number, commitment_point - ); - commitment_point + self.signer.get_commitment_point(commitment_number) } /// Get the counterparty commitment point for the given commitment number. fn get_remote_commitment_point(&self, commitment_number: u64) -> Pubkey { - debug!( - "Getting remote commitment point #{} from remote_commitment_points: {:?}", - commitment_number, &self.remote_commitment_points - ); self.remote_commitment_points .iter() .find_map(|(number, point)| { @@ -5336,10 +5228,6 @@ impl ChannelActorState { ))); } ChannelState::CollaboratingFundingTx(_) => { - debug!( - "Processing commitment_signed message in state {:?}", - &self.state - ); CommitmentSignedFlags::SigningCommitment(SigningCommitmentFlags::empty()) } ChannelState::SigningCommitment(flags) @@ -5351,16 +5239,9 @@ impl ChannelActorState { ))); } ChannelState::SigningCommitment(flags) => { - debug!( - "Processing commitment_signed message in state {:?}", - &self.state - ); CommitmentSignedFlags::SigningCommitment(flags) } - ChannelState::ChannelReady() => { - debug!("Processing commitment_signed message while channel ready"); - CommitmentSignedFlags::ChannelReady() - } + ChannelState::ChannelReady() => CommitmentSignedFlags::ChannelReady(), ChannelState::ShuttingDown(flags) => { if flags.contains(ShuttingDownFlags::AWAITING_PENDING_TLCS) { debug!( @@ -5400,11 +5281,6 @@ impl ChannelActorState { )) .expect(ASSUME_NETWORK_ACTOR_ALIVE); - debug!( - "Updating peer next remote nonce from {:?} to {:?}", - self.get_remote_nonce(), - &commitment_signed.next_local_nonce - ); self.save_remote_nonce(commitment_signed.next_local_nonce); self.latest_commitment_transaction = Some(commitment_tx.data()); match flags { @@ -6858,10 +6734,6 @@ impl InMemorySigner { pub fn derive_musig2_nonce(&self, commitment_number: u64) -> SecNonce { let commitment_point = self.get_commitment_point(commitment_number); let seckey = derive_private_key(&self.musig2_base_nonce, &commitment_point); - debug!( - "Deriving Musig2 nonce: commitment number: {}, commitment point: {:?}", - commitment_number, commitment_point - ); SecNonce::build(seckey.as_ref()).build() } } diff --git a/src/fiber/fee.rs b/src/fiber/fee.rs index caec2d67c..a42236e4f 100644 --- a/src/fiber/fee.rs +++ b/src/fiber/fee.rs @@ -90,16 +90,9 @@ pub(crate) fn shutdown_tx_size( } pub(crate) fn calculate_commitment_tx_fee(fee_rate: u64, udt_type_script: &Option