diff --git a/.github/workflows/ci-basic.yml b/.github/workflows/ci-basic.yml new file mode 100644 index 00000000000..226f1528046 --- /dev/null +++ b/.github/workflows/ci-basic.yml @@ -0,0 +1,36 @@ +name: Basic checks + +#on: [push, pull_request] +on: [push] + +jobs: + test: + name: Test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-24.04] + + env: + # Use system-installed RocksDB library instead of building from scratch + ROCKSDB_LIB_DIR: /usr/lib + # Use system-installed Snappy library for compression in RocksDB + SNAPPY_LIB_DIR: /usr/lib/x86_64-linux-gnu + # FIXME: remove the following commented lines + # Enable the `nu6` feature in `zcash_protocol` + #RUSTFLAGS: '--cfg zcash_unstable="nu6"' + #RUSTDOCFLAGS: '--cfg zcash_unstable="nu6"' + + steps: + - uses: actions/checkout@v4 + - name: Install dependencies on Ubuntu + #run: sudo apt-get update && sudo apt-get install -y protobuf-compiler build-essential librocksdb-dev + run: sudo apt-get update && sudo apt-get install -y protobuf-compiler librocksdb-dev + - name: Run tests + run: cargo test --verbose + - name: Verify working directory is clean + run: git diff --exit-code + - name: Run doc check + run: cargo doc --all-features --document-private-items + - name: Run format check + run: cargo fmt -- --check diff --git a/Cargo.lock b/Cargo.lock index 22f5d505038..ae2e712bd81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -137,9 +137,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -152,33 +152,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -198,9 +198,9 @@ checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" [[package]] name = "arrayvec" @@ -210,9 +210,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "async-compression" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" +checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" dependencies = [ "flate2", "futures-core", @@ -245,9 +245,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", @@ -288,7 +288,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "itoa", "matchit", @@ -314,7 +314,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", @@ -339,6 +339,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.11.0" @@ -429,18 +435,16 @@ dependencies = [ ] [[package]] -name = "bip32" -version = "0.5.2" +name = "bip0039" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa13fae8b6255872fd86f7faf4b41168661d7d78609f7bfe6771b85c6739a15b" +checksum = "bef0f0152ec5cf17f49a5866afaa3439816207fd4f0a224c0211ffaf5e278426" dependencies = [ - "bs58", "hmac", - "rand_core 0.6.4", - "ripemd", - "secp256k1 0.27.0", + "pbkdf2", + "rand 0.8.5", "sha2", - "subtle", + "unicode-normalization", "zeroize", ] @@ -539,9 +543,9 @@ dependencies = [ [[package]] name = "bridgetree" -version = "0.5.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f62227647af796dd9f1637da0392676a2e200973b817b082fc9be89bf93ddd74" +checksum = "fbfcb6c5a091e80cb3d3b0c1a7f126af4631cd5065b1f9929b139f1be8f3fb62" dependencies = [ "incrementalmerkletree", ] @@ -558,9 +562,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.9.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", "serde", @@ -580,9 +584,9 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "bytemuck" -version = "1.16.1" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" +checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83" [[package]] name = "byteorder" @@ -662,13 +666,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.100" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c891175c3fb232128f48de6590095e59198bbeb8620c310be349bfc3afd12c7b" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" dependencies = [ "jobserver", "libc", - "once_cell", ] [[package]] @@ -732,7 +735,7 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -835,9 +838,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "color-eyre" @@ -869,9 +872,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "console" @@ -893,8 +896,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86ed14aa9c9f927213c6e4f3ef75faaad3406134efe84ba2cb7983431d5f0931" dependencies = [ "futures-core", - "prost", - "prost-types", + "prost 0.13.1", + "prost-types 0.13.1", "tonic", "tracing-core", ] @@ -912,8 +915,8 @@ dependencies = [ "hdrhistogram", "humantime", "hyper-util", - "prost", - "prost-types", + "prost 0.13.1", + "prost-types 0.13.1", "serde", "serde_json", "thread_local", @@ -1047,6 +1050,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -1097,12 +1112,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ - "darling_core 0.20.9", - "darling_macro 0.20.9", + "darling_core 0.20.10", + "darling_macro 0.20.10", ] [[package]] @@ -1121,9 +1136,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", @@ -1146,11 +1161,11 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ - "darling_core 0.20.9", + "darling_core 0.20.10", "quote", "syn 2.0.72", ] @@ -1192,6 +1207,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -1219,9 +1235,9 @@ dependencies = [ [[package]] name = "document-features" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" +checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" dependencies = [ "litrs", ] @@ -1232,6 +1248,20 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + [[package]] name = "ed25519" version = "2.2.3" @@ -1261,9 +1291,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elasticsearch" @@ -1285,6 +1315,25 @@ dependencies = [ "void", ] +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "encode_unicode" version = "0.3.6" @@ -1323,7 +1372,7 @@ dependencies = [ [[package]] name = "equihash" version = "0.2.0" -source = "git+https://github.com/zcash/librustzcash/#a1047adf0b6f324dad415db34762dc26f8367ce4" +source = "git+https://github.com/QED-it/librustzcash?branch=txv6-separate-bundles-rebased-dd2#8149034c53c9a33b5ca417689c42ec4d47d0eff5" dependencies = [ "blake2b_simd", "byteorder", @@ -1358,16 +1407,7 @@ dependencies = [ [[package]] name = "f4jumble" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a83e8d7fd0c526af4aad893b7c9fe41e2699ed8a776a6c74aecdeafe05afc75" -dependencies = [ - "blake2b_simd", -] - -[[package]] -name = "f4jumble" -version = "0.1.0" -source = "git+https://github.com/zcash/librustzcash/#a1047adf0b6f324dad415db34762dc26f8367ce4" +source = "git+https://github.com/QED-it/librustzcash?branch=txv6-separate-bundles-rebased-dd2#8149034c53c9a33b5ca417689c42ec4d47d0eff5" dependencies = [ "blake2b_simd", ] @@ -1415,9 +1455,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" dependencies = [ "crc32fast", "miniz_oxide", @@ -1433,7 +1473,7 @@ dependencies = [ "futures-sink", "nanorand", "pin-project", - "spin", + "spin 0.9.8", ] [[package]] @@ -1577,6 +1617,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1693,19 +1734,17 @@ dependencies = [ [[package]] name = "half" -version = "2.4.1" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" dependencies = [ - "cfg-if 1.0.0", "crunchy", ] [[package]] name = "halo2_gadgets" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126a150072b0c38c7b573fe3eaf0af944a7fed09e154071bf2436d3f016f7230" +source = "git+https://github.com/QED-it/halo2?branch=zsa1#1195c9af90205829ba20662bdfaf20dcc878807d" dependencies = [ "arrayvec", "bitvec", @@ -1728,8 +1767,7 @@ checksum = "47716fe1ae67969c5e0b2ef826f32db8c3be72be325e1aa3c1951d06b5575ec5" [[package]] name = "halo2_proofs" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b867a8d9bbb85fca76fff60652b5cd19b853a1c4d0665cb89bee68b18d2caf0" +source = "git+https://github.com/QED-it/halo2?branch=zsa1#1195c9af90205829ba20662bdfaf20dcc878807d" dependencies = [ "blake2b_simd", "ff", @@ -1770,6 +1808,19 @@ dependencies = [ "num-traits", ] +[[package]] +name = "hdwallet" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a03ba7d4c9ea41552cd4351965ff96883e629693ae85005c501bb4b9e1c48a7" +dependencies = [ + "lazy_static", + "rand_core 0.6.4", + "ring 0.16.20", + "secp256k1", + "thiserror", +] + [[package]] name = "heck" version = "0.3.3" @@ -1890,9 +1941,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http 1.1.0", @@ -1907,7 +1958,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -1980,7 +2031,7 @@ dependencies = [ "futures-util", "h2 0.4.5", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "httparse", "httpdate", "itoa", @@ -2027,7 +2078,7 @@ dependencies = [ "futures-channel", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "hyper 1.4.1", "pin-project-lite", "socket2", @@ -2098,9 +2149,9 @@ dependencies = [ [[package]] name = "incrementalmerkletree" -version = "0.6.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75346da3bd8e3d8891d02508245ed2df34447ca6637e343829f8d08986e9cde2" +checksum = "eb1872810fb725b06b8c153dde9e86f3ec26747b9b60096da7a869883b549cbe" dependencies = [ "either", ] @@ -2216,9 +2267,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -2255,9 +2306,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] @@ -2357,6 +2408,20 @@ dependencies = [ "subtle", ] +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + [[package]] name = "known-folders" version = "1.1.0" @@ -2372,7 +2437,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin", + "spin 0.9.8", ] [[package]] @@ -2401,12 +2466,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if 1.0.0", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -2498,9 +2563,9 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lz4-sys" -version = "1.9.5" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9764018d143cc854c9f17f0b907de70f14393b1f502da6375dce70f00514eb3" +checksum = "109de74d5d2353660401699a4174a4ff23fcc649caf553df71933c7fb45ad868" dependencies = [ "cc", "libc", @@ -2696,9 +2761,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -2781,9 +2846,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "opaque-debug" @@ -2799,9 +2864,8 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "orchard" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc7bde644aeb980be296cd908c6650894dc8541deb56f9f5294c52ed7ca568f" +version = "0.8.0" +source = "git+https://github.com/QED-it/orchard?branch=zsa1#3ba9e5b8d208bb44222cb2fe8bcd603c71abf444" dependencies = [ "aes", "bitvec", @@ -2809,10 +2873,12 @@ dependencies = [ "ff", "fpe", "group", + "half", "halo2_gadgets", "halo2_proofs", "hex", "incrementalmerkletree", + "k256", "lazy_static", "memuse", "nonempty", @@ -2822,7 +2888,6 @@ dependencies = [ "serde", "subtle", "tracing", - "visibility", "zcash_note_encryption", "zcash_spec", "zip32", @@ -2945,9 +3010,20 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "password-hash" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", ] [[package]] @@ -2965,6 +3041,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "pbkdf2" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" +dependencies = [ + "digest", + "password-hash", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2973,9 +3059,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" dependencies = [ "memchr", "thiserror", @@ -2984,9 +3070,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" dependencies = [ "pest", "pest_generator", @@ -2994,9 +3080,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" dependencies = [ "pest", "pest_meta", @@ -3007,9 +3093,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" dependencies = [ "once_cell", "pest", @@ -3115,9 +3201,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" [[package]] name = "powerfmt" @@ -3127,9 +3213,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "prettyplease" @@ -3234,6 +3323,16 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "prost" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +dependencies = [ + "bytes", + "prost-derive 0.12.6", +] + [[package]] name = "prost" version = "0.13.1" @@ -3241,7 +3340,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.13.1", +] + +[[package]] +name = "prost-build" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" +dependencies = [ + "bytes", + "heck 0.5.0", + "itertools 0.12.1", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost 0.12.6", + "prost-types 0.12.6", + "regex", + "syn 2.0.72", + "tempfile", ] [[package]] @@ -3258,13 +3378,26 @@ dependencies = [ "once_cell", "petgraph", "prettyplease", - "prost", - "prost-types", + "prost 0.13.1", + "prost-types 0.13.1", "regex", "syn 2.0.72", "tempfile", ] +[[package]] +name = "prost-derive" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +dependencies = [ + "anyhow", + "itertools 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "prost-derive" version = "0.13.1" @@ -3278,13 +3411,22 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "prost-types" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" +dependencies = [ + "prost 0.12.6", +] + [[package]] name = "prost-types" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cee5168b05f49d4b0ca581206eb14a7b22fafd963efe729ac48eb03266e25cc2" dependencies = [ - "prost", + "prost 0.13.1", ] [[package]] @@ -3437,9 +3579,9 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.0.2" +version = "11.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd" +checksum = "cb9ee317cfe3fbd54b36a511efc1edd42e216903c9cd575e686dd68a2ba90d8d" dependencies = [ "bitflags 2.6.0", ] @@ -3506,9 +3648,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags 2.6.0", ] @@ -3611,15 +3753,40 @@ dependencies = [ "winreg", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "rgb" -version = "0.8.37" +version = "0.8.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" +checksum = "e12bc8d2f72df26a5d3178022df33720fbede0d31d82c7291662eff89836994d" dependencies = [ "bytemuck", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + [[package]] name = "ring" version = "0.17.8" @@ -3630,8 +3797,8 @@ dependencies = [ "cfg-if 1.0.0", "getrandom 0.2.15", "libc", - "spin", - "untrusted", + "spin 0.9.8", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -3730,7 +3897,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring", + "ring 0.17.8", "rustls-webpki", "sct", ] @@ -3750,8 +3917,8 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring", - "untrusted", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] @@ -3789,9 +3956,8 @@ dependencies = [ [[package]] name = "sapling-crypto" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e379398fffad84e49f9a45a05635fc004f66086e65942dbf4eb95332c26d2a" +version = "0.1.3" +source = "git+https://github.com/QED-it/sapling-crypto?branch=zsa1#99ad0a5f0bdef332bdc91d577086abd3aca59553" dependencies = [ "aes", "bellman", @@ -3831,27 +3997,32 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring", - "untrusted", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] -name = "secp256k1" -version = "0.26.0" +name = "sec1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4124a35fe33ae14259c490fd70fa199a32b9ce9502f2ee6bc4f81ec06fa65894" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "secp256k1-sys", - "serde", + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", ] [[package]] name = "secp256k1" -version = "0.27.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +checksum = "4124a35fe33ae14259c490fd70fa199a32b9ce9502f2ee6bc4f81ec06fa65894" dependencies = [ "secp256k1-sys", + "serde", ] [[package]] @@ -4092,7 +4263,7 @@ version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ - "darling 0.20.9", + "darling 0.20.10", "proc-macro2", "quote", "syn 2.0.72", @@ -4135,9 +4306,9 @@ dependencies = [ [[package]] name = "shardtree" -version = "0.4.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78222845cd8bbe5eb95687407648ff17693a35de5e8abaa39a4681fb21e033f9" +checksum = "3b3cdd24424ce0b381646737fedddc33c4dcf7dcd2d545056b53f7982097bef5" dependencies = [ "bitflags 2.6.0", "either", @@ -4166,14 +4337,15 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ + "digest", "rand_core 0.6.4", ] [[package]] name = "similar" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" [[package]] name = "sketches-ddsketch" @@ -4228,6 +4400,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" @@ -4672,14 +4850,14 @@ dependencies = [ "bytes", "h2 0.4.5", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "hyper 1.4.1", "hyper-timeout", "hyper-util", "percent-encoding", "pin-project", - "prost", + "prost 0.13.1", "socket2", "tokio", "tokio-stream", @@ -4689,6 +4867,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic-build" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d021fc044c18582b9a2408cd0dd05b1596e3ecdb5c4df822bb0183545683889" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build 0.12.6", + "quote", + "syn 2.0.72", +] + [[package]] name = "tonic-build" version = "0.12.1" @@ -4697,7 +4888,7 @@ checksum = "568392c5a2bd0020723e3f387891176aabafe36fd9fcd074ad309dfa0c8eb964" dependencies = [ "prettyplease", "proc-macro2", - "prost-build", + "prost-build 0.13.1", "quote", "syn 2.0.72", ] @@ -4708,8 +4899,8 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b742c83ad673e9ab5b4ce0981f7b9e8932be9d60e8682cbf9120494764dbc173" dependencies = [ - "prost", - "prost-types", + "prost 0.13.1", + "prost-types 0.13.1", "tokio", "tokio-stream", "tonic", @@ -5048,6 +5239,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -5089,9 +5286,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.9.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "serde", ] @@ -5136,17 +5333,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "visibility" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - [[package]] name = "void" version = "1.0.2" @@ -5355,11 +5541,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5375,7 +5561,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ "windows-core", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -5384,7 +5570,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -5402,7 +5588,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -5422,18 +5617,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -5444,9 +5639,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -5456,9 +5651,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -5468,15 +5663,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -5486,9 +5681,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -5498,9 +5693,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -5510,9 +5705,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -5522,9 +5717,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -5583,86 +5778,20 @@ checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" [[package]] name = "zcash_address" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6d26f21381dc220836dd8d2a9a10dbe85928a26232b011bc6a42b611789b743" -dependencies = [ - "bech32", - "bs58", - "f4jumble 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_encoding 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_protocol 0.2.0", -] - -[[package]] -name = "zcash_address" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14bccd6cefb76f87b6d15a9e7b02b6c0515648c6de8e806c4e2d6f0f6ae640c5" -dependencies = [ - "bech32", - "bs58", - "f4jumble 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_encoding 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_protocol 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zcash_address" -version = "0.5.0" -source = "git+https://github.com/zcash/librustzcash/#a1047adf0b6f324dad415db34762dc26f8367ce4" -dependencies = [ - "bech32", - "bs58", - "f4jumble 0.1.0 (git+https://github.com/zcash/librustzcash/)", - "zcash_encoding 0.2.1 (git+https://github.com/zcash/librustzcash/)", - "zcash_protocol 0.3.0 (git+https://github.com/zcash/librustzcash/)", -] - -[[package]] -name = "zcash_client_backend" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e3a0f3e5d7f299d8b7ef3237697630989c31ab1b162824c99c1cd8bc83715e" +version = "0.3.2" +source = "git+https://github.com/QED-it/librustzcash?branch=txv6-separate-bundles-rebased-dd2#8149034c53c9a33b5ca417689c42ec4d47d0eff5" dependencies = [ - "base64 0.21.7", "bech32", - "bls12_381", "bs58", - "crossbeam-channel", - "document-features", - "group", - "hex", - "incrementalmerkletree", - "memuse", - "nom", - "nonempty", - "percent-encoding", - "prost", - "rand_core 0.6.4", - "rayon", - "sapling-crypto", - "secrecy", - "shardtree", - "subtle", - "time", - "tonic-build", - "tracing", - "which", - "zcash_address 0.4.0", - "zcash_encoding 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_keys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_note_encryption", - "zcash_primitives 0.16.0", - "zcash_protocol 0.2.0", - "zip32", - "zip321 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "f4jumble", + "zcash_encoding", + "zcash_protocol", ] [[package]] name = "zcash_client_backend" -version = "0.13.0" -source = "git+https://github.com/zcash/librustzcash/#a1047adf0b6f324dad415db34762dc26f8367ce4" +version = "0.12.1" +source = "git+https://github.com/QED-it/librustzcash?branch=txv6-separate-bundles-rebased-dd2#8149034c53c9a33b5ca417689c42ec4d47d0eff5" dependencies = [ "base64 0.21.7", "bech32", @@ -5677,7 +5806,7 @@ dependencies = [ "nom", "nonempty", "percent-encoding", - "prost", + "prost 0.12.6", "rand_core 0.6.4", "rayon", "sapling-crypto", @@ -5685,33 +5814,23 @@ dependencies = [ "shardtree", "subtle", "time", - "tonic-build", + "tonic-build 0.10.2", "tracing", "which", - "zcash_address 0.5.0 (git+https://github.com/zcash/librustzcash/)", - "zcash_encoding 0.2.1 (git+https://github.com/zcash/librustzcash/)", - "zcash_keys 0.3.0 (git+https://github.com/zcash/librustzcash/)", + "zcash_address", + "zcash_encoding", + "zcash_keys", "zcash_note_encryption", - "zcash_primitives 0.17.0 (git+https://github.com/zcash/librustzcash/)", - "zcash_protocol 0.3.0 (git+https://github.com/zcash/librustzcash/)", + "zcash_primitives", + "zcash_protocol", "zip32", - "zip321 0.1.0 (git+https://github.com/zcash/librustzcash/)", -] - -[[package]] -name = "zcash_encoding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052d8230202f0a018cd9b5d1b56b94cd25e18eccc2d8665073bcea8261ab87fc" -dependencies = [ - "byteorder", - "nonempty", + "zip321", ] [[package]] name = "zcash_encoding" -version = "0.2.1" -source = "git+https://github.com/zcash/librustzcash/#a1047adf0b6f324dad415db34762dc26f8367ce4" +version = "0.2.0" +source = "git+https://github.com/QED-it/librustzcash?branch=txv6-separate-bundles-rebased-dd2#8149034c53c9a33b5ca417689c42ec4d47d0eff5" dependencies = [ "byteorder", "nonempty", @@ -5720,8 +5839,7 @@ dependencies = [ [[package]] name = "zcash_history" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fde17bf53792f9c756b313730da14880257d7661b5bfc69d0571c3a7c11a76d" +source = "git+https://github.com/QED-it/librustzcash?branch=txv6-separate-bundles-rebased-dd2#8149034c53c9a33b5ca417689c42ec4d47d0eff5" dependencies = [ "blake2b_simd", "byteorder", @@ -5730,34 +5848,8 @@ dependencies = [ [[package]] name = "zcash_keys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712faf4070107ab0b2828d0eda6aeaf4c3cb02564109832d95b97ad3467c95a5" -dependencies = [ - "bech32", - "blake2b_simd", - "bls12_381", - "bs58", - "document-features", - "group", - "memuse", - "nonempty", - "rand_core 0.6.4", - "sapling-crypto", - "secrecy", - "subtle", - "tracing", - "zcash_address 0.4.0", - "zcash_encoding 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_primitives 0.16.0", - "zcash_protocol 0.2.0", - "zip32", -] - -[[package]] -name = "zcash_keys" -version = "0.3.0" -source = "git+https://github.com/zcash/librustzcash/#a1047adf0b6f324dad415db34762dc26f8367ce4" +version = "0.2.0" +source = "git+https://github.com/QED-it/librustzcash?branch=txv6-separate-bundles-rebased-dd2#8149034c53c9a33b5ca417689c42ec4d47d0eff5" dependencies = [ "bech32", "blake2b_simd", @@ -5772,18 +5864,17 @@ dependencies = [ "secrecy", "subtle", "tracing", - "zcash_address 0.5.0 (git+https://github.com/zcash/librustzcash/)", - "zcash_encoding 0.2.1 (git+https://github.com/zcash/librustzcash/)", - "zcash_primitives 0.17.0 (git+https://github.com/zcash/librustzcash/)", - "zcash_protocol 0.3.0 (git+https://github.com/zcash/librustzcash/)", + "zcash_address", + "zcash_encoding", + "zcash_primitives", + "zcash_protocol", "zip32", ] [[package]] name = "zcash_note_encryption" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b4580cd6cee12e44421dac43169be8d23791650816bdb34e6ddfa70ac89c1c5" +source = "git+https://github.com/QED-it/zcash_note_encryption?branch=zsa1#76745f00551d4442dee11ad64a8400b75132d18f" dependencies = [ "chacha20", "chacha20poly1305", @@ -5794,56 +5885,19 @@ dependencies = [ [[package]] name = "zcash_primitives" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f044bc9cf2887ec408196fbafb44749e5581f57cc18d8da7aabaeb60cc40c64" +version = "0.15.0" +source = "git+https://github.com/QED-it/librustzcash?branch=txv6-separate-bundles-rebased-dd2#8149034c53c9a33b5ca417689c42ec4d47d0eff5" dependencies = [ "aes", + "bip0039", "blake2b_simd", - "bs58", "byteorder", "document-features", - "equihash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ff", - "fpe", - "group", - "hex", - "incrementalmerkletree", - "jubjub", - "memuse", - "nonempty", - "orchard", - "rand 0.8.5", - "rand_core 0.6.4", - "redjubjub", - "sapling-crypto", - "sha2", - "subtle", - "tracing", - "zcash_address 0.4.0", - "zcash_encoding 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_note_encryption", - "zcash_protocol 0.2.0", - "zcash_spec", - "zip32", -] - -[[package]] -name = "zcash_primitives" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d87ab6a55591a8cf1866749fdc739ae1bbd06e6cec07ab0bbe5d57ee3390eb2" -dependencies = [ - "aes", - "bip32", - "blake2b_simd", - "bs58", - "byteorder", - "document-features", - "equihash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "equihash 0.2.0 (git+https://github.com/QED-it/librustzcash?branch=txv6-separate-bundles-rebased-dd2)", "ff", "fpe", "group", + "hdwallet", "hex", "incrementalmerkletree", "jubjub", @@ -5855,58 +5909,23 @@ dependencies = [ "redjubjub", "ripemd", "sapling-crypto", - "secp256k1 0.27.0", + "secp256k1", "sha2", "subtle", "tracing", - "zcash_address 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_encoding 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "zcash_address", + "zcash_encoding", "zcash_note_encryption", - "zcash_protocol 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_spec", - "zip32", -] - -[[package]] -name = "zcash_primitives" -version = "0.17.0" -source = "git+https://github.com/zcash/librustzcash/#a1047adf0b6f324dad415db34762dc26f8367ce4" -dependencies = [ - "aes", - "blake2b_simd", - "bs58", - "byteorder", - "document-features", - "equihash 0.2.0 (git+https://github.com/zcash/librustzcash/)", - "ff", - "fpe", - "group", - "hex", - "incrementalmerkletree", - "jubjub", - "memuse", - "nonempty", - "orchard", - "rand 0.8.5", - "rand_core 0.6.4", - "redjubjub", - "sapling-crypto", - "sha2", - "subtle", - "tracing", - "zcash_address 0.5.0 (git+https://github.com/zcash/librustzcash/)", - "zcash_encoding 0.2.1 (git+https://github.com/zcash/librustzcash/)", - "zcash_note_encryption", - "zcash_protocol 0.3.0 (git+https://github.com/zcash/librustzcash/)", + "zcash_protocol", "zcash_spec", "zip32", ] [[package]] name = "zcash_proofs" -version = "0.17.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9fc0032b3d90f000f50dba7a996ad6556b7dba5b5145f93ab67b6eb74d3a48" +checksum = "5163a1110f4265cc5f2fdf87ac4497fd1e014b6ce0760ca8d16d8e3853a5c0f7" dependencies = [ "bellman", "blake2b_simd", @@ -5922,33 +5941,13 @@ dependencies = [ "sapling-crypto", "tracing", "xdg", - "zcash_primitives 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zcash_protocol" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f35eac659fdbba614333d119217c5963c0d7cea43aee33176c4f2f95e5460d8d" -dependencies = [ - "document-features", - "memuse", -] - -[[package]] -name = "zcash_protocol" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1ff002bd41ba76b42d42a02ee11de06790b7fdbc904bdea4486b9a93b2a5e4" -dependencies = [ - "document-features", - "memuse", + "zcash_primitives", ] [[package]] name = "zcash_protocol" -version = "0.3.0" -source = "git+https://github.com/zcash/librustzcash/#a1047adf0b6f324dad415db34762dc26f8367ce4" +version = "0.1.1" +source = "git+https://github.com/QED-it/librustzcash?branch=txv6-separate-bundles-rebased-dd2#8149034c53c9a33b5ca417689c42ec4d47d0eff5" dependencies = [ "document-features", "memuse", @@ -6000,6 +5999,7 @@ dependencies = [ "itertools 0.13.0", "jubjub", "lazy_static", + "nonempty", "num-integer", "orchard", "primitive-types", @@ -6013,7 +6013,7 @@ dependencies = [ "redjubjub", "ripemd", "sapling-crypto", - "secp256k1 0.26.0", + "secp256k1", "serde", "serde-big-array", "serde_json", @@ -6028,13 +6028,13 @@ dependencies = [ "tracing", "uint", "x25519-dalek", - "zcash_address 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_client_backend 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_encoding 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "zcash_address", + "zcash_client_backend", + "zcash_encoding", "zcash_history", "zcash_note_encryption", - "zcash_primitives 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_protocol 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zcash_primitives", + "zcash_protocol", "zebra-test", ] @@ -6091,15 +6091,15 @@ dependencies = [ "color-eyre", "futures-util", "insta", - "prost", + "prost 0.13.1", "serde", "tokio", "tokio-stream", "tonic", - "tonic-build", + "tonic-build 0.12.1", "tonic-reflection", "tower", - "zcash_primitives 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zcash_primitives", "zebra-chain", "zebra-node-services", "zebra-state", @@ -6174,7 +6174,7 @@ dependencies = [ "jsonrpc-http-server", "nix", "proptest", - "prost", + "prost 0.13.1", "rand 0.8.5", "serde", "serde_json", @@ -6182,12 +6182,12 @@ dependencies = [ "tokio", "tokio-stream", "tonic", - "tonic-build", + "tonic-build 0.12.1", "tonic-reflection", "tower", "tracing", - "zcash_address 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_primitives 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zcash_address", + "zcash_primitives", "zebra-chain", "zebra-consensus", "zebra-network", @@ -6229,11 +6229,11 @@ dependencies = [ "tower", "tracing", "tracing-subscriber", - "zcash_address 0.5.0 (git+https://github.com/zcash/librustzcash/)", - "zcash_client_backend 0.13.0 (git+https://github.com/zcash/librustzcash/)", - "zcash_keys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zcash_address", + "zcash_client_backend", + "zcash_keys", "zcash_note_encryption", - "zcash_primitives 0.17.0 (git+https://github.com/zcash/librustzcash/)", + "zcash_primitives", "zebra-chain", "zebra-grpc", "zebra-node-services", @@ -6351,9 +6351,9 @@ dependencies = [ "tokio", "tracing-error", "tracing-subscriber", - "zcash_client_backend 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_primitives 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_protocol 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zcash_client_backend", + "zcash_primitives", + "zcash_protocol", "zebra-chain", "zebra-node-services", "zebra-rpc", @@ -6393,7 +6393,7 @@ dependencies = [ "pin-project", "proptest", "proptest-derive", - "prost", + "prost 0.13.1", "rand 0.8.5", "rayon", "regex", @@ -6409,7 +6409,7 @@ dependencies = [ "tokio-stream", "toml 0.8.19", "tonic", - "tonic-build", + "tonic-build 0.12.1", "tower", "tracing", "tracing-appender", @@ -6433,18 +6433,19 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", @@ -6484,25 +6485,12 @@ dependencies = [ [[package]] name = "zip321" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dc85f862f7be64fb0d46f9eb5b82ad54e58cde314fa979d5bae591bc0143693" -dependencies = [ - "base64 0.21.7", - "nom", - "percent-encoding", - "zcash_address 0.4.0", - "zcash_protocol 0.2.0", -] - -[[package]] -name = "zip321" -version = "0.1.0" -source = "git+https://github.com/zcash/librustzcash/#a1047adf0b6f324dad415db34762dc26f8367ce4" +version = "0.0.0" +source = "git+https://github.com/QED-it/librustzcash?branch=txv6-separate-bundles-rebased-dd2#8149034c53c9a33b5ca417689c42ec4d47d0eff5" dependencies = [ "base64 0.21.7", "nom", "percent-encoding", - "zcash_address 0.5.0 (git+https://github.com/zcash/librustzcash/)", - "zcash_protocol 0.3.0 (git+https://github.com/zcash/librustzcash/)", + "zcash_address", + "zcash_protocol", ] diff --git a/Cargo.toml b/Cargo.toml index a006d6eb8a6..ea9d38d197f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,17 +22,17 @@ resolver = "2" # `cargo release` settings [workspace.dependencies] -incrementalmerkletree = "0.6.0" -orchard = "0.9.0" -sapling-crypto = "0.2.0" -zcash_address = "0.5.0" -zcash_client_backend = "0.13.0" -zcash_encoding = "0.2.1" +incrementalmerkletree = "0.5.1" +orchard = "0.8.0" +sapling-crypto = "0.1.3" +zcash_address = "0.3.2" +zcash_client_backend = "0.12.1" +zcash_encoding = "0.2.0" zcash_history = "0.4.0" -zcash_keys = "0.3.0" -zcash_primitives = "0.17.0" -zcash_proofs = "0.17.0" -zcash_protocol = "0.3.0" +zcash_keys = "0.2.0" +zcash_primitives = "0.15.0" +zcash_proofs = "0.15.0" +zcash_protocol = "0.1.1" [workspace.metadata.release] @@ -102,3 +102,16 @@ panic = "abort" # - add "-flto=thin" to all C/C++ code builds # - see https://doc.rust-lang.org/rustc/linker-plugin-lto.html#cc-code-as-a-dependency-in-rust lto = "thin" + +[patch.crates-io] +halo2_proofs = { version = "0.3.0", git = "https://github.com/QED-it/halo2", branch = "zsa1" } +zcash_note_encryption = { version = "0.4.0", git = "https://github.com/QED-it/zcash_note_encryption", branch = "zsa1" } +sapling-crypto = { version = "0.1.3", git = "https://github.com/QED-it/sapling-crypto", branch = "zsa1" } +orchard = { version = "0.8.0", git = "https://github.com/QED-it/orchard", branch = "zsa1" } +zcash_primitives = { version = "0.15.0", git = "https://github.com/QED-it/librustzcash", branch = "txv6-separate-bundles-rebased-dd2" } +zcash_protocol = { version = "0.1.1", git = "https://github.com/QED-it/librustzcash", branch = "txv6-separate-bundles-rebased-dd2" } +zcash_address = { version = "0.3.2", git = "https://github.com/QED-it/librustzcash", branch = "txv6-separate-bundles-rebased-dd2" } +zcash_encoding = { version = "0.2.0", git = "https://github.com/QED-it/librustzcash", branch = "txv6-separate-bundles-rebased-dd2" } +zcash_history = { version = "0.4.0", git = "https://github.com/QED-it/librustzcash", branch = "txv6-separate-bundles-rebased-dd2" } +zcash_client_backend = { version = "0.12.1", git = "https://github.com/QED-it/librustzcash", branch = "txv6-separate-bundles-rebased-dd2" } +zcash_keys = { version = "0.2.0", git = "https://github.com/QED-it/librustzcash", branch = "txv6-separate-bundles-rebased-dd2" } diff --git a/zebra-chain/Cargo.toml b/zebra-chain/Cargo.toml index a6ec5c1f342..5e539fddba5 100644 --- a/zebra-chain/Cargo.toml +++ b/zebra-chain/Cargo.toml @@ -16,6 +16,7 @@ categories = ["asynchronous", "cryptography::cryptocurrencies", "encoding"] [features] default = [] +#default = ["tx-v6"] # Production features that activate extra functionality @@ -60,6 +61,11 @@ proptest-impl = [ bench = ["zebra-test"] +# Support for transaction version 6 +tx-v6 = [ + "nonempty" +] + [dependencies] # Cryptography @@ -68,7 +74,7 @@ bitflags = "2.5.0" bitflags-serde-legacy = "0.1.1" blake2b_simd = "1.0.2" blake2s_simd = "1.0.2" -bridgetree = "0.5.0" +bridgetree = "0.4.0" bs58 = { version = "0.5.1", features = ["check"] } byteorder = "1.5.0" @@ -104,6 +110,9 @@ sapling-crypto.workspace = true zcash_protocol.workspace = true zcash_address.workspace = true +# Used for orchard serialization +nonempty = { version = "0.7", optional = true } + # Time chrono = { version = "0.4.38", default-features = false, features = ["clock", "std", "serde"] } humantime = "2.1.0" @@ -178,3 +187,7 @@ required-features = ["bench"] [[bench]] name = "redpallas" harness = false + +# FIXME: remove this and all zcash_unstable usage in the code after updating librustzcash +#[lints.rust] +#unexpected_cfgs = { level = "warn", check-cfg = ['cfg(zcash_unstable, values("nu6"))'] } diff --git a/zebra-chain/src/lib.rs b/zebra-chain/src/lib.rs index 460d3a850f0..dd6fa1a1abf 100644 --- a/zebra-chain/src/lib.rs +++ b/zebra-chain/src/lib.rs @@ -41,6 +41,9 @@ pub mod transparent; pub mod value_balance; pub mod work; +#[cfg(feature = "tx-v6")] +pub mod orchard_zsa; + #[cfg(any(test, feature = "proptest-impl"))] pub use block::LedgerState; diff --git a/zebra-chain/src/orchard.rs b/zebra-chain/src/orchard.rs index be96644c8c9..3141b6a1154 100644 --- a/zebra-chain/src/orchard.rs +++ b/zebra-chain/src/orchard.rs @@ -6,6 +6,7 @@ mod action; mod address; mod commitment; mod note; +mod orchard_flavor_ext; mod sinsemilla; #[cfg(any(test, feature = "proptest-impl"))] @@ -22,4 +23,13 @@ pub use address::Address; pub use commitment::{CommitmentRandomness, NoteCommitment, ValueCommitment}; pub use keys::Diversifier; pub use note::{EncryptedNote, Note, Nullifier, WrappedNoteKey}; +pub use orchard_flavor_ext::{OrchardFlavorExt, OrchardVanilla}; pub use shielded_data::{AuthorizedAction, Flags, ShieldedData}; + +pub(crate) use shielded_data::ActionCommon; + +#[cfg(feature = "tx-v6")] +pub use orchard_flavor_ext::OrchardZSA; + +#[cfg(feature = "tx-v6")] +pub(crate) use crate::orchard_zsa::issuance::IssueData; diff --git a/zebra-chain/src/orchard/action.rs b/zebra-chain/src/orchard/action.rs index ae7690def7a..4f256408f11 100644 --- a/zebra-chain/src/orchard/action.rs +++ b/zebra-chain/src/orchard/action.rs @@ -11,6 +11,7 @@ use super::{ commitment::{self, ValueCommitment}, keys, note::{self, Nullifier}, + OrchardFlavorExt, }; /// An Action description, as described in the [Zcash specification §7.3][actiondesc]. @@ -21,7 +22,7 @@ use super::{ /// /// [actiondesc]: https://zips.z.cash/protocol/nu5.pdf#actiondesc #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct Action { +pub struct Action { /// A value commitment to net value of the input note minus the output note pub cv: commitment::ValueCommitment, /// The nullifier of the input note being spent. @@ -35,14 +36,14 @@ pub struct Action { /// encrypted private key in `out_ciphertext`. pub ephemeral_key: keys::EphemeralPublicKey, /// A ciphertext component for the encrypted output note. - pub enc_ciphertext: note::EncryptedNote, + pub enc_ciphertext: V::EncryptedNote, /// A ciphertext component that allows the holder of a full viewing key to /// recover the recipient diversified transmission key and the ephemeral /// private key (and therefore the entire note plaintext). pub out_ciphertext: note::WrappedNoteKey, } -impl ZcashSerialize for Action { +impl ZcashSerialize for Action { fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { self.cv.zcash_serialize(&mut writer)?; writer.write_all(&<[u8; 32]>::from(self.nullifier)[..])?; @@ -55,7 +56,7 @@ impl ZcashSerialize for Action { } } -impl ZcashDeserialize for Action { +impl ZcashDeserialize for Action { fn zcash_deserialize(mut reader: R) -> Result { // # Consensus // @@ -93,7 +94,8 @@ impl ZcashDeserialize for Action { // https://zips.z.cash/protocol/protocol.pdf#concretesym but fixed to // 580 bytes in https://zips.z.cash/protocol/protocol.pdf#outputencodingandconsensus // See [`note::EncryptedNote::zcash_deserialize`]. - enc_ciphertext: note::EncryptedNote::zcash_deserialize(&mut reader)?, + // FIXME: don't mention about 580 here as this should work for OrchardZSA too? + enc_ciphertext: V::EncryptedNote::zcash_deserialize(&mut reader)?, // Type is `Sym.C`, i.e. `𝔹^Y^{\[N\]}`, i.e. arbitrary-sized byte arrays // https://zips.z.cash/protocol/protocol.pdf#concretesym but fixed to // 80 bytes in https://zips.z.cash/protocol/protocol.pdf#outputencodingandconsensus diff --git a/zebra-chain/src/orchard/arbitrary.rs b/zebra-chain/src/orchard/arbitrary.rs index 7a6544606f8..54572085f11 100644 --- a/zebra-chain/src/orchard/arbitrary.rs +++ b/zebra-chain/src/orchard/arbitrary.rs @@ -10,17 +10,18 @@ use reddsa::{orchard::SpendAuth, Signature, SigningKey, VerificationKey, Verific use proptest::{array, collection::vec, prelude::*}; use super::{ - keys::*, note, tree, Action, AuthorizedAction, Flags, NoteCommitment, ValueCommitment, + keys::*, note, tree, Action, AuthorizedAction, Flags, NoteCommitment, OrchardFlavorExt, + OrchardVanilla, ValueCommitment, }; -impl Arbitrary for Action { +impl Arbitrary for Action { type Parameters = (); fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { ( any::(), any::(), - any::(), + any::>(), any::(), ) .prop_map(|(nullifier, rk, enc_ciphertext, out_ciphertext)| Self { @@ -54,11 +55,11 @@ impl Arbitrary for note::Nullifier { type Strategy = BoxedStrategy; } -impl Arbitrary for AuthorizedAction { +impl Arbitrary for AuthorizedAction { type Parameters = (); fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - (any::(), any::()) + (any::>(), any::()) .prop_map(|(action, spend_auth_sig)| Self { action, spend_auth_sig: spend_auth_sig.0, diff --git a/zebra-chain/src/orchard/note/arbitrary.rs b/zebra-chain/src/orchard/note/arbitrary.rs index e9365de80c1..7968877d9bd 100644 --- a/zebra-chain/src/orchard/note/arbitrary.rs +++ b/zebra-chain/src/orchard/note/arbitrary.rs @@ -2,13 +2,13 @@ use proptest::{collection::vec, prelude::*}; use super::*; -impl Arbitrary for EncryptedNote { +impl Arbitrary for EncryptedNote { type Parameters = (); fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - (vec(any::(), 580)) + (vec(any::(), N)) .prop_map(|v| { - let mut bytes = [0; 580]; + let mut bytes = [0; N]; bytes.copy_from_slice(v.as_slice()); Self(bytes) }) diff --git a/zebra-chain/src/orchard/note/ciphertexts.rs b/zebra-chain/src/orchard/note/ciphertexts.rs index 8f857cf1444..68f92dc667d 100644 --- a/zebra-chain/src/orchard/note/ciphertexts.rs +++ b/zebra-chain/src/orchard/note/ciphertexts.rs @@ -10,20 +10,20 @@ use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize} /// /// Corresponds to the Orchard 'encCiphertext's #[derive(Deserialize, Serialize)] -pub struct EncryptedNote(#[serde(with = "BigArray")] pub(crate) [u8; 580]); +pub struct EncryptedNote(#[serde(with = "BigArray")] pub(crate) [u8; N]); // These impls all only exist because of array length restrictions. // TODO: use const generics https://github.com/ZcashFoundation/zebra/issues/2042 -impl Copy for EncryptedNote {} +impl Copy for EncryptedNote {} -impl Clone for EncryptedNote { +impl Clone for EncryptedNote { fn clone(&self) -> Self { *self } } -impl fmt::Debug for EncryptedNote { +impl fmt::Debug for EncryptedNote { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("EncryptedNote") .field(&hex::encode(&self.0[..])) @@ -31,36 +31,36 @@ impl fmt::Debug for EncryptedNote { } } -impl Eq for EncryptedNote {} +impl Eq for EncryptedNote {} -impl From<[u8; 580]> for EncryptedNote { - fn from(bytes: [u8; 580]) -> Self { +impl From<[u8; N]> for EncryptedNote { + fn from(bytes: [u8; N]) -> Self { EncryptedNote(bytes) } } -impl From for [u8; 580] { - fn from(enc_ciphertext: EncryptedNote) -> Self { +impl From> for [u8; N] { + fn from(enc_ciphertext: EncryptedNote) -> Self { enc_ciphertext.0 } } -impl PartialEq for EncryptedNote { +impl PartialEq for EncryptedNote { fn eq(&self, other: &Self) -> bool { self.0[..] == other.0[..] } } -impl ZcashSerialize for EncryptedNote { +impl ZcashSerialize for EncryptedNote { fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { writer.write_all(&self.0[..])?; Ok(()) } } -impl ZcashDeserialize for EncryptedNote { +impl ZcashDeserialize for EncryptedNote { fn zcash_deserialize(mut reader: R) -> Result { - let mut bytes = [0; 580]; + let mut bytes = [0; N]; reader.read_exact(&mut bytes[..])?; Ok(Self(bytes)) } @@ -125,13 +125,16 @@ impl ZcashDeserialize for WrappedNoteKey { } } +#[cfg(test)] +use crate::orchard::OrchardFlavorExt; + #[cfg(test)] use proptest::prelude::*; #[cfg(test)] proptest! { #[test] - fn encrypted_ciphertext_roundtrip(ec in any::()) { + fn encrypted_ciphertext_roundtrip(ec in any::>()) { let _init_guard = zebra_test::init(); let mut data = Vec::new(); diff --git a/zebra-chain/src/orchard/orchard_flavor_ext.rs b/zebra-chain/src/orchard/orchard_flavor_ext.rs new file mode 100644 index 00000000000..f8ce25d0ed5 --- /dev/null +++ b/zebra-chain/src/orchard/orchard_flavor_ext.rs @@ -0,0 +1,84 @@ +//! This module defines traits and structures for supporting the Orchard Shielded Protocol +//! for `V5` and `V6` versions of the transaction. +use std::{fmt::Debug, io}; + +use serde::{de::DeserializeOwned, Serialize}; + +#[cfg(any(test, feature = "proptest-impl"))] +use proptest_derive::Arbitrary; + +use orchard::{note_encryption::OrchardDomainCommon, orchard_flavor}; + +use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}; + +use super::note; + +#[cfg(feature = "tx-v6")] +use crate::orchard_zsa::burn::BurnItem; + +/// A trait representing compile-time settings of Orchard Shielded Protocol used in +/// the transactions `V5` and `V6`. +pub trait OrchardFlavorExt: Clone + Debug { + /// A type representing an encrypted note for this protocol version. + /// A type representing an encrypted note for this protocol version. + type EncryptedNote: Clone + + Debug + + PartialEq + + Eq + + DeserializeOwned + + Serialize + + ZcashDeserialize + + ZcashSerialize; + + /// FIXME: add doc + type Flavor: orchard_flavor::OrchardFlavor; + + /// The size of the encrypted note for this protocol version. + const ENCRYPTED_NOTE_SIZE: usize = Self::Flavor::ENC_CIPHERTEXT_SIZE; + + /// A type representing a burn field for this protocol version. + type BurnType: Clone + Debug + Default + ZcashDeserialize + ZcashSerialize; +} + +/// A structure representing a tag for Orchard protocol variant used for the transaction version `V5`. +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] +pub struct OrchardVanilla; + +/// A structure representing a tag for Orchard protocol variant used for the transaction version `V6` +/// (which ZSA features support). +#[cfg(feature = "tx-v6")] +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] +pub struct OrchardZSA; + +/// A special marker type indicating the absence of a burn field in Orchard ShieldedData for `V5` transactions. +/// Useful for unifying ShieldedData serialization and deserialization implementations across various +/// Orchard protocol variants (i.e. various transaction versions). +#[derive(Default, Clone, Debug, PartialEq, Eq, Serialize)] +pub struct NoBurn; + +impl ZcashSerialize for NoBurn { + fn zcash_serialize(&self, mut _writer: W) -> Result<(), io::Error> { + Ok(()) + } +} + +impl ZcashDeserialize for NoBurn { + fn zcash_deserialize(mut _reader: R) -> Result { + Ok(Self) + } +} + +impl OrchardFlavorExt for OrchardVanilla { + type Flavor = orchard_flavor::OrchardVanilla; + type EncryptedNote = note::EncryptedNote<{ Self::ENCRYPTED_NOTE_SIZE }>; + type BurnType = NoBurn; +} + +#[cfg(feature = "tx-v6")] +impl OrchardFlavorExt for OrchardZSA { + type Flavor = orchard_flavor::OrchardZSA; + type EncryptedNote = note::EncryptedNote<{ Self::ENCRYPTED_NOTE_SIZE }>; + type BurnType = Vec; +} diff --git a/zebra-chain/src/orchard/shielded_data.rs b/zebra-chain/src/orchard/shielded_data.rs index 5347919cd01..baf98da8c42 100644 --- a/zebra-chain/src/orchard/shielded_data.rs +++ b/zebra-chain/src/orchard/shielded_data.rs @@ -20,9 +20,17 @@ use crate::{ }, }; +use super::OrchardFlavorExt; + +#[cfg(not(feature = "tx-v6"))] +use super::OrchardVanilla; + +#[cfg(feature = "tx-v6")] +use super::OrchardZSA; + /// A bundle of [`Action`] descriptions and signature data. #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct ShieldedData { +pub struct ShieldedData { /// The orchard flags for this transaction. /// Denoted as `flagsOrchard` in the spec. pub flags: Flags, @@ -37,13 +45,18 @@ pub struct ShieldedData { pub proof: Halo2Proof, /// The Orchard Actions, in the order they appear in the transaction. /// Denoted as `vActionsOrchard` and `vSpendAuthSigsOrchard` in the spec. - pub actions: AtLeastOne, + pub actions: AtLeastOne>, /// A signature on the transaction `sighash`. /// Denoted as `bindingSigOrchard` in the spec. pub binding_sig: Signature, + + #[cfg(feature = "tx-v6")] + /// Assets intended for burning + /// Denoted as `vAssetBurn` in the spec (ZIP 230). + pub burn: V::BurnType, } -impl fmt::Display for ShieldedData { +impl fmt::Display for ShieldedData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut fmter = f.debug_struct("orchard::ShieldedData"); @@ -59,13 +72,18 @@ impl fmt::Display for ShieldedData { } } -impl ShieldedData { +impl ShieldedData { /// Iterate over the [`Action`]s for the [`AuthorizedAction`]s in this /// transaction, in the order they appear in it. - pub fn actions(&self) -> impl Iterator { + pub fn actions(&self) -> impl Iterator> { self.actions.actions() } + /// FIXME: add a doc comment + pub fn action_commons(&self) -> impl Iterator + '_ { + self.actions.actions().map(|action| action.into()) + } + /// Collect the [`Nullifier`]s for this transaction. pub fn nullifiers(&self) -> impl Iterator { self.actions().map(|action| &action.nullifier) @@ -119,9 +137,9 @@ impl ShieldedData { } } -impl AtLeastOne { +impl AtLeastOne> { /// Iterate over the [`Action`]s of each [`AuthorizedAction`]. - pub fn actions(&self) -> impl Iterator { + pub fn actions(&self) -> impl Iterator> { self.iter() .map(|authorized_action| &authorized_action.action) } @@ -131,23 +149,64 @@ impl AtLeastOne { /// /// Every authorized Orchard `Action` must have a corresponding `SpendAuth` signature. #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct AuthorizedAction { +pub struct AuthorizedAction { /// The action description of this Action. - pub action: Action, + pub action: Action, /// The spend signature. pub spend_auth_sig: Signature, } -impl AuthorizedAction { +impl AuthorizedAction { + /// The size of a single Action + /// + /// Actions are 5 * 32 + ENCRYPTED_NOTE_SIZE + 80 bytes so the total size of each Action is 820 bytes. + /// [7.5 Action Description Encoding and Consensus][ps] + /// + /// [ps]: + pub const ACTION_SIZE: u64 = 5 * 32 + (V::ENCRYPTED_NOTE_SIZE as u64) + 80; + + /// The size of a single `Signature`. + /// + /// Each Signature is 64 bytes. + /// [7.1 Transaction Encoding and Consensus][ps] + /// + /// [ps]: + pub const SPEND_AUTH_SIG_SIZE: u64 = 64; + + /// The size of a single AuthorizedAction + /// + /// Each serialized `Action` has a corresponding `Signature`. + pub const AUTHORIZED_ACTION_SIZE: u64 = Self::ACTION_SIZE + Self::SPEND_AUTH_SIG_SIZE; + + /// The maximum number of actions in the transaction. + // Since a serialized Vec uses at least one byte for its length, + // and the signature is required, + // a valid max allocation can never exceed this size + pub const ACTION_MAX_ALLOCATION: u64 = (MAX_BLOCK_BYTES - 1) / Self::AUTHORIZED_ACTION_SIZE; + + // To be but we ensure ACTION_MAX_ALLOCATION is less than 2^16 on compile time + // (this is a workaround, as static_assertions::const_assert! doesn't work for generics, + // see TrustedPreallocate for Action) + const _ACTION_MAX_ALLOCATION_OK: u64 = (1 << 16) - Self::ACTION_MAX_ALLOCATION; + /* FIXME: remove this + const ACTION_MAX_ALLOCATION_OK: () = assert!( + Self::ACTION_MAX_ALLOCATION < 1, //(1 << 16), + "must be less than 2^16" + ); + */ + /// Split out the action and the signature for V5 transaction /// serialization. - pub fn into_parts(self) -> (Action, Signature) { + pub fn into_parts(self) -> (Action, Signature) { (self.action, self.spend_auth_sig) } // Combine the action and the spend auth sig from V5 transaction /// deserialization. - pub fn from_parts(action: Action, spend_auth_sig: Signature) -> AuthorizedAction { + pub fn from_parts( + action: Action, + spend_auth_sig: Signature, + ) -> AuthorizedAction { AuthorizedAction { action, spend_auth_sig, @@ -155,38 +214,48 @@ impl AuthorizedAction { } } -/// The size of a single Action -/// -/// Actions are 5 * 32 + 580 + 80 bytes so the total size of each Action is 820 bytes. -/// [7.5 Action Description Encoding and Consensus][ps] -/// -/// [ps]: -pub const ACTION_SIZE: u64 = 5 * 32 + 580 + 80; +// TODO: FIXME: Consider moving it to transaction.rs as it's not used here. Or move its usage here from transaction.rs. +/// A struct that contains values of several fields of an `Action` struct. +/// Those fields are used in other parts of the code that call the `orchard_actions()` method of the `Transaction`. +/// The goal of using `ActionCommon` is that it's not a generic, unlike `Action`, so it can be returned from Transaction methods +/// (the fields of `ActionCommon` do not depend on the generic parameter `Version` of `Action`). +pub struct ActionCommon { + /// A reference to the value commitment to the net value of the input note minus the output note. + pub cv: super::commitment::ValueCommitment, + /// A reference to the nullifier of the input note being spent. + pub nullifier: super::note::Nullifier, + /// A reference to the randomized validating key for `spendAuthSig`. + pub rk: reddsa::VerificationKeyBytes, + /// A reference to the x-coordinate of the note commitment for the output note. + pub cm_x: pallas::Base, +} -/// The size of a single `Signature`. -/// -/// Each Signature is 64 bytes. -/// [7.1 Transaction Encoding and Consensus][ps] -/// -/// [ps]: -pub const SPEND_AUTH_SIG_SIZE: u64 = 64; +impl From<&Action> for ActionCommon { + fn from(action: &Action) -> Self { + Self { + cv: action.cv, + nullifier: action.nullifier, + rk: action.rk, + cm_x: action.cm_x, + } + } +} -/// The size of a single AuthorizedAction -/// -/// Each serialized `Action` has a corresponding `Signature`. -pub const AUTHORIZED_ACTION_SIZE: u64 = ACTION_SIZE + SPEND_AUTH_SIG_SIZE; +/* +struct AssertBlockSizeLimit; + +impl AssertBlockSizeLimit { + const OK: () = assert!(N < (1 << 16), "must be less than 2^16"); +} +*/ /// The maximum number of orchard actions in a valid Zcash on-chain transaction V5. /// /// If a transaction contains more actions than can fit in maximally large block, it might be /// valid on the network and in the mempool, but it can never be mined into a block. So /// rejecting these large edge-case transactions can never break consensus. -impl TrustedPreallocate for Action { +impl TrustedPreallocate for Action { fn max_allocation() -> u64 { - // Since a serialized Vec uses at least one byte for its length, - // and the signature is required, - // a valid max allocation can never exceed this size - const MAX: u64 = (MAX_BLOCK_BYTES - 1) / AUTHORIZED_ACTION_SIZE; // # Consensus // // > [NU5 onward] nSpendsSapling, nOutputsSapling, and nActionsOrchard MUST all be less than 2^16. @@ -196,15 +265,28 @@ impl TrustedPreallocate for Action { // This acts as nActionsOrchard and is therefore subject to the rule. // The maximum value is actually smaller due to the block size limit, // but we ensure the 2^16 limit with a static assertion. - static_assertions::const_assert!(MAX < (1 << 16)); - MAX + // + // TODO: FIXME: find a better way to use static check (see https://github.com/nvzqz/static-assertions/issues/40, + // https://users.rust-lang.org/t/how-do-i-static-assert-a-property-of-a-generic-u32-parameter/76307)? + // The following expression doesn't work for generics, so a workaround with _ACTION_MAX_ALLOCATION_OK in + // AuthorizedAction impl is used instead: + // static_assertions::const_assert!(AuthorizedAction::::ACTION_MAX_ALLOCATION < (1 << 16)); + AuthorizedAction::::ACTION_MAX_ALLOCATION } } impl TrustedPreallocate for Signature { fn max_allocation() -> u64 { // Each signature must have a corresponding action. - Action::max_allocation() + #[cfg(not(feature = "tx-v6"))] + let result = Action::::max_allocation(); + + // TODO: FIXME: Check this: V6 is used as it provides the max size of the action. + // So it's used even for V5 - is this correct? + #[cfg(feature = "tx-v6")] + let result = Action::::max_allocation(); + + result } } diff --git a/zebra-chain/src/orchard/tests/preallocate.rs b/zebra-chain/src/orchard/tests/preallocate.rs index 79f6a16e7d9..6b1fadfce29 100644 --- a/zebra-chain/src/orchard/tests/preallocate.rs +++ b/zebra-chain/src/orchard/tests/preallocate.rs @@ -4,10 +4,7 @@ use reddsa::{orchard::SpendAuth, Signature}; use crate::{ block::MAX_BLOCK_BYTES, - orchard::{ - shielded_data::{ACTION_SIZE, AUTHORIZED_ACTION_SIZE}, - Action, AuthorizedAction, - }, + orchard::{Action, AuthorizedAction, OrchardVanilla}, serialization::{arbitrary::max_allocation_is_big_enough, TrustedPreallocate, ZcashSerialize}, }; @@ -17,16 +14,16 @@ proptest! { /// Confirm that each `AuthorizedAction` takes exactly AUTHORIZED_ACTION_SIZE /// bytes when serialized. #[test] - fn authorized_action_size_is_small_enough(authorized_action in ::arbitrary_with(())) { + fn authorized_action_size_is_small_enough(authorized_action in >::arbitrary_with(())) { let (action, spend_auth_sig) = authorized_action.into_parts(); let mut serialized_len = action.zcash_serialize_to_vec().expect("Serialization to vec must succeed").len(); serialized_len += spend_auth_sig.zcash_serialize_to_vec().expect("Serialization to vec must succeed").len(); - prop_assert!(serialized_len as u64 == AUTHORIZED_ACTION_SIZE) + prop_assert!(serialized_len as u64 == AuthorizedAction::::AUTHORIZED_ACTION_SIZE) } /// Verify trusted preallocation for `AuthorizedAction` and its split fields #[test] - fn authorized_action_max_allocation_is_big_enough(authorized_action in ::arbitrary_with(())) { + fn authorized_action_max_allocation_is_big_enough(authorized_action in >::arbitrary_with(())) { let (action, spend_auth_sig) = authorized_action.into_parts(); let ( @@ -37,12 +34,14 @@ proptest! { ) = max_allocation_is_big_enough(action); // Calculate the actual size of all required Action fields - prop_assert!((smallest_disallowed_serialized_len as u64)/ACTION_SIZE*AUTHORIZED_ACTION_SIZE >= MAX_BLOCK_BYTES); - prop_assert!((largest_allowed_serialized_len as u64)/ACTION_SIZE*AUTHORIZED_ACTION_SIZE <= MAX_BLOCK_BYTES); + prop_assert!((smallest_disallowed_serialized_len as u64)/AuthorizedAction::::ACTION_SIZE* + AuthorizedAction::::AUTHORIZED_ACTION_SIZE >= MAX_BLOCK_BYTES); + prop_assert!((largest_allowed_serialized_len as u64)/AuthorizedAction::::ACTION_SIZE* + AuthorizedAction::::AUTHORIZED_ACTION_SIZE <= MAX_BLOCK_BYTES); // Check the serialization limits for `Action` - prop_assert!(((smallest_disallowed_vec_len - 1) as u64) == Action::max_allocation()); - prop_assert!((largest_allowed_vec_len as u64) == Action::max_allocation()); + prop_assert!(((smallest_disallowed_vec_len - 1) as u64) == Action::::max_allocation()); + prop_assert!((largest_allowed_vec_len as u64) == Action::::max_allocation()); prop_assert!((largest_allowed_serialized_len as u64) <= MAX_BLOCK_BYTES); let ( diff --git a/zebra-chain/src/orchard_zsa.rs b/zebra-chain/src/orchard_zsa.rs new file mode 100644 index 00000000000..9806850daf9 --- /dev/null +++ b/zebra-chain/src/orchard_zsa.rs @@ -0,0 +1,7 @@ +//! Orchard ZSA related functionality. + +pub mod burn; +pub mod issuance; +pub mod serialize; + +pub use burn::BurnItem; diff --git a/zebra-chain/src/orchard_zsa/burn.rs b/zebra-chain/src/orchard_zsa/burn.rs new file mode 100644 index 00000000000..04c878feb49 --- /dev/null +++ b/zebra-chain/src/orchard_zsa/burn.rs @@ -0,0 +1,80 @@ +//! Orchard ZSA burn related functionality. + +use std::io; + +use crate::{ + amount::Amount, + block::MAX_BLOCK_BYTES, + serialization::{SerializationError, TrustedPreallocate, ZcashDeserialize, ZcashSerialize}, +}; + +use orchard::note::AssetBase; + +use super::serialize::ASSET_BASE_SIZE; + +// Sizes of the serialized values for types in bytes (used for TrustedPreallocate impls) +const AMOUNT_SIZE: u64 = 8; +// FIXME: is this a correct way to calculate (simple sum of sizes of components)? +const BURN_ITEM_SIZE: u64 = ASSET_BASE_SIZE + AMOUNT_SIZE; + +/// Represents an Orchard ZSA burn item. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct BurnItem(AssetBase, Amount); + +impl ZcashSerialize for BurnItem { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + let BurnItem(asset_base, amount) = self; + + asset_base.zcash_serialize(&mut writer)?; + amount.zcash_serialize(&mut writer)?; + + Ok(()) + } +} + +impl ZcashDeserialize for BurnItem { + fn zcash_deserialize(mut reader: R) -> Result { + Ok(Self( + AssetBase::zcash_deserialize(&mut reader)?, + Amount::zcash_deserialize(&mut reader)?, + )) + } +} + +impl TrustedPreallocate for BurnItem { + fn max_allocation() -> u64 { + // FIXME: is this a correct calculation way? + // The longest Vec we receive from an honest peer must fit inside a valid block. + // Since encoding the length of the vec takes at least one byte, we use MAX_BLOCK_BYTES - 1 + (MAX_BLOCK_BYTES - 1) / BURN_ITEM_SIZE + } +} + +#[cfg(any(test, feature = "proptest-impl"))] +impl serde::Serialize for BurnItem { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + // FIXME: return custom error with a meaningful description? + (self.0.to_bytes(), &self.1).serialize(serializer) + } +} + +#[cfg(any(test, feature = "proptest-impl"))] +impl<'de> serde::Deserialize<'de> for BurnItem { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + // FIXME: consider another implementation (explicit specifying of [u8; 32] may not look perfect) + let (asset_base_bytes, amount) = <([u8; 32], Amount)>::deserialize(deserializer)?; + // FIXME: return custom error with a meaningful description? + Ok(BurnItem( + // FIXME: duplicates the body of AssetBase::zcash_deserialize? + Option::from(AssetBase::from_bytes(&asset_base_bytes)) + .ok_or_else(|| serde::de::Error::custom("Invalid orchard_zsa AssetBase"))?, + amount, + )) + } +} diff --git a/zebra-chain/src/orchard_zsa/issuance.rs b/zebra-chain/src/orchard_zsa/issuance.rs new file mode 100644 index 00000000000..3e55edcf14d --- /dev/null +++ b/zebra-chain/src/orchard_zsa/issuance.rs @@ -0,0 +1,260 @@ +//! Orchard ZSA issuance related functionality. + +use std::{fmt::Debug, io}; + +use crate::{ + block::MAX_BLOCK_BYTES, + serialization::{ + zcash_serialize_empty_list, ReadZcashExt, SerializationError, TrustedPreallocate, + ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize, + }, +}; + +use nonempty::NonEmpty; + +// FIXME: needed for "as_bool" only - consider to implement as_bool locally +use bitvec::macros::internal::funty::Fundamental; + +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; + +use orchard::{ + issuance::{IssueAction, IssueBundle, Signed}, + keys::IssuanceValidatingKey, + note::{RandomSeed, Rho}, + primitives::redpallas::{SigType, Signature, SpendAuth}, + value::NoteValue, + Address, Note, +}; + +use super::serialize::ASSET_BASE_SIZE; + +/// Wrapper for `IssueBundle` used in the context of Transaction V6. This allows the implementation of +/// a Serde serializer for unit tests within this crate. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct IssueData(IssueBundle); + +// Sizes of the serialized values for types in bytes (used for TrustedPreallocate impls) +// FIXME: are those values correct (43, 32 etc.)? +//const ISSUANCE_VALIDATING_KEY_SIZE: u64 = 32; +const ADDRESS_SIZE: u64 = 43; +const NULLIFIER_SIZE: u64 = 32; +const NOTE_VALUE_SIZE: u64 = 4; +const RANDOM_SEED_SIZE: u64 = 32; +// FIXME: is this a correct way to calculate (simple sum of sizes of components)? +const NOTE_SIZE: u64 = + ADDRESS_SIZE + NOTE_VALUE_SIZE + ASSET_BASE_SIZE + NULLIFIER_SIZE + RANDOM_SEED_SIZE; + +// FIXME: duplicates ZcashSerialize for reddsa::Signature in transaction/serialize.rs +// (as Signature from oechard_zsa is formally a different type) +impl ZcashSerialize for Signature { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + writer.write_all(&<[u8; 64]>::from(self))?; + Ok(()) + } +} + +// FIXME: duplicates ZcashDeserialize for reddsa::Signature in transaction/serialize.rs +// (as Signature from oechard_zsa is formally a different type) +impl ZcashDeserialize for Signature { + fn zcash_deserialize(mut reader: R) -> Result { + Ok(reader.read_64_bytes()?.into()) + } +} + +impl ZcashDeserialize for Signed { + fn zcash_deserialize(mut reader: R) -> Result { + let signature = Signature::::zcash_deserialize(&mut reader)?; + Ok(Signed::from_data((&signature).into())) + } +} + +impl ZcashSerialize for IssuanceValidatingKey { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + writer.write_all(&self.to_bytes()) + } +} + +impl ZcashDeserialize for IssuanceValidatingKey { + fn zcash_deserialize(mut reader: R) -> Result { + IssuanceValidatingKey::from_bytes(&reader.read_32_bytes()?) + .ok_or_else(|| SerializationError::Parse("Invalid orchard_zsa IssuanceValidatingKey!")) + } +} + +impl ZcashSerialize for Address { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + writer.write_all(&self.to_raw_address_bytes()) + } +} + +impl ZcashDeserialize for Address { + fn zcash_deserialize(mut reader: R) -> Result { + let mut bytes = [0u8; ADDRESS_SIZE as usize]; + reader.read_exact(&mut bytes)?; + Option::from(Address::from_raw_address_bytes(&bytes)) + .ok_or_else(|| SerializationError::Parse("Invalid orchard_zsa Address!")) + } +} + +impl ZcashSerialize for Rho { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + writer.write_all(&self.to_bytes()) + } +} + +impl ZcashDeserialize for Rho { + fn zcash_deserialize(mut reader: R) -> Result { + Option::from(Rho::from_bytes(&reader.read_32_bytes()?)) + .ok_or_else(|| SerializationError::Parse("Invalid orchard_zsa Rho!")) + } +} + +impl ZcashSerialize for RandomSeed { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + writer.write_all(self.as_bytes()) + } +} + +// RandomSeed::zcash_deserialize can't be implemented and used as it requires Nullifier parameter. +// That's why we need to have this function. +fn zcash_deserialize_random_seed( + mut reader: R, + rho: &Rho, +) -> Result { + Option::from(RandomSeed::from_bytes(reader.read_32_bytes()?, rho)) + .ok_or_else(|| SerializationError::Parse("Invalid orchard_zsa RandomSeed!")) +} + +impl ZcashSerialize for NoteValue { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + // FIXME: use Amount serializer/deserializer? + writer.write_u64::(self.inner())?; + Ok(()) + } +} + +impl ZcashDeserialize for NoteValue { + fn zcash_deserialize(mut reader: R) -> Result { + Ok(NoteValue::from_raw(reader.read_u64::()?)) + } +} + +impl ZcashSerialize for Note { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + self.recipient().zcash_serialize(&mut writer)?; + self.value().zcash_serialize(&mut writer)?; + self.asset().zcash_serialize(&mut writer)?; + self.rho().zcash_serialize(&mut writer)?; + self.rseed().zcash_serialize(&mut writer)?; + + Ok(()) + } +} + +impl ZcashDeserialize for Note { + fn zcash_deserialize(mut reader: R) -> Result { + let recipient = (&mut reader).zcash_deserialize_into()?; + let value = (&mut reader).zcash_deserialize_into()?; + let asset = (&mut reader).zcash_deserialize_into()?; + let rho = (&mut reader).zcash_deserialize_into()?; + let rseed = zcash_deserialize_random_seed(&mut reader, &rho)?; + + Option::from(Note::from_parts(recipient, value, asset, rho, rseed)) + .ok_or_else(|| SerializationError::Parse("Invalid orchard_zsa Note components!")) + } +} + +impl TrustedPreallocate for Note { + fn max_allocation() -> u64 { + // FIXME: is this a correct calculation way? + // The longest Vec we receive from an honest peer must fit inside a valid block. + // Since encoding the length of the vec takes at least one byte, we use MAX_BLOCK_BYTES - 1 + (MAX_BLOCK_BYTES - 1) / NOTE_SIZE + } +} + +impl ZcashSerialize for IssueAction { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + writer.write_u8(self.is_finalized().as_u8())?; + self.notes().zcash_serialize(&mut writer)?; + self.asset_desc().zcash_serialize(&mut writer)?; + Ok(()) + } +} + +impl ZcashDeserialize for IssueAction { + fn zcash_deserialize(mut reader: R) -> Result { + let finalize = reader.read_u8()?.as_bool(); + let notes = (&mut reader).zcash_deserialize_into()?; + let asset_descr = (&mut reader).zcash_deserialize_into()?; + Ok(IssueAction::from_parts(asset_descr, notes, finalize)) + } +} + +impl TrustedPreallocate for IssueAction { + fn max_allocation() -> u64 { + // FIXME: impl correct calculation + 10 + } +} + +impl ZcashSerialize for IssueBundle { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + // FIXME: try to avoid transforming to Vec (consider implementation of ZcashSerialize for IntoIter generic, + // or use AtLeastOne). + // This is how does it work in librustzcash: + // Vector::write_nonempty(&mut writer, bundle.actions(), |w, action| write_action(action, w))?; + let actions: Vec<_> = self.actions().clone().into(); + + actions.zcash_serialize(&mut writer)?; + self.ik().zcash_serialize(&mut writer)?; + writer.write_all(&<[u8; 64]>::from(self.authorization().signature()))?; + Ok(()) + } +} + +impl ZcashSerialize for Option { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + match self { + None => { + // Denoted as `&Option` in the spec (ZIP 230). + zcash_serialize_empty_list(writer)?; + } + Some(issue_data) => { + issue_data.0.zcash_serialize(&mut writer)?; + } + } + Ok(()) + } +} + +// FIXME: We can't split IssueData out of Option deserialization, +// because the counts are read along with the arrays. +impl ZcashDeserialize for Option { + fn zcash_deserialize(mut reader: R) -> Result { + let actions: Vec<_> = (&mut reader).zcash_deserialize_into()?; + + if actions.is_empty() { + Ok(None) + } else { + let ik = (&mut reader).zcash_deserialize_into()?; + let authorization = (&mut reader).zcash_deserialize_into()?; + + Ok(Some(IssueData(IssueBundle::from_parts( + ik, + NonEmpty::from_vec(actions).ok_or_else(|| { + SerializationError::Parse("Invalid orchard_zsa IssueData - no actions!") + })?, + authorization, + )))) + } + } +} + +#[cfg(any(test, feature = "proptest-impl"))] +impl serde::Serialize for IssueData { + fn serialize(&self, serializer: S) -> Result { + // TODO: FIXME: implement Serde serialization here + "(IssueData)".serialize(serializer) + } +} diff --git a/zebra-chain/src/orchard_zsa/serialize.rs b/zebra-chain/src/orchard_zsa/serialize.rs new file mode 100644 index 00000000000..6afc51e1887 --- /dev/null +++ b/zebra-chain/src/orchard_zsa/serialize.rs @@ -0,0 +1,23 @@ +//! Serialization implementation for selected types from the 'orchard_zsa' crate used in this module. + +use std::io; + +use crate::serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize}; + +use orchard::note::AssetBase; + +// The size of the serialized AssetBase in bytes (used for TrustedPreallocate impls) +pub(crate) const ASSET_BASE_SIZE: u64 = 32; + +impl ZcashSerialize for AssetBase { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + writer.write_all(&self.to_bytes()) + } +} + +impl ZcashDeserialize for AssetBase { + fn zcash_deserialize(mut reader: R) -> Result { + Option::from(AssetBase::from_bytes(&reader.read_32_bytes()?)) + .ok_or_else(|| SerializationError::Parse("Invalid orchard_zsa AssetBase!")) + } +} diff --git a/zebra-chain/src/parameters/network_upgrade.rs b/zebra-chain/src/parameters/network_upgrade.rs index 356ae86577f..79cf18a6291 100644 --- a/zebra-chain/src/parameters/network_upgrade.rs +++ b/zebra-chain/src/parameters/network_upgrade.rs @@ -530,7 +530,12 @@ impl From for NetworkUpgrade { zcash_protocol::consensus::NetworkUpgrade::Heartwood => Self::Heartwood, zcash_protocol::consensus::NetworkUpgrade::Canopy => Self::Canopy, zcash_protocol::consensus::NetworkUpgrade::Nu5 => Self::Nu5, + // FIXME: remove this cfg + //#[cfg(zcash_unstable = "nu6")] zcash_protocol::consensus::NetworkUpgrade::Nu6 => Self::Nu6, + // FIXME: remove this cfg and process Nu7 properly (uses Self::Nu6 for now) + //#[cfg(zcash_unstable = "nu6")] + zcash_protocol::consensus::NetworkUpgrade::Nu7 => Self::Nu6, } } } diff --git a/zebra-chain/src/parameters/transaction.rs b/zebra-chain/src/parameters/transaction.rs index bab59e794db..d7391bdf184 100644 --- a/zebra-chain/src/parameters/transaction.rs +++ b/zebra-chain/src/parameters/transaction.rs @@ -11,3 +11,11 @@ pub const SAPLING_VERSION_GROUP_ID: u32 = 0x892F_2085; /// Orchard transactions must use transaction version 5 and this version /// group ID. Sapling transactions can use v4 or v5 transactions. pub const TX_V5_VERSION_GROUP_ID: u32 = 0x26A7_270A; + +/// The version group ID for version 6 transactions. +/// +/// Orchard transactions must use transaction version 5 and this version +/// group ID. +// FIXME: use a proper value! +#[cfg(feature = "tx-v6")] +pub const TX_V6_VERSION_GROUP_ID: u32 = 0x26A7_270B; diff --git a/zebra-chain/src/primitives/zcash_primitives.rs b/zebra-chain/src/primitives/zcash_primitives.rs index 7ab2f32d751..0d10f8546af 100644 --- a/zebra-chain/src/primitives/zcash_primitives.rs +++ b/zebra-chain/src/primitives/zcash_primitives.rs @@ -10,7 +10,7 @@ use crate::{ amount::{Amount, NonNegative}, parameters::{ConsensusBranchId, Network}, serialization::ZcashSerialize, - transaction::{AuthDigest, HashType, SigHash, Transaction}, + transaction::{tx_v5_and_v6, AuthDigest, HashType, SigHash, Transaction}, transparent::{self, Script}, }; @@ -137,6 +137,17 @@ impl zp_tx::components::orchard::MapAuth + for IdentityMap +{ + fn map_issue_authorization(&self, s: orchard::issuance::Signed) -> orchard::issuance::Signed { + s + } +} + #[derive(Debug)] struct PrecomputedAuth<'a> { _phantom: std::marker::PhantomData<&'a ()>, @@ -146,6 +157,16 @@ impl<'a> zp_tx::Authorization for PrecomputedAuth<'a> { type TransparentAuth = TransparentAuth<'a>; type SaplingAuth = sapling_crypto::bundle::Authorized; type OrchardAuth = orchard::bundle::Authorized; + + // FIXME: is this correct? + // FIXME: remove this cfg + //#[cfg(zcash_unstable = "nu6")] + type OrchardZsaAuth = orchard::bundle::Authorized; + + // FIXME: is this correct? + // FIXME: remove this cfg + //#[cfg(zcash_unstable = "nu6")] + type IssueAuth = orchard::issuance::Signed; } // End of (mostly) copied code @@ -157,12 +178,12 @@ impl TryFrom<&Transaction> for zp_tx::Transaction { /// /// # Panics /// - /// If the transaction is not V5. (Currently there is no need for this + /// If the transaction is not V5/V6. (Currently there is no need for this /// conversion for other versions.) #[allow(clippy::unwrap_in_result)] fn try_from(trans: &Transaction) -> Result { let network_upgrade = match trans { - Transaction::V5 { + tx_v5_and_v6! { network_upgrade, .. } => network_upgrade, Transaction::V1 { .. } @@ -275,7 +296,14 @@ impl<'a> PrecomputedTxData<'a> { }; let tx_data: zp_tx::TransactionData = alt_tx .into_data() - .map_authorization(f_transparent, IdentityMap, IdentityMap); + // FIXME: do we need to pass another arg values or orchard_zsa and issue instead of IdentityMap? + .map_authorization( + f_transparent, + IdentityMap, + IdentityMap, + IdentityMap, + IdentityMap, + ); PrecomputedTxData { tx_data, diff --git a/zebra-chain/src/transaction.rs b/zebra-chain/src/transaction.rs index 3df3edc8d53..e60f13b57a1 100644 --- a/zebra-chain/src/transaction.rs +++ b/zebra-chain/src/transaction.rs @@ -53,6 +53,74 @@ use crate::{ value_balance::{ValueBalance, ValueBalanceError}, }; +// FIXME: doc this +// Move down +macro_rules! orchard_shielded_data_iter { + ($self:expr, $mapper:expr) => { + match $self { + // No Orchard shielded data + Transaction::V1 { .. } + | Transaction::V2 { .. } + | Transaction::V3 { .. } + | Transaction::V4 { .. } => Box::new(std::iter::empty()), + + Transaction::V5 { + orchard_shielded_data, + .. + } => Box::new(orchard_shielded_data.into_iter().flat_map($mapper)), + + #[cfg(feature = "tx-v6")] + Transaction::V6 { + orchard_shielded_data, + .. + } => Box::new(orchard_shielded_data.into_iter().flat_map($mapper)), + } + }; +} + +// FIXME: doc this +// Move down +macro_rules! orchard_shielded_data_field { + ($self:expr, $field:ident) => { + match $self { + // No Orchard shielded data + Transaction::V1 { .. } + | Transaction::V2 { .. } + | Transaction::V3 { .. } + | Transaction::V4 { .. } => None, + + Transaction::V5 { + orchard_shielded_data, + .. + } => orchard_shielded_data.as_ref().map(|data| data.$field), + + #[cfg(feature = "tx-v6")] + Transaction::V6 { + orchard_shielded_data, + .. + } => orchard_shielded_data.as_ref().map(|data| data.$field), + } + }; +} + +// FIXME: +// Define the macro for including the V6 pattern +#[cfg(feature = "tx-v6")] +macro_rules! tx_v5_and_v6 { + { $($fields:tt)* } => { + Transaction::V5 { $($fields)* } | Transaction::V6 { $($fields)* } + }; +} + +#[cfg(not(feature = "tx-v6"))] +macro_rules! tx_v5_and_v6 { + { $($fields:tt)* } => { + Transaction::V5 { $($fields)* } + }; +} + +pub(crate) use tx_v5_and_v6; + /// A Zcash transaction. /// /// A transaction is an encoded data structure that facilitates the transfer of @@ -140,7 +208,34 @@ pub enum Transaction { /// The sapling shielded data for this transaction, if any. sapling_shielded_data: Option>, /// The orchard data for this transaction, if any. - orchard_shielded_data: Option, + orchard_shielded_data: Option>, + }, + // FIXME: implement V6 properly (now it's just a coipy of V5) + /// A `version = 6` transaction , which supports Orchard ZSA, Orchard Vanille, Sapling and + /// transparent, but not Sprout. + #[cfg(feature = "tx-v6")] + V6 { + /// The Network Upgrade for this transaction. + /// + /// Derived from the ConsensusBranchId field. + network_upgrade: NetworkUpgrade, + /// The earliest time or block height that this transaction can be added to the + /// chain. + lock_time: LockTime, + /// The latest block height that this transaction can be added to the chain. + expiry_height: block::Height, + /// The transparent inputs to the transaction. + inputs: Vec, + /// The transparent outputs from the transaction. + outputs: Vec, + /// The sapling shielded data for this transaction, if any. + sapling_shielded_data: Option>, + /// The ZSA orchard shielded data for this transaction, if any. + #[cfg(feature = "tx-v6")] + orchard_shielded_data: Option>, + /// The ZSA issuance data for this transaction, if any. + #[cfg(feature = "tx-v6")] + orchard_zsa_issue_data: Option, }, } @@ -180,7 +275,7 @@ impl Transaction { /// Compute the hash (mined transaction ID) of this transaction. /// - /// The hash uniquely identifies mined v5 transactions, + /// The hash uniquely identifies mined v5/v6 transactions, /// and all v1-v4 transactions, whether mined or unmined. pub fn hash(&self) -> Hash { Hash::from(self) @@ -247,7 +342,7 @@ impl Transaction { | Transaction::V2 { .. } | Transaction::V3 { .. } | Transaction::V4 { .. } => None, - Transaction::V5 { .. } => Some(AuthDigest::from(self)), + tx_v5_and_v6! { .. } => Some(AuthDigest::from(self)), } } @@ -320,7 +415,7 @@ impl Transaction { pub fn is_overwintered(&self) -> bool { match self { Transaction::V1 { .. } | Transaction::V2 { .. } => false, - Transaction::V3 { .. } | Transaction::V4 { .. } | Transaction::V5 { .. } => true, + Transaction::V3 { .. } | Transaction::V4 { .. } | tx_v5_and_v6! { .. } => true, } } @@ -332,6 +427,8 @@ impl Transaction { Transaction::V3 { .. } => 3, Transaction::V4 { .. } => 4, Transaction::V5 { .. } => 5, + #[cfg(feature = "tx-v6")] + Transaction::V6 { .. } => 6, } } @@ -342,7 +439,7 @@ impl Transaction { | Transaction::V2 { lock_time, .. } | Transaction::V3 { lock_time, .. } | Transaction::V4 { lock_time, .. } - | Transaction::V5 { lock_time, .. } => *lock_time, + | tx_v5_and_v6! { lock_time, .. } => *lock_time, }; // `zcashd` checks that the block height is greater than the lock height. @@ -389,7 +486,7 @@ impl Transaction { | Transaction::V2 { lock_time, .. } | Transaction::V3 { lock_time, .. } | Transaction::V4 { lock_time, .. } - | Transaction::V5 { lock_time, .. } => *lock_time, + | tx_v5_and_v6! { lock_time, .. } => *lock_time, }; let mut lock_time_bytes = Vec::new(); lock_time @@ -419,7 +516,7 @@ impl Transaction { Transaction::V1 { .. } | Transaction::V2 { .. } => None, Transaction::V3 { expiry_height, .. } | Transaction::V4 { expiry_height, .. } - | Transaction::V5 { expiry_height, .. } => match expiry_height { + | tx_v5_and_v6! { expiry_height, .. } => match expiry_height { // Consensus rule: // > No limit: To set no limit on transactions (so that they do not expire), nExpiryHeight should be set to 0. // https://zips.z.cash/zip-0203#specification @@ -448,7 +545,7 @@ impl Transaction { ref mut expiry_height, .. } - | Transaction::V5 { + | tx_v5_and_v6! { ref mut expiry_height, .. } => expiry_height, @@ -465,7 +562,7 @@ impl Transaction { | Transaction::V2 { .. } | Transaction::V3 { .. } | Transaction::V4 { .. } => None, - Transaction::V5 { + tx_v5_and_v6! { network_upgrade, .. } => Some(*network_upgrade), } @@ -480,7 +577,7 @@ impl Transaction { Transaction::V2 { ref inputs, .. } => inputs, Transaction::V3 { ref inputs, .. } => inputs, Transaction::V4 { ref inputs, .. } => inputs, - Transaction::V5 { ref inputs, .. } => inputs, + tx_v5_and_v6! { ref inputs, .. } => inputs, } } @@ -492,7 +589,7 @@ impl Transaction { Transaction::V2 { ref mut inputs, .. } => inputs, Transaction::V3 { ref mut inputs, .. } => inputs, Transaction::V4 { ref mut inputs, .. } => inputs, - Transaction::V5 { ref mut inputs, .. } => inputs, + tx_v5_and_v6! { ref mut inputs, .. } => inputs, } } @@ -510,7 +607,7 @@ impl Transaction { Transaction::V2 { ref outputs, .. } => outputs, Transaction::V3 { ref outputs, .. } => outputs, Transaction::V4 { ref outputs, .. } => outputs, - Transaction::V5 { ref outputs, .. } => outputs, + tx_v5_and_v6! { ref outputs, .. } => outputs, } } @@ -530,7 +627,7 @@ impl Transaction { Transaction::V4 { ref mut outputs, .. } => outputs, - Transaction::V5 { + tx_v5_and_v6! { ref mut outputs, .. } => outputs, } @@ -580,7 +677,7 @@ impl Transaction { joinsplit_data: None, .. } - | Transaction::V5 { .. } => Box::new(std::iter::empty()), + | tx_v5_and_v6! { .. } => Box::new(std::iter::empty()), } } @@ -615,7 +712,7 @@ impl Transaction { joinsplit_data: None, .. } - | Transaction::V5 { .. } => 0, + | tx_v5_and_v6! { .. } => 0, } } @@ -654,7 +751,7 @@ impl Transaction { joinsplit_data: None, .. } - | Transaction::V5 { .. } => Box::new(std::iter::empty()), + | tx_v5_and_v6! { .. } => Box::new(std::iter::empty()), } } @@ -690,7 +787,7 @@ impl Transaction { joinsplit_data: None, .. } - | Transaction::V5 { .. } => None, + | tx_v5_and_v6! { .. } => None, } } @@ -698,7 +795,7 @@ impl Transaction { pub fn has_sprout_joinsplit_data(&self) -> bool { match self { // No JoinSplits - Transaction::V1 { .. } | Transaction::V5 { .. } => false, + Transaction::V1 { .. } | tx_v5_and_v6! { .. } => false, // JoinSplits-on-BCTV14 Transaction::V2 { joinsplit_data, .. } | Transaction::V3 { joinsplit_data, .. } => { @@ -745,7 +842,7 @@ impl Transaction { .. } | Transaction::V1 { .. } - | Transaction::V5 { .. } => Box::new(std::iter::empty()), + | tx_v5_and_v6! { .. } => Box::new(std::iter::empty()), } } @@ -762,7 +859,7 @@ impl Transaction { .. } => Box::new(sapling_shielded_data.anchors()), - Transaction::V5 { + tx_v5_and_v6! { sapling_shielded_data: Some(sapling_shielded_data), .. } => Box::new(sapling_shielded_data.anchors()), @@ -775,7 +872,7 @@ impl Transaction { sapling_shielded_data: None, .. } - | Transaction::V5 { + | tx_v5_and_v6! { sapling_shielded_data: None, .. } => Box::new(std::iter::empty()), @@ -786,8 +883,8 @@ impl Transaction { /// returning `Spend` regardless of the underlying /// transaction version. /// - /// Shared anchors in V5 transactions are copied into each sapling spend. - /// This allows the same code to validate spends from V4 and V5 transactions. + /// Shared anchors in V5/V6 transactions are copied into each sapling spend. + /// This allows the same code to validate spends from V4 and V5/V6 transactions. /// /// # Correctness /// @@ -800,7 +897,7 @@ impl Transaction { sapling_shielded_data: Some(sapling_shielded_data), .. } => Box::new(sapling_shielded_data.spends_per_anchor()), - Transaction::V5 { + tx_v5_and_v6! { sapling_shielded_data: Some(sapling_shielded_data), .. } => Box::new(sapling_shielded_data.spends_per_anchor()), @@ -813,7 +910,7 @@ impl Transaction { sapling_shielded_data: None, .. } - | Transaction::V5 { + | tx_v5_and_v6! { sapling_shielded_data: None, .. } => Box::new(std::iter::empty()), @@ -828,7 +925,7 @@ impl Transaction { sapling_shielded_data: Some(sapling_shielded_data), .. } => Box::new(sapling_shielded_data.outputs()), - Transaction::V5 { + tx_v5_and_v6! { sapling_shielded_data: Some(sapling_shielded_data), .. } => Box::new(sapling_shielded_data.outputs()), @@ -841,7 +938,7 @@ impl Transaction { sapling_shielded_data: None, .. } - | Transaction::V5 { + | tx_v5_and_v6! { sapling_shielded_data: None, .. } => Box::new(std::iter::empty()), @@ -858,7 +955,7 @@ impl Transaction { sapling_shielded_data: Some(sapling_shielded_data), .. } => Box::new(sapling_shielded_data.nullifiers()), - Transaction::V5 { + tx_v5_and_v6! { sapling_shielded_data: Some(sapling_shielded_data), .. } => Box::new(sapling_shielded_data.nullifiers()), @@ -871,7 +968,7 @@ impl Transaction { sapling_shielded_data: None, .. } - | Transaction::V5 { + | tx_v5_and_v6! { sapling_shielded_data: None, .. } => Box::new(std::iter::empty()), @@ -888,7 +985,7 @@ impl Transaction { sapling_shielded_data: Some(sapling_shielded_data), .. } => Box::new(sapling_shielded_data.note_commitments()), - Transaction::V5 { + tx_v5_and_v6! { sapling_shielded_data: Some(sapling_shielded_data), .. } => Box::new(sapling_shielded_data.note_commitments()), @@ -901,7 +998,7 @@ impl Transaction { sapling_shielded_data: None, .. } - | Transaction::V5 { + | tx_v5_and_v6! { sapling_shielded_data: None, .. } => Box::new(std::iter::empty()), @@ -916,7 +1013,7 @@ impl Transaction { sapling_shielded_data, .. } => sapling_shielded_data.is_some(), - Transaction::V5 { + tx_v5_and_v6! { sapling_shielded_data, .. } => sapling_shielded_data.is_some(), @@ -925,80 +1022,40 @@ impl Transaction { // orchard - /// Access the [`orchard::ShieldedData`] in this transaction, - /// regardless of version. - pub fn orchard_shielded_data(&self) -> Option<&orchard::ShieldedData> { - match self { - // Maybe Orchard shielded data - Transaction::V5 { - orchard_shielded_data, - .. - } => orchard_shielded_data.as_ref(), - - // No Orchard shielded data - Transaction::V1 { .. } - | Transaction::V2 { .. } - | Transaction::V3 { .. } - | Transaction::V4 { .. } => None, - } - } - - /// Modify the [`orchard::ShieldedData`] in this transaction, - /// regardless of version. - #[cfg(any(test, feature = "proptest-impl"))] - pub fn orchard_shielded_data_mut(&mut self) -> Option<&mut orchard::ShieldedData> { - match self { - Transaction::V5 { - orchard_shielded_data: Some(orchard_shielded_data), - .. - } => Some(orchard_shielded_data), - - Transaction::V1 { .. } - | Transaction::V2 { .. } - | Transaction::V3 { .. } - | Transaction::V4 { .. } - | Transaction::V5 { - orchard_shielded_data: None, - .. - } => None, - } - } - /// Iterate over the [`orchard::Action`]s in this transaction, if there are any, /// regardless of version. - pub fn orchard_actions(&self) -> impl Iterator { - self.orchard_shielded_data() - .into_iter() - .flat_map(orchard::ShieldedData::actions) + pub fn orchard_actions(&self) -> Box + '_> { + orchard_shielded_data_iter!(self, orchard::ShieldedData::action_commons) } /// Access the [`orchard::Nullifier`]s in this transaction, if there are any, /// regardless of version. - pub fn orchard_nullifiers(&self) -> impl Iterator { - self.orchard_shielded_data() - .into_iter() - .flat_map(orchard::ShieldedData::nullifiers) + pub fn orchard_nullifiers(&self) -> Box + '_> { + orchard_shielded_data_iter!(self, orchard::ShieldedData::nullifiers) } /// Access the note commitments in this transaction, if there are any, /// regardless of version. - pub fn orchard_note_commitments(&self) -> impl Iterator { - self.orchard_shielded_data() - .into_iter() - .flat_map(orchard::ShieldedData::note_commitments) + pub fn orchard_note_commitments(&self) -> Box + '_> { + orchard_shielded_data_iter!(self, orchard::ShieldedData::note_commitments) } /// Access the [`orchard::Flags`] in this transaction, if there is any, /// regardless of version. pub fn orchard_flags(&self) -> Option { - self.orchard_shielded_data() - .map(|orchard_shielded_data| orchard_shielded_data.flags) + // FIXME: remove this line with_shielded_data!(self, |data: impl orchard::ShieldedDataCommon| data.flags) + orchard_shielded_data_field!(self, flags) + } + + /// FIXME: add doc + pub fn orchard_shared_anchor(&self) -> Option { + orchard_shielded_data_field!(self, shared_anchor) } /// Return if the transaction has any Orchard shielded data, /// regardless of version. pub fn has_orchard_shielded_data(&self) -> bool { - self.orchard_shielded_data().is_some() + self.orchard_flags().is_some() } // value balances @@ -1086,7 +1143,7 @@ impl Transaction { joinsplit_data: None, .. } - | Transaction::V5 { .. } => Box::new(std::iter::empty()), + | tx_v5_and_v6! { .. } => Box::new(std::iter::empty()), } } @@ -1135,7 +1192,7 @@ impl Transaction { joinsplit_data: None, .. } - | Transaction::V5 { .. } => Box::new(std::iter::empty()), + | tx_v5_and_v6! { .. } => Box::new(std::iter::empty()), } } @@ -1182,7 +1239,7 @@ impl Transaction { joinsplit_data: None, .. } - | Transaction::V5 { .. } => Box::new(std::iter::empty()), + | tx_v5_and_v6! { .. } => Box::new(std::iter::empty()), } } @@ -1231,7 +1288,7 @@ impl Transaction { joinsplit_data: None, .. } - | Transaction::V5 { .. } => Box::new(std::iter::empty()), + | tx_v5_and_v6! { .. } => Box::new(std::iter::empty()), } } @@ -1272,7 +1329,7 @@ impl Transaction { joinsplit_data: None, .. } - | Transaction::V5 { .. } => Box::new(iter::empty()), + | tx_v5_and_v6! { .. } => Box::new(iter::empty()), }; joinsplit_value_balances.map(ValueBalance::from_sprout_amount) @@ -1310,7 +1367,7 @@ impl Transaction { sapling_shielded_data: Some(sapling_shielded_data), .. } => sapling_shielded_data.value_balance, - Transaction::V5 { + tx_v5_and_v6! { sapling_shielded_data: Some(sapling_shielded_data), .. } => sapling_shielded_data.value_balance, @@ -1322,7 +1379,7 @@ impl Transaction { sapling_shielded_data: None, .. } - | Transaction::V5 { + | tx_v5_and_v6! { sapling_shielded_data: None, .. } => Amount::zero(), @@ -1342,7 +1399,7 @@ impl Transaction { sapling_shielded_data: Some(sapling_shielded_data), .. } => Some(&mut sapling_shielded_data.value_balance), - Transaction::V5 { + tx_v5_and_v6! { sapling_shielded_data: Some(sapling_shielded_data), .. } => Some(&mut sapling_shielded_data.value_balance), @@ -1353,7 +1410,7 @@ impl Transaction { sapling_shielded_data: None, .. } - | Transaction::V5 { + | tx_v5_and_v6! { sapling_shielded_data: None, .. } => None, @@ -1372,10 +1429,8 @@ impl Transaction { /// /// pub fn orchard_value_balance(&self) -> ValueBalance { - let orchard_value_balance = self - .orchard_shielded_data() - .map(|shielded_data| shielded_data.value_balance) - .unwrap_or_else(Amount::zero); + let orchard_value_balance = + orchard_shielded_data_field!(self, value_balance).unwrap_or_else(Amount::zero); ValueBalance::from_orchard_amount(orchard_value_balance) } @@ -1386,8 +1441,33 @@ impl Transaction { /// See `orchard_value_balance` for details. #[cfg(any(test, feature = "proptest-impl"))] pub fn orchard_value_balance_mut(&mut self) -> Option<&mut Amount> { - self.orchard_shielded_data_mut() - .map(|shielded_data| &mut shielded_data.value_balance) + match self { + Transaction::V5 { + orchard_shielded_data: Some(orchard_shielded_data), + .. + } => Some(&mut orchard_shielded_data.value_balance), + + #[cfg(feature = "tx-v6")] + Transaction::V6 { + orchard_shielded_data: Some(orchard_shielded_data), + .. + } => Some(&mut orchard_shielded_data.value_balance), + + Transaction::V1 { .. } + | Transaction::V2 { .. } + | Transaction::V3 { .. } + | Transaction::V4 { .. } + | Transaction::V5 { + orchard_shielded_data: None, + .. + } => None, + + #[cfg(feature = "tx-v6")] + Transaction::V6 { + orchard_shielded_data: None, + .. + } => None, + } } /// Returns the value balances for this transaction using the provided transparent outputs. diff --git a/zebra-chain/src/transaction/arbitrary.rs b/zebra-chain/src/transaction/arbitrary.rs index cf4aa7a9552..ffd169f651f 100644 --- a/zebra-chain/src/transaction/arbitrary.rs +++ b/zebra-chain/src/transaction/arbitrary.rs @@ -141,7 +141,7 @@ impl Transaction { transparent::Input::vec_strategy(&ledger_state, MAX_ARBITRARY_ITEMS), vec(any::(), 0..MAX_ARBITRARY_ITEMS), option::of(any::>()), - option::of(any::()), + option::of(any::>()), ) .prop_map( move |( @@ -697,7 +697,7 @@ impl Arbitrary for sapling::TransferData { type Strategy = BoxedStrategy; } -impl Arbitrary for orchard::ShieldedData { +impl Arbitrary for orchard::ShieldedData { type Parameters = (); fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { @@ -707,7 +707,7 @@ impl Arbitrary for orchard::ShieldedData { any::(), any::(), vec( - any::(), + any::>(), 1..MAX_ARBITRARY_ITEMS, ), any::(), @@ -722,6 +722,8 @@ impl Arbitrary for orchard::ShieldedData { .try_into() .expect("arbitrary vector size range produces at least one action"), binding_sig: binding_sig.0, + #[cfg(feature = "tx-v6")] + burn: Default::default(), }, ) .boxed() @@ -918,6 +920,26 @@ pub fn transaction_to_fake_v5( orchard_shielded_data: None, }, v5 @ V5 { .. } => v5.clone(), + #[cfg(feature = "tx-v6")] + V6 { + inputs, + outputs, + lock_time, + sapling_shielded_data, + orchard_shielded_data: _, + .. + } => V5 { + network_upgrade: block_nu, + inputs: inputs.clone(), + outputs: outputs.clone(), + lock_time: *lock_time, + expiry_height: height, + sapling_shielded_data: sapling_shielded_data.clone(), + // FIXME: is it possible to convert V6 shielded data to V5? + // FIXME: add another function for V6, like transaction_to_fake_v6? + //orchard_shielded_data: orchard_shielded_data.clone(), + orchard_shielded_data: None, + }, } } @@ -1020,6 +1042,7 @@ pub fn transactions_from_blocks<'a>( }) } +// FIXME: make it a generic to support V6? /// Modify a V5 transaction to insert fake Orchard shielded data. /// /// Creates a fake instance of [`orchard::ShieldedData`] with one fake action. Note that both the @@ -1034,7 +1057,7 @@ pub fn transactions_from_blocks<'a>( /// Panics if the transaction to be modified is not V5. pub fn insert_fake_orchard_shielded_data( transaction: &mut Transaction, -) -> &mut orchard::ShieldedData { +) -> &mut orchard::ShieldedData { // Create a dummy action let mut runner = TestRunner::default(); let dummy_action = orchard::Action::arbitrary() @@ -1049,13 +1072,15 @@ pub fn insert_fake_orchard_shielded_data( }; // Place the dummy action inside the Orchard shielded data - let dummy_shielded_data = orchard::ShieldedData { + let dummy_shielded_data = orchard::ShieldedData:: { flags: orchard::Flags::empty(), value_balance: Amount::try_from(0).expect("invalid transaction amount"), shared_anchor: orchard::tree::Root::default(), proof: Halo2Proof(vec![]), actions: at_least_one![dummy_authorized_action], binding_sig: Signature::from([0u8; 64]), + #[cfg(feature = "tx-v6")] + burn: Default::default(), }; // Replace the shielded data in the transaction diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index ba65dd054b3..f5fd254773d 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -11,6 +11,7 @@ use reddsa::{orchard::Binding, orchard::SpendAuth, Signature}; use crate::{ amount, block::MAX_BLOCK_BYTES, + orchard::OrchardFlavorExt, parameters::{OVERWINTER_VERSION_GROUP_ID, SAPLING_VERSION_GROUP_ID, TX_V5_VERSION_GROUP_ID}, primitives::{Halo2Proof, ZkSnarkProof}, serialization::{ @@ -20,6 +21,9 @@ use crate::{ }, }; +#[cfg(feature = "tx-v6")] +use crate::parameters::TX_V6_VERSION_GROUP_ID; + use super::*; use crate::sapling; @@ -323,7 +327,7 @@ impl ZcashDeserialize for Option> { } } -impl ZcashSerialize for Option { +impl ZcashSerialize for Option> { fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { match self { None => { @@ -339,14 +343,15 @@ impl ZcashSerialize for Option { orchard_shielded_data.zcash_serialize(&mut writer)?; } } + Ok(()) } } -impl ZcashSerialize for orchard::ShieldedData { +impl ZcashSerialize for orchard::ShieldedData { fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { // Split the AuthorizedAction - let (actions, sigs): (Vec, Vec>) = self + let (actions, sigs): (Vec>, Vec>) = self .actions .iter() .cloned() @@ -374,16 +379,20 @@ impl ZcashSerialize for orchard::ShieldedData { // Denoted as `bindingSigOrchard` in the spec. self.binding_sig.zcash_serialize(&mut writer)?; + #[cfg(feature = "tx-v6")] + // Denoted as `vAssetBurn` in the spec (ZIP 230). + self.burn.zcash_serialize(&mut writer)?; + Ok(()) } } // we can't split ShieldedData out of Option deserialization, // because the counts are read along with the arrays. -impl ZcashDeserialize for Option { +impl ZcashDeserialize for Option> { fn zcash_deserialize(mut reader: R) -> Result { // Denoted as `nActionsOrchard` and `vActionsOrchard` in the spec. - let actions: Vec = (&mut reader).zcash_deserialize_into()?; + let actions: Vec> = (&mut reader).zcash_deserialize_into()?; // "The fields flagsOrchard, valueBalanceOrchard, anchorOrchard, sizeProofsOrchard, // proofsOrchard , and bindingSigOrchard are present if and only if nActionsOrchard > 0." @@ -429,7 +438,7 @@ impl ZcashDeserialize for Option { let binding_sig: Signature = (&mut reader).zcash_deserialize_into()?; // Create the AuthorizedAction from deserialized parts - let authorized_actions: Vec = actions + let authorized_actions: Vec> = actions .into_iter() .zip(sigs) .map(|(action, spend_auth_sig)| { @@ -437,11 +446,17 @@ impl ZcashDeserialize for Option { }) .collect(); - let actions: AtLeastOne = authorized_actions.try_into()?; + let actions: AtLeastOne> = authorized_actions.try_into()?; + + // TODO: FIXME: add a proper comment + #[cfg(feature = "tx-v6")] + let burn = (&mut reader).zcash_deserialize_into()?; - Ok(Some(orchard::ShieldedData { + Ok(Some(orchard::ShieldedData:: { flags, value_balance, + #[cfg(feature = "tx-v6")] + burn, shared_anchor, proof, actions, @@ -673,6 +688,59 @@ impl ZcashSerialize for Transaction { // `proofsOrchard`, `vSpendAuthSigsOrchard`, and `bindingSigOrchard`. orchard_shielded_data.zcash_serialize(&mut writer)?; } + + #[cfg(feature = "tx-v6")] + Transaction::V6 { + network_upgrade, + lock_time, + expiry_height, + inputs, + outputs, + sapling_shielded_data, + orchard_shielded_data, + orchard_zsa_issue_data, + } => { + // FIXME: fix spec or use another link as the current version of the PDF + // doesn't contain V6 description. + // Transaction V6 spec: + // https://zips.z.cash/protocol/protocol.pdf#txnencoding + + // Denoted as `nVersionGroupId` in the spec. + writer.write_u32::(TX_V6_VERSION_GROUP_ID)?; + + // Denoted as `nConsensusBranchId` in the spec. + writer.write_u32::(u32::from( + network_upgrade + .branch_id() + .expect("valid transactions must have a network upgrade with a branch id"), + ))?; + + // Denoted as `lock_time` in the spec. + lock_time.zcash_serialize(&mut writer)?; + + // Denoted as `nExpiryHeight` in the spec. + writer.write_u32::(expiry_height.0)?; + + // Denoted as `tx_in_count` and `tx_in` in the spec. + inputs.zcash_serialize(&mut writer)?; + + // Denoted as `tx_out_count` and `tx_out` in the spec. + outputs.zcash_serialize(&mut writer)?; + + // A bundle of fields denoted in the spec as `nSpendsSapling`, `vSpendsSapling`, + // `nOutputsSapling`,`vOutputsSapling`, `valueBalanceSapling`, `anchorSapling`, + // `vSpendProofsSapling`, `vSpendAuthSigsSapling`, `vOutputProofsSapling` and + // `bindingSigSapling`. + sapling_shielded_data.zcash_serialize(&mut writer)?; + + // A bundle of fields denoted in the spec as `nActionsOrchard`, `vActionsOrchard`, + // `flagsOrchard`,`valueBalanceOrchard`, `anchorOrchard`, `sizeProofsOrchard`, + // `proofsOrchard`, `vSpendAuthSigsOrchard`, and `bindingSigOrchard`. + orchard_shielded_data.zcash_serialize(&mut writer)?; + + // TODO: FIXME: add ref to spec + orchard_zsa_issue_data.zcash_serialize(&mut writer)?; + } } Ok(()) } @@ -929,6 +997,66 @@ impl ZcashDeserialize for Transaction { orchard_shielded_data, }) } + // FIXME: implement a proper deserialization for V6 + #[cfg(feature = "tx-v6")] + (6, true) => { + // FIXME: fix spec or use another link as the current version of the PDF + // doesn't contain V6 description. + // Transaction V6 spec: + // https://zips.z.cash/protocol/protocol.pdf#txnencoding + + // Denoted as `nVersionGroupId` in the spec. + let id = limited_reader.read_u32::()?; + if id != TX_V6_VERSION_GROUP_ID { + return Err(SerializationError::Parse("expected TX_V6_VERSION_GROUP_ID")); + } + // Denoted as `nConsensusBranchId` in the spec. + // Convert it to a NetworkUpgrade + let network_upgrade = + NetworkUpgrade::from_branch_id(limited_reader.read_u32::()?) + .ok_or_else(|| { + SerializationError::Parse( + "expected a valid network upgrade from the consensus branch id", + ) + })?; + + // Denoted as `lock_time` in the spec. + let lock_time = LockTime::zcash_deserialize(&mut limited_reader)?; + + // Denoted as `nExpiryHeight` in the spec. + let expiry_height = block::Height(limited_reader.read_u32::()?); + + // Denoted as `tx_in_count` and `tx_in` in the spec. + let inputs = Vec::zcash_deserialize(&mut limited_reader)?; + + // Denoted as `tx_out_count` and `tx_out` in the spec. + let outputs = Vec::zcash_deserialize(&mut limited_reader)?; + + // A bundle of fields denoted in the spec as `nSpendsSapling`, `vSpendsSapling`, + // `nOutputsSapling`,`vOutputsSapling`, `valueBalanceSapling`, `anchorSapling`, + // `vSpendProofsSapling`, `vSpendAuthSigsSapling`, `vOutputProofsSapling` and + // `bindingSigSapling`. + let sapling_shielded_data = (&mut limited_reader).zcash_deserialize_into()?; + + // A bundle of fields denoted in the spec as `nActionsOrchard`, `vActionsOrchard`, + // `flagsOrchard`,`valueBalanceOrchard`, `anchorOrchard`, `sizeProofsOrchard`, + // `proofsOrchard`, `vSpendAuthSigsOrchard`, and `bindingSigOrchard`. + let orchard_shielded_data = (&mut limited_reader).zcash_deserialize_into()?; + + // TODO: FIXME: add ref to spec + let orchard_zsa_issue_data = (&mut limited_reader).zcash_deserialize_into()?; + + Ok(Transaction::V6 { + network_upgrade, + lock_time, + expiry_height, + inputs, + outputs, + sapling_shielded_data, + orchard_shielded_data, + orchard_zsa_issue_data, + }) + } (_, _) => Err(SerializationError::Parse("bad tx header")), } } @@ -976,6 +1104,11 @@ pub const MIN_TRANSPARENT_TX_V4_SIZE: u64 = MIN_TRANSPARENT_TX_SIZE + 4; /// v5 transactions also have an expiry height and a consensus branch ID. pub const MIN_TRANSPARENT_TX_V5_SIZE: u64 = MIN_TRANSPARENT_TX_SIZE + 4 + 4; +/// The minimum transaction size for v6 transactions. +/// +/// FIXME: uncomment this and specify a proper value and description. +//pub const MIN_TRANSPARENT_TX_V6_SIZE: u64 = MIN_TRANSPARENT_TX_V5_SIZE; + /// No valid Zcash message contains more transactions than can fit in a single block /// /// `tx` messages contain a single transaction, and `block` messages are limited to the maximum diff --git a/zebra-chain/src/transaction/tests/vectors.rs b/zebra-chain/src/transaction/tests/vectors.rs index 66d5009ed05..9e0af8adf63 100644 --- a/zebra-chain/src/transaction/tests/vectors.rs +++ b/zebra-chain/src/transaction/tests/vectors.rs @@ -988,7 +988,7 @@ fn binding_signatures_for_network(network: Network) { .expect("must pass verification"); } } - Transaction::V5 { + tx_v5_and_v6! { sapling_shielded_data, .. } => { diff --git a/zebra-chain/src/transaction/txid.rs b/zebra-chain/src/transaction/txid.rs index f67f6dee58d..08172459ade 100644 --- a/zebra-chain/src/transaction/txid.rs +++ b/zebra-chain/src/transaction/txid.rs @@ -2,7 +2,7 @@ //! from the transaction. use std::io; -use super::{Hash, Transaction}; +use super::{tx_v5_and_v6, Hash, Transaction}; use crate::serialization::{sha256d, ZcashSerialize}; /// A Transaction ID builder. It computes the transaction ID by hashing @@ -28,7 +28,7 @@ impl<'a> TxIdBuilder<'a> { | Transaction::V2 { .. } | Transaction::V3 { .. } | Transaction::V4 { .. } => self.txid_v1_to_v4(), - Transaction::V5 { .. } => self.txid_v5(), + tx_v5_and_v6! { .. } => self.txid_v5_v6(), } } @@ -43,10 +43,14 @@ impl<'a> TxIdBuilder<'a> { Ok(Hash(hash_writer.finish())) } - /// Compute the Transaction ID for a V5 transaction in the given network upgrade. + // FIXME: it looks like the updated zcash_primitives in librustzcash + // auto-detects the transaction version by the first byte, so the same function + // can be used here for both V5 and V6. + // FIXME: fix spec refs below for V6 + /// Compute the Transaction ID for a V5/V6 transaction in the given network upgrade. /// In this case it's the hash of a tree of hashes of specific parts of the /// transaction, as specified in ZIP-244 and ZIP-225. - fn txid_v5(self) -> Result { + fn txid_v5_v6(self) -> Result { // The v5 txid (from ZIP-244) is computed using librustzcash. Convert the zebra // transaction to a librustzcash transaction. let alt_tx: zcash_primitives::transaction::Transaction = self.trans.try_into()?; diff --git a/zebra-chain/src/transaction/unmined.rs b/zebra-chain/src/transaction/unmined.rs index da716573e8b..ce327ae9f76 100644 --- a/zebra-chain/src/transaction/unmined.rs +++ b/zebra-chain/src/transaction/unmined.rs @@ -21,7 +21,7 @@ use crate::{ amount::{Amount, NonNegative}, serialization::ZcashSerialize, transaction::{ - AuthDigest, Hash, + tx_v5_and_v6, AuthDigest, Hash, Transaction::{self, *}, WtxId, }, @@ -140,7 +140,7 @@ impl From<&Transaction> for UnminedTxId { fn from(transaction: &Transaction) -> Self { match transaction { V1 { .. } | V2 { .. } | V3 { .. } | V4 { .. } => Legacy(transaction.into()), - V5 { .. } => Witnessed(transaction.into()), + tx_v5_and_v6! { .. } => Witnessed(transaction.into()), } } } diff --git a/zebra-consensus/Cargo.toml b/zebra-consensus/Cargo.toml index f49041d0ba1..66ebb405492 100644 --- a/zebra-consensus/Cargo.toml +++ b/zebra-consensus/Cargo.toml @@ -16,6 +16,7 @@ categories = ["asynchronous", "cryptography::cryptocurrencies"] [features] default = [] +#default = ["tx-v6"] # Production features that activate extra dependencies, or extra features in dependencies @@ -34,6 +35,12 @@ getblocktemplate-rpcs = [ # Test-only features proptest-impl = ["proptest", "proptest-derive", "zebra-chain/proptest-impl", "zebra-state/proptest-impl"] +# Support for transaction version 6 +tx-v6 = [ + "zebra-state/tx-v6", + "zebra-chain/tx-v6" +] + [dependencies] blake2b_simd = "1.0.2" bellman = "0.14.0" diff --git a/zebra-consensus/src/primitives/halo2.rs b/zebra-consensus/src/primitives/halo2.rs index ffc58a5feb8..ab88f6cbde4 100644 --- a/zebra-consensus/src/primitives/halo2.rs +++ b/zebra-consensus/src/primitives/halo2.rs @@ -19,6 +19,8 @@ use tower::{util::ServiceFn, Service}; use tower_batch_control::{Batch, BatchControl}; use tower_fallback::Fallback; +use zebra_chain::orchard::{OrchardFlavorExt, OrchardVanilla}; + use crate::BoxError; use super::{spawn_fifo, spawn_fifo_and_convert}; @@ -75,7 +77,8 @@ pub type ItemVerifyingKey = VerifyingKey; lazy_static::lazy_static! { /// The halo2 proof verifying key. - pub static ref VERIFYING_KEY: ItemVerifyingKey = ItemVerifyingKey::build(); + // FIXME: support OrchardZSA? + pub static ref VERIFYING_KEY: ItemVerifyingKey = ItemVerifyingKey::build::<::Flavor>(); } // === TEMPORARY BATCH HALO2 SUBSTITUTE === @@ -130,8 +133,8 @@ impl BatchVerifier { // === END TEMPORARY BATCH HALO2 SUBSTITUTE === -impl From<&zebra_chain::orchard::ShieldedData> for Item { - fn from(shielded_data: &zebra_chain::orchard::ShieldedData) -> Item { +impl From<&zebra_chain::orchard::ShieldedData> for Item { + fn from(shielded_data: &zebra_chain::orchard::ShieldedData) -> Item { use orchard::{circuit, note, primitives::redpallas, tree, value}; let anchor = tree::Anchor::from_bytes(shielded_data.shared_anchor.into()).unwrap(); @@ -143,6 +146,15 @@ impl From<&zebra_chain::orchard::ShieldedData> for Item { .flags .contains(zebra_chain::orchard::Flags::ENABLE_OUTPUTS); + // FIXME: simplify the flags creation - make `Flags::from_parts` method pub? + // FIXME: support OrchardZSA? + let flags = match (enable_spend, enable_output) { + (false, false) => orchard::builder::BundleType::DISABLED.flags(), + (false, true) => orchard::bundle::Flags::SPENDS_DISABLED_WITHOUT_ZSA, + (true, false) => orchard::bundle::Flags::OUTPUTS_DISABLED, + (true, true) => orchard::bundle::Flags::ENABLED_WITHOUT_ZSA, + }; + let instances = shielded_data .actions() .map(|action| { @@ -155,8 +167,7 @@ impl From<&zebra_chain::orchard::ShieldedData> for Item { )) .expect("should be a valid redpallas spendauth verification key"), note::ExtractedNoteCommitment::from_bytes(&action.cm_x.into()).unwrap(), - enable_spend, - enable_output, + flags, ) }) .collect(); diff --git a/zebra-consensus/src/primitives/halo2/tests.rs b/zebra-consensus/src/primitives/halo2/tests.rs index e654adcc546..8af73f182e1 100644 --- a/zebra-consensus/src/primitives/halo2/tests.rs +++ b/zebra-consensus/src/primitives/halo2/tests.rs @@ -11,21 +11,23 @@ use orchard::{ bundle::Flags, circuit::ProvingKey, keys::{FullViewingKey, Scope, SpendingKey}, + note::AssetBase, value::NoteValue, Anchor, Bundle, }; use rand::rngs::OsRng; use zebra_chain::{ - orchard::ShieldedData, + orchard::{OrchardFlavorExt, OrchardVanilla, ShieldedData}, serialization::{ZcashDeserializeInto, ZcashSerialize}, }; use crate::primitives::halo2::*; +// FIXME: add support for OrchardZSA (see OrchardVanilla and AssetBase::native() usage below) #[allow(dead_code, clippy::print_stdout)] fn generate_test_vectors() { - let proving_key = ProvingKey::build(); + let proving_key = ProvingKey::build::<::Flavor>(); let rng = OsRng; @@ -38,7 +40,7 @@ fn generate_test_vectors() { let anchor_bytes = [0; 32]; let note_value = 10; - let shielded_data: Vec = (1..=4) + let shielded_data: Vec> = (1..=4) .map(|num_recipients| { let mut builder = Builder::new( BundleType::Transactional { @@ -50,11 +52,18 @@ fn generate_test_vectors() { for _ in 0..num_recipients { builder - .add_output(None, recipient, NoteValue::from_raw(note_value), None) + .add_output( + None, + recipient, + NoteValue::from_raw(note_value), + AssetBase::native(), + None, + ) .unwrap(); } - let bundle: Bundle<_, i64> = builder.build(rng).unwrap().unwrap().0; + let bundle: Bundle<_, i64, ::Flavor> = + builder.build(rng).unwrap().unwrap().0; let bundle = bundle .create_proof(&proving_key, rng) @@ -62,7 +71,7 @@ fn generate_test_vectors() { .apply_signatures(rng, [0; 32], &[]) .unwrap(); - zebra_chain::orchard::ShieldedData { + zebra_chain::orchard::ShieldedData:: { flags, value_balance: note_value.try_into().unwrap(), shared_anchor: anchor_bytes.try_into().unwrap(), @@ -73,13 +82,20 @@ fn generate_test_vectors() { .actions() .iter() .map(|a| { - let action = zebra_chain::orchard::Action { + let action = zebra_chain::orchard::Action:: { cv: a.cv_net().to_bytes().try_into().unwrap(), nullifier: a.nullifier().to_bytes().try_into().unwrap(), rk: <[u8; 32]>::from(a.rk()).into(), cm_x: pallas::Base::from_repr(a.cmx().into()).unwrap(), ephemeral_key: a.encrypted_note().epk_bytes.try_into().unwrap(), - enc_ciphertext: a.encrypted_note().enc_ciphertext.into(), + // FIXME: support OrchardZSA too, 580 works for OrchardVanilla only! + // FIXME: consider more "type safe" way to do the following conversion + // (now it goes through &[u8]) + enc_ciphertext: <[u8; OrchardVanilla::ENCRYPTED_NOTE_SIZE]>::try_from( + a.encrypted_note().enc_ciphertext.as_ref(), + ) + .unwrap() + .into(), out_ciphertext: a.encrypted_note().out_ciphertext.into(), }; zebra_chain::orchard::shielded_data::AuthorizedAction { @@ -91,6 +107,9 @@ fn generate_test_vectors() { .try_into() .unwrap(), binding_sig: <[u8; 64]>::from(bundle.authorization().binding_signature()).into(), + // FIXME: use a proper value when implementing V6 + #[cfg(feature = "tx-v6")] + burn: Default::default(), } }) .collect(); @@ -105,7 +124,7 @@ fn generate_test_vectors() { async fn verify_orchard_halo2_proofs( verifier: &mut V, - shielded_data: Vec, + shielded_data: Vec>, ) -> Result<(), V::Error> where V: tower::Service, @@ -138,9 +157,10 @@ async fn verify_generated_halo2_proofs() { .clone() .iter() .map(|bytes| { - let maybe_shielded_data: Option = bytes - .zcash_deserialize_into() - .expect("a valid orchard::ShieldedData instance"); + let maybe_shielded_data: Option> = + bytes + .zcash_deserialize_into() + .expect("a valid orchard::ShieldedData instance"); maybe_shielded_data.unwrap() }) .collect(); @@ -167,7 +187,7 @@ async fn verify_generated_halo2_proofs() { async fn verify_invalid_orchard_halo2_proofs( verifier: &mut V, - shielded_data: Vec, + shielded_data: Vec>, ) -> Result<(), V::Error> where V: tower::Service, @@ -205,9 +225,10 @@ async fn correctly_err_on_invalid_halo2_proofs() { .clone() .iter() .map(|bytes| { - let maybe_shielded_data: Option = bytes - .zcash_deserialize_into() - .expect("a valid orchard::ShieldedData instance"); + let maybe_shielded_data: Option> = + bytes + .zcash_deserialize_into() + .expect("a valid orchard::ShieldedData instance"); maybe_shielded_data.unwrap() }) .collect(); diff --git a/zebra-consensus/src/transaction.rs b/zebra-consensus/src/transaction.rs index 1c303003615..e91f576f2a5 100644 --- a/zebra-consensus/src/transaction.rs +++ b/zebra-consensus/src/transaction.rs @@ -405,7 +405,8 @@ where sapling_shielded_data, orchard_shielded_data, .. - } => Self::verify_v5_transaction( + } + => Self::verify_v5_transaction( &req, &network, script_verifier, @@ -413,6 +414,14 @@ where sapling_shielded_data, orchard_shielded_data, )?, + // FIXME: implement proper V6 verification + #[cfg(feature = "tx-v6")] + Transaction::V6 { + .. + } => { + tracing::debug!(?tx, "V6 transaction verification is not supported for now"); + return Err(TransactionError::WrongVersion); + } }; if let Some(unmined_tx) = req.mempool_transaction() { @@ -716,7 +725,7 @@ where script_verifier: script::Verifier, cached_ffi_transaction: Arc, sapling_shielded_data: &Option>, - orchard_shielded_data: &Option, + orchard_shielded_data: &Option>, ) -> Result { let transaction = request.transaction(); let upgrade = request.upgrade(network); @@ -1013,7 +1022,7 @@ where /// Verifies a transaction's Orchard shielded data. fn verify_orchard_shielded_data( - orchard_shielded_data: &Option, + orchard_shielded_data: &Option>, shielded_sighash: &SigHash, ) -> Result { let mut async_checks = AsyncChecks::new(); diff --git a/zebra-consensus/src/transaction/check.rs b/zebra-consensus/src/transaction/check.rs index 66e3d0be595..133c7e80470 100644 --- a/zebra-consensus/src/transaction/check.rs +++ b/zebra-consensus/src/transaction/check.rs @@ -172,8 +172,8 @@ pub fn coinbase_tx_no_prevout_joinsplit_spend(tx: &Transaction) -> Result<(), Tr return Err(TransactionError::CoinbaseHasSpend); } - if let Some(orchard_shielded_data) = tx.orchard_shielded_data() { - if orchard_shielded_data.flags.contains(Flags::ENABLE_SPENDS) { + if let Some(orchard_flags) = tx.orchard_flags() { + if orchard_flags.contains(Flags::ENABLE_SPENDS) { return Err(TransactionError::CoinbaseHasEnableSpendsOrchard); } } diff --git a/zebra-consensus/src/transaction/tests.rs b/zebra-consensus/src/transaction/tests.rs index 0a4c21bb039..5494537edb8 100644 --- a/zebra-consensus/src/transaction/tests.rs +++ b/zebra-consensus/src/transaction/tests.rs @@ -12,7 +12,7 @@ use tower::{service_fn, ServiceExt}; use zebra_chain::{ amount::{Amount, NonNegative}, block::{self, Block, Height}, - orchard::AuthorizedAction, + orchard::{AuthorizedAction, OrchardVanilla}, parameters::{Network, NetworkUpgrade}, primitives::{ed25519, x25519, Groth16Proof}, sapling, @@ -2830,9 +2830,9 @@ fn coinbase_outputs_are_decryptable_for_historical_blocks_for_network( /// Given an Orchard action as a base, fill fields related to note encryption /// from the given test vector and returned the modified action. fn fill_action_with_note_encryption_test_vector( - action: &zebra_chain::orchard::Action, + action: &zebra_chain::orchard::Action, v: &zebra_test::vectors::TestVector, -) -> zebra_chain::orchard::Action { +) -> zebra_chain::orchard::Action { let mut action = action.clone(); action.cv = v.cv_net.try_into().expect("test vector must be valid"); action.cm_x = pallas::Base::from_repr(v.cmx).unwrap(); diff --git a/zebra-rpc/qa/rpc-tests/test_framework/mininode.py b/zebra-rpc/qa/rpc-tests/test_framework/mininode.py index d56fb8bf79c..2fbe6faca89 100755 --- a/zebra-rpc/qa/rpc-tests/test_framework/mininode.py +++ b/zebra-rpc/qa/rpc-tests/test_framework/mininode.py @@ -425,6 +425,7 @@ def __repr__(self): return "RedPallasSignature(%s)" % bytes_to_hex_str(self.data) +# FIXME: add support of OrchardZSA class OrchardAction(object): def __init__(self): self.cv = None @@ -441,7 +442,7 @@ def deserialize(self, f): self.rk = deser_uint256(f) self.cmx = deser_uint256(f) self.ephemeralKey = deser_uint256(f) - self.encCiphertext = f.read(580) + self.encCiphertext = f.read(580) # FIXME: works for OrchardVanilla only self.outCiphertext = f.read(80) def serialize(self): diff --git a/zebra-scan/Cargo.toml b/zebra-scan/Cargo.toml index 8ef7cae2577..7d02a4ae81b 100644 --- a/zebra-scan/Cargo.toml +++ b/zebra-scan/Cargo.toml @@ -72,10 +72,10 @@ futures = "0.3.30" # ECC dependencies. # TODO: we can't use the workspace version for all ECC dependencies in this crate yet (#8809) -zcash_client_backend = { git = "https://github.com/zcash/librustzcash/", commit = "40ca428c6081c61d5a2bf3f2053eb9e18219ca95" } +zcash_client_backend = { version = "0.12.1" } zcash_keys = { workspace = true, features = ["sapling"] } -zcash_primitives = { git = "https://github.com/zcash/librustzcash/", commit = "40ca428c6081c61d5a2bf3f2053eb9e18219ca95" } -zcash_address = { git = "https://github.com/zcash/librustzcash/", commit = "40ca428c6081c61d5a2bf3f2053eb9e18219ca95" } +zcash_primitives = "0.15.0" +zcash_address = "0.3.2" sapling-crypto.workspace = true zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.39", features = ["shielded-scan"] } diff --git a/zebra-state/Cargo.toml b/zebra-state/Cargo.toml index db14f448c4b..1cabe066258 100644 --- a/zebra-state/Cargo.toml +++ b/zebra-state/Cargo.toml @@ -15,6 +15,8 @@ keywords = ["zebra", "zcash"] categories = ["asynchronous", "caching", "cryptography::cryptocurrencies"] [features] +default = [] +#default = ["tx-v6"] # Production features that activate extra dependencies, or extra features in dependencies @@ -45,6 +47,11 @@ elasticsearch = [ "zebra-chain/elasticsearch", ] +# Support for transaction version 6 +tx-v6 = [ + "zebra-chain/tx-v6" +] + [dependencies] bincode = "1.3.3" chrono = { version = "0.4.38", default-features = false, features = ["clock", "std"] } diff --git a/zebra-state/src/service/check/anchors.rs b/zebra-state/src/service/check/anchors.rs index 5f6ee293e34..b4a53c8f176 100644 --- a/zebra-state/src/service/check/anchors.rs +++ b/zebra-state/src/service/check/anchors.rs @@ -88,25 +88,21 @@ fn sapling_orchard_anchors_refer_to_final_treestates( // > earlier block’s final Orchard treestate. // // - if let Some(orchard_shielded_data) = transaction.orchard_shielded_data() { + if let Some(shared_anchor) = transaction.orchard_shared_anchor() { tracing::debug!( - ?orchard_shielded_data.shared_anchor, + ?shared_anchor, ?tx_index_in_block, ?height, "observed orchard anchor", ); if !parent_chain - .map(|chain| { - chain - .orchard_anchors - .contains(&orchard_shielded_data.shared_anchor) - }) + .map(|chain| chain.orchard_anchors.contains(&shared_anchor)) .unwrap_or(false) - && !finalized_state.contains_orchard_anchor(&orchard_shielded_data.shared_anchor) + && !finalized_state.contains_orchard_anchor(&shared_anchor) { return Err(ValidateContextError::UnknownOrchardAnchor { - anchor: orchard_shielded_data.shared_anchor, + anchor: shared_anchor, height, tx_index_in_block, transaction_hash, @@ -114,7 +110,7 @@ fn sapling_orchard_anchors_refer_to_final_treestates( } tracing::debug!( - ?orchard_shielded_data.shared_anchor, + ?shared_anchor, ?tx_index_in_block, ?height, "validated orchard anchor", diff --git a/zebra-state/src/service/check/tests/nullifier.rs b/zebra-state/src/service/check/tests/nullifier.rs index 0392f1c8e79..8a8b17e4fd0 100644 --- a/zebra-state/src/service/check/tests/nullifier.rs +++ b/zebra-state/src/service/check/tests/nullifier.rs @@ -700,8 +700,8 @@ proptest! { /// (And that the test infrastructure generally works.) #[test] fn accept_distinct_arbitrary_orchard_nullifiers_in_one_block( - authorized_action in TypeNameToDebug::::arbitrary(), - orchard_shielded_data in TypeNameToDebug::::arbitrary(), + authorized_action in TypeNameToDebug::>::arbitrary(), + orchard_shielded_data in TypeNameToDebug::>::arbitrary(), use_finalized_state in any::(), ) { let _init_guard = zebra_test::init(); @@ -759,9 +759,9 @@ proptest! { /// if they come from different AuthorizedActions in the same orchard::ShieldedData/Transaction. #[test] fn reject_duplicate_orchard_nullifiers_in_transaction( - authorized_action1 in TypeNameToDebug::::arbitrary(), - mut authorized_action2 in TypeNameToDebug::::arbitrary(), - orchard_shielded_data in TypeNameToDebug::::arbitrary(), + authorized_action1 in TypeNameToDebug::>::arbitrary(), + mut authorized_action2 in TypeNameToDebug::>::arbitrary(), + orchard_shielded_data in TypeNameToDebug::>::arbitrary(), ) { let _init_guard = zebra_test::init(); @@ -812,10 +812,10 @@ proptest! { /// if they come from different transactions in the same block. #[test] fn reject_duplicate_orchard_nullifiers_in_block( - authorized_action1 in TypeNameToDebug::::arbitrary(), - mut authorized_action2 in TypeNameToDebug::::arbitrary(), - orchard_shielded_data1 in TypeNameToDebug::::arbitrary(), - orchard_shielded_data2 in TypeNameToDebug::::arbitrary(), + authorized_action1 in TypeNameToDebug::>::arbitrary(), + mut authorized_action2 in TypeNameToDebug::>::arbitrary(), + orchard_shielded_data1 in TypeNameToDebug::>::arbitrary(), + orchard_shielded_data2 in TypeNameToDebug::>::arbitrary(), ) { let _init_guard = zebra_test::init(); @@ -872,10 +872,10 @@ proptest! { /// if they come from different blocks in the same chain. #[test] fn reject_duplicate_orchard_nullifiers_in_chain( - authorized_action1 in TypeNameToDebug::::arbitrary(), - mut authorized_action2 in TypeNameToDebug::::arbitrary(), - orchard_shielded_data1 in TypeNameToDebug::::arbitrary(), - orchard_shielded_data2 in TypeNameToDebug::::arbitrary(), + authorized_action1 in TypeNameToDebug::>::arbitrary(), + mut authorized_action2 in TypeNameToDebug::>::arbitrary(), + orchard_shielded_data1 in TypeNameToDebug::>::arbitrary(), + orchard_shielded_data2 in TypeNameToDebug::>::arbitrary(), duplicate_in_finalized_state in any::(), ) { let _init_guard = zebra_test::init(); @@ -1126,8 +1126,8 @@ fn transaction_v4_with_sapling_shielded_data( /// /// If there are no `AuthorizedAction`s in `authorized_actions`. fn transaction_v5_with_orchard_shielded_data( - orchard_shielded_data: impl Into>, - authorized_actions: impl IntoIterator, + orchard_shielded_data: impl Into>>, + authorized_actions: impl IntoIterator>, ) -> Transaction { let mut orchard_shielded_data = orchard_shielded_data.into(); let authorized_actions: Vec<_> = authorized_actions.into_iter().collect(); diff --git a/zebra-state/src/service/check/utxo.rs b/zebra-state/src/service/check/utxo.rs index 324efa3c035..b856a616dd5 100644 --- a/zebra-state/src/service/check/utxo.rs +++ b/zebra-state/src/service/check/utxo.rs @@ -63,6 +63,7 @@ pub fn transparent_spend( finalized_state, )?; + // FIXME: what about v6? // The state service returns UTXOs from pending blocks, // which can be rejected by later contextual checks. // This is a particular issue for v5 transactions, diff --git a/zebra-state/src/service/finalized_state/zebra_db/arbitrary.rs b/zebra-state/src/service/finalized_state/zebra_db/arbitrary.rs index bbe0e026d8c..39bf082d43d 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/arbitrary.rs +++ b/zebra-state/src/service/finalized_state/zebra_db/arbitrary.rs @@ -66,8 +66,8 @@ impl ZebraDb { } // Orchard - if let Some(orchard_shielded_data) = transaction.orchard_shielded_data() { - batch.zs_insert(&orchard_anchors, orchard_shielded_data.shared_anchor, ()); + if let Some(shared_anchor) = transaction.orchard_shared_anchor() { + batch.zs_insert(&orchard_anchors, shared_anchor, ()); } } diff --git a/zebra-state/src/service/non_finalized_state/chain.rs b/zebra-state/src/service/non_finalized_state/chain.rs index 12ee0528776..190f8b1a930 100644 --- a/zebra-state/src/service/non_finalized_state/chain.rs +++ b/zebra-state/src/service/non_finalized_state/chain.rs @@ -1521,6 +1521,22 @@ impl Chain { sapling_shielded_data, orchard_shielded_data, ), + #[cfg(feature ="tx-v6")] + V6 { + inputs, + outputs, + sapling_shielded_data, + orchard_shielded_data: _, + .. + } => ( + inputs, + outputs, + &None, + &None, + sapling_shielded_data, + // FIXME: support V6 shielded data? + &None, //orchard_shielded_data, + ), V1 { .. } | V2 { .. } | V3 { .. } => unreachable!( "older transaction versions only exist in finalized blocks, because of the mandatory canopy checkpoint", ), @@ -1682,6 +1698,22 @@ impl UpdateWith for Chain { sapling_shielded_data, orchard_shielded_data, ), + #[cfg(feature = "tx-v6")] + V6 { + inputs, + outputs, + sapling_shielded_data, + orchard_shielded_data: _, + .. + } => ( + inputs, + outputs, + &None, + &None, + sapling_shielded_data, + // FIXME: support V6 shielded data? + &None, //orchard_shielded_data, + ), V1 { .. } | V2 { .. } | V3 { .. } => unreachable!( "older transaction versions only exist in finalized blocks, because of the mandatory canopy checkpoint", ), @@ -2017,11 +2049,11 @@ where } } -impl UpdateWith> for Chain { +impl UpdateWith>> for Chain { #[instrument(skip(self, orchard_shielded_data))] fn update_chain_tip_with( &mut self, - orchard_shielded_data: &Option, + orchard_shielded_data: &Option>, ) -> Result<(), ValidateContextError> { if let Some(orchard_shielded_data) = orchard_shielded_data { // We do note commitment tree updates in parallel rayon threads. @@ -2042,7 +2074,7 @@ impl UpdateWith> for Chain { #[instrument(skip(self, orchard_shielded_data))] fn revert_chain_with( &mut self, - orchard_shielded_data: &Option, + orchard_shielded_data: &Option>, _position: RevertPosition, ) { if let Some(orchard_shielded_data) = orchard_shielded_data { diff --git a/zebra-state/src/tests.rs b/zebra-state/src/tests.rs index 488ab4227bd..d01a871f142 100644 --- a/zebra-state/src/tests.rs +++ b/zebra-state/src/tests.rs @@ -34,6 +34,8 @@ impl FakeChainHelper for Arc { Transaction::V3 { inputs, .. } => &mut inputs[0], Transaction::V4 { inputs, .. } => &mut inputs[0], Transaction::V5 { inputs, .. } => &mut inputs[0], + #[cfg(feature = "tx-v6")] + Transaction::V6 { inputs, .. } => &mut inputs[0], }; match input { diff --git a/zebra-test/src/vectors/orchard_note_encryption.rs b/zebra-test/src/vectors/orchard_note_encryption.rs index ff52b661b53..84b576df5c3 100644 --- a/zebra-test/src/vectors/orchard_note_encryption.rs +++ b/zebra-test/src/vectors/orchard_note_encryption.rs @@ -1,6 +1,7 @@ //! Contains test vectors for Orchard note encryptions. use lazy_static::lazy_static; +// FIXME: add tests for OrchardZSA #[allow(missing_docs)] pub struct TestVector { pub incoming_viewing_key: [u8; 64], @@ -18,7 +19,7 @@ pub struct TestVector { pub shared_secret: [u8; 32], pub k_enc: [u8; 32], pub p_enc: [u8; 564], - pub c_enc: [u8; 580], + pub c_enc: [u8; 580], // FIXME: works for OrchardVanilla only! pub ock: [u8; 32], pub op: [u8; 64], pub c_out: [u8; 80], diff --git a/zebrad/Cargo.toml b/zebrad/Cargo.toml index 6b4f2cfec8d..2df700dfc57 100644 --- a/zebrad/Cargo.toml +++ b/zebrad/Cargo.toml @@ -52,7 +52,8 @@ features = [ [features] # In release builds, don't compile debug logging code, to improve performance. -default = ["release_max_level_info", "progress-bar", "getblocktemplate-rpcs"] +#default = ["release_max_level_info", "progress-bar", "getblocktemplate-rpcs"] +default = ["release_max_level_info", "progress-bar", "getblocktemplate-rpcs", "tx-v6"] # Default features for official ZF binary release builds default-release-binaries = ["default", "sentry"] @@ -156,6 +157,13 @@ test_sync_to_mandatory_checkpoint_testnet = [] test_sync_past_mandatory_checkpoint_mainnet = [] test_sync_past_mandatory_checkpoint_testnet = [] +# Support for transaction version 6 +tx-v6 = [ + "zebra-consensus/tx-v6", + "zebra-state/tx-v6", + "zebra-chain/tx-v6" +] + [dependencies] zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.39" } zebra-consensus = { path = "../zebra-consensus", version = "1.0.0-beta.39" } diff --git a/zebrad/src/components/mempool/storage/tests/prop.rs b/zebrad/src/components/mempool/storage/tests/prop.rs index eca65935acb..d3ef954063d 100644 --- a/zebrad/src/components/mempool/storage/tests/prop.rs +++ b/zebrad/src/components/mempool/storage/tests/prop.rs @@ -446,6 +446,7 @@ enum SpendConflictTestInput { conflict: SpendConflictForTransactionV5, }, + // FIXME: add and use V6? } impl SpendConflictTestInput { @@ -568,6 +569,10 @@ impl SpendConflictTestInput { // No JoinSplits Transaction::V1 { .. } | Transaction::V5 { .. } => {} + + // No JoinSplits + #[cfg(feature = "tx-v6")] + Transaction::V6 { .. } => {} } } } @@ -638,6 +643,14 @@ impl SpendConflictTestInput { Self::remove_sapling_transfers_with_conflicts(sapling_shielded_data, &conflicts) } + #[cfg(feature = "tx-v6")] + Transaction::V6 { + sapling_shielded_data, + .. + } => { + Self::remove_sapling_transfers_with_conflicts(sapling_shielded_data, &conflicts) + } + // No Spends Transaction::V1 { .. } | Transaction::V2 { .. } | Transaction::V3 { .. } => {} } @@ -709,6 +722,13 @@ impl SpendConflictTestInput { .. } => Self::remove_orchard_actions_with_conflicts(orchard_shielded_data, &conflicts), + // FIXME: implement for V6 + #[cfg(feature = "tx-v6")] + Transaction::V6 { + orchard_shielded_data: _, + .. + } => {} + // No Spends Transaction::V1 { .. } | Transaction::V2 { .. } @@ -723,7 +743,7 @@ impl SpendConflictTestInput { /// /// This may clear the entire shielded data. fn remove_orchard_actions_with_conflicts( - maybe_shielded_data: &mut Option, + maybe_shielded_data: &mut Option>, conflicts: &HashSet, ) { if let Some(shielded_data) = maybe_shielded_data.take() { @@ -780,10 +800,11 @@ struct SaplingSpendConflict { fallback_shielded_data: DisplayToDebug>, } +// FIXME: make it a generic to support V6 /// A conflict caused by revealing the same Orchard nullifier. #[derive(Arbitrary, Clone, Debug)] struct OrchardSpendConflict { - new_shielded_data: DisplayToDebug, + new_shielded_data: DisplayToDebug>, } impl SpendConflictForTransactionV4 { @@ -929,7 +950,10 @@ impl OrchardSpendConflict { /// the new action is inserted in the transaction. /// /// The transaction will then conflict with any other transaction with the same new nullifier. - pub fn apply_to(self, orchard_shielded_data: &mut Option) { + pub fn apply_to( + self, + orchard_shielded_data: &mut Option>, + ) { if let Some(shielded_data) = orchard_shielded_data.as_mut() { shielded_data.actions.first_mut().action.nullifier = self.new_shielded_data.actions.first().action.nullifier;