diff --git a/Cargo.lock b/Cargo.lock index 4dde581..bac9ce7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -252,17 +252,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "addchain" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5665045de74fda906c0abfaec40cf2551f88c34dccea869f3fe950dde7209764" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "adler2" version = "2.0.1" @@ -279,6 +268,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "aead" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99" +dependencies = [ + "crypto-common 0.2.2", + "inout 0.2.5", +] + [[package]] name = "aes" version = "0.8.4" @@ -286,8 +285,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", - "cipher", - "cpufeatures", + "cipher 0.4.4", + "cpufeatures 0.2.17", +] + +[[package]] +name = "aes" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fc36d7440d015b45468ba08a21e80e056ebbd014c611c6298bb7503e04bd1" +dependencies = [ + "cipher 0.5.2", + "cpubits", + "cpufeatures 0.3.1", ] [[package]] @@ -296,9 +306,9 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ - "aead", - "aes", - "cipher", + "aead 0.5.2", + "aes 0.8.4", + "cipher 0.4.4", "ctr", "ghash", "subtle", @@ -410,15 +420,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - [[package]] name = "atomic-waker" version = "1.1.2" @@ -431,12 +432,6 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - [[package]] name = "base64" version = "0.21.7" @@ -472,22 +467,6 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f" -[[package]] -name = "bip32" -version = "0.6.0-pre.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143f5327f23168716be068f8e1014ba2ea16a6c91e8777bc8927da7b51e1df1f" -dependencies = [ - "bs58", - "hmac 0.13.0-pre.4", - "rand_core 0.6.4", - "ripemd 0.2.0-pre.4", - "secp256k1", - "sha2 0.11.0-pre.4", - "subtle", - "zeroize", -] - [[package]] name = "bitflags" version = "2.13.1" @@ -497,18 +476,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "bitvec" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "blake2b_simd" version = "1.0.5" @@ -540,11 +507,12 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.11.0-rc.3" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd016a0ddc7cb13661bf5576073ce07330a693f8608a1320b4e20561cc12cdc" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ "hybrid-array", + "zeroize", ] [[package]] @@ -562,7 +530,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ - "sha2 0.10.9", + "sha2", "tinyvec", ] @@ -607,11 +575,11 @@ dependencies = [ [[package]] name = "cbc" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +checksum = "ce2dc9ee5f88d11e0beb842c88b33c8a5cf0d1329c4b19494af42b07dbfe8896" dependencies = [ - "cipher", + "cipher 0.5.2", ] [[package]] @@ -632,24 +600,25 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chacha20" -version = "0.9.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" dependencies = [ "cfg-if", - "cipher", - "cpufeatures", + "cipher 0.5.2", + "cpufeatures 0.3.1", + "zeroize", ] [[package]] name = "chacha20poly1305" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +checksum = "9b89e1c441e926b9c82a8d023f6e1b7ae0adcfaa7d621814e4d60789bac751cb" dependencies = [ - "aead", + "aead 0.6.1", "chacha20", - "cipher", + "cipher 0.5.2", "poly1305", "zeroize", ] @@ -675,7 +644,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common 0.1.7", - "inout", + "inout 0.1.4", +] + +[[package]] +name = "cipher" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", + "inout 0.2.5", "zeroize", ] @@ -698,7 +678,7 @@ dependencies = [ "ed25519-dalek", "futures", "hex", - "hmac 0.12.1", + "hmac", "image", "qrcode", "rand 0.8.8", @@ -706,7 +686,7 @@ dependencies = [ "serde", "serde_json", "serde_json_canonicalizer", - "sha2 0.10.9", + "sha2", "sha3", "sqlx", "subtle", @@ -718,27 +698,18 @@ dependencies = [ "url", "uuid", "webauthn-rs", + "zakura-address", + "zakura-note-encryption", "zakura-orchard", "zakura-primitives", - "zcash_address", - "zcash_note_encryption", - "zcash_protocol", + "zakura-protocol", ] [[package]] -name = "cobs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror 2.0.20", -] - -[[package]] -name = "const-crc32-nostd" -version = "1.3.1" +name = "cmov" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808ac43170e95b11dd23d78aa9eaac5bea45776a602955552c4e833f3f0f823d" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" [[package]] name = "const-oid" @@ -810,6 +781,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4df6f98652d30167eaeea34d77b730e07c8caba6df17bd4551842b9b8da01deb" +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -819,6 +796,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.4.0" @@ -843,12 +829,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - [[package]] name = "crossbeam-queue" version = "0.3.14" @@ -883,9 +863,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.2.0-rc.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0b8ce8218c97789f16356e7896b3714f26c2ee1079b79c0b7ae7064bb9089fa" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ "hybrid-array", ] @@ -917,7 +897,16 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ - "cipher", + "cipher 0.4.4", +] + +[[package]] +name = "ctutils" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261af4dc7a06ea8a527a8717d8cbba3417530d6ea14e1edb3de6b67806be474f" +dependencies = [ + "cmov", ] [[package]] @@ -927,9 +916,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "curve25519-dalek-derive", - "digest 0.10.7", + "digest", "fiat-crypto", "rustc_version", "subtle", @@ -987,7 +976,7 @@ dependencies = [ "asn1-rs", "displaydoc", "nom", - "num-bigint", + "num-bigint 0.4.8", "num-traits", "rusticata-macros", ] @@ -998,17 +987,6 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" -[[package]] -name = "derive-getters" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ef43543e701c01ad77d3a5922755c6a1d71b22d942cb8042be4994b380caff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "derive_more" version = "2.1.1" @@ -1044,17 +1022,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "digest" -version = "0.11.0-pre.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2e3d6615d99707295a9673e889bf363a04b2a466bd320c65a72536f7577379" -dependencies = [ - "block-buffer 0.11.0-rc.3", - "crypto-common 0.2.0-rc.1", - "subtle", -] - [[package]] name = "displaydoc" version = "0.2.7" @@ -1066,15 +1033,6 @@ dependencies = [ "syn 3.0.5", ] -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] - [[package]] name = "dotenvy" version = "0.15.7" @@ -1100,7 +1058,7 @@ dependencies = [ "curve25519-dalek", "ed25519", "serde", - "sha2 0.10.9", + "sha2", "subtle", "zeroize", ] @@ -1114,18 +1072,6 @@ dependencies = [ "serde", ] -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - [[package]] name = "encoding_rs" version = "0.8.40" @@ -1141,16 +1087,6 @@ dependencies = [ "simdutf8", ] -[[package]] -name = "equihash" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306286e8dcc39ab3dfceb74c792ce8baffdab90591321d3ffaae64829734c37f" -dependencies = [ - "blake2b_simd", - "corez", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -1164,7 +1100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1188,15 +1124,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "f4jumble" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d42773cb15447644d170be20231a3268600e0c4cea8987d013b93ac973d3cf7" -dependencies = [ - "blake2b_simd", -] - [[package]] name = "fastrand" version = "2.5.0" @@ -1218,27 +1145,10 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1f686ab92a9fb0eaf188f6c6c87b89490baa6fdb0db4544ba4dc47f7942489f" dependencies = [ - "bitvec", - "ff_derive", "rand_core 0.10.1", "subtle", ] -[[package]] -name = "ff_derive" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241afe8c15ffa21933eaefe8a563af36fd9fc98a3e8a044e8f7db52eb1fae3d8" -dependencies = [ - "addchain", - "num-bigint", - "num-integer", - "num-traits", - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "fiat-crypto" version = "0.2.9" @@ -1311,59 +1221,18 @@ dependencies = [ [[package]] name = "fpe" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c4b37de5ae15812a764c958297cfc50f5c010438f60c6ce75d11b802abd404" +checksum = "5045d51a6a5e85e0a18d909eedd270c4d82ad634fee57ba707692fb3b1add5a7" dependencies = [ "cbc", - "cipher", + "cipher 0.5.2", "libm", - "num-bigint", + "num-bigint 0.5.1", "num-integer", "num-traits", ] -[[package]] -name = "frost-core" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ef2787af391c7e8bedc037a3b9ea03dde803fbd93e778e6bb369547800e5cd" -dependencies = [ - "byteorder", - "const-crc32-nostd", - "derive-getters", - "document-features", - "hex", - "itertools", - "postcard", - "rand_core 0.6.4", - "serde", - "serdect", - "thiserror 2.0.20", - "visibility", - "zeroize", - "zeroize_derive", -] - -[[package]] -name = "frost-rerandomized" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4c5cedd2426728adef2c0b1720f57676354c473836d1ccc50d0f0d1c91942b" -dependencies = [ - "derive-getters", - "document-features", - "frost-core", - "hex", - "rand_core 0.6.4", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - [[package]] name = "futures" version = "0.3.34" @@ -1562,7 +1431,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fd1a1c7a5206c5b7a3f5a0d7ccd3ff85d0c8f5133d62a02680255b0004af5f4" dependencies = [ "ff", - "memuse", "rand_core 0.10.1", "subtle", ] @@ -1597,15 +1465,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - [[package]] name = "hashbrown" version = "0.14.5" @@ -1638,20 +1497,6 @@ dependencies = [ "hashbrown 0.15.5", ] -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin", - "stable_deref_trait", -] - [[package]] name = "heck" version = "0.5.0" @@ -1670,7 +1515,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac 0.12.1", + "hmac", ] [[package]] @@ -1679,16 +1524,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "hmac" -version = "0.13.0-pre.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4b1fb14e4df79f9406b434b60acef9f45c26c50062cccf1346c6103b8c47d58" -dependencies = [ - "digest 0.11.0-pre.9", + "digest", ] [[package]] @@ -1758,11 +1594,12 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hybrid-array" -version = "0.2.3" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d35805454dc9f8662a98d6d61886ffe26bd465f5960e0e55345c70d5c0d2a9" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" dependencies = [ "typenum", + "zeroize", ] [[package]] @@ -2017,6 +1854,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "inout" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b5cf4372d022092674a83b8febf5865f7a573cc0c5baec5e49c879b6a20978f" +dependencies = [ + "hybrid-array", +] + [[package]] name = "ipnet" version = "2.12.2" @@ -2055,7 +1901,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", ] [[package]] @@ -2120,12 +1966,6 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - [[package]] name = "local-channel" version = "0.1.5" @@ -2174,7 +2014,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest 0.10.7", + "digest", ] [[package]] @@ -2335,6 +2175,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e7820bc0a80a0238e650327316f929ba18d5be054b647490a3a6a339f3e7c0" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-bigint-dig" version = "0.8.6" @@ -2554,13 +2404,12 @@ dependencies = [ [[package]] name = "poly1305" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +checksum = "6e2d0073b297041425c7c3df6eb4792d598a15323fe63346852b092eca02904c" dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", + "cpufeatures 0.3.1", + "universal-hash 0.6.1", ] [[package]] @@ -2570,9 +2419,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "opaque-debug", - "universal-hash", + "universal-hash 0.5.1", ] [[package]] @@ -2581,19 +2430,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" -[[package]] -name = "postcard" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "heapless", - "serde", -] - [[package]] name = "potential_utf" version = "0.1.6" @@ -2618,6 +2454,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.107" @@ -2678,12 +2523,6 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - [[package]] name = "rand" version = "0.8.8" @@ -2880,16 +2719,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "ripemd" -version = "0.2.0-pre.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48cf93482ea998ad1302c42739bc73ab3adc574890c373ec89710e219357579" -dependencies = [ - "digest 0.11.0-pre.9", + "digest", ] [[package]] @@ -2899,7 +2729,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ "const-oid", - "digest 0.10.7", + "digest", "num-bigint-dig", "num-integer", "num-traits", @@ -2940,7 +2770,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3009,24 +2839,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "secp256k1" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" -dependencies = [ - "secp256k1-sys", -] - -[[package]] -name = "secp256k1-sys" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" -dependencies = [ - "cc", -] - [[package]] name = "security-framework" version = "3.7.0" @@ -3156,16 +2968,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serdect" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" -dependencies = [ - "base16ct", - "serde", -] - [[package]] name = "sha1" version = "0.10.7" @@ -3173,8 +2975,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if", - "cpufeatures", - "digest 0.10.7", + "cpufeatures 0.2.17", + "digest", ] [[package]] @@ -3184,19 +2986,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha2" -version = "0.11.0-pre.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "540c0893cce56cdbcfebcec191ec8e0f470dd1889b6e7a0b503e310a94a168f5" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.11.0-pre.9", + "cpufeatures 0.2.17", + "digest", ] [[package]] @@ -3205,7 +2996,7 @@ version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" dependencies = [ - "digest 0.10.7", + "digest", "keccak", ] @@ -3240,7 +3031,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest 0.10.7", + "digest", "rand_core 0.6.4", ] @@ -3348,7 +3139,7 @@ dependencies = [ "percent-encoding", "serde", "serde_json", - "sha2 0.10.9", + "sha2", "smallvec", "thiserror 2.0.20", "tokio", @@ -3386,7 +3177,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2 0.10.9", + "sha2", "sqlx-core", "sqlx-mysql", "sqlx-postgres", @@ -3409,7 +3200,7 @@ dependencies = [ "bytes", "chrono", "crc", - "digest 0.10.7", + "digest", "dotenvy", "either", "futures-channel", @@ -3419,7 +3210,7 @@ dependencies = [ "generic-array", "hex", "hkdf", - "hmac 0.12.1", + "hmac", "itoa", "log", "md-5", @@ -3430,7 +3221,7 @@ dependencies = [ "rsa", "serde", "sha1", - "sha2 0.10.9", + "sha2", "smallvec", "sqlx-core", "stringprep", @@ -3459,7 +3250,7 @@ dependencies = [ "futures-util", "hex", "hkdf", - "hmac 0.12.1", + "hmac", "home", "itoa", "log", @@ -3469,7 +3260,7 @@ dependencies = [ "rand 0.8.8", "serde", "serde_json", - "sha2 0.10.9", + "sha2", "smallvec", "sqlx-core", "stringprep", @@ -3597,12 +3388,6 @@ dependencies = [ "libc", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "target-features" version = "0.1.6" @@ -3616,10 +3401,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3813,6 +3598,36 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml_datetime" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.18+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec6e78bd70db9420d8d212fa9dc97f116448a1ceff5d00eabb991d407e21396" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" +dependencies = [ + "winnow", +] + [[package]] name = "tower" version = "0.5.3" @@ -3999,6 +3814,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "universal-hash" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96" +dependencies = [ + "crypto-common 0.2.2", + "ctutils", +] + [[package]] name = "untrusted" version = "0.9.0" @@ -4060,17 +3885,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.119", -] - [[package]] name = "want" version = "0.3.1" @@ -4484,6 +4298,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3b93199df0ab874cdf0c6a94f0a0dc3423fe41f1cafb62b8bd7b1deb277aef" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen" version = "0.57.1" @@ -4496,15 +4319,6 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - [[package]] name = "x509-parser" version = "0.16.0" @@ -4545,11 +4359,53 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zakura-address" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c7f5722bca853575df47323f7c3445db1d88879720968892f16bde95fbedf8" +dependencies = [ + "bech32", + "blake2b_simd", + "bs58", + "corez", + "zakura-protocol", +] + +[[package]] +name = "zakura-bento" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feb6bc45a1c5ec17d7721ddefec96edfbc0f15620e9aea845b482b3b67f61c97" +dependencies = [ + "zakura-bento-core", + "zakura-bento-macros", +] + +[[package]] +name = "zakura-bento-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22674d025e6df7ef104c85d725b9f6ba492743dc26bc2b826fdb03afddc87e4e" + +[[package]] +name = "zakura-bento-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec31cdcdd72866e1aed6ff8a5d38fdb56e5038cdf86f44b0f45cf84ef4bf224" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.119", + "zakura-bento-core", +] + [[package]] name = "zakura-bls12-381" -version = "1.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2c114620056f8c97ecc17d7333add6c818ff376434943c7ff4974320426887" +checksum = "d907defbb441a23e7c1d737c5eb7559a60741dc6c466f9abd4ccccce11a1ee63" dependencies = [ "ff", "group", @@ -4559,11 +4415,10 @@ dependencies = [ [[package]] name = "zakura-halo2-poseidon" -version = "1.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdac6fc73528451edc4ee8cff55946ff2c75359c47937eb42e6d31b83b542d39" +checksum = "107f3e0b6520c726bb5c736d474f757e48477ad67c8255cac65a01e2676aa5b1" dependencies = [ - "bitvec", "ff", "group", "zakura-pasta-curves", @@ -4571,11 +4426,10 @@ dependencies = [ [[package]] name = "zakura-jubjub" -version = "1.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9915c2c7f2c021379453608c91548f2811d1ba59b7e8505bb8ba32f51e494db" +checksum = "1b194dd8d83146f28e3d2f4e0e5adef3181774d41312fa4305baaf49f74fadb4" dependencies = [ - "bitvec", "ff", "group", "rand_core 0.10.1", @@ -4583,45 +4437,65 @@ dependencies = [ "zakura-bls12-381", ] +[[package]] +name = "zakura-note-encryption" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b5f70a372a3bae88f0bdb8e862786851d4ab09c9050bdfeb5c16938bb8ba97" +dependencies = [ + "chacha20", + "chacha20poly1305", + "cipher 0.5.2", + "rand_core 0.10.1", + "subtle", +] + [[package]] name = "zakura-orchard" -version = "1.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd7edaa754f9bafb4965559e38af6d337eb001f76de666fe20e510fb8e1cf631" +checksum = "47cd783b3ef284d8ed2a71dbaf7101de407a516b2407c146d292124b2a3e4751" dependencies = [ - "aes", - "bitvec", + "aes 0.9.4", "blake2b_simd", "corez", - "ff", "fpe", "getset", - "group", "hex", "incrementalmerkletree", - "memuse", "nonempty", "once_cell", "rand 0.10.2", - "rand_core 0.10.1", - "rand_core 0.6.4", "serde", "subtle", "tracing", + "zakura-note-encryption", + "zakura-orchard-legacy", + "zakura-sensei", + "zcash_spec", + "zeroize", + "zip32", +] + +[[package]] +name = "zakura-orchard-legacy" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "412273bcb7858fcd5cfab0ebc4c16c04dac58aaf482c62454a52b0236c02e740" +dependencies = [ + "ff", + "group", "zakura-halo2-poseidon", "zakura-pasta-curves", "zakura-reddsa", "zakura-sinsemilla", - "zcash_note_encryption", - "zcash_spec", - "zip32", ] [[package]] name = "zakura-pasta-curves" -version = "1.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e878bab2110a70ed4496e377b4b3f3039d6a227c5d79e171b316f334857531b9" +checksum = "d7718cb167e18c0fc2066e749bca3c6035c00580b2ea0d9f101e5a6032be3de9" dependencies = [ "blake2b_simd", "ff", @@ -4634,171 +4508,183 @@ dependencies = [ [[package]] name = "zakura-primitives" -version = "1.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799de508ecd41846dd0dfd06490e30ec6ee918008ceba19155e09f2545f3df73" +checksum = "4b4093c1f2c7990de2fa767a883c66dd0df5ccc1c2bf714ed83acb3a2620ec04" dependencies = [ "blake2b_simd", - "block-buffer 0.11.0-rc.3", "corez", - "crypto-common 0.2.0-rc.1", - "equihash", "ff", "hex", "incrementalmerkletree", - "memuse", "nonempty", "rand_core 0.10.1", - "sha2 0.10.9", + "sha2", "zakura-jubjub", + "zakura-note-encryption", "zakura-orchard", + "zakura-protocol", "zakura-redjubjub", "zakura-sapling-crypto", - "zcash_encoding", - "zcash_note_encryption", - "zcash_protocol", - "zcash_script", - "zcash_transparent", + "zakura-transparent", + "zakura-zcash-script", +] + +[[package]] +name = "zakura-protocol" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fce0f6b4a4a480c1bb44f54f2e1da0208e8b0289bee7ac45d89160c6d0e9126" +dependencies = [ + "corez", + "hex", + "nonempty", ] [[package]] name = "zakura-reddsa" -version = "1.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3391ff6c3e6222f5176c046e1d3645748be5b211880747e279d0f17860d51526" +checksum = "71235064ee2b86790cbceae68f65322d60b2527943cfd57b0e3bc79646cde5e0" dependencies = [ "blake2b_simd", - "frost-rerandomized", "group", "hex", + "once_cell", "rand_core 0.10.1", "serde", - "thiserror 2.0.20", "zakura-jubjub", "zakura-pasta-curves", - "zeroize", ] [[package]] name = "zakura-redjubjub" -version = "1.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "174ffd325c22f5dbb4c4dfe6f825bd82c3ca88a91bbe603b5cdf0dd7590d0a9c" +checksum = "55190512d69bce1690fe95996de8fc47a37e6037d56ae637ecced7f559e3da22" dependencies = [ "rand_core 0.10.1", + "zakura-jubjub", "zakura-reddsa", - "zeroize", ] [[package]] name = "zakura-sapling-crypto" -version = "1.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadf81594078e0e18f6c1744d978a9ee418fce988c293567131bc4870247ee85" +checksum = "24382d3dfda7bd98226a4a26b4d26520cff5ca1be27197a8e2dcd14d9f3172a8" dependencies = [ - "aes", - "bitvec", "blake2b_simd", "blake2s_simd", "corez", "ff", - "fpe", "getset", "group", "hex", "incrementalmerkletree", - "memuse", "once_cell", "rand 0.10.2", "rand_core 0.10.1", - "rand_core 0.6.4", "subtle", "tracing", "zakura-bls12-381", "zakura-jubjub", + "zakura-note-encryption", "zakura-redjubjub", - "zcash_note_encryption", "zcash_spec", - "zip32", ] [[package]] -name = "zakura-sinsemilla" -version = "1.1.0" +name = "zakura-sensei" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "582ec66fe58b717034b8f5c8b54834d93abd515fc20a0ce2ab769d522432b8ca" +checksum = "f45881bb2ae95492243292dabcb2a0b9bdc5cc84c57afd5cfaccef4a4aec2252" dependencies = [ - "group", + "blake2b_simd", "once_cell", + "rand 0.10.2", "subtle", - "zakura-pasta-curves", + "zakura-bento", + "zakura-sensei-artifacts", + "zakura-sensei-shared", + "zakura-udon", ] [[package]] -name = "zcash_address" -version = "0.13.0" +name = "zakura-sensei-artifacts" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a854b28c07dba372f4410ea8ad62b4bf7d5c2bf8be32fc4b31bc0db6521a975" +checksum = "afe47fed099f19d9d372831a28ebc8c6f60be551a554199a4bded2a5d3f4f134" dependencies = [ - "bech32", - "bs58", - "corez", - "f4jumble", - "zcash_encoding", - "zcash_protocol", + "zakura-bento", + "zakura-sensei-shared", + "zakura-udon", ] [[package]] -name = "zcash_encoding" -version = "0.4.0" +name = "zakura-sensei-shared" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1440921903cdb86133fb9e2fe800be488015db2939a30bedb413078a1acb0306" +checksum = "d17a999a972bef1053a5c841b870c13bbd18657325f4219f86375f40120f156b" dependencies = [ - "corez", - "hex", - "nonempty", + "zakura-bento", + "zakura-udon", ] [[package]] -name = "zcash_note_encryption" -version = "0.4.2" +name = "zakura-sinsemilla" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cb1b9170c94370e3d66c5cc0877661db743337588b64de7711239eed462198" +checksum = "ddbb6199d80ec099e9045b5b7625273cf89d4d5b1d504108a2c47aa11bd80eda" dependencies = [ - "chacha20", - "chacha20poly1305", - "cipher", - "rand_core 0.6.4", + "group", + "once_cell", "subtle", + "zakura-pasta-curves", ] [[package]] -name = "zcash_protocol" -version = "0.10.5" +name = "zakura-transparent" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314329b91ec4bbb517441840e47d0b2029bf0b946f086980c96c889c2d92dc5d" +checksum = "6bc362f020ef0bddebd853b484e7ba231c67aae373b785c96e2a35a910b5ffd6" dependencies = [ + "bs58", "corez", - "document-features", + "getset", "hex", - "memuse", - "zcash_encoding", + "nonempty", + "ripemd", + "sha2", + "subtle", + "zakura-address", + "zakura-protocol", + "zakura-zcash-script", + "zcash_spec", ] [[package]] -name = "zcash_script" -version = "0.4.5" +name = "zakura-udon" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f872800287d118be71bdf6fe8c869c6a6ff6fb0a5762f68fb2af54c97edf0f2" +checksum = "6d5b59abb65f3ef3d696caf9aa490c4b2e70caa4f9f048b99b8fd191670a2bf9" +dependencies = [ + "cc", + "cpufeatures 0.3.1", + "zakura-bento", +] + +[[package]] +name = "zakura-zcash-script" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6e8e9ee2f42d0925d6c95337746d698b0ecc9cf21c8e1e69587bda65cfc80f5" dependencies = [ - "bip32", "bitflags", "bounded-vec", - "hex", - "ripemd 0.1.3", - "secp256k1", + "ripemd", "sha1", - "sha2 0.10.9", + "sha2", "thiserror 2.0.20", ] @@ -4811,29 +4697,6 @@ dependencies = [ "blake2b_simd", ] -[[package]] -name = "zcash_transparent" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "547c012778bae17f58007731af074d638aa146ab0ecfc120adebf23d049aff6c" -dependencies = [ - "bip32", - "bs58", - "corez", - "getset", - "hex", - "nonempty", - "ripemd 0.1.3", - "sha2 0.10.9", - "subtle", - "zcash_address", - "zcash_encoding", - "zcash_protocol", - "zcash_script", - "zcash_spec", - "zip32", -] - [[package]] name = "zerocopy" version = "0.8.56" @@ -4880,20 +4743,6 @@ name = "zeroize" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] [[package]] name = "zerotrie" diff --git a/Cargo.toml b/Cargo.toml index e21acf6..6d99f47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,15 +31,17 @@ reqwest = { version = "0.12", features = ["json"] } # WebSocket client (for ZecBlock real-time mempool push) tokio-tungstenite = { version = "0.26", features = ["native-tls"] } -# Zcash crates (NU6.3 / Ironwood support) +# Zcash crates (NU7 / consensus branch 0x77190AD9, Ironwood support) # Zakura Common: performance-optimized forks of librustzcash (1.5x trial decryption, # 21x Sinsemilla). Same APIs, lib names unchanged — `use zcash_primitives::...` and -# `use orchard::...` still work. -zcash_primitives = { package = "zakura-primitives", version = "1.0.1", default-features = false } -zcash_note_encryption = "0.4.2" -orchard = { package = "zakura-orchard", version = "1.0.1", default-features = false, features = ["std"] } -zcash_address = "0.13" -zcash_protocol = "0.10" +# `use orchard::...` still work. Keep every Zcash crate on the same Zakura release so +# BranchId, NetworkType and note-encryption traits are one set of types; mixing in +# upstream zcash_protocol/zcash_address/zcash_note_encryption breaks that. +zcash_primitives = { package = "zakura-primitives", version = "5.2.0", default-features = false } +zcash_note_encryption = { package = "zakura-note-encryption", version = "5.2.0" } +orchard = { package = "zakura-orchard", version = "5.2.0", default-features = false, features = ["std", "backend-halo2", "zip32-addresses"] } +zcash_address = { package = "zakura-address", version = "5.2.0" } +zcash_protocol = { package = "zakura-protocol", version = "5.2.0" } # WebAuthn / Passkeys webauthn-rs = { version = "0.5", features = ["danger-allow-state-serialisation"] } diff --git a/src/addresses.rs b/src/addresses.rs index fe11f05..261c357 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -51,4 +51,59 @@ mod tests { assert_ne!(addr0.ua_string, addr1.ua_string); assert_ne!(addr0.orchard_receiver_hex, addr1.orchard_receiver_hex); } + + /// Golden values produced by the pre-NU7 production build (b902f50, Zakura 1.x + /// crates). Existing invoices are matched by these receivers, so a Zcash crate + /// upgrade must derive byte-identical keys and addresses. + #[test] + fn derivation_matches_pre_nu7_production_build() { + use orchard::keys::{FullViewingKey, SpendingKey}; + use zcash_address::unified::{Fvk, Ufvk}; + use zcash_protocol::consensus::NetworkType; + + const RECEIVERS: [(u32, &str); 4] = [ + (0, "4559029c0b5dbf941c5ad181a5fe8f45b34630f29d0c8dd8dc1cc3573386f416cb324133156d723df5e62d"), + (1, "37f1c1f4c922ecb98f3cf2dbe6f12f65a73fc93316a1c0ad4a23a8a3b9b4eadbb7687b6e82161d031698bf"), + (7, "75bef073ad7a0fb0ab7d8aff0284d9f57d9efb6b32ab6916cbbb119961d55f45a3c719edee4a2e5acbff84"), + (1000, "6a61da5631788cc6ecc9db8e8cbaaf8d3f3b5ea81a2704c9da47a060274f257d5a044fb39ae3ebe14977af"), + ]; + let cases = [ + ( + NetworkType::Main, + "uivk1ewu2n4n4xgwxvem5krz36flunule40kyss82myn583hj9ypsrmt34yw3t5h6utkcx45w3tcharxck5fzurycymxp408wxh7f7u2snqdekm8d9au580fvm7yj9y3qsw7d4l9qsmsz98", + [ + "u1u4zdvtcrjt4cnffw3shrx440754g0mhr4a7fenck686tfr6rdqy9wu5v39ydpgm4ut37qnlh9kpw9fsp8wcwyu2y2r5stjhj0qwfnmrq", + "u16p5xgserze3c9lj4pyuxhesqsssllaunzhehy2y0se5r8ac0tn7eaz4525kvf84sxhahngkd3wp3vlcydapyqyhehttncc0u0y4kqqje", + "u12lqydgardgp2g3d8ndvl09zycau3a008njs3uww4a2j2l9yvnul5g5lvqw6f6v08h00jy46p84qq2uaqmrwfp3n6yx7wzadq8vd0dc4h", + "u1rg3yrz2c34qgky548d57s8nvts8txja4m04ug4l5v7nfaxwhjrpjtynjtkqjdyhpwmqy4nn8624wftr84dgdnmm5nalzcpqe4g3cfsk7", + ], + ), + ( + NetworkType::Test, + "uivktest1zk0r9g2yavyhv03qdeexrwkfzp5vt7sspfa3fstt7pz3z0zwgw6gppm96vp5fd8atsftgn92agytakhwshmswsrxrgzprzzyzq63dyvvpagd3ktt8qvwpu3xpcmgjk0x9a0qaqjz24", + [ + "utest1j6uf5arygvvnypvh7n9pgcmt70xapzx70t3nemk2yy6646ekn2d296wyc355pvjtwnftcaukuqv687wnecvs47h9w82z4v498c58d6w8", + "utest1scuz7xf9wxep7xzuf5utvwclg649svw8wk2z90zdygpza0mkpe4070nleu5me07j8g7re27ed2y2qy5p5vtwgcf0vrr3ym33jve4eafm", + "utest1m7pvrhnnpjajfww846shv52puz5palj068m83e4mdklw70ckmt7nmfluap4vuguh7hm9pr53k4sne8dxnvrvlkqn646a822ppgfq074s", + "utest1p5wvwuhera8t7pp2z3uhelvpxfkv2e5e2302kjt45lwyf3lw6qtyr9ul2954tkcrg9qp3d593d6zs5q4g8lxhpkpvldruwrqpyw4vtvg", + ], + ), + ]; + + let fvk = FullViewingKey::from(&SpendingKey::from_bytes([7u8; 32]).unwrap()); + for (network, expected_uivk, uas) in cases { + let ufvk = Ufvk::try_from_items(vec![Fvk::Orchard(fvk.to_bytes())]) + .unwrap() + .encode(&network); + let uivk = crate::scanner::decrypt::derive_uivk_from_ufvk(&ufvk).unwrap(); + assert_eq!(uivk, expected_uivk, "{network:?} UIVK"); + for ((index, receiver), ua) in RECEIVERS.iter().zip(uas) { + for key in [&ufvk, &uivk] { + let addr = derive_invoice_address(key, *index).unwrap(); + assert_eq!(addr.orchard_receiver_hex, *receiver, "{network:?} #{index}"); + assert_eq!(addr.ua_string, ua, "{network:?} #{index}"); + } + } + } + } } diff --git a/src/scanner/decrypt.rs b/src/scanner/decrypt.rs index 4381f72..ecd1469 100644 --- a/src/scanner/decrypt.rs +++ b/src/scanner/decrypt.rs @@ -115,21 +115,30 @@ pub fn derive_uivk_from_ufvk(ufvk_str: &str) -> Result { pub fn validate_raw_transaction(raw_hex: &str) -> Result<()> { let bytes = hex::decode(raw_hex)?; anyhow::ensure!(bytes.len() >= 4, "Truncated raw transaction"); - Transaction::read(&mut Cursor::new(&bytes[..]), BranchId::Nu6_3)?; + parse_transaction(&bytes)?; Ok(()) } +/// Parse a raw transaction. +/// +/// v5 and v6 transactions carry their consensus branch ID in the header (NU6.3 = +/// `0x37A5165B`, NU7 = `0x77190AD9`) and the parser validates that header value; the +/// argument below is used only for legacy v4 transactions, which NU7 no longer +/// accepts. A parse failure is returned as an error, never as "no outputs", so a +/// future network upgrade the parser does not know is visible instead of silently +/// hiding payments. +fn parse_transaction(bytes: &[u8]) -> Result { + Transaction::read(&mut Cursor::new(bytes), BranchId::Nu6_3) + .map_err(|e| anyhow::anyhow!("Transaction parse failed: {e}")) +} + pub fn try_decrypt_with_keys(raw_hex: &str, keys: &CachedKeys) -> Result> { let tx_bytes = hex::decode(raw_hex)?; if tx_bytes.len() < 4 { return Ok(vec![]); } - let mut cursor = Cursor::new(&tx_bytes[..]); - let tx = match Transaction::read(&mut cursor, BranchId::Nu6_3) { - Ok(tx) => tx, - Err(_) => return Ok(vec![]), - }; + let tx = parse_transaction(&tx_bytes)?; let mut outputs = Vec::new(); @@ -236,11 +245,7 @@ pub fn try_decrypt_all_outputs_ivk(raw_hex: &str, key_str: &str) -> Result tx, - Err(_) => return Ok(vec![]), - }; + let tx = parse_transaction(&tx_bytes)?; let mut outputs = Vec::new(); @@ -287,11 +292,7 @@ pub fn try_decrypt_all_outputs(raw_hex: &str, ufvk_str: &str) -> Result tx, - Err(_) => return Ok(vec![]), - }; + let tx = parse_transaction(&tx_bytes)?; let mut outputs = Vec::new(); @@ -384,4 +385,118 @@ mod tests { let result = try_decrypt_memo("deadbeef", "uviewtest1dummy").unwrap(); assert_eq!(result, None); } + + // Real testnet transactions around NU7 activation (testnet height 4,465,026). + // Pre-activation transactions carry NU6.3 branch 0x37A5165B; activation and later + // carry NU7 branch 0x77190AD9. The expected txids pin the parsed bytes. + const NU7_FIXTURES: &[(&str, &str, u32, &str)] = &[ + ( + "pre_activation_v6_coinbase_4465025", + include_str!("fixtures/nu7_testnet/pre_activation_v6_coinbase_4465025.hex"), + 0x37A5_165B, + "d501345693ac4c2ca5855258f5ec55389abbfa0fc71f12d79384d8b305e4e1d3", + ), + ( + "pre_activation_v5_4465025", + include_str!("fixtures/nu7_testnet/pre_activation_v5_4465025.hex"), + 0x37A5_165B, + "d759e629035fc77989d8b3253d16660e5cd3beef33bd8a011ba335d0f44d7bb8", + ), + ( + "activation_v6_coinbase_4465026", + include_str!("fixtures/nu7_testnet/activation_v6_coinbase_4465026.hex"), + 0x7719_0AD9, + "98ccf227cfa19e8ad89312500bf724090997443e6ae0656e33b2d5cec99bb608", + ), + ( + "activation_v5_4465026", + include_str!("fixtures/nu7_testnet/activation_v5_4465026.hex"), + 0x7719_0AD9, + "a85b0f6a352b9699d4221a93eeadbab457862c4dec2a3ac7ccd0d2f034fc89ea", + ), + ( + "post_v6_orchard7_ironwood2_4513429", + include_str!("fixtures/nu7_testnet/post_v6_orchard7_ironwood2_4513429.hex"), + 0x7719_0AD9, + "462b5634f6e8bf8892db9c81260057957ac14e7bb3d8427a3dd165918a5cec25", + ), + ]; + + fn test_ufvk() -> String { + let sk = orchard::keys::SpendingKey::from_bytes([7u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + Ufvk::try_from_items(vec![Fvk::Orchard(fvk.to_bytes())]) + .unwrap() + .encode(&NetworkType::Test) + } + + #[test] + fn nu6_3_and_nu7_testnet_transactions_parse() { + for (name, raw_hex, branch, txid) in NU7_FIXTURES { + let bytes = hex::decode(raw_hex.trim()).unwrap(); + let header_branch = u32::from_le_bytes(bytes[8..12].try_into().unwrap()); + assert_eq!(header_branch, *branch, "{name}: fixture header branch"); + + validate_raw_transaction(raw_hex.trim()) + .unwrap_or_else(|e| panic!("{name}: validate failed: {e}")); + let tx = parse_transaction(&bytes).unwrap(); + assert_eq!(u32::from(tx.consensus_branch_id()), *branch, "{name}"); + assert_eq!(tx.txid().to_string(), *txid, "{name}: txid"); + } + } + + #[test] + fn nu7_orchard_and_ironwood_bundles_are_read() { + let (_, raw_hex, _, _) = NU7_FIXTURES[4]; + let tx = parse_transaction(&hex::decode(raw_hex.trim()).unwrap()).unwrap(); + assert_eq!(tx.orchard_bundle().map(|b| b.actions().len()), Some(7)); + assert_eq!(tx.ironwood_bundle().map(|b| b.actions().len()), Some(2)); + + let (_, coinbase_hex, _, _) = NU7_FIXTURES[2]; + let coinbase = parse_transaction(&hex::decode(coinbase_hex.trim()).unwrap()).unwrap(); + assert_eq!( + coinbase.ironwood_bundle().map(|b| b.actions().len()), + Some(1) + ); + } + + #[test] + fn nu7_trial_decryption_runs_for_every_caller_path() { + // A key unrelated to these transactions must decrypt nothing, without error, + // through each entry point the scanner, x402 and session deposits use. + let ufvk = test_ufvk(); + let keys = prepare_keys(&ufvk).unwrap(); + for (name, raw_hex, _, _) in NU7_FIXTURES { + let raw_hex = raw_hex.trim(); + assert!( + try_decrypt_with_keys(raw_hex, &keys).unwrap().is_empty(), + "{name}" + ); + assert!( + try_decrypt_all_outputs_ivk(raw_hex, &ufvk) + .unwrap() + .is_empty(), + "{name}" + ); + assert!( + try_decrypt_all_outputs(raw_hex, &ufvk).unwrap().is_empty(), + "{name}" + ); + } + } + + #[test] + fn unknown_branch_id_is_an_error_not_an_empty_result() { + let (_, raw_hex, _, _) = NU7_FIXTURES[3]; + let mut bytes = hex::decode(raw_hex.trim()).unwrap(); + bytes[8..12].copy_from_slice(&0xDEAD_BEEFu32.to_le_bytes()); + let mangled = hex::encode(bytes); + + assert!(validate_raw_transaction(&mangled).is_err()); + let ufvk = test_ufvk(); + let keys = prepare_keys(&ufvk).unwrap(); + assert!(try_decrypt_with_keys(&mangled, &keys).is_err()); + assert!(try_decrypt_all_outputs_ivk(&mangled, &ufvk).is_err()); + assert!(try_decrypt_all_outputs(&mangled, &ufvk).is_err()); + } } diff --git a/src/scanner/fixtures/nu7_testnet/activation_v5_4465026.hex b/src/scanner/fixtures/nu7_testnet/activation_v5_4465026.hex new file mode 100644 index 0000000..f67dcec --- /dev/null +++ b/src/scanner/fixtures/nu7_testnet/activation_v5_4465026.hex @@ -0,0 +1 @@ +050000800a27a726d90a197700000000fa21440001b87b4df4d035a31b018abd33efbed35c0e66163d25b3d88979c75f0329e659d7020000006a473044022043c971e06555e2413276314bfc5d881487e4eaa749148f87f3ac55b2b8fe07f1022061d53ac6c9d6e053cca4ce5b072c34eb252683a4cbd14da6a5b0be1cc8e549e8012102bc0a8bf008166b8a99a1bcf27086172fd709467ea55b429449a3fe6a92f03738ffffffff0300000000000000001d6a1b535601bd8a560dfb415d4babb99662dc157267d166b7c90000000010270000000000001976a914000000000000000000000000000000000000000088aca0aa762a000000001976a9141aded9db78a48344f8541ffa7d4300ada64fc68088ac000000 \ No newline at end of file diff --git a/src/scanner/fixtures/nu7_testnet/activation_v6_coinbase_4465026.hex b/src/scanner/fixtures/nu7_testnet/activation_v6_coinbase_4465026.hex new file mode 100644 index 0000000..3629229 --- /dev/null +++ b/src/scanner/fixtures/nu7_testnet/activation_v6_coinbase_4465026.hex @@ -0,0 +1 @@ +0600008098b684d8d90a19770000000082214400010000000000000000000000000000000000000000000000000000000000000000ffffffff150382214404f09f8cb87a6b636f646578636f646572ffffffff010a943f000000000017a9147a86d6c7eb12ce0aa309d7391a6f338eba3c242b8700000001ac7dffe812200cf709774ad79d8df7b17a782889b44472e472f75299fb5e882d614a7020a65abe309e93205278057ff70c8b3131c7451bb29f78fd8e61350b146337bbdd370e27ec685e8d88e3d55eaba3b0be4c09ce1beb3062c0494112a7303777161ec58b8284c48efbc04fce2de2ae15ebd1c3396850fdc98cb903e84b2fad30306779bc19a9b2e7e0c15807fac6fef3423b22085a2e1d5eebb6f837adbc6c2ba32654e3f96d803efb48227fc21a174c43d545273b8ff7337e3296449868c11f5a497b020cd6a9c3b0dc421a5d5c1385c2a369f9b130dba6f5834721eeae06672036162e0f1f313bef75926dd4bb8494ab4dc3513fec8c3b786a2c47525e368ab04b5a03b65d5832f715bf3ab96201b3acd9a5a6c9cb693117419db17904f111343bf6ccaa5e31139ce59c69e62a6ceccc507b23434e4b7a88b49ee8d29cb48f6feb42fac3fdc39e9669d6580dc6a1d5a40cdd13af2316170d774570692c10b5a5fc326490bf26f4e5e9203c48f41c456920ba36b4e36b945a2272258976f0a2bebcec71b1aae6af4750905a64e05d204595b3d92185b73ce021a0d34707f2dd54d343ca5f5f0e4723e3f27ef57395dcd0605dba87d97d60581521cb5bdc74d6539de22a76c02299a29dd9fd6ef5e676b53ed09d71169d0635e653dff222307ce47a29ace6dd23af350f3bb56c418de71130d02f34f52b66d28fdfb447ddc108ccfd1a30707d3e1b580a9e087310802680c7204951d864d567c5b22e41cb6f9dcc8d192c15cf7151f84e266f2be58b1e2757414237ed1c7dd04989f3b33bba3cef9c6eb79c3c7cdbd9246752222d496f797276219177199f0cd75f543269822695557bf0852baccdcdc246311c841fbecfdb4dfed9ad5db11366b6f28c776283fa49c959bdf7271398208f613c5ce9296f10709eece8679a2708dc0bfdd8e9e22e5305e0370592b6537734e807cf99eb47befba74ec2e2254839547ea40fe85cb63a0f57834e70fba611c0a5477903c90830ba3fd0c8ac2e9373328f18206a1e8e5d5719e83b9b6fb857d205f1831f2f4cc40a448d1468f6a8e1de7bf5a51d83f4e6c783b23025b49d6d8ceb3487d37d0b3c601c1af6be2bce4d35afff4204b49e06dbfae5f7844618a94452f8bcb93762c606541884fdffffffffae2935f1dfd8a24aed7c70df7de3a668eb7a49b1319880dde2bbd9031ae5d82ffd80134f2120ef589de3d15f4fb5b1ecfccba153d374007b737609d952846e1ab60bbb09b243a796fa1ad5540a14c48468f88ffe248e9bffa41e092100243269b7f4014eb705f52a0b615aa62191807df3d17c5890010c6f5aef028c2cfd2f763fbe3fe1b8a2f4ef2b1dd8828d6f4af2de6ef7c482b8b2deeabb4e861a6dc2cf17cc349a631aef838a988e070443cf07fa7ec8a6f491578c1a18513bba706508322ca70bc588f2b7a8cb189f686df764e9226da892e9e68c1d40685a50b9187f32ae0f52c6e680b80f9de2d38fd60d72013a75bde9a754b524f55a4c6523ff5903e98657e752b2aaeacb374376d599e4b39ef0c95983953ee0fbdaacb8a80f3bdca213953e45cf11d36f9216bb309f5190cd0aa5d66776b886f6d20ed94d742fd33737bf79f030f95e04ff8b75d9ad67ee49178a64b043ad4a8d7fe33168badfaa96aa4a6dcf90c6cf6960c81e1cbb252e9afd9abec06e8975e86c99a575d602adc1bb41ea5e8c0bf22ce7d68b5303b6783c41e60bf1e8b44f31e3b472732662be5402c1e7f947c036169a409fcf48fd66e8dc7aeec8024f369763eb5c3cf29ee9440b1f9841be63f70b8506092da97041064a4df313a93930a17a7fc41d1db97979bdb2c1c4c18ba4cacb7d9ca3f0109a439fb46554d5edc2ac33a63ed210b28ccc0352055b9587df2454130267eb5ff6708bb157f5d4fe523a6f8fb23addc98c931ccd441ccb6207243e934e5176739938e3ba017baa75218e452e49129ab5bce3a362fd60d63d79737a53b108db20e9178238b24f82a38a3ae9d9a6778ae43719093e2670a9c9f808c96b4cd252b8910321aed1b7d9d8fa9f9f8d8ddeaa6edcfc18ec836aa7977848aa1879a0c9babbce44b057ae3055964b56ef82a4c5693f9ea00806b27e6854db4c5b638bce28a53986af3c9fbf6d496d4b6a367a28144b7a1c58efa19b98002ae4a62c94ac29698bf7326f814a6b8621ee148eca7606ffe33ef7d2a804040a927c061eb93c988a26420412fc5e9ea5dad2c5a5f0120bd8d533d9fff89fd92a80ce881c83de7155441af22526a65b996c7c7c1a68c114320516d95929a28654127b340e1f6dbd56cbd015a583aab04d6c437dd040e168e316229103586cb40582d88f4a74d6f9e3faead96d9981982265ae1dc856fafd24a801023d0bdd242f2e3cfd0d0449905686ba52006168c6ab2204c60b6cedd51b53b371ffb6a7d4cea66353f10d667ce0b1d59f3eca4fc866f5e5b0a0df003db0b52424bf6f58b0e94fb2d0cb07b427b339a44c167e10d2f05992bbbc06b573ab7712eda94bd2ff60b3bb02c3c152013d76c4a6a65acba9cc45717c8220bee6ace2831b6ba5a82a3800f6bc80c177fffa9db9b7ed64fb63ce336057f5f7c2645d82821ddd1b3026f2667b844d7200be9fec4140b0765716ecae6eb86c98aac304df0bc235d52e1e4729691f940763c06f7b619b4fdd6d0a2ea08c281574cb0133bd23128f6ee7e98c3931987950f4e0c173a96e3af1d73bcb3d0abe5df7f43b15c12d637ed82a47c667ace83fd2640765df334aafc26463cf7f34d502e44d9c21d7087c4664656b0a930cb121d166762e40c0856e63312d8b87a39b55eef74d065f0e5571d718c80c490819153e92592cb67640c9a427b2ad98ab40b0b69aed80600a1bfcf6532978a7255cf6dc7d26c6ce4a39832de03c130578f0740ddcb5f2310d8a4bf0b6fd179f0c588cd0509e7ef6a1e185635bf07bc574950a9b004e74870ffd186c9f15adc20b52861a1bc4c9cd54b538c5215d54e7da92538485788939079ebbe6a6de6617a4315670b6540dfe6b3b1858d72c6a19ff5ab273aa0015fc11a6fdafa156726ffa3828d31a751c9c56c30c11dbcc0b1b2fffa13fdbe7ade738477613247967a8dd36ce2cec5fc98717cb94fbd3fbd4c4c85e25bb4e93358d246d835dac1776b7f9cd205190acfba726efdf76178a9f3b4598f19649906f751fcb9e3173f565611fb66c74db290177b2c1c6e3b2c9302d8251481628780279371a3e40ced0b0a2d614a6955b5cfe03300db356b7c0e731d20ef950bb60f6f11ec26da4a00f3346a5be3df27eb8e859d8a790a61da8fbe9df23673def8ef0751f6c14174ef92013ebad0c876c1074e047ed90c3526e7f5c433709b63b6dd66d1f92383bfd14adff3c791349d5b339515aafc061bc3306538380cde336449c153332ec550ed94a7b453866b9935f9d13dc15ced16e69286a7e503e4c162059a517998677b3213c31f0ee705958236dacee8badb5e7cfd070e43e4aa8756bcf2426d3f3e938ad080306d5e92b8ca45fa7f388ebf1a67b98718e4cd0cd9b0320bc32665f7b2334a5e4089ef7e31635a2e1339d95dea897c6620e8fa933cd4df86009880801f6d5d1f194d75a76ac7af3595b30e5fa595d88e6eab6b80c839dd5c13980b946414373388e9eeaefb073fb6b331475e6de144c6adcf555f92d915879131bbe44251238f77f6435ac4f7e800e7839be7c6169648608824ec49ebf934a1796d0b26fc2c38433c1eb107b43f3cbd94950fcaa6ced6315d5ec274c25596708266beb391216adc00895ee9d659123b71af2f7abef101a47a1fb8c2e8eb6bd0ae00a1136e80b1e06ec107eb9f2d6147ae18e53d1548a08b15e78d4299a888b0257c77706d60d1f1ddf433fdf74fef4397b10b34b85117accde1e8117d5a43132b46b2961081985bf71aac1426c968cc46ba59d53aa8eb17142892eb5ebd86011b5e47a4fa2995135ea887c667f16bc4d0668b62362ee14bbfc06c0403d3c650291d7c106b2a0e67b4c0fcf1c322c922a813f7a145bdcb037b1036b498444b5231ca59efbc481b0a65c37981247ca552e9c56757b0b518745599e4f8edacf31175d79dc5ae48a843bb9ee27c737c080ba8fc373c6f14231276acb5ef9cc309336ae409cc4f45e46c3e4275dfb18697afe34de52ed3f0a2c1557fd01ea697e2703df259f82fde6590cef19a6802a82a1c559f563ac4bf74d68c03af37081511b3b2975f7f84ec0164184f73133d132b3e2966326062f439c8b543f197d1e581a02120957c2bc98c4836deb7399c42c254ed8217e724f99947097a5f6d674553e10fcdd18cc20c7dd800508e4e920107abe3e6b9519e363353a6ededfbad0d4621c4c8157e2a157c0c7d5a255334cfb2624595fb62218f0f2b5fd49b6b64c55c7014b0f3fdf55fcf1aa2f31e4264b64c719414d98084cdb0292f2a02cedd9cf4d177c0dcd7093eb070545336255bc158e0db5b94ea73d6e9cb8233d871aa6453437de060d686730b2c4f3e6badb86cf59c970d49b5928ddac531f6c29dc1dd6c5028b74ee582819f2a623dc04f5fa3b073b4c2c1cc6117898c2c8019a9bae2df41bc9d454041a773b0a663c1908199f90023c619305ceaa9679d3f19aac64aba631dd0e483aa2948f59e2faf025c73219eebfae501cc57dc79003a7cc054a4e2004c86999befd58909df9050020d63162703a9b51fca16a40c27d401a36c686d0126f68dc0a39502a8426447e410c5f9cf871e59f66b1a26c0db7b06fc8595abe2fad5e7c0eb8c90996a7ccd229409e81c82bef007379ca8f46adc0957a6520db1a0b39783b8354a6540d3bdbe0020b6b605c990b2b2197c12df2e85afba0b31f09001ad0d3723085adfa5cf989a144afc2a710782a60533712f7cf46365f5ff52f26aac16c2670e2b0c55195a2c3dea629408bbc4b830bea77db6e3b154974cf3894b3705fc8ef59590f10a791ca10d9eadd9dc7b70846e4981a91fda75bb3db02cfb908cfc6222255c993f2dae1e0a8b7a3c84c81b6c109f1d2232cdd7712a507e911da7155bbde5697eb0f21fa55baad80d7786cb0d0b76047db4b96f9543134647e0c97b03ff6ecb5c267139172b63395b75d4a8f4671ab3580967c6d234b18244da74da454ed75c0d39312ae6441f354e5ecfa446626de91ed86b40835121d9cbc110e191ac2f325270220b1f2919246a0a8d476da3d4b7288f6bfb6db622e52629aace0c6cc5352b309c5921af9fd537efa837435388f93f81ac9114afb38749d9df298933b04a9c57783f01ba6f57814a4a3b8a6f29e632be2ca7086c83d0d977dd0f1682127f8abf5ff821071cced5dd894ce4a249c03c4668a4918923122f8ec424a4cb8b2a1c38008da439bfe841ac95b3a14e02c10b52fe7481fe10c9fbe99b1f5bebf4ff9c90bfb63db1aea3ff54293c66691c1a75b67f5c0d85901b2fbaf614a078d86a96b06207e8800382dceb879928ef34dba427aa1ddd5eb186b6d7ea6bf7dd95c90b3f05e3b1bcfa1e9c4dbbb568a9dc8f135dc12e8a8d039e9e0d7c41e73ed105b466813752509f622dade699a3f790451fb8ede40817b1f06dedad43e535d29c35850345b3b488484a6443f03cf7a126363dd8e26af1113a3278288bf2be274f5403db49eeb68f09c624c3f2ab4182986263bfd8ea35237619b9260a5fd31f4feff3345091a0fd5888bdc8baa376eef8d2c5a53eade931961538ce226a7370b17205d48e359151d011b8689be14f2b97f34ef70fb516d32c1d485b45a31a9a03eecb3e7459882c73f7a1be4a8eb65b8621bf5f53701503d23d863846a6ef30d620eb4512f041d14512bbe2eaa10e2c9d28965b5d6a24805d806890dffc366e09684ced1c51f3fd8e73d2485008eaa9296d0903e38a0f90edf34740063f263d36991a0091f0e4d672a72f7e50759871e0439f5b390f3dc33e4f1d77799d2c542e2d5701ab7a9779556c37da8fa4feffbc7e5f25c93dd2912b9ada5fdae1b017b12df1a80b9c51734ade1e6bd4f86dd8d545d303bf6347924ed10487eea6331b1bd09b37a7a0bd76f009a1ce4fc9528f238451b7c92f18c3e37fa14c83d6288158189a50ced8e20426d5695acb1125c9d7810e9a3750d7d29466ef6d3b801833a017bed16b681579f360fb66444511a4cdf9be4443ab82125f97e959149ad637e12c771a6dc96c5b54f1a8c1ffb700f5637944a16c11e402153894a0ae011a33a6631259111e0f1048066a841b9a2b869c8a0c16e0b9aa339a65a42cd8d704397db93e61690247b8ce80dae8bd7565c745be0e4a089cfa30e90d3e7272fa2417965c578edc10d0af1201d37bcd6fe99b9c25106eb07a2883f3e83fc0dbac856483a6785392a2c46401ba7bbc27e17378fd1db239a2a12de0d4d173934ff873ebb1ddb7bcb54dfab570924223c5cbc63c541fb791498a59021e20702488ea1ec517a691729fcc5185035b5b4b0138eb3ca02e5f2bf7a10fe19bc5a48b85cdd590c007c395d951957032e2fe493d0611bda4fec1620e7d1ed3f4c261a2f23e34e3618b28f3a01b7763b7cb68185b6a07b50b0622a9ed2ed981420547b75709541c1ef3de70cd4f881850a6c5ab4d8a49a505c078eb232b6bf309999303d598850a1fa9b1bce1b73c5a90e94c5103086408227840bd8e2e85432106b0aaee8a17e6279b9488a8052bcfa7516708b0197440469b9961ec807ef31e063f5974d992bc3f834f81f311dfbbda9cc89b3030ddfbcdd3ddf41e269d81e691c3ca05b10e50e02fed97bb26ebcd128eb25d136a1137c9e98e70a9d9b1828f4adf24cb1bfdf54c31ac7e7e11f7667f292a88499fa1b48a7d44b389f355200b05a416d99d663f4934462abaf9936bb16b3394ef0b744abb53d1c06b321279b8a25c59cfa2bedf6016d094d505eaa58d6ae46ca46db8af54ab0e40dbafbfc07a47c35c8ac41a804a2a204e22e2de7fe51b4b36a0f814e0d9750a0e3dbac25299f5459dec4c5a4e6b088fe74272e6b7eed08c49ed93db576eb5927606c7fd43263fee374d4fce10e95176c73b632f2d0d8ffccccf8820a1f8b63ff7f1218a912c2a542a86eaf264c63a18e7a211a52c6eacf9e9d115cd24aa7841ccbe5f7fa0e136c76611a52941730339090d5744c8080b2640282b657e33ceeba18dd27b9311f9ee2ec9691d8ee628251e4f25d43022a82402d044bb2a1a3598945bbcdea3009b9145c631ca32c408105e8188a738f8da932295e7205a09efb2c1fe942978fd124fbca6368991f3a7393108d81b5b8f4331d66456562289635a6d76c206487c8ea4b5a3c273b9eeec47854f81b44765e3a31732320f23c6e984ad5147111b5a695161d840181e6cb5dcfa7b2b8e76a69968cfccbff267a69a9b6e30c715a87d2ce150b293026b3dad8b207246691d9b0378537cab0a40a2158146d116949122d49425775a2e6dbb86d24fec18546209943646d47f6b73a485d390be0ca9296041042b40f33a6ca67c076c9699f3c48f6b0ef6aa6dc21650f27d70ce3dcf72b335c9823dd9b11c64f6267bae8aa92df58ad06f182b9e0b88cbade73db6d6e8e089dfef905aff1c1d83e45613bf8d1a98df0a9fedc2323d0c9c41ea932bb2a3025f7552fbf90329c13d0ba11ca2777cdcd735b293855b488f9dbb2c6d231c81d5176aa0a302d3fbe757572609b0e12bc9f403f9b123f2473e893babcda11f12e6219bd271adb3603e7b5c921c7991636b2662937e7c732d356667f0806f20721586533f2d4f97595ee522895f3c2f666f44a5376255b69bd842b0c1516c4502f5e2a3396b0d7f5763e97f3da328d2cd1793bbe05818ed37ff60a3fada867852fd271bcc35a0d509828e50b1466eb3cf8f003b41466860cedc3df5db877189911c5a5db33ecfd806f40a76d260e3facad29f0f363bdcbac06fb407419275822913aeaa4001c24a5763441d76d42a19dcee97e7d2fd83182fd003862c483a9b298db1e77b348744cd01143f6ffe55f152622f88fd37685c63a50a80ead979478bc35e8bbae3d749d05def8c3d814381e6f46ccf4975640684cd3273216d719c8a67bd100354bfabf020436756a5c60689e666708575844c8a604ed21e9aa304c3ae60546a1c9852d0f2595858925f7745b9aa388b882b948f508d436d0074fa88c8f7d28ce3b3b385c7ad8a486ceb673d108a1f88361b09a4bc9be5212539950195c508b9b8b47344e991101c17b54bf45d784b6977cf6df867bf73525f41cbf30a88aa5f55044e3f2ade862a81bf5452061a7242524e65c6a5a67879373815a27ac49b075ee3555ead587e8409961c463da75df49dc549b0c32cade3b24e6ff0a10c9f10524126d3155bfa2202e6f30eaa7881f502d33aca445345cb384a846820bc0c8963fb669cee5ee59768cddc5126d4ab63550a4468c37aab926993a753a \ No newline at end of file diff --git a/src/scanner/fixtures/nu7_testnet/post_v6_orchard7_ironwood2_4513429.hex b/src/scanner/fixtures/nu7_testnet/post_v6_orchard7_ironwood2_4513429.hex new file mode 100644 index 0000000..79acb65 --- /dev/null +++ b/src/scanner/fixtures/nu7_testnet/post_v6_orchard7_ironwood2_4513429.hex @@ -0,0 +1 @@ +0600008098b684d8d90a197700000000b8de440000000000077822862e335aa36c7e14a9dee0eb2afa7dda29116ac53f9deaa009efed02fba659257574abac91a12b0b19c65ee7f354a97fb84498f3dd6ab81eee812d14d93c0f86ec6be7331d8145f7124c77a027c5b94a4647630fe7bd47a2ffa5f8fbc9a7f16bda57641a3f3f3152b68e0396ccfe84f8ce17390bc509ea00dc3ce4aaf213bd354bd643f37a195d64d0385a43b48dc609e212f976ee6577a1922deeab74baa70b3b4e79546b99b97d0219bd36f5b8c668366f029c72b9c82e4d62863ca0bed080afdb2dcdff5441168d02306100c7ab23943facd7708ab948bf3ad9b88296f306b16f14aeb9b1d760c86f1bddaee26b60774699ff73281286323b61a9c5a62170910773f66a5ea3e8babba789aa735798b8f6d7607af2ff6c5734d7e2044fd4b3f209fcbf601bbf2d2a76022cfb53d17be92b897d0dba3ad55f9503d9ab65f05561c536e8feadcf2815ee6d3b20a3c3e768fb555c3af5db334a205668cc85498d0330916867ada888e5c7480ec28dcdc852e961a59154894243602b83b84ffaa42a4093b6ef887effc5b9698ba7584e94b4ca4e76c85a7edfc3b8067364b038b7e5fb672d96c9df344592d457067b454bf53daede981816d3a222b5c71243a7a1a6b1c2c4159c8f475308f5a21d96c8b7d3194a1447c384989e86514ef75a651ecc2d760a2b85033e3a8ff010ef5fe0885068ba6cdaa0324b54646db1bd306f5dfbedd5c8c1ee1f9f151bd950e8934faa4d1c5bd306db0a97c8ad3bf51d327e261233788b55969d344b773fbd8ca8b2304c407749da1bdb667f82f330d6278c9a6631d4dd6dfde4c2eed99fd18af0cf8d93faf5ec7233ccdaa21d50aadd8eda06618e06730a9ca8a63e73fca6dc5a275b22d1f7e7ab2ba25dc80625eb7494c674864c0aa3cd4759b4d79511e83767f665ca49c52266f43e5c8aa886b3d7ea2978cbd5a0c3e4a8bc4ce93e4ecf3776efb5784828d8b73c08b320a2d0ecf1843737f942fbc4e6080961720a0de4aed17a114d3b24ce944e738a301a2cebd4bc16efd6837a249150646cf1771bf59f4069ec351cce94d9685684fc902e5ebc8c4b6dcdca16a38c54ea90e88e8481cd268d504e6797688b55f5ed48fc4d6467d4b4473e3f867f51d550da0e969fae47ed24967620bf3ae99fabd9b27e1635832e23bb64d5d9cc63c63da40411cb9e00bf9b1bb6931a9d7e690068106bde9925ce4f0eaecaacfae6024d2cc38b90289e53c49590108ebde2fba6fcfbf4714c6935811150a3bd7bef074276acbab096f82c7bc456a2410f9813706ac6e971a19a29bafe992851274ba6ad29e0099ec40173ad249734035e1e1b33508ba3bd52e5acca91f84fe63e58f1e82a5b9940ccdf8caa242129a65101346029d8c0d0878818fa6bf86a4cf17b911b1e7f5e72c3b3e6d66d4773c63ae212e955458f5b0e694a806d7b06692f7a1a91d68c7602ab1a67c3df983a9745a13db832e9d8b4640c99b70fe013f17f88cfeb7e8bb0934a00f6b2e4cdfc7d21a291138bcf8f0d3f5bda87800884c051c38bc84a0da170224256d11ef86602593f9e295128e5b04ccefd21ea66b2e4bd21101f78dacf7411be948a6edad3453cedce866a2dd89df527ccd26889e7785cec5c6092e9849e69f5ae8eb5567b419468a5628525d105278262c0a53eda5930f548610dcab12a282ec21f4ae608e6bacf5734db3c2074208262e841498be69b4de986f351065ee5cb839d4c25a3cf6ac4b7db3a9e8b32a48379951153a321a3785c05baf0af46af38a5fdec699c270a4b8dd640d7a1f154e62a9457d43d4e1ea9e53966fcfc51ad09bed410f08c080bc7befd7c6eee2893eef29fa2eecbbc94ad44262d22ee8d95e6bb09848b636cdec1527a97806a4d3dde4e25d5ad39740d73c4c5f824c1ecc6e8f9e870a993a8a12103b6c69c8b09410279b77941bdbebf81fd2d74db1a1462da8ccc5e09cc051ed24ccfd0f426c3c5c4f30bca256dd862c7c57fa369ac57a91f7067cbcbc798beb487f219762e2fac1940f8b2375aafc72cc77bc1954ceaa523d71ad6d15f3aacd86180f6b325b24832f25fdb19ddb0668237678207a8baea4c765962bb0321f03486cc3626459a842136069ff8ce48491d5ed432bc334f92be6cd8b54efd9c32138f32c3f821d871b8c8340711ef9c6bfa47bfaa98ed10d56faf3fa3ab24762811be2ccf2141841f42c8e2862f6a0b2a65ff87ae7b4977630b479bc8d54830bd7f885a7d72927f34d82ce0991d7f318e0bce88039eb130ca3e5b6beaf78d6f1b4beed3808e07ac5d1be2a8ed48b2a26d934493c95e2474c671ec284f598dbf71cadb8b8589aa25dfd5ad16ce64ba4254bd9df7de96b0af912f1c04cf2b66577e8e9ac82ecdf1eb0dca1d3deae8baf70e3b1f24409cbb1bc359736672c174058781ea61afa145040d0bd2ebb21b782b17bc9be4e19e2e94e0dec0ecab9df4f898973b35cb2ce7090031dcb42737c21fdcc038e57fa4a0276c849abca2eaf6b657a9886e35af6d2c396a7f553d47b9a4168408fba77d99257ac7795e4fd3ec06a3e6a0f460a9a2cc042e0a6943099591bb5174f030091249b23e12f410a3be685384fdd9e72d1d0be48d0f520610e97b1c8ee2d08297b340caaa7b976715a797b62874cfdf3ebf5c91cbfb7827cdba7bc1350aeb460158858167d4db9f845fa9e67012622c21425d3550bebf94e56a79774af393d81ee771ac10eca65196ed408a8810f6e74bbdd2588ea8e38d0cef8dc25841154c69f75bdba956f42c0a6067ee3cdf4289c37a7e8c90ec3cfabc977a767dc78bc662919efe57b049899efe5d70d4b9e3c13817631c248a5e6d86838d5629953a201abc70fc06012c32876bbdc513d4cb74401a1f818f987d0d5531d5386849a7228c017b13ed36ff6167c3023d1e41ca34999336e10994e83502295fd6c4825153751c2b859b4748f02fc617b48353cc54399f051edcbfcdc755ff7faf5186fe210aa87693c15823224fe441e193c3a5628919e0e4a8308fed93b118a7bc03154ae1ae02a905bcc6cc1f218cd15a421ea4bfec8af60da2e38c016cf396fdb2b28cb62496f15848ebcdb7e0f9d25eb57d8eaaa709154252fd2e1b52cffa4ab867f24bfbff80ff9a01de08c3a29911f27d9aa354c34acdead65a656d68043ef2258e41bde873d2111147e51c192f4e7ce9a34f3111a03013fadbbc39b3da20fc30d84758c35f5ace3d43ef902f347cccae259e65822a6d20e3214fca33905ef6ef0065094a4468dd2c5cd896d07b2313f6ccb502e1744883bb412a20a280f2468f9cbca169b8b53a8f8b32d819d459953105ba70aa1e7a13a9286445d642fbee13f332693132d2d4bd49a8e3df4025b0b34e366878c2665600699c6ca1ea0c79aa9b4a43502eac4fc59855f40d07c6e74e8fad380c43802b749f66c2c15dfd2a8f4e2be270e6f6f59f0967b98cc20c7a2e3d6010643bd2ac05a284f96b474414d80364bc59e1c156bc670fdd8848b23913a7950d1bc5257a44942b38e0b7b9f681f1fd1d3192e05627567a8445ee61601819bf29671a894a0b36e2654772a979c15cfb40f5a82573d86c49ebbe53d020ffadec8ecd781fe472961619328d0ae0e368f2fc50aef06d3ed8e5dc6f826d51a8f0bf1de7e00b7d9c335f3961f2495e573e7853d87c947140a2b0d4b3971e1121e4b715514ebcb73395720d84255dce55a98784ecf55f7d5ec446db7cb9a8ff47f1fab5b9bdc21423848f5da1d37e32e49c12239fd6e7d4c45c972294cb632b33667c9a7aa67b375b7fee50ebe9fdaaf5034a5d729bdf59d29c976d154b2f6bf934915e5a898b1bc8d1bbe829beb1ea0c73f03ee608ca2074236cad007236ddf46379b9d4411cd1835dffcf20c5accd2517fd23056304cc505b7f7db35ec86b37c645a439ada3d63cae8583e1cde00e104155c683856180ed41352deb21162608ca9211b5aa9825164e0f8d7e3e7915263acb9017cda4573b8071326475a456d725e2f9c0411288b4dbc0fcd8b86d62f722a89bcda68538608baf7aadd43d12056d65e059b9f2f37aa85d1d46d73b3821f007c0bf66f859f8ed252759ee14abf8bcfaf427dc5cbf5369efd582cb74a63670fcc974c2d8585ac29c4e66138500fdfd720047cd982453bc76d1909f3bd55a13bb387895acf58879ed377adf0b03dc6006d9a2e2451c632b1639933fa03d5adc6ffec32f6149d34c2d926462ae8c202206224483a8fa9bb92fb84db3b7c4564d74380a38267c4de030e878471b9a5d8e1d74df6ddb43ad4b1208e971ead4c01e9fc922a05be9d7520fc26a7bddfa3165eeb8d55c7e26fe25472c0888ab785dfd932f6c88847b0c6b7123c78979c135bd21b261741f149e2eff7937eb558247cd1ed13a63ed1886fbc001944a924b27dabeee7e31da4f15d8a6410b168359ac2faddb03e2e0b6236bd7a93e326c0e05e036fbc99c93c24126dc3f165df0c66849f487cb6bbf82131d7e721a143c4772d5f6fa84cd23686f64c00088cc3534c745f3dfd75b2d1fece7b74eac784bd5ade9d9d60651d27915889cd08a145cc6aec672019d024269e4f9c81b5f5cdd8cdbda17fc296c654bddf2bfa99f1c3717e564ebbdff0fb92b37e5a129f7bd90e1aad50f483ebc9b0c85d439c1b1a64dceeb3268504a6bbc2a345a3eada95c793b8bf4bfbc23b37f2b7759dd9106599fd3163cb3b1733c860ecfbe0a023967df2b5c915ab9265c777ffa07a07ab7f5db60160a0f4f6adf748bb652e8480f2d3a9cb1e714326c6c5f1e404117011104f62c2a02ea33efa53c03321b9044f1d00aff6c1b25dc98305100f34ed939508476c6b14a5d8f6e10a72a1a7e85a5bfa21e19bc0785a53dc2f2bdca49ff461834bb0381c84e2246eb109a6a0bee37dd478a91830c185e4fb7c69447e305945de11c0f24e1aaf332a1b082736f8853a042dab362d5d94ffaff0b5392c7aa9101a41cd663fb3b36b272508080a1b7eebc2a247a6d2a5c21301069cf99bc0566e0df802f03457dbd1d96b0bff62cb4b1a79c558c38e4bccabbc23c8c0a67b6a545ad275f4c372239b2c087f9a821b466e5c4b9ce9e9d3c8ab170dc3b473204308157ad9ed634e8687d625595b2e514fc17813c1065fd13c3a5cd9f122351e95ca37cfa22f1e9e282eb32b800074dcc67707d4630056c9e0ea8f9a72ae5a52067ce5b4efe9aa7681cf552e88a05514511b72cb5c33863a2cf0bb8410890891a328dac098a8a90777c4db6839d9c42cc600eb39d486cfbe8f931d287e0545a3e8cf96975647becc541109fb371c2340ae450180481d38671732be200396842ec4e9a315837b5399f3c06f7e5b9fb995e6b7d8f55e6d4e8bb0c82aca6a593cee2ed2dfa98aca114138fe4e57ecfb9bc77d2bba241bfeab57ecee5ee89de053bc1157699ef3ba4124d95fd9dba5aca217b2f24a7be7458be7005a0766aae40c4feebd0de75563ec7f66e5c8313c7236cbf55d93b0f1968d6989acb084dac22a37a827a3c0c0a9dbdee976dd8307371f5d7cdbd9f307e450cec57af9f1df1d05d8467031dd123b1b94fff734ea830ccfeca6f01b0e3b4f774cc90569b78a63ecd6125bd92f3cc891a80f386c3bdbb52880d91c2c0900941b814121a908968ab8a83ce10d6bc69f766e9dc190df64a20672bce06cab2491bd4f467349f56522d32adb9481e93f4c1cc60ec371aedf47dae58413dd97e876bad81f44be83f24b87d3b5ed0677472f4cbd0ed3efe29657c00906b5b64c9cc268501107695a6cce29fe5de01497e5ff8550d49df673a8775e7597685613c4b5a92441c6ea719f9b26b8fbf08ac8ef4b3ef1a7ae2cfa34b27d547362f414272a0a341db6980df3e6a6bf7226416b676bff67fc9cf9513d7e0e177612485be864e0f7308b3de562d43b4ee035de366c189e1deb45f8170e5a51bde5364c1faf7ec30a274faa125753cb9003db560c63157553dcfe93e9151cd6a4d37d9dcf4c3e82b33415f308f42e4a4941593cb7d070e4891dba53dad53398b0f72a674c7d51144b01ac8b87fb911757444f00ddb07c0d8f0a1b50709f2da4a41f3aa353a15c85675acb1fc50bffec321bd678f53522eeac6dadc86118e20b900c34f1a13b904b022815ba7ebf21fd6e9d8ecfec3bc130b97c90c6dbe87039b7c54efdae9eec46722df1146528b95dfc722f4fdd8b2406ca3cea14080b9170fb3450ed68f761c8f7df8c9c508da4b7c001cb33a049af1d4e01579afd71394616e3eb88c627fc7d33e1b46396409e0771345cf3b1be62aee0593367150d9f1a839ba34ef5bda2428531380c0f441b2f3d0eb002c85b8284a08a29d2fee9d11dbdf73ac9e5d11835cfd5ae6c59803a6f8bcb592258a259416913af974f70f11d55405e5e7c22ddc9be24716a31d94b12feb067027e0f4ffe93c21ef1c3568c7ab40cb1467177047ee92584d2d240d8064ac6c5ee140572ba12720233a6942efa5617b54c948138c6063b2f728417f566f1c08b9dfc8b60f978b18a8e36e70f48b5e9d80e3708e07b09d7e236cb589c66a95f8899ff61b846c9a3b6cc421141d925d8bdbb35c8c813dd49e805bac26aa4a575b70a3cbd97ec154546b53c856a7296162d12a8954360ed0bf7bc2d316db3b3472ed13bfdec1a61059a1662827e1c2b115520749ea05223922f8ce6717616aca8b2453f00352be486d00032b5f5d33112a9ae9338b7472090d09111afe38287c96383f4a496258107e0c0fdf8e93e062c376da975a240c72d313bd1384c71823238e4acb70d5f4a4b0a2822b4d794821822ebd1e9dab678a238dd502fc7d8c27eca47daad0ed878a15061ae16ee6b59691df30a3bb2aafd9d7fab0bfb2ebabc1f7101234f577f7b7fe0ab39719c8dac643a29ddf56b8bb142fbf760bb2ad05fd4d14beb7eb6c2165de356c52971ffbb7a8199b79279368ab84977e0dc3f8555c663fdaf9c46c9d5c6b2ceb7f45f2d3ff631c8cfe25525f1f0bf49441fe18e5de5fea2da0bb9ddfc40fbd9809ddb57aa97d3b9395055a2fe727c364cabedb2d8c6845ebf7b6864500e4446a4cc10faa6d4260fab798d0d008c70a26cd94c66b5c9b172c686a5bb6c956ab04bd6d0e76edef23dbcb368620caf6f4104ef2145edd96571b4fa213ac6540653c7f692311d2a6e8635c3a41535185401341400ccf3ed7c8face9975ef5a8d178343cc6b2aaf4b3113694969f4ba69e2b2c555e0d6b1a98edf29dee7bb8ea72d426fdc06ff0b366e91bd099ed331fcb09a6d1524fa77233b1c063e5861f20bd6c917e6e76815cfa75ea21792aa545ed76b01012fb90c179c87dab65f9af8184b4cfd867f5d5c3eee54e49c29bd78d55cd0d898274eb8dbb450e8fe03006dcdee83f6227cb5d96c10798e64b8c9afba2e009414e83500e85b5268e327ce33403d94dc61b345e2cee69160d31eeef1d060da00fe6d4ccc52a1ed5f257335622c61ff391927e9efb1c4de2179a9eb3c66ccafceff05c45532a35671ee7770e8a1a5c2fa248b5e3e59eb5385790f95f2f1c0202c9020a535183802c03beb7c51e50b4dc632cd88d53eec21a8c7222ed0d8475c826152c9ab0ef3a478b9306e494c904c901f644d572f036fd1b27804b4c9ad01cc43f100854a9405c7aa93af3f736755a5713efc5e92a4571af0a24f3029e944ec108167aa03adbd7a276136eef967a7790f58d06afa390e95c1b74f70ffa2ee99e90ee3186500769758b0ac50a1cf400330f31d3d81c4f0aeb3a975241225fe5d40963523a3c5acc58254bf76f0a454044639b515c089b47b98f3dff8a37274b6b28e9afd419de5d83f705dd61f32e0d014e642cc0cdf3663cb9a4aa9b390c29171026b307e864e3411cd44dc279bf6f6ed247aa47a53487c1f29919ecb315024dcda788a45ad90d31499fa3f552eb2d876bc6ae6e0d570170092241171580e0638382289a94ce446f495fb82eca9992325372f51a25a7303c758fbfdd81dadabbb8258a91fa3c3d8eee9f1f1b421833a510324b3e6033091880c3d06000328f01f0013079f06508de90fac9fdda77a91b8772f515b7030037eba8fddda9ba6081f1d0717080dafd97c50b7b75103007d3153170000007e0cbb330c356674bff2df78f455203f01a643cb39b5ec55b457c34a84d5da1cfdc048a114ef90c7797d672adc16afa2ce98287a963a24ff9361ada7ba2b6efd37dc35638bede8d83a3cb76bfbaaff79c04dc15ad74cdedad1ad1e6bbd09ec920f422d8a236a9510a79642e69646d99e64b4d3a5481c54213662adf6d8c250dc7a05920f1cdd8f55624f857c523be60e4b0f9f6a81e2770d17b868d5ea6387526ff92b93dfabcb8683b2bb8a17e6204f095e6d77918b680c3a28048a0286108968aea81fe5ea04ece01c02b82a84d90228ea7fa8e38142ae38b68b3258cf86eb3e39aaee79f07f2dd395045556310b39cf8fbe9c11c2e74bf29f2020997aeecb488e8aae1fec09b409312cf6480ce84de7525c0e0829dd890aa734e53f0d5ef7606f826e181e2fb68d8e37df0c9a6ec4bb3f5c67bfe38ff850f074d9f42e91f681782ef7e36a8a4c0fc027f94e9a6fd5ac50ae1d9e1c592b9cd1c9c0a2ef0c0756b43331d4cbd289a176e72f71036ef2228a61ecae9e1df74dd6862bcd1753eff2890444e451d68f34f71eb9eafe4e81ac75ad73ad858172279f025c4b60130a6bd6348be60853e466f558d427e57d035b81a95cbbed56ef55b34e2b177bdef5ffec184f807e71652554aff3bf2fff1f45dcfbd56386a86995944295c1b36a7534889335c6590a6ce674243c780afffdd0dd7f146e740f7300373b04af736c2b26fd12e165f8796452caca6321deb5a8ae307cb779d30f1e91f78a6a7128fd4b26611839b2ea3dd5af9d2f8609169999310e7c15ba529df33a4e064cfc320ac2978931b1defa9245a0b7c87f2e6c31717eb8ccd3d463d27d0ad8de31070266dcf8f23c4830eaec1026af0baffd7e7fced3bbdf4268a80e39d0de09f8bcf546025cc4bae2851dca1769138fd217c596b448c7980df490c814bf1b9b212022f167fd761b6770ee36450504d66ddfe21a780bdede4e07905feb79b0c02d88656a59f888326af44fd0e834b5d3f2a6bf3647ae34a34e5d158a4e43ca4093207882864b0039d50278aafeef7fc1d40f52bd9f9a17f5f13c22114c8fe5578bb83568dfaf6b33a3d5458a93488ab81a8d6bcaaa7c4d2803a1534c9b8bb1d5bc87cbfa1b90950df3883e50e84621efd44bd4cb9033e798dcdbc831c716a3625ef98d77d5ca733f78229f3425bcb783a310a24810cf6e9a0291b1b13dccea1c9538dd8d0ee8c6224163d9f2053215526ecff6d4fda8ffe0ca5bc5587fde9cb7bc1705ad9391c603c821afc3875db41663aa852b85ae63f7e82c7483986e53cc8f52612512f3351eb660155dd2ff190faf04701d7dcd3b0b70398314789755fe96f5abbb9828fc050ca00ec5e0ed900fff0bac28f1d639fc33147c5c173e9e4940256d0e013d762caa5deaa7c493f28455f1dabedbf25fe9d65ff00f1e90e4ba81d07257b40ef2a871c1d27b6fceeee9465ea704ca4dcb593bfcfdef0dc60334cec8de4e98409511db7a65fa0fefdf6b27bc318b77f0f25dcde05d0dea51f2c013d51611f3ac80ac9e0d672081f65fecaa05da4c01e1bc5cfad89bfd054a21c6a711d90b2d689a23bfb0b69bb29aee96c09b4dbfe73cfe8cc8e11f115d513db7fb4b3bcc285c368317d003997ca64172f1beef21b4398382f66189b22aefd69ce6f7bd353ec235bec5c7fedc7d9eb9c5e8ef5b552c56c189efb62d0e42b0eade7e9e3c669e946b1fd23d1e09da0ad67888e9b2a48fcb9e501af2c9109185f295c42570fdcd2d61360d1dfb6c29158f5c858584ef85318974c295ca4ab0d3bd7d56348237aba2ef9a87e3263952f9c8b9982c635e72d6eacef299da553503a1c35862e5918353dc822eacc4c8992a47a315d4393ebe70dc645eb3da4bafeac8fc2041297ccc052e00eb10bcbb7d26be8495c13d4023ab479aed13a031a8149fe1be36f2d310ed820feba536d6c3f8c9ea02a10527ab1e38eabbe06c8d5806cddc2da7659baadab33ea1600876e564c4e6137bbd47b748aafa7ba9fcab6bb3b8ae02ffda0b26a1ad9594772c02d4a7177cb8d2bb0caea1969f247e448daf7fb565a32c43ed068302bc500971943a42e2bbf9bd9dceea0390e399f47881993bbf0ce9ba53293af1e4127732dd4645024c0c2f54bc9e8004188dcb1493f6c6848ebb610435d9e039ae05ac25f259c8239df258ec28d9105cffd4c00fb2f36587a8e9be7cb60bd7104096f5acbf46efa3eebfe6572b249949d4e234f25cb8ba16a22a273b51570b76a594f3f36852deafcf4f538fe617c2d38930d6d0e28c4ad104c86167432aa2fe673edeb34b1e102279b50fd0ebea3a9c845dafd921315111709984ad5602cab1b3220d6a3cff22c129088a711448d0eecb86ac73bee4eb4f4b8252180ef2cdf41a389ec8d33108da07564e814b3e48e5828ed1f9db4070f6cc3920eb9fa95ab4259a563cbada16aff2ec348238b5bc0a53f31e2ac86b218609b7b69a3764f28365ab0889b94ea4c3ff671c351cdd14e9db82da2da698e567b2f1cdc2dbe1d97ff983e020500382c83675f362beafb159e66b3f50ad3143ed7c6506e65dff6825629136886d40a8ba1c22ef241a6f4d7b91eed2556893b3b005e26b384c0a9776b4819c4ebfab95d5c2f037d3d593c131f5fb91206ea959eaf948d1b2535393444daa6bc036a52593d9e41fc50fe169a6ddbf653814268585856be4663357d7f2eb8aaa2a842f3abecb8258852ae27da504f8e72f1cb6679d0bc567f4e15fc2cc4080a3f09c6abfb09237831ea24d1ef8933cc1a694b5f81a56612076cb13bb554e1a4dbb78ba8774e823b1aa55945882ca8a9baab4645bd964fa14a21007a4b6c09cf5b6e339b5dfcff3458f4a4a91bfd6b7f46645601e3fd5a34a4969fb93068203203ee08da0524a9655fa14c7955bb91bb00c7d9ff848d3faa2c003645e03930f03c399a369cd93a8bae8ee78928c0bc8948f327cfd658c403a46762b8276359b4f8ddf7debb3103156c2e0ffdc79abc154944b81ba6a57c717cb094ba000882e8aa335ff99cb96e3afde46b134d5996e209c586297f06556270230be9c5ec31d841091c8498c01df4f9d975b0ee79b9d2bc054e88ac9dc4ff31cc0de087e642898e17077b9051a18579ed27688b1656f47427b832dd76e2399a243150f2b4da722559391c3711faa32405c2551ee1cbe6da6a78528ff4f3e24dbc0878107041e5f057dbebc66bacf323207b6b5f942cddcda7daf6c0ef3c27de6422b140db9b02469a6f926d96b030d6cb29c994fbe430539d446725f9e73ff15091693f742b398ebdfc83fd14feb01df6f40821650268962ac15581087b1e84c40a7f328ecaeb3060c619ab999e7fa23e8d97c820f7f113de6cd99fa490c7128efec0bbd5a9197b657631f28a9c9689c0f49c315845a5e56bea7fbe317cebb778d362d30abba47d14457554176763e05df8e4cc7dc94d25020f45609f3ed1c95e9e1ba9e8593c975b04ba94c7df83753b2757727162c206532d987921b03a6cff0dcf0bc6f2e675d958248c65f94564da53ad8d7bb5810ebac6f6237523880e7d65cb472a2aa271e66503d6570dc0f189de8ba05207c8f474b3023df8ca169c04a02e786e43e7224078fd281bf7e087b5a85e720cca1989ff2da78b9b766d4b0d5ef668bc7adb3f095d9274a73655e0cefae84a7cf9b7a0745598005002ceeeef4eb6e29fd2020e488664c9fb4a8af4f1eef2aa727822b4b52e96d2ae66e21779ada561de7bd8fd898b44650f4a4844f3f9d1daa77ec1b4c012472f65223311dab5bb638a297124f53e225269e4f89fa99e254aba203f77b084086e11c696f5e41338d96562b103e5e5fcfa4960e677fa878d0b01545964a98125d549c3443e33adff4bdc6396d3570df91f192d037db2420be06dc3bf6050c4faeb2c90e703c07f132f2bc16b24c66803f056c8a4e5cb3c33f9e7debfa1137a7e74c645c057b1b36a886c224ff7582a42ba77aa38d6097c312ce0e59af6ed3729a3569aee03e107ef30a820f5c3fe7982ff05242b4356648aa9bd2ab1af369fbe85e021823afe053d07e3e8872ce858d1a6c467e6496e8a4848f1df9a815eb5ecb17c358b86e933a6f8ce9a4453d40e1d4c92b096beb5a025e07229224886731a05514b99ac4901fdcc2020d0e457d7bccfd780e3a0578f9d5d09b52bf392e50922c9f03c7c77aec9ecf01b2a2b06806e4ff2973daf3373ae3120153d5aa8391e8758fac9c33efa3da290a21cfcc5ce54345b49361d9a9ce1f2cb7b351b86acb780c07f3fcb8b0a5fdc9709a9f5456f3b050604af43e06fb19a64b579627d3c604f217f86675fcc827df5620d44fce4a0c288556c4df3fe9c5fc05f1ed6da392553a133fd289d3886d12bebadfd6bff576d8ffd8d4f0e59fce51f5cacfe85fbddc488298d1925599db9bb50d9a733ed6c167e12cf0c94af4535db69ed753d67a4546663e9a7a7a6714b0cca0f090eb3de1b0dc05606360dde0183305a213f18304b92e7c8442e2ec25e4460887c5c8c284051eddd36ba27e7d1ecc1466a2e55538c0ff55962702055e5981bbe9525fa2c102cea21f06f269aad61bb2aad1b5bc2e8537b1347dd9065b7373148c7c2f7333e4ab7b1b9ae0163041bbcf8d5d11f4428700153c7bc567c1d7553f2f6aed9e0994aecc517b787f5ff78351e60815997bd9a7e6b7e9926f548b9e15a26104824beb8f963bce1b48a75831187925e9212a824af16bd35f9635f28314f7c6793cf2feeab8944794858c82fb68d45ab5140602b3448ba0ac8091c63438b8aeeccf785c0aa1e7d22764a97212314fd2f8ac1361cba7fd160e98f663968f5a4b50f1c8461bd0e85b53c1cffa8d5a806001211081d47d426b746fad1ad7193ca2afeaa0dd9e656561f6bac704fe30336cbc1beb08c52777cf31908a89ae80c5def3df921e4a7bc7b3934eb62a0c68e36464739d42ac94b142c1e82d5efb0feb5643e4305807dc4346943f9537347653e28345d7eb9aced158f6bd5e9533a67fa617205786ef2c9dffcfa827dc3928cc780512e036da0cb058d4aaf86be78f9ad7d46ed566e91cb6933d368b5ff89c420e7792c2fda543342d64e64f269810fd93a823002c1f28acb541fe4b6923bfa115d54414805a4517a4ee7aeddc07b9b92745deef33d45488f32ebdafe632c7836182f969399d0e8c8e44384f4c5888a86e6cba9c7a16806c9196b654bf1b72eb635e02ca92b38c8c9263a0574bf82f0a3318a52e2f9330fa91669438bbe917bda6b61a5036b4e7c9a3196c2a7af82698ae614164852eb15523171876b01dfdceaf5ba885a7e1d9d9b2f0b51f641c3eb00b789bda25b9da1b2c7d00298c291f6ff0a38771af0b970746ecbbab3f24b2bf61a13b007e0a9edde4dfab713b8770f75d1066f148df81dca71d46c2143f3e6f7cab6ec53279c93461c773fed6080b02636e681f603e6774537900bd5f9fb0fc8f0b957e57722cceffa869b8b86d2b459114c68a9a6ef76d821b16d00f5132ce972b164c29f0ace0258bd82195b38af8051fdc44cad637ed26b90b849db1b3a26dc9d558370fc051f56faa2ffb593ea03df39ce790854933db6363cd5be9944824da3cf8994c17e79aba3476c2548f87eb7e58f6c65c052fef4d52058d8b976229d1e2fab1f90d687d02d22a13f663eae0e1878f0a7950f5d8722fa0688020cce0e83a50f26ad00666ece82610a061a828e67e45f2e9adceb7e0e3fc40bc3f861e311c965aed0dc7014eee97741814ec7937ef2570af3689a2002b31c7abaa7cb1ff21e880aa74b1ff402de9190861232e8bf39e3c8fe53d9c1f2ec97b7aba6cab029a1dd47d970d46d6300cafd930110b40867acff66b58fecc2a9334492dfc372463f906b95ba2ed0107cc10c88cc3f85da3f21e9587756a5935ddc7f484ee1c9db0678933b0e8f32aaa827640b78a099bd125a2248863be768ac016b58f4d362db1fdc6ef7da99093cc5f5e202132548721ed6ee499da90898bf09041ace39e79b50e6921bf1d81e54e2404f3280fe12ced24b5e6e1656cd632d7426c2a7107603499300842be0c8fec1365a4e55c5a57765b1748d8eb731df8d3d9ec3fbdd94e82386d5c02fbb79a78ac1f7d47224fe894b3c1fb4b3d8c5722ab4d9424d3ee1059faa7ca608cb21026be98326708c03d0eb1762d05217463e2868a3a38192eaa4d4d73fa7aa0cc54f2050abb5d6ad03f208e6588c520699dea983cd1378a4e5a411f0cfee5699ebecb8397b165432d9ed0fc9424c34c644d7a68cad50dbb0d9620769915a076e3bfe817b43f36aeda207c6672be68100625ce961e02aedb0669e4db7193a0ffaffec981e1bf5f6a13ecec7722f2123161be7ab92ad9a104e19e03cf98c811b53ca00b248808ee41bcac2b2c36b795ba06b1aff31b900ddade81230a689304c4079eb11245d20d53b2d20822c15ca6b32d74823a9c15130156b0de15bd314479a53aef0d9053f651793b2847caad3a8402c894f946cd8d6870394b9967b10b228f638549cc6c7d874b3c00725e57eeb140b063de24403f3d18837bc1c113975d34d6dc6b314c253c181771197eb23f546745e8308ed0824e7fb1528be904cc7277fd0f1c60a3bf63880a6cfef2938d9fc97a06cbd02294cff0e9e312e88048dc056db1643c90b860b400ec2ae66eea90d11b22f41511243b26ba6587209a3d3d9e8350042678eac215692200f977717a50cc104f2723107fc5ccd41bd1ef4c975761d72579c3b40efa726091bb2b5aecbd43ff022f5f32da24cd832e793413ec0be00a0c0919bc9e8efab2a86dacd193f20c2de29443003485fa64f6f3b0a9e749a384169d8e4c7671115206a1b917475d5c2b3c7d83ac3bc3c0214d206bbb4f440d1a2ae005ede874a031b16d7e69fa7a8e7670a5992aa44c272eef4d42ba88907bf67076d7b450c15e8c08e27ed75f5c7664827605201116902421b3a473c600b5d4ce5d4ba52fe508532fe01866b17b24c6ef6045be94aa73f8e6dedc9e41410d897380fe9d2de5317dff771456bedb636ecdc4a60c7e64e001b3d2a9fdd3c3b5e190768574d7c3aef48eb65e654c6efd3d018a1fb795b996d3fbdf5256b23532763e00fedb19705f491920bcdb34c86b2f5c58b92436e0da9a8500cedfccd93b859a84fe211a81e6732132d041a0fffbca8ac124a1c3864672a8caf96c0f17d916eb1dfa235512ce85c98d2a608cc76ed5f478dc02305c6b398acb2c1d0641ad04b6cfcccfc7bd23e5ea0a6cb9a4bc7d8f0bbf1137a13d39d08c5df33d4619cb5eb33841b90fe9a06d4083471c8e3ca81d29cca205923fc2459b0fe9d92703ae6d2cf1bade3cce41ab761ab46ee4643d6f56bc7ea235a9abea3e21ed9c23a87e857ec0b2d1aa5721a27005aaf2ce3ee7454ca9e19510772efe5d1bed8d9c3ec3c498b368e498b3cdfb37fe86534724fc912e8a41155813d32f6e94e3f7f81e2ce516b461ab203ecbf809e96f48d30689af4ae8f3069acd6b0614dd473ee20cf828e1f800a19ebd055609d5d02bfa38e57edc6c1d180a1331f9102630b536e6ddbc87a916825aaf2688ba13cabd99e190f794e1f1361d7df199a8bdae31c34530d5d7e49452ad452d2038277bf7cdf8742bb85a780b7a6951dacc0534862a769dfb8c670eb96c8d2196047122b62785e1c965af1311c539d086f23c433f86ab4ce83e0368e08eceaf5d9b484f9e507cf88f206a3937bc8a8ce68cc21ce75035880209513c72af4eec9721d0bec3c0c3f3244b07281d101e647cb925b436fce48c6f606b1f2e8d14934ee639a990bf0c87c11cb40911144682938c5b226b3275324a083dd6141e39c8f5616bc8cb2b22fd514fdbe12a76da30763c7f18082a4a0ca62cc395bedfea6af982863cd84b815c419e2b011f2f140b2d3175b071f40cbf392a7f5bba80183d984a64fbd6fd931fb1f83a8a3d0a8c2548869729e3fa568cfd9e7befd92bb51594c7b6c22ce595fc9e42a94018a65ab9dcf6bac0ba7776bfabcf4c91e7abfc400171d8b22a92b724885044d71354aa39e803481587933aaa754ba9057be68a0856f58bef8210dc127b26c22d0775e6308b417011cb238baf306191bc18e1fd1fe14284a4b01584fc2352d9ac111e714298a5b126a8d1ec6173216f30a81324aae76af4f38f4e5d22cec19e6337c9221b9fc6009c836aab085eef2fc1b2f78ef417dba4d536bcf51be8f5f16e18fd51448bec01e25132f8fbde3913088ef90592b471cabe57b4346fc89076671ca12c4b32ea06cbceabeec786cb1990e0536c318dc91fc1fee10683ef3842141dddac1d7643b427e9161cbb620d0cfe22674b160dd045f1a75ed3b38de3b98807206210a55db0eb6e592c90a684d03a36e2257c947f7be48d15f305694a5faa13f388963b3876b9573dd9d24d932f19d16d2b305275f2ee39968311e0613fba396394bffcfb9e6ad6e51bba91195ee01bd217c90acf26694abaa301c87a994d32ce37248db185ef97f3eacb84979caf094473a2079a218ed12c0e46884451ea02ed3ba0339cb699f15919424f5bd6da8a9e956e9defdcd3a259966e83ed0330235b3ae761e3a0f2ba074d099b7ce0780dbd56ffaba47fa3d08a33dcbe1577c315f1625ca8a529f10e9f273d8910be8e22cb87ee899f0dc137f8d37db231f0031020eed695d63b6c8f9537308fa037fc7f0576af1759241bf22fa60e856343a40bd45b9d9d24bfc154e316e7ad4be09717ddf3a341d2c81f6e99543c92e9ec3503c08555ca3fa87a32c67ff8dba958a75286ceaa90b2151f9df9175c62e9c2e632c671be542b6bf560ec7e10a8ab7498c3f57f79856e26dbf1b4ac405ee425fc30a44b6c74b108aea71a10b706dc355869f3defdcc2ee58b08c20238a0d2087235aec32d7c085a09b10a290e34dcf7485038eac75c907067c2a5c1c610fa743b300ceb13254d86b46fdc120eeff3c47dda3a3a5b3d027f9d2ece9e2b35d9d03401920c5213a8c594bf1db537e1610b29116a768050fe805eef16b001c7162feb26ceb5cfe2fc22723cb1513e649d5cd670f3c3705102521f04b0b56c2a92092b3aed286e61482518c389f5f7dd0987e7ea8e7c07ebc8748dbbd9d4a2e6f3853a3817505d98d5850d7f1367191fa3252fa38dc4e286232b1122d7033c41b54969035be7a1b71a9c90a7b758b29b4380c0f5ddb590344ad5c33be3c54bc80a4eb337cb18c5953ba60727bec45ac7ecdfb2813b365f143fe87c57815df9ebe73c6f05764a5d6857ed63b8c1dbbf0079a0d9a6d32df8f5f86abd01a47d45fb7122e11f0a94f776906501e9e529b68161b55fb265ea3e0b81f632527fbc4fa9e3b6cd06918b3de403f31f808843ae4e51f8117b1630d7db39b5c8272e8dae39403e511780ab0f4e44f90f562dea5f44d41b5d0e236c6cfd28bf22103099f23f7e5bc224805861d5e328f52caf041d27b4e3e25c1e9255bb4c5346a7b590ea2a3a4f543a661a3b95273e68284bd187505656e4c03feacc82a3b6e14ced5a7613188cd217350bb74e23ca20aba3dc1489a5a25797b6893154d80f8f562d3f354e3effce1f466daf53c5ea8e2e9e63f9f9e71e75fdf42727be9e68527079c3ccfb9b2b7b0222f5f1c956c695d81621d1aa816127665371de2e0f8c0f6db7471f7247444d27de02921ab271a938ecdeffdff32b74a88055615cb0194fcde59745491d7100329fb03620714b9064097bd5936149d7aeb1158ec243c9fc6205957d4f4b73cc0650163ce57359cf25826eaf5b3fdf64325f2a8f9bb909f117c1b2cf08009a9e3ba7b904cc7619c319faeee4c1bd566af7ad922b2e0f05cbbec53845431b93ff3d8bfee1b1e4c2916b36336565d1670cf55484366da9242a496e277a1ee6c73426da5fae286ab30753a054080b8291f3856316e39f9e7a65e984693d8e6ac13e22698959cf76a2229a63850587bccbfea960075a05afbbd66e0b8f45e64c6f890c81a3161533ff78b5ae334364445861b323c144c889a68acb29ec8726e57f9a193b506ff39d09ecf445bdeb3e082be700a37092d77977b3fd8fee86cac98dfd1735f665d78f0acf4cf3c1bb2a386dcec72fa1788902059c082349756d87d77a224098ecb33e4f1956c27d4db64e693d5b18a2b78f3b50541eb1bc0f056399ce10a9e910450d8e00c41dfa508b3f55bbce162c68ddfb0d72ba8c549eba268641254948707b11c84c77053bea8d42df85e46e99d1a4f56a28e44fa2129bd80afe20a513c945ef0779e588a506e9f7ebee91692457c44139739d0dea5cad15c4fe327ef91dc2fdc88eaaac2ad5a4d9176dfdbfd792c19728a5d8b8715e77b457810f50330d6b8d8bd65b4c946c6d2a890a1c64eaa4ecbe98b8e3421b3de3fbfde72b999e7d4afbfec4b68d0e5532a90f44cd31c2a4e80f641d736ce64e727df0763b3c3ba637577d6c9406b82e26b455e7d14f8d98c2324ebda2873b308aff3b013a8e929620b36c1f20f572cf3e5c74fa0450aee46c79ee9653cb701dc3f041a723517c8a87c75770f4c4684e27824da92b0cc688f346354b08494ec69e738dc9308fa4582842a9aa024a9ad98ae6c66de38946d068e490cf501f414ba10e57511c15ff3db5e5303f27277988740136d66816d70dd49a11e717ef46a8f843365737c010bd0b32c7fe114baf197015c33e747110229abf5a42023c3f77c44fe62d0425e51a26ab6c3d06ef698db027f983d9669309b390415bfdd9318a3ebf76da07846c6eaff7a1c45ea6a6fbac5d75e5d640a62891c69eb49735df208f1c013c1e0aac7d3638511b3959c0e8b136420e95b78cc631e22be907a508eb64b5673939c33cffe4f78fd6ba6e2d2091d86e61dfd94e9dd781a4840523a474c75a3a40058abe576bdb50926ba2c4876fafebac2252d7aa2940a67403838a3f1b5386691c432a82f6b8236113a89f9c6060e4f54a30af25d3db6b57e3605bfcf737606c324648cc110725d0a328e5122c33186f9e22888f7048dbb9b29e84335bd0a5331281c8696fe765a3da982aa77a2ac8115d1dafa9f8aeb5ba01a322dd4f6d90f820b37d0f2931b86de9287a865f11988943ae73f9a4d933a19b93c25005d1376c34a12fa0445efd73acc7400e1d099831a37d61c77dc464479a168092e5b3909b2936f42bcfe213576b6af4aeeb3361154199de1884902f265cfab66f164d98d305f79e8466f58f59eacb250970d865c1b478f018b6f66ee7a07c792d719431eb0434e4455a8a6986762fc8258e441097f44b6c2dd5b2b8f014b0ce2a016ef89d2ae2166d9b24248636f71e3680e6cf55fa7d10f5539fd7beb85b0ce8247af2eb0755a390420050e1460c61e159cc9694b4272fdef20ab1e50d312a738b0ee9e82518492ae8568c9d24b9c568cdd29d3e66540b1ca02d4804fb81e1c5f8b736e0275d2711af571e970d59653cd2005f049b3e17913887be924710c3c743ea56da0a317786ff9a5206c5054952b38b0c96cad75a636c75273fc01d38722d4ba8bf0c77ae4de86ee42f3539e17351a473c955f987420b463bd3959193800ec059443d24ea1a31e99b511ca624297c6af9c4f03c6561c73f9da0b837cd1f7f0447991f30ccebbdf988b9d4b2edaf56913231750b35c9bd9a618ab9a4e69a7099ad8031328625a651407df40a633b8775169cd4bf41ec2f100a5c33e863b8de22389e0ed8a747f99856c473bfea59f758bb71a925ebc9aba7a632a1ce463c3c82eae3174d9dd663734879f8305818a99e0e104e7d70e25812b8e2a809b38f9be344cd20a3e5fc3f41c5dbefbc9ca94671bd31ad8a85d5e71217fd39f90d9bff738b5025f4f6ef2f9aaa632f6f7ccbfd66658fa7bdb227cc558c4aa82d944cd004d1df37fc6f99238dd65bf01292321dce7513fd89d791d6730136a0a410f9438d23d933e0d96355946ca9b70b356530fd4c4f2d44214bb3bc5c865c09f33e3937c4a21c5ce064c47979005fb5181360e3ec009b5fc5ea0f79aedae8415b0f6e6457f81e9933c2f529b0ef71f4df1d7ac59545da372a77807fb7103565d5b1b6a086d81c3d0f764523d73adfa6bafd36ae22fb7c30f8f29fd7c0a319c4169ccc6ede3d325a23744f4a2c833d7373a0f04b22af92d1031ea8dab0723ec7ff01b98f0e3a24373bbbdfcbf15953dd567d83803fd41ebf114c63e13282abf74748880ef21f1b39cfa0e886baf4357f9fdd6f68b76727f1276810eaaff42a1c58d823be396001734a11f12ab84c9054ec0d74954b3ca673c3fde6469f817f2c6f416ae55d0e225994d1569756a66b144c599590346dc5168c281a0bce01cb80ee4875f725d73b9d5901b55a711da62ef59689d2d900a793e34c585de3e2264153d03a3a0f6822bd6647257ff6ca6fbc6852554ac88d97b9df4f51a40040e9f6fd4220111ec91e39cf9893eb593d9b96e320b9b7f0b7c71471e49c421a60c45d72bcfe53a3b6206e674689f0df3e30986b9230bcf3fa74da0ed7b5a4226984672669183ad9bc2241dba4c9bfe465a44731adcdb07f4e7aad553b1a82c8dc8afbf919ca5f38592628f1139b50c26e166a593911f65c95ee1bc63a6bd847b1054068dafcb574262a231bca3012a4cbcc4ce6a388ea34b5f54bc967683acaec28c756e86d948f802d091834b046bacf155388ad8a891ef0ca5d3f8fc7ddfa488dea7fcd5caff2f135b06c3ed12fb4ec18a804466cafacf90a4f6d9d74b7582e4333788adb7c682617671790e8d060fab41fb4eef33df59e34ebf1ecd43c1fd8049adde924a4ad39243e1509704105118637fdcd939cb6781a86d525d89b1a8e0c91d72404995f0411d79c45a5a6be3c29ccabe3b465e0456a84c8f201e41323a08474519e9b53eb1181d26dbcbd754c62e2191f784eba9c17935c91a683ad6941ca65c0f441da6810b0c9cf0f01a3330fbce6cf097d4240824c981a85aced269def9168aff8fd5f30019c9becb2e7d9cef1f62607a549e90d6678f2f03541384d8c8d54af4646dd3d49e4301281aecf3a66fbf1b3c3a371fe9482e0eb6a0c750b9d703707c7f654254b8a07be411453f9e60c5352ecd083b29f98d24869ab9a434810242e492d461cc2b10c7e7d783ee0d56192134dfe85e651c00a17ddcb8ff88de4d89669a0f236ea0daa34db6c60b255e7e397e06c35be0790ae89fdb87f77ea60431f8620b12c37961204cd898bb8cc9b697a0ff8f645be33ba62fce4aeed93749cb33a5fb10e5612f6f985c40e4a1df68d1da9e92642f62a25959578dfab7309ff074b5e851e0b401a09ab1781877030203a8750c03f83b330b5ff95de8dc2add8d89e2276352e8ff8a518bb7b6100713ff87071cb38ea31ee43c5989b1769c90abc88c6f7274728a9d21e28c3377c00b22ad58c86ba94e5cf70f65a9dedfc173c8e109eaf2742959434a05d537394dc3dca5cc0497fbe05ebfa9651293491678e4df2b9eb3006d60b9294db3e40f835fe51f13b628142a35987b51626a28d71fe82964401218c5d9c1f903f5694e269cee2d08179ce309eb0fcd4d75ed82e9f89e20ead6c38266ff2d973d1d6d8191ccc255dc3e305fe1669dd9266805b386af2688ad0c40a49147e01f866ad5c3d7a1bae393ea0caf573a1bc5a308ce5c22f11ec6148e536efc59a14b125c6a1aa7f7ec1aef51e6731e390d6f66a4e5c4b1e00ee9de840151dd5990da408674cdfb704a57fe07ebddddb20d29fbc20e32fea1632412de030a12d518b66a546a2d54d814c19f827e916596a3b30441dedd67a74cf9c2acd1da76e30310541aec35a72b2b85b07fe85061d6c9986f331b74196aa54762a241c41d33e8fa5dd3bacb6409339db40e8ce6e8dc942ea87bb8e76c1eef543125f308efb6c223114f705ec5006580bec7bc8698df9c59bd033857101c3d6907c6222a84f1152d4335bf4ffe673b5566b1e58066c566b144ef1f8ad0806d61bf3c014a2901f7317fb6bc079a2299f3a7731d212cf837e2a903459c612d8c386e42413afa3e7442d54e81bd7180dcb277222aa334269aab21dd3b4beaea4a33fac980317e062694957f48759f5b9f023c1a15c922ba4a0527aa9cd6b105732799cbb0e838e36580c31a6b1108b2e18b380e27e65db8fb36be00df8fbf7a5449dddcc1248abc3e9a488a73cca177b541d6283f90aa769eb3c17e3330c51591bcac69f1e5429c91ff859f11f84ea14f5dac5bd818b0bbe8b3c5972c0754f58c869d4203da4a6ff6f29da9b0a561711bccb99e5d2773a1e8103e2d0130c9b2f209bf26015e79800b9b37606dbff84dee7a2d8448ed411e1ca91374e714d04e5cea998b722087eeb87b80e4e70b8859875a01fc04662a41ebef49a64b1e32bc530a02bdb18893d417ed93e68f01ad85177f8cd8756c1da5167de6fcc7a9f85194595e4bb1eb9bb5f52d26f728af00fbdb8988c5f7f33c1d8e90ee634d049e054f789b18c154e745ddb8f3a16fe490f124d3823cc4b81e21aa13ac2047986abde68e73f803f6b4aa6f7715f325fa2b4d116530bb8b14a17b489c7dc2a7b6a5e5c521aae6129356212ce48e7d3946d455bc8e73cf92c909bfa9a3e878fe146db337fb573e20a2734ce164db4d951913daa727d26bd2f0773db4d4e0e3c13cc81cda621404034445b261f60fb54777770311c3af8cf560456050ec92eda7f247fababde8b132900ebf43b439005d4280afb0f17320abf21000df79a044d3c38aaf3465cd0d60f325ba08cf0c87b2346b47c59cb8ae704496be009ec5343026921fa077e204118cc31391dd4cb5b512643ca53afa8066401085a5076312311b013d683abc9ca3e9a1ea62a04fcdcfa87e0f10a566a088036c04492443d9def5b3eac07aa1d97214691e68f3924d3dac763c67310fd790395f3a066a68e43dddec6f89d0ad8da01a3e3c3f0a32814cb055b8a0095fb8e4059684052245bd127ef0690ce5fbb3b0ff818e8e51204f3d9ba2dc2cb4bd08c9f8d6746a3146fdc33f524ce0ec614322c329a156424257bef8b33beb71ec4f42d2a23287b503ecf4edae791d37a9fb620b85740efee1739f29752c23f6d4fbf04ee7094843e64c59a882003fb58624a1c737783d3c8058caff17ca2fb492667307272b554e527ab2ef989fe1ec8c30338a60c18d7fc33295c2c3f12dd4a405e5d7277c8ffdb61de2671d46c0d2b9c3d1b4fd7ebf03a88ebade9eb92c6d7c9a62469ba5941ca4dcedb2dffd358dea1d519fa6a51c7b08cbe0d18411e2ab51088d2ba09a2292c3973cbda8fbb64a74a7e21d8219ed8cadf8e38604593292901a5c709d9003e99d20e4a5b099bd84808ee3fce927966bd87d744dd0545746a7a14c3e171bba6c363c80f1f9d006fd6ffda2f24cb1f3c1cccde8ed1cc82bf38709f200f13c32f2874f61c31544c09d97c9801046e1d2230a0d41c923b973fb2f887346ef68cff3f721d6c2b2ac64173dc6f27fcf2a1f510f4444c34315a61a3c43521a624cfbcdc802d1278bb34877576841e108bc48bdf24c982c7c1791d83ca445075f19793ab667505d4690c28034ee72aafd6801733ba5054a6bbbc5860533255c6a44d160c41fc4b8072dfc9d18f5a07b0c81d222870970e92928f34062c3d85f9e03a5f5280d863fb8c0418b1c98c2cfc42a4cbf505c8641651ca1d90f98bbc51662f85c4d98773911f96989f92612295b497d7dbb608f4e64fa1e6320c5518b92968ffbf1a674d5068621dff353f03f94e1fcf60fa8f57df5ed5fd6217c305988afa2487331aea0b5845d029e9952b291e79125d5977e143d38d6d7973a07566640c10b2c7a233067e8f47499fe90a8f1bfb8c150dc72211ea3049685c3af1c4eb85a58b9c8415b5f73f6a4bd9c02b5d659778dd814fd6bc93cdab43e74219eafcf46ad6b9d5167bbdfc3bcf5bf410409d4b5cda2a93c72657d8b7f3da855fc006da325d8365d323ed90941d5f9502ce31196afa63e350a777b9f55e639bfaec61b69563c77cf6f0a9d85cd4ddd606a68bdbf6d9f22832891465677e433ddc0516b8f9a479d51c889cc6cecc005a1d09956adbcc68271faafba6d62631f8dff2ebef96a3ac9c88e17dd7c87d61612c5be9e8560fa260b2f7a67c3e01f695a91cd5088d2c4ca8ddb4c8bd6489c6122b5e355b51f70d76eb28cf8bf9d37bd06ce168fee9fbfc86adb6e67282fb7d8639117f5d4891e7566d0b3382cb626c2a2148a83c764e7b351db87f80fca6c9f03b61d4be8c715a52ecbf107224d0370a424c9df9fa6591ecd67e0a9d2790cccc0e9da942ef1d17530097ebcc189286316eb843fa7c5104f7f33721db00d6a3eb10b837c9772e3dd2305bf3230197fa00fd1046a0fd8d4de3fda82b6d2aeab7b11419bdf90d68369ebe56a1b56b22b4f563127ea4bede5dcc927dfcb8c2d54c5f321fd00a7cf2dd1a2b7c36b04b5d2056ea0de4d63948d4b8a5f3dc43a12b4e771f605320b0ad55f865a3ae062c86d50326414abbab00fa092d50c3ba5776ae880d3607c827b9a2c0ff8a395b7f81d333c7745cca52382ec8a756e793b36ff5c024d85a9ce17d4aad9c4cb39ba1e82554ff421e813f208808f2d245e0bac15e7f15c1630a8f648419e608dd53fad20cb0498750e02cf89b6a7c0768bb785ac2d72de9a7045ff8cc75a86bd0e24c40a1748f73644015293eec29b362a5cb3a38692cf874163b06a1e8d0a3d4e69d5c01cc2d4aa026b10d33a3bbf39a7f20a023d4389593bbdd9d3b0c6886d05a6d39afa3766c0ffd60326970288dcfc1ca5322b238c39482b8dcbf34aff1969178c4b1d6fd3e4b9f523e574a336721e5939fd1bf031e609f3a624e7af4bd901ddc16aed9b8c0604f17edaefa13181e0746032c632e1ed093f61b904a3ad38482166dc822920cb2218c6973187e34c8fb52e80e960d461d57ee52f9e62c9adfb6c00615a3fa414d7165127e657e73ae2e784106192579759d18f001412a63af444402d880eb07c13e12273859a520d6b52d1bed821849aa0dbcc087857922a2decca07ae6e463f6408731d2b74c684bf162ffa9993c27517dadc884ae79e11be23081c3bb340d43eb4f708f7a84aa4ae47494e7742774189fa83929ca896233037b5b06e5ed26592e266fb8768a0dd8bbb5b60dbc1f6c8aa0e8210388047ba2862a86df045284cad13cf122fbe05b877404b3fb53136459c96da235bb5546728d09e0085ef4b085ef6d74ce7e238617d9abe9053920385ca99b8defe729968c346de19653684c638deabbaf87ed6d2726b6deac2e3c9fb8a93c6190710c8aa4f276fda4a6ad1ca2bbd3e5068338e60d5b1ef538c60df84a781cb588943240a9253590482c44dc2719d637db82173f45403574fd7708e86c9596bfa7798e6327173b6821ffeaa041f946baaacfcbe956064a058cd535801139724f2b05e42c71ea58b1ade521ea93345fa70dcbbc27154fce0da92d29f855387900a0a1ab144eb1acf1ad84b8fa1d158da6deeabc4817a9871a70a921cc08f6b3eb7c002d212252e695b66b217a7a9b3dc263f5850eb3369fe28ec917be8e51cc48cbda2e22f08c789064dcbbcd8c2f0d09bf32488573522d551a9804640f89c7cdae59ff36a9ec815d4029425d0eb7b45a1d3c882cc1f6392109ef104f6c5bd2653ce7edc3a6a4274d3ec9f18ff759ab0b334c9d117c2d0e049b0718906ac312a1210ab2b3c5f9da7ad44a6cf0215d383713ff3c96a219d9bf163a258a25db32803ae36226252031d807d3167af7fbd0648b6aca5797533fec246c0cdb244bcfa0b9ddbf3a7cd5d6d747f542a921ddb913706be3a73b2603e63c6935fdbca8ed1d4f94e21eeca9544edccb33174650a2e7465c67fee718483dd4f30ca373b4f738afaf2bb8484f4c779f8c90bfd1b9944b38f4b3778d702991baf91f415945b871551953da5598f4fdd81ca3a2310ac450221ac0542e2b3bd8ccc00e60340456907401130549e6597fe49d775c10d64c10201d97b9f701f80b1a0829df283c3e2f528b22cc7a93350d985e4b3ee86d634910d68eaea6a3f4cc8001212d6e86da0f65c2f6eb78a6ed99d2803355f20a3851c374b9496521117ad8640a9f9cf526cedef4d1b5ff669c233504371f376c994adb735cf4e3ce7630ebef0097c47d6f8a3284563e64eb133c19cb1ebb8926d2c2f43b14e2930aa209c9b010bffd3358d52712939894acd94962518b975f5761882496109571000da116cc1c425ace0303d7894066df77073129dde7941776b19f3ff1e207637ec22b0ded173559fcb54b3a6ef879f9c61242b36fa7bbc6999f84ecb956a217079a0806a434b1455349e9436169ee52356165757a83dfba0fcd8c91c5d89969806aa37b64164bda142e3c63432677286fc74563d47afbc5caebbbc741883c394b4fc9fcdf11f072aa404906adbd0193ba67f7601d16a1f808e3a89835139df3796a65bd4323a78ec36e37fdb3f554290481956b2b44421424e2946cad928f5d1633125b970d6e32a129805a9e0fcd28207af4cb4cef0cbfa143747da9f39c6c3620a20cb209b61270227d90e6b1e29b9b89475a0b79c5e2375fdfe2b64d334f9e6c3dbac02de62da8d7c2f7f969bb8d8a2779ff783e62dc4c6bf0ccfe81f4b6723a37078b365357182170294a8c0d25c3179bd40105eabc061b032031d1d43c8ba0f70b4025c56cdbb079bc4c56750461fa0dc933130630b3fc8b7f71bb5dbab8266d643905034d5bc67076efe4e839afbb26bbd6590d9927e953039b9d1634cb43207c8024eff3137424dc0417be76ce445b01291f42be5596970e18cdc1c2046f625234240ee278f4685e35a26efdd38f289e1b4e24a5204b7a4b912a8244299f0237602d3460cca835b87501374f176f4e9a8d4c56ce6c37a69e26f136792af03582f50dbdc000a17f5d95681c15fc6c7c7328e7c488d730ef5850f98122315c34fda1293150ca08d80ef2388814d2a30e2274645f97b78df34f3c674ccfc909e4142304a3ced00753445bb44ba8b828fb8127383bac8f92d9c27139c2b4f240e44c911eac565a7c40fed054beab0b165f71c09a44ee2874bce729caab9084ae589cb71c6542fa0371e0320d5288b46519900d781f0b807549341026e44a7db6ba89e938526cd500b8c16fdb0e7a136e12f8141034b2950856a275e93f92237a8c6c4a3a29074aedba09630589e38518e694635ee361631553cb5bf4093896220b343c21086f353f8c59a7c66d94562649f86cbcac98f4d43cdd6fe5d80f94e63af6811f9e0b33688ec63916a0aae6c5f0567baaf8a06c26135e2e5f95e1eb11537ac70e4bcc6290a1398dff8ac71e58132eefb369fed5c0efb3df9279cb8f0f01e93c221c12b3a7acdcbe2c3391045b1685e07a6bdbfe91a855b5a202571e1a9cc1fe259d08ce0635fac7048e3e0a922b7583199626579dedd1c412343d8ec717c216073f76c30f3a0591ce5fda84ba2b8f673fe75b21bbdcc808bb0ce96f01b7bc0c1ecafef0c207b69ceb17f8039e6235203b1538746cf35316590a42686d1954cc29c095d5b52b25bbfdf6fa125d06fe3c0e7639a8ad7173d30891402a1e8f19353650f439aa8c8bcba8da1d863002669f713253f6796830c6bbe7993696c7430337e4f276733d0d9c53dddb08e81dc7dba58b4fdec3ee8cecb9c6d42d1e04054b3861f503494cbdc7a7ac9351b081f813a26aa825b0dcb0500229b66330a33bf02babfb935ec12b0e4c78d1c197bbfd195a7cbb0ec4bc5f30023d8b201b55acdc0f516d7ba777b17998be0e2cea5cb6bee2416081f85d2857b5e4233280cdbe161fcfd19dc620012064b5e33466463c37a83c80046f0b33803e62cf584050e8c227529fad542af5c87db21ac3adbd800a783ee444636d690b9c644263ece3fa750b77b7e7cd4c5b58acfa82fa7b679d272bbb01adefca962d5e2d14311623aea12aad332e89907280fb0c13c8de657f70fea2ef73bafd9187e67ea199031a2be4306c4b0a5acbf7c4047e731dc22921a41dbe8dec7272f84a7ebb5ad9539797553aa3fe3d986d638c6f4c31f945f9d89c19a2dcb66531e90cd1becc6c2bb78b3a0b42179d9200f2c8d023c8968f31ca42a3801af4fa9c8fec5ecfe9c60d9e74ef1b63bd71809f80a6d68b770f0038d754f4a580731c6cf758c532b7cdae3a31420b442a67cd8311e6e651e025f366b8267e5fd5c9667c427da26d9e6e9d3969a8016ce33547cffbcde684c15642cbc35585864f8aa6940942f2202c0a84e38ef228ad7d10d8c769b11a75526a79807e92f876e8dd05be3b639c116edda0d0d48f323991380778e239333024099a47b9a672787337ce3832b1c7b466466c616c551c3276159c78cea6c57e4939268492021a66485564f89b367e65221439f45cd028ea7fd844989acb988424e492a7430d0ab5fb0362ebdd4c557bf91c3335f7c72d1dee496b4c09f2d334bd3f7b816142a9f278e05e7ad540c5356c5e66e967f31c24b01de5cf1b25ff7cb88d7ff67790f45420efd0efb4996f42896f5fc5f9d81ccd2e418a1510c85f944c7ad963bf1c3a1e70b9122d29d6e98eac6f78b356062bd19f10a372fb8413887f226ab0b17c965fb5a23e634ac1ab34ab94c17dc80325254eaed4eece97de47f2d5c2aced7069be4f28e22dbdfacfb25fa1c295a3801d8c789328d07df6059af651f4a91d3457553dc145b5fe893276076c456fe039032fc1e6928db2c05bbbc6553ad8cd6d6d078fce6f49f62a99510c7624915a5a0da0c1be51497ac412917996bf825d9bfe261498efee0495bcf2add6411e82020b6dc7580cf93f130afd2470fa34caf2a86782ab63b903a1ffac936107c78fa233725a7f02e2f560b4c3a3bbf271cd45e6c775e337c3438cc86febb12f854e4a3bcff7a14c829ace265492f6283acbcae50e58ba699a731a1942517c04ed7dd50c2c56edfa3f8f5143f6715aef4427f58bf2e8e60361fc20aac37a8969f4148e293d4b131a9b9327d343ded1f4c0886c356a609e86df20ed00016a6696f74d5e212ac4a67878ee0fe1de6b80e9cc6a5808cfc05be090a26091f9a882b84a020f218dee6e3486e6c6e35cb4fdea5cc79e8bc9e8f4b1deaa6ab5f9c2eb290b8a5d25b9fc58426bf75614067b87ca2f462e6d87cd2bdc00243019289ddbf83ef9e83d29c0497fe4e6e11d8b944df96c160d62f66bf1c0c1877245924fedce5111d51f4e84c8168f45f3d4710913953043f89d69df0c9b9c1af91438c8360bb6ae7b00be9c3b7a2c7760b984a88e6364aa3e5f7cdd5b0cc35877c164b06cd17fdacb006eadcd74749534ec65fd194e84b87299af9e7b84cfa31c09faad027b980fe03dcfb87f328b7861b0b6aa00aea1e2a6b8494d98e4efd2e8a94b6e7427995ef62abff3e7f199b7e2ddb8cdecd733e01a26b00cd5cfbf40f52e3e297cd1d1133320ccaef81e0c28a200ed6b1d0947217bdd180c6b698b5b085136a8ecb157f9fc2b7bb33339b6f672d305e489d22a4adab9551169342781bc20b94a2a946538cd0adb35469103df43ed1d3ffa65d210832b4e90258e7b436dd13209665adf5430029961e3f20ea82c9b940f443348c62e575912739bda9857bca6f7b3b7643a0720e4baff397095a411de86bac3bd017719da58fe2d50d979c3af1a140bf64fd20fbf3914160b10b0c0d410ead250c60d58fbb6f1fa89e4295d86f36b8cae454c2e44534b1a2ca44d175a4b6d2ce6af767e1a237ae3563a3067077640f3677aed31269e2d567250ea96f17c29b9ad0ca55571692abaa49bc2b3fe20b3b83d75603c510ae80bad5e0a91cf5cc4f919e6aaeff7d9c0c06b3b671af56f720af763d73819d831b93de6dbfc225da1bb3e19c024c2728791dce565a460b42e339b3b081e9caf22a553e5b60cb8db6470d5592f747bc546e60aa6167dea84eb7e70c1171741783103c390021bc49f2114d2c79f8698f7a3c56c48faef254ff0203c55513bfaac151ae83b332e956032e8b7ad5c11e556090f7da5b24da2591090bf57743e825eb4fbd72a39f9bb3fb2c7c8e34d5539cddf09e7c8cb282a099c173a9447297a8da89bfa8487f474d2ad769570a81a72ea409126d89f469f0b4164317b283852b00b1df00fbcc3268de714467d3bc90d4e1bffdabdc4c971c6941a8470b902c3d889dd6fb8b1376a6380773a302c8b100dcabc9dfb6e674084240013495d05cdf494a925478c61c27683e6c616e6736d0818e8281ebf3fbfdf80fd6cc47a0acb5134133ac4679c4e3d9b1bdca23d55824641b71e229e09e45443095992363c4a5d7df03acdb8c0d8bcd0e2e693dbf5f81b30cf86bcd29dbd6a953bcc35171c295b2e0d4bd2556bd1bdd0bb0ff2b7dd34ef16cc9abfa441ad8f17a5bc67e52e46fdc6c75a77a8cdce170360c7070cab2d300d54ea420ba9bb7c404b10659433b08f54f011dd9f0e41ab0af42a8373c926402b512c8d4b99ee6f78b4fc1d4b1031f3aeab2c256904e27b5e933fb7a46b67cebef459303d2e86142a1792ece125c141efda4351dfa3f2f2b9422085544d6d93e7a9caaec417af5a30ce3781633b10b8120ba7e0d53a3f8811da8bd584b64763a66f9b98b8e34673c824ddae8b36482c90272135370a7ee1161a3c4319e7d638c6be6918d26a2d1a34d93b636403fc058bc2a68fbd65044478abe20abd9a43aebc1b32453db17649bb1d86ed0c0de3b3fd518f23ced43392857c6fdc341f26e0817ea2f10e0e9442bed51587a80aa1f068c3dda1068544c9be51888427fefd95fb7d64653b7fcf3c794c8ff118251ed49db92e95b119408be5db3431b9b88a633041fe2882a3268663249837871a8d4492eb9a336e76a77db12d098c9d470701e3f448dfb333422980ecb22f94292359f04117327823d9d934b21849a4465d7fff8c0de5d75e8c3d0b6efcfa5935e02f795c2155508fb28b83898f96f66e63e292e98285972d6514771206f39b2bbe637701cf6098e41e2a07537496cd5464ff2b7200392363769778b10dbaaf0e4b4439ca6590f6b3c8aa1fe929c737d06467dcd692452e65bf52513bb58f95056c7646b94441b4fa6ef57f3292bb967959e6fdd796c54d1c19a97f8ac2a1cb0ae132bda0f0f29edb897318e205de5b1c5e239a9cc94472805a825f911071fe3dd1598747cdbd58c616bb9940784691bb20ecb0e42a0a7ec11e779a321a4c7e0f1c79c2cf68cf81b96d523c595b583110fddd6b86d9bf60e624ce0fe71c7f7005e4f3520bc96639dfc19ba9f91378e791326bf6e553a4a6457876da6d235f2f11c2d6ae535705cd120d83a36a3743b91caae90d55589b30fccdd95bcc85e2ed018d69af716a12d5d28ec25cac8c200b814759d10bbc3975af756b977e645a4710902fc42a1b29c65e0a86e6e48499d4475057adc6063c42da189f213bbef8031ac57e964d7a031e105109824dc617c25e59e3a4b1408cadb657c41cafade49f3e1c2aa63fddecbb665157faf6a3dba0f48bad0445514c8cc27cb3862ed82ee91aed28f4b8c5950758cf5dca61a1cab3b39f9032c13aecf6e3bd91f2b94c283c1fcfbbf05d3913496a41606c258a93be38f455f34bad02a38fbd40f2422e0ae91ca1967e14c24da1248bf9505b4574404968f963da0e77a9a219e7233d33d15427aab6fb647bf2c7f68514c47fa682606c8de34b0bf93e1ba1fcc066527218dd237e3fa4e18767075086c1e504bbc663f6af2b3aa7596c587c6d76d99d1ddd5c391253982fa85215cb70f5f6e3866ea7966fd88599006a418ac0f8cbfe71c9c630177db2bc87003ee4aac49f9fc31b68a885ee79860d74992353052979f7bed21833abef0bdb94295cc37d88570d92c1410704607bb05811e25ee8172a02c2eb1940ff845e4b5fc7636db412232c4aeaf5833ee1209180239225dbd5d6e4bad528e3aeee70dc6941152e1db995dfcfe9a4491b5e75b4ba599cb4f758dffc94ae36ce88307a494c00e34def97c558fb7fe8c85c5675b7377d697bcbadacb559f314b6b124c8da40330d9a460afbd3fdcb36058d609412cc12663f3997a03163cd0e15a0482a0b6ad326697052f483f8ed81ca0765db34c0e9fd4bf45c4a67cc5c1f0147e6030724ed411c4571db114893ffc7322ad066b0c5503256ddac7babfb011116d7d666e7293a204a794cc864e0163ddd1610f6b371bb7da0ded05b15d53c76d2693e348aa87885aebcdb44408fe73d4464334945b696fa2b207f002efd1d29fc5551d6064778178ff90686c1dcba623be667e0ef37afbac7f62fab2c843018369a0c7b425e8a556354551952024d45200680142287c1893e05ad8bb3f712144558877ffd06b518ac3a1dc887d41894c4800785908cb61402b62037b67b16cd870492759d738ac793a8863d84965f65c9af134e6af82437eb7fedeba05603e8da0f2885f62ea4914afe752fe58c3efce6152b6dfd50a26f59fe9eabe4e30588220b6f19550fd0f7352dc6e285beb6336fa6c56e29092707520e69d7dd393412249d205389af7bda7214c046ff4aef3deff5767d76f3ca5e5f681d8766701fb759bfa64c5b0c49c96bd3fe3fafa57591d6547e428e45f9601c7076a7e2f13ddf14b4d6572b59997884adfe874d8ec87dbd9e08a24a892fd471149673047920ec1b6f2f71fdf485127b5108ad1fbb669bbad19f11857bcd7f5490de23a69e124cc79c21f0ed20db08545e0a89bda33cef704523b095b54efe05753cf5fb512008f17000e8d8ab3c69a3486690c43c03859766c1fd92aaa9cb2b7ed81ce90814e4bd0caf23ffe32574e9c7f148f1b1a387205f1ebae6b8daf360d426b041813afb2f8bb32715b44e4ecb1bb4172b587e6c82a3132dab5d0bf7fe561b21f8cb249f311e862cb20b8f1d9ec884a2e0d1745e2f1edad3b8afa0286b9f0ac995c30cc8783b649422fa9b21af5b1773bdd6ab92696d82db89928172bca49fa659721e62b6ed7553f59b3b8aadaa15b99b8bfa0eaf77c1f05435ce0119151774f9652236c13b4e7c289c8411d7366beb522eff753eb48edd7af9bb995570522256c027f0792a32bb7656f1a1ef308944c2fe3b2fa296296a6b305fd9099b884a328c008e82adbc68dd9ee53c13fc4c832faf64c1e8a82f4e582425153558452ef3e71845d4ee82a3a14b74ba69c34bd5ba52867c41cceab5f0a96474116ba6f7ba633bcd343a2e3104d6aabe7795bada2e1bac6db259f4f417b5f6786983af8d0ae61c1cd590189f7f34b0a31f9df798334ffd78945ac9f80ae3d49f6fde84becc11a41c522fe17215a071c7daca6121aedff90879c1ffbedf89199b9e304899328692c85ca4d1421e7c931bf8f6f485ff34e4d98943a8fdbf7742da3614bcfca39eb4b2ad6c4b69bbfc2ea0a95b9cbfd77729f2bd6ac168f919bc50a2dbd81d53e831ce526f3898083b42d514ea7c9b482f6e8626eb020dafe1b6792273a6a72ad0ba99bbb70044a5dad6a12df680f2d47d6198fe462d76749e48d1e74abb3c0030189aa72395d734006aab52255b0fd2e2733e764dbe3091416498f64f65b6935b3b37229aef500b1403f6d3bbdf5b5579cfb0b42e9f8a73ee7dd8fdc35efdd4d8af7d8a4ef6f3564ea4e31898d559cf47304bd585673c669421618b09d4a3fb343a4808cdba0511b45a3bc05397a8da62f94d360714690dfe1a5c5d3c713b771e28d5bcf460e7e140d3e1dbc5bc0b4ecdedfa312b5dbc0df93edcc4baa8dd13ec1c3a87c26a100204f271ac1e292b3dcd4a458731e37c5b144bd02fb0e1e51d46ab394deea067d3f72527a1850dfc59a52ee4c1fa4a18c45d10cc917fe0b5c82d0fffa1ce130e9cd1e30ebfd56458bd155061c72a792842ef4f7c66a43e09212aa926d424be0c10d69985091eacfbc54a47ee057122f20cbda6e908e82e1450b30a9043934683825d6f7562c14ba803132a93fcf0c4e6cced2b7fdcf6b767458735917b2080ea86bad9c3bff8102ae09f6083d475c9679bcb5a023dab34051df8a251670e002434e14ee1f0a16d0b63da7d0c81057fa3b409e4907d97f473c11c2e3a0f6587e1b8adb460ea3b8ab17eba604df4997a837a2e1b6325eabf3234fd94121c23e1cc7067478082716633c2dffcb314f53e148f2c3e07b818bdd5c8202671eebf5da88b31d8206a0e12a6916fae7711c2908fed10e6f0b1e9353acfe18f7d835acecb4af0af2dbf9d55ab7fb2cda2e2a8e0468618bd6c62dae8118e1811e7b9b6d1b058c24ef5d58110e7f62ac754feabb2496ebcf8250c689b21595617dfc2a3317ca2abdf3c9325bc1483eeefe30f30f44220507df8014500684aa01af535b5f19877625edad90ec68ae196fa3236ff339c6a8870957b4aceaf76c1173ade5ae12f8f008979a2932e7297a79e1b42ea453b3f1adfd2e99aeae3050e932e8594686a517203b589268e6d2d9194e40b2d473e1d376f194d8271116215281c2a5d81d3ae91ea997ff3857223626d51483921477c72420a369226fc1b76abbbfd607212f3628a6c1c40f7dd16dd5c53aaa74e136555617ecf4f63e2400c18df5cb0666ee505657a700f26b4ad1deb785413b33bc5b2460f7f8c71bf07dd16216a2f9246490f6d04adcfbedb55b7e3643f9f83f59d7c9a7dd57d616cec1f1a347f35756ef655f6dd61799bd793d842a39315754e9184bd06087ee1ac9e2315588eda0e25409876820b01a18f091d6321fa0a3d70d305c9afee7d219e3b0e0d9bff5447024cff495413492d2f14fdc634f8d41b4c32aa0d892958b8de6b4389ed0673360500edfbc6785f58601b8e074a9f4d90fd0442bedc62c427599dee0e3006fc567b8e04b8a3e47df22b8efde61df9ede9333b58aaa4724d349322b2910248dd0b59c1c6c731c7a9458792fb3d00c92068a62f9d8e48ed0c713853c8319b5173f6a0abf01af475532a15678a43e6d03beb987b14bba7f20eab89661c81444523fb7b4e8367a40d9ce41f022321c50aaa63ed5c84722e400a49db0eac34f5532a3e9ff8e8a3a7e4abcba6b7eff1127d21a8da35e7de5291651022470ba8b214d3e1d2bf64995a44fbc2d68d6b42265891b31c3d20f8d9f64294bdec273f0213eea02c13b8c7eaaaf40ea8aaab9304c86197f40220ffea39b89a71415a0cbb947c67270313f525df062a2b570ed856a245631146a9db5d302f8f9b2a2478332d32735bd9e58e5746fdb76b34ea7ba607848e8af1ca5da1dde0a25e1217eeae994fa05b51b1971b4d8fe2631fcc523640e18f2fbd1da64c8295093c7b355119d3eb2427c1a74f454a0b2940f6d2385aa7df436e9e20b7d63147529b458ea11cf4c6ee3b3d3d4b601ecd5b3d8893e540bb9512e617ed662568e0b0155441706bbdd0ae14ca576c353f5c719d5b7576b69330d8007d54826809cb720124083f855c8f54328322eb14248ed034eec3dcb85999bbb398c16839858514c701f15d004f8e94fbbc86f280e5bdfd74acf6eddcef4c2a4f97bc1e024a552bcf0bc5500c04525e0f22e4be5f5385104345659d54d0ac5a3cc7ac441b6e568fbdb8a9f62e547678b20132b2d9fc89ab1d7c0fb96079b0c6ac200ce7a7aab2102b1c9431111a4c9f042fc11fe89f87accfd4bd23e6b675140853cdc33e8c1a09feb3c788b7fcc0fa8539b563f567c595cf42c32a1991bedb9412d580b634a552b4d5210a9333d56819c5da04599248d22e4a4aede7190768941d5448aa29b9605e0014848fcc7cbb5dae191ee344cb2c04b57a8d28fe938bdc6544e9fc4769c77deccb4b47f2114374815ec72b9191d6c0340ab33aa0464f96e21a19af89d39997fdf07f51fc0417e8a0aabc85d448439cafbb22f2c05d3ae050157d15e085c85f10a458fb30aa61d1ffc481a4a031c4a5fe4b31483bac1a2a735c02c09a11f1b50da10108145973d0ac71c5372993b694090e27c1e2de5c26fcf8ae6b61c8032eede6730b6b6cb8f1a24e3e27dd73350a268db75eacb7d9b5bf867004e5cf1c115487a189544c8d52e88ced9d9c094d4fb1147654824e832e7429b07baaed62d654d146edac967c65f1e341aba2626edf21757ddf1f4b8da7499633760184f1eb7849f08d48f0e8d3a084c903b045c88e8f7bc305e495f42992c2b92fcbe27a8fd134fbafe980789d010c6be5820dc9f8dcd783ee30f4df138568bbae22a7a1f489414ad7d6f174f3151304689c30f37462989114ecf646d026f82aa2d7179d53e08f9eda2e708b099fa0dc45db02542aaed47b733741a2d938038e87b2c7be7f5b0aa619830ecd7904adbb2411b8459e543d7af49cc218a629f532df68bd498588add207c7b54898a09ff7869b95a48034fe0a936d13a52a4c5d09daf7c7d8e05f597166d69ec68d043ac6ede4771e59f5d2064d332938b0cbf5955854e966aaae74296e4c67b932a3446303a07e734835cdead5beae7b07f30730c3d69ba2369c4177422e96d9f0fa9e227d9710719331ccba1454b184b23a2ddbee7bd36755142cb5c40587b2b198656f4dd3e1914a2128f4e4c20ea394c67455f254869a79244df9dba1ecc003b75cd96bad910403b0e707bfe71b9210382101e15f53dd3dac60fd4f8ea5bc812090c84c69d71d68fdfeabcd8e7455949fee62c4ed136d8d1c7a207696dd86e031937e71b3db014eac9f6226bed911cd6188bb4a02647e86e733aef4e26572ddc9529900c018df7a449e9f6680eb11cb0a62b083af398a9cd4bd5edb8931d440ef29fae0ac8ffb5c844d707eec99ffee6065fc46b12f7219d5828cb5f4337b740997af38170e532efe79ade8667b390956e2d2863e29ef1207e254b56f92d3d3439757518257f0c13e51adb4714a052ee12573bd716e27e7d274a79c2a8bb2b902712f1e21a151c89a52362359296e1faa30b7763045384dc8d839dd3be590555fe3cd16d3ad7611bcd279d12d2ef7ed5cc2fa78e4e503a32d7110e25831985b0e4b29a4866278ea4d044d9ec10a5beceab93dd46a533a62897f47848f59c35fc6f53ed446163081c4ef1e3b037b723e52ff2678aa6da0ddc78f5cebed44b1bfb187754cc141837128706d60eb70b0532649eea353ba57e51ca54c840ea1e730980c7a5265d5a9111efda8d7232d182c83d08cc97a376c8d0abe6dc1956eda8d12f12fe0184bb0e888e8f7503caf7227f6a06f58d427392313bc5e87e662952bd6986b113f15602f18e4ae1b8b13277fa78d420022e5f0a3b9ee13110b4273a6cfe68b3a566bbaa72b52a9ef3094606d5df7b5c280f0c1a1b110ad073289245e6106b94b36ba8bf5c6fd130095338bf5a8d4add6d2e298d93940d975b9ed9fc1462adc34b36fe09c17535a008413a7fc3e96411a0cfb285abedc3bcdcae6c44f3658824fce329321e7e0eddfbdc153a63d3bf623ccb69a9953aaf492b0cfdd762983218a07c832cface8ffffff9d193988ec76cdfdd383b3a591055e7040c5c603832676242eb92da8a03e4534fd601c129988dbb5d17e5fe65a1c6e9e28f949792da314edf949fe916daaf4793509a56757a22e0b6128f3acec3e9ea721d38d711088f1af23d05bcae8cb70136b230799ced6cebc5f837ccfea82495042f2590580ed6e695daea55d216d6e2fd9f4af6671b9dfdd8c7de147ed61a75a7d8cf1cc37299648f8325078188027dd60a338f6e7f512b5ed1fe8a747dc7090245aa44312c102c7f4e1ffcaf5732f15dd3213846a92c97fbdf600a8d818a289de589690043daa0b4839ef5880cdb89a68663238cb2a25faf6a5d0df3521db1ba937201dee69acf2f5d1f88a427f3b81f847aa930683d1cc71345529bb3b3a5ace46023006d128ea6bb14d2b2e9a7ff2bab536b15874bd5cc638798290e309ed907c3cf5aee506aa4ced866feda5491702072e3ef3f53c265fe07c01bd5bde4ce930b90a17887a51be0d7bee01fcd74652e0b65f28a85000f6ca5cd142bf65161144bec3a9d3ed90f50f4e04cddb939a96531446ced62e9d2d693ad64e8828f4aded3d24403b466ee87057fd6d63862920a13c8c267fa59c2ae893b414128f933ef97bb249de2aec6da42eb4c0d1b40438362e4f15e3ec28f74b10a261d26270f07d179689a3cb7a1cf12dd337d5758a4c612433af9c5e2b96477e0d0949e138418c9faea2b3b38ef0988bd2db33f55f0f32b39026a78cac01e0e8f47a3d467c4821aa1743ffba3cd50355a23924b76624631353ae37982954c061466da23256024535a54bf9079e77f7d68c60e09a23a1e7187720e216e4dfe2bdbab6eb3a1e932bb4e97c14516b302dd0dea2901d21355011ff0b5765e551a8a9b071a0540258b3302fc5c4211705a228ef53b88de0e8428f641fd2dfa744bca89ff31b9f9155448690837b535b4fe649eee6d781ae6cda3fc33fd826e858a29a6273308b64fc8b64d1429d06118742c7723069f5e5eb89ab68887933e021cee0a40fe9eae6b7a01b42eba3e7932a50f8d1466e58ed80f184474dc3f6c071f92f1da646d9c42a59e54f78e8d24b859f5388ada63044322d876677e0cf94c1ca6708ef0514bcceb0a3d0742c2d2dea8a3f517b1a52a98a4c2e01ba9f4a2660fc97473be97d544f862d9f07ba0c05b3aa72b9628baad3dea2ba389c45e32ed8cc9bff8ee87bffcc266e7607feecfb6aee0f5a858d74e801660fb7f50e022e206e923266abffbd21015d2b8aa6485eb1d18881c280eb711ccfa59d645edbaae49d0a31e0c4e13931f4df58b520e92424c252f4fe099c6941420e449c0dc31f184cd10a256d88081db5c2eb75b5197b6f2b4fbabecbf16649f5bdce761f203f641ce994b89818c70481c172e803ffb3c7ed8136b881ea6ce15623602972736e3e98ec8ade1b7f8c5beb5564075c369e9e222f8b2903279df9c42257baeb303e4a44244bb7247f42cd9f7e15c518c0d7bc5fd7d98ae3e0d392f71fb53d651a7f2711c0983471e723c33333d074bb3af926aaaf6654c98aa4397619eec8f4a611bc1dad02a6f0ff311344bdb77578c74c6bb96de38928deb630f72206267845c6783052a06348f98a9f7640bed36764ecedeb8c0f02d19efa1c8eaf3f8051ba7cdec9510b38b8186cc2c23305a2a11060e3b8f81414991595a8efb7e9d8a9653a0b661858a26ff4e76e69df31c509a65820fd701a74b0357ce40e1a287bcf80f72df1cbc7a1fd90a28702ac643ee8ba9256b9cc77cadcab0836458fac2c67b78cdcf024c651537f4ae67e65d2a345da67314c4dd5cbf89adb96b2ae77f4b52963d75e8ef2a64024433346c78b7452369bb0b65dad42478da2756c0f3296f9257f1c903da28b92e37c2e1ce00a1621d207085fca94757942008a5b8f8178b1f09e3668613b1bf70bf2f4e10fc5bcc5199639000179f3b00100cedf8191a05ad6ff5605633cc256b60dbf14cb5820272af05de4f8482bd68b0f1329ad2d9cd27e5dd684fa1dd3fae987313fd2318e55cea4958d74760f17d52f7a489357b59a755316a9bd94fe506ae12c2fac55a40a3c96f3245c8388e482fe60fd97df27e0e27b06b97d46a847ae162f62c5c211dafc8b77de49d4d0f512f09989af8ebc4d264a79bca7b7f35ab9b6953c84228301154d2585c7289c339cadb4a88b81d866f3f36519284d16a1bb705577105521e35e2b3dc7d4b72908697922cc25bc7091ba2b140aecd19fc60110ec3c860a99e85311de032e965de05b7151d7313c8bd4b38ded00c1af7f155e3dff08783f8c8de5e51e8416a6c4120a5f880788b12b0f10c5ff8b8459d92e53442b2c0779e85c24713ddfa8d2586f26555d132d612056b4be708504bce0bf245cf723737cad3ad7d9bd9ea25aeabf35c8d086935fa9bf4aa023b29ea751ddaac3477006ed1f24757c3a67f83476014b46cd4e08e1b33f3c6bdacffd41e5a1747dd9d85552b1efc56291c73f6349ca49e01b0316bf6b4db8687cb61ccb55ff67ea94a121870591ead3c768a2f6bac80c46a11706e700ad84e5feddeda93daea24257fbcf2105e01d3fa6382da66ce7bb5f5b1335e7fab1c415469c0b5e84a08837704f093f1e3a2a98543a10258e3bd4b2a90d3229c289187c828f6b511156d0693db4f7f5623e32b2a6dc6096c112f6d7010c23d3623afa31d2683f430dd6a306c26fa4c5350901b228cfabe28379b8f5d7b017d5888663e4518a3c495baaa288a4ea8868db7db4db705d45957fe874884cb617fb36324b319631a697b394c6dbffa754f2d2288e463c139063996d7d358faa20f760be73733d8b05c23ad94d7a1beca6724fd0301cff879c694ebc9306ff7a2ab11082073d57efce1e98a1b19dfaf1633ce7d0d75dcb17c5038e117b21f00f2a4988628623945bb7df1bae7e5b062eac94d48712c3516aa4a3206c508a1ba91e72d220a39320a8402a7383edf092e2d98fc32dd9ef9afb62dc6d04929b05ba0e9bbc13353514876d7352069a5d5b5ed2a666a092090bb202d4e6023af7918008066ee7e0318716c71ed421897a551bc1783e83f17023564f1d6894b257f9292f77fa5d24839db9bf18944d7230aa4cbf16020f00124e533e1aba844bdaad6a262547feb1a7f9d8e324055fd3cf1752324fe908dbd53436cd4ace8e32b2bc252b0eee4f4871b7ce7481c59e10f9ca34ca267e6d2064150d84662ad0155460a1382461dfefe91f5ba0f443d39ca6c4addcfe0e84b333d1048db58d8b3633ed751cba1c5125c9635e4d6a80a5ed6b7f2eee526c5f31d5cdddaf5e26027f380a8937ccc44c54af8354a72fe6e39d1f64cf082c308e8c9d0a8a254dd82d2f77323735802cda0409b9f3395c5b2e42ea8c88615232cbf41516fadf207cb54a9464f3342ef500ecfc863010858997ddfda7e6add73165f8da63bfd4cf1cfe1ea8bd6935ed0dbcd7d23254d31bcefbd11f4a3c52494980a315469ac0c4290efe9c77f125c5227746349915c124a07733ec254ee4121e8936a71ffab844a1bc322e8a0e2827d817a843a5fcb681745e5f20b20c3e9e4caadb1e614b8cb780c1f26ad57522d2792776e026a19d98c84221934d7d5ba1835641e469f35ae7cfea202af46216bad8f5f4002f61b79e3dfa677c3de59b478f25518aeae58a48a97d70a5fd4402993e8eed9d2d3cefa1fbc747c6202313090029c18431a632faa01ffb1606f02ce30939f924c0199cbf4f04a79fb9bcacbb7f815236dc40a961dd25efa39a220f1834c67fa2cf407c71b260f72e83bd61f923a9e524d8a19e3c80dfbfab176b029406c96cb9f1b861c46fe0eba6e400057b84a05d2ad36e2dfc3d6fbb0298901e71afd0c402e2e742f6c7f210d0b4d92ae914e39cb4a5b14a7a144f5fe760b31068453c261fe1463b800be14927ac13e90dbed37c7c1c2e6bb63a0d478a62212734b83c64b70722088795371e0e3dcd7293e2b13465811151cbe9d7f5d6924c0971d6470a2b23fad5d66c01b5a403cc256379355f5217570959dcfb6c5209962e64d06de643f9dbb5f112a8628a6851b6212e4df20dd583ad38bbd9e964b7393ef327ca96b3b91a0f94f589fd7f7b3ec68cf54fb21c47cc7e00fbf4181910b52332859b0e12cd43f04f2b43414e20375b95c75c7127ef76424c473b3fa68bc51b5059c22f18e12cac63a5edbea961e873794e242477494b0aaf2081308f6cde07c8dd4ff323c5fb415a7cccaf7d6e2fb8906fbba9e4931a30263f0f5d9e162b3e7ec21969214a226b21cd2145c4f4287557db85a2afa419c8a85a9c4d5743381cdf4dbf4d7da3a6407ef3787135680adc856cfb3b853d8c86a5c306a9f8c3162861dab20b5f71109796eeda24cf0553948d88b4ccc39d74f048d7e51bf687ac0f0e3e516da6149fb6fe19f2be49ec77c5f627215172f6173c3e24520d07ecca01625d5b732dc3bbc5233c01db8217b923a99c9c708696faab2c549b016abede2ccdc44c275ad6fb451a47635229e947826b5542e908f5caf1f0c742060e388c19d3b79f44141681d4ab61304ad30b6fd4dcd3be202e18ffef31d1010593541929fc40bb9e8eaf71e5bd7a13d6e8f83026fe85955bfd8b4349d081d3b56f858a33a80f7df6c4612fef286a8745dd261f96b740f41215ae851a6e5fc7cb8b9ea0129c941be54e76bb3eed31425fc2d96a225041ee9c1858b10007af95c278f5413208a04dd3a6e9370caa099d71ade44b694853878d1a096d6b21fd8801a909ae27322b2a984a4faa612c6b200d4b8d3f1d9dd3231b998ef5f12ff17cfece7d1208d2fd3107cfafc8007276062bb747ef93caa01b21a37f2ff6df8d5c6c81bd42087212e8e404fa7c5f6f1c1893f50fc1e043fb95e0b87e3e1929419399cf0d811197530d4bb1d66fa32da1029db9526d3f058edc78a64e57ae47701ebe83c1f91063795bcfde6afead6e9359c08860afb49c2d7a91769871801b5941545b3a2e21ef6788f56232dd40be086dce8f2d8eb8671782656c2b60ed7321552f678ddb224ac6fd1d110c20ce2a000b4457ce1cc982588aff8580da272716eeaec996ee3a0a6f5f5f1cc2dbe56fbf537500eb92cccbcfe76036e0a99ce31b1c2ed999ed25042b3cb7bfc104554187eb6a6c7f42a0b379d36a7370e5ecf95848d39f766b04d02e3dc2c6e21167a05206c3fffede97e3066596675ec5799751c3f45f0ef41d8cd44de443438e169459016614db5ebb6f8f2515c37f5469437d98256f26f90fe433788b7918ed558ca92e3fc58c7b84da3f81bdfd1975d1ab3ecec931bb5c318bd01bb01236088089dbc78355947ef0db419ab51fea39659a4aeac2a2a8a81248367958730f62e291697925a5a59eee0473f70d8d39365b931eb393f46edf3a6f764800da0920fb3d46ae41e6eda58bec4eea286979dbafc3955b2875451b0afafdf7b78a777eda4587fdd578e51fcea17ef9b354d92537ca65c2a651682c3375f5e8fbafccbd57583a3afd7a8a82f0890d6eb58badb4e2c2fc60a679a5fa1c3282a96c1f76885d555b80edae9b7f3d7736163841cb5e8c8a6af6ff8648442c1b41557a9afb7e976838269b1db8db5dd76981d66eca328e7863a3a1d51aab2822553cac8692e47a95870cd80468dc804fb609618b012cbbef554a4b7b1f152e21a85a374d217ca05343bc202f9b5a34422a020912b3346fbc2b0ec404570b3ef032556541e5beec3834ba967947d2aca45158da4df6c46cf3b1def2855a4b20a3938fca41b87669e2b75eeb4b87a72c9cdbe034110f7cc01ff6145183c33018c8f5351cfdaeb566d92915460fb37745353d20dfc803a19078e4ca3031193d0f88ec5c641ea37343d854cc67fb11cccaf77ec1d6e42dac0610b050c70115f11c9a5cf69bd3b8c200e67a7ec2ad504913263dd6b31b8474fe31e879503f70502c63fa76e26fc43d58d218c0ac35a53ad57b6282ed09efb2e1e45d890cd2071902be09083c52d0b01d44fb45929e8715a03a51ad0e478f19ae33f0d2a19004ed1089016f5ab8f5605b588562384f90040f56abf61d0922768a7e969c4acb892e3030fca565f390b776355b91d17a929237cdff72a3831de19d62dd2726fd6c5308c985a83feff911a36b6c99045dea353603ebd769a57f21c8d70b33286cdff51545c32992096d48d6d4947d1285ad378c26ab95f1db4dde835f35ddd8ae5542198740d4a45676716c63aaeb67a27651f3f280632d7c7ea835d454ea9692b1b71d5a6b867206d887ce056f9dec3f4ca82acdc3080c81e6f7e93041bcd33e67b7001e99c606b558cfbd93c0fe828bc47fe5dde8724579bc40349b9d9c79131cc721e2b98e483ad6cac6a5eefa1490074e246b1bcdb7956d39cc9f9d76d98197e03d95508fb7ab013ff995f6b6baf2b94db8186f33f5d2155201c5dd0757d618221ee0b904ca9e80bad9fd240228cd469a2b7825f9eb0f9061d8c745c9b1472ee12c9a27d4e3d97ddc547ecf7087f381af17e8c33f43b4ddcebfca38f1ec937f8836c263b34cb562e3ac9ff61521c333f3f857ddac05f12f6405a4c9ef91e7c01e27ebd0cf4d63855d2ebc0c3aa798eb18169b8aa5ae39ae53f73935e9a46e48a4028d485ebe66ebf5b6b0806425b7f4bdb0a0e730187bacdc10c0d17daf0954ac009f26e9aaaf4ec4533706874e742925522f8aa621445acef881da9e5894f0e82afa84b79bcc75b829aef3b6af21fe69784df90b6cfaf511255e7be833067a8c04fd741b93218509460b01cce8a7da850b00e367e3590f63df52c227d9c97bc302586839234e20c05bdf1da0b0c280edb180944236447fedfd0a7ac81d4974ff3b90923a94d17c61264e4f3e36d3f3af9ca84a276d480e3f64185608574e33c3355910f2f09adc1c05f6bd67b4af03fb86452c60c44376c147318ea1821b97f91c2f0b185e7256b745766e717724c39f33a7e7edf8464fad8c6325005bb0365e08865e00f0a0f873933aa73dbc98214de1bcccfd493459b2216e0c95f580b71f2c80f8310e29f5fffe35b73ab30d14ff2191bef2760a555e7997594c6c97fbbe2b617de93960f015212107fc3a6994220101be5dadea8c83fad2489fbb37f0a936d1a88d6065101f9aeabe2485bd7660cac4088cf1dfd49f629b7d5a6db9967813ebe1be55dbfea6e52008d4ac333abdba7978627bc4bdad8666458a699f046d0c2f5109e5f5400885dce436c35b3ee13b4c613c0e96e1de37bfb26a1d23b3cc33a9f61d422497e7aa568388c7802bc2e728e274fb5d55e608735f3253bfea2215f6ad12662fe31a59a91eb397a6ca8666085eb24acca6247f6077154f4194fc0f96c998817d5555151e81da5fd64dc41855cc60d2e7519e60d2316a4ca6835011bbbfa992331bc02542d198039087e7ff42ec8f01df5b95872d158d24847ea20350d689e3dba5608b45d4c203ba7a7e35d19820653faa9cf17af474f827848b32479bb0934e488c746438a724c292c92db1036f9ca0522d0e98acee007a552613c7ce7e811a80344fbe117491cd01a6f4e50826ed4fd917e0da8b41c3c5d44301d14301057112103f35bd566ec63a7ae1e1ffe3b95f17296df709697f50055738e21de82ccd0935cdfc691a9fdc60223c8bfbe576b5a8288192b74315e2b2b00d220b5ba93be801493ec5927e306016d21ebc1008dde9e6971100624f69a4e40659c7f1c768dafcd2bc478928b30b56875ef54dccaa4167262c19ddf9bfbf8b206968d0b07ec5249d302e3d097423a134b54d729a929fee4091a8f82768fecf287f9a260b347580a884fedb55fd8f82809770aa9bd7f634eb838f822ed366bb29784c26c9c68230ea7e9aed096852595b9c5751255786c197935bbb09ff3a2637ea5e81c87328943167665c940ae42d8ea2fdbd4fe5b52eeef7669f0955ef120d4a3284c4aa604e9e5222fe5e932fc5dbdc9faaf6fa610847d900492329d05032d43263ed6555f9a7f016135d55989bdfa630339d735a5e1b8f0c8f1ae0028c097559be0de2f8a10bd345b75263ace2b8a376ff659400bec36c818428dcd0111b4a5da94ae6cf46bf7440cb74b1c7d6827ec41d9b00927ed14746a6c595582717410f002cc2c8bd742211b9d33c3ec0dd30ade6747a72b6253bb6c3d9851d932fdfe1b0cab028c718a699af03de21683f130dbab533308c3ecc61c86971d3f91171db1dac07a21cf560fd71296193de3472f734feba529012a8d63a5f9f3fb726ce47fa6388a97992d0c4f3d9e7ef6cb48c186992dbcdda57e8170d58d5bc571a2b8037a854d726ae8df00c7407827470c24dca58705a3184c6b8e0dda3d9d51862fbf07027e0f2b181709589d570674c99776e55889f0cc1628201c6a60d6d268c4d0cad3d39686bca2afe14e808045e3173b76fb6be0b0fe5d8b27ee580d91e3dc1399c3bb399264fcf00350a068351bd5eac269b2d85fbf01136b76acbc13626ca4568128146498b8857ac77d763c0d90e9037423d23bcad9782ce80852f235224e024d5147ccb70eaf4d3f3f4daa0b10d8be06cc69c53dda8227e37de153c9a671b2a68b85d8aebfeca2b8bdc862640d87b37322534af0165110ee56b431f900dc7403b54eacd9467efbf5514ec6d8c31efb358c0792a2fff45d1a308ca3cc0887cc8789e3e93a45f4ce5263849fa6678db4ea2731a67ddaf8d1aa73a733fd93582fbcda87414f3aeae41f73cd5ad4dc97f6d2a84a7f2140e6088142d4d226919a69f30e1381f9b097e4bda725623ba805b547f460991d6efb6838f3bb003374efc2e198f31e54bc21d7ef5ddf2c39eb1c3098783b69b49561d7ad148712fb71ce5fa22853a2f996209300505f986bc7f32b3fa0071f2cd834b5e7c6b600e23768d8c9c5eb7ac24ce8027c4f4dc20dc10646ca164ebfc9197dc4358e9163aff2674c30c83a69f0bca311b409894d87316eac9d4d48d2027a3e347db72ce1d65a89fc992dea79de8643293458c1c5b3a2d666f02ec24fc534f377195260218bab50a2b9383acae2801b479394a218a28d73f692ae46b0a6e4ab6cca647c507fe5e94d0279ca68515fdad7caf9fe2eee36f5baf29fbadf3f0378e8e1f36d011b01b2675da70ab211880b94e216e6dd5c48959b416a92191a5cf88126042f1126c8af1b9616044d3dd209b0c1e1cbc64722893686def93371457bf83bbce4313668c4f0a88cb270e95a96df6a48376e0ea908f5bd73876b39b0b96d7221873a8f68da4c27a8a02822b9129b88a9680b73df5eac2bf40e90536abf2bede60400dbf94632ed335d599f5e0edc6c13bffc0bc7d64b41884b41f7b23812e6ff2ad1c9081424193e1e7f0303ef2e8c998d1ea0469d4484b7bb6acb66883ad42c0430d523e7e48bac087ad3abc1609bd211769f41cf209c028da2388d4f113b82e33be35ea6b25311ca9b3d2d7af93e7b49adaf927a33e0c3176f9290e72763ba5b39ad29b17527caa9690120f85eb010582b95c8ace1a7418ec227065adb49a9a12b7e4b04dde8ae030da2a569f3f59e84db319e86c20d0c322242bb3588f9681208147f3954a47e40ab7f4c7faea32eee4843d0e6b7c20c714b7fcfe3f62ef19d1b8aa8bbca27a128472c377427af4175bf087dd67444b8d85e8c72d1c81896bf6b59e0fce3267fe2ce8473a89805078fd80bdc4515a434fad874b0e6f82feaf9d24ffca1a447254fbd9043cae4aaad3aecde2534502152bdabf2d5a8d178e3b0991896b9e8d4cd7787375ca69db0a645510f913e15b7e122b9ddf5807c0c57db5b28d889ec876ab1bd911c9e62c6ba755c6dc5194071c5caa5a06d3b4686fbfd2a573a0200303c7aa0f2708f96153f990c66f74cd91b943ac37ee69f5c0f8e03d10151dc61f545fa47b1f897d6049b326780fe334e73c68a1a8d6a8824efb07d6b8a7a2c1b9907afef2e0db79ca07a069476a6c36da0422c3ebf0798f0b18db73b94d3772ffd0bd144016e96fccd69add6e30f07ff863c3d6c446fe72d61a26bb805601cce57d20d9c9f40fde6e79c2f7bd174e770bf30bbc7ccd389f933814443c09ae127e241f940a674d525f262b1a86823a0cf85703d7953defb32d7ffd73b49ad0cf3b8b7eb30d6470100f54d4f5aa58c5b1ef5bae9d026c111a7ffba8731016b93f8badf8c2bfad287a5cc1065d6c654ad0e862e3b90254ebf31fbaf67303eb727e7f920901674468ac513d192a2a47f6cf055f58b7f25014c3574316d50113920bd46f71f5e5baa3f28be4ae23b439d8d37287357b653fbc49357b81841f851d7ab33a912783425367cc4a2aae7b68bc9705c097dced4d97cdb5ed63ef3d820bf2fa71bdcd78a503d4112f285e379203068dc4071530647766fdc2cbb3855aa266cea59090977ea572f6059584820dc60e05ce7005d3acdfdfaaa0f6870119cc7be37c67af8d1f89e64602f107a87112b6e969320c35186506fbc1b691810a3928d16a11c5dfdecbce24dff330070f64cee4c79cedb22d48cd1f8a671f2302b69e9ceb94f3559497dc018c31abba0fdc1bbe9c9879cb1281f22c0dee5d050b01e6e38149e46031ff5f90902244d75f456789e1fe0dda2870581485ccd32f \ No newline at end of file diff --git a/src/scanner/fixtures/nu7_testnet/pre_activation_v5_4465025.hex b/src/scanner/fixtures/nu7_testnet/pre_activation_v5_4465025.hex new file mode 100644 index 0000000..6580b85 --- /dev/null +++ b/src/scanner/fixtures/nu7_testnet/pre_activation_v5_4465025.hex @@ -0,0 +1 @@ +050000800a27a7265b16a53700000000a921440001223b43649c4480eb2caffc49842cd971e40299b3185159ef015d843cfab968a7020000006b4830450221008dd6ef1527b7725b50573e3df4b214adaea643d0f14be5afc88d48f65dff11c102206ec7fc29ede35d228e75b8a29e8b15325797e18422b9e6a41b65ca4ba40058ee012102bc0a8bf008166b8a99a1bcf27086172fd709467ea55b429449a3fe6a92f03738ffffffff0300000000000000001d6a1b535601bd8a560dfb415d4babb99662dc157267d166b7c90000000010270000000000001976a914000000000000000000000000000000000000000088acd01f772a000000001976a9141aded9db78a48344f8541ffa7d4300ada64fc68088ac000000 \ No newline at end of file diff --git a/src/scanner/fixtures/nu7_testnet/pre_activation_v6_coinbase_4465025.hex b/src/scanner/fixtures/nu7_testnet/pre_activation_v6_coinbase_4465025.hex new file mode 100644 index 0000000..6e319c7 --- /dev/null +++ b/src/scanner/fixtures/nu7_testnet/pre_activation_v6_coinbase_4465025.hex @@ -0,0 +1 @@ +0600008098b684d85b16a5370000000081214400010000000000000000000000000000000000000000000000000000000000000000ffffffff150381214404f09f8cb87a6b636f646578636f646572ffffffff0120bcbe000000000017a9147a86d6c7eb12ce0aa309d7391a6f338eba3c242b87000000011cba4a825c815337d722b5720bb17aa62bf02d47e60fadfe67fc95b4cdc9ad833b75d7e1f726c79cd6595402c3acd547de8d549c5ec8c50fc5261d32fd276a3cc8148817565948d93fbbfac812440401ff4214618ed1f29c2a0215fb1a70938ba5f0c694cf72507a1cec5f69b2d5549a9b97fc88ed4d915fa46fb25175df6e31940d8668a92af08ca1d5229188b5ac520d8b18e4954a56a27ac1af4b0c5f9a039b25d1a07faece183977d72dfb84f1660599968ec1feb0ff6709c3b851c3d5d46bb5346de7ecd15d57f91d689e111b5ae2b0d59ce4b076211c12f5026fbbe17269c0695795f424eb8fe526fe13474a79c1d726678891f7e17a8de1bd35c852e277b44b6ccc6921d62e4325dc9f8e97a76bb60a6efbbed1536edbc5976f3d20caee4d8845fdc9af8bbb2254d64d28cd91edcd89f7fd64ba294f575bf06c0bbe14ce6918313b2238b91ba42a225a471a7fa8e95f7c90625fafcc6111a4cca2590ba0cc7299c73e766acb20fb406a59f2f70c9a1fbf855d855fbe860707d2627a95991e5666c1dc0752c06f95cbb64e882aab29ce447c4aafeffd9b58d2197e79e6bba72a95a48a89f6dcde7b9a3d608f1d7f0c9242e2daebe1eb3294039c9b5880c4f676cfafd4b1ce68a50ecce9ccd2f06ac775ce78467962505a6c1ee156d785391087a0f6d1c5a874bf478d92e08085a29ce18842e805750a8f55d750d69ad00ff024319ae2f55aedfdbaeb1efafb6f1fbf5c0f9ca099a2d0c611a3df1e11616986e364f407f14d9abd80b1d8ba08944a207805ccd43710d692e73825fd94ba18c0f06c9f9e9da85ccfc8ebaab8d8892163d4ba947a2123b2d4294f4c0c8858da5b3b080e2a89634f677dd5be98aff00973e42e0b4f7051763144be196dcadced8ffea16cffdfd4fcb97ee00e0f632307ff90d7894f2c16c30b672d29d647ab3653fa67a07016756a62c8c3786ab83e147f8bb37e60ac1c6ef3ca9c82d4d9b812a5ccb9f7d6ed78ff9334c4776d67b4bb8d658a70e165203316f67a663e210f50de09bff2b2ee3f6529f89235020e1460730bec3d463a52b3b2c6022a6e74a0f74cdde2e52c609b0551d080d994030c16ee97dc9a5c2f50a5c2512af675b2a693269bd965478d93d8f657321ac7e7e9b2f6564706a0588cf8ffffffffae2935f1dfd8a24aed7c70df7de3a668eb7a49b1319880dde2bbd9031ae5d82ffd8013010da95f5b5472d1963d18ceb5871a819056aaebac79e13b2902f900c49fdfa001b58ed1300c2c7b7b89db39a369eb1e193a3042b33626e31ad909e469f95abfcd8f475d1cb243dd21aabd44185b87756f60ce6d4e02665bec5153f0df5b3a8ba288ce4b84adf7de131a87a253bafbe18eef0f785ac08c53fe4de4994fc3d8a909ab22f87872693aa6b43e4e22d007f07bcaea5cdd6ee0434baf26944bcbfc2fb6857fc1f60003b0da31f8ded694a50ca097553c0591f36ed4ca48b9e9841a14fc1c576b5c8cc7f2a9897a7a514989d488eab4e5b4417fa6affe9b820c6c88bda0aacbfdce4081243d24df3f6c3c449346cc6b4cdef67662646516338e684913f840d2a0c12de3d372600aeb0a4004f25a171f61677db20799324a04a556cd27c5059592793e286c830c7b87b779f81fd74808d8fc79d5ed5ece079dd8009d1cb9894ebc3eb6450849242492fccc8f08224684842b50dd37f4787e4d5281cc96ffad16099e0e2796c328b77a7d1456cb04aaff79312176483d3c72ee5214268d708ded42240d3c72695788f033cb051fd9e7a7360c1da4baae8cd22cc4e87f01b629f245c2f5ef83d8857688961cd1861528f3c9992ddad8110811000e250f396c3aacb3bbdba3640d20d7af01f63cec72eb4288ae75e0df43ef08213fc46db20c3084fab2fd00e395c75d86f2c052dc13e0ace313b01dc1b7e8fcd2053561a6974e6bea48093a8e5ba873b5e91d78c4d4382ef50f1010a6963c8abd8c5136af519785850eb674900d3bb6d29cc69cd1193e4c601858729458ac241a5a4a4199e3d4e3cfc0b46353529e2c1ed7a49e44478c7aa9ad4145b44b0e9d59539ab62a57085ebc2d71b1d92bfd60e0d0604e3eaf71d78f320f3176091bc1da1b74351c9f6ef98a9853bf9a0ce53efc9715a5262fcaa0bdf67aac119c567dc1617622b7d92830ec3ea5f812868d88b8f211015f68a101716903f53a565fee192bd945be0772094f032f89b1466cb4f13af47c24a09ab11a2e814a67081a532270c390a724b1514143699aca5f451498cc07c5bb5e04fb0875c94eb9359351a6851279bae456da7a1da037a76ca74c9af078f10f4d7acfdf50d6badac5ab4d411bfbaab2d74a36c4cac9b03d74e2ac637628791b15eef64fc8da394c7329baaab1ee3c320f58a1be3f4ea12a2f730775145c2fe9a6e9be30e1bebb9ee01ae76ef847e99e3d66d69634420bfc7790c591d3fe1225c398247dc5a0ca858999ded260dff80c27d4ceb34afb549f87f65f1b9ddca1e921255ea69657253a4eba331ddcf66d28568d88c2612cefe808ebc95312bbad4a25eec74cd0beb965fd8f104b628cb6aaca1062357cf9784d125e08fd3701ff77d1bd7253b230c0e3c809e291397d689a2f64cfe6f0c4172e150417c47214e7f1f99b77e94afe37d962075308ef5c862eb7f26263bb38b3e8e21a4dcd1b511a1380b556678f6114560b7265c41b3bb138b2c642eb8112638810311862bb2908c5f0f26c163fc02f2345f452fa0924610be5b581ce595858911355b83b8a5533611f98cb444ddb64df07792deee3db6a0f9085dc65013d230f9f36365836e1c2e83dd1d5680c36c1db6106a5698f79162716ae5a3629d217040f22bd0d941129c7a64cae625dc3dd52098c7ac05289063bfd91c6b01d769655e0b4b0c51cd914e2ea1d9f5f36bb0f37e9b23a955e32d203f0baa036bbe4c6dc6077b57007878d91b0eab93c02b4b5b8cf4449187f05353651ef01b405b7923804b42de59cdf03db2a39d7b218b4110240df84fc74ebcb3b6f4ced654da0c21ca703f67f42df349c64cf076e280971778498a2153d42dc0752160a84b456e6ffdcc1488000077236be61c183955b69399a59633feaaf040db49d8aba553a50a2dde40d8818c74fc4afe79bce619664d56d62a31020a2213b28157de25ed6e840bfc05d5611e20a8f8d2ff71c3dbf7f838579e2d6d6ab392a80c8c0da6fb2e8d1e967d667735cd84cb907665f16e6631c8728191e22dfcb113e0bbe3f85e2fd8203d8ad1ac4690c4a112a15ca0d13427e79ae5d63f6b7d30d1a8255c6b650e550ae99cd48569f460352f5befd70c6f0b773cdde87b770913599c6c278139e2b96b6df757397e6aba1e3f3baecb7647432bbc76e42b59b4b101027bae6fb6c1028b08ff0a00e24f85308ce2492176dca891f03156f176be5225afd8028c85a24205ada1debf4eaa946b2262ffb372b644a9a77d4622d722b13e4357a3ec87ef518295aa08c3e5d8aa182a910b9aa134e7388de1bc0f19ffd00fb3982f2ee57e4ce68d6f6c3b6741c285669520426386abbe273527b16866334dd2801aca0bc68fb5f61742df72813ff73a5988261bac910885a77ab35d0330a883f78e3880da08493ef0d0b9b22ec5b1db489acc6c1060ec7e1e4648298e50000a83b465009fea450d214b04bea4e50970ca266d3b161712c09a301e0f635218b868fa7dd9d6d4531ee4cb46b471a20d7e612f01dfc4b60be3a2bb84b6e31265706f67149cfb026a1fc21dbc247f732daf38db6b3b010ea7b4477e58e39130da4a49b08c356559e6971b8a39d277670f168b327760c873e31df3c4c919a6d3c94f8f11fecbf8cea90df15d85a4628bc284c9184b7bae7c0552ce139059a03313c93b882d18b3cb110bd748d39481877878da192299551c2609d95a17d2cd300777f8274322cc11abc3d343e8cb4f3d30cb78faa152630e25b17cb5116987b057e7852cf51073c8fdafd4e832aab92abf08a487c78e82f90a6e4609469e68c04c99ae8ac7e1da645c6bd419277d85506da7a6492a800a215c7fc92a098102e3bc9641ec436bbd475dfd668f4c8f35fa20873d4057d46d486a986b2b89573f416e906ed44740d8a675f54828f17797fd30e63bc9a06f44353b4d229acffc68d1b51375717a28d84d88f5a47cf643303ff26e231eb1f5bde4e59c616aa5920b63c511fb4859a241f50ddf506b3ab87027aa7d9ecb918990cd2b1f91aa22af69b24fa4372da76ec06561cfea93acba051f28cacaff6d9ff7a43a027697b9b326513ffd971c440f8055b7303fd6f18a61c067d933f301d313a1af357e08c0943d7042ba1ee850ce3baa45a05e776f2f6b0a12d24fc7badfcf250397bf795be39ae16b75af17d5483490ac85782d9fe06120dbdf31a9e43142a05a269fc63b1da240c6e36a311f1b912621eb8fc6498222127bdf3ee03120ff1b11042854dcad2dd36b0fcfff4531167aa080bcafda21c181c31c10367ecf6e70cff5cc1eb3d0e37185d4260fc51331a070728b48da9d21942b95975c2b62e11b3024300792ccae33747b05e2ce4d1d3774a1dfaa0e36dd191ec125318015100f9730c8304bb27370b63ea73a1b2484476e1cb927b9852b1af0d9e5aae76681dfa50115a87a945881541e5daef2c23762f7ff514ba38868b53656d39f77e7e3eee16ded783a197101fdf1a09533d781e9061d2a6c1a627ab04578e04c0ffd896b95306cc8db8938931ae4758925031132162be1939f04f505ba1eeff4b31422bbb94c5fff837b1670e404b34aa686169799be32aed6b03f6a566b283227289194f522410c32bfbc33f7a9cc62b5c83b0c053738845750fa780c3449df62aad175d47360c569ed3f838f1a62f6f905869c0cbf274291c0eca4bb7dcbc8e513c84d014cf3ab3f3b21c34e3020e8520e628a8e1617e9ea8689bbee13dfaedb56b3fda9aa476d0f6800d3fe3bcf6a2190cb6dd2f9a7eb3f479f9c74109862101f2e4b5f0615fa8d0d769103247d375659386670d73cf6b0318a6e8bb8dfdfab608bc10fd2330d0bbce100f0b57acb27741190295cd5f9aa6b53ed2651b9b114cd124bb2a7d70fbd7dab1177ce6d31f6ac2691b7744e5f0f501f57983965203cb00f8ad11540089e7f94c1bd84afb441cb45dcd1eb6c400add408b10bb00ce6b9824be0cfb886ef4b621f37723a25b0b80de36f53daa8ecff523bd162e27ddd31b7323b3ecb3f062a49de3fe986fd03305771cc45d7f0953fe931cc0de7aa7e21d4d2c6cfd90852b2f2193c9df22bdaf4487805dc7693edafc95f28f5cdaf99ebaec0b420a62a09ffd7fa10d057af337ec7af65ad28ba232eb85303ce474d21015cf751f069c6cecd95340139ad624ca37e8ec55bda639134ac2b93cd2f88be9ae0409fda186f8d3e02a3216dfc4a96c38c93d5e7fc70e8f58289238a9f8198a1b6ba9f0a591eb831fca50f7345d268a62b399ae29e14228871d3fd81cd2d3fa3e8f324f96f8fb64acfa513715b0b104f5d449a5fdcbc56e891a1acb62e7c2adaa29f155c8ad244e140cc19afd4eef8c97946e533e893937f7610261a17c9e4693360e23e027b90bbcbb81c1192d3ff872cc6561ea7d9c9fd719085ae6a81e59304fad18dd86db986c8bc03ba7edf879b36ddd773bfdae461826e6eb0dd6beedb3480192ba33369e7a63a061d07e903ce3d8473ab0c8fe0386884f8c082b4cab6c6e32d11e04d22bf17b126f28ed2a0d50f5be4e90b83cbd57dc909746d701bacb8f0c2778464788788560afcfc2e71ffaf446213fcbb5efa91a2f22b3648f167a17a22962ccfedb6fbbf07320c84f480bac12749f8a28f86f5dcaafb04dbf77eb4c076880ec21cfd04242f8f91fbb4532eb519589256943769346fcc3272d48d2d2ca037e4199ac05950064923981905523e9112941347f9acaee57864ec7714f23e5dda77cc80a428ac185290bccffdd243de3cf2cf59385f0feb9e63f175bd265d85ecb3efde99053228be333058f2651753251ddbb32aa6d3fe489046c93b1c870221e5a79ac009a221a93d5513234b4cc91ecd0e47a3baf00f2be765d77832f15a7445c945d8fbc90b91c34cc22d32a2031b60fc67edd53c966596454598956c2eea275c14386b711ba65f58ae64290a1eb17fd382f1254f0a36615decc386c3910a15972935549413aff7733df5e37a350fdb43b095620e1d76915f50a9eae27843a6942feec3d31f65b513307d242610664e01ec6bcddaada374cd76064524e1bc7615959643472be975a0062152ff9d4b0d923345c41648ab73451bae0b1ac38242ab12185d9421a072ef174d50ad0e0a509848237f25e11049e4a8d977fe1c4d051ddea834cf2a491cdc9b50d2bdc738b85879ee9691550379b60aa745f545b4f731cbe74dce14bfa95641ba5b253629dcad0f3cbe4ad2e902de913838091f2653eb427f18210646d4d26c01d8288fe34e7a1c4eafe0b8668ce9d7456e9c70faa491f563d020009428c96b4e5d70f8db77d86f3bba992fbf324d5e24bc30d272f341883e95502476a19af5febaa3f1134c218a2483ba88b7b549a041f4c95bf6e5216015e2e73cea79e45953c541824cea19c364e631c335cc7f5ce7b2e202dbc68c3eab901d0df8c2e2a6d197200604fca5c70b9ac5bfb2dfb28b882221cf3955349ca4ec2505e6c18cd59b2b27661faab2d998069255dccdbcccf90ee309744299e9d966432e61a7c389acc19de970d3c5061d966be02a6117d7850fc8a661c471119cb0be196e3a8ee25e97aa531d5683ed4a6d937310d1040e751ba629d69613084fe6d334ab6c4fd0c2170b8ae5f4b1920a5f89c6f8a67303289a62565ec15837ee8b0f293bede3d635147fab9b0613b964a1c6ee4595e3579360448c2ead6d230ffe500f1f8b8e95634e3399ae1dba59c26eb6b6ab00eec1afce7f0103946ee45ceb1b21d2db62e50ace1b515e9f6c7cb092af9c69f04e4b48775131b8c2be5542b5860a6b800ea6f959d5595287beb2c8be0fb1bc609fc4c76de04565ea59b24ccb311b268b15e94a81b979d257e4d62fca38e534acf854147a1316e4ffdd9c3c145d38c264ed91ee7ab8c0a16a0c83ea98116afd554b60810068361507ced56162650660858be452b1bcd7dc8b3007b082283f71e40c1498709f1b1e557ffa24acd91a2741c1215ebfde39bd897f6279b29b2721c8482b27a955ad897a86e82431f98354ca53e13df3f39fba4ae56b230e2534ecc79d6af1c8e21070547353c74a359f5ce67a84588864b34553e77f37532c2e8574c0178444a8617ed7b5efead7ca33968c7d9d8702bb7cbdee708c01b5aba19005bfe88db0906f9d048265151270a11d652eabf6713becc2337535bda2a8d9561f31916314592c6c719f8539ea53b9843e0e90798ee75f99603affb14ae839b856b73ef2b206fa09ca15b9694d6fbfeb5d911c3ac2d7fb96104c7785f6c4bd846bfccb68cd9f050d388a90852488156202d3215729cf7dc604d63c5de956f43153af9a86cca538ea74fb96ee2694b4edfed43e2113e86cef62fb63d1094cf6eda656bbd814557addd6f4ad0c937d14910b5a4ca741e2347b75f1b51f1fa0732405e85a6034590e1615db777650d811e279b858a10d852c589a037844a2deecf0cd1087f6b35b75b5da932165b9af35cae1aa31e1aa4e4c5effa2eaa4201faf1864be3e70b498ea0b5ff09f7b8970024e962dead58a36eeb9fe4820dc33aa855b32a19f94cf1ea2dd2cb5919839ea18360bf5656b4167ef9d9c567e2c638210933bb2122764509f9c33229470a8839f4bf2c31bcb856f7cc07f5c8c8615a3c649788c0d831973fe574f5e7dffa2e9284668046451e3333271df80b72a0bdb671143b2d2f5b23615a2b53e9c1363f60cb2b3552eb41111678a0a07c99f469a6a80b9c47f11cd1eb0dd88a498b75e79af74b6e2b548a44348033bed6a5bf4e9345bc8f818174ac304df4eb31d6386b313861723c3c7d0084268605b62d1b956e945395db2b50a9238a602f2a7947ff9989f7ed1bf6b67b4d9a955846e0fc14a3540b4b20be52149e33d5d03d3477675975b56f6c5756bd1b3b3fed15a99999f53e274f2b7a796ebd1d013edb40c4509113e5266c39c855c1f7a5b35156b3c46626eda4f062f28b85c171646d0ae496422e1ad7edecc19826f69a518e3fc5b6c30178a45fca36e307091709e7526ed241fb664cca35c0081851763449ae850f44012550c5f873c010619bbf7c5c8970f002e0b32a9178bf4bb84013571866e41d00fedabb4796898f4ea2ca0c7112fda912512a7742e88b7b345917daa0c368872fc0b7ebba20f2ce313920889cf155d20fa93f31f780098661816b0f17b30369966236208c30cd106056e33d1d7f05d27e65fa0c1fd07046d42da7657726496ceed301d4142593965cd333e0e3edf5e39 \ No newline at end of file diff --git a/src/scanner/mod.rs b/src/scanner/mod.rs index 84d0729..c9aa6c3 100644 --- a/src/scanner/mod.rs +++ b/src/scanner/mod.rs @@ -463,6 +463,24 @@ async fn confirmed_fiat( const MAX_BLOCKS_PER_SCAN: u64 = 100; const MAX_BLOCKS_CATCHUP: u64 = 1000; +/// Shortest target block spacing the chain uses. NU7 cuts the post-Blossom 75 s +/// target by `NU7_POW_TARGET_SPACING_RATIO` (3) to 25 s. Converting elapsed time to a +/// block count must assume the *shortest* spacing: overestimating the number of +/// blocks only rescans a little more, while underestimating it skips blocks that +/// may hold payments for pending invoices. +const MIN_TARGET_BLOCK_SPACING_SECS: u64 = 25; +/// Extra blocks rescanned before the oldest relevant item (about two hours at 25 s), +/// covering clock skew and blocks arriving faster than the target. +const RELEVANCE_SAFETY_MARGIN_BLOCKS: u64 = 300; + +/// Lowest height that can contain a payment for an item created `secs_ago` seconds +/// before the chain tip at `current_height`. +fn earliest_relevant_height(current_height: u64, secs_ago: u64) -> u64 { + let blocks_ago = + secs_ago.div_ceil(MIN_TARGET_BLOCK_SPACING_SECS) + RELEVANCE_SAFETY_MARGIN_BLOCKS; + current_height.saturating_sub(blocks_ago) +} + /// Find the earliest `created_at` across pending invoices and active campaigns. fn earliest_relevant_timestamp( pending: &[invoices::Invoice], @@ -644,7 +662,8 @@ async fn scan_blocks( // When items exist, only scan from the oldest relevant creation time. // No point scanning blocks from before any pending invoice or campaign existed. - // Zcash averages ~75s per block; add a 100-block safety margin. + // The estimate assumes NU7's 25 s target spacing plus a safety margin, so it never + // skips forward past a block that could contain a relevant payment. let start_height = { let oldest_ts = earliest_relevant_timestamp(&pending, &active_campaigns); if let Some(ts) = oldest_ts { @@ -653,8 +672,7 @@ async fn scan_blocks( let secs_ago = (now - created.with_timezone(&chrono::Utc)) .num_seconds() .max(0) as u64; - let blocks_ago = secs_ago / 75 + 100; - let earliest_block = current_height.saturating_sub(blocks_ago); + let earliest_block = earliest_relevant_height(current_height, secs_ago); if earliest_block > persisted_start { tracing::info!( from = persisted_start, @@ -1414,3 +1432,190 @@ mod payment_confirmation_tests { server.join().unwrap(); } } + +#[cfg(test)] +mod catch_up_window_tests { + use super::earliest_relevant_height; + + #[test] + fn window_covers_every_block_at_nu7_spacing() { + let tip = 3_600_000; + // An invoice created 3 hours ago spans 432 NU7 blocks (25 s). The old + // 75 s estimate (144 + 100 = 244 blocks) would have skipped ~188 of them. + let secs_ago = 3 * 3600; + let nu7_blocks = secs_ago / 25; + assert!(earliest_relevant_height(tip, secs_ago) <= tip - nu7_blocks); + assert!( + tip - (secs_ago / 75 + 100) > tip - nu7_blocks, + "old estimate was short" + ); + + // Exact window: ceil(elapsed / 25 s) plus the safety margin. + assert_eq!(earliest_relevant_height(tip, 3601), tip - (145 + 300)); + assert_eq!(earliest_relevant_height(tip, 0), tip - 300); + } + + #[test] + fn window_never_underflows() { + assert_eq!(earliest_relevant_height(50, 10 * 86_400), 0); + } +} + +#[cfg(test)] +mod nu7_block_scan_tests { + use super::*; + use tokio::io::{AsyncReadExt, AsyncWriteExt}; + + const ACTIVATION_HEIGHT: u64 = 4_465_026; + const COINBASE: (&str, &str) = ( + "98ccf227cfa19e8ad89312500bf724090997443e6ae0656e33b2d5cec99bb608", + include_str!("fixtures/nu7_testnet/activation_v6_coinbase_4465026.hex"), + ); + const V5: (&str, &str) = ( + "a85b0f6a352b9699d4221a93eeadbab457862c4dec2a3ac7ccd0d2f034fc89ea", + include_str!("fixtures/nu7_testnet/activation_v5_4465026.hex"), + ); + + /// Explorer stub serving testnet block 4,465,026 (the NU7 activation block). + async fn explorer() -> String { + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let base = format!("http://{}", listener.local_addr().unwrap()); + tokio::spawn(async move { + loop { + let (mut socket, _) = listener.accept().await.unwrap(); + let mut request = Vec::new(); + while !request.windows(4).any(|w| w == b"\r\n\r\n") { + let mut buf = [0; 1024]; + let n = socket.read(&mut buf).await.unwrap(); + if n == 0 { + break; + } + request.extend_from_slice(&buf[..n]); + } + let line = String::from_utf8_lossy(&request) + .lines() + .next() + .unwrap_or("") + .to_string(); + let path = line.split(' ').nth(1).unwrap_or(""); + let data = match path { + "/v1/network/blockchain-info" => { + serde_json::json!({"blocks": ACTIVATION_HEIGHT}) + } + "/v1/blocks/4465026" => serde_json::json!({ + "height": ACTIVATION_HEIGHT, + "transactions": [{"txid": COINBASE.0}, {"txid": V5.0}], + }), + p if p == format!("/v1/transactions/{}/raw", COINBASE.0) => { + serde_json::json!({"hex": COINBASE.1.trim()}) + } + p if p == format!("/v1/transactions/{}/raw", V5.0) => { + serde_json::json!({"hex": V5.1.trim()}) + } + _ => serde_json::Value::Null, + }; + let (status, body) = if data.is_null() { + (404, "{}".to_string()) + } else { + ( + 200, + serde_json::json!({"data": data, "meta": {"network": "testnet"}}) + .to_string(), + ) + }; + let response = format!( + "HTTP/1.1 {status} Test\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{body}", + body.len() + ); + let _ = socket.write_all(response.as_bytes()).await; + } + }); + base + } + + fn config(api_url: String) -> Config { + Config { + database_url: "sqlite::memory:".into(), + cipherscan_api_url: api_url, + network: "testnet".into(), + api_host: "127.0.0.1".into(), + api_port: 0, + mempool_poll_interval_secs: 5, + block_poll_interval_secs: 15, + encryption_key: String::new(), + invoice_expiry_minutes: 30, + data_purge_days: 30, + coingecko_api_url: "http://127.0.0.1:9".into(), + price_cache_secs: 60, + allowed_origins: vec![], + cookie_domain: None, + frontend_url: None, + smtp_pass: None, + smtp_from: None, + fee_ufvk: None, + fee_address: None, + fee_rate: 0.0, + billing_cycle_days_new: 30, + billing_cycle_days_standard: 30, + admin_key: None, + cipherscan_service_key: None, + checkout_service_key: None, + webauthn_rp_id: "localhost".into(), + webauthn_rp_origin: "http://localhost".into(), + referrals_enabled: false, + } + } + + /// With a pending invoice, the block scanner must parse every transaction in + /// the NU7 activation block and advance its checkpoint past it. Before the parser + /// upgrade, validation failed with "invalid consensus branch id" and the scanner + /// retried the same block forever. + #[tokio::test] + async fn block_scanner_crosses_nu7_activation_with_pending_invoice() { + use orchard::keys::{FullViewingKey, SpendingKey}; + use zcash_address::unified::{Encoding, Fvk, Ufvk}; + + let pool = crate::repair_tests::pool().await; + crate::repair_tests::merchant(&pool, "m").await; + let fvk = FullViewingKey::from(&SpendingKey::from_bytes([7u8; 32]).unwrap()); + let ufvk = Ufvk::try_from_items(vec![Fvk::Orchard(fvk.to_bytes())]) + .unwrap() + .encode(&zcash_protocol::consensus::NetworkType::Test); + sqlx::query("UPDATE merchants SET ufvk = ? WHERE id = 'm'") + .bind(&ufvk) + .execute(&pool) + .await + .unwrap(); + crate::repair_tests::invoice(&pool, "inv", "m").await; + + let config = config(explorer().await); + let http = reqwest::Client::new(); + let seen: SeenTxids = Arc::new(RwLock::new(HashMap::new())); + let last_height = Arc::new(RwLock::new(Some(ACTIVATION_HEIGHT - 1))); + let mut key_cache = None; + let prices = PriceService::new(&config.coingecko_api_url, 60); + + scan_blocks( + &config, + &pool, + &http, + &http, + &seen, + &last_height, + &mut key_cache, + &prices, + ) + .await + .expect("scan of the NU7 activation block must succeed"); + + assert_eq!(*last_height.read().await, Some(ACTIVATION_HEIGHT)); + let persisted: Option = + sqlx::query_scalar("SELECT value FROM scanner_state WHERE key = 'last_height'") + .fetch_optional(&pool) + .await + .unwrap(); + assert_eq!(persisted.as_deref(), Some("4465026")); + let invoice = invoices::get_invoice(&pool, "inv").await.unwrap().unwrap(); + assert_eq!(invoice.status, "pending"); + } +}