diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ade5322..b42331c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -62,12 +62,6 @@ jobs: restore-keys: | ${{ runner.os }}-cargo-${{ hashFiles('rust-toolchain') }}- - - name: Electrs cache - uses: actions/cache@v2 - with: - path: ~/coins/bitcoin/electrs/target/debug/electrs - key: ${{ runner.os }}-electrs-v0.8.10 - - name: Nano-node cache uses: actions/cache@v2 with: @@ -83,11 +77,14 @@ jobs: ${{ runner.os }}-pip-electrum- ${{ runner.os }}-pip- - - name: Setup Bitcoin - run: ./ci/setup-coins/bitcoin.sh + - name: Setup Litecoin + run: ./ci/setup-coins/litecoin.sh + + - name: Setup Monero + run: ./ci/setup-coins/monero.sh - name: Setup Nano run: ./ci/setup-coins/nano.sh - - name: Run Bitcoin-Nano swap tests - run: RUST_LOG=asmr=debug cargo test --features test_bitcoin_node,test_nano_node -- btc_and_nano --nocapture + - name: Run Litecoin-Monero swap tests + run: RUST_LOG=asmr=debug cargo test --features test_litecoin_node,test_monero_node -- ltc_and_xmr --nocapture diff --git a/Cargo.lock b/Cargo.lock index 0adb38d..f3158b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,37 +17,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" -[[package]] -name = "aes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" -dependencies = [ - "aes-soft", - "aesni", - "cipher", -] - -[[package]] -name = "aes-soft" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" -dependencies = [ - "cipher", - "opaque-debug 0.3.0", -] - -[[package]] -name = "aesni" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" -dependencies = [ - "cipher", - "opaque-debug 0.3.0", -] - [[package]] name = "aho-corasick" version = "0.7.13" @@ -108,11 +77,10 @@ dependencies = [ "enum_dispatch", "env_logger", "ff", - "futures 0.3.5", + "futures", "group", "hex 0.4.2", "hex-literal", - "jubjub", "lazy_static", "log", "monero", @@ -127,9 +95,6 @@ dependencies = [ "sha2 0.9.1", "structopt", "tokio", - "zcash_client_backend", - "zcash_primitives", - "zcash_proofs", ] [[package]] @@ -173,19 +138,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293" dependencies = [ "addr2line", - "cfg-if 0.1.10", + "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", ] -[[package]] -name = "base-x" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" - [[package]] name = "base58-monero" version = "0.1.1" @@ -201,43 +160,11 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - [[package]] name = "bech32" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdcf67bb7ba7797a081cd19009948ab533af7c355d5caf1d08c777582d351e9c" - -[[package]] -name = "bech32" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c7f7096bc256f5e5cb960f60dfc4f4ef979ca65abe7fb9d5a4f77150d3783d4" - -[[package]] -name = "bellman" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7089887635778eabf0038a166f586eee5413fb85c8fa6c9a754914f0f644f49f" -dependencies = [ - "bitvec 0.18.5", - "blake2s_simd", - "byteorder", - "crossbeam", - "ff", - "futures 0.1.31", - "futures-cpupool", - "group", - "num_cpus", - "pairing", - "rand_core 0.5.1", - "subtle 2.4.0", -] +checksum = "cf9ff0bbfd639f15c74af777d81383cf53efb7c93613f6cab67c6c11e05bbf8b" [[package]] name = "bigint" @@ -261,20 +188,19 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a32c9d2fa897cfbb0db45d71e3d2838666194abc4828c0f994e4b5c3bf85ba4" +version = "0.28.0" +source = "git+https://github.com/rust-litecoin/rust-litecoin?branch=ltc#17ea786d46eb93b973bba00ef2eafbba0c8dc7af" dependencies = [ - "bech32 0.7.2", + "bech32", "bitcoin_hashes", "secp256k1", ] [[package]] name = "bitcoin_hashes" -version = "0.7.6" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b375d62f341cef9cd9e77793ec8f1db3fc9ce2e4d57e982c8fe697a2c16af3b6" +checksum = "006cc91e1a1d99819bc5b8214be3555c1f0611b169f527a1fdc54ed1f2b745b0" [[package]] name = "bitflags" @@ -289,7 +215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" dependencies = [ "either", - "radium 0.3.0", + "radium", ] [[package]] @@ -299,19 +225,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98fcd36dda4e17b7d7abc64cb549bf0201f4ab71e00700c798ca7e62ed3761fa" dependencies = [ "funty", - "radium 0.3.0", - "wyz", -] - -[[package]] -name = "bitvec" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" -dependencies = [ - "funty", - "radium 0.5.3", - "tap", + "radium", "wyz", ] @@ -351,24 +265,13 @@ dependencies = [ "constant_time_eq", ] -[[package]] -name = "blake2s_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] - [[package]] name = "block-buffer" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "block-padding 0.1.5", + "block-padding", "byte-tools", "byteorder", "generic-array 0.12.3", @@ -383,16 +286,6 @@ dependencies = [ "generic-array 0.14.4", ] -[[package]] -name = "block-modes" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0" -dependencies = [ - "block-padding 0.2.1", - "cipher", -] - [[package]] name = "block-padding" version = "0.1.5" @@ -402,35 +295,6 @@ dependencies = [ "byte-tools", ] -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - -[[package]] -name = "bls12_381" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4caf0101205582491f772d60a6fcb6bcec19963e68209cb631851eeadb01421f" -dependencies = [ - "bitvec 0.18.5", - "ff", - "group", - "pairing", - "rand_core 0.5.1", - "subtle 2.4.0", -] - -[[package]] -name = "bs58" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" -dependencies = [ - "sha2 0.9.1", -] - [[package]] name = "bumpalo" version = "3.4.0" @@ -473,21 +337,6 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cipher" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" -dependencies = [ - "generic-array 0.14.4", -] - [[package]] name = "clap" version = "2.33.3" @@ -521,12 +370,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "const_fn" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -555,67 +398,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" -[[package]] -name = "crossbeam" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" -dependencies = [ - "cfg-if 0.1.10", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" -dependencies = [ - "crossbeam-utils", - "maybe-uninit", -] - -[[package]] -name = "crossbeam-deque" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", - "maybe-uninit", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -dependencies = [ - "autocfg 1.0.1", - "cfg-if 0.1.10", - "crossbeam-utils", - "lazy_static", - "maybe-uninit", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" -dependencies = [ - "cfg-if 0.1.10", - "crossbeam-utils", - "maybe-uninit", -] - [[package]] name = "crossbeam-utils" version = "0.7.2" @@ -623,7 +405,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ "autocfg 1.0.1", - "cfg-if 0.1.10", + "cfg-if", "lazy_static", ] @@ -659,21 +441,6 @@ dependencies = [ "subtle 2.4.0", ] -[[package]] -name = "crypto_api" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f855e87e75a4799e18b8529178adcde6fd4f97c1449ff4821e747ff728bb102" - -[[package]] -name = "crypto_api_chachapoly" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930b6a026ce9d358a17f9c9046c55d90b14bb847f36b6ebb6b19365d4feffb8" -dependencies = [ - "crypto_api", -] - [[package]] name = "curve25519-dalek" version = "1.2.4" @@ -743,32 +510,6 @@ dependencies = [ "sha2 0.8.2", ] -[[package]] -name = "directories" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69600ff1703123957937708eb27f7a564e48885c537782722ed0ba3189ce1d7" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" -dependencies = [ - "libc", - "redox_users", - "winapi 0.3.9", -] - -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "dtoa" version = "0.4.6" @@ -799,7 +540,7 @@ version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a51b8cf747471cb9499b6d59e59b0444f4c90eba8968c4e44874e92b5b64ace2" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", ] [[package]] @@ -851,16 +592,6 @@ dependencies = [ "termcolor", ] -[[package]] -name = "equihash" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4127688f6177e3f57521881cb1cfd90d1228214f9dc43b8efe6f6c6948cd8280" -dependencies = [ - "blake2b_simd", - "byteorder", -] - [[package]] name = "ethbloom" version = "0.5.3" @@ -993,19 +724,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "fpe" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25080721bbcd2cd4d765b7d607ea350425fa087ce53cd3e31afcacdab850352" -dependencies = [ - "aes", - "block-modes", - "num-bigint 0.3.2", - "num-integer", - "num-traits 0.2.12", -] - [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -1034,12 +752,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" -[[package]] -name = "futures" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" - [[package]] name = "futures" version = "0.3.5" @@ -1071,16 +783,6 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" -[[package]] -name = "futures-cpupool" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -dependencies = [ - "futures 0.1.31", - "num_cpus", -] - [[package]] name = "futures-executor" version = "0.3.5" @@ -1170,22 +872,11 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] -[[package]] -name = "getrandom" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", -] - [[package]] name = "gimli" version = "0.22.0" @@ -1330,7 +1021,7 @@ dependencies = [ "itoa", "pin-project", "socket2", - "time 0.1.44", + "time", "tokio", "tower-service", "tracing", @@ -1410,20 +1101,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "jubjub" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "620638af3b80d23f4df0cae21e3cc9809ac8826767f345066f010bcea66a2c55" -dependencies = [ - "bitvec 0.18.5", - "bls12_381", - "ff", - "group", - "rand_core 0.5.1", - "subtle 2.4.0", -] - [[package]] name = "keccak-hash" version = "0.1.2" @@ -1460,19 +1137,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lexical-core" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 1.0.0", - "ryu", - "static_assertions 1.1.0", -] - [[package]] name = "libc" version = "0.2.95" @@ -1485,7 +1149,7 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", ] [[package]] @@ -1494,12 +1158,6 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - [[package]] name = "md-5" version = "0.8.0" @@ -1517,15 +1175,6 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" -[[package]] -name = "memoffset" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" -dependencies = [ - "autocfg 1.0.1", -] - [[package]] name = "mime" version = "0.3.16" @@ -1557,7 +1206,7 @@ version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "fuchsia-zircon", "fuchsia-zircon-sys", "iovec", @@ -1643,7 +1292,7 @@ dependencies = [ "digest 0.8.1", "ed25519-dalek", "hex 0.3.2", - "num-bigint 0.1.44", + "num-bigint", "num-traits 0.1.43", "rand 0.6.5", "serde", @@ -1674,24 +1323,11 @@ version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "libc", "winapi 0.3.9", ] -[[package]] -name = "nom" -version = "6.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" -dependencies = [ - "bitvec 0.19.5", - "funty", - "lexical-core", - "memchr", - "version_check", -] - [[package]] name = "num-bigint" version = "0.1.44" @@ -1704,17 +1340,6 @@ dependencies = [ "rustc-serialize", ] -[[package]] -name = "num-bigint" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d0a3d5e207573f948a9e5376662aa743a2ea13f7c50a554d7af443a73fbfeba" -dependencies = [ - "autocfg 1.0.1", - "num-integer", - "num-traits 0.2.12", -] - [[package]] name = "num-integer" version = "0.1.43" @@ -1784,7 +1409,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4" dependencies = [ "bitflags", - "cfg-if 0.1.10", + "cfg-if", "foreign-types", "lazy_static", "libc", @@ -1810,16 +1435,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "pairing" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f702cdbee9e0a6272452c20dec82465bc821116598b4eeb63e9a71a69dbf7fd" -dependencies = [ - "ff", - "group", -] - [[package]] name = "parity-scale-codec" version = "1.3.4" @@ -1938,31 +1553,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "protobuf" -version = "2.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45604fc7a88158e7d514d8e22e14ac746081e7a70d7690074dd0029ee37458d6" - -[[package]] -name = "protobuf-codegen" -version = "2.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb87f342b585958c1c086313dbc468dcac3edf5e90362111c26d7a58127ac095" -dependencies = [ - "protobuf", -] - -[[package]] -name = "protobuf-codegen-pure" -version = "2.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca6e0e2f898f7856a6328650abc9b2df71b7c1a5f39be0800d19051ad0214b2" -dependencies = [ - "protobuf", - "protobuf-codegen", -] - [[package]] name = "quick-error" version = "1.2.3" @@ -1984,12 +1574,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - [[package]] name = "rand" version = "0.4.6" @@ -2041,7 +1625,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.14", + "getrandom", "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", @@ -2089,7 +1673,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.14", + "getrandom", ] [[package]] @@ -2178,25 +1762,6 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" -[[package]] -name = "redox_syscall" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" -dependencies = [ - "getrandom 0.2.3", - "redox_syscall 0.2.8", -] - [[package]] name = "regex" version = "1.3.9" @@ -2230,7 +1795,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9eaa17ac5d7b838b7503d118fa16ad88f440498bf9ffe5424e621f93190d61e" dependencies = [ - "base64 0.12.3", + "base64", "bytes", "encoding_rs", "futures-core", @@ -2266,7 +1831,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" dependencies = [ - "base64 0.12.3", + "base64", "blake2b_simd", "constant_time_eq", "crossbeam-utils", @@ -2290,15 +1855,6 @@ version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - [[package]] name = "ryu" version = "1.0.5" @@ -2315,26 +1871,20 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - [[package]] name = "secp256k1" -version = "0.17.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2932dc07acd2066ff2e3921a4419606b220ba6cd03a9935123856cc534877056" +checksum = "295642060261c80709ac034f52fca8e5a9fa2c7d341ded5cdb164b7c33768b2a" dependencies = [ "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.1.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab2c26f0d3552a0f12e639ae8a64afc2e3db9c52fe32f5fc6c289d38519f220" +checksum = "152e20a0fd0519390fc43ab404663af8a0b794273d2a91d60ad4a39f13ffe110" dependencies = [ "cc", ] @@ -2386,21 +1936,6 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.115" @@ -2455,12 +1990,6 @@ dependencies = [ "url", ] -[[package]] -name = "sha1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" - [[package]] name = "sha2" version = "0.8.2" @@ -2480,7 +2009,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1" dependencies = [ "block-buffer 0.9.0", - "cfg-if 0.1.10", + "cfg-if", "cpuid-bool", "digest 0.9.0", "opaque-debug 0.3.0", @@ -2508,21 +2037,12 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "libc", - "redox_syscall 0.1.57", + "redox_syscall", "winapi 0.3.9", ] -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - [[package]] name = "static_assertions" version = "0.2.5" @@ -2535,55 +2055,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "strsim" version = "0.8.0" @@ -2649,22 +2120,16 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "libc", "rand 0.7.3", - "redox_syscall 0.1.57", + "redox_syscall", "remove_dir_all", "winapi 0.3.9", ] @@ -2707,44 +2172,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "time" -version = "0.2.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a8cbfbf47955132d0202d1662f49b2423ae35862aee471f3ba4b133358f372" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros", - "version_check", - "winapi 0.3.9", -] - -[[package]] -name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - -[[package]] -name = "time-macros-impl" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn", -] - [[package]] name = "tiny-keccak" version = "1.5.0" @@ -2831,7 +2258,7 @@ version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "log", "tracing-core", ] @@ -2983,7 +2410,7 @@ version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "serde", "serde_json", "wasm-bindgen-macro", @@ -3010,7 +2437,7 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95f8d235a77f880bcef268d379810ea6c0af2eacfa90b1ad5af731776e0c4699" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -3123,77 +2550,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" -[[package]] -name = "zcash_client_backend" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe10ae6417779fbd7903fdbef0c32d26bcdcf3b3a521d6372be8b55ce63410f5" -dependencies = [ - "base64 0.13.0", - "bech32 0.8.0", - "bls12_381", - "bs58", - "ff", - "group", - "hex 0.4.2", - "jubjub", - "nom", - "percent-encoding", - "protobuf", - "protobuf-codegen-pure", - "rand_core 0.5.1", - "subtle 2.4.0", - "time 0.2.26", - "zcash_primitives", -] - -[[package]] -name = "zcash_primitives" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926666fae42e08d65ddba7c3808873d1e6cd6e7dd86e84f51a909c79b5fe285c" -dependencies = [ - "aes", - "bitvec 0.18.5", - "blake2b_simd", - "blake2s_simd", - "bls12_381", - "byteorder", - "crypto_api_chachapoly", - "equihash", - "ff", - "fpe", - "funty", - "group", - "hex 0.4.2", - "jubjub", - "lazy_static", - "log", - "rand 0.7.3", - "rand_core 0.5.1", - "sha2 0.9.1", - "subtle 2.4.0", -] - -[[package]] -name = "zcash_proofs" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc3cd16a4efbebf925756f339d01e876816d37d1f458bd8243edb3bd8dbad74b" -dependencies = [ - "bellman", - "blake2b_simd", - "bls12_381", - "byteorder", - "directories", - "ff", - "group", - "jubjub", - "lazy_static", - "rand_core 0.5.1", - "zcash_primitives", -] - [[package]] name = "zeroize" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 9aee83d..4726d61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,17 +30,13 @@ derive_more = "0.99.9" bincode = "1.3.1" serde_json = "1.0.56" reqwest = { version = "0.10.6", features = ["json"] } -bitcoin = "0.23.0" +bitcoin = { git = "https://github.com/rust-litecoin/rust-litecoin", branch = "ltc" } nanocurrency-types = "0.3.19" num_cpus = "1.13.0" monero = "0.8.1" digest_auth = "0.2.3" ff = "0.8" group = "0.8" -jubjub = "0.5.1" -zcash_primitives = "0.5.0" -zcash_proofs = "0.5.0" -zcash_client_backend = "0.5.0" [features] no_confs = [] @@ -48,7 +44,6 @@ test_bitcoin_node = [] test_meros_node = [] test_nano_node = [] test_monero_node = [] -test_zcash_node = [] # Always optimize dependencies [profile.dev.package."*"] diff --git a/ci/setup-coins/bitcoin.sh b/ci/setup-coins/bitcoin.sh deleted file mode 100755 index 328e29b..0000000 --- a/ci/setup-coins/bitcoin.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -set -euxo pipefail - -config_dir="$(pwd)/config" -mkdir -p "$config_dir" - -mkdir -p ~/coins/bitcoin -cd ~/coins/bitcoin - -btc_version="0.20.1" -curl https://bitcoincore.org/bin/bitcoin-core-"$btc_version"/bitcoin-"$btc_version"-x86_64-linux-gnu.tar.gz | tar -xzf - -mv bitcoin-"$btc_version" bitcoin-node - -if [ ! -e electrs/target/debug/electrs ]; then - git clone --depth 1 --branch v0.8.10 'https://github.com/romanz/electrs' electrs - pushd electrs - cargo build - popd -fi - -git clone --depth 1 --branch 4.0.2 'https://github.com/spesmilo/electrum' -pushd electrum -python3 -m pip install --user -e . -popd - -./bitcoin-node/bin/bitcoind -regtest -daemon -server=1 -txindex=1 -prune=0 -rpcport=18443 -rpcuser=ci -rpcpassword=password -echo 'auth = "ci:password"' > electrs.toml -echo 'txid_limit = 0' >> electrs.toml -./electrs/target/debug/electrs --network regtest & -./electrum/run_electrum --regtest --offline setconfig rpcport 3000 -./electrum/run_electrum --regtest --offline setconfig rpcuser ci -./electrum/run_electrum --regtest --offline setconfig rpcpassword password -./electrum/run_electrum --regtest daemon -d -s 127.0.0.1:60401:t -./electrum/run_electrum --regtest create -./electrum/run_electrum --regtest load_wallet - -address="$(./electrum/run_electrum --regtest getunusedaddress)" -./bitcoin-node/bin/bitcoin-cli -regtest -rpcuser=ci -rpcpassword=password generatetoaddress 110 "$address" - -destination="$(./electrum/run_electrum --regtest getunusedaddress)" -refund="$(./electrum/run_electrum --regtest getunusedaddress)" - -cat > "$config_dir/bitcoin.json" << EOF -{ - "url": "http://ci:password@127.0.0.1:3000", - "btc_url": "http://ci:password@127.0.0.1:18443", - "destination": "$destination", - "refund": "$refund" -} -EOF diff --git a/ci/setup-coins/litecoin.sh b/ci/setup-coins/litecoin.sh new file mode 100755 index 0000000..1ff2add --- /dev/null +++ b/ci/setup-coins/litecoin.sh @@ -0,0 +1,49 @@ +#!/bin/bash +set -euxo pipefail + +config_dir="$(pwd)/config" +mkdir -p "$config_dir" + +mkdir -p ~/coins/litecoin +cd ~/coins/litecoin + +ltc_version="0.20.1" +curl https://download.litecoin.org/litecoin-0.21.3/linux/litecoin-"$ltc_version"/linux/litecoin-"$ltc_version"-x86_64-linux-gnu.tar.gz | tar -xzf - +mv litecoin-"$ltc_version" litecoin-node + +git clone --depth 1 --branch v0.8.10 'https://github.com/spesmilo/electrumx' + +git clone --depth 1 --branch 4.0.2 'https://github.com/pooler/electrum-ltc' +pushd electrum-ltc +python3 -m pip install --user -e . +popd + +./litecoin-node/bin/litecoind -regtest -daemon -server=1 -txindex=1 -prune=0 -rpcport=18443 -rpcuser=ci -rpcpassword=password + +echo 'COIN=Litecoin' > ~/electrumx.conf +echo 'SERVICES=tcp://127.0.0.1:5000' > ~/electrumx.conf +echo 'DAEMON_URL=ci:password@127.0.0.1:18443' > ~/electrumx.conf +echo 'PEER_DISCOVERY=self' > ~/electrumx.conf + +./electrs/target/debug/electrs --network regtest & +./electrum-ltc/run_electrum --regtest --offline setconfig rpcport 3000 +./electrum-ltc/run_electrum --regtest --offline setconfig rpcuser ci +./electrum-ltc/run_electrum --regtest --offline setconfig rpcpassword password +./electrum-ltc/run_electrum --regtest daemon -d -s 127.0.0.1:5000:t +./electrum-ltc/run_electrum --regtest create +./electrum-ltc/run_electrum --regtest load_wallet + +address="$(./electrum-ltc/run_electrum --regtest getunusedaddress)" +./litecoin-node/bin/litecoin-cli -regtest -rpcuser=ci -rpcpassword=password generatetoaddress 110 "$address" + +destination="$(./electrum-ltc/run_electrum --regtest getunusedaddress)" +refund="$(./electrum-ltc/run_electrum --regtest getunusedaddress)" + +cat > "$config_dir/litecoin.json" << EOF +{ + "url": "http://ci:password@127.0.0.1:3000", + "btc_url": "http://ci:password@127.0.0.1:18443", + "destination": "$destination", + "refund": "$refund" +} +EOF diff --git a/config_example/bitcoin.json b/config_example/litecoin.json similarity index 100% rename from config_example/bitcoin.json rename to config_example/litecoin.json diff --git a/config_example/meros.json b/config_example/meros.json deleted file mode 100644 index a47abeb..0000000 --- a/config_example/meros.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "address": "127.0.0.1:5133", - "destination": "mr1qz3286zv8gfwac2hej686lkvxdqlsw7jt006m4qcktkjlhwxxp9ggs83vms", - "refund": "mr1qz3286zv8gfwac2hej686lkvxdqlsw7jt006m4qcktkjlhwxxp9ggs83vms" -} diff --git a/config_example/zcashshielded.json b/config_example/zcashshielded.json deleted file mode 100644 index 276d567..0000000 --- a/config_example/zcashshielded.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "url": "http://user:pass@127.0.0.1:18232", - "destination": "zregtestsapling1c4nzed2xz5zmcy3d73uswm46ycquk3e632muffyzuxzkt2ye85gwrgce45drll4s6tmmqlr7yze", - "refund": "zregtestsapling1tcltlrgrq2kyhaljkh5j5addjyks2mgcdc3n2775gs56xx4v3q236qeeqmsjf4ntxcdcwkha3nq" -} diff --git a/src/cli.rs b/src/cli.rs index fbb3bd6..95cf5e2 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -49,20 +49,16 @@ fn host_or_client_from_str(s: &str) -> Result { #[derive(FromStr, Debug, Clone)] #[enumeration(rename_all = "lowercase")] pub enum ScriptedCoin { - #[enumeration(alias = "btc")] - Bitcoin, + #[enumeration(alias = "ltc")] + Litecoin, } #[derive(FromStr, Debug, Clone)] #[enumeration(rename_all = "lowercase")] pub enum UnscriptedCoin { - #[enumeration(alias = "mr")] - Meros, Nano, #[enumeration(alias = "xmr")] Monero, - #[enumeration(alias = "zec")] - ZCashShielded, } enum AnyCoin { diff --git a/src/coins/btc/engine.rs b/src/coins/btc/engine.rs index 1e8601a..8c62384 100644 --- a/src/coins/btc/engine.rs +++ b/src/coins/btc/engine.rs @@ -10,7 +10,8 @@ use bitcoin::{ hashes::Hash, hash_types::{Txid, WPubkeyHash}, blockdata::{script::Script, transaction::{OutPoint, TxIn, TxOut, Transaction}}, network::constants::Network, - util::{address::Address, bip143::SighashComponents} + util::{address::Address, bip143::SighashComponents}, + Witness }; use crate::crypt_engines::{CryptEngine, secp256k1_engine::Secp256k1Engine}; @@ -96,7 +97,7 @@ impl BtcEngine { let key = Secp256k1Engine::new_private_key(); let public_key = &bitcoin::util::key::PublicKey { compressed: true, - key: secp256k1::PublicKey::from_secret_key( + inner: secp256k1::PublicKey::from_secret_key( &SECP, &secp256k1::SecretKey::from_slice( &Secp256k1Engine::private_key_to_bytes(&key) @@ -104,11 +105,11 @@ impl BtcEngine { ), }; let mut hash_engine = WPubkeyHash::engine(); - public_key.write_into(&mut hash_engine); + public_key.write_into(&mut hash_engine).unwrap(); ( key, - Address::p2wpkh(public_key, NETWORK).to_string(), + Address::p2wpkh(public_key, NETWORK).unwrap().to_string(), // This is the same payload used in the Address // The field unfortunately isn't public though WPubkeyHash::from_engine(hash_engine).as_ref().try_into().expect("Couldn't convert a twenty-byte hash to a twenty-byte array") @@ -217,7 +218,7 @@ impl BtcEngine { }, script_sig: Script::new(), sequence: T0 as u32, - witness: Vec::new() + witness: Witness::new(), } ], output: vec![ @@ -225,7 +226,9 @@ impl BtcEngine { script_pubkey: Address::p2wsh(&refund_script, NETWORK).script_pubkey(), value: value } - ] + ], + is_hog_ex: false, + mw_tx: None, }; let fee = ((refund.get_weight() as u64) / 4) * fee_per_byte; refund.output[0].value = refund.output[0].value.checked_sub(fee) @@ -274,7 +277,7 @@ impl BtcEngine { }, script_sig: Script::new(), sequence: 0xFFFFFFFF, - witness: Vec::new() + witness: Witness::new(), } ], output: vec![ @@ -282,7 +285,9 @@ impl BtcEngine { script_pubkey: output, value: value } - ] + ], + is_hog_ex: false, + mw_tx: None, }; let fee = ((spend.get_weight() as u64) / 4) * fee_per_byte; spend.output[0].value = spend.output[0].value.checked_sub(fee) diff --git a/src/coins/btc/host.rs b/src/coins/btc/host.rs index 9b1ec5b..1c8794a 100644 --- a/src/coins/btc/host.rs +++ b/src/coins/btc/host.rs @@ -17,7 +17,7 @@ use bitcoin::{ hashes::hex::FromHex, hash_types::Txid, blockdata::{script::Script, transaction::{OutPoint, TxIn, TxOut, Transaction}}, util::{address::Address, bip143::SighashComponents}, - consensus::serialize + consensus::serialize, Witness, }; use crate::{ @@ -197,7 +197,7 @@ impl ScriptedHost for BtcHost { previous_output: OutPoint{txid: Txid::from_hex(&input.tx_hash)?, vout: input.tx_pos}, script_sig: Script::new(), sequence: 0xFFFFFFFF, - witness: Vec::new() + witness: Witness::new() }) }).collect::>()?; @@ -212,7 +212,9 @@ impl ScriptedHost for BtcHost { output: vec![TxOut { value, script_pubkey: Script::from(lock_script_hash) - }] + }], + is_hog_ex: false, + mw_tx: None, }; let fee = ((lock.get_weight() / 4) as u64) * self.rpc.get_fee_per_byte().await?; lock.output[0].value = lock.output[0].value.checked_sub(fee) @@ -240,7 +242,7 @@ impl ScriptedHost for BtcHost { let mut signature = signature.to_vec(); signature.push(1); - lock.input[i].witness = vec![signature, key_bytes.clone()]; + lock.input[i].witness = Witness::from_vec(vec![signature, key_bytes.clone()]); } let fee_per_byte_and_sig = self.prepare_refund_and_spend(lock.txid(), lock.output[0].value).await?; @@ -280,15 +282,13 @@ impl ScriptedHost for BtcHost { // Complete the refund transaction let mut refund = self.refund.take().expect("Verifying and completing the refund before creating it"); - refund.input[0].witness = vec![ + refund.input[0].witness = Witness::from_vec(vec![ Vec::new(), - refund_signature, - self.refund_signature.clone().expect("Verifying the refund yet we never signed it"), + [refund_signature.as_slice(), &[1]].concat(), + [self.refund_signature.clone().expect("Verifying the refund yet we never signed it").as_slice(), &[1]].concat(), Vec::new(), self.engine.lock_script_bytes.clone().expect("Finishing despite not knowing the lock script") - ]; - refund.input[0].witness[1].push(1); - refund.input[0].witness[2].push(1); + ]); self.refund = Some(refund); self.encrypted_spend_signature = Some(encrypted_spend_signature); @@ -354,7 +354,7 @@ impl ScriptedHost for BtcHost { previous_output: OutPoint{txid: Txid::from_hex(&input.tx_hash)?, vout: input.tx_pos}, script_sig: Script::new(), sequence: 0xFFFFFFFF, - witness: Vec::new() + witness: Witness::new() }) }).collect::>()?; @@ -367,7 +367,9 @@ impl ScriptedHost for BtcHost { script_pubkey: self.refund_pubkey_script, value } - ] + ], + is_hog_ex: false, + mw_tx: None, }; let fee = ((return_tx.get_weight() / 4) as u64) * self.rpc.get_fee_per_byte().await?; return_tx.output[0].value = return_tx.output[0].value.checked_sub(fee) @@ -395,7 +397,7 @@ impl ScriptedHost for BtcHost { let mut signature = signature.to_vec(); signature.push(1); - return_tx.input[i].witness = vec![signature, key_bytes.clone()]; + return_tx.input[i].witness = Witness::from_vec(vec![signature, key_bytes.clone()]); } self.rpc.publish(&serialize(&return_tx)).await?; @@ -448,27 +450,25 @@ impl ScriptedHost for BtcHost { // Complete and publish the spend transaction. let mut spend = self.spend.expect("Spend transaction doesn't exist despite having published the lock"); - spend.input[0].witness = vec![ + spend.input[0].witness = Witness::from_vec(vec![ Vec::new(), - secp256k1::Signature::from_compact( + [secp256k1::Signature::from_compact( &Secp256k1Engine::signature_to_bytes( &Secp256k1Engine::decrypt_signature( &self.encrypted_spend_signature.expect("Spend signature doesn't exist despite having published the lock"), &self.engine.bs.expect("Never generated keys despite having published the lock") )? ) - )?.serialize_der().to_vec(), - SECP.sign( + )?.serialize_der().to_vec().as_slice(), &[1]].concat(), + [SECP.sign( &secp256k1::Message::from_slice( &self.spend_message.expect("Spend message doesn't exist despite having published the lock") )?, &secp256k1::SecretKey::from_slice(&Secp256k1Engine::private_key_to_bytes(&self.engine.br))? - ).serialize_der().to_vec(), + ).serialize_der().to_vec().as_slice(), &[1]].concat(), vec![1], self.engine.refund_script_bytes.expect("Finishing despite not knowing the lock script") - ]; - spend.input[0].witness[1].push(1); - spend.input[0].witness[2].push(1); + ]); self.rpc.publish(&serialize(&spend)).await?; Ok(()) @@ -490,7 +490,7 @@ impl ScriptedHost for BtcHost { }, script_sig: Script::new(), sequence: 0xFFFFFFFF, - witness: Vec::new() + witness: Witness::new() } ], output: vec![ @@ -498,7 +498,9 @@ impl ScriptedHost for BtcHost { script_pubkey: self.client_destination_script.clone().expect("Preparing buy for client before knowing their destination"), value: lock.output[0].value } - ] + ], + is_hog_ex: false, + mw_tx: None, }; let fee = ((buy.get_weight() as u64) / 4) * self.rpc.get_fee_per_byte().await?; buy.output[0].value = buy.output[0].value.checked_sub(fee) @@ -541,7 +543,7 @@ impl ScriptedHost for BtcHost { } } - let their_signature = &buy?.input[0].witness[2]; + let their_signature = &buy?.input[0].witness.clone().to_vec()[2]; let signature = secp256k1::Signature::from_der( &their_signature[.. their_signature.len() - 1] ).expect("Signature included in the buy transaction wasn't valid despite getting on chain").serialize_compact(); diff --git a/src/coins/btc/verifier.rs b/src/coins/btc/verifier.rs index eff8f80..b88474b 100644 --- a/src/coins/btc/verifier.rs +++ b/src/coins/btc/verifier.rs @@ -15,7 +15,8 @@ use bitcoin::{ hash_types::Txid, blockdata::{script::Script, transaction::{OutPoint, TxIn, TxOut, Transaction}}, util::{address::Address, bip143::SighashComponents}, - consensus::{serialize, deserialize} + consensus::{serialize, deserialize}, + Witness, }; use crate::{ @@ -92,7 +93,7 @@ impl BtcVerifier { refund_spend = history.remove(0).tx; } let decrypted = secp256k1::Signature::from_der( - &refund_spend.input[0].witness[1][0 .. refund_spend.input[0].witness[1].len() - 1] + &refund_spend.input[0].witness.clone().to_vec()[1][0 .. refund_spend.input[0].witness.clone().to_vec()[1].len() - 1] ).expect("Published BTC transaction has an invalid signature").serialize_compact().to_vec(); Some( @@ -201,15 +202,13 @@ impl ScriptedVerifier for BtcVerifier { let encrypted_spend_sig = Secp256k1Engine::encrypted_signature_to_bytes(&encrypted_spend_sig_typed); self.encrypted_spend_sig = Some(encrypted_spend_sig_typed); - refund.input[0].witness = vec![ + refund.input[0].witness = Witness::from_vec(vec![ Vec::new(), - refund_sig.clone(), - lock_and_refund.host_refund_signature, + [refund_sig.clone().as_slice(), &[1]].concat(), + [lock_and_refund.host_refund_signature.as_slice(), &[1]].concat(), Vec::new(), self.engine.lock_script_bytes.clone().expect("Completing refund despite not knowing the lock script") - ]; - refund.input[0].witness[1].push(1); - refund.input[0].witness[2].push(1); + ]); self.refund = Some(refund); Ok(bincode::serialize(&ClientRefundAndSpendSignatures { @@ -244,7 +243,7 @@ impl ScriptedVerifier for BtcVerifier { }, script_sig: Script::new(), sequence: 0xFFFFFFFF, - witness: Vec::new() + witness: Witness::new() } ], output: vec![ @@ -252,7 +251,9 @@ impl ScriptedVerifier for BtcVerifier { script_pubkey: self.destination_script.clone(), value: buy_info.value } - ] + ], + is_hog_ex: false, + mw_tx: None, }; let components = SighashComponents::new(&buy); @@ -285,16 +286,14 @@ impl ScriptedVerifier for BtcVerifier { ).expect("Secp256k1Engine generated an invalid secp256k1 key") ).serialize_der(); - buy.input[0].witness = vec![ + buy.input[0].witness = Witness::from_vec(vec![ Vec::new(), - signature.to_vec(), - decrypted_signature.serialize_der().to_vec(), + [signature.to_vec().as_slice(), &[1]].concat(), + [decrypted_signature.serialize_der().to_vec().as_slice(), &[1]].concat(), Vec::new(), vec![1], self.engine.lock_script_bytes.clone().expect("Finishing despite not knowing the lock script") - ]; - buy.input[0].witness[1].push(1); - buy.input[0].witness[2].push(1); + ]); self.buy = Some(buy); Ok(()) @@ -401,11 +400,7 @@ impl ScriptedVerifier for BtcVerifier { }, script_sig: Script::new(), sequence: T1 as u32, - witness: vec![ - vec![0; 65], - Vec::new(), - refund_script.to_bytes() - ] + witness: Witness::new(), } ], output: vec![ @@ -413,14 +408,17 @@ impl ScriptedVerifier for BtcVerifier { script_pubkey: self.destination_script.clone(), value: refund.output[0].value } - ] + ], + is_hog_ex: false, + mw_tx: None, }; let fee = ((claim.get_weight() as u64) / 4) * self.rpc.get_fee_per_byte().await?; claim.output[0].value = claim.output[0].value.checked_sub(fee) .ok_or_else(|| anyhow::anyhow!("Not enough Bitcoin to pay for {} sats of fees", fee))?; let components = SighashComponents::new(&claim); - claim.input[0].witness[0] = SECP.sign( + claim.input[0].witness = Witness::from_vec(vec![ + [SECP.sign( &secp256k1::Message::from_slice( &components.sighash_all( &claim.input[0], @@ -431,8 +429,10 @@ impl ScriptedVerifier for BtcVerifier { &secp256k1::SecretKey::from_slice( &Secp256k1Engine::private_key_to_bytes(&self.engine.b) ).expect("Secp256k1Engine generated an invalid secp256k1 key") - ).serialize_der().to_vec(); - claim.input[0].witness[0].push(1); + ).serialize_der().to_vec().as_slice(), &[1]].concat(), + Vec::new(), + refund_script.to_bytes() + ]); let _ = self.rpc.publish(&serialize(&claim)).await; let claim_id = claim.txid(); @@ -476,7 +476,11 @@ impl ScriptedVerifier for BtcVerifier { } let mut buy = self.buy.clone().expect("Finishing before verifying buy"); - buy.input[0].witness[3] = swap_secret.to_vec(); + { + let mut witness = buy.input[0].witness.to_vec(); + witness[3] = swap_secret.to_vec(); + buy.input[0].witness = Witness::from_vec(witness); + } self.rpc.publish(&serialize(&buy)).await?; Ok(()) diff --git a/src/coins/meros/client.rs b/src/coins/meros/client.rs deleted file mode 100644 index db3697c..0000000 --- a/src/coins/meros/client.rs +++ /dev/null @@ -1,148 +0,0 @@ -use std::{ - marker::PhantomData, - path::Path, - fs::File -}; - -use async_trait::async_trait; - -use crate::{ - crypt_engines::{KeyBundle, CryptEngine, ed25519_engine::Ed25519Sha}, - coins::{ - UnscriptedClient, ScriptedVerifier, - meros::{ - transaction::Transaction, - engine::MerosEngine, - rpc::MerosRpc - } - } -}; - -pub struct MerosClient { - rpc: MerosRpc, - refund: Vec, - key_share: Option<::PrivateKey>, - shared_key: Option<::PublicKey>, - address: Option, - deposited: bool -} - -impl MerosClient { - pub fn new(config_path: &Path) -> anyhow::Result { - let config = serde_json::from_reader(File::open(config_path)?)?; - Ok(MerosClient{ - rpc: MerosRpc::new(&config)?, - refund: MerosEngine::decode_address(&config.refund)?, - key_share: None, - shared_key: None, - address: None, - deposited: false - }) - } -} - -#[async_trait] -impl UnscriptedClient for MerosClient { - fn generate_keys(&mut self, verifier: &mut Verifier) -> Vec { - let (dl_eq, key) = verifier.generate_keys_for_engine::(PhantomData); - self.key_share = Some(key); - KeyBundle { - dl_eq, - B: verifier.B(), - BR: verifier.BR(), - scripted_destination: verifier.destination_script() - }.serialize() - } - - fn verify_keys(&mut self, keys: &[u8], verifier: &mut Verifier) -> anyhow::Result<()> { - let host_key = verifier.verify_keys_for_engine::(&keys, PhantomData)?; - let our_pubkey = Ed25519Sha::to_public_key(self.key_share.as_ref().expect("Verifying DLEQ proof before generating keys")); - self.shared_key = Some(our_pubkey + host_key); - Ok(()) - } - - fn get_address(&mut self) -> String { - let address = MerosEngine::get_address( - &Ed25519Sha::public_key_to_bytes( - &self.shared_key.expect("Trying to get the Meros deposit addresss despite not having verified the host's DLEQ proof") - ) - ); - self.address = Some(address.clone()); - address - } - - async fn wait_for_deposit(&mut self) -> anyhow::Result<()> { - let address = self.address.clone().expect("Waiting for deposit despite not knowing the deposit address"); - let mut utxos = self.rpc.get_utxos(address.clone()).await; - while utxos.len() == 0 { - tokio::time::delay_for(std::time::Duration::from_secs(5)).await; - utxos = self.rpc.get_utxos(address.clone()).await; - } - self.deposited = true; - Ok(()) - } - - async fn refund(mut self, verifier: Verifier) -> anyhow::Result<()> { - // No deposit could have occurred/did occur - if self.address.is_none() || (!self.deposited) { - Ok(()) - } else { - let utxos = self.rpc.get_utxos(self.address.expect("Couldn't get address despite the option being some")).await; - - /* - No UTXOs meant the other party already claimed these funds - We can't then claim the BTC as this would've required us to try to claim the BTC - And since we tried it, and failed, there's not much to do - We can publish the refund transaction, yet the other party can instantly claim it for themselves - */ - if utxos.len() == 0 { - anyhow::bail!("Deposited yet no UTXOs exist and we're trying to call refund"); - } else { - /* - Once we publish the refund, two paths open up - A) We can claim the BTC after the second timeout expires - B) We can claim the MR after the host claims the BTC - We assume path A, and then revert to path B if path A fails - */ - if let Some(recovered_key) = verifier.claim_refund_or_recover_key().await? { - let mut value_sum = 0; - for input in utxos.clone() { - value_sum += self.rpc.get_transaction_output_value(input.clone()).await?; - } - - let send = MerosEngine::create_send( - Ed25519Sha::little_endian_bytes_to_private_key(recovered_key)?, - self.key_share.expect("Finishing before generating keys"), - utxos, - self.refund, - value_sum, - self.rpc.get_send_difficulty().await - ); - self.rpc.publish_send(send.serialize()).await?; - } - Ok(()) - } - } - } - - #[cfg(test)] - fn override_refund_with_random_address(&mut self) { - self.refund = Ed25519Sha::public_key_to_bytes(&Ed25519Sha::to_public_key(&Ed25519Sha::new_private_key())); - } - #[cfg(test)] - async fn send_from_node(&mut self) -> anyhow::Result<()> { - self.rpc.send(self.address.clone().expect("Calling send from node before generating the address")).await - } - #[cfg(test)] - async fn advance_consensus(&self) -> anyhow::Result<()> { - Ok(()) - } - #[cfg(test)] - fn get_refund_address(&self) -> String { - MerosEngine::get_address(&self.refund) - } - #[cfg(test)] - async fn get_if_funded(mut self, address: &str) -> bool { - self.rpc.get_utxos(address.to_string()).await.len() != 0 - } -} diff --git a/src/coins/meros/engine.rs b/src/coins/meros/engine.rs deleted file mode 100644 index 05439d5..0000000 --- a/src/coins/meros/engine.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::net::SocketAddr; - -use log::debug; -use serde::Deserialize; -use bitcoin::bech32::{self, ToBase32, FromBase32}; - -use crate::{ - crypt_engines::{CryptEngine, ed25519_engine::Ed25519Sha}, - coins::meros::transaction::{Input, Output, Send} -}; - -#[derive(Deserialize)] -pub struct MerosConfig { - pub address: SocketAddr, - pub destination: String, - pub refund: String -} - -pub struct MerosEngine { - pub k: Option<::PrivateKey> -} - -impl MerosEngine { - pub fn new() -> MerosEngine { - MerosEngine { - k: None - } - } - - pub fn decode_address(address: &str) -> anyhow::Result> { - let mut result = Vec::::from_base32(&bech32::decode(address)?.1)?; - if (result[0] != 0) || (result.len() != 33) { - anyhow::bail!("Unsupported Meros address type."); - } - result.remove(0); - Ok(result) - } - - pub fn get_address(key: &[u8]) -> String { - let mut data = vec![0]; - data.extend(key); - bech32::encode("mr", data.to_base32()).unwrap() - } - - pub fn create_send( - key_a: ::PrivateKey, - key_b: ::PrivateKey, - utxos: Vec, - destination: Vec, - value: u64, - diff: u32 - ) -> Send { - let mut send = Send::new( - utxos, - vec![ - Output { - key: destination, - value: value - } - ] - ); - let total_key = key_a + key_b; - debug!( - "Creating Meros send for shared address {}", - Self::get_address((&total_key * &curve25519_dalek::constants::ED25519_BASEPOINT_TABLE).compress().as_bytes()) - ); - send.sign(total_key); - send.mine(diff); - send - } -} diff --git a/src/coins/meros/mod.rs b/src/coins/meros/mod.rs deleted file mode 100644 index a65d1bb..0000000 --- a/src/coins/meros/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod transaction; -mod engine; -mod rpc; - -pub mod client; -pub mod verifier; diff --git a/src/coins/meros/rpc.rs b/src/coins/meros/rpc.rs deleted file mode 100644 index b529842..0000000 --- a/src/coins/meros/rpc.rs +++ /dev/null @@ -1,137 +0,0 @@ - -use std::{ - marker::Send, - str::FromStr, - fmt::Debug, - io::prelude::*, - net::{TcpStream, SocketAddr} -}; - -use log::debug; - -use serde::{Serialize, Deserialize, de::DeserializeOwned}; -use serde_json::json; - -use tokio::task; - -use crate::{ - coins::{ - meros::{ - transaction::Input, - engine::MerosConfig - } - } -}; - - -pub struct MerosRpc(SocketAddr); - -impl MerosRpc { - pub fn new(config: &MerosConfig) -> anyhow::Result { - Ok(MerosRpc(config.address)) - } - - async fn rpc_call< - Params: Clone + Send + Sync + Serialize + Debug + 'static, - Response: Send + DeserializeOwned + Debug + 'static - >(&self, method: String, params: Params) -> anyhow::Result { - #[derive(Serialize)] - struct FullParams<'a, T> { - jsonrpc: &'a str, - id: (), - method: &'a str, - params: T, - } - - #[derive(Deserialize, Debug)] - #[serde(untagged)] - enum FullResponse { - Err { - error: serde_json::Value - }, - Ok { - result: T - }, - } - - let ip = self.0.clone(); - let method_clone = method.clone(); - let params_clone = params.clone(); - let parsed_res = task::spawn_blocking(move || -> anyhow::Result> { - let mut stream = TcpStream::connect(ip)?; - stream.write_all( - serde_json::to_string( - &FullParams { - jsonrpc: "2.0", - id: (), - method: &method_clone, - params: params_clone - } - )?.as_ref() - )?; - Ok( - serde_json::from_value( - serde_json::Value::deserialize( - &mut serde_json::de::Deserializer::from_reader(&mut stream) - )? - ).map_err(|_| anyhow::anyhow!("Meros request failed due to incompatible RPC version"))? - ) - }).await??; - debug!("RPC call to {} with {:?} finished.", method, params); - - match parsed_res { - FullResponse::Err { error } => anyhow::bail!("Meros RPC returned an error: {}", error), - FullResponse::Ok { result } => Ok(result), - } - } - - pub async fn get_utxos(&mut self, address: String) -> Vec { - self.rpc_call("transactions_getUTXOs".to_string(), [address]).await.expect("Couldn't call transactions.getUTXOs") - } - - pub async fn get_transaction_output_value(&mut self, input: Input) -> anyhow::Result { - #[derive(Deserialize, Debug)] - struct OutputResponse { - amount: String - }; - #[derive(Deserialize, Debug)] - struct TxResponse { - outputs: Vec - }; - - let tx: TxResponse = self.rpc_call("transactions_getTransaction".to_string(), [input.hash]).await?; - if tx.outputs.len() <= (input.nonce as usize) { - anyhow::bail!("Transaction doesn't have an output with that index"); - } - Ok(u64::from_str(&tx.outputs[(input.nonce as usize)].amount).expect("Meros didn't return a String for the output value")) - } - - pub async fn get_confirmed(&mut self, hash: String) -> anyhow::Result { - #[derive(Deserialize, Debug)] - struct StatusResponse { - verified: bool - }; - - let status: StatusResponse = self.rpc_call("consensus_getStatus".to_string(), [hash]).await?; - Ok(status.verified) - } - - pub async fn publish_send(&mut self, tx: Vec) -> anyhow::Result<()> { - let result = self.rpc_call("transactions_publishSend".to_string(), [hex::encode(tx)]).await?; - if result { - Ok(()) - } else { - anyhow::bail!("Published an invalid send"); - } - } - - pub async fn get_send_difficulty(&mut self) -> u32 { - self.rpc_call("consensus_getSendDifficulty".to_string(), json!([])).await.expect("Couldn't get the send difficulty") - } - - #[cfg(test)] - pub async fn send(&mut self, address: String) -> anyhow::Result<()> { - let _: String = self.rpc_call("personal_send".to_string(), json!([address, "1"])).await?; - Ok(()) - } -} diff --git a/src/coins/meros/transaction.rs b/src/coins/meros/transaction.rs deleted file mode 100644 index 55d6b8b..0000000 --- a/src/coins/meros/transaction.rs +++ /dev/null @@ -1,130 +0,0 @@ -use std::{ - convert::TryInto, - fmt::Debug -}; - -use bigint::uint::U256; -use blake2::digest::{Update, VariableOutput}; -use argon2::{self, Config, ThreadMode, Variant, Version, hash_raw}; - -use serde::Deserialize; - -use crate::crypt_engines::{CryptEngine, ed25519_engine::Ed25519Sha}; - -const CONFIG: Config = Config { - variant: Variant::Argon2d, - version: Version::Version13, - mem_cost: 8, - time_cost: 1, - lanes: 1, - thread_mode: ThreadMode::Parallel, - secret: &[], - ad: &[], - hash_length: 32 -}; - -#[derive(Clone, Deserialize, Debug)] -pub struct Input { - pub hash: String, - pub nonce: u8 -} - -pub struct Output { - pub key: Vec, - pub value: u64 -} - -pub trait Transaction { - fn inputs(&self) -> &Vec; - fn outputs(&self) -> &Vec; - fn hash(&self) -> Vec; - fn serialize(&self) -> Vec; -} - -pub struct Send { - inputs: Vec, - outputs: Vec, - hash: Vec, - signature: Option>, - proof: u32 -} - -// This function consistently mines proofs into the space of hundreds -// It shold finish < 10. That said, it does still finish in a few seconds -fn mine(data: &[u8], diff: u32) -> u32 { - let mut proof: i64 = -1; - let mut hash = U256::max_value(); - let diff = U256::from(diff); - while hash.overflowing_mul(diff).1 { - proof += 1; - hash = U256::from_little_endian(&hash_raw(data, &proof.to_le_bytes(), &CONFIG).unwrap()); - } - std::cmp::max(0, proof).try_into().expect("Couldn't convert a spam proof to a u32") -} - -impl Transaction for Send { - fn inputs(&self) -> &Vec { - &self.inputs - } - - fn outputs(&self) -> &Vec { - &self.outputs - } - - fn hash(&self) -> Vec { - self.hash.clone() - } - - fn serialize(&self) -> Vec { - let mut result = vec![self.inputs.len() as u8]; - for input in &self.inputs { - result.extend(&hex::decode(&input.hash).expect("Input's hex hash wasn't hex")); - result.push(input.nonce); - } - result.push(self.outputs.len() as u8); - for output in &self.outputs { - result.extend(&output.key); - result.extend(&output.value.to_le_bytes()); - } - result.extend(self.signature.as_ref().expect("Tried to serialize a Transaction which was never signed")); - result.extend(&self.proof.to_le_bytes()); - result - } -} - -impl Send { - pub fn new(inputs: Vec, outputs: Vec) -> Send { - let mut hash = vec![2, inputs.len() as u8]; - for input in &inputs { - hash.extend(&hex::decode(&input.hash).expect("Input's hex hash wasn't hex")); - hash.push(input.nonce); - } - hash.push(outputs.len() as u8); - for output in &outputs { - hash.extend(&output.key); - hash.extend(&output.value.to_le_bytes()); - } - - let mut hasher = blake2::VarBlake2b::new(32).unwrap(); - hasher.update(&hash); - hasher.finalize_variable(|hash_ref| hash = hash_ref.to_vec()); - - Send { - inputs, - outputs, - hash, - signature: None, - proof: 0 - } - } - - pub fn sign(&mut self, key: ::PrivateKey) { - let mut to_sign = b"MEROS".to_vec(); - to_sign.extend(&self.hash); - self.signature = Some(Ed25519Sha::signature_to_bytes(&Ed25519Sha::sign(&key, &to_sign).unwrap())); - } - - pub fn mine(&mut self, diff: u32) { - self.proof = mine(&self.hash, diff * (((70 + (self.inputs.len() * 33) + (self.outputs.len() * 40) / 143)) as u32)); - } -} diff --git a/src/coins/meros/verifier.rs b/src/coins/meros/verifier.rs deleted file mode 100644 index e3e0d31..0000000 --- a/src/coins/meros/verifier.rs +++ /dev/null @@ -1,132 +0,0 @@ -use std::{ - marker::PhantomData, - io::Write, - path::Path, - fs::File -}; - -use async_trait::async_trait; - -use crate::{ - crypt_engines::{CryptEngine, ed25519_engine::Ed25519Sha}, - dl_eq::DlEqProof, - coins::{ - UnscriptedVerifier, ScriptedHost, - meros::{ - transaction::{Input, Transaction}, - engine::MerosEngine, - rpc::MerosRpc - } - } -}; - -pub struct MerosVerifier { - engine: MerosEngine, - rpc: MerosRpc, - destination_key: Vec, - - shared_key: Option<::PublicKey>, - utxos: Option>, - value_sum: Option -} - -impl MerosVerifier { - pub fn new(config_path: &Path) -> anyhow::Result { - let config = serde_json::from_reader(File::open(config_path)?)?; - - Ok(MerosVerifier { - engine: MerosEngine::new(), - rpc: MerosRpc::new(&config)?, - destination_key: MerosEngine::decode_address(&config.destination)?, - - shared_key: None, - utxos: None, - value_sum: None - }) - } -} - -#[async_trait] -impl UnscriptedVerifier for MerosVerifier { - fn generate_keys_for_engine(&mut self, _: PhantomData<&OtherCrypt>) -> (Vec, OtherCrypt::PrivateKey) { - let (proof, key1, key2) = DlEqProof::::new(); - self.engine.k = Some(key1); - self.shared_key = Some(Ed25519Sha::to_public_key(&key1)); - (proof.serialize(), key2) - } - - fn verify_dleq_for_engine(&mut self, dleq: &[u8], _: PhantomData<&OtherCrypt>) -> anyhow::Result { - let dleq = DlEqProof::::deserialize(dleq)?; - let (key1, key2) = dleq.verify()?; - self.shared_key = Some(self.shared_key.expect("Verifying DLEQ proof before generating keys") + key2); - Ok(key1) - } - - async fn verify_and_wait_for_send(&mut self) -> anyhow::Result<()> { - let address = MerosEngine::get_address( - &Ed25519Sha::public_key_to_bytes( - self.shared_key.as_ref().expect("Waiting for send before verifying the other's DLEQ proof") - ) - ); - - /* - Considering Meros transactions are directly to public keys, there's not actually anything to verify - There's no timelocks or alternate spending paths - The node will only track the transaction if it's viable, including having a valid signature - We do need to make the transaction was verified, yet Meros's getUTXOs route already has that premise - That said, Meros also isn't at mainnet and subject to changes, so it's best to be extremely secure here - */ - - let mut result = Vec::new(); - let mut value_sum = 0; - let mut done = false; - while !done { - result = Vec::new(); - value_sum = 0; - done = true; - - for input in self.rpc.get_utxos(address.clone()).await { - // Verify the UTXO is confirmed - // We don't need to check if it's spent since we have half of the key and it therefore can't be spent without us - if !self.rpc.get_confirmed(input.hash.clone()).await? { - done = false; - break; - } - value_sum += self.rpc.get_transaction_output_value(input.clone()).await?; - result.push(input); - } - - // Don't immediately run the next loop iteration - done = done && (result.len() != 0); - if !done { - tokio::time::delay_for(std::time::Duration::from_secs(5)).await; - } - } - self.value_sum = Some(value_sum); - self.utxos = Some(result); - - if !cfg!(test) { - print!("You will receive {} MR. Continue (yes/no)? ", value_sum); - std::io::stdout().flush().expect("Failed to flush stdout"); - let mut line = String::new(); - std::io::stdin().read_line(&mut line).expect("Couldn't read from stdin"); - if !line.to_lowercase().starts_with("y") { - anyhow::bail!("User didn't confirm MR amount"); - } - } - Ok(()) - } - - async fn finish(&mut self, host: &Host) -> anyhow::Result<()> { - let send = MerosEngine::create_send( - Ed25519Sha::little_endian_bytes_to_private_key(host.recover_final_key().await?)?, - self.engine.k.expect("Finishing before generating keys"), - self.utxos.clone().expect("Finishing before knowing of the UTXOs"), - self.destination_key.clone(), - self.value_sum.expect("Finishing before knowing of the amount"), - self.rpc.get_send_difficulty().await - ); - self.rpc.publish_send(send.serialize()).await?; - Ok(()) - } -} diff --git a/src/coins/mod.rs b/src/coins/mod.rs index 0d2cccf..122517e 100644 --- a/src/coins/mod.rs +++ b/src/coins/mod.rs @@ -1,8 +1,6 @@ pub mod btc; -pub mod meros; pub mod nano; pub mod xmr; -pub mod zec; use std::marker::PhantomData; @@ -72,10 +70,8 @@ pub trait UnscriptedClient { #[enum_dispatch] pub enum AnyUnscriptedClient { - Meros(meros::client::MerosClient), Nano(nano::client::NanoClient), Monero(xmr::client::XmrClient), - ZCashShielded(zec::client::ZecShieldedClient) } #[async_trait] @@ -125,8 +121,6 @@ pub trait UnscriptedVerifier: Send + Sync { #[enum_dispatch] pub enum AnyUnscriptedVerifier { - Meros(meros::verifier::MerosVerifier), Nano(nano::verifier::NanoVerifier), Monero(xmr::verifier::XmrVerifier), - ZCashShielded(zec::verifier::ZecShieldedVerifier) } diff --git a/src/coins/zec/client.rs b/src/coins/zec/client.rs index e8929cc..e69de29 100644 --- a/src/coins/zec/client.rs +++ b/src/coins/zec/client.rs @@ -1,131 +0,0 @@ -#[allow(unused_imports)] -use std::{ - marker::PhantomData, - convert::TryInto, - path::Path, - fs::File -}; - -use async_trait::async_trait; - -#[allow(unused_imports)] -use rand::{rngs::OsRng, RngCore}; - -#[allow(unused_imports)] -use zcash_primitives::{ - primitives::Note, - zip32::{ExtendedSpendingKey, ExtendedFullViewingKey} -}; - -#[cfg(test)] -use zcash_client_backend::encoding::encode_payment_address; - -use crate::{ - crypt_engines::{KeyBundle, CryptEngine, jubjub_engine::JubjubEngine}, - coins::{UnscriptedClient, ScriptedVerifier, zec::engine::*} -}; - -pub struct ZecShieldedClient { - engine: ZecEngine, - deposited: bool, - #[cfg(test)] - refund_seed: [u8; 32] -} - -impl ZecShieldedClient { - pub async fn new(config_path: &Path) -> anyhow::Result { - Ok(ZecShieldedClient { - engine: ZecEngine::new(serde_json::from_reader(File::open(config_path)?)?).await?, - deposited: false, - #[cfg(test)] - refund_seed: [0; 32] - }) - } -} - -#[async_trait] -impl UnscriptedClient for ZecShieldedClient { - fn generate_keys(&mut self, verifier: &mut Verifier) -> Vec { - let (dl_eq, key) = verifier.generate_keys_for_engine::(PhantomData); - self.engine.ask = Some(key); - KeyBundle { - dl_eq: bincode::serialize( - &ZecKeys { - dl_eq, - nsk: JubjubEngine::private_key_to_bytes(&self.engine.nsk) - } - ).unwrap(), - B: verifier.B(), - BR: verifier.BR(), - scripted_destination: verifier.destination_script() - }.serialize() - } - - fn verify_keys(&mut self, keys: &[u8], verifier: &mut Verifier) -> anyhow::Result<()> { - let mut bundle: KeyBundle = bincode::deserialize(keys)?; - let zec_keys: ZecKeys = bincode::deserialize(&bundle.dl_eq)?; - bundle.dl_eq = zec_keys.dl_eq; - self.engine.set_ak_nsk( - &verifier.verify_keys_for_engine::(&bincode::serialize(&bundle).unwrap(), PhantomData)?, - &JubjubEngine::bytes_to_private_key(zec_keys.nsk)? - ); - Ok(()) - } - - fn get_address(&mut self) -> String { - self.engine.get_deposit_address() - } - - async fn wait_for_deposit(&mut self) -> anyhow::Result<()> { - let vk = self.engine.vk.clone().expect("Getting the deposit before sharing keys"); - self.deposited = self.engine.get_deposit(&vk, true).await?.is_some(); - Ok(()) - } - - async fn refund(self, verifier: Verifier) -> anyhow::Result<()> { - if !self.deposited { - Ok(()) - } else { - if let Some(recovered_key) = verifier.claim_refund_or_recover_key().await? { - self.engine.claim( - JubjubEngine::little_endian_bytes_to_private_key(recovered_key)?, - &self.engine.config.refund - ).await?; - } - Ok(()) - } - } - - #[cfg(test)] - fn override_refund_with_random_address(&mut self) { - let mut seed = [0; 32]; - OsRng.fill_bytes(&mut seed); - self.refund_seed = seed; - self.engine.config.refund = encode_payment_address( - SAPLING_HRP, - &ExtendedSpendingKey::master(&seed).default_address().expect("Couldn't get default address").1 - ); - } - - #[cfg(test)] - async fn send_from_node(&mut self) -> anyhow::Result<()> { - self.engine.send_from_wallet().await?; - Ok(()) - } - - #[cfg(test)] - async fn advance_consensus(&self) -> anyhow::Result<()> { - self.engine.mine_block().await - } - - #[cfg(test)] - fn get_refund_address(&self) -> String { - hex::encode(&self.refund_seed) - } - - #[cfg(test)] - async fn get_if_funded(mut self, address: &str) -> bool { - let efvk: ExtendedFullViewingKey = (&ExtendedSpendingKey::master(hex::decode(address).unwrap()[..32].try_into().unwrap())).into(); - self.engine.get_deposit(&efvk.fvk.vk, false).await.expect("Couldn't get if a Transaction to a ViewKey exists").is_some() - } -} diff --git a/src/coins/zec/data/sapling-output.params b/src/coins/zec/data/sapling-output.params deleted file mode 100644 index 01760fa..0000000 Binary files a/src/coins/zec/data/sapling-output.params and /dev/null differ diff --git a/src/coins/zec/data/sapling-spend.params b/src/coins/zec/data/sapling-spend.params deleted file mode 100644 index b91cd77..0000000 Binary files a/src/coins/zec/data/sapling-spend.params and /dev/null differ diff --git a/src/coins/zec/engine.rs b/src/coins/zec/engine.rs deleted file mode 100644 index 712e388..0000000 --- a/src/coins/zec/engine.rs +++ /dev/null @@ -1,502 +0,0 @@ -use std::{ - convert::TryInto, - fmt::Debug -}; -use log::debug; - -use rand::{RngCore, rngs::OsRng}; - -use digest::Digest; - -use serde::{Serialize, Deserialize, de::DeserializeOwned}; -use serde_json::json; - -use reqwest; - -use zcash_primitives::{ - primitives::{ViewingKey, Diversifier, Note}, - sapling::Node, - merkle_tree::{CommitmentTree, IncrementalWitness}, - keys::{OutgoingViewingKey, ExpandedSpendingKey}, - zip32::ExtendedSpendingKey, - transaction::{components::Amount, Transaction, builder::Builder}, - note_encryption::try_sapling_note_decryption, - constants::regtest::{self, HRP_SAPLING_PAYMENT_ADDRESS}, - consensus::{BlockHeight, BranchId, NetworkUpgrade, Parameters} -}; -use zcash_proofs::prover::LocalTxProver; -use zcash_client_backend::encoding::{encode_payment_address, decode_payment_address}; - -use crate::crypt_engines::{CryptEngine, jubjub_engine::JubjubEngine}; - -#[cfg(not(feature = "no_confs"))] -pub const CONFIRMATIONS: isize = 4; -#[cfg(feature = "no_confs")] -pub const CONFIRMATIONS: isize = 1; - -#[cfg(test)] -pub const SAPLING_HRP: &str = HRP_SAPLING_PAYMENT_ADDRESS; - -// Needed as zcash_primitives provides mainnet (zcash_primitives::consensus::MainNetwork) -// and testnet (zcash_primitives::consensus::TestNetwork) params, yet not regtest -// Expected to be used with: -// ./bin/zcashd --regtest -nuparams=5ba81b19:1 -nuparams=76b809bb:1 -nuparams=2bb40e60:1 -nuparams=f5b9230b:1 -nuparams=e9ff75a6:1 -#[derive(Clone)] -struct RegtestParams(()); -impl Parameters for RegtestParams { - fn activation_height(&self, _nu: NetworkUpgrade) -> Option { - Some(BlockHeight::from_u32(1)) - } - fn coin_type(&self) -> u32 { - 1 - } - fn hrp_sapling_extended_spending_key(&self) -> &str { - regtest::HRP_SAPLING_EXTENDED_SPENDING_KEY - } - fn hrp_sapling_extended_full_viewing_key(&self) -> &str { - regtest::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY - } - fn hrp_sapling_payment_address(&self) -> &str { - HRP_SAPLING_PAYMENT_ADDRESS - } - fn b58_pubkey_address_prefix(&self) -> [u8; 2] { - regtest::B58_PUBKEY_ADDRESS_PREFIX - } - fn b58_script_address_prefix(&self) -> [u8; 2] { - regtest::B58_SCRIPT_ADDRESS_PREFIX - } - fn is_nu_active(&self, _nu: NetworkUpgrade, _height: BlockHeight) -> bool { - true - } -} - -#[derive(Serialize)] -struct FullParams<'a, T> { - jsonrpc: &'a str, - id: (), - method: &'a str, - params: T -} - -#[derive(Deserialize, Debug)] -struct EmptyResponse {} - -#[derive(Clone, Deserialize)] -pub struct ZecConfig { - pub url: String, - pub destination: String, - pub refund: String -} - -#[derive(Serialize, Deserialize)] -pub struct ZecKeys { - pub dl_eq: Vec, - pub nsk: [u8; 32] -} - -pub struct ZecEngine { - pub config: ZecConfig, - prover: LocalTxProver, - - pub ask: Option<::PrivateKey>, - pub nsk: ::PrivateKey, - pub vk: Option, - diversifier: Option, - - height_at_start: isize, - tree: CommitmentTree, - - // Other coins would generally return these, yet it's advantageous to have them inlined to reduce code reuse - // Especially due to the considerations of them as privacy tech - // It does change the mutability of get_deposit, yet that already had to be mutable due to the above tree - // Unless that was also passed around, in which case we just have a secondary struct for effectively no reason - witness: Option>, - note: Option, - branch: Option, - - #[cfg(test)] - node_address: String -} - -impl ZecEngine { - pub async fn new(config: ZecConfig) -> anyhow::Result { - let mut result = ZecEngine { - config, - // Inline the params directly into the binary - prover: LocalTxProver::from_bytes( - std::include_bytes!("data/sapling-spend.params"), - std::include_bytes!("data/sapling-output.params") - ), - - ask: None, - nsk: JubjubEngine::new_private_key(), - vk: None, - diversifier: None, - - height_at_start: -1, - tree: CommitmentTree::::empty(), - - witness: None, - note: None, - branch: None, - - #[cfg(test)] - node_address: "".to_string() - }; - result.height_at_start = result.get_height().await; - - #[allow(non_snake_case)] - #[derive(Deserialize, Debug)] - struct CommitmentResponse { - finalState: String - } - #[derive(Deserialize, Debug)] - struct SaplingResponse { - commitments: CommitmentResponse - } - #[derive(Deserialize, Debug)] - struct TreeResponse { - sapling: SaplingResponse - } - let tree: TreeResponse = result.rpc_call("z_gettreestate", &json![[result.height_at_start.to_string()]]).await?; - result.tree = CommitmentTree::::read(&*hex::decode(tree.sapling.commitments.finalState).expect("ZCashd returned a non-hex tree"))?; - - #[cfg(test)] - { - result.node_address = result.rpc_call("z_getnewaddress", &json!([])).await?; - } - - Ok(result) - } - - async fn rpc_call< - Params: Serialize + Debug, - Response: DeserializeOwned + Debug - >(&self, method: &str, params: &Params) -> anyhow::Result { - #[derive(Deserialize, Debug)] - #[serde(untagged)] - enum FullResponse { - Err { - error: String, - }, - Ok { - result: T, - }, - } - - let client = reqwest::Client::new(); - let res: String = - client.post(&self.config.url) - .json( - & FullParams { - jsonrpc: "2.0", - id: (), - method, - params - } - ) - .send() - .await? - .text() - .await?; - debug!("RPC call to {} with {:?} returned {}", method, params, &res); - - let parsed_res: FullResponse = serde_json::from_str(&res) - .map_err(|_| anyhow::anyhow!("ZCashd didn't respond with expected JSON"))?; - match parsed_res { - FullResponse::Err { error } => anyhow::bail!("ZCashd RPC returned an error: {}", error), - FullResponse::Ok { result } => Ok(result), - } - } - - pub fn set_ak_nsk( - &mut self, - ak: &::PublicKey, - nsk: &::PrivateKey - ) { - self.nsk = JubjubEngine::add_private_key(&self.nsk, nsk); - let vk = ViewingKey { - ak: JubjubEngine::add_public_key(&JubjubEngine::to_public_key( - &self.ask.as_ref().expect("Key exchange occurring before generating keys")), - ak - ), - nk: JubjubEngine::mul_by_proof_generation_generator(&self.nsk) - }; - - // Seemingly random, generated using common data so we don't need to send another mutual variable - // Avoids the need for a more complicated method/a master secret - // This should likely be improved to the algorithm described by the Sapling protocol documentation - let mut diversifier = [0; 11]; - diversifier.copy_from_slice(&sha2::Sha256::new() - // DST for extra safety. If for some reason H(self.nsk) must be kept secret, this ensures it - // While we'd only leak 11 bytes, that's still a 88-bit reduction - .chain("asmr diversifier") - .chain(&JubjubEngine::private_key_to_bytes(&self.nsk)) - .finalize()[..11] - ); - // Recursively hash the diversifier until a valid one is found - // This is also somewhat mirrored by the protocol's definition of how to generate a diversifier - // That also has multiple failure values and takes the first which works - while vk.to_payment_address(Diversifier(diversifier)).is_none() { - let diversifier_copy = diversifier; - diversifier.copy_from_slice(&sha2::Sha256::digest(&diversifier_copy)[..11]); - } - - self.vk = Some(vk); - self.diversifier = Some(Diversifier(diversifier)); - } - - pub fn get_deposit_address(&mut self) -> String { - encode_payment_address( - HRP_SAPLING_PAYMENT_ADDRESS, - &self - .vk.as_ref().expect("Getting deposit address before sharing keys") - // unwrap as it'd have the same expect message as above - .to_payment_address(self.diversifier.clone().unwrap()) - .expect("Generated an invalid diversifier when sharing keys") - ) - } - - async fn get_height(&self) -> isize { - #[derive(Deserialize, Debug)] - struct InfoResponse { - blocks: isize - } - let info: InfoResponse = self.rpc_call("getinfo", &json!([])).await.expect("Couldn't get the network info"); - info.blocks - } - - async fn get_transaction(&self, tx_hash_hex: &str, block_hash_hex: &str) -> anyhow::Result { - let res: String = self.rpc_call("getrawtransaction", &json!([ - tx_hash_hex, 0, block_hash_hex - ])).await?; - let tx = Transaction::read( - &*hex::decode(&res).expect("ZCashd returned a non-hex block") - ).expect("ZCashd returned an invalid Transaction"); - Ok(tx) - } - - async fn get_block_transactions(&self, height: isize) -> anyhow::Result<(Vec, String)> { - #[derive(Deserialize, Debug)] - struct BlockResponse { - hash: String, - tx: Vec - } - - let res: BlockResponse = self.rpc_call("getblock", &json!([height.to_string()])).await?; - - let mut result = vec![]; - for tx in res.tx { - result.push(self.get_transaction(&tx, &res.hash).await?); - } - Ok((result, res.hash)) - } - - async fn get_confirmations(&self, tx_hash_hex: &str, block_hash_hex: &str) -> anyhow::Result { - #[derive(Deserialize, Debug)] - struct ConfirmationResponse { - in_active_chain: bool, - confirmations: isize - } - - let res: ConfirmationResponse = self.rpc_call("getrawtransaction", &json!([ - tx_hash_hex, 1, block_hash_hex - ])).await?; - if !res.in_active_chain { - anyhow::bail!("Transaction was reorganized off the chain"); - } - Ok(res.confirmations) - } - - pub async fn get_deposit(&mut self, vk: &ViewingKey, wait: bool) -> anyhow::Result> { - let mut block = self.height_at_start + 1; - let mut block_hash = "".to_string(); - let mut tx_hash = "".to_string(); - let mut funds; - 'outer: loop { - while self.get_height().await > block { - let txs = self.get_block_transactions(block).await?; - for tx in txs.0 { - let data = &*tx; - for output in data.shielded_outputs.clone() { - let node = Node::new(output.cmu.into()); - self.tree.append(node).unwrap(); - if self.witness.is_some() { - let mut witness = self.witness.clone().unwrap(); - witness.append(node).unwrap(); - self.witness = Some(witness); - } - - if self.note.is_none() { - funds = try_sapling_note_decryption( - &RegtestParams(()), - BlockHeight::from_u32(block as u32), - &vk.ivk(), - &output.ephemeral_key, - &output.cmu, - &output.enc_ciphertext - ); - - if funds.is_some() { - self.note = Some(funds.unwrap().0); - self.witness = Some(IncrementalWitness::from_tree(&self.tree)); - self.branch = Some(BranchId::for_height(&RegtestParams(()), BlockHeight::from_u32(block as u32))); - // The TXID is stored in little endian, forcing this - tx_hash = hex::encode(&tx.txid().0.to_vec().into_iter().rev().map(|x| x.to_owned()).collect::>()); - block_hash = txs.1.clone(); - } - } - } - } - - #[derive(Deserialize, Debug)] - struct BlockResponse { - finalsaplingroot: String - } - let block_res: BlockResponse = self.rpc_call("getblock", &json!([block.to_string()])).await?; - - if Node::new( - hex::decode(block_res.finalsaplingroot).expect("Sapling root wasn't hex") - .into_iter().rev().collect::>()[..].try_into().expect("Sapling root wasn't 32 bytes") - ) != self.tree.root() { - anyhow::bail!("Block root doesn't match"); - } - - // Only break once we finish this entire block - if self.note.is_some() { - break 'outer; - } - - block += 1; - } - if !wait { - return Ok(None); - } - tokio::time::delay_for(std::time::Duration::from_secs(10)).await; - } - - while self.get_confirmations(&tx_hash, &block_hash).await? < CONFIRMATIONS { - if !wait { - return Ok(None); - } - tokio::time::delay_for(std::time::Duration::from_secs(10)).await; - } - - return Ok(Some(self.note.as_ref().unwrap().value)); - } - - pub async fn claim( - &self, - ask: ::PrivateKey, - destination: &str - ) -> anyhow::Result<()> { - let destination = decode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, destination)?.expect("Invalid destination address"); - - // The below function only uses the expsk field of esk - // We have a expsk; we don't have a esk - // We also can't construct a dummy esk with the field we do have due to private fields - // Constructs and overrides a legitimate esk with our custom keys to satisfy the below API - let mut esk = ExtendedSpendingKey::master(&vec![0]); - let mut stub_ovk = [0; 32]; - OsRng.fill_bytes(&mut stub_ovk); - esk.expsk = ExpandedSpendingKey { - ask: JubjubEngine::get_scalar( - &JubjubEngine::add_private_key(&self.ask.as_ref().expect("Claiming despite never setting our key share"), &ask) - ), - nsk: JubjubEngine::get_scalar(&self.nsk), - ovk: OutgoingViewingKey(stub_ovk) - }; - - let mut builder = Builder::new(RegtestParams(()), BlockHeight::from_u32(self.get_height().await as u32)); - builder.add_sapling_spend( - esk, - self.diversifier.clone().expect("Claiming despite never sharing keys"), - self.note.clone().expect("Didn't set the note when funds were received"), - self.witness.clone().expect("Didn't set the witness when funds were received").path().unwrap() - )?; - builder.add_sapling_output( - None, - destination, - Amount::from_u64(self.note.as_ref().unwrap().value - 10000).expect("Invalid transaction amount; trying to swap < 10k sats?"), - None - )?; - - let tx = builder.build(self.branch.expect("Didn't set the branch when funds were received"), &self.prover)?.0; - let mut raw = vec![]; - tx.write(&mut raw).unwrap(); - let _: String = self.rpc_call("sendrawtransaction", &json!([hex::encode(raw)])).await?; - - Ok(()) - } - - #[cfg(test)] - pub async fn mine_block(&self) -> anyhow::Result<()> { - for _ in 0 .. 10 { - #[derive(Deserialize, Debug)] - struct ShieldResponse { - opid: String - } - let mut shield: anyhow::Result = self.rpc_call("z_shieldcoinbase", &json!([ - "*", &self.node_address - ])).await; - - if shield.is_ok() { - #[derive(Deserialize, Debug)] - struct StatusResponse { - status: String - } - while { - let status: Vec = self.rpc_call("z_getoperationstatus", &json!([[shield.as_ref().unwrap().opid]])).await?; - if status[0].status == "failed" { - tokio::time::delay_for(std::time::Duration::from_secs(1)).await; - shield = self.rpc_call("z_shieldcoinbase", &json!([ - "*", &self.node_address - ])).await; - } - (status[0].status != "success") && shield.is_ok() // Needed due to the tests being run in parallel. - // It can fail if another test picks it up. - } { - tokio::time::delay_for(std::time::Duration::from_secs(1)).await; - } - } - let _: Vec = self.rpc_call("generate", &json!([1])).await?; - } - - Ok(()) - } - - #[cfg(test)] - pub async fn send_from_wallet(&mut self) -> anyhow::Result { - for _ in 0 .. 11 { - self.mine_block().await?; - } - - let address = self.get_deposit_address(); - let send: String = self.rpc_call("z_sendmany", &json!([ - &self.node_address, [{"address": address, "amount": 1}] - ])).await?; - - // This is needed for some reason - // Given that we wait for the operation to succeed before mining blocks, and wait on that, I have no idea why - // Potentially a delay in parsing the info relevant to our wallet out of the above sapling send - // Therefore, this should be updated, yet for now, it works - tokio::time::delay_for(std::time::Duration::from_secs(3)).await; - - #[derive(Deserialize, Debug)] - struct StatusResponse { - status: String - } - while { - let status: Vec = self.rpc_call("z_getoperationstatus", &json!([[send]])).await?; - if status[0].status == "failed" { - anyhow::bail!("Send to wallet failed"); - } - status[0].status != "success" - } { - tokio::time::delay_for(std::time::Duration::from_secs(1)).await; - } - self.mine_block().await?; - - Ok(send) - } -} diff --git a/src/coins/zec/mod.rs b/src/coins/zec/mod.rs deleted file mode 100644 index 6263c84..0000000 --- a/src/coins/zec/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(not(test))] -mod engine; -#[cfg(test)] -pub mod engine; - -pub mod client; -pub mod verifier; diff --git a/src/coins/zec/verifier.rs b/src/coins/zec/verifier.rs deleted file mode 100644 index 33b5ceb..0000000 --- a/src/coins/zec/verifier.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::{ - marker::PhantomData, - io::Write, - path::Path, - fs::File -}; - -use async_trait::async_trait; - -use crate::{ - crypt_engines::{CryptEngine, jubjub_engine::JubjubEngine}, - dl_eq::DlEqProof, - coins::{ - UnscriptedVerifier, ScriptedHost, - zec::engine::* - } -}; - -pub struct ZecShieldedVerifier(ZecEngine); - -impl ZecShieldedVerifier { - pub async fn new(config_path: &Path) -> anyhow::Result { - Ok(ZecShieldedVerifier(ZecEngine::new(serde_json::from_reader(File::open(config_path)?)?).await?)) - } -} - -#[async_trait] -impl UnscriptedVerifier for ZecShieldedVerifier { - fn generate_keys_for_engine(&mut self, _: PhantomData<&OtherCrypt>) -> (Vec, OtherCrypt::PrivateKey) { - let (proof, key1, key2) = DlEqProof::::new(); - self.0.ask = Some(key1); - ( - bincode::serialize( - &ZecKeys { - dl_eq: proof.serialize(), - nsk: JubjubEngine::private_key_to_bytes(&self.0.nsk) - } - ).unwrap(), - key2 - ) - } - - fn verify_dleq_for_engine(&mut self, dleq: &[u8], _: PhantomData<&OtherCrypt>) -> anyhow::Result { - let keys: ZecKeys = bincode::deserialize(dleq)?; - let dleq = DlEqProof::::deserialize(&keys.dl_eq)?; - let (key1, key2) = dleq.verify()?; - self.0.set_ak_nsk( - &key2, - &JubjubEngine::bytes_to_private_key(keys.nsk)? - ); - Ok(key1) - } - - async fn verify_and_wait_for_send(&mut self) -> anyhow::Result<()> { - let vk = self.0.vk.clone().expect("Getting the deposit before sharing keys"); - let deposit = self.0.get_deposit(&vk, true).await?.unwrap(); - - if !cfg!(test) { - print!("You will receive {} atomic units of ZEC. Continue (yes/no)? ", deposit); - std::io::stdout().flush().expect("Failed to flush stdout"); - let mut line = String::new(); - std::io::stdin().read_line(&mut line).expect("Couldn't read from stdin"); - if !line.to_lowercase().starts_with("y") { - anyhow::bail!("User didn't confirm ZEC amount"); - } - } - - Ok(()) - } - - async fn finish(&mut self, host: &Host) -> anyhow::Result<()> { - self.0.claim( - JubjubEngine::little_endian_bytes_to_private_key(host.recover_final_key().await?)?, - &self.0.config.destination - ).await - } -} diff --git a/src/crypt_engines/jubjub_engine.rs b/src/crypt_engines/jubjub_engine.rs deleted file mode 100644 index bef9c3b..0000000 --- a/src/crypt_engines/jubjub_engine.rs +++ /dev/null @@ -1,314 +0,0 @@ -use std::{ - convert::TryInto, - fmt::Debug -}; - -use rand::rngs::OsRng; -use digest::Digest; -use serde::{Serialize, Deserialize}; - -use ff::Field; -use group::{Group, GroupEncoding}; -use jubjub::{Fr, SubgroupPoint}; -// SKG is used as the primary basepoint, as `ask` is what the atomic secret is, and `ask`'s public key is defined as its product -// JubJub's native generator is used as the alternate basepoint -use zcash_primitives::constants::{SPENDING_KEY_GENERATOR, PROOF_GENERATION_KEY_GENERATOR}; - -use crate::{ - crypt_engines::{Commitment, CryptEngine}, - dl_eq::SHARED_KEY_BITS -}; - -#[derive(Clone, Serialize, Deserialize, PartialEq)] -pub struct NonExistant; - -// Work around for the lack of Serialize/Deserialize on Fr/SubgroupPoint. -#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)] -pub struct PrivateKey { - bytes: [u8; 32] -} - -#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)] -pub struct PublicKey { - bytes: [u8; 32] -} - -#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)] -#[allow(non_snake_case)] -pub struct Signature { - R: [u8; 32], - s: [u8; 32], -} - -fn fr_from_bytes_mod(scalar: [u8; 32]) -> Fr { - let mut wide: [u8; 64] = [0; 64]; - wide[..32].copy_from_slice(&scalar); - Fr::from_bytes_wide(&wide) -} - -pub struct JubjubEngine; - -impl JubjubEngine { - pub fn get_scalar(key: &PrivateKey) -> Fr { - Fr::from_bytes(&key.bytes).unwrap() - } - - pub fn get_point(key: &PublicKey) -> SubgroupPoint { - SubgroupPoint::from_bytes(&key.bytes).unwrap() - } - - pub fn add_private_key(a: &PrivateKey, b: &PrivateKey) -> PrivateKey { - PrivateKey { - bytes: (JubjubEngine::get_scalar(a) + JubjubEngine::get_scalar(b)).to_bytes() - } - } - - pub fn add_public_key(a: &PublicKey, b: &PublicKey) -> SubgroupPoint { - JubjubEngine::get_point(a) + JubjubEngine::get_point(b) - } - - pub fn mul_by_proof_generation_generator(key: &PrivateKey) -> SubgroupPoint { - PROOF_GENERATION_KEY_GENERATOR * JubjubEngine::get_scalar(key) - } -} - -impl CryptEngine for JubjubEngine { - type PrivateKey = PrivateKey; - type PublicKey = PublicKey; - type Signature = Signature; - type EncryptedSignature = NonExistant; - - fn new_private_key() -> Self::PrivateKey { - PrivateKey { - bytes: Fr::random(&mut OsRng).to_bytes() - } - } - - fn to_public_key(key: &Self::PrivateKey) -> Self::PublicKey { - PublicKey { - bytes: (SPENDING_KEY_GENERATOR * Fr::from_bytes(&key.bytes).unwrap()).to_bytes() - } - } - - fn bytes_to_private_key(bytes: [u8; 32]) -> anyhow::Result { - if Fr::from_bytes(&bytes).is_some().into() { - Ok(PrivateKey { - bytes - }) - } else { - Err(anyhow::anyhow!("Invalid private key")) - } - } - - fn bytes_to_public_key(bytes: &[u8]) -> anyhow::Result { - if SubgroupPoint::from_bytes(&bytes.try_into()?).is_some().into() { - Ok(PublicKey { - bytes: bytes.try_into()? - }) - } else { - Err(anyhow::anyhow!("Invalid public key")) - } - } - - fn bytes_to_signature(bytes: &[u8]) -> anyhow::Result { - if bytes.len() != 64 { - anyhow::bail!("Expected JubJub signature to be 64 bytes long"); - } - - #[allow(non_snake_case)] - let R = SubgroupPoint::from_bytes(&bytes[..32].try_into()?); - let s = Fr::from_bytes(&bytes[32..].try_into()?); - if R.is_none().into() || s.is_none().into() { - anyhow::bail!("Invalid point/scalar value in signature"); - } - - // Could also use bytes[..32].try_into()? - Ok(Signature { - R: R.unwrap().to_bytes(), - s: s.unwrap().to_bytes() - }) - } - - fn little_endian_bytes_to_private_key(bytes: [u8; 32]) -> anyhow::Result { - Self::bytes_to_private_key(bytes) - } - - fn private_key_to_little_endian_bytes(key: &Self::PrivateKey) -> [u8; 32] { - Self::private_key_to_bytes(key) - } - - fn dl_eq_generate_commitments(key: [u8; 32]) -> anyhow::Result>> { - let mut commitments = Vec::new(); - let mut blinding_key_total = Fr::zero(); - let mut power_of_two = Fr::one(); - for i in 0..SHARED_KEY_BITS { - let blinding_key = if i == SHARED_KEY_BITS - 1 { - -blinding_key_total * power_of_two.invert().unwrap() - } else { - Fr::random(&mut OsRng) - }; - blinding_key_total += blinding_key * power_of_two; - power_of_two = power_of_two.double(); - let commitment_base = &SubgroupPoint::generator() * blinding_key; - let (commitment, commitment_minus_one) = if (key[i/8] >> (i % 8)) & 1 == 1 { - (&commitment_base + SPENDING_KEY_GENERATOR, commitment_base) - } else { - (commitment_base, &commitment_base - SPENDING_KEY_GENERATOR) - }; - commitments.push(Commitment { - blinding_key: PrivateKey { - bytes: blinding_key.to_bytes() - }, - commitment_minus_one: PublicKey { - bytes: commitment_minus_one.to_bytes() - }, - commitment: PublicKey { - bytes: commitment.to_bytes() - } - }); - } - debug_assert_eq!(blinding_key_total, Fr::zero()); - debug_assert_eq!( - Self::dl_eq_reconstruct_key(commitments.iter().map(|c| &c.commitment))?, - PublicKey { - bytes: (SPENDING_KEY_GENERATOR * Fr::from_bytes(&key).unwrap()).to_bytes() - } - ); - Ok(commitments) - } - - fn dl_eq_compute_signature_s(nonce: &Self::PrivateKey, challenge: [u8; 32], key: &Self::PrivateKey) -> anyhow::Result { - Ok(PrivateKey { - bytes: ( - (Fr::from_bytes(&key.bytes).unwrap() * fr_from_bytes_mod(challenge)) + - Fr::from_bytes(&nonce.bytes).unwrap() - ).to_bytes() - }) - } - - #[allow(non_snake_case)] - fn dl_eq_compute_signature_R(s_value: &Self::PrivateKey, challenge: [u8; 32], key: &Self::PublicKey) -> anyhow::Result { - Ok(PublicKey { - bytes: ( - (&SubgroupPoint::generator() * Fr::from_bytes(&s_value.bytes).unwrap()) - - (SubgroupPoint::from_bytes(&key.bytes).unwrap() * fr_from_bytes_mod(challenge)) - ).to_bytes() - }) - } - - fn dl_eq_commitment_sub_one(commitment: &Self::PublicKey) -> anyhow::Result { - Ok(PublicKey { - bytes: (SubgroupPoint::from_bytes(&commitment.bytes).unwrap() - SPENDING_KEY_GENERATOR).to_bytes() - }) - } - - fn dl_eq_reconstruct_key<'a>(commitments: impl Iterator) -> anyhow::Result { - let mut power_of_two = Fr::one(); - let mut res = SubgroupPoint::identity(); - for comm in commitments { - res = res + (SubgroupPoint::from_bytes(&comm.bytes).unwrap() * power_of_two); - power_of_two = power_of_two.double(); - } - Ok(PublicKey { - bytes: res.to_bytes() - }) - } - - fn dl_eq_blinding_key_to_public(key: &Self::PrivateKey) -> anyhow::Result { - Ok(PublicKey { - bytes: (&SubgroupPoint::generator() * Fr::from_bytes(&key.bytes).unwrap()).to_bytes() - }) - } - - fn private_key_to_bytes(key: &Self::PrivateKey) -> [u8; 32] { - key.bytes - } - fn public_key_to_bytes(key: &Self::PublicKey) -> Vec { - key.bytes.to_vec() - } - - fn signature_to_bytes(sig: &Self::Signature) -> Vec { - let mut bytes = sig.R.to_vec(); - bytes.extend(&sig.s); - bytes - } - - // This implements EdDSA; implementing RedDSA instead to further match ZCash would be optimal. - // The reason this implements EdDSA is because *any* algorithm would work here, and we already had EdDSA code. - // It is solely used as a proof of knowledge, outsourcing the actual spend auth signature to ZCash code. - #[allow(non_snake_case)] - fn sign(key: &Self::PrivateKey, message: &[u8]) -> anyhow::Result { - let key = Fr::from_bytes(&key.bytes).unwrap(); - let r = Fr::random(&mut OsRng); - let R = SPENDING_KEY_GENERATOR * r; - let A = SPENDING_KEY_GENERATOR * &key; - let mut hram = [0u8; 64]; - let hash = sha2::Sha512::new() - .chain(&R.to_bytes()) - .chain(&A.to_bytes()) - .chain(message) - .finalize(); - hram.copy_from_slice(&hash); - let c = Fr::from_bytes_wide(&hram); - let s = r + c * key; - Ok(Signature { - R: R.to_bytes(), - s: s.to_bytes(), - }) - } - - #[allow(non_snake_case)] - fn verify_signature(public_key: &Self::PublicKey, message: &[u8], signature: &Self::Signature) -> anyhow::Result<()> { - let mut hram = [0u8; 64]; - let hash = sha2::Sha512::new() - .chain(&signature.R) - .chain(&public_key.bytes) - .chain(message) - .finalize(); - hram.copy_from_slice(&hash); - let c = Fr::from_bytes_wide(&hram); - let expected_R = (SPENDING_KEY_GENERATOR * Fr::from_bytes(&signature.s).unwrap()) - - (SubgroupPoint::from_bytes(&public_key.bytes).unwrap() * c); - if SubgroupPoint::from(expected_R) == SubgroupPoint::from_bytes(&signature.R).unwrap() { - Ok(()) - } else { - Err(anyhow::anyhow!("Bad signature")) - } - } - - // JubJub is used in ZK-Snarks. They don't have traditional signatures - // Because of that, the following functions should never be called. They accordingly immediately error - // The above functions are kept, however, as part of the proof of knowledge required with the DL EQ proof - fn bytes_to_encrypted_signature(_bytes: &[u8]) -> anyhow::Result { - panic!("JubJub isn't used with signatures; there shouldn't be anything to deserialize"); - } - - fn encrypted_signature_to_bytes(_sig: &Self::EncryptedSignature) -> Vec { - panic!("JubJub isn't used with signatures; there shouldn't be anything to serialize"); - } - - fn encrypted_sign( - _signing_key: &Self::PrivateKey, - _encryption_key: &Self::PublicKey, - _message: &[u8] - ) -> anyhow::Result { - panic!("JubJub isn't used with signatures; there shouldn't be anything to encrypt"); - } - - fn encrypted_verify( - _signing_key: &Self::PublicKey, - _encryption_key: &Self::PublicKey, - _ciphertext: &Self::EncryptedSignature, - _message: &[u8] - ) -> anyhow::Result<()> { - panic!("JubJub isn't used with signatures; there shouldn't be anything to verify"); - } - - fn decrypt_signature(_sig: &Self::EncryptedSignature, _key: &Self::PrivateKey) -> anyhow::Result { - panic!("JubJub isn't used with signatures; there shouldn't be anything to decrypt"); - } - - fn recover_key(_encryption_key: &Self::PublicKey, _ciphertext: &Self::EncryptedSignature, _sig: &Self::Signature) -> anyhow::Result { - panic!("JubJub isn't used with signatures; there shouldn't be anything to recover from"); - } -} diff --git a/src/crypt_engines/mod.rs b/src/crypt_engines/mod.rs index 998e5b0..5b24683 100644 --- a/src/crypt_engines/mod.rs +++ b/src/crypt_engines/mod.rs @@ -1,6 +1,5 @@ pub mod secp256k1_engine; pub mod ed25519_engine; -pub mod jubjub_engine; use serde::{Serialize, Deserialize, de::DeserializeOwned}; diff --git a/src/main.rs b/src/main.rs index 90703a4..cd9979d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,10 +25,8 @@ use crate::{ coins::{ *, btc::{host::BtcHost, verifier::BtcVerifier}, - meros::{client::MerosClient, verifier::MerosVerifier}, nano::{client::NanoClient, verifier::NanoVerifier}, xmr::{client::XmrClient, verifier::XmrVerifier}, - zec::{client::ZecShieldedClient, verifier::ZecShieldedVerifier} }, cli::{ScriptedCoin, UnscriptedCoin, Cli} }; @@ -51,13 +49,11 @@ async fn main() { let mut listen_handle = None; if opts.host_or_client.is_host() { let mut scripted_host: AnyScriptedHost = match opts.pair.scripted { - ScriptedCoin::Bitcoin => BtcHost::new(&scripted_config).map(Into::into), + ScriptedCoin::Litecoin => BtcHost::new(&scripted_config).map(Into::into), }.expect("Failed to create scripted host"); let mut unscripted_verifier: AnyUnscriptedVerifier = match opts.pair.unscripted { - UnscriptedCoin::Meros => MerosVerifier::new(&unscripted_config).map(Into::into), UnscriptedCoin::Nano => NanoVerifier::new(&unscripted_config).map(Into::into), UnscriptedCoin::Monero => XmrVerifier::new(&unscripted_config).await.map(Into::into), - UnscriptedCoin::ZCashShielded => ZecShieldedVerifier::new(&unscripted_config).await.map(Into::into) }.expect("Failed to create unscripted verifier"); // Have the host also host the server socket @@ -103,13 +99,11 @@ async fn main() { if opts.host_or_client.is_client() { let mut unscripted_client: AnyUnscriptedClient = match opts.pair.unscripted { - UnscriptedCoin::Meros => MerosClient::new(&unscripted_config).map(Into::into), UnscriptedCoin::Nano => NanoClient::new(&unscripted_config).map(Into::into), UnscriptedCoin::Monero => XmrClient::new(&unscripted_config).await.map(Into::into), - UnscriptedCoin::ZCashShielded => ZecShieldedClient::new(&unscripted_config).await.map(Into::into), }.expect("Failed to create unscripted client"); let mut scripted_verifier: AnyScriptedVerifier = match opts.pair.scripted { - ScriptedCoin::Bitcoin => BtcVerifier::new(&scripted_config).map(Into::into), + ScriptedCoin::Litecoin => BtcVerifier::new(&scripted_config).map(Into::into), }.expect("Failed to create scripted verifier"); let stream = TcpStream::connect(opts.tcp_address).await.expect("Failed to connect to host"); diff --git a/src/tests/btc_and_meros.rs b/src/tests/btc_and_meros.rs deleted file mode 100644 index 8d90b6e..0000000 --- a/src/tests/btc_and_meros.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::{ - path::PathBuf, - future::Future -}; - -use crate::{ - coins::{ - *, - btc::{host::BtcHost, verifier::BtcVerifier}, - meros::{client::MerosClient, verifier::MerosVerifier} - }, - tests::swap::{ - success::test_success, - host::{ - no_address::test_no_host_address, - never_funded_address::test_never_funded_address, - funded_address_no_lock::test_funded_address_no_lock, - funded_address_created_lock::test_funded_address_created_lock, - published_lock::test_published_lock, - attempted_refund_yet_success::test_attempted_refund_yet_success - }, - client::{ - no_address::test_no_client_address, - generated_address::test_generated_address, - funded_get_unscripted::test_funded_get_unscripted, - funded_get_scripted::test_funded_get_scripted - } - } -}; - -pub async fn run_test(host_test: bool, test: F) - where F: FnOnce(AnyScriptedHost, AnyUnscriptedVerifier, AnyUnscriptedClient, AnyScriptedVerifier) -> Fut, - Fut: Future> -{ - let scripted: PathBuf = "config/bitcoin.json".to_string().into(); - let unscripted: PathBuf = "config/meros.json".to_string().into(); - - let mut host: AnyScriptedHost = BtcHost::new(&scripted).expect("Failed to create BTC host").into(); - host.override_refund_with_random_address(); - let host_refund = host.get_refund_address(); - let hosts_verifier: AnyUnscriptedVerifier = MerosVerifier::new(&unscripted).expect("Failed to create BTC verifier").into(); - - let mut client: AnyUnscriptedClient = MerosClient::new(&unscripted).expect("Failed to create Meros client").into(); - client.override_refund_with_random_address(); - let client_refund = client.get_refund_address(); - let clients_verifier: AnyScriptedVerifier = BtcVerifier::new(&scripted).expect("Failed to create Meros verifier").into(); - - let should_have_funds = test(host, hosts_verifier, client, clients_verifier).await.unwrap(); - if host_test { - let host = BtcHost::new(&scripted).unwrap(); - host.advance_consensus().await.unwrap(); - assert_eq!(should_have_funds, host.get_if_funded(&host_refund).await); - } else { - let client = MerosClient::new(&unscripted).unwrap(); - client.advance_consensus().await.unwrap(); - assert_eq!(should_have_funds, client.get_if_funded(&client_refund).await); - } -} - -#[tokio::test] -pub async fn test_btc_and_meros() { - let _ = env_logger::builder().is_test(true).try_init(); - run_test(true, test_success).await; - - run_test(true, test_no_host_address).await; - run_test(true, test_never_funded_address).await; - run_test(true, test_funded_address_no_lock).await; - run_test(true, test_funded_address_created_lock).await; - run_test(true, test_published_lock).await; - run_test(true, test_attempted_refund_yet_success).await; - - run_test(false, test_no_client_address).await; - run_test(false, test_generated_address).await; - run_test(false, test_funded_get_unscripted).await; - run_test(false, test_funded_get_scripted).await; -} diff --git a/src/tests/btc_and_zec.rs b/src/tests/btc_and_zec.rs deleted file mode 100644 index 2f14ab0..0000000 --- a/src/tests/btc_and_zec.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::{ - path::PathBuf, - future::Future -}; - -use crate::{ - coins::{ - *, - btc::{host::BtcHost, verifier::BtcVerifier}, - zec::{client::ZecShieldedClient, verifier::ZecShieldedVerifier} - }, - tests::swap::{ - success::test_success, - host::{ - no_address::test_no_host_address, - never_funded_address::test_never_funded_address, - funded_address_no_lock::test_funded_address_no_lock, - funded_address_created_lock::test_funded_address_created_lock, - published_lock::test_published_lock, - attempted_refund_yet_success::test_attempted_refund_yet_success - }, - client::{ - no_address::test_no_client_address, - generated_address::test_generated_address, - funded_get_unscripted::test_funded_get_unscripted, - funded_get_scripted::test_funded_get_scripted - } - } -}; - -pub async fn run_test(host_test: bool, test: F) - where F: FnOnce(AnyScriptedHost, AnyUnscriptedVerifier, AnyUnscriptedClient, AnyScriptedVerifier) -> Fut, - Fut: Future> -{ - let scripted: PathBuf = "config/bitcoin.json".to_string().into(); - let unscripted: PathBuf = "config/zcashshielded.json".to_string().into(); - - let mut host: AnyScriptedHost = BtcHost::new(&scripted).expect("Failed to create BTC host").into(); - host.override_refund_with_random_address(); - let host_refund = host.get_refund_address(); - let hosts_verifier: AnyUnscriptedVerifier = ZecShieldedVerifier::new(&unscripted).await.expect("Failed to create BTC verifier").into(); - - let mut client: AnyUnscriptedClient = ZecShieldedClient::new(&unscripted).await.expect("Failed to create ZCash client").into(); - client.override_refund_with_random_address(); - let client_refund = client.get_refund_address(); - let clients_verifier: AnyScriptedVerifier = BtcVerifier::new(&scripted).expect("Failed to create ZCash verifier").into(); - - let should_have_funds = test(host, hosts_verifier, client, clients_verifier).await.unwrap(); - if host_test { - let host = BtcHost::new(&scripted).unwrap(); - host.advance_consensus().await.unwrap(); - assert_eq!(should_have_funds, host.get_if_funded(&host_refund).await); - } else { - let client = ZecShieldedClient::new(&unscripted).await.unwrap(); - client.advance_consensus().await.unwrap(); - assert_eq!(should_have_funds, client.get_if_funded(&client_refund).await); - } -} - -#[tokio::test] -pub async fn test_btc_and_zec() { - let _ = env_logger::builder().is_test(true).try_init(); - run_test(true, test_success).await; - - run_test(true, test_no_host_address).await; - run_test(true, test_never_funded_address).await; - run_test(true, test_funded_address_no_lock).await; - run_test(true, test_funded_address_created_lock).await; - run_test(true, test_published_lock).await; - run_test(true, test_attempted_refund_yet_success).await; - - run_test(false, test_no_client_address).await; - run_test(false, test_generated_address).await; - run_test(false, test_funded_get_unscripted).await; - run_test(false, test_funded_get_scripted).await; -} diff --git a/src/tests/coin_specific/mod.rs b/src/tests/coin_specific/mod.rs index 84b0d87..95ecf78 100644 --- a/src/tests/coin_specific/mod.rs +++ b/src/tests/coin_specific/mod.rs @@ -1,3 +1 @@ mod nano; -#[cfg(feature = "test_zcash_node")] -mod zcash; diff --git a/src/tests/coin_specific/zcash.rs b/src/tests/coin_specific/zcash.rs deleted file mode 100644 index 1af4919..0000000 --- a/src/tests/coin_specific/zcash.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::{ - crypt_engines::{CryptEngine, jubjub_engine::JubjubEngine}, - coins::zec::engine::{ZecConfig, ZecEngine} -}; - -#[tokio::test] -async fn receive_funds() -> anyhow::Result<()> { - let mut engine = ZecEngine::new(ZecConfig { - url: "http://user:pass@127.0.0.1:18232".to_string(), - destination: "".to_string(), - refund: "".to_string() - }).await?; - - let other_ask = JubjubEngine::new_private_key(); - let other_nsk = JubjubEngine::new_private_key(); - - engine.ask = Some(JubjubEngine::new_private_key()); - engine.set_ak_nsk(&JubjubEngine::to_public_key(&other_ask), &other_nsk); - let vk = engine.vk.clone().expect("ViewingKey wasn't created despite setting the other ak/nsk"); - assert!(engine.get_deposit(&vk, false).await?.is_none()); - engine.send_from_wallet().await?; - assert!(engine.get_deposit(&vk, false).await?.is_some()); - Ok(()) -} - -#[tokio::test] -async fn send_funds() -> anyhow::Result<()> { - // Copied from the above test to get a funded engine - let mut engine = ZecEngine::new(ZecConfig { - url: "http://user:pass@127.0.0.1:18232".to_string(), - destination: "".to_string(), - refund: "".to_string() - }).await?; - - let other_ask = JubjubEngine::new_private_key(); - let other_nsk = JubjubEngine::new_private_key(); - - engine.ask = Some(JubjubEngine::new_private_key()); - engine.set_ak_nsk(&JubjubEngine::to_public_key(&other_ask), &other_nsk); - let vk = engine.vk.clone().expect("ViewingKey wasn't created despite setting the other ak/nsk"); - engine.send_from_wallet().await?; - let value = engine.get_deposit(&vk, false).await?; - assert!(value.is_some()); - - // Now the trick is spending our funds. This is done by creating ANOTHER engine which will receive the funds - let mut recipient = ZecEngine::new(ZecConfig { - url: "http://user:pass@127.0.0.1:18232".to_string(), - destination: "".to_string(), - refund: "".to_string() - }).await?; - recipient.ask = Some(JubjubEngine::new_private_key()); - recipient.set_ak_nsk( - &JubjubEngine::to_public_key(&JubjubEngine::new_private_key()), - &JubjubEngine::new_private_key() - ); - - // Address to send to - let address = recipient.get_deposit_address(); - - // Send the funds - engine.claim(other_ask, &address).await?; - engine.mine_block().await?; - - // Verify we were sent to - let vk = recipient.vk.clone().expect("ViewingKey wasn't created despite setting the other ak/nsk"); - assert!(recipient.get_deposit(&vk, false).await?.is_some()); - - Ok(()) -} diff --git a/src/tests/dl_eq.rs b/src/tests/dl_eq.rs index b83d54c..e3ab3f4 100644 --- a/src/tests/dl_eq.rs +++ b/src/tests/dl_eq.rs @@ -3,7 +3,6 @@ use crate::{ crypt_engines::{ ed25519_engine::Ed25519Sha, secp256k1_engine::Secp256k1Engine, - jubjub_engine::JubjubEngine }, dl_eq::DlEqProof }; @@ -28,12 +27,6 @@ fn dl_eq_secp256k1_with_self() { test_dl_eq_with_engines::(); } -#[test] -fn dl_eq_jubjub_with_self() { - let _ = env_logger::builder().is_test(true).try_init(); - test_dl_eq_with_engines::(); -} - #[test] fn dl_eq_secp256k1_with_ed25519() { let _ = env_logger::builder().is_test(true).try_init(); @@ -41,20 +34,6 @@ fn dl_eq_secp256k1_with_ed25519() { test_dl_eq_with_engines::(); } -#[test] -fn dl_eq_secp256k1_with_jubjub() { - let _ = env_logger::builder().is_test(true).try_init(); - test_dl_eq_with_engines::(); - test_dl_eq_with_engines::(); -} - -#[test] -fn dl_eq_ed25519_with_jubjub() { - let _ = env_logger::builder().is_test(true).try_init(); - test_dl_eq_with_engines::(); - test_dl_eq_with_engines::(); -} - #[test] fn test_max_key_wrapping() { let _ = env_logger::builder().is_test(true).try_init(); @@ -65,5 +44,4 @@ fn test_max_key_wrapping() { key_rev.reverse(); assert_eq!(Ed25519Sha::private_key_to_bytes(&Ed25519Sha::little_endian_bytes_to_private_key(key).unwrap()), key); assert_eq!(Secp256k1Engine::private_key_to_bytes(&Secp256k1Engine::little_endian_bytes_to_private_key(key).unwrap()), key_rev); - assert_eq!(JubjubEngine::private_key_to_bytes(&JubjubEngine::little_endian_bytes_to_private_key(key).unwrap()), key); } diff --git a/src/tests/jubjub.rs b/src/tests/jubjub.rs deleted file mode 100644 index 616c550..0000000 --- a/src/tests/jubjub.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::crypt_engines::{CryptEngine, jubjub_engine::JubjubEngine}; - -#[test] -fn test_jubjub_signature() { - let _ = env_logger::builder().is_test(true).try_init(); - let key = JubjubEngine::new_private_key(); - let sig = JubjubEngine::sign(&key, &vec![1]).expect("Couldn't call send"); - JubjubEngine::verify_signature(&JubjubEngine::to_public_key(&key), &vec![1], &sig).expect("Signature verification failed"); -} diff --git a/src/tests/btc_and_nano.rs b/src/tests/ltc_and_nano.rs similarity index 96% rename from src/tests/btc_and_nano.rs rename to src/tests/ltc_and_nano.rs index fa71d07..526ff32 100644 --- a/src/tests/btc_and_nano.rs +++ b/src/tests/ltc_and_nano.rs @@ -35,7 +35,7 @@ pub async fn run_test(host_test: bool, test: F) where F: FnOnce(AnyScriptedHost, AnyUnscriptedVerifier, AnyUnscriptedClient, AnyScriptedVerifier) -> Fut, Fut: Future> { - let scripted: PathBuf = "config/bitcoin.json".to_string().into(); + let scripted: PathBuf = "config/litecoin.json".to_string().into(); let unscripted: PathBuf = "config/nano.json".to_string().into(); let mut host: AnyScriptedHost = BtcHost::new(&scripted).expect("Failed to create BTC host").into(); @@ -61,7 +61,7 @@ pub async fn run_test(host_test: bool, test: F) } #[tokio::test] -pub async fn test_btc_and_nano() { +pub async fn test_ltc_and_nano() { let _ = env_logger::builder().is_test(true).try_init(); run_test(true, test_success).await; diff --git a/src/tests/btc_and_xmr.rs b/src/tests/ltc_and_xmr.rs similarity index 96% rename from src/tests/btc_and_xmr.rs rename to src/tests/ltc_and_xmr.rs index 77b5173..57892c0 100644 --- a/src/tests/btc_and_xmr.rs +++ b/src/tests/ltc_and_xmr.rs @@ -32,7 +32,7 @@ pub async fn run_test(host_test: bool, test: F) where F: FnOnce(AnyScriptedHost, AnyUnscriptedVerifier, AnyUnscriptedClient, AnyScriptedVerifier) -> Fut, Fut: Future> { - let scripted: PathBuf = "config/bitcoin.json".to_string().into(); + let scripted: PathBuf = "config/litecoin.json".to_string().into(); let unscripted: PathBuf = "config/monero.json".to_string().into(); let mut host: AnyScriptedHost = BtcHost::new(&scripted).expect("Failed to create BTC host").into(); @@ -58,7 +58,7 @@ pub async fn run_test(host_test: bool, test: F) } #[tokio::test] -pub async fn test_btc_and_xmr() { +pub async fn test_ltc_and_xmr() { let _ = env_logger::builder().is_test(true).try_init(); run_test(true, test_success).await; diff --git a/src/tests/mod.rs b/src/tests/mod.rs index f1262b7..1bd2da9 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,17 +1,12 @@ -mod jubjub; mod dl_eq; mod secp_dl_eq; mod ves; mod serialization; mod coin_specific; -#[cfg_attr(not(feature = "test_bitcoin_node"), allow(dead_code))] +#[cfg_attr(not(feature = "test_litecoin_node"), allow(dead_code))] mod swap; -#[cfg(all(feature = "test_bitcoin_node", feature = "test_meros_node"))] -mod btc_and_meros; -#[cfg(all(feature = "test_bitcoin_node", feature = "test_nano_node"))] -mod btc_and_nano; -#[cfg(all(feature = "test_bitcoin_node", feature = "test_monero_node"))] -mod btc_and_xmr; -#[cfg(all(feature = "test_bitcoin_node", feature = "test_zcash_node"))] -mod btc_and_zec; +#[cfg(all(feature = "test_litecoin_node", feature = "test_nano_node"))] +mod ltc_and_nano; +#[cfg(all(feature = "test_litecoin_node", feature = "test_monero_node"))] +mod ltc_and_xmr;