diff --git a/Cargo.lock b/Cargo.lock index da45e6864d..4920e0bdc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -419,16 +419,16 @@ dependencies = [ [[package]] name = "bip32" -version = "0.2.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2d0f0fc59c7ba0333eed9dcc1b6980baa7b7a4dc7c6c5885994d0674f7adf34" +checksum = "db40d3dfbeab4e031d78c844642fa0caa0b0db11ce1607ac9d2986dff1405c69" dependencies = [ - "bs58 0.4.0", - "hkd32", - "hmac 0.11.0", - "ripemd160", - "secp256k1 0.20.3", - "sha2 0.9.9", + "bs58 0.5.0", + "hmac 0.12.1", + "rand_core 0.6.4", + "ripemd", + "secp256k1", + "sha2 0.10.7", "subtle", "zeroize", ] @@ -439,28 +439,45 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ - "bitcoin_hashes", - "rand_core 0.6.4", + "bitcoin_hashes 0.11.0", + "rand_core 0.5.1", "zeroize", ] [[package]] name = "bitcoin" -version = "0.29.2" +version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3" +checksum = "1945a5048598e4189e239d3f809b19bdad4845c4b2ba400d304d2dcf26d2c462" dependencies = [ "bech32", - "bitcoin_hashes", - "secp256k1 0.24.3", + "bitcoin-private", + "bitcoin_hashes 0.12.0", + "hex_lit", + "secp256k1", ] +[[package]] +name = "bitcoin-private" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" + [[package]] name = "bitcoin_hashes" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" +[[package]] +name = "bitcoin_hashes" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" +dependencies = [ + "bitcoin-private", +] + [[package]] name = "bitcrypto" version = "0.1.0" @@ -639,6 +656,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" dependencies = [ + "sha2 0.10.7", "tinyvec", ] @@ -833,7 +851,7 @@ dependencies = [ "base64 0.21.7", "bip32", "bitcoin", - "bitcoin_hashes", + "bitcoin_hashes 0.12.0", "bitcrypto", "blake2b_simd", "bs58 0.4.0", @@ -877,6 +895,7 @@ dependencies = [ "lightning-background-processor", "lightning-invoice", "lightning-net-tokio", + "lightning-persister", "mm2_core", "mm2_db", "mm2_err_handle", @@ -909,8 +928,7 @@ dependencies = [ "rust-ini", "rustls 0.21.10", "script", - "secp256k1 0.20.3", - "secp256k1 0.24.3", + "secp256k1", "ser_error", "ser_error_derive", "serde", @@ -977,7 +995,6 @@ dependencies = [ "parking_lot", "rpc", "rpc_task", - "secp256k1 0.24.3", "ser_error", "ser_error_derive", "serde", @@ -1325,7 +1342,7 @@ dependencies = [ "rpc", "rpc_task", "rustc-hex", - "secp256k1 0.20.3", + "secp256k1", "ser_error", "ser_error_derive", "serde", @@ -1372,16 +1389,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "crypto_api" version = "0.2.2" @@ -1847,7 +1854,7 @@ dependencies = [ [[package]] name = "equihash" version = "0.1.0" -source = "git+https://github.com/komodoplatform/librustzcash.git?tag=k-1.4.2#4e030a0f44cc17f100bf5f019563be25c5b8755f" +source = "git+https://github.com/komodoplatform/librustzcash.git?branch=upgrade-secp256k1#5535e5b4d84a81e6351e1087081e8661d33eb7a5" dependencies = [ "blake2b_simd", "byteorder", @@ -1866,7 +1873,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1902,7 +1909,7 @@ dependencies = [ [[package]] name = "ethcore-transaction" version = "0.1.0" -source = "git+https://github.com/KomodoPlatform/mm2-parity-ethereum.git?rev=mm2-v2.1.1#d5524212230c4773d01b2527e9b3c422a251e0dc" +source = "git+https://github.com/KomodoPlatform/mm2-parity-ethereum.git?branch=upgrade-secp256k1#8a12cefc6cc4779b04fea1ff326d6753f6202098" dependencies = [ "ethereum-types", "ethkey", @@ -1929,16 +1936,16 @@ dependencies = [ [[package]] name = "ethkey" version = "0.3.0" -source = "git+https://github.com/KomodoPlatform/mm2-parity-ethereum.git?rev=mm2-v2.1.1#d5524212230c4773d01b2527e9b3c422a251e0dc" +source = "git+https://github.com/KomodoPlatform/mm2-parity-ethereum.git?branch=upgrade-secp256k1#8a12cefc6cc4779b04fea1ff326d6753f6202098" dependencies = [ "byteorder", "edit-distance", "ethereum-types", "log", "mem", - "rand 0.6.5", + "rand 0.8.5", "rustc-hex", - "secp256k1 0.20.3", + "secp256k1", "serde", "serde_derive", "tiny-keccak 1.4.4", @@ -2517,6 +2524,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-conservative" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" + [[package]] name = "hex_fmt" version = "0.3.0" @@ -2524,16 +2537,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" [[package]] -name = "hkd32" -version = "0.6.0" +name = "hex_lit" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84f2a5541afe0725f0b95619d6af614f48c1b176385b8aa30918cfb8c4bfafc8" -dependencies = [ - "hmac 0.11.0", - "rand_core 0.6.4", - "sha2 0.9.9", - "zeroize", -] +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" [[package]] name = "hkdf" @@ -2550,17 +2557,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", -] - -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac 0.11.1", + "crypto-mac", "digest 0.9.0", ] @@ -2652,7 +2649,7 @@ dependencies = [ "js-sys", "mm2_err_handle", "rusb", - "secp256k1 0.20.3", + "secp256k1", "serde", "serde_derive", "wasm-bindgen", @@ -3051,7 +3048,7 @@ dependencies = [ "rand 0.8.5", "relay_client", "relay_rpc", - "secp256k1 0.20.3", + "secp256k1", "serde", "serde_json", "sha2 0.10.7", @@ -3093,8 +3090,9 @@ dependencies = [ "lazy_static", "primitives", "rand 0.6.5", + "rand 0.8.5", "rustc-hex", - "secp256k1 0.20.3", + "secp256k1", "serde", "serde_derive", ] @@ -3588,18 +3586,19 @@ dependencies = [ [[package]] name = "lightning" -version = "0.0.113" +version = "0.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "087add70f81d2fdc6d4409bc0cef69e11ad366ef1d0068550159bd22b3ac8664" +checksum = "32899363dc48d297838ce1264c4bb6867ede6ec11f06f3b9823f3ff403f1ccc2" dependencies = [ "bitcoin", + "hex-conservative", ] [[package]] name = "lightning-background-processor" -version = "0.0.113" +version = "0.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2288d211a2ab15e2c9fb492fb99c7998df1a37f228552f703824ee678b8980c9" +checksum = "1dd4579eae0ba4479bdbee06b95380fa785b740843ab8211e38cedc96527e918" dependencies = [ "bitcoin", "lightning", @@ -3608,34 +3607,45 @@ dependencies = [ [[package]] name = "lightning-invoice" -version = "0.21.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9680857590c3529cf8c7d32b04501f215f2bf1e029fdfa22f4112f66c1741e4" +checksum = "fd3421ccfaeac77763114f68f3fc5308f11a0e8a880618b4f84d1d22493aa465" dependencies = [ "bech32", - "bitcoin_hashes", + "bitcoin", "lightning", "num-traits", - "secp256k1 0.24.3", + "secp256k1", "serde", ] [[package]] name = "lightning-net-tokio" -version = "0.0.113" +version = "0.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e94b019ffcbd423c67bc8e65093d46cf5c00ff696b4b633936fce6e4d0cb845" +checksum = "f67f8eafcb02c2ea3896f4c3ec274350487c4c34b7a21b28c4f5b1089bfbcd18" dependencies = [ "bitcoin", "lightning", "tokio", ] +[[package]] +name = "lightning-persister" +version = "0.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e526d0c4fe135cf4c0d97221a833304f1150a335279edbf951100c22aa50a5c" +dependencies = [ + "bitcoin", + "lightning", + "windows-sys 0.48.0", +] + [[package]] name = "lightning-rapid-gossip-sync" -version = "0.0.113" +version = "0.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488b68c7d24093d35a83f37c560e427f1085f4c5d37918b81b11d95cd3675a0f" +checksum = "d6ae008f2992342421bb2871a84ae9cbba6d6ef10284282f752ca04f67c5465a" dependencies = [ "bitcoin", "lightning", @@ -3743,7 +3753,7 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "mem" version = "0.1.0" -source = "git+https://github.com/KomodoPlatform/mm2-parity-ethereum.git?rev=mm2-v2.1.1#d5524212230c4773d01b2527e9b3c422a251e0dc" +source = "git+https://github.com/KomodoPlatform/mm2-parity-ethereum.git?branch=upgrade-secp256k1#8a12cefc6cc4779b04fea1ff326d6753f6202098" [[package]] name = "memchr" @@ -3985,7 +3995,7 @@ dependencies = [ "indexmap 1.9.3", "itertools", "mm2_err_handle", - "secp256k1 0.20.3", + "secp256k1", "serde", "serde_json", "web3", @@ -4134,7 +4144,7 @@ dependencies = [ "rustls 0.21.10", "rustls-pemfile 1.0.2", "script", - "secp256k1 0.20.3", + "secp256k1", "ser_error", "ser_error_derive", "serde", @@ -4287,7 +4297,7 @@ dependencies = [ "rand 0.7.3", "regex", "rmp-serde", - "secp256k1 0.20.3", + "secp256k1", "serde", "serde_bytes", "serde_json", @@ -4990,7 +5000,7 @@ dependencies = [ name = "primitives" version = "0.1.0" dependencies = [ - "bitcoin_hashes", + "bitcoin_hashes 0.12.0", "byteorder", "rustc-hex", "uint", @@ -5862,7 +5872,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -6061,38 +6071,20 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.20.3" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" dependencies = [ - "rand 0.6.5", - "secp256k1-sys 0.4.2", -] - -[[package]] -name = "secp256k1" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" -dependencies = [ - "bitcoin_hashes", - "secp256k1-sys 0.6.1", -] - -[[package]] -name = "secp256k1-sys" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" -dependencies = [ - "cc", + "bitcoin_hashes 0.12.0", + "rand 0.8.5", + "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.6.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +checksum = "4473013577ec77b4ee3668179ef1186df3146e2cf2d927bd200974c6fe60fd99" dependencies = [ "cc", ] @@ -7602,7 +7594,7 @@ dependencies = [ [[package]] name = "unexpected" version = "0.1.0" -source = "git+https://github.com/KomodoPlatform/mm2-parity-ethereum.git?rev=mm2-v2.1.1#d5524212230c4773d01b2527e9b3c422a251e0dc" +source = "git+https://github.com/KomodoPlatform/mm2-parity-ethereum.git?branch=upgrade-secp256k1#8a12cefc6cc4779b04fea1ff326d6753f6202098" [[package]] name = "unicode-bidi" @@ -8405,7 +8397,7 @@ checksum = "0f9079049688da5871a7558ddacb7f04958862c703e68258594cb7a862b5e33f" [[package]] name = "zcash_client_backend" version = "0.5.0" -source = "git+https://github.com/komodoplatform/librustzcash.git?tag=k-1.4.2#4e030a0f44cc17f100bf5f019563be25c5b8755f" +source = "git+https://github.com/komodoplatform/librustzcash.git?branch=upgrade-secp256k1#5535e5b4d84a81e6351e1087081e8661d33eb7a5" dependencies = [ "async-trait", "base64 0.13.0", @@ -8430,7 +8422,7 @@ dependencies = [ [[package]] name = "zcash_client_sqlite" version = "0.3.0" -source = "git+https://github.com/komodoplatform/librustzcash.git?tag=k-1.4.2#4e030a0f44cc17f100bf5f019563be25c5b8755f" +source = "git+https://github.com/komodoplatform/librustzcash.git?branch=upgrade-secp256k1#5535e5b4d84a81e6351e1087081e8661d33eb7a5" dependencies = [ "async-trait", "bech32", @@ -8452,7 +8444,7 @@ dependencies = [ [[package]] name = "zcash_extras" version = "0.1.0" -source = "git+https://github.com/komodoplatform/librustzcash.git?tag=k-1.4.2#4e030a0f44cc17f100bf5f019563be25c5b8755f" +source = "git+https://github.com/komodoplatform/librustzcash.git?branch=upgrade-secp256k1#5535e5b4d84a81e6351e1087081e8661d33eb7a5" dependencies = [ "async-trait", "ff 0.8.0", @@ -8468,7 +8460,7 @@ dependencies = [ [[package]] name = "zcash_note_encryption" version = "0.0.0" -source = "git+https://github.com/komodoplatform/librustzcash.git?tag=k-1.4.2#4e030a0f44cc17f100bf5f019563be25c5b8755f" +source = "git+https://github.com/komodoplatform/librustzcash.git?branch=upgrade-secp256k1#5535e5b4d84a81e6351e1087081e8661d33eb7a5" dependencies = [ "blake2b_simd", "byteorder", @@ -8482,7 +8474,7 @@ dependencies = [ [[package]] name = "zcash_primitives" version = "0.5.0" -source = "git+https://github.com/komodoplatform/librustzcash.git?tag=k-1.4.2#4e030a0f44cc17f100bf5f019563be25c5b8755f" +source = "git+https://github.com/komodoplatform/librustzcash.git?branch=upgrade-secp256k1#5535e5b4d84a81e6351e1087081e8661d33eb7a5" dependencies = [ "aes", "bitvec 0.18.5", @@ -8503,7 +8495,7 @@ dependencies = [ "rand 0.7.3", "rand_core 0.5.1", "ripemd160", - "secp256k1 0.20.3", + "secp256k1", "sha2 0.9.9", "subtle", "zcash_note_encryption", @@ -8512,7 +8504,7 @@ dependencies = [ [[package]] name = "zcash_proofs" version = "0.5.0" -source = "git+https://github.com/komodoplatform/librustzcash.git?tag=k-1.4.2#4e030a0f44cc17f100bf5f019563be25c5b8755f" +source = "git+https://github.com/komodoplatform/librustzcash.git?branch=upgrade-secp256k1#5535e5b4d84a81e6351e1087081e8661d33eb7a5" dependencies = [ "bellman", "blake2b_simd", diff --git a/Cargo.toml b/Cargo.toml index 1f8adea7a2..9ecf264ee2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,10 +63,10 @@ base64 = "0.21.2" bech32 = "0.9.1" bs58 = "0.4.0" bigdecimal = { version = "0.3", features = ["serde"] } -bip32 = { version = "0.2.2", default-features = false, features = ["alloc", "secp256k1-ffi"] } +bip32 = { version = "0.5.0", default-features = false, features = ["alloc", "secp256k1-ffi"] } bip39 = { version = "2.0.0", features = ["rand_core", "zeroize"], default-features = false } -bitcoin = "0.29" -bitcoin_hashes = "0.11" +bitcoin = "0.30" +bitcoin_hashes = "0.12" blake2 = "0.10.6" blake2b_simd = "0.5.10" bytes = "1.1" @@ -89,9 +89,9 @@ either = "1.6" enum-primitive-derive = "0.2" env_logger = { version = "0.11", default-features = false } ethabi = "17.0.0" -ethcore-transaction = { git = "https://github.com/KomodoPlatform/mm2-parity-ethereum.git", rev = "mm2-v2.1.1" } +ethcore-transaction = { git = "https://github.com/KomodoPlatform/mm2-parity-ethereum.git", branch = "upgrade-secp256k1" } ethereum-types = { version = "0.13", default-features = false, features = ["std", "serialize"] } -ethkey = { git = "https://github.com/KomodoPlatform/mm2-parity-ethereum.git", rev = "mm2-v2.1.1" } +ethkey = { git = "https://github.com/KomodoPlatform/mm2-parity-ethereum.git", branch = "upgrade-secp256k1" } # Waiting for https://github.com/rust-lang/rust/issues/54725 to use on Stable. #enum_dispatch = "0.1" ff = "0.8" @@ -127,10 +127,11 @@ jsonrpc-core = "18.0.0" lazy_static = "1.4" libc = "0.2" libp2p = { git = "https://github.com/KomodoPlatform/rust-libp2p.git", tag = "k-0.52.12", default-features = false } -lightning = "0.0.113" -lightning-background-processor = "0.0.113" -lightning-invoice = { version = "0.21.0", features = ["serde"] } -lightning-net-tokio = "0.0.113" +lightning = "0.0.119" +lightning-background-processor = "0.0.119" +lightning-invoice = { version = "0.27.0", features = ["serde"] } +lightning-net-tokio = "0.0.119" +lightning-persister = "0.0.119" log = "0.4" metrics = "0.21" metrics-exporter-prometheus = "0.12.1" @@ -169,8 +170,7 @@ rust-ini = "0.13" rustls = { version = "0.21", default-features = false } rustls-pemfile = "1.0.2" rusqlite = { version = "0.28", features = ["bundled"] } -secp256k1 = "0.20" -secp256k1v24 = { version = "0.24", package = "secp256k1" } +secp256k1 = "0.27" serde = { version = "1", default-features = false } serde_bytes = "0.11.5" serde_derive = { version = "1", default-features = false } @@ -222,11 +222,11 @@ web-sys = {version = "0.3.55", default-features = false } web3 = { git = "https://github.com/komodoplatform/rust-web3", tag = "v0.20.0", default-features = false } winapi = "0.3" zbase32 = "0.1.2" -zcash_client_backend = { git = "https://github.com/komodoplatform/librustzcash.git", tag = "k-1.4.2" } -zcash_client_sqlite = { git = "https://github.com/KomodoPlatform/librustzcash.git", tag = "k-1.4.2" } -zcash_extras = { git = "https://github.com/komodoplatform/librustzcash.git", tag = "k-1.4.2" } -zcash_primitives = { git = "https://github.com/komodoplatform/librustzcash.git", tag = "k-1.4.2", features = ["transparent-inputs"] } -zcash_proofs = { git = "https://github.com/KomodoPlatform/librustzcash.git", tag = "k-1.4.2", default-features = false } +zcash_client_backend = { git = "https://github.com/komodoplatform/librustzcash.git", branch = "upgrade-secp256k1" } +zcash_client_sqlite = { git = "https://github.com/komodoplatform/librustzcash.git", branch = "upgrade-secp256k1" } +zcash_extras = { git = "https://github.com/komodoplatform/librustzcash.git", branch = "upgrade-secp256k1" } +zcash_primitives = { git = "https://github.com/komodoplatform/librustzcash.git", branch = "upgrade-secp256k1", features = ["transparent-inputs"] } +zcash_proofs = { git = "https://github.com/komodoplatform/librustzcash.git", branch = "upgrade-secp256k1", default-features = false } x25519-dalek = { version = "2.0", features = ["static_secrets"] } zeroize = { version = "1.8.1", features = ["zeroize_derive"] } @@ -249,3 +249,7 @@ codegen-units = 256 [profile.release.package.mocktopus] opt-level = 1 # TODO: MIR fails on optimizing this dependency, remove that.. + +# [patch.crates-io] +# secp256k1-sys61 = { version = "0.6.1", git = "https://github.com/rust-bitcoin/rust-secp256k1.git", tag = "secp256k1-sys-0.6.1", package = "secp256k1-sys" } +# secp256k1-sys42 = { version = "0.4.2", git = "https://github.com/rust-bitcoin/rust-secp256k1.git", tag = "secp256k1-sys-0.6.1", package = "secp256k1-sys" } diff --git a/mm2src/coins/Cargo.toml b/mm2src/coins/Cargo.toml index e869d94ab7..8c6f091b07 100644 --- a/mm2src/coins/Cargo.toml +++ b/mm2src/coins/Cargo.toml @@ -10,6 +10,13 @@ enable-sia = [ "dep:blake2b_simd", "dep:sia-rust" ] +enable-lightning = [ + "dep:lightning", + "dep:lightning-background-processor", + "dep:lightning-invoice", + "dep:lightning-net-tokio", + "dep:lightning-persister" +] enable-solana = [] default = [] run-docker-tests = [] @@ -157,13 +164,13 @@ zcash_proofs = { workspace = true, features = ["local-prover"] } bitcoin.workspace = true hyper = { workspace = true, features = ["client", "http2", "server", "tcp"] } hyper-rustls = { workspace = true, default-features = false, features = ["http1", "http2", "webpki-tokio"] } -lightning.workspace = true -lightning-background-processor.workspace = true -lightning-invoice.workspace = true -lightning-net-tokio.workspace = true +lightning = { workspace = true, optional = true } +lightning-background-processor = { workspace = true, optional = true } +lightning-invoice = { workspace = true, optional = true } +lightning-net-tokio = { workspace = true, optional = true } +lightning-persister = { workspace = true, optional = true } rust-ini.workspace = true rustls = { workspace = true, features = ["dangerous_configuration"] } -secp256k1v24.workspace = true timed-map = { workspace = true, features = ["rustc-hash"] } tokio.workspace = true tokio-rustls.workspace = true diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index eb7a8192e2..a047085de6 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6148,11 +6148,11 @@ impl MmCoin for EthCoin { } fn swap_contract_address(&self) -> Option { - Some(BytesJson::from(self.swap_contract_address.0.as_ref())) + Some(BytesJson::new(self.swap_contract_address.0.to_vec())) } fn fallback_swap_contract(&self) -> Option { - self.fallback_swap_contract.map(|a| BytesJson::from(a.0.as_ref())) + self.fallback_swap_contract.map(|a| BytesJson::new(a.0.to_vec())) } fn mature_confirmations(&self) -> Option { diff --git a/mm2src/coins/eth/wallet_connect.rs b/mm2src/coins/eth/wallet_connect.rs index b5d45ec742..c27dce9f4a 100644 --- a/mm2src/coins/eth/wallet_connect.rs +++ b/mm2src/coins/eth/wallet_connect.rs @@ -18,7 +18,7 @@ use kdf_walletconnect::chain::{WcChainId, WcRequestMethods}; use kdf_walletconnect::error::WalletConnectError; use kdf_walletconnect::{WalletConnectCtx, WalletConnectOps, WcTopic}; use mm2_err_handle::prelude::*; -use secp256k1::recovery::{RecoverableSignature, RecoveryId}; +use secp256k1::ecdsa::{RecoverableSignature, RecoveryId}; use secp256k1::{PublicKey, Secp256k1}; use std::iter::FromIterator; use std::str::FromStr; @@ -258,7 +258,7 @@ pub(crate) fn recover(signature: &Signature, message: &Message) -> Result Result> { - if final_cltv_expiry_delta < MIN_FINAL_CLTV_EXPIRY { - return MmError::err(PaymentError::CLTVExpiry(final_cltv_expiry_delta, MIN_FINAL_CLTV_EXPIRY)); + if final_cltv_expiry_delta < MIN_FINAL_CLTV_EXPIRY_DELTA { + return MmError::err(PaymentError::CLTVExpiry( + final_cltv_expiry_delta, + MIN_FINAL_CLTV_EXPIRY_DELTA, + )); } let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes()); @@ -425,15 +428,15 @@ impl LightningCoin { } } - // Todo: this can be removed after next rust-lightning release when min_final_cltv_expiry can be specified in + // Todo: this can be removed after next rust-lightning release when min_final_cltv_expiry_delta can be specified in // Todo: create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash https://github.com/lightningdevkit/rust-lightning/pull/1878 - // Todo: The above PR will also validate min_final_cltv_expiry. + // Todo: The above PR will also validate min_final_cltv_expiry_delta. async fn create_invoice_for_hash( &self, payment_hash: PaymentHash, amt_msat: Option, description: String, - min_final_cltv_expiry: u64, + min_final_cltv_expiry_delta: u64, invoice_expiry_delta_secs: u32, ) -> Result>> { let open_channels_nodes = self.open_channels_nodes.lock().clone(); @@ -445,11 +448,19 @@ impl LightningCoin { )); } + // TODO: Here we just don't set the delta if we can't convert it to u16. There is probably a better solution. + let min_final_cltv_expiry_delta: Option = min_final_cltv_expiry_delta.try_into().ok(); + // `create_inbound_payment` only returns an error if the amount is greater than the total bitcoin // supply. let payment_secret = self .channel_manager - .create_inbound_payment_for_hash(payment_hash, amt_msat, invoice_expiry_delta_secs) + .create_inbound_payment_for_hash( + payment_hash, + amt_msat, + invoice_expiry_delta_secs, + min_final_cltv_expiry_delta, + ) .map_to_mm(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?; let our_node_pubkey = self.channel_manager.get_our_node_id(); // Todo: Check if it's better to use UTC instead of local time for invoice generations @@ -462,7 +473,6 @@ impl LightningCoin { .payment_hash(Hash::from_inner(payment_hash.0)) .payment_secret(payment_secret) .basic_mpp() - .min_final_cltv_expiry(min_final_cltv_expiry) .expiry_time(core::time::Duration::from_secs(invoice_expiry_delta_secs.into())); if let Some(amt) = amt_msat { invoice = invoice.amount_milli_satoshis(amt); @@ -499,7 +509,7 @@ impl LightningCoin { secret_hash: &[u8], amount: BigDecimal, expires_in: u64, - min_final_cltv_expiry: u64, + min_final_cltv_expiry_delta: u64, ) -> Result, MmError> { // lightning decimals should be 11 in config since the smallest divisible unit in lightning coin is msat let amt_msat = sat_from_big_decimal(&amount, self.decimals()).map_mm_err()?; @@ -511,7 +521,7 @@ impl LightningCoin { payment_hash, Some(amt_msat), "".into(), - min_final_cltv_expiry, + min_final_cltv_expiry_delta, expires_in.try_into().expect("expires_in shouldn't exceed u32::MAX"), ) .await @@ -524,7 +534,7 @@ impl LightningCoin { instructions: &[u8], secret_hash: &[u8], amount: BigDecimal, - min_final_cltv_expiry: u64, + min_final_cltv_expiry_delta: u64, ) -> Result> { let invoice = Invoice::from_str(&String::from_utf8_lossy(instructions))?; if invoice.payment_hash().as_inner() != secret_hash @@ -544,9 +554,9 @@ impl LightningCoin { )); } - if invoice.min_final_cltv_expiry() != min_final_cltv_expiry { + if invoice.min_final_cltv_expiry() != min_final_cltv_expiry_delta { return MmError::err(ValidateInstructionsErr::ValidateLightningInvoiceErr( - "Invalid invoice min_final_cltv_expiry!".into(), + "Invalid invoice min_final_cltv_expiry_delta!".into(), )); } @@ -585,7 +595,7 @@ impl LightningCoin { match coin.db.get_payment_from_db(payment_hash).await { Ok(Some(payment)) => { let amount_claimable = payment.amt_msat; - // Note: locktime doesn't need to be validated since min_final_cltv_expiry should be validated in rust-lightning after fixing the below issue + // Note: locktime doesn't need to be validated since min_final_cltv_expiry_delta should be validated in rust-lightning after fixing the below issue // https://github.com/lightningdevkit/rust-lightning/issues/1850 // Also, PaymentClaimable won't be fired if amount_claimable < the amount requested in the invoice, this check is probably not needed. // But keeping it just in case any changes happen in rust-lightning @@ -875,10 +885,15 @@ impl SwapOps for LightningCoin { &self, args: PaymentInstructionArgs<'_>, ) -> Result>, MmError> { - let min_final_cltv_expiry = self.estimate_blocks_from_duration(args.maker_lock_duration); - self.swap_payment_instructions(args.secret_hash, args.amount, args.expires_in, min_final_cltv_expiry) - .await - .map(Some) + let min_final_cltv_expiry_delta = self.estimate_blocks_from_duration(args.maker_lock_duration); + self.swap_payment_instructions( + args.secret_hash, + args.amount, + args.expires_in, + min_final_cltv_expiry_delta, + ) + .await + .map(Some) } #[inline] @@ -890,7 +905,7 @@ impl SwapOps for LightningCoin { args.secret_hash, args.amount, args.expires_in, - MIN_FINAL_CLTV_EXPIRY as u64, + MIN_FINAL_CLTV_EXPIRY_DELTA as u64, ) .await .map(Some) @@ -901,8 +916,8 @@ impl SwapOps for LightningCoin { instructions: &[u8], args: PaymentInstructionArgs, ) -> Result> { - let min_final_cltv_expiry = self.estimate_blocks_from_duration(args.maker_lock_duration); - self.validate_swap_instructions(instructions, args.secret_hash, args.amount, min_final_cltv_expiry) + let min_final_cltv_expiry_delta = self.estimate_blocks_from_duration(args.maker_lock_duration); + self.validate_swap_instructions(instructions, args.secret_hash, args.amount, min_final_cltv_expiry_delta) } #[inline] @@ -915,7 +930,7 @@ impl SwapOps for LightningCoin { instructions, args.secret_hash, args.amount, - MIN_FINAL_CLTV_EXPIRY as u64, + MIN_FINAL_CLTV_EXPIRY_DELTA as u64, ) } @@ -992,10 +1007,7 @@ impl MarketCoinOps for LightningCoin { )); } let message_hash = self.sign_message_hash(message).ok_or(SignatureError::PrefixNotFound)?; - let secret_key = self - .keys_manager - .get_node_secret(Recipient::Node) - .map_err(|_| SignatureError::InternalError("Error accessing node keys".to_string()))?; + let secret_key = self.keys_manager.get_node_secret_key(); let private = Private { prefix: 239, secret: H256::from_slice(secret_key.as_ref()) @@ -1182,12 +1194,7 @@ impl MarketCoinOps for LightningCoin { } fn display_priv_key(&self) -> Result { - Ok(self - .keys_manager - .get_node_secret(Recipient::Node) - .map_err(|_| "Unsupported recipient".to_string())? - .display_secret() - .to_string()) + Ok(self.keys_manager.get_node_secret_key().display_secret().to_string()) } // This will depend on the route/routes taken for the payment, since every channel's counterparty specifies the minimum amount they will allow to route. @@ -1413,27 +1420,32 @@ impl MmCoin for LightningCoin { let hint = log_err_and_return_false!(Readable::read(&mut Cursor::new(h))); route_hints.push(hint); } - let mut payment_params = - PaymentParameters::from_node_id(protocol_info.node_id.into()).with_route_hints(route_hints); let final_cltv_expiry_delta = if is_maker { self.estimate_blocks_from_duration(locktime) .try_into() .expect("final_cltv_expiry_delta shouldn't exceed u32::MAX") } else { + MIN_FINAL_CLTV_EXPIRY_DELTA as u32 + }; + let mut payment_params = PaymentParameters::from_node_id(protocol_info.node_id.into(), final_cltv_expiry_delta) + .with_route_hints(route_hints) + .expect("Payment is initialized as clear payment, so route hints should be valid"); + if is_maker { payment_params.max_total_cltv_expiry_delta = self .estimate_blocks_from_duration(locktime) .try_into() .expect("max_total_cltv_expiry_delta shouldn't exceed u32::MAX"); - MIN_FINAL_CLTV_EXPIRY - }; + } + drop_mutability!(payment_params); let route_params = RouteParameters { payment_params, final_value_msat, - final_cltv_expiry_delta, + // TODO: We should set a sane limit here on the maximum fee to be paid. + max_total_routing_fee_msat: None, }; - let payer = self.channel_manager.node_id(); - let first_hops = self.channel_manager.first_hops(); + let payer = self.channel_manager.get_our_node_id(); + let first_hops = self.channel_manager.list_usable_channels(); let inflight_htlcs = self.channel_manager.compute_inflight_htlcs(); self.router .find_route( diff --git a/mm2src/coins/lightning/ln_db.rs b/mm2src/coins/lightning/ln_db.rs index b20bf72b5f..4fa68be745 100644 --- a/mm2src/coins/lightning/ln_db.rs +++ b/mm2src/coins/lightning/ln_db.rs @@ -3,7 +3,7 @@ use common::{now_sec_i64, PagingOptionsEnum}; use db_common::sqlite::rusqlite::types::FromSqlError; use derive_more::Display; use lightning::ln::{PaymentHash, PaymentPreimage}; -use secp256k1v24::PublicKey; +use secp256k1::PublicKey; use serde::{Deserialize, Serialize}; use std::str::FromStr; use uuid::Uuid; diff --git a/mm2src/coins/lightning/ln_events.rs b/mm2src/coins/lightning/ln_events.rs index a34eec7e62..b8e7f299d6 100644 --- a/mm2src/coins/lightning/ln_events.rs +++ b/mm2src/coins/lightning/ln_events.rs @@ -12,11 +12,11 @@ use core::time::Duration; use derive_more::Display; use futures::compat::Future01CompatExt; use lightning::chain::chaininterface::{ConfirmationTarget, FeeEstimator}; -use lightning::chain::keysinterface::SpendableOutputDescriptor; -use lightning::util::events::{Event, EventHandler, PaymentPurpose}; +use lightning::events::{Event, EventHandler, PaymentPurpose}; +use lightning::sign::SpendableOutputDescriptor; use rand::Rng; use script::{Builder, SignatureVersion}; -use secp256k1v24::Secp256k1; +use secp256k1::Secp256k1; use std::convert::TryInto; use std::sync::Arc; use utxo_signer::with_key_pair::sign_tx; diff --git a/mm2src/coins/lightning/ln_filesystem_persister.rs b/mm2src/coins/lightning/ln_filesystem_persister.rs index 4ffe65868b..16b0749771 100644 --- a/mm2src/coins/lightning/ln_filesystem_persister.rs +++ b/mm2src/coins/lightning/ln_filesystem_persister.rs @@ -8,12 +8,14 @@ use bitcoin_hashes::hex::FromHex; use common::async_blocking; use common::log::LogState; use lightning::chain::channelmonitor::ChannelMonitor; -use lightning::chain::keysinterface::{KeysInterface, Sign}; -use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters}; -use lightning::util::persist::KVStorePersister; +use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringDecayParameters}; +use lightning::sign::ecdsa::WriteableEcdsaChannelSigner as Sign; +use lightning::sign::SignerProvider; +use lightning::util::persist::KVStore; use lightning::util::ser::{ReadableArgs, Writeable}; +use lightning_persister::fs_store::FilesystemStore; use mm2_io::fs::{check_dir_operations, invalid_data_err, read_json, write_json}; -use secp256k1v24::PublicKey; +use secp256k1::PublicKey; use std::collections::{HashMap, HashSet}; use std::fs; use std::io::{BufReader, BufWriter, Cursor}; @@ -31,375 +33,378 @@ use {std::ffi::OsStr, std::os::windows::ffi::OsStrExt}; const USE_TMP_FILE: bool = true; -pub struct LightningFilesystemPersister { - main_path: PathBuf, - backup_path: Option, -} - -impl LightningFilesystemPersister { - /// Initialize a new LightningPersister and set the path to the individual channels' - /// files. - #[inline] - pub fn new(main_path: PathBuf, backup_path: Option) -> Self { - Self { main_path, backup_path } - } - - /// Get the directory which was provided when this persister was initialized. - #[inline] - pub fn main_path(&self) -> PathBuf { - self.main_path.clone() - } - - /// Get the backup directory which was provided when this persister was initialized. - #[inline] - pub fn backup_path(&self) -> Option { - self.backup_path.clone() - } - - pub fn nodes_addresses_path(&self) -> PathBuf { - let mut path = self.main_path(); - path.push("channel_nodes_data"); - path - } - - pub fn nodes_addresses_backup_path(&self) -> Option { - self.backup_path().map(|mut backup_path| { - backup_path.push("channel_nodes_data"); - backup_path - }) - } - - pub fn network_graph_path(&self) -> PathBuf { - let mut path = self.main_path(); - path.push("network_graph"); - path - } - - pub fn scorer_path(&self) -> PathBuf { - let mut path = self.main_path(); - path.push("scorer"); - path - } - - pub fn trusted_nodes_path(&self) -> PathBuf { - let mut path = self.main_path(); - path.push("trusted_nodes"); - path - } - - pub fn manager_path(&self) -> PathBuf { - let mut path = self.main_path(); - path.push("manager"); - path - } - - pub fn monitors_path(&self) -> PathBuf { - let mut path = self.main_path(); - path.push("monitors"); - path - } - - pub fn monitors_backup_path(&self) -> Option { - self.backup_path().map(|mut backup_path| { - backup_path.push("monitors"); - backup_path - }) - } - - /// Read `ChannelMonitor`s from disk. - pub fn read_channelmonitors( - &self, - keys_manager: K, - ) -> Result)>, std::io::Error> - where - K::Target: KeysInterface + Sized, - { - let path = self.monitors_path(); - if !path.exists() { - return Ok(Vec::new()); - } - let mut res = Vec::new(); - for file_option in fs::read_dir(path)? { - let file = file_option?; - let owned_file_name = file.file_name(); - let filename = owned_file_name - .to_str() - .ok_or_else(|| invalid_data_err("Invalid ChannelMonitor file name", format!("{owned_file_name:?}")))?; - if filename == "checkval" { - continue; - } - if !filename.is_ascii() || filename.len() < 65 { - return Err(invalid_data_err("Invalid ChannelMonitor file name", filename)); - } - if filename.ends_with(".tmp") { - // If we were in the middle of committing an new update and crashed, it should be - // safe to ignore the update - we should never have returned to the caller and - // irrevocably committed to the new state in any way. - continue; - } - - let txid = Txid::from_hex(filename.split_at(64).0) - .map_err(|e| invalid_data_err("Invalid tx ID in filename error", e))?; - - let index = filename - .split_at(65) - .1 - .parse::() - .map_err(|e| invalid_data_err("Invalid tx index in filename error", e))?; - - let contents = fs::read(file.path())?; - let mut buffer = Cursor::new(&contents); - let (blockhash, channel_monitor) = <(BlockHash, ChannelMonitor)>::read(&mut buffer, &*keys_manager) - .map_err(|e| invalid_data_err("Failed to deserialize ChannelMonito", e))?; - - if channel_monitor.get_funding_txo().0.txid != txid || channel_monitor.get_funding_txo().0.index != index { - return Err(invalid_data_err( - "ChannelMonitor was stored in the wrong file", - filename, - )); - } - - res.push((blockhash, channel_monitor)); - } - Ok(res) - } -} - -impl KVStorePersister for LightningFilesystemPersister { - fn persist(&self, key: &str, object: &W) -> std::io::Result<()> { - let mut dest_file = self.main_path(); - dest_file.push(key); - drop_mutability!(dest_file); - write_to_file(dest_file, object)?; - - if !matches!(key, "network_graph" | "scorer") { - if let Some(mut dest_file) = self.backup_path() { - dest_file.push(key); - drop_mutability!(dest_file); - write_to_file(dest_file, object)?; - } - } - - Ok(()) - } -} - -#[cfg(target_family = "windows")] -macro_rules! call { - ($e: expr) => { - if $e != 0 { - return Ok(()); - } else { - return Err(std::io::Error::last_os_error()); - } - }; -} - -#[cfg(target_family = "windows")] -fn path_to_windows_str>(path: T) -> Vec { - path.as_ref().encode_wide().chain(Some(0)).collect() -} - -fn write_to_file(dest_file: PathBuf, data: &W) -> std::io::Result<()> { - let mut tmp_file = dest_file.clone(); - tmp_file.set_extension("tmp"); - drop_mutability!(tmp_file); - - // Do a crazy dance with lots of fsync()s to be overly cautious here... - // We never want to end up in a state where we've lost the old data, or end up using the - // old data on power loss after we've returned. - // The way to atomically write a file on Unix platforms is: - // open(tmpname), write(tmpfile), fsync(tmpfile), close(tmpfile), rename(), fsync(dir) - { - // Note that going by rust-lang/rust@d602a6b, on MacOS it is only safe to use - // rust stdlib 1.36 or higher. - let mut buf = BufWriter::new(fs::File::create(&tmp_file)?); - data.write(&mut buf)?; - buf.into_inner()?.sync_all()?; - } - // Fsync the parent directory on Unix. - #[cfg(target_family = "unix")] - { - let parent_directory = dest_file.parent().unwrap(); - fs::rename(&tmp_file, &dest_file)?; - let dir_file = fs::OpenOptions::new().read(true).open(parent_directory)?; - unsafe { - libc::fsync(dir_file.as_raw_fd()); - } - } - #[cfg(target_family = "windows")] - { - if dest_file.exists() { - unsafe { - winapi::um::winbase::ReplaceFileW( - path_to_windows_str(dest_file).as_ptr(), - path_to_windows_str(tmp_file).as_ptr(), - std::ptr::null(), - winapi::um::winbase::REPLACEFILE_IGNORE_MERGE_ERRORS, - std::ptr::null_mut() as *mut winapi::ctypes::c_void, - std::ptr::null_mut() as *mut winapi::ctypes::c_void, - ) - }; - } else { - call!(unsafe { - winapi::um::winbase::MoveFileExW( - path_to_windows_str(tmp_file).as_ptr(), - path_to_windows_str(dest_file).as_ptr(), - winapi::um::winbase::MOVEFILE_WRITE_THROUGH | winapi::um::winbase::MOVEFILE_REPLACE_EXISTING, - ) - }); - } - } - Ok(()) -} - -#[async_trait] -impl LightningStorage for LightningFilesystemPersister { - type Error = std::io::Error; - - async fn init_fs(&self) -> Result<(), Self::Error> { - let path = self.monitors_path(); - let backup_path = self.monitors_backup_path(); - async_blocking(move || { - fs::create_dir_all(path.clone())?; - if let Some(path) = backup_path { - fs::create_dir_all(path.clone())?; - check_dir_operations(&path)?; - check_dir_operations(path.parent().unwrap())?; - } - check_dir_operations(&path)?; - check_dir_operations(path.parent().unwrap()) - }) - .await - } - - async fn is_fs_initialized(&self) -> Result { - let dir_path = self.monitors_path(); - let backup_dir_path = self.monitors_backup_path(); - async_blocking(move || { - if !dir_path.exists() || backup_dir_path.as_ref().map(|path| !path.exists()).unwrap_or(false) { - Ok(false) - } else if !dir_path.is_dir() { - Err(std::io::Error::other(format!( - "{} is not a directory", - dir_path.display() - ))) - } else if backup_dir_path.as_ref().map(|path| !path.is_dir()).unwrap_or(false) { - Err(std::io::Error::other("Backup path is not a directory")) - } else { - let check_backup_ops = if let Some(backup_path) = backup_dir_path { - check_dir_operations(&backup_path).is_ok() - } else { - true - }; - check_dir_operations(&dir_path).map(|_| check_backup_ops) - } - }) - .await - } - - async fn get_nodes_addresses(&self) -> Result { - let path = self.nodes_addresses_path(); - if !path.exists() { - return Ok(HashMap::new()); - } - - let nodes_addresses: HashMap = read_json(&path) - .await - .map_err(|e| invalid_data_err("Error", e))? - .ok_or_else(|| std::io::Error::from(std::io::ErrorKind::NotFound))?; - - nodes_addresses - .iter() - .map(|(pubkey_str, addr)| { - let pubkey = PublicKey::from_str(pubkey_str).map_err(|e| invalid_data_err("Error", e))?; - Ok((pubkey, *addr)) - }) - .collect() - } - - async fn save_nodes_addresses(&self, nodes_addresses: NodesAddressesMapShared) -> Result<(), Self::Error> { - let path = self.nodes_addresses_path(); - let backup_path = self.nodes_addresses_backup_path(); - - let nodes_addresses: HashMap = nodes_addresses - .lock() - .iter() - .map(|(pubkey, addr)| (pubkey.to_string(), *addr)) - .collect(); - - write_json(&nodes_addresses, &path, USE_TMP_FILE) - .await - .map_err(|e| invalid_data_err("Error", e))?; - - if let Some(path) = backup_path { - write_json(&nodes_addresses, &path, USE_TMP_FILE) - .await - .map_err(|e| invalid_data_err("Error", e))?; - } - - Ok(()) - } - - async fn get_network_graph(&self, network: Network, logger: Arc) -> Result { - let path = self.network_graph_path(); - if !path.exists() { - return Ok(NetworkGraph::new(genesis_block(network).header.block_hash(), logger)); - } - async_blocking(move || { - let file = fs::File::open(path)?; - common::log::info!("Reading the saved lightning network graph from file, this can take some time!"); - NetworkGraph::read(&mut BufReader::new(file), logger).map_err(|e| invalid_data_err("Error", e)) - }) - .await - } - - async fn get_scorer(&self, network_graph: Arc, logger: Arc) -> Result { - let path = self.scorer_path(); - if !path.exists() { - return Ok(Mutex::new(ProbabilisticScorer::new( - ProbabilisticScoringParameters::default(), - network_graph, - logger, - ))); - } - async_blocking(move || { - let file = fs::File::open(path)?; - let scorer = ProbabilisticScorer::read( - &mut BufReader::new(file), - (ProbabilisticScoringParameters::default(), network_graph, logger), - ) - .map_err(|e| invalid_data_err("Error", e))?; - Ok(Mutex::new(scorer)) - }) - .await - } - - async fn get_trusted_nodes(&self) -> Result, Self::Error> { - let path = self.trusted_nodes_path(); - if !path.exists() { - return Ok(HashSet::new()); - } - - let trusted_nodes: HashSet = read_json(&path) - .await - .map_err(|e| invalid_data_err("Error", e))? - .ok_or_else(|| std::io::Error::from(std::io::ErrorKind::NotFound))?; - - trusted_nodes - .iter() - .map(|pubkey_str| { - let pubkey = PublicKey::from_str(pubkey_str).map_err(|e| invalid_data_err("Error", e))?; - Ok(pubkey) - }) - .collect() - } - - async fn save_trusted_nodes(&self, trusted_nodes: TrustedNodesShared) -> Result<(), Self::Error> { - let path = self.trusted_nodes_path(); - let trusted_nodes: HashSet = trusted_nodes.lock().iter().map(|pubkey| pubkey.to_string()).collect(); - write_json(&trusted_nodes, &path, USE_TMP_FILE) - .await - .map_err(|e| invalid_data_err("Error", e)) - } -} +// TODO: We should rather upgrade to the new more performant MonitorUpdatingPersister. +pub type LightningFilesystemPersister = FilesystemStore; + +// pub struct LightningFilesystemPersister { +// main_path: PathBuf, +// backup_path: Option, +// } + +// impl LightningFilesystemPersister { +// /// Initialize a new LightningPersister and set the path to the individual channels' +// /// files. +// #[inline] +// pub fn new(main_path: PathBuf, backup_path: Option) -> Self { +// Self { main_path, backup_path } +// } + +// /// Get the directory which was provided when this persister was initialized. +// #[inline] +// pub fn main_path(&self) -> PathBuf { +// self.main_path.clone() +// } + +// /// Get the backup directory which was provided when this persister was initialized. +// #[inline] +// pub fn backup_path(&self) -> Option { +// self.backup_path.clone() +// } + +// pub fn nodes_addresses_path(&self) -> PathBuf { +// let mut path = self.main_path(); +// path.push("channel_nodes_data"); +// path +// } + +// pub fn nodes_addresses_backup_path(&self) -> Option { +// self.backup_path().map(|mut backup_path| { +// backup_path.push("channel_nodes_data"); +// backup_path +// }) +// } + +// pub fn network_graph_path(&self) -> PathBuf { +// let mut path = self.main_path(); +// path.push("network_graph"); +// path +// } + +// pub fn scorer_path(&self) -> PathBuf { +// let mut path = self.main_path(); +// path.push("scorer"); +// path +// } + +// pub fn trusted_nodes_path(&self) -> PathBuf { +// let mut path = self.main_path(); +// path.push("trusted_nodes"); +// path +// } + +// pub fn manager_path(&self) -> PathBuf { +// let mut path = self.main_path(); +// path.push("manager"); +// path +// } + +// pub fn monitors_path(&self) -> PathBuf { +// let mut path = self.main_path(); +// path.push("monitors"); +// path +// } + +// pub fn monitors_backup_path(&self) -> Option { +// self.backup_path().map(|mut backup_path| { +// backup_path.push("monitors"); +// backup_path +// }) +// } + +// /// Read `ChannelMonitor`s from disk. +// pub fn read_channelmonitors( +// &self, +// keys_manager: K, +// ) -> Result)>, std::io::Error> +// where +// K::Target: SignerProvider + Sized, +// { +// let path = self.monitors_path(); +// if !path.exists() { +// return Ok(Vec::new()); +// } +// let mut res = Vec::new(); +// for file_option in fs::read_dir(path)? { +// let file = file_option?; +// let owned_file_name = file.file_name(); +// let filename = owned_file_name +// .to_str() +// .ok_or_else(|| invalid_data_err("Invalid ChannelMonitor file name", format!("{owned_file_name:?}")))?; +// if filename == "checkval" { +// continue; +// } +// if !filename.is_ascii() || filename.len() < 65 { +// return Err(invalid_data_err("Invalid ChannelMonitor file name", filename)); +// } +// if filename.ends_with(".tmp") { +// // If we were in the middle of committing an new update and crashed, it should be +// // safe to ignore the update - we should never have returned to the caller and +// // irrevocably committed to the new state in any way. +// continue; +// } + +// let txid = Txid::from_hex(filename.split_at(64).0) +// .map_err(|e| invalid_data_err("Invalid tx ID in filename error", e))?; + +// let index = filename +// .split_at(65) +// .1 +// .parse::() +// .map_err(|e| invalid_data_err("Invalid tx index in filename error", e))?; + +// let contents = fs::read(file.path())?; +// let mut buffer = Cursor::new(&contents); +// let (blockhash, channel_monitor) = <(BlockHash, ChannelMonitor)>::read(&mut buffer, &*keys_manager) +// .map_err(|e| invalid_data_err("Failed to deserialize ChannelMonito", e))?; + +// if channel_monitor.get_funding_txo().0.txid != txid || channel_monitor.get_funding_txo().0.index != index { +// return Err(invalid_data_err( +// "ChannelMonitor was stored in the wrong file", +// filename, +// )); +// } + +// res.push((blockhash, channel_monitor)); +// } +// Ok(res) +// } +// } + +// impl KVStorePersister for LightningFilesystemPersister { +// fn persist(&self, key: &str, object: &W) -> std::io::Result<()> { +// let mut dest_file = self.main_path(); +// dest_file.push(key); +// drop_mutability!(dest_file); +// write_to_file(dest_file, object)?; + +// if !matches!(key, "network_graph" | "scorer") { +// if let Some(mut dest_file) = self.backup_path() { +// dest_file.push(key); +// drop_mutability!(dest_file); +// write_to_file(dest_file, object)?; +// } +// } + +// Ok(()) +// } +// } + +// #[cfg(target_family = "windows")] +// macro_rules! call { +// ($e: expr) => { +// if $e != 0 { +// return Ok(()); +// } else { +// return Err(std::io::Error::last_os_error()); +// } +// }; +// } + +// #[cfg(target_family = "windows")] +// fn path_to_windows_str>(path: T) -> Vec { +// path.as_ref().encode_wide().chain(Some(0)).collect() +// } + +// fn write_to_file(dest_file: PathBuf, data: &W) -> std::io::Result<()> { +// let mut tmp_file = dest_file.clone(); +// tmp_file.set_extension("tmp"); +// drop_mutability!(tmp_file); + +// // Do a crazy dance with lots of fsync()s to be overly cautious here... +// // We never want to end up in a state where we've lost the old data, or end up using the +// // old data on power loss after we've returned. +// // The way to atomically write a file on Unix platforms is: +// // open(tmpname), write(tmpfile), fsync(tmpfile), close(tmpfile), rename(), fsync(dir) +// { +// // Note that going by rust-lang/rust@d602a6b, on MacOS it is only safe to use +// // rust stdlib 1.36 or higher. +// let mut buf = BufWriter::new(fs::File::create(&tmp_file)?); +// data.write(&mut buf)?; +// buf.into_inner()?.sync_all()?; +// } +// // Fsync the parent directory on Unix. +// #[cfg(target_family = "unix")] +// { +// let parent_directory = dest_file.parent().unwrap(); +// fs::rename(&tmp_file, &dest_file)?; +// let dir_file = fs::OpenOptions::new().read(true).open(parent_directory)?; +// unsafe { +// libc::fsync(dir_file.as_raw_fd()); +// } +// } +// #[cfg(target_family = "windows")] +// { +// if dest_file.exists() { +// unsafe { +// winapi::um::winbase::ReplaceFileW( +// path_to_windows_str(dest_file).as_ptr(), +// path_to_windows_str(tmp_file).as_ptr(), +// std::ptr::null(), +// winapi::um::winbase::REPLACEFILE_IGNORE_MERGE_ERRORS, +// std::ptr::null_mut() as *mut winapi::ctypes::c_void, +// std::ptr::null_mut() as *mut winapi::ctypes::c_void, +// ) +// }; +// } else { +// call!(unsafe { +// winapi::um::winbase::MoveFileExW( +// path_to_windows_str(tmp_file).as_ptr(), +// path_to_windows_str(dest_file).as_ptr(), +// winapi::um::winbase::MOVEFILE_WRITE_THROUGH | winapi::um::winbase::MOVEFILE_REPLACE_EXISTING, +// ) +// }); +// } +// } +// Ok(()) +// } + +// #[async_trait] +// impl LightningStorage for LightningFilesystemPersister { +// type Error = std::io::Error; + +// async fn init_fs(&self) -> Result<(), Self::Error> { +// let path = self.monitors_path(); +// let backup_path = self.monitors_backup_path(); +// async_blocking(move || { +// fs::create_dir_all(path.clone())?; +// if let Some(path) = backup_path { +// fs::create_dir_all(path.clone())?; +// check_dir_operations(&path)?; +// check_dir_operations(path.parent().unwrap())?; +// } +// check_dir_operations(&path)?; +// check_dir_operations(path.parent().unwrap()) +// }) +// .await +// } + +// async fn is_fs_initialized(&self) -> Result { +// let dir_path = self.monitors_path(); +// let backup_dir_path = self.monitors_backup_path(); +// async_blocking(move || { +// if !dir_path.exists() || backup_dir_path.as_ref().map(|path| !path.exists()).unwrap_or(false) { +// Ok(false) +// } else if !dir_path.is_dir() { +// Err(std::io::Error::other(format!( +// "{} is not a directory", +// dir_path.display() +// ))) +// } else if backup_dir_path.as_ref().map(|path| !path.is_dir()).unwrap_or(false) { +// Err(std::io::Error::other("Backup path is not a directory")) +// } else { +// let check_backup_ops = if let Some(backup_path) = backup_dir_path { +// check_dir_operations(&backup_path).is_ok() +// } else { +// true +// }; +// check_dir_operations(&dir_path).map(|_| check_backup_ops) +// } +// }) +// .await +// } + +// async fn get_nodes_addresses(&self) -> Result { +// let path = self.nodes_addresses_path(); +// if !path.exists() { +// return Ok(HashMap::new()); +// } + +// let nodes_addresses: HashMap = read_json(&path) +// .await +// .map_err(|e| invalid_data_err("Error", e))? +// .ok_or_else(|| std::io::Error::from(std::io::ErrorKind::NotFound))?; + +// nodes_addresses +// .iter() +// .map(|(pubkey_str, addr)| { +// let pubkey = PublicKey::from_str(pubkey_str).map_err(|e| invalid_data_err("Error", e))?; +// Ok((pubkey, *addr)) +// }) +// .collect() +// } + +// async fn save_nodes_addresses(&self, nodes_addresses: NodesAddressesMapShared) -> Result<(), Self::Error> { +// let path = self.nodes_addresses_path(); +// let backup_path = self.nodes_addresses_backup_path(); + +// let nodes_addresses: HashMap = nodes_addresses +// .lock() +// .iter() +// .map(|(pubkey, addr)| (pubkey.to_string(), *addr)) +// .collect(); + +// write_json(&nodes_addresses, &path, USE_TMP_FILE) +// .await +// .map_err(|e| invalid_data_err("Error", e))?; + +// if let Some(path) = backup_path { +// write_json(&nodes_addresses, &path, USE_TMP_FILE) +// .await +// .map_err(|e| invalid_data_err("Error", e))?; +// } + +// Ok(()) +// } + +// async fn get_network_graph(&self, network: Network, logger: Arc) -> Result { +// let path = self.network_graph_path(); +// if !path.exists() { +// return Ok(NetworkGraph::new(genesis_block(network).header.block_hash(), logger)); +// } +// async_blocking(move || { +// let file = fs::File::open(path)?; +// common::log::info!("Reading the saved lightning network graph from file, this can take some time!"); +// NetworkGraph::read(&mut BufReader::new(file), logger).map_err(|e| invalid_data_err("Error", e)) +// }) +// .await +// } + +// async fn get_scorer(&self, network_graph: Arc, logger: Arc) -> Result { +// let path = self.scorer_path(); +// if !path.exists() { +// return Ok(Mutex::new(ProbabilisticScorer::new( +// ProbabilisticScoringDecayParameters::default(), +// network_graph, +// logger, +// ))); +// } +// async_blocking(move || { +// let file = fs::File::open(path)?; +// let scorer = ProbabilisticScorer::read( +// &mut BufReader::new(file), +// (ProbabilisticScoringDecayParameters::default(), network_graph, logger), +// ) +// .map_err(|e| invalid_data_err("Error", e))?; +// Ok(Mutex::new(scorer)) +// }) +// .await +// } + +// async fn get_trusted_nodes(&self) -> Result, Self::Error> { +// let path = self.trusted_nodes_path(); +// if !path.exists() { +// return Ok(HashSet::new()); +// } + +// let trusted_nodes: HashSet = read_json(&path) +// .await +// .map_err(|e| invalid_data_err("Error", e))? +// .ok_or_else(|| std::io::Error::from(std::io::ErrorKind::NotFound))?; + +// trusted_nodes +// .iter() +// .map(|pubkey_str| { +// let pubkey = PublicKey::from_str(pubkey_str).map_err(|e| invalid_data_err("Error", e))?; +// Ok(pubkey) +// }) +// .collect() +// } + +// async fn save_trusted_nodes(&self, trusted_nodes: TrustedNodesShared) -> Result<(), Self::Error> { +// let path = self.trusted_nodes_path(); +// let trusted_nodes: HashSet = trusted_nodes.lock().iter().map(|pubkey| pubkey.to_string()).collect(); +// write_json(&trusted_nodes, &path, USE_TMP_FILE) +// .await +// .map_err(|e| invalid_data_err("Error", e)) +// } +// } diff --git a/mm2src/coins/lightning/ln_p2p.rs b/mm2src/coins/lightning/ln_p2p.rs index 8a3374ab73..25b6a50a82 100644 --- a/mm2src/coins/lightning/ln_p2p.rs +++ b/mm2src/coins/lightning/ln_p2p.rs @@ -2,15 +2,14 @@ use super::*; use common::executor::{spawn_abortable, SpawnFuture, Timer}; use common::log::LogState; use derive_more::Display; -use lightning::chain::Access; -use lightning::ln::msgs::NetAddress; +use lightning::ln::msgs::SocketAddress; use lightning::ln::peer_handler::{IgnoringMessageHandler, MessageHandler, SimpleArcPeerManager}; -use lightning::onion_message::SimpleArcOnionMessenger; use lightning::routing::gossip; +use lightning::routing::utxo::UtxoLookup; use lightning_net_tokio::SocketDescriptor; use mm2_net::ip_addr::fetch_external_ip; use rand::RngCore; -use secp256k1v24::PublicKey; +use secp256k1::PublicKey; use std::net::{IpAddr, Ipv4Addr}; use std::num::TryFromIntError; use tokio::net::TcpListener; @@ -18,10 +17,15 @@ use tokio::net::TcpListener; const TRY_RECONNECTING_TO_NODE_INTERVAL: f64 = 60.; const BROADCAST_NODE_ANNOUNCEMENT_INTERVAL: u64 = 600; -pub type NetworkGossip = gossip::P2PGossipSync, Arc, Arc>; -type OnionMessenger = SimpleArcOnionMessenger; -pub type PeerManager = - SimpleArcPeerManager; +pub type NetworkGossip = gossip::P2PGossipSync, Arc, Arc>; +pub type PeerManager = SimpleArcPeerManager< + SocketDescriptor, + ChainMonitor, + Platform, + Platform, + Arc, + LogState, +>; #[derive(Display)] pub enum ConnectToNodeRes { @@ -99,24 +103,6 @@ pub async fn connect_to_ln_nodes_loop(open_channels_nodes: NodesAddressesMapShar } } -// TODO: add TOR address option -fn netaddress_from_ipaddr(addr: IpAddr, port: u16) -> Vec { - if addr == Ipv4Addr::new(0, 0, 0, 0) || addr == Ipv4Addr::new(127, 0, 0, 1) { - return Vec::new(); - } - let address = match addr { - IpAddr::V4(addr) => NetAddress::IPv4 { - addr: u32::from(addr).to_be_bytes(), - port, - }, - IpAddr::V6(addr) => NetAddress::IPv6 { - addr: u128::from(addr).to_be_bytes(), - port, - }, - }; - vec![address] -} - pub async fn ln_node_announcement_loop( peer_manager: Arc, node_name: [u8; 32], @@ -130,7 +116,8 @@ pub async fn ln_node_announcement_loop( let addresses = match fetch_external_ip().await { Ok(ip) => { log::debug!("Fetch real IP successfully: {}:{}", ip, port); - netaddress_from_ipaddr(ip, port) + // TODO: add TOR address option + vec![SocketAddress::from(std::net::SocketAddr::new(ip, port))] }, Err(e) => { log::error!("Error while fetching external ip for node announcement: {}", e); @@ -190,15 +177,11 @@ pub async fn init_peer_manager( // ephemeral_random_data is used to derive per-connection ephemeral keys let mut ephemeral_bytes = [0; 32]; rand::thread_rng().fill_bytes(&mut ephemeral_bytes); - let onion_message_handler = Arc::new(OnionMessenger::new( - keys_manager.clone(), - logger.clone(), - IgnoringMessageHandler {}, - )); let lightning_msg_handler = MessageHandler { chan_handler: channel_manager, route_handler: gossip_sync, - onion_message_handler, + onion_message_handler: IgnoringMessageHandler {}, + custom_message_handler: IgnoringMessageHandler {}, }; let node_secret = keys_manager diff --git a/mm2src/coins/lightning/ln_platform.rs b/mm2src/coins/lightning/ln_platform.rs index 634918bd0d..ba0af00253 100644 --- a/mm2src/coins/lightning/ln_platform.rs +++ b/mm2src/coins/lightning/ln_platform.rs @@ -9,7 +9,7 @@ use crate::utxo::spv::SimplePaymentVerification; use crate::utxo::utxo_standard::UtxoStandardCoin; use crate::utxo::GetConfirmedTxError; use crate::{MarketCoinOps, MmCoin, WaitForHTLCTxSpendArgs, WeakSpawner}; -use bitcoin::blockdata::block::BlockHeader; +use bitcoin::blockdata::block::Header as BlockHeader; use bitcoin::blockdata::script::Script; use bitcoin::blockdata::transaction::Transaction; use bitcoin::consensus::encode::{deserialize, serialize_hex}; @@ -20,6 +20,7 @@ use common::log::{debug, error, info}; use common::{block_on_f01, wait_until_sec}; use futures::compat::Future01CompatExt; use futures::future::join_all; +use hex::FromHexError; use keys::hash::H256; use lightning::chain::{ chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}, @@ -616,42 +617,49 @@ impl FeeEstimator for Platform { } impl BroadcasterInterface for Platform { - fn broadcast_transaction(&self, tx: &Transaction) { - let txid = tx.txid(); - let tx_hex = serialize_hex(tx); - debug!("Trying to broadcast transaction: {}", tx_hex); - let tx_bytes = match hex::decode(&tx_hex) { - Ok(b) => b, + // TODO: If multiple transactions are passed, they should be broadcast in a package. (check the doc comment of the trait method) + fn broadcast_transactions(&self, tx: &[&Transaction]) { + let txids_and_tx_bytes = match tx + .iter() + .map(|tx| hex::decode(serialize_hex(tx)).map(|tx_bytes| (tx.txid(), tx_bytes))) + .collect::, FromHexError>>() + { + Ok(map) => map, Err(e) => { - error!("Converting transaction to bytes error:{}", e); + error!("Converting transaction to bytes error: {}", e); return; }, }; let platform_coin = self.coin.clone(); let fut = async move { - loop { - match platform_coin - .as_ref() - .rpc_client - .send_raw_transaction(tx_bytes.clone().into()) - .compat() - .await - { - Ok(id) => { - info!("Transaction broadcasted successfully: {:?} ", id); - break; - }, - // Todo: broadcast transaction through p2p network instead in case of error - // Todo: I don't want to rely on p2p broadcasting for now since there is no way to know if there are nodes running bitcoin in native mode or not - // Todo: Also we need to make sure that the transaction was broadcasted after relying on the p2p network - Err(e) => { - error!("Broadcast transaction {} failed: {}", txid, e); - if !e.get_inner().is_network_error() { + for (txid, tx_bytes) in txids_and_tx_bytes { + debug!("Trying to broadcast transaction: {}", txid); + + loop { + match platform_coin + .as_ref() + .rpc_client + .send_raw_transaction(tx_bytes.clone().into()) + .compat() + .await + { + Ok(id) => { + info!("Transaction broadcasted successfully: {:?} ", id); break; - } - Timer::sleep(TRY_LOOP_INTERVAL).await; - }, + }, + // Todo: broadcast transaction through p2p network instead in case of error + // Todo: I don't want to rely on p2p broadcasting for now since there is no way to know if there are nodes running bitcoin in native mode or not + // Todo: Also we need to make sure that the transaction was broadcasted after relying on the p2p network + // TODO: After upgrading to lightning v0.0.119, looks like retrials are now handled via LDK. So this might not be needed anymore. + Err(e) => { + error!("Broadcast transaction {} failed: {}", txid, e); + if !e.get_inner().is_network_error() { + break; + } + Timer::sleep(TRY_LOOP_INTERVAL).await; + }, + } } } }; diff --git a/mm2src/coins/lightning/ln_serialization.rs b/mm2src/coins/lightning/ln_serialization.rs index 7a3c1b0bda..05e0941292 100644 --- a/mm2src/coins/lightning/ln_serialization.rs +++ b/mm2src/coins/lightning/ln_serialization.rs @@ -3,7 +3,7 @@ use crate::lightning::ln_platform::h256_json_from_txid; use crate::H256Json; use lightning::chain::channelmonitor::Balance; use lightning::ln::channelmanager::ChannelDetails; -use secp256k1v24::PublicKey; +use secp256k1::PublicKey; use serde::{de, Serialize, Serializer}; use std::fmt; use std::net::{SocketAddr, ToSocketAddrs}; @@ -330,43 +330,44 @@ pub enum ClaimableBalance { impl From for ClaimableBalance { fn from(balance: Balance) -> Self { match balance { - Balance::ClaimableOnChannelClose { - claimable_amount_satoshis, - } => ClaimableBalance::ClaimableOnChannelClose { - claimable_amount_satoshis, + Balance::ClaimableOnChannelClose { amount_satoshis } => ClaimableBalance::ClaimableOnChannelClose { + claimable_amount_satoshis: amount_satoshis, }, Balance::ClaimableAwaitingConfirmations { - claimable_amount_satoshis, + amount_satoshis, confirmation_height, } => ClaimableBalance::ClaimableAwaitingConfirmations { - claimable_amount_satoshis, + claimable_amount_satoshis: amount_satoshis, confirmation_height, }, Balance::ContentiousClaimable { - claimable_amount_satoshis, + amount_satoshis, timeout_height, + .. } => ClaimableBalance::ContentiousClaimable { - claimable_amount_satoshis, + claimable_amount_satoshis: amount_satoshis, timeout_height, }, Balance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis, + amount_satoshis, claimable_height, + .. } => ClaimableBalance::MaybeTimeoutClaimableHTLC { - claimable_amount_satoshis, + claimable_amount_satoshis: amount_satoshis, claimable_height, }, Balance::MaybePreimageClaimableHTLC { - claimable_amount_satoshis, + amount_satoshis, expiry_height, + .. } => ClaimableBalance::MaybePreimageClaimableHTLC { - claimable_amount_satoshis, + claimable_amount_satoshis: amount_satoshis, expiry_height, }, - Balance::CounterpartyRevokedOutputClaimable { - claimable_amount_satoshis, - } => ClaimableBalance::CounterpartyRevokedOutputClaimable { - claimable_amount_satoshis, + Balance::CounterpartyRevokedOutputClaimable { amount_satoshis } => { + ClaimableBalance::CounterpartyRevokedOutputClaimable { + claimable_amount_satoshis: amount_satoshis, + } }, } } diff --git a/mm2src/coins/lightning/ln_sql.rs b/mm2src/coins/lightning/ln_sql.rs index 58af0e1bec..d7695f54ef 100644 --- a/mm2src/coins/lightning/ln_sql.rs +++ b/mm2src/coins/lightning/ln_sql.rs @@ -16,7 +16,7 @@ use db_common::sqlite::{ CHECK_TABLE_EXISTS_SQL, }; use lightning::ln::{PaymentHash, PaymentPreimage}; -use secp256k1v24::PublicKey; +use secp256k1::PublicKey; use std::convert::TryInto; use std::str::FromStr; use uuid::Uuid; @@ -1039,7 +1039,7 @@ mod tests { use db_common::sqlite::rusqlite::{self, Connection}; use rand::distributions::Alphanumeric; use rand::{Rng, RngCore}; - use secp256k1v24::{Secp256k1, SecretKey}; + use secp256k1::{Secp256k1, SecretKey}; use std::num::NonZeroUsize; use std::sync::{Arc, Mutex}; diff --git a/mm2src/coins/lightning/ln_storage.rs b/mm2src/coins/lightning/ln_storage.rs index 9ece4d2e8f..2b0666f31b 100644 --- a/mm2src/coins/lightning/ln_storage.rs +++ b/mm2src/coins/lightning/ln_storage.rs @@ -1,12 +1,20 @@ use async_trait::async_trait; -use bitcoin::Network; +use bitcoin::{BlockHash, Network, Txid}; use common::log::LogState; +use lightning::chain::channelmonitor::ChannelMonitor; use lightning::routing::gossip; -use lightning::routing::scoring::ProbabilisticScorer; +use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringDecayParameters}; +use lightning::sign::ecdsa::WriteableEcdsaChannelSigner as Sign; +use lightning::sign::SignerProvider; +use lightning::util::persist::KVStore; +use lightning::util::ser::ReadableArgs; +use mm2_io::fs::invalid_data_err; use parking_lot::Mutex as PaMutex; -use secp256k1v24::PublicKey; +use secp256k1::PublicKey; use std::collections::{HashMap, HashSet}; use std::net::SocketAddr; +use std::ops::Deref; +use std::str::FromStr; use std::sync::{Arc, Mutex}; pub type NodesAddressesMap = HashMap; @@ -21,9 +29,9 @@ pub trait LightningStorage { type Error; /// Initializes dirs/collection/tables in storage for a specified coin - async fn init_fs(&self) -> Result<(), Self::Error>; + // async fn init_fs(&self) -> Result<(), Self::Error>; - async fn is_fs_initialized(&self) -> Result; + // async fn is_fs_initialized(&self) -> Result; async fn get_nodes_addresses(&self) -> Result; @@ -36,4 +44,112 @@ pub trait LightningStorage { async fn get_trusted_nodes(&self) -> Result, Self::Error>; async fn save_trusted_nodes(&self, trusted_nodes: TrustedNodesShared) -> Result<(), Self::Error>; + + fn read_channelmonitors( + &self, + keys_manager: K, + ) -> Result)>, std::io::Error> + where + K::Target: SignerProvider + Sized; +} + +#[async_trait] +impl LightningStorage for Store { + type Error = std::io::Error; + + async fn get_nodes_addresses(&self) -> Result { + let content = self.read("", "", "channel_nodes_data")?; + serde_json::from_slice(&content).map_err(|err| invalid_data_err("Error", err)) + } + + async fn save_nodes_addresses(&self, nodes_addresses: NodesAddressesMapShared) -> Result<(), Self::Error> { + let nodes_addresses: HashMap = nodes_addresses + .lock() + .iter() + .map(|(pubkey, addr)| (pubkey.to_string(), *addr)) + .collect(); + let content = serde_json::to_vec(&nodes_addresses).map_err(|err| invalid_data_err("Error", err))?; + self.write("", "", "channel_nodes_data", &content) + } + + async fn get_network_graph(&self, network: Network, logger: Arc) -> Result { + common::log::info!("Reading the saved lightning network graph from file, this can take some time!"); + let content = self.read("", "", "network_graph")?; + NetworkGraph::read(&mut content, logger).map_err(|e| invalid_data_err("Error", e)) + } + + async fn get_scorer(&self, network_graph: Arc, logger: Arc) -> Result { + let content = self.read("", "", "scorer")?; + let scorer = ProbabilisticScorer::read( + &mut content.as_slice(), + (ProbabilisticScoringDecayParameters::default(), network_graph, logger), + ) + .map_err(|e| invalid_data_err("Error", e))?; + Ok(Mutex::new(scorer)) + } + + async fn get_trusted_nodes(&self) -> Result, Self::Error> { + let content = self.read("", "", "trusted_nodes")?; + let trusted_nodes: HashSet = + serde_json::from_slice(&content).map_err(|err| invalid_data_err("Error", err))?; + trusted_nodes + .iter() + .map(|pubkey_str| { + let pubkey = PublicKey::from_str(pubkey_str).map_err(|e| invalid_data_err("Error", e))?; + Ok(pubkey) + }) + .collect() + } + + async fn save_trusted_nodes(&self, trusted_nodes: TrustedNodesShared) -> Result<(), Self::Error> { + let trusted_nodes: HashSet = trusted_nodes.lock().iter().map(|pubkey| pubkey.to_string()).collect(); + let content = serde_json::to_vec(&trusted_nodes).map_err(|err| invalid_data_err("Error", err))?; + self.write("", "", "trusted_nodes", &content) + } + + /// Read `ChannelMonitor`s from disk. + fn read_channelmonitors( + &self, + keys_manager: K, + ) -> Result)>, std::io::Error> + where + K::Target: SignerProvider + Sized, + { + let mut res = Vec::new(); + for filename in self.list("monitors", "")? { + if filename.len() < 65 { + return Err(invalid_data_err("Invalid ChannelMonitor file name", filename)); + } + if filename.ends_with(".tmp") { + // If we were in the middle of committing an new update and crashed, it should be + // safe to ignore the update - we should never have returned to the caller and + // irrevocably committed to the new state in any way. + continue; + } + + let txid = Txid::from_hex(filename.split_at(64).0) + .map_err(|e| invalid_data_err("Invalid tx ID in filename error", e))?; + + let index = filename + .split_at(65) + .1 + .parse::() + .map_err(|e| invalid_data_err("Invalid tx index in filename error", e))?; + + let content = self.read("monitors", "", &filename)?; + let (blockhash, channel_monitor) = + <(BlockHash, ChannelMonitor)>::read(&mut content, &*keys_manager) + .map_err(|e| invalid_data_err("Failed to deserialize ChannelMonito", e))?; + + if channel_monitor.get_funding_txo().0.txid != txid || channel_monitor.get_funding_txo().0.index != index { + return Err(invalid_data_err( + "ChannelMonitor was stored in the wrong file", + filename, + )); + } + + res.push((blockhash, channel_monitor)); + } + Ok(res) + } } diff --git a/mm2src/coins/lightning/ln_utils.rs b/mm2src/coins/lightning/ln_utils.rs index 7263d09858..30764d79fe 100644 --- a/mm2src/coins/lightning/ln_utils.rs +++ b/mm2src/coins/lightning/ln_utils.rs @@ -9,13 +9,15 @@ use bitcoin_hashes::{sha256d, Hash}; use common::executor::SpawnFuture; use common::log::LogState; use derive_more::Display; -use lightning::chain::keysinterface::{InMemorySigner, KeysManager}; use lightning::chain::{chainmonitor, BestBlock, ChannelMonitorUpdateStatus, Watch}; use lightning::ln::channelmanager::{ - ChainParameters, ChannelManagerReadArgs, PaymentId, PaymentSendFailure, SimpleArcChannelManager, + ChainParameters, ChannelManagerReadArgs, PaymentId, PaymentSendFailure, RecipientOnionFields, + SimpleArcChannelManager, }; use lightning::routing::gossip::RoutingFees; use lightning::routing::router::{PaymentParameters, RouteHint, RouteHintHop, RouteParameters, Router as RouterTrait}; +use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters}; +use lightning::sign::{InMemorySigner, KeysManager}; use lightning::util::config::UserConfig; use lightning::util::errors::APIError; use lightning::util::ser::ReadableArgs; @@ -38,7 +40,13 @@ pub type ChainMonitor = chainmonitor::ChainMonitor< >; pub type ChannelManager = SimpleArcChannelManager; -pub type Router = DefaultRouter, Arc, Arc>; +pub type Router = DefaultRouter< + Arc, + Arc, + Arc, + ProbabilisticScoringFeeParameters, + ProbabilisticScorer, Arc>, +>; #[derive(Debug, PartialEq)] pub struct RpcBestBlock { @@ -74,16 +82,9 @@ pub async fn init_persister( ctx: &MmArc, platform_coin_address: &str, ticker: String, - backup_path: Option, ) -> EnableLightningResult> { let ln_data_dir = ln_data_dir(ctx, platform_coin_address, &ticker); - let ln_data_backup_dir = ln_data_backup_dir(backup_path, platform_coin_address, &ticker); - let persister = Arc::new(LightningFilesystemPersister::new(ln_data_dir, ln_data_backup_dir)); - - let is_initialized = persister.is_fs_initialized().await?; - if !is_initialized { - persister.init_fs().await?; - } + let persister = Arc::new(LightningFilesystemPersister::new(ln_data_dir)); Ok(persister) } @@ -128,6 +129,7 @@ pub async fn init_channel_manager( persister: Arc, db: SqliteLightningDB, keys_manager: Arc, + router: Arc, user_config: UserConfig, ) -> EnableLightningResult<(Arc, Arc)> { // Initialize the FeeEstimator. UtxoStandardCoin implements the FeeEstimator trait, so it'll act as our fee estimator. @@ -160,7 +162,7 @@ pub async fn init_channel_manager( for (_, chan_mon) in channelmonitors.iter() { // Although there is a mutex lock inside the load_outputs_to_watch fn // it shouldn't be held by anything yet, so async_blocking is not needed. - chan_mon.load_outputs_to_watch(&platform); + chan_mon.load_outputs_to_watch(&platform, &logger); } let rpc_client = match &platform.coin.as_ref().rpc_client { @@ -190,10 +192,13 @@ pub async fn init_channel_manager( // Read ChannelManager data from the file let read_args = ChannelManagerReadArgs::new( + keys_manager.clone(), + keys_manager.clone(), keys_manager.clone(), fee_estimator.clone(), chain_monitor_for_args, broadcaster.clone(), + router, logger.clone(), user_config, channel_monitor_mut_references, @@ -244,10 +249,14 @@ pub async fn init_channel_manager( fee_estimator.clone(), chain_monitor.clone(), broadcaster.clone(), + router, logger.clone(), keys_manager.clone(), + keys_manager.clone(), + keys_manager.clone(), user_config, chain_params, + now_sec() as u32, )) }; @@ -349,7 +358,7 @@ pub(crate) fn filter_channels(channels: Vec, min_inbound_capacit #[derive(Debug, Display)] pub enum PaymentError { #[display(fmt = "Final cltv expiry delta {_0} is below the required minimum of {_1}")] - CLTVExpiry(u32, u32), + CLTVExpiry(u16, u16), #[display(fmt = "Error paying invoice: {_0}")] Invoice(String), #[display(fmt = "Keysend error: {_0}")] @@ -382,10 +391,11 @@ pub(crate) fn pay_invoice_with_max_total_cltv_expiry_delta( .ok_or(InvoicePaymentError::Invoice("amount missing"))?; let expiry_time = (invoice.duration_since_epoch() + invoice.expiry_time()).as_secs(); - let mut payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key()) - .with_expiry_time(expiry_time) - .with_route_hints(invoice.route_hints()) - .with_max_total_cltv_expiry_delta(max_total_cltv_expiry_delta); + let mut payment_params = + PaymentParameters::from_node_id(invoice.recover_payee_pub_key(), invoice.min_final_cltv_expiry() as u32) + .with_expiry_time(expiry_time) + .with_route_hints(invoice.route_hints()) + .with_max_total_cltv_expiry_delta(max_total_cltv_expiry_delta); if let Some(features) = invoice.features() { payment_params = payment_params.with_features(features.clone()); } @@ -393,7 +403,8 @@ pub(crate) fn pay_invoice_with_max_total_cltv_expiry_delta( let route_params = RouteParameters { payment_params, final_value_msat, - final_cltv_expiry_delta: invoice.min_final_cltv_expiry() as u32, + // TODO: Set a sensible default for max_total_routing_fee_msat + max_total_routing_fee_msat: None, }; pay_internal(channel_manager, router, &route_params, invoice, &mut 0, &mut Vec::new()) @@ -407,8 +418,8 @@ fn pay_internal( attempts: &mut usize, errors: &mut Vec, ) -> Result { - let payer = channel_manager.node_id(); - let first_hops = channel_manager.first_hops(); + let payer = channel_manager.get_our_node_id(); + let first_hops = channel_manager.list_usable_channels(); let payment_hash_inner = invoice.payment_hash().into_inner(); let payment_hash = PaymentHash(payment_hash_inner); let payment_id = PaymentId(payment_hash_inner); @@ -423,8 +434,8 @@ fn pay_internal( ) .map_err(InvoicePaymentError::Routing)?; - let payment_secret = Some(*invoice.payment_secret()); - match channel_manager.send_payment(&route, payment_hash, &payment_secret, payment_id) { + let onion_fields = RecipientOnionFields::secret_only(invoice.payment_secret().clone()); + match channel_manager.send_payment_with_route(&route, payment_hash, onion_fields, payment_id) { Ok(()) => Ok(payment_id), Err(e) => match e { PaymentSendFailure::ParameterError(_) => Err(e), @@ -480,8 +491,8 @@ fn retry_payment( attempts: &mut usize, errors: &mut Vec, ) -> Result<(), PaymentError> { - let payer = channel_manager.node_id(); - let first_hops = channel_manager.first_hops(); + let payer = channel_manager.get_our_node_id(); + let first_hops = channel_manager.list_usable_channels(); let inflight_htlcs = channel_manager.compute_inflight_htlcs(); let route = router .find_route( diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 878d0101af..e42d37f20c 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -97,13 +97,17 @@ use std::{fmt, iter}; use utxo_signer::with_key_pair::UtxoSignWithKeyPairError; use zcash_primitives::transaction::Transaction as ZTransaction; +#[cfg(feature = "enable-lightning")] cfg_native! { use crate::lightning::LightningCoin; use crate::lightning::ln_conf::PlatformCoinConfirmationTargets; use ::lightning::ln::PaymentHash as LightningPayment; + use lightning_invoice::{Invoice, ParseOrSemanticError}; +} + +cfg_native! { use async_std::fs; use futures::AsyncWriteExt; - use lightning_invoice::{Invoice, ParseOrSemanticError}; use std::io; use std::path::PathBuf; } @@ -241,7 +245,7 @@ use hd_wallet::{ HDWalletOps, HDWithdrawError, HDXPubExtractor, WithdrawSenderAddress, }; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] pub mod lightning; #[cfg_attr(target_arch = "wasm32", allow(dead_code, unused_imports))] pub mod my_tx_history_v2; @@ -616,23 +620,23 @@ pub enum TransactionEnum { SignedEthTx(SignedEthTx), ZTransaction(ZTransaction), CosmosTransaction(CosmosTransaction), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] LightningPayment(LightningPayment), } ifrom!(TransactionEnum, UtxoTx); ifrom!(TransactionEnum, SignedEthTx); ifrom!(TransactionEnum, ZTransaction); -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] ifrom!(TransactionEnum, LightningPayment); impl TransactionEnum { - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] pub fn supports_tx_helper(&self) -> bool { !matches!(self, TransactionEnum::LightningPayment(_)) } - #[cfg(target_arch = "wasm32")] + #[cfg(not(feature = "enable-lightning"))] pub fn supports_tx_helper(&self) -> bool { true } @@ -647,7 +651,7 @@ impl Deref for TransactionEnum { TransactionEnum::SignedEthTx(ref t) => t, TransactionEnum::ZTransaction(ref t) => t, TransactionEnum::CosmosTransaction(ref t) => t, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] TransactionEnum::LightningPayment(ref p) => p, } } @@ -1053,7 +1057,7 @@ pub struct WaitForHTLCTxSpendArgs<'a> { #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] pub enum PaymentInstructions { - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] Lightning(Invoice), WatcherReward(BigDecimal), } @@ -1083,7 +1087,7 @@ pub enum ValidateInstructionsErr { DeserializationErr(String), } -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] impl From for ValidateInstructionsErr { fn from(e: ParseOrSemanticError) -> Self { ValidateInstructionsErr::ValidateLightningInvoiceErr(e.to_string()) @@ -3722,7 +3726,7 @@ pub enum MmCoinEnum { SlpToken(SlpToken), Tendermint(TendermintCoin), TendermintToken(TendermintToken), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] LightningCoin(LightningCoin), #[cfg(feature = "enable-sia")] SiaCoin(SiaCoin), @@ -3787,7 +3791,7 @@ impl From for MmCoinEnum { } } -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] impl From for MmCoinEnum { fn from(c: LightningCoin) -> MmCoinEnum { MmCoinEnum::LightningCoin(c) @@ -3827,7 +3831,7 @@ impl Deref for MmCoinEnum { MmCoinEnum::SlpToken(ref c) => c, MmCoinEnum::Tendermint(ref c) => c, MmCoinEnum::TendermintToken(ref c) => c, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] MmCoinEnum::LightningCoin(ref c) => c, MmCoinEnum::ZCoin(ref c) => c, #[cfg(feature = "enable-sia")] @@ -3871,7 +3875,7 @@ impl MmCoinEnum { MmCoinEnum::Tendermint(_) | MmCoinEnum::TendermintToken(_) | MmCoinEnum::EthCoin(_) => { SecretHashAlgo::SHA256 }, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] MmCoinEnum::LightningCoin(_) => SecretHashAlgo::SHA256, _ => SecretHashAlgo::DHASH160, } @@ -4757,7 +4761,7 @@ pub enum CoinProtocol { }, TENDERMINT(TendermintProtocolInfo), TENDERMINTTOKEN(TendermintTokenProtocolInfo), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] LIGHTNING { platform: String, network: BlockchainNetwork, @@ -4802,7 +4806,7 @@ impl CoinProtocol { | CoinProtocol::SLPTOKEN { platform, .. } | CoinProtocol::NFT { platform, .. } => Some(platform), CoinProtocol::TENDERMINTTOKEN(info) => Some(&info.platform), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] CoinProtocol::LIGHTNING { platform, .. } => Some(platform), CoinProtocol::UTXO { .. } | CoinProtocol::QTUM @@ -4832,7 +4836,7 @@ impl CoinProtocol { | CoinProtocol::TENDERMINTTOKEN(_) | CoinProtocol::ZHTLC(_) | CoinProtocol::NFT { .. } => None, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] CoinProtocol::LIGHTNING { .. } => None, #[cfg(feature = "enable-sia")] CoinProtocol::SIA => None, @@ -5182,7 +5186,7 @@ pub async fn lp_coininit(ctx: &MmArc, ticker: &str, req: &Json) -> Result return ERR!("ZHTLC protocol is not supported by lp_coininit"), CoinProtocol::NFT { .. } => return ERR!("NFT protocol is not supported by lp_coininit"), CoinProtocol::TRX { .. } => return ERR!("TRX protocol is not supported by lp_coininit"), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] CoinProtocol::LIGHTNING { .. } => return ERR!("Lightning protocol is not supported by lp_coininit"), #[cfg(feature = "enable-sia")] CoinProtocol::SIA => { @@ -5824,7 +5828,7 @@ pub fn address_by_coin_conf_and_pubkey_str( _ => ERR!("Platform protocol {:?} is not TENDERMINT", platform_protocol), } }, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] CoinProtocol::LIGHTNING { .. } => { ERR!("address_by_coin_conf_and_pubkey_str is not implemented for lightning protocol yet!") }, diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index ba44aeaad2..3f4f6df23d 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -1414,11 +1414,11 @@ impl MmCoin for Qrc20Coin { } fn swap_contract_address(&self) -> Option { - Some(BytesJson::from(self.swap_contract_address.0.as_ref())) + Some(BytesJson::new(self.swap_contract_address.0.to_vec())) } fn fallback_swap_contract(&self) -> Option { - self.fallback_swap_contract.map(|a| BytesJson::from(a.0.as_ref())) + self.fallback_swap_contract.map(|a| BytesJson::new(a.0.to_vec())) } fn mature_confirmations(&self) -> Option { diff --git a/mm2src/coins/rpc_command/lightning/send_payment.rs b/mm2src/coins/rpc_command/lightning/send_payment.rs index 8d99615fdd..1cc301188d 100644 --- a/mm2src/coins/rpc_command/lightning/send_payment.rs +++ b/mm2src/coins/rpc_command/lightning/send_payment.rs @@ -73,8 +73,8 @@ pub enum Payment { amount_in_msat: u64, // The number of blocks the payment will be locked for if not claimed by the destination, // It's can be assumed that 6 blocks = 1 hour. We can claim the payment amount back after this cltv expires. - // Minmum value allowed is MIN_FINAL_CLTV_EXPIRY which is currently 24 for rust-lightning. - expiry: u32, + // Minmum value allowed is MIN_FINAL_CLTV_EXPIRY_DELTA which is currently 24 for rust-lightning. + expiry: u16, }, } diff --git a/mm2src/coins/rpc_command/mod.rs b/mm2src/coins/rpc_command/mod.rs index e201d6f308..122b6663e1 100644 --- a/mm2src/coins/rpc_command/mod.rs +++ b/mm2src/coins/rpc_command/mod.rs @@ -12,5 +12,5 @@ pub mod init_withdraw; pub mod offline_keys; pub mod tendermint; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] pub mod lightning; diff --git a/mm2src/coins/rpc_command/offline_keys.rs b/mm2src/coins/rpc_command/offline_keys.rs index 3a306503b4..a05bd1f1a3 100644 --- a/mm2src/coins/rpc_command/offline_keys.rs +++ b/mm2src/coins/rpc_command/offline_keys.rs @@ -2,13 +2,13 @@ use crate::eth::{addr_from_pubkey_str, checksum_address}; use crate::tendermint; use crate::z_coin::{ZcoinConsensusParams, ZcoinProtocolInfo}; use crate::CoinProtocol; -use bitcoin_hashes::hex::ToHex; use bitcrypto::ChecksumType; use common::HttpStatusCode; use crypto::privkey::{key_pair_from_secret, key_pair_from_seed}; use crypto::{Bip32DerPathOps, CryptoCtx, HDPathToCoin, KeyPairPolicy, StandardHDPath}; use derive_more::Display; use futures_util::future::try_join_all; +use hex::ToHex; use http::StatusCode; use keys::{AddressBuilder, AddressFormat, AddressPrefix, KeyPair, NetworkAddressPrefixes, Private}; use mm2_core::mm_ctx::MmArc; @@ -235,7 +235,7 @@ fn get_pubkey_for_protocol(key_pair: &KeyPair, protocol: &CoinProtocol) -> Resul }, _ => { // For other protocols, use compressed public keys - Ok(key_pair.public().to_vec().to_hex()) + Ok(key_pair.public().to_vec().encode_hex()) }, } } @@ -452,7 +452,7 @@ async fn offline_hd_keys_export_internal( }, }; - let priv_key = format!("0x{}", key_pair.private().secret.to_hex()); + let priv_key = format!("0x{}", key_pair.private().secret.to_string()); (address, priv_key) }, @@ -461,7 +461,7 @@ async fn offline_hd_keys_export_internal( .map_err(|e| OfflineKeysError::Internal(e.to_string()))? .to_string(); - let priv_key = key_pair.private().secret.to_hex(); + let priv_key = key_pair.private().secret.to_string(); (address, priv_key) }, @@ -573,7 +573,7 @@ async fn offline_iguana_keys_export_internal( }, }; - let priv_key = format!("0x{}", key_pair.private().secret.to_hex()); + let priv_key = format!("0x{}", key_pair.private().secret.to_string()); (address, priv_key) }, @@ -582,7 +582,7 @@ async fn offline_iguana_keys_export_internal( .map_err(|e| OfflineKeysError::Internal(e.to_string()))? .to_string(); - let priv_key = key_pair.private().secret.to_hex(); + let priv_key = key_pair.private().secret.to_string(); (address, priv_key) }, diff --git a/mm2src/coins/utxo.rs b/mm2src/coins/utxo.rs index 4da7dbf092..7d2375a127 100644 --- a/mm2src/coins/utxo.rs +++ b/mm2src/coins/utxo.rs @@ -69,7 +69,7 @@ pub use keys::{ Address, AddressBuilder, AddressFormat as UtxoAddressFormat, AddressHashEnum, AddressPrefix, AddressScriptType, KeyPair, LegacyAddress, Private, Public, Secret, }; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] use lightning_invoice::Currency as LightningCurrency; use mm2_core::mm_ctx::{MmArc, MmWeak}; use mm2_err_handle::prelude::*; @@ -82,7 +82,7 @@ use num_traits::ToPrimitive; use primitives::hash::{H160, H256, H264}; use rpc::v1::types::{Bytes as BytesJson, Transaction as RpcTransaction, H256 as H256Json}; use script::{Builder, Script, SignatureVersion, TransactionInputSigner}; -use secp256k1::Signature as SecpSignature; +use secp256k1::ecdsa::Signature as SecpSignature; use serde_json::{self as json, Value as Json}; use serialization::{deserialize, serialize, serialize_with_flags, Error as SerError, SERIALIZE_TRANSACTION_WITNESS}; use spv_validation::conf::SPVConf; @@ -489,7 +489,7 @@ impl From for BitcoinNetwork { } } -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] impl From for LightningCurrency { fn from(network: BlockchainNetwork) -> Self { match network { diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index bd41621eae..fce0781324 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -62,7 +62,7 @@ use rpc::v1::types::{Bytes as BytesJson, ToTxHash, TransactionInputEnum, H256 as #[cfg(test)] use rpc_clients::NativeClientImpl; use script::{Builder, Opcode, Script, ScriptAddress, TransactionInputSigner, UnsignedTransactionInput}; -use secp256k1::{PublicKey, Signature as SecpSignature}; +use secp256k1::{ecdsa::Signature as SecpSignature, PublicKey}; use serde_json::{self as json}; use serialization::{deserialize, serialize, serialize_with_flags, CoinVariant, SERIALIZE_TRANSACTION_WITNESS}; use std::cmp::Ordering; diff --git a/mm2src/coins/utxo/wallet_connect.rs b/mm2src/coins/utxo/wallet_connect.rs index cf9ecfb4f7..52010d286d 100644 --- a/mm2src/coins/utxo/wallet_connect.rs +++ b/mm2src/coins/utxo/wallet_connect.rs @@ -6,7 +6,7 @@ use crate::utxo::{utxo_common, UtxoCoinFields}; use crate::UtxoTx; use base64::engine::general_purpose::STANDARD as BASE64_ENGINE; use base64::Engine; -use bitcoin::{consensus::Decodable, consensus::Encodable, psbt::Psbt, EcdsaSighashType}; +use bitcoin::{consensus::Decodable, consensus::Encodable, psbt::Psbt, sighash::EcdsaSighashType}; use bitcrypto::sign_message_hash; use chain::bytes::Bytes; use chain::hash::H256; @@ -182,10 +182,7 @@ async fn sign_psbt( broadcast: bool, ) -> MmResult { // Serialize the PSBT and encode it in base64 format. - let mut serialized_psbt = Vec::new(); - psbt.consensus_encode(&mut serialized_psbt).map_to_mm(|e| { - WalletConnectError::InternalError(format!("Failed to serialize our PSBT for WalletConnect: {e}")) - })?; + let serialized_psbt = psbt.serialize(); let serialized_psbt = BASE64_ENGINE.encode(serialized_psbt); wc.validate_update_active_chain_id(session_topic, chain_id).await?; @@ -200,7 +197,7 @@ async fn sign_psbt( .send_session_request_and_wait(session_topic, chain_id, WcRequestMethods::UtxoSignPsbt, params) .await?; - let signed_psbt = Psbt::consensus_decode(&mut &signed_psbt.psbt[..]).map_to_mm(|e| { + let signed_psbt = Psbt::deserialize(&signed_psbt.psbt[..]).map_to_mm(|e| { WalletConnectError::InternalError(format!("Failed to parse signed PSBT from WalletConnect: {e}")) })?; diff --git a/mm2src/coins_activation/Cargo.toml b/mm2src/coins_activation/Cargo.toml index 37f0e309d2..a19fef7049 100644 --- a/mm2src/coins_activation/Cargo.toml +++ b/mm2src/coins_activation/Cargo.toml @@ -8,6 +8,11 @@ doctest = false [features] enable-sia = [] +enable-lightning = [ + "dep:lightning", + "dep:lightning-background-processor", + "dep:lightning-invoice", +] enable-solana = [] default = [] for-tests = [] @@ -41,7 +46,6 @@ url.workspace = true mm2_metamask = { path = "../mm2_metamask" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -lightning.workspace = true -lightning-background-processor.workspace = true -lightning-invoice.workspace = true -secp256k1v24.workspace = true +lightning = { workspace = true, optional = true } +lightning-background-processor = { workspace = true, optional = true } +lightning-invoice = { workspace = true, optional = true } diff --git a/mm2src/coins_activation/src/context.rs b/mm2src/coins_activation/src/context.rs index dca33f40c8..f314fb4058 100644 --- a/mm2src/coins_activation/src/context.rs +++ b/mm2src/coins_activation/src/context.rs @@ -1,6 +1,6 @@ use crate::eth_with_token_activation::EthTaskManagerShared; use crate::init_erc20_token_activation::Erc20TokenTaskManagerShared; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] use crate::lightning_activation::LightningTaskManagerShared; #[cfg(feature = "enable-sia")] use crate::sia_coin_activation::SiaCoinTaskManagerShared; @@ -21,7 +21,7 @@ pub struct CoinsActivationContext { pub(crate) init_eth_task_manager: EthTaskManagerShared, pub(crate) init_erc20_token_task_manager: Erc20TokenTaskManagerShared, pub(crate) init_tendermint_coin_task_manager: TendermintCoinTaskManagerShared, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] pub(crate) init_lightning_task_manager: LightningTaskManagerShared, } @@ -39,7 +39,7 @@ impl CoinsActivationContext { init_eth_task_manager: RpcTaskManager::new_shared(ctx.event_stream_manager.clone()), init_erc20_token_task_manager: RpcTaskManager::new_shared(ctx.event_stream_manager.clone()), init_tendermint_coin_task_manager: RpcTaskManager::new_shared(ctx.event_stream_manager.clone()), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] init_lightning_task_manager: RpcTaskManager::new_shared(ctx.event_stream_manager.clone()), }) }) diff --git a/mm2src/coins_activation/src/lib.rs b/mm2src/coins_activation/src/lib.rs index 3adaf77327..505263bd03 100644 --- a/mm2src/coins_activation/src/lib.rs +++ b/mm2src/coins_activation/src/lib.rs @@ -5,7 +5,7 @@ mod eth_with_token_activation; mod init_erc20_token_activation; mod init_token; mod l2; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] mod lightning_activation; mod platform_coin_with_tokens; mod prelude; diff --git a/mm2src/coins_activation/src/lightning_activation.rs b/mm2src/coins_activation/src/lightning_activation.rs index cab083840b..d11c755039 100644 --- a/mm2src/coins_activation/src/lightning_activation.rs +++ b/mm2src/coins_activation/src/lightning_activation.rs @@ -28,12 +28,13 @@ use lightning::chain::keysinterface::{KeysInterface, Recipient}; use lightning::chain::Access; use lightning::routing::gossip; use lightning::routing::router::DefaultRouter; +use lightning::routing::scoring::ProbabilisticScoringFeeParameters; use lightning_background_processor::{BackgroundProcessor, GossipSync}; use lightning_invoice::payment; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use parking_lot::Mutex as PaMutex; -use secp256k1v24::Secp256k1; +use secp256k1::Secp256k1; use ser_error_derive::SerializeErrorType; use serde_derive::{Deserialize, Serialize}; use serde_json::{self as json, Value as Json}; @@ -134,6 +135,7 @@ pub struct LightningValidatedParams { // as this is a good default value. pub payment_retries: Option, // Node's backup path for channels and other data that requires backup. + // TODO: This parameter is deprecated and not used anymore. But check if we must have it back for funds security? pub backup_path: Option, } @@ -378,7 +380,7 @@ async fn start_lightning( let node_id = node_id.to_string(); // Initialize Persister - let persister = init_persister(ctx, &node_id, conf.ticker.clone(), params.backup_path).await?; + let persister = init_persister(ctx, &node_id, conf.ticker.clone()).await?; // Initialize the P2PGossipSync. This is used for providing routes to send payments over task_handle @@ -396,6 +398,23 @@ async fn start_lightning( logger.clone(), )); + // Initialize routing Scorer + task_handle + .update_in_progress_status(LightningInProgressStatus::ReadingScorerFromFile) + .map_mm_err()?; + // status_notifier + // .try_send(LightningInProgressStatus::ReadingScorerFromFile) + // .debug_log_with_msg("No one seems interested in LightningInProgressStatus"); + let scorer = Arc::new(persister.get_scorer(network_graph.clone(), logger.clone()).await?); + + let router = DefaultRouter::new( + network_graph.clone(), + logger.clone(), + keys_manager.get_secure_random_bytes(), + scorer.clone(), + ProbabilisticScoringFeeParameters::default(), + ); + // Initialize DB let db = init_db(ctx, &node_id, conf.ticker.clone()).await?; @@ -409,6 +428,7 @@ async fn start_lightning( persister.clone(), db.clone(), keys_manager.clone(), + router, conf.clone().into(), ) .await?; @@ -441,15 +461,6 @@ async fn start_lightning( trusted_nodes.clone(), )); - // Initialize routing Scorer - task_handle - .update_in_progress_status(LightningInProgressStatus::ReadingScorerFromFile) - .map_mm_err()?; - // status_notifier - // .try_send(LightningInProgressStatus::ReadingScorerFromFile) - // .debug_log_with_msg("No one seems interested in LightningInProgressStatus"); - let scorer = Arc::new(persister.get_scorer(network_graph.clone(), logger.clone()).await?); - // Create InvoicePayer // random_seed_bytes are additional random seed to improve privacy by adding a random CLTV expiry offset to each path's final hop. // This helps obscure the intended recipient from adversarial intermediate hops. The seed is also used to randomize candidate paths during route selection. @@ -463,7 +474,9 @@ async fn start_lightning( logger.clone(), router_random_seed_bytes, scorer.clone(), + ProbabilisticScoringFeeParameters::default(), ); + let invoice_payer = Arc::new(InvoicePayer::new( channel_manager.clone(), router, @@ -530,6 +543,7 @@ async fn start_lightning( logger.clone(), router_random_seed_bytes, scorer, + ProbabilisticScoringFeeParameters::default(), )), logger, }) diff --git a/mm2src/common/log.rs b/mm2src/common/log.rs index 7e5ad50584..e8ef67bd00 100644 --- a/mm2src/common/log.rs +++ b/mm2src/common/log.rs @@ -1052,7 +1052,7 @@ impl LogState { #[cfg(not(target_arch = "wasm32"))] impl LightningLogger for LogState { - fn log(&self, record: &LightningRecord) { + fn log(&self, record: LightningRecord) { let level = match record.level { LightningLevel::Gossip => Level::Trace, LightningLevel::Trace => Level::Debug, diff --git a/mm2src/hw_common/Cargo.toml b/mm2src/hw_common/Cargo.toml index f3390fb087..01a8997505 100644 --- a/mm2src/hw_common/Cargo.toml +++ b/mm2src/hw_common/Cargo.toml @@ -13,7 +13,7 @@ common = { path = "../common" } mm2_err_handle = { path = "../mm2_err_handle" } derive_more.workspace = true futures = { workspace = true, features = ["compat", "async-await"] } -secp256k1 = { workspace = true, features = ["rand"] } +secp256k1 = { version = "0.27", features = ["rand"] } serde.workspace = true serde_derive.workspace = true diff --git a/mm2src/mm2_bitcoin/chain/src/block_header.rs b/mm2src/mm2_bitcoin/chain/src/block_header.rs index b0eb0aad75..e0d44ad743 100644 --- a/mm2src/mm2_bitcoin/chain/src/block_header.rs +++ b/mm2src/mm2_bitcoin/chain/src/block_header.rs @@ -1,9 +1,11 @@ use compact::Compact; use crypto::dhash256; +use ext_bitcoin::block::Version; #[cfg(not(target_arch = "wasm32"))] -use ext_bitcoin::blockdata::block::BlockHeader as ExtBlockHeader; +use ext_bitcoin::blockdata::block::Header as ExtBlockHeader; #[cfg(not(target_arch = "wasm32"))] use ext_bitcoin::hash_types::{BlockHash as ExtBlockHash, TxMerkleNode as ExtTxMerkleNode}; +use ext_bitcoin::CompactTarget; use hash::H256; use hex::FromHex; use primitives::bytes::Bytes; @@ -381,19 +383,19 @@ impl From<&'static str> for BlockHeader { #[cfg(not(target_arch = "wasm32"))] impl From for ExtBlockHeader { fn from(header: BlockHeader) -> Self { - let prev_blockhash = ExtBlockHash::from_hash(header.previous_header_hash.to_sha256d()); - let merkle_root = ExtTxMerkleNode::from_hash(header.merkle_root_hash.to_sha256d()); + let prev_blockhash = ExtBlockHash::from_raw_hash(header.previous_header_hash.to_sha256d()); + let merkle_root = ExtTxMerkleNode::from_raw_hash(header.merkle_root_hash.to_sha256d()); // note: H256 nonce is not supported for bitcoin, we will just set nonce to 0 in this case since this will never happen let nonce = match header.nonce { BlockHeaderNonce::U32(n) => n, _ => 0, }; ExtBlockHeader { - version: header.version as i32, + version: Version::from_consensus(header.version as i32), prev_blockhash, merkle_root, time: header.time, - bits: header.bits.into(), + bits: CompactTarget::from_consensus(header.bits.into()), nonce, } } diff --git a/mm2src/mm2_bitcoin/chain/src/raw_block.rs b/mm2src/mm2_bitcoin/chain/src/raw_block.rs index bfa0f2dfbe..7e6fc8bb6f 100644 --- a/mm2src/mm2_bitcoin/chain/src/raw_block.rs +++ b/mm2src/mm2_bitcoin/chain/src/raw_block.rs @@ -34,14 +34,14 @@ impl RawBlockHeader { /// Extract the LE tx merkle root from the header pub fn extract_merkle_root(&self) -> H256 { let mut root = H256::default(); - root.as_mut().copy_from_slice(&self.0.as_ref()[36..68]); + root.copy_from_slice(&self.0.as_ref()[36..68]); root } /// Extract the LE parent digest from the header pub fn parent(&self) -> H256 { let mut root = H256::default(); - root.as_mut().copy_from_slice(&self.0.as_ref()[4..36]); + root.copy_from_slice(&self.0.as_ref()[4..36]); root } } diff --git a/mm2src/mm2_bitcoin/chain/src/transaction.rs b/mm2src/mm2_bitcoin/chain/src/transaction.rs index 00af2871f4..6cf681c6cd 100644 --- a/mm2src/mm2_bitcoin/chain/src/transaction.rs +++ b/mm2src/mm2_bitcoin/chain/src/transaction.rs @@ -6,7 +6,7 @@ use constants::{LOCKTIME_THRESHOLD, SEQUENCE_FINAL}; use crypto::{dhash256, sha256}; use ext_bitcoin::blockdata::transaction::{OutPoint as ExtOutpoint, Transaction as ExtTransaction, TxIn, TxOut}; use ext_bitcoin::hash_types::Txid; -use ext_bitcoin::{PackedLockTime, Sequence, Witness}; +use ext_bitcoin::{absolute::LockTime, Sequence, Witness}; use hash::{CipherText, EncCipherText, OutCipherText, ZkProof, ZkProofSapling, H256, H512, H64}; use hex::FromHex; use ser::{deserialize, serialize, serialize_with_flags, SERIALIZE_TRANSACTION_WITNESS}; @@ -44,7 +44,7 @@ impl OutPoint { impl From for ExtOutpoint { fn from(outpoint: OutPoint) -> Self { ExtOutpoint { - txid: Txid::from_hash(outpoint.hash.to_sha256d()), + txid: Txid::from_raw_hash(outpoint.hash.to_sha256d()), vout: outpoint.index, } } @@ -243,7 +243,7 @@ impl From for ExtTransaction { fn from(tx: Transaction) -> Self { ExtTransaction { version: tx.version, - lock_time: PackedLockTime(tx.lock_time), + lock_time: LockTime::from_consensus(tx.lock_time), input: tx.inputs.into_iter().map(|i| i.into()).collect(), output: tx.outputs.into_iter().map(|o| o.into()).collect(), } diff --git a/mm2src/mm2_bitcoin/keys/Cargo.toml b/mm2src/mm2_bitcoin/keys/Cargo.toml index 9acf887d18..0d38d2effc 100644 --- a/mm2src/mm2_bitcoin/keys/Cargo.toml +++ b/mm2src/mm2_bitcoin/keys/Cargo.toml @@ -15,6 +15,7 @@ derive_more.workspace = true lazy_static.workspace = true primitives = { path = "../primitives" } rand = { version = "0.6", features = ["wasm-bindgen"] } +rand8 = { version = "0.8", package = "rand" } rustc-hex.workspace = true secp256k1 = { workspace = true, features = ["rand", "recovery"] } serde = { workspace = true, features = ["derive"] } diff --git a/mm2src/mm2_bitcoin/keys/src/keypair.rs b/mm2src/mm2_bitcoin/keys/src/keypair.rs index 44aa433818..3cf254871a 100644 --- a/mm2src/mm2_bitcoin/keys/src/keypair.rs +++ b/mm2src/mm2_bitcoin/keys/src/keypair.rs @@ -88,7 +88,7 @@ impl KeyPair { } pub fn random_compressed() -> Self { - let secp_secret = SecretKey::new(&mut rand::thread_rng()); + let secp_secret = SecretKey::new(&mut rand8::thread_rng()); let pub_key = PublicKey::from_secret_key(&SECP_SIGN, &secp_secret); KeyPair { diff --git a/mm2src/mm2_bitcoin/keys/src/private.rs b/mm2src/mm2_bitcoin/keys/src/private.rs index 36cf5379fe..d025baef22 100644 --- a/mm2src/mm2_bitcoin/keys/src/private.rs +++ b/mm2src/mm2_bitcoin/keys/src/private.rs @@ -26,7 +26,7 @@ impl Private { pub fn sign(&self, message: &Message) -> Result { let secret = SecretKey::from_slice(&*self.secret)?; let message = SecpMessage::from_slice(&**message)?; - let signature = SECP_SIGN.sign(&message, &secret); + let signature = SECP_SIGN.sign_ecdsa(&message, &secret); let data = signature.serialize_der(); Ok(data.as_ref().to_vec().into()) } @@ -36,7 +36,7 @@ impl Private { pub fn sign_low_r(&self, message: &Message) -> Result { let secret = SecretKey::from_slice(&*self.secret)?; let message = SecpMessage::from_slice(&**message)?; - let signature = SECP_SIGN.sign_low_r(&message, &secret); + let signature = SECP_SIGN.sign_ecdsa_low_r(&message, &secret); let data = signature.serialize_der(); Ok(data.as_ref().to_vec().into()) } @@ -45,7 +45,7 @@ impl Private { pub fn sign_compact(&self, message: &Message) -> Result { let secret = SecretKey::from_slice(&*self.secret)?; let message = SecpMessage::from_slice(&**message)?; - let signature = SECP_SIGN.sign_recoverable(&message, &secret); + let signature = SECP_SIGN.sign_ecdsa_recoverable(&message, &secret); let (recover_id, bytes) = signature.serialize_compact(); let mut out = bytes.to_vec(); let header = 27 + recover_id.to_i32() as u8; diff --git a/mm2src/mm2_bitcoin/keys/src/public.rs b/mm2src/mm2_bitcoin/keys/src/public.rs index 0d2c80b715..d4213b4af5 100644 --- a/mm2src/mm2_bitcoin/keys/src/public.rs +++ b/mm2src/mm2_bitcoin/keys/src/public.rs @@ -3,8 +3,8 @@ use crypto::dhash160; use hash::{H160, H264, H520}; use hex::ToHex; use secp256k1::{ - recovery::{RecoverableSignature, RecoveryId}, - Error as SecpError, Message as SecpMessage, PublicKey, Signature as SecpSignature, + ecdsa::{RecoverableSignature, RecoveryId, Signature as SecpSignature}, + Error as SecpError, Message as SecpMessage, PublicKey, }; use std::{fmt, ops::Deref}; use {CompactSignature, Error, Message, Signature}; @@ -53,7 +53,7 @@ impl Public { let mut signature = SecpSignature::from_der_lax(signature)?; signature.normalize_s(); let message = SecpMessage::from_slice(&**message)?; - Ok(SECP_VERIFY.verify(&message, &signature, &public).is_ok()) + Ok(SECP_VERIFY.verify_ecdsa(&message, &signature, &public).is_ok()) } pub fn recover_compact(message: &Message, signature: &CompactSignature) -> Result { @@ -65,7 +65,7 @@ impl Public { let recovery_id = RecoveryId::from_i32(recovery_id as i32)?; let signature = RecoverableSignature::from_compact(&signature[1..65], recovery_id)?; let message = SecpMessage::from_slice(&**message)?; - let pubkey = SECP_VERIFY.recover(&message, &signature)?; + let pubkey = SECP_VERIFY.recover_ecdsa(&message, &signature)?; let public = if compressed { let serialized = pubkey.serialize(); Public::Compressed(serialized.into()) diff --git a/mm2src/mm2_bitcoin/primitives/src/hash.rs b/mm2src/mm2_bitcoin/primitives/src/hash.rs index 8c967b89ad..2118220bb9 100644 --- a/mm2src/mm2_bitcoin/primitives/src/hash.rs +++ b/mm2src/mm2_bitcoin/primitives/src/hash.rs @@ -204,6 +204,6 @@ impl H256 { #[inline] pub fn to_sha256d(self) -> sha256d::Hash { - sha256d::Hash::from_inner(self.take()) + sha256d::Hash::from_byte_array(self.take()) } } diff --git a/mm2src/mm2_bitcoin/spv_validation/src/helpers_validation.rs b/mm2src/mm2_bitcoin/spv_validation/src/helpers_validation.rs index 214deba8ed..53a072e57c 100644 --- a/mm2src/mm2_bitcoin/spv_validation/src/helpers_validation.rs +++ b/mm2src/mm2_bitcoin/spv_validation/src/helpers_validation.rs @@ -111,7 +111,7 @@ impl MerkleArray<'_> { return Err(SPVError::BadMerkleProof); } let mut digest = H256::default(); - digest.as_mut().copy_from_slice(&self.0[index * 32..to_index]); + digest.copy_from_slice(&self.0[index * 32..to_index]); Ok(digest) } } diff --git a/mm2src/mm2_eth/src/eip712_encode.rs b/mm2src/mm2_eth/src/eip712_encode.rs index a83873e94b..56f4bd1016 100644 --- a/mm2src/mm2_eth/src/eip712_encode.rs +++ b/mm2src/mm2_eth/src/eip712_encode.rs @@ -107,7 +107,7 @@ fn encode_custom( encoded_tokens.append(&mut encoded); } - Ok(keccak256(&encoded_tokens).as_ref().to_vec()) + Ok(keccak256(&encoded_tokens).to_vec()) } fn encode_bytes32(value: &Json, field_name: Option<&str>) -> Result> { diff --git a/mm2src/mm2_eth/src/recovery.rs b/mm2src/mm2_eth/src/recovery.rs index 1afa478e6f..29a3470c6b 100644 --- a/mm2src/mm2_eth/src/recovery.rs +++ b/mm2src/mm2_eth/src/recovery.rs @@ -1,5 +1,5 @@ use mm2_err_handle::prelude::*; -use secp256k1::recovery::{RecoverableSignature, RecoveryId}; +use secp256k1::ecdsa::{RecoverableSignature, RecoveryId}; use secp256k1::{Message as SecpMessage, Secp256k1}; use web3::types::{H256, H520}; @@ -19,7 +19,7 @@ pub fn recover_pubkey(message_hash: H256, mut signature: Signature) -> MmResult< let recovery_id = RecoveryId::from_i32(signature[64] as i32)?; let sig = RecoverableSignature::from_compact(&signature[0..64], recovery_id)?; let secp_message = SecpMessage::from_slice(message_hash.as_ref())?; - let pubkey = Secp256k1::new().recover(&secp_message, &sig)?; + let pubkey = Secp256k1::new().recover_ecdsa(&secp_message, &sig)?; let serialized = pubkey.serialize_uncompressed(); Ok(H520::from_slice(&serialized)) diff --git a/mm2src/mm2_main/Cargo.toml b/mm2src/mm2_main/Cargo.toml index fb15d8b373..366a971ed0 100644 --- a/mm2src/mm2_main/Cargo.toml +++ b/mm2src/mm2_main/Cargo.toml @@ -22,6 +22,7 @@ default = [] trezor-udp = ["crypto/trezor-udp"] # use for tests to connect to trezor emulator over udp run-device-tests = [] enable-sia = ["coins/enable-sia", "coins_activation/enable-sia"] +enable-lightning = ["coins/enable-lightning", "coins_activation/enable-lightning"] sepolia-maker-swap-v2-tests = [] sepolia-taker-swap-v2-tests = [] test-ext-api = ["trading_api/test-ext-api"] diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 90cb215881..d14cb302b7 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -6428,7 +6428,7 @@ fn orderbook_address( } }, CoinProtocol::ZHTLC { .. } => Ok(OrderbookAddress::Shielded), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] // Todo: Shielded address is used for lightning for now, the lightning node public key can be used for the orderbook entry pubkey // Todo: instead of the platform coin pubkey which is used right now. But lightning payments are supposed to be private, // Todo: so maybe we should hide the node address in the orderbook, only the sending node and the receiving node should know about a payment, diff --git a/mm2src/mm2_main/src/lp_swap.rs b/mm2src/mm2_main/src/lp_swap.rs index b59fe05225..92c5a25992 100644 --- a/mm2src/mm2_main/src/lp_swap.rs +++ b/mm2src/mm2_main/src/lp_swap.rs @@ -86,7 +86,7 @@ use mm2_number::{BigDecimal, MmNumber, MmNumberMultiRepr}; use mm2_state_machine::storable_state_machine::StateMachineStorage; use parking_lot::Mutex as PaMutex; use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json, H264}; -use secp256k1::{PublicKey, SecretKey, Signature}; +use secp256k1::{ecdsa::Signature, PublicKey, SecretKey}; use serde::Serialize; use serde_json::{self as json, Value as Json}; use std::collections::{HashMap, HashSet}; @@ -1621,7 +1621,7 @@ pub async fn active_swaps_rpc(ctx: MmArc, req: Json) -> Result> // Todo: Maybe add a secret_hash_algo method to the SwapOps trait instead /// Selects secret hash algorithm depending on types of coins being swapped -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] pub fn detect_secret_hash_algo(maker_coin: &MmCoinEnum, taker_coin: &MmCoinEnum) -> SecretHashAlgo { match (maker_coin, taker_coin) { (MmCoinEnum::Tendermint(_) | MmCoinEnum::TendermintToken(_) | MmCoinEnum::LightningCoin(_), _) => { @@ -1634,7 +1634,7 @@ pub fn detect_secret_hash_algo(maker_coin: &MmCoinEnum, taker_coin: &MmCoinEnum) } /// Selects secret hash algorithm depending on types of coins being swapped -#[cfg(target_arch = "wasm32")] +#[cfg(not(feature = "enable-lightning"))] pub fn detect_secret_hash_algo(maker_coin: &MmCoinEnum, taker_coin: &MmCoinEnum) -> SecretHashAlgo { match (maker_coin, taker_coin) { (MmCoinEnum::Tendermint(_) | MmCoinEnum::TendermintToken(_), _) => SecretHashAlgo::SHA256, @@ -1681,7 +1681,7 @@ pub fn broadcast_swap_v2_message( let secp_secret = SecretKey::from_slice(&p2p_private).expect("valid secret key"); let secp_message = secp256k1::Message::from_slice(sha256(&encoded_msg).as_slice()).expect("sha256 is 32 bytes hash"); - let signature = SECP_SIGN.sign(&secp_message, &secp_secret); + let signature = SECP_SIGN.sign_ecdsa(&secp_message, &secp_secret); let signed_message = SignedMessage { from: PublicKey::from_secret_key(&*SECP_SIGN, &secp_secret).serialize().into(), @@ -1732,7 +1732,7 @@ pub fn process_swap_v2_msg(ctx: MmArc, topic: &str, msg: &[u8]) -> P2PProcessRes .expect("sha256 is 32 bytes hash"); SECP_VERIFY - .verify(&secp_message, &signature, &pubkey) + .verify_ecdsa(&secp_message, &signature, &pubkey) .map_to_mm(|e| P2PProcessError::InvalidSignature(e.to_string()))?; let swap_message = SwapMessage::decode(signed_message.payload.as_slice()) diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs index 97c258c6e4..896231a9ca 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs @@ -90,6 +90,7 @@ use serde::de::DeserializeOwned; use serde_json::{self as json, Value as Json}; use std::net::SocketAddr; +#[cfg(feature = "enable-lightning")] cfg_native! { use coins::lightning::LightningCoin; } @@ -212,7 +213,7 @@ async fn dispatcher_v2(request: MmRpcRequest, ctx: MmArc) -> DispatcherResult handle_mmrpc(ctx, request, cancel_init_standalone_coin::).await, "enable_z_coin::status" => handle_mmrpc(ctx, request, init_standalone_coin_status::).await, "enable_z_coin::user_action" => handle_mmrpc(ctx, request, init_standalone_coin_user_action::).await, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] native_only_methods => match native_only_methods { "enable_lightning::cancel" => handle_mmrpc(ctx, request, cancel_init_l2::).await, "enable_lightning::init" => handle_mmrpc(ctx, request, init_l2::).await, @@ -397,6 +398,8 @@ async fn rpc_task_dispatcher( "connect_metamask::status" => handle_mmrpc(ctx, request, connect_metamask_status).await, _ => MmError::err(DispatcherError::NoSuchMethod), }, + #[cfg(not(feature = "enable-lightning"))] + _ => MmError::err(DispatcherError::NoSuchMethod), } } @@ -452,7 +455,7 @@ async fn gui_storage_dispatcher( /// # Note /// /// `lightning_method` is a method name with the `lightning::` prefix removed. -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] async fn lightning_dispatcher( request: MmRpcRequest, ctx: MmArc, diff --git a/mm2src/mm2_main/tests/mm2_tests/mod.rs b/mm2src/mm2_main/tests/mm2_tests/mod.rs index bbfbfcb9ff..321db7041a 100644 --- a/mm2src/mm2_main/tests/mm2_tests/mod.rs +++ b/mm2src/mm2_main/tests/mm2_tests/mod.rs @@ -1,6 +1,7 @@ mod bch_and_slp_tests; mod best_orders_tests; mod eth_tests; +#[cfg(all(not(target_arch = "wasm32"), feature = "enable-lightning"))] mod lightning_tests; mod lp_bot_tests; mod mm2_tests_inner; diff --git a/mm2src/mm2_p2p/src/lib.rs b/mm2src/mm2_p2p/src/lib.rs index 8438354b9e..926f9712fd 100644 --- a/mm2src/mm2_p2p/src/lib.rs +++ b/mm2src/mm2_p2p/src/lib.rs @@ -10,7 +10,7 @@ pub mod p2p_ctx; use derive_more::Display; use lazy_static::lazy_static; use secp256k1::{ - Message as SecpMessage, PublicKey as Secp256k1Pubkey, Secp256k1, SecretKey, SignOnly, Signature, VerifyOnly, + ecdsa::Signature, Message as SecpMessage, PublicKey as Secp256k1Pubkey, Secp256k1, SecretKey, SignOnly, VerifyOnly, }; use serde::{de, Deserialize, Serialize, Serializer}; use sha2::digest::Update; @@ -159,7 +159,7 @@ pub fn encode_and_sign(message: &T, secret: &[u8; 32]) -> Result>( let sig_hash = SecpMessage::from_slice(&sha256(helper.payload)).expect("Message::from_slice should never fail"); match &helper.pubkey { PublicKey::Secp256k1(serialized_pub) => { - if SECP_VERIFY.verify(&sig_hash, &signature, &serialized_pub.0).is_err() { + if SECP_VERIFY + .verify_ecdsa(&sig_hash, &signature, &serialized_pub.0) + .is_err() + { return Err(rmp_serde::decode::Error::Syntax("Invalid message signature".into())); } }, @@ -247,7 +250,7 @@ impl PublicKey { pub fn to_hex(&self) -> String { match self { - PublicKey::Secp256k1(pubkey) => hex::encode(pubkey.0.serialize().as_ref()), + PublicKey::Secp256k1(pubkey) => hex::encode(pubkey.0.serialize()), } }